This commit is contained in:
Lana Steuck 2014-09-18 13:27:48 -07:00
commit 76fe0bf4de
128 changed files with 7630 additions and 1650 deletions

View File

@ -220,7 +220,6 @@ RT_JAR_EXCLUDES += \
sun/tools/serialver \
sun/tools/tree \
sun/tools/util \
sun/util/cldr/CLDRLocaleDataMetaInfo.class \
sun/util/resources/provider/NonEnLocaleDataMetaInfo.class \
META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo \
sun/util/resources/cldr \
@ -452,11 +451,9 @@ $(CLDR_METAINF_SERVICES): $(JDK_TOPDIR)/src/jdk.localedata/META-INF/cldrdata-ser
$(eval $(call SetupArchive,BUILD_CLDRDATA_JAR, \
$(CLDR_METAINF_SERVICES), \
SRCS := $(JDK_OUTPUTDIR)/modules/jdk.localedata \
$(JDK_OUTPUTDIR)/modules/java.base \
$(CLDR_SERVICES_DIR), \
SUFFIXES := .class, \
INCLUDES := sun/text/resources/cldr \
sun/util/cldr/CLDRLocaleDataMetaInfo.class \
sun/util/resources/cldr, \
EXTRA_FILES := META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo, \
JAR := $(CLDRDATA_JAR_DST), \

View File

@ -29,14 +29,13 @@ include GensrcCommon.gmk
include GensrcProperties.gmk
GENSRC_JAVA_BASE += $(GENSRC_PROPERTIES)
include GensrcLocaleDataMetaInfo.gmk
include GensrcLocaleData.gmk
include GensrcCharacterData.gmk
include GensrcMisc.gmk
include GensrcCharsetMapping.gmk
include GensrcCharsetCoder.gmk
include GensrcBuffer.gmk
include GensrcExceptions.gmk
include GensrcCLDR.gmk
java.base: $(GENSRC_JAVA_BASE)

View File

@ -0,0 +1,38 @@
#
# 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
# 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.
#
include GensrcCommon.gmk
# Hook to include the corresponding custom file, if present.
$(eval $(call IncludeCustomExtension, jdk, gensrc/Gensrc-jdk.localedata.gmk))
include GensrcLocaleData.gmk
include GensrcCLDR.gmk
jdk.localedata: $(GENSRC_JDK_LOCALEDATA)
all: jdk.localedata
.PHONY: all jdk.localedata

View File

@ -27,9 +27,8 @@ CLDRVERSION := 21.0.1
CLDRSRCDIR := $(JDK_TOPDIR)/src/jdk.localedata/share/classes/sun/util/cldr/resources/$(subst .,_,$(CLDRVERSION))
GENSRC_DIR := $(JDK_OUTPUTDIR)/gensrc/jdk.localedata
BASE_GENSRC_DIR := $(JDK_OUTPUTDIR)/gensrc/java.base
CLDR_METAINFO_FILE := $(BASE_GENSRC_DIR)/sun/util/cldr/CLDRLocaleDataMetaInfo.java
CLDR_METAINFO_FILE := $(GENSRC_DIR)/sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo.java
$(CLDR_METAINFO_FILE): $(wildcard $(CLDRSRCDIR)/common/dtd/*.dtd) \
$(wildcard $(CLDRSRCDIR)/common/main/*.xml) \
@ -37,16 +36,6 @@ $(CLDR_METAINFO_FILE): $(wildcard $(CLDRSRCDIR)/common/dtd/*.dtd) \
$(BUILD_TOOLS_JDK)
$(MKDIR) -p $(GENSRC_DIR)
$(TOOL_CLDRCONVERTER) -base $(CLDRSRCDIR) -o $(GENSRC_DIR)
$(MKDIR) -p $(BASE_GENSRC_DIR)/sun/text/resources/cldr
$(MKDIR) -p $(BASE_GENSRC_DIR)/sun/util/resources/cldr
$(RM) -r $(BASE_GENSRC_DIR)/sun/text/resources/cldr/en \
$(BASE_GENSRC_DIR)/sun/util/resources/cldr/en
$(MV) $(GENSRC_DIR)/sun/text/resources/cldr/en $(BASE_GENSRC_DIR)/sun/text/resources/cldr/en
$(MV) $(GENSRC_DIR)/sun/util/resources/cldr/en $(BASE_GENSRC_DIR)/sun/util/resources/cldr/en
$(MV) $(GENSRC_DIR)/sun/text/resources/cldr/*.java $(BASE_GENSRC_DIR)/sun/text/resources/cldr
$(MV) $(GENSRC_DIR)/sun/util/resources/cldr/*.java $(BASE_GENSRC_DIR)/sun/util/resources/cldr
$(MKDIR) -p $(@D)
$(MV) $(GENSRC_DIR)/sun/util/cldr/CLDRLocaleDataMetaInfo.java $@
GENSRC_CLDR := $(CLDR_METAINFO_FILE)
GENSRC_JAVA_BASE += $(GENSRC_CLDR)
GENSRC_JDK_LOCALEDATA += $(GENSRC_CLDR)

View File

@ -130,8 +130,8 @@ $(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDa
$(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" > $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources
$(SED) $(SED_NONENARGS) $< > $@
GENSRC_LOCALEDATAMETAINFO := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java \
$(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java
GENSRC_BASELOCALEDATA := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java
GENSRC_LOCALEDATA := $(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java
################################################################################
@ -145,7 +145,8 @@ $(GENSRC_CRBC_DST): $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/CoreResou
$(MKDIR) -p $(@D)
NAWK="$(NAWK)" SED="$(SED)" $(SH) $(GENSRC_CRBC_CMD) "$(JRE_NONEXIST_LOCALES)" $< $@
GENSRC_LOCALEDATAMETAINFO += $(GENSRC_CRBC_DST)
GENSRC_JAVA_BASE += $(GENSRC_LOCALEDATAMETAINFO)
GENSRC_BASELOCALEDATA += $(GENSRC_CRBC_DST)
GENSRC_JAVA_BASE += $(GENSRC_BASELOCALEDATA)
GENSRC_JDK_LOCALEDATA += $(GENSRC_LOCALEDATA)
################################################################################

View File

@ -217,10 +217,8 @@ ifeq ($(OPENJDK_TARGET_OS), windows)
-I$(JDK_OUTPUTDIR)/gensrc_headers/java.base \
#
LIBAWT_EXFILES += \
sun/java2d/d3d/D3DPipeline.cpp \
sun/java2d/d3d/D3DShaderGen.c \
sun/awt/image/cvutils/img_colors.c \
sun/windows/WBufferStrategy.cpp \
#
LIBAWT_LANG := C++

View File

@ -143,8 +143,9 @@ class ResourceBundleGenerator implements BundleGenerator {
@Override
public void generateMetaInfo(Map<String, SortedSet<String>> metaInfo) throws IOException {
String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator + "util" + File.separator
+ "cldr" + File.separator;
String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator + "util" +
File.separator + "resources" + File.separator + "cldr" + File.separator +
"provider" + File.separator ;
File dir = new File(dirName);
if (!dir.exists()) {
dir.mkdirs();
@ -158,7 +159,7 @@ class ResourceBundleGenerator implements BundleGenerator {
try (PrintWriter out = new PrintWriter(file, "us-ascii")) {
out.println(CopyrightHeaders.getOpenJDKCopyright());
out.println("package sun.util.cldr;\n\n"
out.println("package sun.util.resources.cldr.provider;\n\n"
+ "import java.util.ListResourceBundle;\n"
+ "import sun.util.locale.provider.LocaleProviderAdapter;\n"
+ "import sun.util.locale.provider.LocaleDataMetaInfo;\n");

View File

@ -25,29 +25,17 @@
package build.tools.module;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.xml.namespace.QName;
import javax.xml.stream.*;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.XMLEvent;
import java.util.stream.Collectors;
/**
* GenJdepsModulesXml augments the input modules.xml file(s)
@ -97,14 +85,14 @@ public final class GenJdepsModulesXml {
Set<Module> modules = new HashSet<>();
for (; i < args.length; i++) {
Path p = Paths.get(args[i]);
try (InputStream in = new BufferedInputStream(Files.newInputStream(p))) {
Set<Module> mods = gentool.load(in);
modules.addAll(mods);
}
modules.addAll(ModulesXmlReader.readModules(p)
.stream()
.map(gentool::buildIncludes)
.collect(Collectors.toSet()));
}
Files.createDirectories(outfile.getParent());
gentool.writeXML(modules, outfile);
ModulesXmlWriter.writeModules(modules, outfile);
}
final Path modulepath;
@ -112,228 +100,21 @@ public final class GenJdepsModulesXml {
this.modulepath = modulepath;
}
private static final String MODULES = "modules";
private static final String MODULE = "module";
private static final String NAME = "name";
private static final String DEPEND = "depend";
private static final String EXPORT = "export";
private static final String TO = "to";
private static final String INCLUDE = "include";
private static final QName REEXPORTS = new QName("re-exports");
private Set<Module> load(InputStream in) throws XMLStreamException, IOException {
Set<Module> modules = new HashSet<>();
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader stream = factory.createXMLEventReader(in);
Module.Builder mb = null;
String modulename = null;
String pkg = null;
Set<String> permits = new HashSet<>();
while (stream.hasNext()) {
XMLEvent event = stream.nextEvent();
if (event.isStartElement()) {
String startTag = event.asStartElement().getName().getLocalPart();
switch (startTag) {
case MODULES:
break;
case MODULE:
if (mb != null) {
throw new RuntimeException("end tag for module is missing");
}
modulename = getNextTag(stream, NAME);
mb = new Module.Builder();
mb.name(modulename);
break;
case NAME:
throw new RuntimeException(event.toString());
case DEPEND:
boolean reexports = false;
Attribute attr = event.asStartElement().getAttributeByName(REEXPORTS);
if (attr != null) {
String value = attr.getValue();
if (value.equals("true") || value.equals("false")) {
reexports = Boolean.parseBoolean(value);
} else {
throw new RuntimeException("unexpected attribute " + attr.toString());
}
}
mb.require(getData(stream), reexports);
break;
case INCLUDE:
throw new RuntimeException("unexpected " + event);
case EXPORT:
pkg = getNextTag(stream, NAME);
break;
case TO:
permits.add(getData(stream));
break;
default:
}
} else if (event.isEndElement()) {
String endTag = event.asEndElement().getName().getLocalPart();
switch (endTag) {
case MODULE:
buildIncludes(mb, modulename);
modules.add(mb.build());
mb = null;
break;
case EXPORT:
if (pkg == null) {
throw new RuntimeException("export-to is malformed");
}
mb.exportTo(pkg, permits);
pkg = null;
permits.clear();
break;
default:
}
} else if (event.isCharacters()) {
String s = event.asCharacters().getData();
if (!s.trim().isEmpty()) {
throw new RuntimeException("export-to is malformed");
}
}
}
return modules;
}
private String getData(XMLEventReader reader) throws XMLStreamException {
XMLEvent e = reader.nextEvent();
if (e.isCharacters()) {
return e.asCharacters().getData();
}
throw new RuntimeException(e.toString());
}
private String getNextTag(XMLEventReader reader, String tag) throws XMLStreamException {
XMLEvent e = reader.nextTag();
if (e.isStartElement()) {
String t = e.asStartElement().getName().getLocalPart();
if (!tag.equals(t)) {
throw new RuntimeException(e + " expected: " + tag);
}
return getData(reader);
}
throw new RuntimeException("export-to name is missing:" + e);
}
private void writeXML(Set<Module> modules, Path path)
throws IOException, XMLStreamException
{
XMLOutputFactory xof = XMLOutputFactory.newInstance();
try (OutputStream out = Files.newOutputStream(path)) {
int depth = 0;
XMLStreamWriter xtw = xof.createXMLStreamWriter(out, "UTF-8");
xtw.writeStartDocument("utf-8","1.0");
writeStartElement(xtw, MODULES, depth);
modules.stream()
.sorted(Comparator.comparing(Module::name))
.forEach(m -> writeModuleElement(xtw, m, depth+1));
writeEndElement(xtw, depth);
xtw.writeCharacters("\n");
xtw.writeEndDocument();
xtw.flush();
xtw.close();
}
}
private void writeElement(XMLStreamWriter xtw, String element, String value, int depth) {
try {
writeStartElement(xtw, element, depth);
xtw.writeCharacters(value);
xtw.writeEndElement();
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
private void writeDependElement(XMLStreamWriter xtw, Module.Dependence d, int depth) {
try {
writeStartElement(xtw, DEPEND, depth);
if (d.reexport) {
xtw.writeAttribute("re-exports", "true");
}
xtw.writeCharacters(d.name);
xtw.writeEndElement();
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
private void writeExportElement(XMLStreamWriter xtw, String pkg, int depth) {
writeExportElement(xtw, pkg, Collections.emptySet(), depth);
}
private void writeExportElement(XMLStreamWriter xtw, String pkg,
Set<String> permits, int depth) {
try {
writeStartElement(xtw, EXPORT, depth);
writeElement(xtw, NAME, pkg, depth+1);
if (!permits.isEmpty()) {
permits.stream().sorted()
.forEach(m -> writeElement(xtw, TO, m, depth + 1));
}
writeEndElement(xtw, depth);
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
private void writeModuleElement(XMLStreamWriter xtw, Module m, int depth) {
try {
writeStartElement(xtw, MODULE, depth);
writeElement(xtw, NAME, m.name(), depth+1);
m.requires().stream().sorted(Comparator.comparing(d -> d.name))
.forEach(d -> writeDependElement(xtw, d, depth+1));
m.exports().keySet().stream()
.filter(pn -> m.exports().get(pn).isEmpty())
.sorted()
.forEach(pn -> writeExportElement(xtw, pn, depth+1));
m.exports().entrySet().stream()
.filter(e -> !e.getValue().isEmpty())
.sorted(Map.Entry.comparingByKey())
.forEach(e -> writeExportElement(xtw, e.getKey(), e.getValue(), depth+1));
m.packages().stream().sorted()
.forEach(p -> writeElement(xtw, INCLUDE, p, depth+1));
writeEndElement(xtw, depth);
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
/** Two spaces; the default indentation. */
public static final String DEFAULT_INDENT = " ";
/** stack[depth] indicates what's been written into the current scope. */
private static String[] stack = new String[] { "\n",
"\n" + DEFAULT_INDENT,
"\n" + DEFAULT_INDENT + DEFAULT_INDENT,
"\n" + DEFAULT_INDENT + DEFAULT_INDENT + DEFAULT_INDENT};
private void writeStartElement(XMLStreamWriter xtw, String name, int depth)
throws XMLStreamException
{
xtw.writeCharacters(stack[depth]);
xtw.writeStartElement(name);
}
private void writeEndElement(XMLStreamWriter xtw, int depth) throws XMLStreamException {
xtw.writeCharacters(stack[depth]);
xtw.writeEndElement();
}
private String packageName(Path p) {
private static String packageName(Path p) {
return packageName(p.toString().replace(File.separatorChar, '/'));
}
private String packageName(String name) {
private static String packageName(String name) {
int i = name.lastIndexOf('/');
return (i > 0) ? name.substring(0, i).replace('/', '.') : "";
}
private boolean includes(String name) {
return name.endsWith(".class") && !name.equals("module-info.class");
private static boolean includes(String name) {
return name.endsWith(".class");
}
public void buildIncludes(Module.Builder mb, String modulename) throws IOException {
Path mclasses = modulepath.resolve(modulename);
public Module buildIncludes(Module module) {
Module.Builder mb = new Module.Builder(module);
Path mclasses = modulepath.resolve(module.name());
try {
Files.find(mclasses, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr)
-> includes(p.getFileName().toString()))
@ -341,145 +122,9 @@ public final class GenJdepsModulesXml {
.forEach(mb::include);
} catch (NoSuchFileException e) {
// aggregate module may not have class
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
static class Module {
static class Dependence {
final String name;
final boolean reexport;
Dependence(String name) {
this(name, false);
}
Dependence(String name, boolean reexport) {
this.name = name;
this.reexport = reexport;
}
@Override
public int hashCode() {
int hash = 5;
hash = 11 * hash + Objects.hashCode(this.name);
hash = 11 * hash + (this.reexport ? 1 : 0);
return hash;
}
public boolean equals(Object o) {
Dependence d = (Dependence)o;
return this.name.equals(d.name) && this.reexport == d.reexport;
}
}
private final String moduleName;
private final Set<Dependence> requires;
private final Map<String, Set<String>> exports;
private final Set<String> packages;
private Module(String name,
Set<Dependence> requires,
Map<String, Set<String>> exports,
Set<String> packages) {
this.moduleName = name;
this.requires = Collections.unmodifiableSet(requires);
this.exports = Collections.unmodifiableMap(exports);
this.packages = Collections.unmodifiableSet(packages);
}
public String name() {
return moduleName;
}
public Set<Dependence> requires() {
return requires;
}
public Map<String, Set<String>> exports() {
return exports;
}
public Set<String> packages() {
return packages;
}
@Override
public boolean equals(Object ob) {
if (!(ob instanceof Module)) {
return false;
}
Module that = (Module) ob;
return (moduleName.equals(that.moduleName)
&& requires.equals(that.requires)
&& exports.equals(that.exports)
&& packages.equals(that.packages));
}
@Override
public int hashCode() {
int hc = moduleName.hashCode();
hc = hc * 43 + requires.hashCode();
hc = hc * 43 + exports.hashCode();
hc = hc * 43 + packages.hashCode();
return hc;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("module ").append(moduleName).append(" {").append("\n");
requires.stream().sorted().forEach(d ->
sb.append(String.format(" requires %s%s%n", d.reexport ? "public " : "", d.name)));
exports.entrySet().stream().filter(e -> e.getValue().isEmpty())
.sorted(Map.Entry.comparingByKey())
.forEach(e -> sb.append(String.format(" exports %s%n", e.getKey())));
exports.entrySet().stream().filter(e -> !e.getValue().isEmpty())
.sorted(Map.Entry.comparingByKey())
.forEach(e -> sb.append(String.format(" exports %s to %s%n", e.getKey(), e.getValue())));
packages.stream().sorted().forEach(pn -> sb.append(String.format(" includes %s%n", pn)));
sb.append("}");
return sb.toString();
}
static class Builder {
private String name;
private final Set<Dependence> requires = new HashSet<>();
private final Map<String, Set<String>> exports = new HashMap<>();
private final Set<String> packages = new HashSet<>();
public Builder() {
}
public Builder name(String n) {
name = n;
return this;
}
public Builder require(String d, boolean reexport) {
requires.add(new Dependence(d, reexport));
return this;
}
public Builder include(String p) {
packages.add(p);
return this;
}
public Builder export(String p) {
return exportTo(p, Collections.emptySet());
}
public Builder exportTo(String p, Set<String> ms) {
Objects.requireNonNull(p);
Objects.requireNonNull(ms);
if (exports.containsKey(p)) {
throw new RuntimeException(name + " already exports " + p);
}
exports.put(p, new HashSet<>(ms));
return this;
}
public Module build() {
Module m = new Module(name, requires, exports, packages);
return m;
}
}
return mb.build();
}
}

View File

@ -0,0 +1,159 @@
/*
* 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
* 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 build.tools.module;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
/**
* $ java build.tools.module.GenModulesList \
* -o modules.list \
* top/modules.xml ...
*/
public final class GenModulesList {
private final static String USAGE =
"Usage: GenModulesList -o <output file> path-to-modules-xml";
private Set<Module> modules = new HashSet<>();
private HashMap<String,Module> nameToModule = new HashMap<>();
public static void main(String[] args) throws Exception {
GenModulesList gen = new GenModulesList();
gen.run(args);
}
void run(String[] args) throws Exception {
Path outfile = null;
int i = 0;
while (i < args.length) {
String arg = args[i];
if (arg.equals("-o")) {
outfile = Paths.get(args[i+1]);
i = i+2;
} else {
break;
}
}
if (outfile == null || i >= args.length) {
System.err.println(USAGE);
System.exit(-1);
}
for (; i < args.length; i++) {
Path p = Paths.get(args[i]);
modules.addAll(ModulesXmlReader.readModules(p));
}
modules.stream()
.forEach(m -> nameToModule.put(m.name(), m));
Path parent = outfile.getParent();
if (parent != null)
Files.createDirectories(parent);
Iterable<Module> sortedModules = (new TopoSorter(modules)).result();
try (PrintWriter writer = new PrintWriter(outfile.toFile())) {
for (Module m : sortedModules) {
if (isNotAggregator(m)) {
String deps = getModuleDependences(m).stream()
.filter(GenModulesList::isNotAggregator)
.map(Module::name)
.collect(Collectors.joining(" "));
writer.format("%s: %s%n", m.name(), deps);
}
}
}
}
private Module nameToModule(String name) {
return nameToModule.get(name);
}
private Set<Module> getModuleDependences(Module m) {
return m.requires().stream()
.map(d -> d.name())
.map(this::nameToModule)
.collect(Collectors.toSet());
}
static boolean isNotAggregator(Module m) {
return isNotAggregator(m.name());
}
static boolean isNotAggregator(String name) {
return AGGREGATORS.contains(name) ? false : true;
}
static final List<String> AGGREGATORS = Arrays.asList(new String[] {
"java.se", "java.compact1", "java.compact2",
"java.compact3", "jdk.compact3"});
class TopoSorter {
final Deque<Module> result = new LinkedList<>();
final Deque<Module> nodes = new LinkedList<>();
TopoSorter(Collection<Module> nodes) {
nodes.stream()
.forEach(m -> this.nodes.add(m));
sort();
}
public Iterable<Module> result() {
return result;
}
private void sort() {
Deque<Module> visited = new LinkedList<>();
Deque<Module> done = new LinkedList<>();
Module node;
while ((node = nodes.poll()) != null) {
if (!visited.contains(node)) {
visit(node, visited, done);
}
}
}
private void visit(Module m, Deque<Module> visited, Deque<Module> done) {
if (visited.contains(m)) {
if (!done.contains(m)) {
throw new IllegalArgumentException("Cyclic detected: " +
m + " " + getModuleDependences(m));
}
return;
}
visited.add(m);
getModuleDependences(m).stream()
.forEach(x -> visit(x, visited, done));
done.add(m);
result.addLast(m);
}
}
}

View File

@ -0,0 +1,178 @@
/*
* 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
* 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 build.tools.module;
import java.util.*;
public class Module {
static class Dependence {
final String name;
final boolean reexport;
Dependence(String name) {
this(name, false);
}
Dependence(String name, boolean reexport) {
this.name = name;
this.reexport = reexport;
}
public String name() {
return name;
}
@Override
public int hashCode() {
int hash = 5;
hash = 11 * hash + Objects.hashCode(this.name);
hash = 11 * hash + (this.reexport ? 1 : 0);
return hash;
}
public boolean equals(Object o) {
Dependence d = (Dependence)o;
return this.name.equals(d.name) && this.reexport == d.reexport;
}
}
private final String moduleName;
private final Set<Dependence> requires;
private final Map<String, Set<String>> exports;
private final Set<String> packages;
private Module(String name,
Set<Dependence> requires,
Map<String, Set<String>> exports,
Set<String> packages) {
this.moduleName = name;
this.requires = Collections.unmodifiableSet(requires);
this.exports = Collections.unmodifiableMap(exports);
this.packages = Collections.unmodifiableSet(packages);
}
public String name() {
return moduleName;
}
public Set<Dependence> requires() {
return requires;
}
public Map<String, Set<String>> exports() {
return exports;
}
public Set<String> packages() {
return packages;
}
@Override
public boolean equals(Object ob) {
if (!(ob instanceof Module)) {
return false;
}
Module that = (Module) ob;
return (moduleName.equals(that.moduleName)
&& requires.equals(that.requires)
&& exports.equals(that.exports)
&& packages.equals(that.packages));
}
@Override
public int hashCode() {
int hc = moduleName.hashCode();
hc = hc * 43 + requires.hashCode();
hc = hc * 43 + exports.hashCode();
hc = hc * 43 + packages.hashCode();
return hc;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("module ").append(moduleName).append(" {").append("\n");
requires.stream().sorted().forEach(d ->
sb.append(String.format(" requires %s%s%n", d.reexport ? "public " : "", d.name)));
exports.entrySet().stream().filter(e -> e.getValue().isEmpty())
.sorted(Map.Entry.comparingByKey())
.forEach(e -> sb.append(String.format(" exports %s%n", e.getKey())));
exports.entrySet().stream().filter(e -> !e.getValue().isEmpty())
.sorted(Map.Entry.comparingByKey())
.forEach(e -> sb.append(String.format(" exports %s to %s%n", e.getKey(), e.getValue())));
packages.stream().sorted().forEach(pn -> sb.append(String.format(" includes %s%n", pn)));
sb.append("}");
return sb.toString();
}
static class Builder {
private String name;
private final Set<Dependence> requires = new HashSet<>();
private final Map<String, Set<String>> exports = new HashMap<>();
private final Set<String> packages = new HashSet<>();
public Builder() {
}
public Builder(Module module) {
name = module.name();
requires.addAll(module.requires());
exports.putAll(module.exports());
packages.addAll(module.packages());
}
public Builder name(String n) {
name = n;
return this;
}
public Builder require(String d, boolean reexport) {
requires.add(new Dependence(d, reexport));
return this;
}
public Builder include(String p) {
packages.add(p);
return this;
}
public Builder export(String p) {
return exportTo(p, Collections.emptySet());
}
public Builder exportTo(String p, Set<String> ms) {
Objects.requireNonNull(p);
Objects.requireNonNull(ms);
if (exports.containsKey(p)) {
throw new RuntimeException(name + " already exports " + p);
}
exports.put(p, new HashSet<>(ms));
return this;
}
public Module build() {
Module m = new Module(name, requires, exports, packages);
return m;
}
}
}

View File

@ -0,0 +1,165 @@
/*
* 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
* 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 build.tools.module;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.XMLEvent;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Set;
public class ModulesXmlReader {
private ModulesXmlReader() {}
public static Set<Module> readModules(Path modulesXml)
throws XMLStreamException, IOException
{
Set<Module> modules = new HashSet<>();
try (InputStream in = new BufferedInputStream(Files.newInputStream(modulesXml))) {
Set<Module> mods = ModulesXmlReader.load(in);
modules.addAll(mods);
}
return modules;
}
private static final String MODULES = "modules";
private static final String MODULE = "module";
private static final String NAME = "name";
private static final String DEPEND = "depend";
private static final String EXPORT = "export";
private static final String TO = "to";
private static final String INCLUDE = "include";
private static final QName REEXPORTS = new QName("re-exports");
private static Set<Module> load(InputStream in)
throws XMLStreamException, IOException
{
Set<Module> modules = new HashSet<>();
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader stream = factory.createXMLEventReader(in);
Module.Builder mb = null;
String modulename = null;
String pkg = null;
Set<String> permits = new HashSet<>();
while (stream.hasNext()) {
XMLEvent event = stream.nextEvent();
if (event.isStartElement()) {
String startTag = event.asStartElement().getName().getLocalPart();
switch (startTag) {
case MODULES:
break;
case MODULE:
if (mb != null) {
throw new RuntimeException("end tag for module is missing");
}
modulename = getNextTag(stream, NAME);
mb = new Module.Builder();
mb.name(modulename);
break;
case NAME:
throw new RuntimeException(event.toString());
case DEPEND:
boolean reexports = false;
Attribute attr = event.asStartElement().getAttributeByName(REEXPORTS);
if (attr != null) {
String value = attr.getValue();
if (value.equals("true") || value.equals("false")) {
reexports = Boolean.parseBoolean(value);
} else {
throw new RuntimeException("unexpected attribute " + attr.toString());
}
}
mb.require(getData(stream), reexports);
break;
case INCLUDE:
throw new RuntimeException("unexpected " + event);
case EXPORT:
pkg = getNextTag(stream, NAME);
break;
case TO:
permits.add(getData(stream));
break;
default:
}
} else if (event.isEndElement()) {
String endTag = event.asEndElement().getName().getLocalPart();
switch (endTag) {
case MODULE:
modules.add(mb.build());
mb = null;
break;
case EXPORT:
if (pkg == null) {
throw new RuntimeException("export-to is malformed");
}
mb.exportTo(pkg, permits);
pkg = null;
permits.clear();
break;
default:
}
} else if (event.isCharacters()) {
String s = event.asCharacters().getData();
if (!s.trim().isEmpty()) {
throw new RuntimeException("export-to is malformed");
}
}
}
return modules;
}
private static String getData(XMLEventReader reader)
throws XMLStreamException
{
XMLEvent e = reader.nextEvent();
if (e.isCharacters())
return e.asCharacters().getData();
throw new RuntimeException(e.toString());
}
private static String getNextTag(XMLEventReader reader, String tag)
throws XMLStreamException
{
XMLEvent e = reader.nextTag();
if (e.isStartElement()) {
String t = e.asStartElement().getName().getLocalPart();
if (!tag.equals(t)) {
throw new RuntimeException(e + " expected: " + tag);
}
return getData(reader);
}
throw new RuntimeException("export-to name is missing:" + e);
}
}

View File

@ -0,0 +1,179 @@
/*
* 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
* 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 build.tools.module;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
public final class ModulesXmlWriter {
private ModulesXmlWriter() {}
public static void writeModules(Set<Module> modules, Path path)
throws IOException, XMLStreamException
{
writeXML(modules, path);
}
private static final String MODULES = "modules";
private static final String MODULE = "module";
private static final String NAME = "name";
private static final String DEPEND = "depend";
private static final String EXPORT = "export";
private static final String TO = "to";
private static final String INCLUDE = "include";
private static final QName REEXPORTS = new QName("re-exports");
private static void writeXML(Set<Module> modules, Path path)
throws IOException, XMLStreamException
{
XMLOutputFactory xof = XMLOutputFactory.newInstance();
try (OutputStream out = Files.newOutputStream(path)) {
int depth = 0;
XMLStreamWriter xtw = xof.createXMLStreamWriter(out, "UTF-8");
xtw.writeStartDocument("utf-8","1.0");
writeStartElement(xtw, MODULES, depth);
modules.stream()
.sorted(Comparator.comparing(Module::name))
.forEach(m -> writeModuleElement(xtw, m, depth+1));
writeEndElement(xtw, depth);
xtw.writeCharacters("\n");
xtw.writeEndDocument();
xtw.flush();
xtw.close();
}
}
private static void writeElement(XMLStreamWriter xtw,
String element,
String value,
int depth) {
try {
writeStartElement(xtw, element, depth);
xtw.writeCharacters(value);
xtw.writeEndElement();
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
private static void writeDependElement(XMLStreamWriter xtw,
Module.Dependence d,
int depth) {
try {
writeStartElement(xtw, DEPEND, depth);
if (d.reexport) {
xtw.writeAttribute("re-exports", "true");
}
xtw.writeCharacters(d.name);
xtw.writeEndElement();
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
private static void writeExportElement(XMLStreamWriter xtw,
String pkg,
int depth) {
writeExportElement(xtw, pkg, Collections.emptySet(), depth);
}
private static void writeExportElement(XMLStreamWriter xtw,
String pkg,
Set<String> permits,
int depth) {
try {
writeStartElement(xtw, EXPORT, depth);
writeElement(xtw, NAME, pkg, depth+1);
if (!permits.isEmpty()) {
permits.stream().sorted()
.forEach(m -> writeElement(xtw, TO, m, depth + 1));
}
writeEndElement(xtw, depth);
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
private static void writeModuleElement(XMLStreamWriter xtw,
Module m,
int depth) {
try {
writeStartElement(xtw, MODULE, depth);
writeElement(xtw, NAME, m.name(), depth+1);
m.requires().stream().sorted(Comparator.comparing(d -> d.name))
.forEach(d -> writeDependElement(xtw, d, depth+1));
m.exports().keySet().stream()
.filter(pn -> m.exports().get(pn).isEmpty())
.sorted()
.forEach(pn -> writeExportElement(xtw, pn, depth+1));
m.exports().entrySet().stream()
.filter(e -> !e.getValue().isEmpty())
.sorted(Map.Entry.comparingByKey())
.forEach(e -> writeExportElement(xtw, e.getKey(), e.getValue(), depth+1));
m.packages().stream().sorted()
.forEach(p -> writeElement(xtw, INCLUDE, p, depth+1));
writeEndElement(xtw, depth);
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
/** Two spaces; the default indentation. */
public static final String DEFAULT_INDENT = " ";
/** stack[depth] indicates what's been written into the current scope. */
private static String[] stack = new String[] { "\n",
"\n" + DEFAULT_INDENT,
"\n" + DEFAULT_INDENT + DEFAULT_INDENT,
"\n" + DEFAULT_INDENT + DEFAULT_INDENT + DEFAULT_INDENT};
private static void writeStartElement(XMLStreamWriter xtw,
String name,
int depth)
throws XMLStreamException
{
xtw.writeCharacters(stack[depth]);
xtw.writeStartElement(name);
}
private static void writeEndElement(XMLStreamWriter xtw, int depth)
throws XMLStreamException
{
xtw.writeCharacters(stack[depth]);
xtw.writeEndElement();
}
}

View File

@ -62,7 +62,7 @@ class InvokerBytecodeGenerator {
private static final String CLL_SIG = "(L" + CLS + ";L" + OBJ + ";)L" + OBJ + ";";
/** Name of its super class*/
private static final String superName = LF;
private static final String superName = OBJ;
/** Name of new class */
private final String className;
@ -97,7 +97,7 @@ class InvokerBytecodeGenerator {
if (DUMP_CLASS_FILES) {
className = makeDumpableClassName(className);
}
this.className = superName + "$" + className;
this.className = LF + "$" + className;
this.sourceFile = "LambdaForm$" + className;
this.lambdaForm = lambdaForm;
this.invokerName = invokerName;

View File

@ -188,7 +188,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType,
boolean strict, boolean monobox) {
MethodType dstType = target.type();
assert(dstType.parameterCount() == target.type().parameterCount());
if (srcType == dstType)
return target;
if (USE_LAMBDA_FORM_EDITOR) {
@ -265,6 +264,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static MethodHandle makePairwiseConvertIndirect(MethodHandle target, MethodType srcType,
boolean strict, boolean monobox) {
assert(target.type().parameterCount() == srcType.parameterCount());
// Calculate extra arguments (temporaries) required in the names array.
Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox);
final int INARG_COUNT = srcType.parameterCount();

View File

@ -2023,8 +2023,9 @@ return invoker;
*/
public static
MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
MethodType oldType = target.type();
explicitCastArgumentsChecks(target, newType);
// use the asTypeCache when possible:
MethodType oldType = target.type();
if (oldType == newType) return target;
if (oldType.explicitCastEquivalentToAsType(newType)) {
return target.asType(newType);
@ -2032,6 +2033,12 @@ return invoker;
return MethodHandleImpl.makePairwiseConvert(target, newType, false);
}
private static void explicitCastArgumentsChecks(MethodHandle target, MethodType newType) {
if (target.type().parameterCount() != newType.parameterCount()) {
throw new WrongMethodTypeException("cannot explicitly cast " + target + " to " + newType);
}
}
/**
* Produces a method handle which adapts the calling sequence of the
* given method handle to a new type, by reordering the arguments.
@ -2164,7 +2171,7 @@ assert((int)twice.invokeExact(21) == 42);
// dropIdx is missing from reorder; add it in at the end
int oldArity = reorder.length;
target = dropArguments(target, oldArity, newType.parameterType(dropIdx));
reorder = Arrays.copyOf(reorder, oldArity+1);
reorder = Arrays.copyOf(reorder, oldArity + 1);
reorder[oldArity] = dropIdx;
}
assert(target == originalTarget || permuteArgumentChecks(reorder, newType, target.type()));
@ -2182,9 +2189,9 @@ assert((int)twice.invokeExact(21) == 42);
long mask = 0;
for (int arg : reorder) {
assert(arg < newArity);
mask |= (1 << arg);
mask |= (1L << arg);
}
if (mask == (1 << newArity) - 1) {
if (mask == (1L << newArity) - 1) {
assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity);
return -1;
}
@ -2193,16 +2200,18 @@ assert((int)twice.invokeExact(21) == 42);
int zeroPos = Long.numberOfTrailingZeros(zeroBit);
assert(zeroPos < newArity);
return zeroPos;
} else {
BitSet mask = new BitSet(newArity);
for (int arg : reorder) {
assert (arg < newArity);
mask.set(arg);
}
int zeroPos = mask.nextClearBit(0);
assert(zeroPos <= newArity);
if (zeroPos == newArity)
return -1;
return zeroPos;
}
BitSet mask = new BitSet(newArity);
for (int arg : reorder) {
assert(arg < newArity);
mask.set(arg);
}
int zeroPos = mask.nextClearBit(0);
if (zeroPos == newArity)
return -1;
return zeroPos;
}
/**
@ -2218,32 +2227,42 @@ assert((int)twice.invokeExact(21) == 42);
long mask = 0;
for (int i = 0; i < reorder.length; i++) {
int arg = reorder[i];
if (arg >= newArity) return reorder.length;
int bit = 1 << arg;
if ((mask & bit) != 0)
if (arg >= newArity) {
return reorder.length;
}
long bit = 1L << arg;
if ((mask & bit) != 0) {
return i; // >0 indicates a dup
}
mask |= bit;
}
if (mask == (1 << newArity) - 1) {
if (mask == (1L << newArity) - 1) {
assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity);
return 0;
}
// find first zero
long zeroBit = Long.lowestOneBit(~mask);
int zeroPos = Long.numberOfTrailingZeros(zeroBit);
assert(zeroPos < newArity);
assert(zeroPos <= newArity);
if (zeroPos == newArity) {
return 0;
}
return ~zeroPos;
} else {
// same algorithm, different bit set
BitSet mask = new BitSet(newArity);
for (int i = 0; i < reorder.length; i++) {
int arg = reorder[i];
if (arg >= newArity) return reorder.length;
if (mask.get(arg))
if (arg >= newArity) {
return reorder.length;
}
if (mask.get(arg)) {
return i; // >0 indicates a dup
}
mask.set(arg);
}
int zeroPos = mask.nextClearBit(0);
assert(zeroPos <= newArity);
if (zeroPos == newArity) {
return 0;
}
@ -2479,6 +2498,7 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
MethodType oldType = target.type(); // get NPE
int dropped = dropArgumentChecks(oldType, pos, valueTypes);
MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
if (dropped == 0) return target;
BoundMethodHandle result = target.rebind();
LambdaForm lform = result.form;
@ -2490,7 +2510,6 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
} else {
lform = lform.addArguments(pos, valueTypes);
}
MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
result = result.copyWith(newType, lform);
return result;
}

View File

@ -869,9 +869,7 @@ class MethodType implements java.io.Serializable {
if (dstTypes == srcTypes) {
return true;
}
if (dstTypes.length != srcTypes.length) {
return false;
}
assert(dstTypes.length == srcTypes.length);
for (int i = 0; i < dstTypes.length; i++) {
if (!explicitCastEquivalentToAsType(srcTypes[i], dstTypes[i])) {
return false;

View File

@ -1261,19 +1261,20 @@ class MutableBigInteger {
int sigma = (int) Math.max(0, n32 - b.bitLength()); // step 3: sigma = max{T | (2^T)*B < beta^n}
MutableBigInteger bShifted = new MutableBigInteger(b);
bShifted.safeLeftShift(sigma); // step 4a: shift b so its length is a multiple of n
safeLeftShift(sigma); // step 4b: shift this by the same amount
MutableBigInteger aShifted = new MutableBigInteger (this);
aShifted.safeLeftShift(sigma); // step 4b: shift a by the same amount
// step 5: t is the number of blocks needed to accommodate this plus one additional bit
int t = (int) ((bitLength()+n32) / n32);
// step 5: t is the number of blocks needed to accommodate a plus one additional bit
int t = (int) ((aShifted.bitLength()+n32) / n32);
if (t < 2) {
t = 2;
}
// step 6: conceptually split this into blocks a[t-1], ..., a[0]
MutableBigInteger a1 = getBlock(t-1, t, n); // the most significant block of this
// step 6: conceptually split a into blocks a[t-1], ..., a[0]
MutableBigInteger a1 = aShifted.getBlock(t-1, t, n); // the most significant block of a
// step 7: z[t-2] = [a[t-1], a[t-2]]
MutableBigInteger z = getBlock(t-2, t, n); // the second to most significant block
MutableBigInteger z = aShifted.getBlock(t-2, t, n); // the second to most significant block
z.addDisjoint(a1, n); // z[t-2]
// do schoolbook division on blocks, dividing 2-block numbers by 1-block numbers
@ -1284,7 +1285,7 @@ class MutableBigInteger {
ri = z.divide2n1n(bShifted, qi);
// step 8b: z = [ri, a[i-1]]
z = getBlock(i-1, t, n); // a[i-1]
z = aShifted.getBlock(i-1, t, n); // a[i-1]
z.addDisjoint(ri, n);
quotient.addShifted(qi, i*n); // update q (part of step 9)
}
@ -1292,7 +1293,7 @@ class MutableBigInteger {
ri = z.divide2n1n(bShifted, qi);
quotient.add(qi);
ri.rightShift(sigma); // step 9: this and b were shifted, so shift back
ri.rightShift(sigma); // step 9: a and b were shifted, so shift back
return ri;
}
}

View File

@ -336,8 +336,21 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
return new ZipEntry(name);
}
/*
/**
* Reads end of deflated entry as well as EXT descriptor if present.
*
* Local headers for DEFLATED entries may optionally be followed by a
* data descriptor, and that data descriptor may optionally contain a
* leading signature (EXTSIG).
*
* From the zip spec http://www.pkware.com/documents/casestudies/APPNOTE.TXT
*
* """Although not originally assigned a signature, the value 0x08074b50
* has commonly been adopted as a signature value for the data descriptor
* record. Implementers should be aware that ZIP files may be
* encountered with or without this signature marking data descriptors
* and should account for either case when reading ZIP files to ensure
* compatibility."""
*/
private void readEnd(ZipEntry e) throws IOException {
int n = inf.getRemaining();
@ -356,7 +369,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC);
e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC);
((PushbackInputStream)in).unread(
tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC - 1, ZIP64_EXTCRC);
tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC, ZIP64_EXTCRC);
} else {
e.crc = get32(tmpbuf, ZIP64_EXTCRC);
e.csize = get64(tmpbuf, ZIP64_EXTSIZ);
@ -370,7 +383,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
e.csize = get32(tmpbuf, EXTSIZ - EXTCRC);
e.size = get32(tmpbuf, EXTLEN - EXTCRC);
((PushbackInputStream)in).unread(
tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC);
tmpbuf, EXTHDR - EXTCRC, EXTCRC);
} else {
e.crc = get32(tmpbuf, EXTCRC);
e.csize = get32(tmpbuf, EXTSIZ);

View File

@ -34,6 +34,10 @@
#include <fcntl.h>
#include <sys/uio.h>
#include <unistd.h>
#if defined(__linux__)
#include <linux/fs.h>
#include <sys/ioctl.h>
#endif
#include "nio.h"
#include "nio_util.h"
@ -177,10 +181,21 @@ Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this,
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
{
jint fd = fdval(env, fdo);
struct stat64 fbuf;
if (fstat64(fdval(env, fdo), &fbuf) < 0)
if (fstat64(fd, &fbuf) < 0)
return handle(env, -1, "Size failed");
#ifdef BLKGETSIZE64
if (S_ISBLK(fbuf.st_mode)) {
uint64_t size;
if (ioctl(fd, BLKGETSIZE64, &size) < 0)
return handle(env, -1, "Size failed");
return (jlong)size;
}
#endif
return fbuf.st_size;
}

View File

@ -990,9 +990,11 @@ JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0
case MIB_IF_TYPE_FDDI:
case IF_TYPE_IEEE80211:
len = ifRowP->dwPhysAddrLen;
ret = (*env)->NewByteArray(env, len);
if (!IS_NULL(ret)) {
(*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr);
if (len > 0) {
ret = (*env)->NewByteArray(env, len);
if (!IS_NULL(ret)) {
(*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr);
}
}
break;
}

View File

@ -418,7 +418,8 @@ public class InputMethodEvent extends AWTEvent {
private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
s.defaultReadObject();
if (when == 0) {
when = getMostRecentEventTimeForSource(this.source);
// Can't use getMostRecentEventTimeForSource because source is always null during deserialization
when = EventQueue.getMostRecentEventTime();
}
}

View File

@ -43,6 +43,7 @@ import java.io.IOException;
import java.beans.PropertyVetoException;
import java.util.Set;
import java.util.TreeSet;
import java.util.LinkedHashSet;
/**
* A container used to create a multiple-document interface or a virtual desktop.
* You create <code>JInternalFrame</code> objects and add them to the
@ -271,7 +272,7 @@ public class JDesktopPane extends JLayeredPane implements Accessible
private static Collection<JInternalFrame> getAllFrames(Container parent) {
int i, count;
Collection<JInternalFrame> results = new ArrayList<JInternalFrame>();
Collection<JInternalFrame> results = new LinkedHashSet<>();
count = parent.getComponentCount();
for (i = 0; i < count; i++) {
Component next = parent.getComponent(i);

View File

@ -65,7 +65,11 @@ public class OGLSurfaceDataProxy extends SurfaceDataProxy {
int w, int h)
{
if (cachedData == null) {
cachedData = oglgc.createManagedSurface(w, h, transparency);
try {
cachedData = oglgc.createManagedSurface(w, h, transparency);
} catch (OutOfMemoryError er) {
return null;
}
}
return cachedData;
}

View File

@ -1082,86 +1082,60 @@ static int allocateSpaceForGP(GPData* gpdata, int npoints, int ncontours) {
return 1;
}
static void addSeg(GPData *gp, jbyte type) {
gp->pointTypes[gp->numTypes++] = type;
}
static void addCoords(GPData *gp, FT_Vector *p) {
gp->pointCoords[gp->numCoords++] = F26Dot6ToFloat(p->x);
gp->pointCoords[gp->numCoords++] = -F26Dot6ToFloat(p->y);
}
static int moveTo(FT_Vector *to, GPData *gp) {
if (gp->numCoords)
addSeg(gp, SEG_CLOSE);
addCoords(gp, to);
addSeg(gp, SEG_MOVETO);
return FT_Err_Ok;
}
static int lineTo(FT_Vector *to, GPData *gp) {
addCoords(gp, to);
addSeg(gp, SEG_LINETO);
return FT_Err_Ok;
}
static int conicTo(FT_Vector *control, FT_Vector *to, GPData *gp) {
addCoords(gp, control);
addCoords(gp, to);
addSeg(gp, SEG_QUADTO);
return FT_Err_Ok;
}
static int cubicTo(FT_Vector *control1,
FT_Vector *control2,
FT_Vector *to,
GPData *gp) {
addCoords(gp, control1);
addCoords(gp, control2);
addCoords(gp, to);
addSeg(gp, SEG_CUBICTO);
return FT_Err_Ok;
}
static void addToGP(GPData* gpdata, FT_Outline*outline) {
jbyte current_type=SEG_UNKNOWN;
int i, j;
jfloat x, y;
static const FT_Outline_Funcs outline_funcs = {
(FT_Outline_MoveToFunc) moveTo,
(FT_Outline_LineToFunc) lineTo,
(FT_Outline_ConicToFunc) conicTo,
(FT_Outline_CubicToFunc) cubicTo,
0, /* shift */
0, /* delta */
};
j = 0;
for(i=0; i<outline->n_points; i++) {
x = F26Dot6ToFloat(outline->points[i].x);
y = -F26Dot6ToFloat(outline->points[i].y);
if (FT_CURVE_TAG(outline->tags[i]) == FT_CURVE_TAG_ON) {
/* If bit 0 is unset, the point is "off" the curve,
i.e., a Bezier control point, while it is "on" when set. */
if (current_type == SEG_UNKNOWN) { /* special case:
very first point */
/* add segment */
gpdata->pointTypes[gpdata->numTypes++] = SEG_MOVETO;
current_type = SEG_LINETO;
} else {
gpdata->pointTypes[gpdata->numTypes++] = current_type;
current_type = SEG_LINETO;
}
} else {
if (current_type == SEG_UNKNOWN) { /* special case:
very first point */
if (FT_CURVE_TAG(outline->tags[i+1]) == FT_CURVE_TAG_ON) {
/* just skip first point. Adhoc heuristic? */
continue;
} else {
x = (x + F26Dot6ToFloat(outline->points[i+1].x))/2;
y = (y - F26Dot6ToFloat(outline->points[i+1].y))/2;
gpdata->pointTypes[gpdata->numTypes++] = SEG_MOVETO;
current_type = SEG_LINETO;
}
} else if (FT_CURVE_TAG(outline->tags[i]) == FT_CURVE_TAG_CUBIC) {
/* Bit 1 is meaningful for 'off' points only.
If set, it indicates a third-order Bezier arc control
point; and a second-order control point if unset. */
current_type = SEG_CUBICTO;
} else {
/* two successive conic "off" points forces the rasterizer
to create (during the scan-line conversion process
exclusively) a virtual "on" point amidst them, at their
exact middle. This greatly facilitates the definition of
successive conic Bezier arcs. Moreover, it is the way
outlines are described in the TrueType specification. */
if (current_type == SEG_QUADTO) {
gpdata->pointCoords[gpdata->numCoords++] =
F26Dot6ToFloat(outline->points[i].x +
outline->points[i-1].x)/2;
gpdata->pointCoords[gpdata->numCoords++] =
- F26Dot6ToFloat(outline->points[i].y +
outline->points[i-1].y)/2;
gpdata->pointTypes[gpdata->numTypes++] = SEG_QUADTO;
}
current_type = SEG_QUADTO;
}
}
gpdata->pointCoords[gpdata->numCoords++] = x;
gpdata->pointCoords[gpdata->numCoords++] = y;
if (outline->contours[j] == i) { //end of contour
int start = j > 0 ? outline->contours[j-1]+1 : 0;
gpdata->pointTypes[gpdata->numTypes++] = current_type;
if (current_type == SEG_QUADTO &&
FT_CURVE_TAG(outline->tags[start]) != FT_CURVE_TAG_ON) {
gpdata->pointCoords[gpdata->numCoords++] =
(F26Dot6ToFloat(outline->points[start].x) + x)/2;
gpdata->pointCoords[gpdata->numCoords++] =
(-F26Dot6ToFloat(outline->points[start].y) + y)/2;
} else {
gpdata->pointCoords[gpdata->numCoords++] =
F26Dot6ToFloat(outline->points[start].x);
gpdata->pointCoords[gpdata->numCoords++] =
-F26Dot6ToFloat(outline->points[start].y);
}
gpdata->pointTypes[gpdata->numTypes++] = SEG_CLOSE;
current_type = SEG_UNKNOWN;
j++;
}
}
FT_Outline_Decompose(outline, &outline_funcs, gpdata);
if (gpdata->numCoords)
addSeg(gpdata, SEG_CLOSE);
/* If set to 1, the outline will be filled using the even-odd fill rule */
if (outline->flags & FT_OUTLINE_EVEN_ODD_FILL) {

View File

@ -467,11 +467,12 @@ void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh
CAM02COLOR clr;
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
memset(&clr, 0, sizeof(clr));
_cmsAssert(lpMod != NULL);
_cmsAssert(pIn != NULL);
_cmsAssert(pOut != NULL);
memset(&clr, 0, sizeof(clr));
clr.XYZ[0] = pIn ->X;
clr.XYZ[1] = pIn ->Y;
clr.XYZ[2] = pIn ->Z;
@ -492,11 +493,12 @@ void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ
CAM02COLOR clr;
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
memset(&clr, 0, sizeof(clr));
_cmsAssert(lpMod != NULL);
_cmsAssert(pIn != NULL);
_cmsAssert(pOut != NULL);
memset(&clr, 0, sizeof(clr));
clr.J = pIn -> J;
clr.C = pIn -> C;
clr.h = pIn -> h;
@ -511,4 +513,3 @@ void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ
pOut ->Y = clr.XYZ[1];
pOut ->Z = clr.XYZ[2];
}

View File

@ -2179,9 +2179,9 @@ void CookPointers(cmsIT8* it8)
if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
t -> SampleID = idField;
t -> SampleID = idField;
for (i=0; i < t -> nPatches; i++) {
for (i=0; i < t -> nPatches; i++) {
char *Data = GetData(it8, i, idField);
if (Data) {
@ -2196,7 +2196,7 @@ void CookPointers(cmsIT8* it8)
SetData(it8, i, idField, Buffer);
}
}
}
}

View File

@ -137,15 +137,68 @@ static cmsIntentsList DefaultIntents[] = {
// A pointer to the begining of the list
static cmsIntentsList *Intents = DefaultIntents;
_cmsIntentsPluginChunkType _cmsIntentsPluginChunk = { NULL };
// Duplicates the zone of memory used by the plug-in in the new context
static
void DupPluginIntentsList(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
_cmsIntentsPluginChunkType newHead = { NULL };
cmsIntentsList* entry;
cmsIntentsList* Anterior = NULL;
_cmsIntentsPluginChunkType* head = (_cmsIntentsPluginChunkType*) src->chunks[IntentPlugin];
// Walk the list copying all nodes
for (entry = head->Intents;
entry != NULL;
entry = entry ->Next) {
cmsIntentsList *newEntry = ( cmsIntentsList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsIntentsList));
if (newEntry == NULL)
return;
// We want to keep the linked list order, so this is a little bit tricky
newEntry -> Next = NULL;
if (Anterior)
Anterior -> Next = newEntry;
Anterior = newEntry;
if (newHead.Intents == NULL)
newHead.Intents = newEntry;
}
ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsIntentsPluginChunkType));
}
void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
if (src != NULL) {
// Copy all linked list
DupPluginIntentsList(ctx, src);
}
else {
static _cmsIntentsPluginChunkType IntentsPluginChunkType = { NULL };
ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx ->MemPool, &IntentsPluginChunkType, sizeof(_cmsIntentsPluginChunkType));
}
}
// Search the list for a suitable intent. Returns NULL if not found
static
cmsIntentsList* SearchIntent(cmsUInt32Number Intent)
cmsIntentsList* SearchIntent(cmsContext ContextID, cmsUInt32Number Intent)
{
_cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin);
cmsIntentsList* pt;
for (pt = Intents; pt != NULL; pt = pt -> Next)
for (pt = ctx -> Intents; pt != NULL; pt = pt -> Next)
if (pt ->Intent == Intent) return pt;
for (pt = DefaultIntents; pt != NULL; pt = pt -> Next)
if (pt ->Intent == Intent) return pt;
return NULL;
@ -1031,7 +1084,7 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID,
// this case would present some issues if the custom intent tries to do things like
// preserve primaries. This solution is not perfect, but works well on most cases.
Intent = SearchIntent(TheIntents[0]);
Intent = SearchIntent(ContextID, TheIntents[0]);
if (Intent == NULL) {
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]);
return NULL;
@ -1046,12 +1099,14 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID,
// Get information about available intents. nMax is the maximum space for the supplied "Codes"
// and "Descriptions" the function returns the total number of intents, which may be greater
// than nMax, although the matrices are not populated beyond this level.
cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions)
cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions)
{
_cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin);
cmsIntentsList* pt;
cmsUInt32Number nIntents;
for (nIntents=0, pt = Intents; pt != NULL; pt = pt -> Next)
for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next)
{
if (nIntents < nMax) {
if (Codes != NULL)
@ -1064,37 +1119,52 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32
nIntents++;
}
for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next)
{
if (nIntents < nMax) {
if (Codes != NULL)
Codes[nIntents] = pt ->Intent;
if (Descriptions != NULL)
Descriptions[nIntents] = pt ->Description;
}
nIntents++;
}
return nIntents;
}
cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions)
{
return cmsGetSupportedIntentsTHR(NULL, nMax, Codes, Descriptions);
}
// The plug-in registration. User can add new intents or override default routines
cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data)
{
_cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(id, IntentPlugin);
cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data;
cmsIntentsList* fl;
// Do we have to reset the intents?
// Do we have to reset the custom intents?
if (Data == NULL) {
Intents = DefaultIntents;
return TRUE;
ctx->Intents = NULL;
return TRUE;
}
fl = SearchIntent(Plugin ->Intent);
fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList));
if (fl == NULL) return FALSE;
if (fl == NULL) {
fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList));
if (fl == NULL) return FALSE;
}
fl ->Intent = Plugin ->Intent;
strncpy(fl ->Description, Plugin ->Description, 255);
fl ->Description[255] = 0;
strncpy(fl ->Description, Plugin ->Description, sizeof(fl ->Description)-1);
fl ->Description[sizeof(fl ->Description)-1] = 0;
fl ->Link = Plugin ->Link;
fl ->Next = Intents;
Intents = fl;
fl ->Next = ctx ->Intents;
ctx ->Intents = fl;
return TRUE;
}

View File

@ -60,13 +60,14 @@
// compare two strings ignoring case
int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2)
{
register const unsigned char *us1 = (const unsigned char *)s1,
*us2 = (const unsigned char *)s2;
register const unsigned char *us1 = (const unsigned char *)s1,
*us2 = (const unsigned char *)s2;
while (toupper(*us1) == toupper(*us2++))
if (*us1++ == '\0')
return (0);
return (toupper(*us1) - toupper(*--us2));
while (toupper(*us1) == toupper(*us2++))
if (*us1++ == '\0')
return 0;
return (toupper(*us1) - toupper(*--us2));
}
// long int because C99 specifies ftell in such way (7.19.9.2)
@ -91,9 +92,8 @@ long int CMSEXPORT cmsfilelength(FILE* f)
//
// This is the interface to low-level memory management routines. By default a simple
// wrapping to malloc/free/realloc is provided, although there is a limit on the max
// amount of memoy that can be reclaimed. This is mostly as a safety feature to
// prevent bogus or malintentionated code to allocate huge blocks that otherwise lcms
// would never need.
// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent
// bogus or evil code to allocate huge blocks that otherwise lcms would never need.
#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U))
@ -103,7 +103,7 @@ long int CMSEXPORT cmsfilelength(FILE* f)
// required to be implemented: malloc, realloc and free, although the user may want to
// replace the optional mallocZero, calloc and dup as well.
cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin);
cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// *********************************************************************************
@ -143,7 +143,7 @@ void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr)
cmsUNUSED_PARAMETER(ContextID);
}
// The default realloc function. Again it check for exploits. If Ptr is NULL,
// The default realloc function. Again it checks for exploits. If Ptr is NULL,
// realloc behaves the same way as malloc and allocates a new block of size bytes.
static
void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size)
@ -196,28 +196,73 @@ void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number si
return mem;
}
// Pointers to malloc and _cmsFree functions in current environment
static void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocDefaultFn;
static void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocZeroDefaultFn;
static void (* FreePtr)(cmsContext ContextID, void *Ptr) = _cmsFreeDefaultFn;
static void * (* ReallocPtr)(cmsContext ContextID, void *Ptr, cmsUInt32Number NewSize) = _cmsReallocDefaultFn;
static void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)= _cmsCallocDefaultFn;
static void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size) = _cmsDupDefaultFn;
// Pointers to memory manager functions in Context0
_cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn,
_cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn
};
// Reset and duplicate memory manager
void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src)
{
_cmsAssert(ctx != NULL);
if (src != NULL) {
// Duplicate
ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType));
}
else {
// To reset it, we use the default allocators, which cannot be overriden
ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager;
}
}
// Auxiliar to fill memory management functions from plugin (or context 0 defaults)
void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr)
{
if (Plugin == NULL) {
memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk));
}
else {
ptr ->MallocPtr = Plugin -> MallocPtr;
ptr ->FreePtr = Plugin -> FreePtr;
ptr ->ReallocPtr = Plugin -> ReallocPtr;
// Make sure we revert to defaults
ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn;
ptr ->CallocPtr = _cmsCallocDefaultFn;
ptr ->DupPtr = _cmsDupDefaultFn;
if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr;
if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr;
if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr;
}
}
// Plug-in replacement entry
cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data)
cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data)
{
cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data;
_cmsMemPluginChunkType* ptr;
// NULL forces to reset to defaults
// NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure.
// Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the
// context internal data should be malloce'd by using those functions.
if (Data == NULL) {
MallocPtr = _cmsMallocDefaultFn;
MallocZeroPtr= _cmsMallocZeroDefaultFn;
FreePtr = _cmsFreeDefaultFn;
ReallocPtr = _cmsReallocDefaultFn;
CallocPtr = _cmsCallocDefaultFn;
DupPtr = _cmsDupDefaultFn;
struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID;
// Return to the default allocators
if (ContextID != NULL) {
ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager;
}
return TRUE;
}
@ -227,51 +272,56 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data)
Plugin -> ReallocPtr == NULL) return FALSE;
// Set replacement functions
MallocPtr = Plugin -> MallocPtr;
FreePtr = Plugin -> FreePtr;
ReallocPtr = Plugin -> ReallocPtr;
if (Plugin ->MallocZeroPtr != NULL) MallocZeroPtr = Plugin ->MallocZeroPtr;
if (Plugin ->CallocPtr != NULL) CallocPtr = Plugin -> CallocPtr;
if (Plugin ->DupPtr != NULL) DupPtr = Plugin -> DupPtr;
ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
if (ptr == NULL)
return FALSE;
_cmsInstallAllocFunctions(Plugin, ptr);
return TRUE;
}
// Generic allocate
void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size)
{
return MallocPtr(ContextID, size);
_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
return ptr ->MallocPtr(ContextID, size);
}
// Generic allocate & zero
void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size)
{
return MallocZeroPtr(ContextID, size);
_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
return ptr->MallocZeroPtr(ContextID, size);
}
// Generic calloc
void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)
{
return CallocPtr(ContextID, num, size);
_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
return ptr->CallocPtr(ContextID, num, size);
}
// Generic reallocate
void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size)
{
return ReallocPtr(ContextID, Ptr, size);
_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
return ptr->ReallocPtr(ContextID, Ptr, size);
}
// Generic free memory
void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr)
{
if (Ptr != NULL) FreePtr(ContextID, Ptr);
if (Ptr != NULL) {
_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
ptr ->FreePtr(ContextID, Ptr);
}
}
// Generic block duplication
void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size)
{
return DupPtr(ContextID, Org, size);
_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
return ptr ->DupPtr(ContextID, Org, size);
}
// ********************************************************************************************
@ -380,6 +430,26 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size)
return (void*) ptr;
}
// Duplicate in pool
void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size)
{
void *NewPtr;
// Dup of null pointer is also NULL
if (ptr == NULL)
return NULL;
NewPtr = _cmsSubAlloc(s, size);
if (ptr != NULL && NewPtr != NULL) {
memcpy(NewPtr, ptr, size);
}
return NewPtr;
}
// Error logging ******************************************************************
// There is no error handling at all. When a funtion fails, it returns proper value.
@ -401,8 +471,26 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size)
// This is our default log error
static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text);
// The current handler in actual environment
static cmsLogErrorHandlerFunction LogErrorHandler = DefaultLogErrorHandlerFunction;
// Context0 storage, which is global
_cmsLogErrorChunkType _cmsLogErrorChunk = { DefaultLogErrorHandlerFunction };
// Allocates and inits error logger container for a given context. If src is NULL, only initializes the value
// to the default. Otherwise, it duplicates the value. The interface is standard across all context clients
void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction };
void* from;
if (src != NULL) {
from = src ->chunks[Logger];
}
else {
from = &LogErrorChunk;
}
ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType));
}
// The default error logger does nothing.
static
@ -416,13 +504,24 @@ void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorC
cmsUNUSED_PARAMETER(Text);
}
// Change log error
// Change log error, context based
void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn)
{
_cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger);
if (lhg != NULL) {
if (Fn == NULL)
lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction;
else
lhg -> LogErrorHandler = Fn;
}
}
// Change log error, legacy
void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn)
{
if (Fn == NULL)
LogErrorHandler = DefaultLogErrorHandlerFunction;
else
LogErrorHandler = Fn;
cmsSetLogErrorHandlerTHR(NULL, Fn);
}
// Log an error
@ -431,13 +530,18 @@ void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, c
{
va_list args;
char Buffer[MAX_ERROR_MESSAGE_LEN];
_cmsLogErrorChunkType* lhg;
va_start(args, ErrorText);
vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args);
va_end(args);
// Call handler
LogErrorHandler(ContextID, ErrorCode, Buffer);
// Check for the context, if specified go there. If not, go for the global
lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger);
if (lhg ->LogErrorHandler) {
lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer);
}
}
// Utility function to print signatures
@ -455,3 +559,125 @@ void _cmsTagSignature2String(char String[5], cmsTagSignature sig)
String[4] = 0;
}
//--------------------------------------------------------------------------------------------------
static
void* defMtxCreate(cmsContext id)
{
_cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex));
_cmsInitMutexPrimitive(ptr_mutex);
return (void*) ptr_mutex;
}
static
void defMtxDestroy(cmsContext id, void* mtx)
{
_cmsDestroyMutexPrimitive((_cmsMutex *) mtx);
_cmsFree(id, mtx);
}
static
cmsBool defMtxLock(cmsContext id, void* mtx)
{
cmsUNUSED_PARAMETER(id);
return _cmsLockPrimitive((_cmsMutex *) mtx) == 0;
}
static
void defMtxUnlock(cmsContext id, void* mtx)
{
cmsUNUSED_PARAMETER(id);
_cmsUnlockPrimitive((_cmsMutex *) mtx);
}
// Pointers to memory manager functions in Context0
_cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock };
// Allocate and init mutex container.
void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock };
void* from;
if (src != NULL) {
from = src ->chunks[MutexPlugin];
}
else {
from = &MutexChunk;
}
ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType));
}
// Register new ways to transform
cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
cmsPluginMutex* Plugin = (cmsPluginMutex*) Data;
_cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
if (Data == NULL) {
// No lock routines
ctx->CreateMutexPtr = NULL;
ctx->DestroyMutexPtr = NULL;
ctx->LockMutexPtr = NULL;
ctx ->UnlockMutexPtr = NULL;
return TRUE;
}
// Factory callback is required
if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL ||
Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE;
ctx->CreateMutexPtr = Plugin->CreateMutexPtr;
ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr;
ctx ->LockMutexPtr = Plugin ->LockMutexPtr;
ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr;
// All is ok
return TRUE;
}
// Generic Mutex fns
void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID)
{
_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
if (ptr ->CreateMutexPtr == NULL) return NULL;
return ptr ->CreateMutexPtr(ContextID);
}
void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx)
{
_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
if (ptr ->DestroyMutexPtr != NULL) {
ptr ->DestroyMutexPtr(ContextID, mtx);
}
}
cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx)
{
_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
if (ptr ->LockMutexPtr == NULL) return TRUE;
return ptr ->LockMutexPtr(ContextID, mtx);
}
void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx)
{
_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
if (ptr ->UnlockMutexPtr != NULL) {
ptr ->UnlockMutexPtr(ContextID, mtx);
}
}

View File

@ -82,7 +82,6 @@ typedef struct _cmsParametricCurvesCollection_st {
} _cmsParametricCurvesCollection;
// This is the default (built-in) evaluator
static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R);
@ -95,22 +94,77 @@ static _cmsParametricCurvesCollection DefaultCurves = {
NULL // Next in chain
};
// Duplicates the zone of memory used by the plug-in in the new context
static
void DupPluginCurvesList(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
_cmsCurvesPluginChunkType newHead = { NULL };
_cmsParametricCurvesCollection* entry;
_cmsParametricCurvesCollection* Anterior = NULL;
_cmsCurvesPluginChunkType* head = (_cmsCurvesPluginChunkType*) src->chunks[CurvesPlugin];
_cmsAssert(head != NULL);
// Walk the list copying all nodes
for (entry = head->ParametricCurves;
entry != NULL;
entry = entry ->Next) {
_cmsParametricCurvesCollection *newEntry = ( _cmsParametricCurvesCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsParametricCurvesCollection));
if (newEntry == NULL)
return;
// We want to keep the linked list order, so this is a little bit tricky
newEntry -> Next = NULL;
if (Anterior)
Anterior -> Next = newEntry;
Anterior = newEntry;
if (newHead.ParametricCurves == NULL)
newHead.ParametricCurves = newEntry;
}
ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsCurvesPluginChunkType));
}
// The allocator have to follow the chain
void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
_cmsAssert(ctx != NULL);
if (src != NULL) {
// Copy all linked list
DupPluginCurvesList(ctx, src);
}
else {
static _cmsCurvesPluginChunkType CurvesPluginChunk = { NULL };
ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx ->MemPool, &CurvesPluginChunk, sizeof(_cmsCurvesPluginChunkType));
}
}
// The linked list head
static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves;
_cmsCurvesPluginChunkType _cmsCurvesPluginChunk = { NULL };
// As a way to install new parametric curves
cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext id, cmsPluginBase* Data)
cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
_cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin);
cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data;
_cmsParametricCurvesCollection* fl;
if (Data == NULL) {
ParametricCurves = &DefaultCurves;
ctx -> ParametricCurves = NULL;
return TRUE;
}
fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(id, sizeof(_cmsParametricCurvesCollection));
fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsParametricCurvesCollection));
if (fl == NULL) return FALSE;
// Copy the parameters
@ -126,8 +180,8 @@ cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext id, cmsPluginBase* Data)
memmove(fl->ParameterCount, Plugin ->ParameterCount, fl->nFunctions * sizeof(cmsUInt32Number));
// Keep linked list
fl ->Next = ParametricCurves;
ParametricCurves = fl;
fl ->Next = ctx->ParametricCurves;
ctx->ParametricCurves = fl;
// All is ok
return TRUE;
@ -149,12 +203,24 @@ int IsInSet(int Type, _cmsParametricCurvesCollection* c)
// Search for the collection which contains a specific type
static
_cmsParametricCurvesCollection *GetParametricCurveByType(int Type, int* index)
_cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, int Type, int* index)
{
_cmsParametricCurvesCollection* c;
int Position;
_cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin);
for (c = ParametricCurves; c != NULL; c = c ->Next) {
for (c = ctx->ParametricCurves; c != NULL; c = c ->Next) {
Position = IsInSet(Type, c);
if (Position != -1) {
if (index != NULL)
*index = Position;
return c;
}
}
// If none found, revert for defaults
for (c = &DefaultCurves; c != NULL; c = c ->Next) {
Position = IsInSet(Type, c);
@ -251,7 +317,7 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr
p ->Segments[i].SampledPoints = NULL;
c = GetParametricCurveByType(Segments[i].Type, NULL);
c = GetParametricCurveByType(ContextID, Segments[i].Type, NULL);
if (c != NULL)
p ->Evals[i] = c ->Evaluator;
}
@ -677,12 +743,12 @@ cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt
cmsCurveSegment Seg0;
int Pos = 0;
cmsUInt32Number size;
_cmsParametricCurvesCollection* c = GetParametricCurveByType(Type, &Pos);
_cmsParametricCurvesCollection* c = GetParametricCurveByType(ContextID, Type, &Pos);
_cmsAssert(Params != NULL);
if (c == NULL) {
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type);
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type);
return NULL;
}
@ -872,7 +938,10 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, con
_cmsAssert(InCurve != NULL);
// Try to reverse it analytically whatever possible
if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && InCurve -> Segments[0].Type <= 5) {
if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 &&
/* InCurve -> Segments[0].Type <= 5 */
GetParametricCurveByType(InCurve ->InterpParams->ContextID, InCurve ->Segments[0].Type, NULL) != NULL) {
return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID,
-(InCurve -> Segments[0].Type),

View File

@ -191,7 +191,7 @@ cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID,
out = ComputeKToLstar(ContextID, nPoints, 1,
Intents + (nProfiles - 1),
hProfiles + (nProfiles - 1),
&hProfiles [nProfiles - 1],
BPC + (nProfiles - 1),
AdaptationStates + (nProfiles - 1),
dwFlags);

View File

@ -62,31 +62,57 @@
static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags);
// This is the default factory
static cmsInterpFnFactory Interpolators = DefaultInterpolatorsFactory;
_cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL };
// The interpolation plug-in memory chunk allocator/dup
void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src)
{
void* from;
_cmsAssert(ctx != NULL);
if (src != NULL) {
from = src ->chunks[InterpPlugin];
}
else {
static _cmsInterpPluginChunkType InterpPluginChunk = { NULL };
from = &InterpPluginChunk;
}
_cmsAssert(from != NULL);
ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType));
}
// Main plug-in entry
cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data)
cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data;
_cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);
if (Data == NULL) {
Interpolators = DefaultInterpolatorsFactory;
ptr ->Interpolators = NULL;
return TRUE;
}
// Set replacement functions
Interpolators = Plugin ->InterpolatorsFactory;
ptr ->Interpolators = Plugin ->InterpolatorsFactory;
return TRUE;
}
// Set the interpolation method
cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p)
cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p)
{
// Invoke factory, possibly in the Plug-in
p ->Interpolation = Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags);
_cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);
p ->Interpolation.Lerp16 = NULL;
// Invoke factory, possibly in the Plug-in
if (ptr ->Interpolators != NULL)
p ->Interpolation = ptr->Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags);
// If unsupported by the plug-in, go for the LittleCMS default.
// If happens only if an extern plug-in is being used
@ -97,6 +123,7 @@ cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p)
if (p ->Interpolation.Lerp16 == NULL) {
return FALSE;
}
return TRUE;
}
@ -141,7 +168,7 @@ cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID,
p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i];
if (!_cmsSetInterpolationRoutine(p)) {
if (!_cmsSetInterpolationRoutine(ContextID, p)) {
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan);
_cmsFree(ContextID, p);
return NULL;

View File

@ -229,15 +229,14 @@ cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, con
if (ResData == NULL) return FALSE; // Housekeeping
// Check for available space. Clip.
if (iohandler ->UsedSpace + size > ResData->Size) {
size = ResData ->Size - iohandler ->UsedSpace;
if (ResData->Pointer + size > ResData->Size) {
size = ResData ->Size - ResData->Pointer;
}
if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing
memmove(ResData ->Block + ResData ->Pointer, Ptr, size);
ResData ->Pointer += size;
iohandler->UsedSpace += size;
if (ResData ->Pointer > iohandler->UsedSpace)
iohandler->UsedSpace = ResData ->Pointer;
@ -371,7 +370,7 @@ cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset)
static
cmsUInt32Number FileTell(cmsIOHANDLER* iohandler)
{
return ftell((FILE*)iohandler ->stream);
return (cmsUInt32Number) ftell((FILE*)iohandler ->stream);
}
// Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error
@ -414,7 +413,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha
cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName);
return NULL;
}
iohandler -> ReportedSize = cmsfilelength(fm);
iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(fm);
break;
case 'w':
@ -461,7 +460,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* S
iohandler -> ContextID = ContextID;
iohandler -> stream = (void*) Stream;
iohandler -> UsedSpace = 0;
iohandler -> ReportedSize = cmsfilelength(Stream);
iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(Stream);
iohandler -> PhysicalFile[0] = 0;
iohandler ->Read = FileRead;
@ -501,6 +500,9 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
// Set creation date/time
memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created));
// Create a mutex if the user provided proper plugin. NULL otherwise
Icc ->UsrMutex = _cmsCreateMutex(ContextID);
// Return the handle
return (cmsHPROFILE) Icc;
}
@ -579,9 +581,39 @@ int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks
return n;
}
// Deletes a tag entry
// Create a new tag entry
static
void _cmsDeleteTagByPos(_cmsICCPROFILE* Icc, int i)
{
_cmsAssert(Icc != NULL);
_cmsAssert(i >= 0);
if (Icc -> TagPtrs[i] != NULL) {
// Free previous version
if (Icc ->TagSaveAsRaw[i]) {
_cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
}
else {
cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];
if (TypeHandler != NULL) {
cmsTagTypeHandler LocalTypeHandler = *TypeHandler;
LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter
LocalTypeHandler.ICCVersion = Icc ->Version;
LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]);
Icc ->TagPtrs[i] = NULL;
}
}
}
}
// Creates a new tag entry
static
cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos)
{
@ -589,15 +621,15 @@ cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos)
// Search for the tag
i = _cmsSearchTag(Icc, sig, FALSE);
// Now let's do it easy. If the tag has been already written, that's an error
if (i >= 0) {
cmsSignalError(Icc ->ContextID, cmsERROR_ALREADY_DEFINED, "Tag '%x' already exists", sig);
return FALSE;
// Already exists? delete it
_cmsDeleteTagByPos(Icc, i);
*NewPos = i;
}
else {
// New one
// No, make a new one
if (Icc -> TagCount >= MAX_TABLE_TAG) {
cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG);
@ -979,7 +1011,7 @@ void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Vers
// 4.2 -> 0x4200000
Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0), 10, 16) << 16;
Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0 + 0.5), 10, 16) << 16;
}
cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile)
@ -1011,6 +1043,32 @@ Error:
return NULL;
}
// Create profile from IOhandler
cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write)
{
_cmsICCPROFILE* NewIcc;
cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);
if (hEmpty == NULL) return NULL;
NewIcc = (_cmsICCPROFILE*) hEmpty;
NewIcc ->IOhandler = io;
if (write) {
NewIcc -> IsWrite = TRUE;
return hEmpty;
}
if (!_cmsReadHeader(NewIcc)) goto Error;
return hEmpty;
Error:
cmsCloseProfile(hEmpty);
return NULL;
}
// Create profile from disk file
cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess)
{
@ -1202,7 +1260,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig)
else {
// Search for support on this tag
TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]);
TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, Icc -> TagNames[i]);
if (TagDescriptor == NULL) continue; // Unsupported, ignore it
if (TagDescriptor ->DecideType != NULL) {
@ -1214,7 +1272,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig)
Type = TagDescriptor ->SupportedTypes[0];
}
TypeHandler = _cmsGetTagTypeHandler(Type);
TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type);
if (TypeHandler == NULL) {
cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]);
@ -1282,10 +1340,12 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH
{
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
_cmsICCPROFILE Keep;
cmsIOHANDLER* PrevIO;
cmsIOHANDLER* PrevIO = NULL;
cmsUInt32Number UsedSpace;
cmsContext ContextID;
_cmsAssert(hProfile != NULL);
memmove(&Keep, Icc, sizeof(_cmsICCPROFILE));
ContextID = cmsGetProfileContextID(hProfile);
@ -1294,18 +1354,19 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH
// Pass #1 does compute offsets
if (!_cmsWriteHeader(Icc, 0)) return 0;
if (!SaveTags(Icc, &Keep)) return 0;
if (!_cmsWriteHeader(Icc, 0)) goto Error;
if (!SaveTags(Icc, &Keep)) goto Error;
UsedSpace = PrevIO ->UsedSpace;
// Pass #2 does save to iohandler
if (io != NULL) {
Icc ->IOhandler = io;
if (!SetLinks(Icc)) goto CleanUp;
if (!_cmsWriteHeader(Icc, UsedSpace)) goto CleanUp;
if (!SaveTags(Icc, &Keep)) goto CleanUp;
if (!SetLinks(Icc)) goto Error;
if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error;
if (!SaveTags(Icc, &Keep)) goto Error;
}
memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
@ -1314,7 +1375,7 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH
return UsedSpace;
CleanUp:
Error:
cmsCloseIOhandler(PrevIO);
memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
return 0;
@ -1362,11 +1423,13 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn
cmsIOHANDLER* io;
cmsContext ContextID = cmsGetProfileContextID(hProfile);
_cmsAssert(BytesNeeded != NULL);
// Should we just calculate the needed space?
if (MemPtr == NULL) {
*BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL);
return (*BytesNeeded == 0 ? FALSE : TRUE);
return (*BytesNeeded == 0) ? FALSE : TRUE;
}
// That is a real write operation
@ -1419,6 +1482,8 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
rc &= cmsCloseIOhandler(Icc->IOhandler);
}
_cmsDestroyMutex(Icc->ContextID, Icc->UsrMutex);
_cmsFree(Icc ->ContextID, Icc); // Free placeholder memory
return rc;
@ -1459,14 +1524,18 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
cmsUInt32Number ElemCount;
int n;
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL;
n = _cmsSearchTag(Icc, sig, TRUE);
if (n < 0) return NULL; // Not found, return NULL
if (n < 0) goto Error; // Not found, return NULL
// If the element is already in memory, return the pointer
if (Icc -> TagPtrs[n]) {
if (Icc ->TagSaveAsRaw[n]) return NULL; // We don't support read raw tags as cooked
if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return Icc -> TagPtrs[n];
}
@ -1476,23 +1545,32 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
// Seek to its location
if (!io -> Seek(io, Offset))
return NULL;
goto Error;
// Search for support on this tag
TagDescriptor = _cmsGetTagDescriptor(sig);
if (TagDescriptor == NULL) return NULL; // Unsupported.
TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig);
if (TagDescriptor == NULL) {
char String[5];
_cmsTagSignature2String(String, sig);
// An unknown element was found.
cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown tag type '%s' found.", String);
goto Error; // Unsupported.
}
// if supported, get type and check if in list
BaseType = _cmsReadTypeBase(io);
if (BaseType == 0) return NULL;
if (BaseType == 0) goto Error;
if (!IsTypeSupported(TagDescriptor, BaseType)) return NULL;
if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error;
TagSize -= 8; // Alredy read by the type base logic
// Get type handler
TypeHandler = _cmsGetTagTypeHandler(BaseType);
if (TypeHandler == NULL) return NULL;
TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType);
if (TypeHandler == NULL) goto Error;
LocalTypeHandler = *TypeHandler;
@ -1511,7 +1589,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
_cmsTagSignature2String(String, sig);
cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String);
return NULL;
goto Error;
}
// This is a weird error that may be a symptom of something more serious, the number of
@ -1527,7 +1605,14 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
// Return the data
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return Icc -> TagPtrs[n];
// Return error and unlock tha data
Error:
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return NULL;
}
@ -1561,49 +1646,26 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
cmsFloat64Number Version;
char TypeString[5], SigString[5];
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE;
// To delete tags.
if (data == NULL) {
// Delete the tag
i = _cmsSearchTag(Icc, sig, FALSE);
if (i >= 0)
if (i >= 0) {
// Use zero as a mark of deleted
_cmsDeleteTagByPos(Icc, i);
Icc ->TagNames[i] = (cmsTagSignature) 0;
// Unsupported by now, reserved for future ampliations (delete)
return FALSE;
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return TRUE;
}
// Didn't find the tag
goto Error;
}
i = _cmsSearchTag(Icc, sig, FALSE);
if (i >=0) {
if (Icc -> TagPtrs[i] != NULL) {
// Already exists. Free previous version
if (Icc ->TagSaveAsRaw[i]) {
_cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
}
else {
TypeHandler = Icc ->TagTypeHandlers[i];
if (TypeHandler != NULL) {
LocalTypeHandler = *TypeHandler;
LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter
LocalTypeHandler.ICCVersion = Icc ->Version;
LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]);
}
}
}
}
else {
// New one
i = Icc -> TagCount;
if (i >= MAX_TABLE_TAG) {
cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG);
return FALSE;
}
Icc -> TagCount++;
}
if (!_cmsNewTag(Icc, sig, &i)) goto Error;
// This is not raw
Icc ->TagSaveAsRaw[i] = FALSE;
@ -1612,10 +1674,10 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
Icc ->TagLinked[i] = (cmsTagSignature) 0;
// Get information about the TAG.
TagDescriptor = _cmsGetTagDescriptor(sig);
TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig);
if (TagDescriptor == NULL){
cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig);
return FALSE;
goto Error;
}
@ -1633,7 +1695,6 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
}
else {
Type = TagDescriptor ->SupportedTypes[0];
}
@ -1644,18 +1705,18 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
_cmsTagSignature2String(SigString, sig);
cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString);
return FALSE;
goto Error;
}
// Does we have a handler for this type?
TypeHandler = _cmsGetTagTypeHandler(Type);
TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type);
if (TypeHandler == NULL) {
_cmsTagSignature2String(TypeString, (cmsTagSignature) Type);
_cmsTagSignature2String(SigString, sig);
cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString);
return FALSE; // Should never happen
goto Error; // Should never happen
}
@ -1668,7 +1729,7 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
LocalTypeHandler = *TypeHandler;
LocalTypeHandler.ContextID = Icc ->ContextID;
LocalTypeHandler.ICCVersion = Icc ->Version;
Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount);
Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount);
if (Icc ->TagPtrs[i] == NULL) {
@ -1676,10 +1737,16 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
_cmsTagSignature2String(SigString, sig);
cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString);
return FALSE;
goto Error;
}
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return TRUE;
Error:
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return FALSE;
}
// Read and write raw data. The only way those function would work and keep consistence with normal read and write
@ -1700,9 +1767,11 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
cmsUInt32Number rc;
cmsUInt32Number Offset, TagSize;
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;
// Search for given tag in ICC profile directory
i = _cmsSearchTag(Icc, sig, TRUE);
if (i < 0) return 0; // Not found, return 0
if (i < 0) goto Error; // Not found,
// It is already read?
if (Icc -> TagPtrs[i] == NULL) {
@ -1717,12 +1786,14 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
if (BufferSize < TagSize)
TagSize = BufferSize;
if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0;
if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0;
if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error;
if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error;
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return TagSize;
}
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return Icc ->TagSizes[i];
}
@ -1738,16 +1809,22 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
memmove(data, Icc ->TagPtrs[i], TagSize);
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return TagSize;
}
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return Icc ->TagSizes[i];
}
// Already readed, or previously set by cmsWriteTag(). We need to serialize that
// data to raw in order to maintain consistency.
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
Object = cmsReadTag(hProfile, sig);
if (Object == NULL) return 0;
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;
if (Object == NULL) goto Error;
// Now we need to serialize to a memory block: just use a memory iohandler
@ -1756,17 +1833,18 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
} else{
MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w");
}
if (MemIO == NULL) return 0;
if (MemIO == NULL) goto Error;
// Obtain type handling for the tag
TypeHandler = Icc ->TagTypeHandlers[i];
TagDescriptor = _cmsGetTagDescriptor(sig);
TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig);
if (TagDescriptor == NULL) {
cmsCloseIOhandler(MemIO);
return 0;
goto Error;
}
// FIXME: No handling for TypeHandler == NULL here?
if (TypeHandler == NULL) goto Error;
// Serialize
LocalTypeHandler = *TypeHandler;
LocalTypeHandler.ContextID = Icc ->ContextID;
@ -1774,19 +1852,24 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) {
cmsCloseIOhandler(MemIO);
return 0;
goto Error;
}
if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) {
cmsCloseIOhandler(MemIO);
return 0;
goto Error;
}
// Get Size and close
rc = MemIO ->Tell(MemIO);
cmsCloseIOhandler(MemIO); // Ignore return code this time
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return rc;
Error:
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return 0;
}
// Similar to the anterior. This function allows to write directly to the ICC profile any data, without
@ -1798,7 +1881,12 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
int i;
if (!_cmsNewTag(Icc, sig, &i)) return FALSE;
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;
if (!_cmsNewTag(Icc, sig, &i)) {
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return FALSE;
}
// Mark the tag as being written as RAW
Icc ->TagSaveAsRaw[i] = TRUE;
@ -1809,6 +1897,7 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons
Icc ->TagPtrs[i] = _cmsDupMem(Icc ->ContextID, data, Size);
Icc ->TagSizes[i] = Size;
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return TRUE;
}
@ -1818,7 +1907,12 @@ cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSi
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
int i;
if (!_cmsNewTag(Icc, sig, &i)) return FALSE;
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE;
if (!_cmsNewTag(Icc, sig, &i)) {
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return FALSE;
}
// Keep necessary information
Icc ->TagSaveAsRaw[i] = FALSE;
@ -1829,6 +1923,7 @@ cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSi
Icc ->TagSizes[i] = 0;
Icc ->TagOffsets[i] = 0;
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return TRUE;
}

View File

@ -334,7 +334,8 @@ Error:
// Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc
// is adjusted here in order to create a LUT that takes care of all those details
// is adjusted here in order to create a LUT that takes care of all those details.
// We add intent = -1 as a way to read matrix shaper always, no matter of other LUT
cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
{
cmsTagTypeSignature OriginalType;
@ -364,49 +365,54 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
return Lut;
}
if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
// This is an attempt to reuse this funtion to retrieve the matrix-shaper as pipeline no
// matter other LUT are present and have precedence. Intent = -1 means just this.
if (Intent != -1) {
// Floating point LUT are always V4, but the encoding range is no
// longer 0..1.0, so we need to add an stage depending on the color space
return _cmsReadFloatInputTag(hProfile, tagFloat);
}
if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
// Revert to perceptual if no tag is found
if (!cmsIsTag(hProfile, tag16)) {
tag16 = Device2PCS16[0];
}
// Floating point LUT are always V4, but the encoding range is no
// longer 0..1.0, so we need to add an stage depending on the color space
return _cmsReadFloatInputTag(hProfile, tagFloat);
}
if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
// Revert to perceptual if no tag is found
if (!cmsIsTag(hProfile, tag16)) {
tag16 = Device2PCS16[0];
}
// Check profile version and LUT type. Do the necessary adjustments if needed
if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
// First read the tag
cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
if (Lut == NULL) return NULL;
// Check profile version and LUT type. Do the necessary adjustments if needed
// After reading it, we have now info about the original type
OriginalType = _cmsGetTagTrueType(hProfile, tag16);
// First read the tag
cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
if (Lut == NULL) return NULL;
// The profile owns the Lut, so we need to copy it
Lut = cmsPipelineDup(Lut);
// After reading it, we have now info about the original type
OriginalType = _cmsGetTagTrueType(hProfile, tag16);
// The profile owns the Lut, so we need to copy it
Lut = cmsPipelineDup(Lut);
// We need to adjust data only for Lab16 on output
if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
return Lut;
// If the input is Lab, add also a conversion at the begin
if (cmsGetColorSpace(hProfile) == cmsSigLabData &&
!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
goto Error;
// Add a matrix for conversion V2 to V4 Lab PCS
if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
goto Error;
// We need to adjust data only for Lab16 on output
if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
return Lut;
// If the input is Lab, add also a conversion at the begin
if (cmsGetColorSpace(hProfile) == cmsSigLabData &&
!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
goto Error;
// Add a matrix for conversion V2 to V4 Lab PCS
if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
goto Error;
return Lut;
Error:
cmsPipelineFree(Lut);
return NULL;
cmsPipelineFree(Lut);
return NULL;
}
}
// Lut was not found, try to create a matrix-shaper
@ -551,7 +557,7 @@ void ChangeInterpolationToTrilinear(cmsPipeline* Lut)
_cmsStageCLutData* CLUT = (_cmsStageCLutData*) Stage ->Data;
CLUT ->Params->dwFlags |= CMS_LERP_FLAGS_TRILINEAR;
_cmsSetInterpolationRoutine(CLUT ->Params);
_cmsSetInterpolationRoutine(Lut->ContextID, CLUT ->Params);
}
}
}
@ -609,54 +615,58 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent)
cmsTagSignature tagFloat = PCS2DeviceFloat[Intent];
cmsContext ContextID = cmsGetProfileContextID(hProfile);
if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
// Floating point LUT are always V4
return _cmsReadFloatOutputTag(hProfile, tagFloat);
}
if (Intent != -1) {
// Revert to perceptual if no tag is found
if (!cmsIsTag(hProfile, tag16)) {
tag16 = PCS2Device16[0];
}
if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
// Floating point LUT are always V4
return _cmsReadFloatOutputTag(hProfile, tagFloat);
}
// Check profile version and LUT type. Do the necessary adjustments if needed
// Revert to perceptual if no tag is found
if (!cmsIsTag(hProfile, tag16)) {
tag16 = PCS2Device16[0];
}
// First read the tag
cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
if (Lut == NULL) return NULL;
if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
// After reading it, we have info about the original type
OriginalType = _cmsGetTagTrueType(hProfile, tag16);
// Check profile version and LUT type. Do the necessary adjustments if needed
// The profile owns the Lut, so we need to copy it
Lut = cmsPipelineDup(Lut);
if (Lut == NULL) return NULL;
// First read the tag
cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
if (Lut == NULL) return NULL;
// Now it is time for a controversial stuff. I found that for 3D LUTS using
// Lab used as indexer space, trilinear interpolation should be used
if (cmsGetPCS(hProfile) == cmsSigLabData)
ChangeInterpolationToTrilinear(Lut);
// After reading it, we have info about the original type
OriginalType = _cmsGetTagTrueType(hProfile, tag16);
// We need to adjust data only for Lab and Lut16 type
if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
return Lut;
// The profile owns the Lut, so we need to copy it
Lut = cmsPipelineDup(Lut);
if (Lut == NULL) return NULL;
// Add a matrix for conversion V4 to V2 Lab PCS
if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
goto Error;
// Now it is time for a controversial stuff. I found that for 3D LUTS using
// Lab used as indexer space, trilinear interpolation should be used
if (cmsGetPCS(hProfile) == cmsSigLabData)
ChangeInterpolationToTrilinear(Lut);
// If the output is Lab, add also a conversion at the end
if (cmsGetColorSpace(hProfile) == cmsSigLabData)
if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
// We need to adjust data only for Lab and Lut16 type
if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
return Lut;
// Add a matrix for conversion V4 to V2 Lab PCS
if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
goto Error;
return Lut;
// If the output is Lab, add also a conversion at the end
if (cmsGetColorSpace(hProfile) == cmsSigLabData)
if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
goto Error;
return Lut;
Error:
cmsPipelineFree(Lut);
return NULL;
cmsPipelineFree(Lut);
return NULL;
}
}
// Lut not found, try to create a matrix-shaper
@ -782,7 +792,7 @@ Error:
// Now it is time for a controversial stuff. I found that for 3D LUTS using
// Lab used as indexer space, trilinear interpolation should be used
if (cmsGetColorSpace(hProfile) == cmsSigLabData)
if (cmsGetPCS(hProfile) == cmsSigLabData)
ChangeInterpolationToTrilinear(Lut);
// After reading it, we have info about the original type
@ -793,12 +803,12 @@ Error:
// Here it is possible to get Lab on both sides
if (cmsGetPCS(hProfile) == cmsSigLabData) {
if (cmsGetColorSpace(hProfile) == cmsSigLabData) {
if(!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
goto Error2;
}
if (cmsGetColorSpace(hProfile) == cmsSigLabData) {
if (cmsGetPCS(hProfile) == cmsSigLabData) {
if(!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
goto Error2;
}

View File

@ -542,11 +542,13 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor
cmsToneCurve* InversePostLin = cmsReverseToneCurve(Curves[i]);
if (InversePostLin == NULL) {
WhiteOut[i] = 0;
continue;
WhiteOut[i] = WhitePointOut[i];
} else {
WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]);
cmsFreeToneCurve(InversePostLin);
}
WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]);
cmsFreeToneCurve(InversePostLin);
}
}
else {
@ -1666,44 +1668,102 @@ static _cmsOptimizationCollection DefaultOptimization[] = {
};
// The linked list head
static _cmsOptimizationCollection* OptimizationCollection = DefaultOptimization;
_cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk = { NULL };
// Duplicates the zone of memory used by the plug-in in the new context
static
void DupPluginOptimizationList(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
_cmsOptimizationPluginChunkType newHead = { NULL };
_cmsOptimizationCollection* entry;
_cmsOptimizationCollection* Anterior = NULL;
_cmsOptimizationPluginChunkType* head = (_cmsOptimizationPluginChunkType*) src->chunks[OptimizationPlugin];
_cmsAssert(ctx != NULL);
_cmsAssert(head != NULL);
// Walk the list copying all nodes
for (entry = head->OptimizationCollection;
entry != NULL;
entry = entry ->Next) {
_cmsOptimizationCollection *newEntry = ( _cmsOptimizationCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsOptimizationCollection));
if (newEntry == NULL)
return;
// We want to keep the linked list order, so this is a little bit tricky
newEntry -> Next = NULL;
if (Anterior)
Anterior -> Next = newEntry;
Anterior = newEntry;
if (newHead.OptimizationCollection == NULL)
newHead.OptimizationCollection = newEntry;
}
ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsOptimizationPluginChunkType));
}
void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
if (src != NULL) {
// Copy all linked list
DupPluginOptimizationList(ctx, src);
}
else {
static _cmsOptimizationPluginChunkType OptimizationPluginChunkType = { NULL };
ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx ->MemPool, &OptimizationPluginChunkType, sizeof(_cmsOptimizationPluginChunkType));
}
}
// Register new ways to optimize
cmsBool _cmsRegisterOptimizationPlugin(cmsContext id, cmsPluginBase* Data)
cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data;
_cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin);
_cmsOptimizationCollection* fl;
if (Data == NULL) {
OptimizationCollection = DefaultOptimization;
ctx->OptimizationCollection = NULL;
return TRUE;
}
// Optimizer callback is required
if (Plugin ->OptimizePtr == NULL) return FALSE;
fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(id, sizeof(_cmsOptimizationCollection));
fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsOptimizationCollection));
if (fl == NULL) return FALSE;
// Copy the parameters
fl ->OptimizePtr = Plugin ->OptimizePtr;
// Keep linked list
fl ->Next = OptimizationCollection;
OptimizationCollection = fl;
fl ->Next = ctx->OptimizationCollection;
// Set the head
ctx ->OptimizationCollection = fl;
// All is ok
return TRUE;
}
// The entry point for LUT optimization
cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut,
cmsBool _cmsOptimizePipeline(cmsContext ContextID,
cmsPipeline** PtrLut,
int Intent,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
cmsUInt32Number* dwFlags)
{
_cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin);
_cmsOptimizationCollection* Opts;
cmsBool AnySuccess = FALSE;
@ -1733,8 +1793,8 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut,
if (*dwFlags & cmsFLAGS_NOOPTIMIZE)
return FALSE;
// Try built-in optimizations and plug-in
for (Opts = OptimizationCollection;
// Try plug-in optimizations
for (Opts = ctx->OptimizationCollection;
Opts != NULL;
Opts = Opts ->Next) {
@ -1745,6 +1805,17 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut,
}
}
// Try built-in optimizations
for (Opts = DefaultOptimization;
Opts != NULL;
Opts = Opts ->Next) {
if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) {
return TRUE;
}
}
// Only simple optimizations succeeded
return AnySuccess;
}

View File

@ -883,6 +883,42 @@ cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info,
}
}
// This is a conversion of XYZ float to 16 bits
static
cmsUInt8Number* UnrollXYZFloatTo16(register _cmsTRANSFORM* info,
register cmsUInt16Number wIn[],
register cmsUInt8Number* accum,
register cmsUInt32Number Stride)
{
if (T_PLANAR(info -> InputFormat)) {
cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
cmsCIEXYZ XYZ;
XYZ.X = Pt[0];
XYZ.Y = Pt[Stride];
XYZ.Z = Pt[Stride*2];
cmsFloat2XYZEncoded(wIn, &XYZ);
return accum + sizeof(cmsFloat32Number);
}
else {
cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
cmsCIEXYZ XYZ;
XYZ.X = Pt[0];
XYZ.Y = Pt[1];
XYZ.Z = Pt[2];
cmsFloat2XYZEncoded(wIn, &XYZ);
accum += 3 * sizeof(cmsFloat32Number) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat32Number);
return accum;
}
}
// Check if space is marked as ink
cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type)
{
@ -2333,6 +2369,39 @@ cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info,
}
}
static
cmsUInt8Number* PackXYZFloatFrom16(register _cmsTRANSFORM* Info,
register cmsUInt16Number wOut[],
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
if (T_PLANAR(Info -> OutputFormat)) {
cmsCIEXYZ XYZ;
cmsFloat32Number* Out = (cmsFloat32Number*) output;
cmsXYZEncoded2Float(&XYZ, wOut);
Out[0] = (cmsFloat32Number) XYZ.X;
Out[Stride] = (cmsFloat32Number) XYZ.Y;
Out[Stride*2] = (cmsFloat32Number) XYZ.Z;
return output + sizeof(cmsFloat32Number);
}
else {
cmsCIEXYZ XYZ;
cmsFloat32Number* Out = (cmsFloat32Number*) output;
cmsXYZEncoded2Float(&XYZ, wOut);
Out[0] = (cmsFloat32Number) XYZ.X;
Out[1] = (cmsFloat32Number) XYZ.Y;
Out[2] = (cmsFloat32Number) XYZ.Z;
return output + (3 * sizeof(cmsFloat32Number) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
}
}
static
cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info,
register cmsUInt16Number wOut[],
@ -2893,6 +2962,7 @@ static cmsFormatters16 InputFormatters16[] = {
{ TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleTo16},
{ TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleTo16},
{ TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatTo16},
{ TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatTo16},
{ TYPE_GRAY_DBL, 0, UnrollDouble1Chan},
{ FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
ANYSWAP|ANYEXTRA|ANYSPACE, UnrollDoubleTo16},
@ -3027,6 +3097,7 @@ static cmsFormatters16 OutputFormatters16[] = {
{ TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFrom16},
{ TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFrom16},
{ TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, PackXYZFloatFrom16},
{ FLOAT_SH(1)|BYTES_SH(0), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackDoubleFrom16},
@ -3182,40 +3253,98 @@ typedef struct _cms_formatters_factory_list {
} cmsFormattersFactoryList;
static cmsFormattersFactoryList* FactoryList = NULL;
_cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL };
// Duplicates the zone of memory used by the plug-in in the new context
static
void DupFormatterFactoryList(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
_cmsFormattersPluginChunkType newHead = { NULL };
cmsFormattersFactoryList* entry;
cmsFormattersFactoryList* Anterior = NULL;
_cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin];
_cmsAssert(head != NULL);
// Walk the list copying all nodes
for (entry = head->FactoryList;
entry != NULL;
entry = entry ->Next) {
cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList));
if (newEntry == NULL)
return;
// We want to keep the linked list order, so this is a little bit tricky
newEntry -> Next = NULL;
if (Anterior)
Anterior -> Next = newEntry;
Anterior = newEntry;
if (newHead.FactoryList == NULL)
newHead.FactoryList = newEntry;
}
ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType));
}
// The interpolation plug-in memory chunk allocator/dup
void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
_cmsAssert(ctx != NULL);
if (src != NULL) {
// Duplicate the LIST
DupFormatterFactoryList(ctx, src);
}
else {
static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL };
ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType));
}
}
// Formatters management
cmsBool _cmsRegisterFormattersPlugin(cmsContext id, cmsPluginBase* Data)
cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
_cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data;
cmsFormattersFactoryList* fl ;
// Reset
// Reset to built-in defaults
if (Data == NULL) {
FactoryList = NULL;
ctx ->FactoryList = NULL;
return TRUE;
}
fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(id, sizeof(cmsFormattersFactoryList));
fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList));
if (fl == NULL) return FALSE;
fl ->Factory = Plugin ->FormattersFactory;
fl ->Next = FactoryList;
FactoryList = fl;
fl ->Next = ctx -> FactoryList;
ctx ->FactoryList = fl;
return TRUE;
}
cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
cmsFormatter _cmsGetFormatter(cmsContext ContextID,
cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
cmsFormatterDirection Dir,
cmsUInt32Number dwFlags)
{
_cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
cmsFormattersFactoryList* f;
for (f = FactoryList; f != NULL; f = f ->Next) {
for (f =ctx->FactoryList; f != NULL; f = f ->Next) {
cmsFormatter fn = f ->Factory(Type, Dir, dwFlags);
if (fn.Fmt16 != NULL) return fn;

View File

@ -544,22 +544,31 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
// Plugin memory management -------------------------------------------------------------------------------------------------
static _cmsSubAllocator* PluginPool = NULL;
// Specialized malloc for plug-ins, that is freed upon exit.
void* _cmsPluginMalloc(cmsContext id, cmsUInt32Number size)
void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size)
{
if (PluginPool == NULL)
PluginPool = _cmsCreateSubAlloc(id, 4*1024);
struct _cmsContext_struct* ctx = _cmsGetContext(ContextID);
return _cmsSubAlloc(PluginPool, size);
if (ctx ->MemPool == NULL) {
if (ContextID == NULL) {
ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024);
}
else {
cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context");
return NULL;
}
}
return _cmsSubAlloc(ctx->MemPool, size);
}
// Main plug-in dispatcher
cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
{
return cmsPluginTHR(NULL, Plug_in);
return cmsPluginTHR(NULL, Plug_in);
}
cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
@ -571,12 +580,12 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
Plugin = Plugin -> Next) {
if (Plugin -> Magic != cmsPluginMagicNumber) {
cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
return FALSE;
}
if (Plugin ->ExpectedVersion > LCMS_VERSION) {
cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
Plugin ->ExpectedVersion, LCMS_VERSION);
return FALSE;
}
@ -584,11 +593,11 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
switch (Plugin -> Type) {
case cmsPluginMemHandlerSig:
if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE;
if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginInterpolationSig:
if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE;
if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginTagTypeSig:
@ -623,8 +632,12 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginMutexSig:
if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE;
break;
default:
cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
return FALSE;
}
}
@ -637,19 +650,337 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
// Revert all plug-ins to default
void CMSEXPORT cmsUnregisterPlugins(void)
{
_cmsRegisterMemHandlerPlugin(NULL);
_cmsRegisterInterpPlugin(NULL);
_cmsRegisterTagTypePlugin(NULL, NULL);
_cmsRegisterTagPlugin(NULL, NULL);
_cmsRegisterFormattersPlugin(NULL, NULL);
_cmsRegisterRenderingIntentPlugin(NULL, NULL);
_cmsRegisterParametricCurvesPlugin(NULL, NULL);
_cmsRegisterMultiProcessElementPlugin(NULL, NULL);
_cmsRegisterOptimizationPlugin(NULL, NULL);
_cmsRegisterTransformPlugin(NULL, NULL);
if (PluginPool != NULL)
_cmsSubAllocDestroy(PluginPool);
PluginPool = NULL;
cmsUnregisterPluginsTHR(NULL);
}
// The Global storage for system context. This is the one and only global variable
// pointers structure. All global vars are referenced here.
static struct _cmsContext_struct globalContext = {
NULL, // Not in the linked list
NULL, // No suballocator
{
NULL, // UserPtr,
&_cmsLogErrorChunk, // Logger,
&_cmsAlarmCodesChunk, // AlarmCodes,
&_cmsAdaptationStateChunk, // AdaptationState,
&_cmsMemPluginChunk, // MemPlugin,
&_cmsInterpPluginChunk, // InterpPlugin,
&_cmsCurvesPluginChunk, // CurvesPlugin,
&_cmsFormattersPluginChunk, // FormattersPlugin,
&_cmsTagTypePluginChunk, // TagTypePlugin,
&_cmsTagPluginChunk, // TagPlugin,
&_cmsIntentsPluginChunk, // IntentPlugin,
&_cmsMPETypePluginChunk, // MPEPlugin,
&_cmsOptimizationPluginChunk, // OptimizationPlugin,
&_cmsTransformPluginChunk, // TransformPlugin,
&_cmsMutexPluginChunk // MutexPlugin
},
{ NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0
};
// The context pool (linked list head)
static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
static struct _cmsContext_struct* _cmsContextPoolHead = NULL;
// Internal, get associated pointer, with guessing. Never returns NULL.
struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
{
struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;
struct _cmsContext_struct* ctx;
// On 0, use global settings
if (id == NULL)
return &globalContext;
// Search
for (ctx = _cmsContextPoolHead;
ctx != NULL;
ctx = ctx ->Next) {
// Found it?
if (id == ctx)
return ctx; // New-style context,
}
return &globalContext;
}
// Internal: get the memory area associanted with each context client
// Returns the block assigned to the specific zone.
void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc)
{
struct _cmsContext_struct* ctx;
void *ptr;
if (mc < 0 || mc >= MemoryClientMax) {
cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client");
return NULL;
}
ctx = _cmsGetContext(ContextID);
ptr = ctx ->chunks[mc];
if (ptr != NULL)
return ptr;
// A null ptr means no special settings for that context, and this
// reverts to Context0 globals
return globalContext.chunks[mc];
}
// This function returns the given context its default pristine state,
// as no plug-ins were declared. There is no way to unregister a single
// plug-in, as a single call to cmsPluginTHR() function may register
// many different plug-ins simultaneously, then there is no way to
// identify which plug-in to unregister.
void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID)
{
_cmsRegisterMemHandlerPlugin(ContextID, NULL);
_cmsRegisterInterpPlugin(ContextID, NULL);
_cmsRegisterTagTypePlugin(ContextID, NULL);
_cmsRegisterTagPlugin(ContextID, NULL);
_cmsRegisterFormattersPlugin(ContextID, NULL);
_cmsRegisterRenderingIntentPlugin(ContextID, NULL);
_cmsRegisterParametricCurvesPlugin(ContextID, NULL);
_cmsRegisterMultiProcessElementPlugin(ContextID, NULL);
_cmsRegisterOptimizationPlugin(ContextID, NULL);
_cmsRegisterTransformPlugin(ContextID, NULL);
_cmsRegisterMutexPlugin(ContextID, NULL);
}
// Returns the memory manager plug-in, if any, from the Plug-in bundle
static
cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle)
{
cmsPluginBase* Plugin;
for (Plugin = (cmsPluginBase*) PluginBundle;
Plugin != NULL;
Plugin = Plugin -> Next) {
if (Plugin -> Magic == cmsPluginMagicNumber &&
Plugin -> ExpectedVersion <= LCMS_VERSION &&
Plugin -> Type == cmsPluginMemHandlerSig) {
// Found!
return (cmsPluginMemHandler*) Plugin;
}
}
// Nope, revert to defaults
return NULL;
}
// Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined
// data that will be forwarded to plug-ins and logger.
cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
{
struct _cmsContext_struct* ctx;
struct _cmsContext_struct fakeContext;
_cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
fakeContext.chunks[UserPtr] = UserData;
fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;
// Create the context structure.
ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct));
if (ctx == NULL)
return NULL; // Something very wrong happened!
// Init the structure and the memory manager
memset(ctx, 0, sizeof(struct _cmsContext_struct));
// Keep memory manager
memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk));
// Maintain the linked list (with proper locking)
_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
ctx ->Next = _cmsContextPoolHead;
_cmsContextPoolHead = ctx;
_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
ctx ->chunks[UserPtr] = UserData;
ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;
// Now we can allocate the pool by using default memory manager
ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 32 pointers
if (ctx ->MemPool == NULL) {
cmsDeleteContext(ctx);
return NULL;
}
_cmsAllocLogErrorChunk(ctx, NULL);
_cmsAllocAlarmCodesChunk(ctx, NULL);
_cmsAllocAdaptationStateChunk(ctx, NULL);
_cmsAllocMemPluginChunk(ctx, NULL);
_cmsAllocInterpPluginChunk(ctx, NULL);
_cmsAllocCurvesPluginChunk(ctx, NULL);
_cmsAllocFormattersPluginChunk(ctx, NULL);
_cmsAllocTagTypePluginChunk(ctx, NULL);
_cmsAllocMPETypePluginChunk(ctx, NULL);
_cmsAllocTagPluginChunk(ctx, NULL);
_cmsAllocIntentsPluginChunk(ctx, NULL);
_cmsAllocOptimizationPluginChunk(ctx, NULL);
_cmsAllocTransformPluginChunk(ctx, NULL);
_cmsAllocMutexPluginChunk(ctx, NULL);
// Setup the plug-ins
if (!cmsPluginTHR(ctx, Plugin)) {
cmsDeleteContext(ctx);
return NULL;
}
return (cmsContext) ctx;
}
// Duplicates a context with all associated plug-ins.
// Caller may specify an optional pointer to user-defined
// data that will be forwarded to plug-ins and logger.
cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
{
int i;
struct _cmsContext_struct* ctx;
const struct _cmsContext_struct* src = _cmsGetContext(ContextID);
void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr];
ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct));
if (ctx == NULL)
return NULL; // Something very wrong happened
// Setup default memory allocators
memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
// Maintain the linked list
_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
ctx ->Next = _cmsContextPoolHead;
_cmsContextPoolHead = ctx;
_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
ctx ->chunks[UserPtr] = userData;
ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;
ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));
if (ctx ->MemPool == NULL) {
cmsDeleteContext(ctx);
return NULL;
}
// Allocate all required chunks.
_cmsAllocLogErrorChunk(ctx, src);
_cmsAllocAlarmCodesChunk(ctx, src);
_cmsAllocAdaptationStateChunk(ctx, src);
_cmsAllocMemPluginChunk(ctx, src);
_cmsAllocInterpPluginChunk(ctx, src);
_cmsAllocCurvesPluginChunk(ctx, src);
_cmsAllocFormattersPluginChunk(ctx, src);
_cmsAllocTagTypePluginChunk(ctx, src);
_cmsAllocMPETypePluginChunk(ctx, src);
_cmsAllocTagPluginChunk(ctx, src);
_cmsAllocIntentsPluginChunk(ctx, src);
_cmsAllocOptimizationPluginChunk(ctx, src);
_cmsAllocTransformPluginChunk(ctx, src);
_cmsAllocMutexPluginChunk(ctx, src);
// Make sure no one failed
for (i=Logger; i < MemoryClientMax; i++) {
if (src ->chunks[i] == NULL) {
cmsDeleteContext((cmsContext) ctx);
return NULL;
}
}
return (cmsContext) ctx;
}
static
struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id)
{
struct _cmsContext_struct* prev;
// Search for previous
for (prev = _cmsContextPoolHead;
prev != NULL;
prev = prev ->Next)
{
if (prev ->Next == id)
return prev;
}
return NULL; // List is empty or only one element!
}
// Frees any resources associated with the given context,
// and destroys the context placeholder.
// The ContextID can no longer be used in any THR operation.
void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
{
if (ContextID != NULL) {
struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID;
struct _cmsContext_struct fakeContext;
struct _cmsContext_struct* prev;
memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr];
fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;
// Get rid of plugins
cmsUnregisterPluginsTHR(ContextID);
// Since all memory is allocated in the private pool, all what we need to do is destroy the pool
if (ctx -> MemPool != NULL)
_cmsSubAllocDestroy(ctx ->MemPool);
ctx -> MemPool = NULL;
// Maintain list
_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
if (_cmsContextPoolHead == ctx) {
_cmsContextPoolHead = ctx->Next;
}
else {
// Search for previous
for (prev = _cmsContextPoolHead;
prev != NULL;
prev = prev ->Next)
{
if (prev -> Next == ctx) {
prev -> Next = ctx ->Next;
break;
}
}
}
_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
// free the memory block itself
_cmsFree(&fakeContext, ctx);
}
}
// Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation
void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID)
{
return _cmsContextGetClientChunk(ContextID, UserPtr);
}

View File

@ -942,7 +942,7 @@ int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Nu
if (DeviceLink == NULL) return 0;
dwFlags |= cmsFLAGS_FORCE_CLUT;
_cmsOptimizePipeline(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
_cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
cmsPipelineFree(DeviceLink);
@ -1359,7 +1359,7 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32N
// We need a CLUT
dwFlags |= cmsFLAGS_FORCE_CLUT;
_cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
_cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
_cmsIOPrintf(m, "<<\n");
_cmsIOPrintf(m, "/ColorRenderingType 1\n");

View File

@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2011 Marti Maria Saguer
// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@ -61,7 +61,7 @@
// are no profiles holding them. The programmer can also extend this list by defining his own types
// by using the appropiate plug-in. There are three types of plug ins regarding that. First type
// allows to define new tags using any existing type. Next plug-in type allows to define new types
// and the third one is very specific: allows to extend the number of elements in the multiprofile
// and the third one is very specific: allows to extend the number of elements in the multiprocessing
// elements special type.
//--------------------------------------------------------------------------------------------------
@ -89,54 +89,49 @@ typedef struct _cmsTagTypeLinkedList_st {
// Helper macro to define a MPE handler. Callbacks do have a fixed naming convention
#define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 }
// Register a new type handler. This routine is shared between normal types and MPE
// Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head
static
cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount)
cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos)
{
cmsPluginTagType* Plugin = (cmsPluginTagType*) Data;
_cmsTagTypeLinkedList *pt, *Anterior = NULL;
_cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos);
_cmsTagTypeLinkedList *pt;
// Calling the function with NULL as plug-in would unregister the plug in.
if (Data == NULL) {
LinkedList[DefaultListCount-1].Next = NULL;
// There is no need to set free the memory, as pool is destroyed as a whole.
ctx ->TagTypes = NULL;
return TRUE;
}
pt = Anterior = LinkedList;
while (pt != NULL) {
if (Plugin->Handler.Signature == pt -> Handler.Signature) {
pt ->Handler = Plugin ->Handler; // Replace old behaviour.
// Note that since no memory is allocated, unregister does not
// reset this action.
return TRUE;
}
Anterior = pt;
pt = pt ->Next;
}
// Registering happens in plug-in memory pool
// Registering happens in plug-in memory pool.
pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList));
if (pt == NULL) return FALSE;
pt ->Handler = Plugin ->Handler;
pt ->Next = NULL;
pt ->Next = ctx ->TagTypes;
if (Anterior)
Anterior -> Next = pt;
ctx ->TagTypes = pt;
return TRUE;
}
// Return handler for a given type or NULL if not found. Shared between normal types and MPE
// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons
// made by plug-ins and then the built-in defaults.
static
cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* LinkedList)
cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList)
{
_cmsTagTypeLinkedList* pt;
for (pt = LinkedList;
for (pt = PluginLinkedList;
pt != NULL;
pt = pt ->Next) {
if (sig == pt -> Handler.Signature) return &pt ->Handler;
}
for (pt = DefaultLinkedList;
pt != NULL;
pt = pt ->Next) {
@ -163,6 +158,7 @@ cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t*
return TRUE;
}
// Auxiliar to read an array of wchar_t
static
cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
{
@ -777,6 +773,8 @@ cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
// Create memory
Text = (char*) _cmsMalloc(self ->ContextID, size);
if (Text == NULL) return FALSE;
cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size);
// Write it, including separator
@ -1783,7 +1781,6 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
if (!_cmsReadUInt8Number(io, NULL)) goto Error;
// Do some checking
if (InputChannels > cmsMAXCHANNELS) goto Error;
if (OutputChannels > cmsMAXCHANNELS) goto Error;
@ -1824,9 +1821,16 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
if (T == NULL) goto Error;
Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize);
if (Temp == NULL) goto Error;
if (Temp == NULL) {
_cmsFree(self ->ContextID, T);
goto Error;
}
if (io ->Read(io, Temp, nTabSize, 1) != 1) goto Error;
if (io ->Read(io, Temp, nTabSize, 1) != 1) {
_cmsFree(self ->ContextID, T);
_cmsFree(self ->ContextID, Temp);
goto Error;
}
for (i = 0; i < nTabSize; i++) {
@ -2371,27 +2375,30 @@ cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUI
// Precision can be 1 or 2 bytes
if (Precision == 1) {
cmsUInt8Number v;
cmsUInt8Number v;
for (i=0; i < Data ->nEntries; i++) {
if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL;
Data ->Tab.T[i] = FROM_8_TO_16(v);
if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL;
Data ->Tab.T[i] = FROM_8_TO_16(v);
}
}
else
if (Precision == 2) {
if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) return NULL;
}
else {
cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
return NULL;
}
if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) {
cmsStageFree(CLUT);
return NULL;
}
}
else {
cmsStageFree(CLUT);
cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
return NULL;
}
return CLUT;
return CLUT;
}
static
@ -4374,7 +4381,7 @@ static _cmsTagTypeLinkedList SupportedMPEtypes[] = {
{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL },
};
#define DEFAULT_MPE_TYPE_COUNT (sizeof(SupportedMPEtypes) / sizeof(_cmsTagTypeLinkedList))
_cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL };
static
cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
@ -4387,6 +4394,8 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
cmsTagTypeHandler* TypeHandler;
cmsUInt32Number nItems;
cmsPipeline *NewLUT = (cmsPipeline *) Cargo;
_cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
// Take signature and channels for each element.
if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE;
@ -4395,7 +4404,7 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
if (!_cmsReadUInt32Number(io, NULL)) return FALSE;
// Read diverse MPE types
TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes);
TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes);
if (TypeHandler == NULL) {
char String[5];
@ -4472,6 +4481,7 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v
cmsPipeline* Lut = (cmsPipeline*) Ptr;
cmsStage* Elem = Lut ->Elements;
cmsTagTypeHandler* TypeHandler;
_cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
@ -4505,7 +4515,7 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v
ElementSig = Elem ->Type;
TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes);
TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes);
if (TypeHandler == NULL) {
char String[5];
@ -5125,7 +5135,7 @@ void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i
}
else {
rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU);
rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU);
}
if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS);
@ -5282,24 +5292,95 @@ static _cmsTagTypeLinkedList SupportedTagTypes[] = {
{TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL }
};
#define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList))
_cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL };
// Duplicates the zone of memory used by the plug-in in the new context
static
void DupTagTypeList(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src,
int loc)
{
_cmsTagTypePluginChunkType newHead = { NULL };
_cmsTagTypeLinkedList* entry;
_cmsTagTypeLinkedList* Anterior = NULL;
_cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc];
// Walk the list copying all nodes
for (entry = head->TagTypes;
entry != NULL;
entry = entry ->Next) {
_cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList));
if (newEntry == NULL)
return;
// We want to keep the linked list order, so this is a little bit tricky
newEntry -> Next = NULL;
if (Anterior)
Anterior -> Next = newEntry;
Anterior = newEntry;
if (newHead.TagTypes == NULL)
newHead.TagTypes = newEntry;
}
ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType));
}
void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
if (src != NULL) {
// Duplicate the LIST
DupTagTypeList(ctx, src, TagTypePlugin);
}
else {
static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL };
ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType));
}
}
void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
if (src != NULL) {
// Duplicate the LIST
DupTagTypeList(ctx, src, MPEPlugin);
}
else {
static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL };
ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType));
}
}
// Both kind of plug-ins share same structure
cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data)
{
return RegisterTypesPlugin(id, Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT);
return RegisterTypesPlugin(id, Data, TagTypePlugin);
}
cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data)
{
return RegisterTypesPlugin(id, Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT);
return RegisterTypesPlugin(id, Data,MPEPlugin);
}
// Wrapper for tag types
cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig)
cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig)
{
return GetHandler(sig, SupportedTagTypes);
_cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin);
return GetHandler(sig, ctx->TagTypes, SupportedTagTypes);
}
// ********************************************************************************
@ -5414,48 +5495,94 @@ static _cmsTagLinkedList SupportedTags[] = {
cmsSigDeviceSettingsTag ==> Deprecated, useless
*/
#define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList))
_cmsTagPluginChunkType _cmsTagPluginChunk = { NULL };
// Duplicates the zone of memory used by the plug-in in the new context
static
void DupTagList(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
_cmsTagPluginChunkType newHead = { NULL };
_cmsTagLinkedList* entry;
_cmsTagLinkedList* Anterior = NULL;
_cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin];
// Walk the list copying all nodes
for (entry = head->Tag;
entry != NULL;
entry = entry ->Next) {
_cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList));
if (newEntry == NULL)
return;
// We want to keep the linked list order, so this is a little bit tricky
newEntry -> Next = NULL;
if (Anterior)
Anterior -> Next = newEntry;
Anterior = newEntry;
if (newHead.Tag == NULL)
newHead.Tag = newEntry;
}
ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType));
}
void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
if (src != NULL) {
DupTagList(ctx, src);
}
else {
static _cmsTagPluginChunkType TagPluginChunk = { NULL };
ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType));
}
}
cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data)
{
cmsPluginTag* Plugin = (cmsPluginTag*) Data;
_cmsTagLinkedList *pt, *Anterior;
_cmsTagLinkedList *pt;
_cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin);
if (Data == NULL) {
SupportedTags[DEFAULT_TAG_COUNT-1].Next = NULL;
TagPluginChunk->Tag = NULL;
return TRUE;
}
pt = Anterior = SupportedTags;
while (pt != NULL) {
if (Plugin->Signature == pt -> Signature) {
pt ->Descriptor = Plugin ->Descriptor; // Replace old behaviour
return TRUE;
}
Anterior = pt;
pt = pt ->Next;
}
pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList));
if (pt == NULL) return FALSE;
pt ->Signature = Plugin ->Signature;
pt ->Descriptor = Plugin ->Descriptor;
pt ->Next = NULL;
pt ->Next = TagPluginChunk ->Tag;
if (Anterior != NULL) Anterior -> Next = pt;
TagPluginChunk ->Tag = pt;
return TRUE;
}
// Return a descriptor for a given tag or NULL
cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig)
cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig)
{
_cmsTagLinkedList* pt;
_cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin);
for (pt = TagPluginChunk->Tag;
pt != NULL;
pt = pt ->Next) {
if (sig == pt -> Signature) return &pt ->Descriptor;
}
for (pt = SupportedTags;
pt != NULL;

View File

@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2011 Marti Maria Saguer
// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@ -1019,7 +1019,7 @@ typedef struct {
static const cmsAllowedLUT AllowedLUTTypes[] = {
{ FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
{ FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
{ FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
{ FALSE, 0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType}},
{ TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }},
@ -1150,7 +1150,7 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
if (AllowedLUT == NULL) {
// Try to optimize
_cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
_cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
}
@ -1159,7 +1159,7 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
if (AllowedLUT == NULL) {
dwFlags |= cmsFLAGS_FORCE_CLUT;
_cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
_cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
// Put identity curves if needed
if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType)

View File

@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2012 Marti Maria Saguer
// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),

View File

@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2011 Marti Maria Saguer
// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@ -58,44 +58,120 @@
// Transformations stuff
// -----------------------------------------------------------------------
// Alarm codes for 16-bit transformations, because the fixed range of containers there are
// no values left to mark out of gamut. volatile is C99 per 6.2.5
static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS] = { 0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static volatile cmsFloat64Number GlobalAdaptationState = 1;
#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0
// The Context0 observer adaptation state.
_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
// Init and duplicate observer adaptation state
void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
void* from;
if (src != NULL) {
from = src ->chunks[AdaptationStateContext];
}
else {
from = &AdaptationStateChunk;
}
ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType));
}
// Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all
// but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states.
cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d)
{
cmsFloat64Number prev;
_cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext);
// Get previous value for return
prev = ptr ->AdaptationState;
// Set the value if d is positive or zero
if (d >= 0.0) {
ptr ->AdaptationState = d;
}
// Always return previous value
return prev;
}
// The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine
cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)
{
cmsFloat64Number OldVal = GlobalAdaptationState;
if (d >= 0)
GlobalAdaptationState = d;
return OldVal;
return cmsSetAdaptationStateTHR(NULL, d);
}
// Alarm codes are always global
void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
{
int i;
// -----------------------------------------------------------------------
// Alarm codes for 16-bit transformations, because the fixed range of containers there are
// no values left to mark out of gamut.
#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be
// encoded in 16 bits.
void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
{
_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
_cmsAssert(ContextAlarmCodes != NULL); // Can't happen
memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes));
}
// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context.
// Values are meant to be encoded in 16 bits.
void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
{
_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
_cmsAssert(ContextAlarmCodes != NULL); // Can't happen
memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes));
}
void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
{
_cmsAssert(NewAlarm != NULL);
for (i=0; i < cmsMAXCHANNELS; i++)
Alarm[i] = NewAlarm[i];
cmsSetAlarmCodesTHR(NULL, NewAlarm);
}
// You can get the codes cas well
void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS])
{
int i;
_cmsAssert(OldAlarm != NULL);
for (i=0; i < cmsMAXCHANNELS; i++)
OldAlarm[i] = Alarm[i];
cmsGetAlarmCodesTHR(NULL, OldAlarm);
}
// Init and duplicate alarm codes
void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
void* from;
if (src != NULL) {
from = src ->chunks[AlarmCodesContext];
}
else {
from = &AlarmCodesChunk;
}
ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType));
}
// -----------------------------------------------------------------------
// Get rid of transform resources
void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)
{
@ -202,6 +278,30 @@ void FloatXFORM(_cmsTRANSFORM* p,
}
}
static
void NullFloatXFORM(_cmsTRANSFORM* p,
const void* in,
void* out,
cmsUInt32Number Size,
cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
cmsFloat32Number fIn[cmsMAXCHANNELS];
cmsUInt32Number i, n;
accum = (cmsUInt8Number*) in;
output = (cmsUInt8Number*) out;
n = Size;
for (i=0; i < n; i++) {
accum = p -> FromInputFloat(p, fIn, accum, Stride);
output = p -> ToOutputFloat(p, fIn, output, Stride);
}
}
// 16 bit precision -----------------------------------------------------------------------------------------------------------
// Null transformation, only applies formatters. No caché
@ -252,7 +352,7 @@ void PrecalculatedXFORM(_cmsTRANSFORM* p,
}
// Auxiliar: Handle precalculated gamut check
// Auxiliar: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical.
static
void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
const cmsUInt16Number wIn[],
@ -264,9 +364,12 @@ void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
if (wOutOfGamut >= 1) {
cmsUInt16Number i;
_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext);
for (i=0; i < p ->Lut->OutputChannels; i++)
wOut[i] = Alarm[i];
for (i=0; i < p ->Lut->OutputChannels; i++) {
wOut[i] = ContextAlarmCodes ->AlarmCodes[i];
}
}
else
p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
@ -393,34 +496,86 @@ typedef struct _cmsTransformCollection_st {
} _cmsTransformCollection;
// The linked list head
static _cmsTransformCollection* TransformCollection = NULL;
_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL };
// Duplicates the zone of memory used by the plug-in in the new context
static
void DupPluginTransformList(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
_cmsTransformPluginChunkType newHead = { NULL };
_cmsTransformCollection* entry;
_cmsTransformCollection* Anterior = NULL;
_cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin];
// Walk the list copying all nodes
for (entry = head->TransformCollection;
entry != NULL;
entry = entry ->Next) {
_cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection));
if (newEntry == NULL)
return;
// We want to keep the linked list order, so this is a little bit tricky
newEntry -> Next = NULL;
if (Anterior)
Anterior -> Next = newEntry;
Anterior = newEntry;
if (newHead.TransformCollection == NULL)
newHead.TransformCollection = newEntry;
}
ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType));
}
void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
if (src != NULL) {
// Copy all linked list
DupPluginTransformList(ctx, src);
}
else {
static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL };
ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType));
}
}
// Register new ways to transform
cmsBool _cmsRegisterTransformPlugin(cmsContext id, cmsPluginBase* Data)
cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
_cmsTransformCollection* fl;
_cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin);
if (Data == NULL) {
if (Data == NULL) {
// Free the chain. Memory is safely freed at exit
TransformCollection = NULL;
ctx->TransformCollection = NULL;
return TRUE;
}
// Factory callback is required
if (Plugin ->Factory == NULL) return FALSE;
if (Plugin ->Factory == NULL) return FALSE;
fl = (_cmsTransformCollection*) _cmsPluginMalloc(id, sizeof(_cmsTransformCollection));
fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection));
if (fl == NULL) return FALSE;
// Copy the parameters
// Copy the parameters
fl ->Factory = Plugin ->Factory;
// Keep linked list
fl ->Next = TransformCollection;
TransformCollection = fl;
fl ->Next = ctx->TransformCollection;
ctx->TransformCollection = fl;
// All is ok
return TRUE;
@ -463,6 +618,7 @@ static
_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
{
_cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin);
_cmsTransformCollection* Plugin;
// Allocate needed memory
@ -473,7 +629,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
p ->Lut = lut;
// Let's see if any plug-in want to do the transform by itself
for (Plugin = TransformCollection;
for (Plugin = ctx ->TransformCollection;
Plugin != NULL;
Plugin = Plugin ->Next) {
@ -493,10 +649,10 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
// Fill the formatters just in case the optimized routine is interested.
// No error is thrown if the formatter doesn't exist. It is up to the optimization
// factory to decide what to do in those cases.
p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
return p;
}
@ -504,14 +660,14 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
// Not suitable for the transform plug-in, let's check the pipeline plug-in
if (p ->Lut != NULL)
_cmsOptimizePipeline(&p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
_cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
// Check whatever this is a true floating point transform
if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
// Get formatter function always return a valid union, but the contents of this union may be NULL.
p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
@ -521,8 +677,15 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
return NULL;
}
// Float transforms don't use caché, always are non-NULL
p ->xform = FloatXFORM;
if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
p ->xform = NullFloatXFORM;
}
else {
// Float transforms don't use caché, always are non-NULL
p ->xform = FloatXFORM;
}
}
else {
@ -534,8 +697,8 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
int BytesPerPixelInput;
p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
if (p ->FromInput == NULL || p ->ToOutput == NULL) {
@ -727,6 +890,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
// Check channel count
if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) ||
(cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) {
cmsPipelineFree(Lut);
cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");
return NULL;
}
@ -829,7 +993,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,
for (i=0; i < nProfiles; i++) {
BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE;
Intents[i] = Intent;
AdaptationStates[i] = GlobalAdaptationState;
AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1);
}
@ -909,7 +1073,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,
Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent;
BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0;
Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = GlobalAdaptationState;
Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1);
if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);
@ -984,8 +1148,8 @@ cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
return FALSE;
}
FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
if (FromInput == NULL || ToOutput == NULL) {

View File

@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2013 Marti Maria Saguer
// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@ -52,7 +52,7 @@
//
//---------------------------------------------------------------------------------
//
// Version 2.5
// Version 2.6
//
#ifndef _lcms2_H
@ -84,6 +84,9 @@
// Uncomment to get rid of the tables for "half" float support
// #define CMS_NO_HALF_SUPPORT 1
// Uncomment to get rid of pthreads/windows dependency
// #define CMS_NO_PTHREADS 1
// ********** End of configuration toggles ******************************
// Needed for streams
@ -101,7 +104,7 @@ extern "C" {
#endif
// Version/release
#define LCMS_VERSION 2050
#define LCMS_VERSION 2060
// I will give the chance of redefining basic types for compilers that are not fully C99 compliant
#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
@ -202,28 +205,42 @@ typedef int cmsBool;
// Try to detect big endian platforms. This list can be endless, so only some checks are performed over here.
// you can pass this toggle to the compiler by using -DCMS_USE_BIG_ENDIAN or something similar
#if defined(__sgi__) || defined(__sgi) || defined(sparc)
# define CMS_USE_BIG_ENDIAN 1
#endif
#if defined(__s390__) || defined(__s390x__)
# define CMS_USE_BIG_ENDIAN 1
#endif
# ifdef TARGET_CPU_PPC
# if TARGET_CPU_PPC
# define CMS_USE_BIG_ENDIAN 1
# endif
# endif
#if defined(__powerpc__) || defined(__ppc__) || defined(TARGET_CPU_PPC)
# define CMS_USE_BIG_ENDIAN 1
# if defined (__GNUC__) && defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN)
# if __BYTE_ORDER == __LITTLE_ENDIAN
// // Don't use big endian for PowerPC little endian mode
# undef CMS_USE_BIG_ENDIAN
# endif
# endif
#endif
// WORDS_BIGENDIAN takes precedence
#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN)
# define CMS_USE_BIG_ENDIAN 1
#endif
#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc)
# define CMS_USE_BIG_ENDIAN 1
#endif
#if defined(__ppc__) || defined(__s390__) || defined(__s390x__)
# define CMS_USE_BIG_ENDIAN 1
#endif
#ifdef TARGET_CPU_PPC
# if TARGET_CPU_PPC
# define CMS_USE_BIG_ENDIAN 1
# endif
#endif
#ifdef macintosh
# ifdef __BIG_ENDIAN__
# define CMS_USE_BIG_ENDIAN 1
# endif
# ifdef __LITTLE_ENDIAN__
# undef CMS_USE_BIG_ENDIAN
# endif
#endif
// Calling convention -- this is hardly platform and compiler dependent
@ -249,6 +266,14 @@ typedef int cmsBool;
# define CMSAPI
#endif
#ifdef HasTHREADS
# if HasTHREADS == 1
# undef CMS_NO_PTHREADS
# else
# define CMS_NO_PTHREADS 1
# endif
#endif
// Some common definitions
#define cmsMAX_PATH 256
@ -642,7 +667,6 @@ typedef struct {
// Little CMS specific typedefs
typedef void* cmsContext; // Context identifier for multithreaded environments
typedef void* cmsHANDLE ; // Generic handle
typedef void* cmsHPROFILE; // Opaque typedefs to hide internals
typedef void* cmsHTRANSFORM;
@ -1012,11 +1036,25 @@ typedef struct {
CMSAPI int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2);
CMSAPI long int CMSEXPORT cmsfilelength(FILE* f);
// Plug-In registering ---------------------------------------------------------------------------------------------------
// Context handling --------------------------------------------------------------------------------------------------------
// Each context holds its owns globals and its own plug-ins. There is a global context with the id = 0 for lecacy compatibility
// though using the global context is not recomended. Proper context handling makes lcms more thread-safe.
typedef struct _cmsContext_struct* cmsContext;
CMSAPI cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData);
CMSAPI void CMSEXPORT cmsDeleteContext(cmsContext ContexID);
CMSAPI cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData);
CMSAPI void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID);
// Plug-In registering --------------------------------------------------------------------------------------------------
CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin);
CMSAPI cmsBool CMSEXPORT cmsPluginTHR(cmsContext ContextID, void* Plugin);
CMSAPI void CMSEXPORT cmsUnregisterPlugins(void);
CMSAPI void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID);
// Error logging ----------------------------------------------------------------------------------------------------------
@ -1053,6 +1091,7 @@ typedef void (* cmsLogErrorHandlerFunction)(cmsContext ContextID, cmsUInt32Numb
// Allows user to set any specific logger
CMSAPI void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn);
CMSAPI void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn);
// Conversions --------------------------------------------------------------------------------------------------------------
@ -1514,6 +1553,7 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext Context
CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void * MemPtr, cmsUInt32Number dwSize);
CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void * MemPtr, cmsUInt32Number dwSize);
CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io);
CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write);
CMSAPI cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile);
CMSAPI cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName);
@ -1604,6 +1644,7 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransfo
// Call with NULL as parameters to get the intent count
CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions);
CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions);
// Flags
@ -1715,11 +1756,22 @@ CMSAPI void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform,
cmsUInt32Number Stride);
CMSAPI void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
CMSAPI void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
CMSAPI void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID,
const cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]);
CMSAPI void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID,
cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]);
// Adaptation state for absolute colorimetric intent
CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d);
CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d);
// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
CMSAPI cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform);

View File

@ -30,7 +30,7 @@
//
// Little Color Management System
// Copyright (c) 1998-2011 Marti Maria Saguer
// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@ -193,16 +193,171 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d)
return _cmsQuickFloorWord(d);
}
// Plug-In registering ---------------------------------------------------------------
// Pthread support --------------------------------------------------------------------
#ifndef CMS_NO_PTHREADS
// This is the threading support. Unfortunately, it has to be platform-dependent because
// windows does not support pthreads.
#ifdef CMS_IS_WINDOWS_
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
// From: http://locklessinc.com/articles/pthreads_on_windows/
// The pthreads API has an initialization macro that has no correspondence to anything in
// the windows API. By investigating the internal definition of the critical section type,
// one may work out how to initialize one without calling InitializeCriticalSection().
// The trick here is that InitializeCriticalSection() is not allowed to fail. It tries
// to allocate a critical section debug object, but if no memory is available, it sets
// the pointer to a specific value. (One would expect that value to be NULL, but it is
// actually (void *)-1 for some reason.) Thus we can use this special value for that
// pointer, and the critical section code will work.
// The other important part of the critical section type to initialize is the number
// of waiters. This controls whether or not the mutex is locked. Fortunately, this
// part of the critical section is unlikely to change. Apparently, many programs
// already test critical sections to see if they are locked using this value, so
// Microsoft felt that it was necessary to keep it set at -1 for an unlocked critical
// section, even when they changed the underlying algorithm to be more scalable.
// The final parts of the critical section object are unimportant, and can be set
// to zero for their defaults. This yields an initialization macro:
typedef CRITICAL_SECTION _cmsMutex;
#define CMS_MUTEX_INITIALIZER {(void*) -1,-1,0,0,0,0}
cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
{
EnterCriticalSection(m);
return 0;
}
cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
{
LeaveCriticalSection(m);
return 0;
}
cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
{
InitializeCriticalSection(m);
return 0;
}
cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
{
DeleteCriticalSection(m);
return 0;
}
cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
{
EnterCriticalSection(m);
return 0;
}
cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
{
LeaveCriticalSection(m);
return 0;
}
#else
// Rest of the wide world
#include <pthread.h>
#define CMS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
typedef pthread_mutex_t _cmsMutex;
cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
{
return pthread_mutex_lock(m);
}
cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
{
return pthread_mutex_unlock(m);
}
cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
{
return pthread_mutex_init(m, NULL);
}
cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
{
return pthread_mutex_destroy(m);
}
cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
{
return pthread_mutex_lock(m);
}
cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
{
return pthread_mutex_unlock(m);
}
#endif
#else
#define CMS_MUTEX_INITIALIZER 0
typedef int _cmsMutex;
cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
}
cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
}
cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
}
cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
}
cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
}
cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
}
#endif
// Plug-In registration ---------------------------------------------------------------
// Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once.
void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size);
// Memory management
cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin);
cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Interpolation
cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin);
cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Parametric curves
cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
@ -228,9 +383,12 @@ cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Plu
// Transform
cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Mutex
cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// ---------------------------------------------------------------------------------------------------------
// Suballocators. Those are blocks of memory that is freed at the end on whole block.
// Suballocators.
typedef struct _cmsSubAllocator_chunk_st {
cmsUInt8Number* Block;
@ -253,9 +411,264 @@ typedef struct {
_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial);
void _cmsSubAllocDestroy(_cmsSubAllocator* s);
void* _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size);
void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size);
// ----------------------------------------------------------------------------------
// The context clients.
typedef enum {
UserPtr, // User-defined pointer
Logger,
AlarmCodesContext,
AdaptationStateContext,
MemPlugin,
InterpPlugin,
CurvesPlugin,
FormattersPlugin,
TagTypePlugin,
TagPlugin,
IntentPlugin,
MPEPlugin,
OptimizationPlugin,
TransformPlugin,
MutexPlugin,
// Last in list
MemoryClientMax
} _cmsMemoryClient;
// Container for memory management plug-in.
typedef struct {
_cmsMallocFnPtrType MallocPtr;
_cmsMalloZerocFnPtrType MallocZeroPtr;
_cmsFreeFnPtrType FreePtr;
_cmsReallocFnPtrType ReallocPtr;
_cmsCallocFnPtrType CallocPtr;
_cmsDupFnPtrType DupPtr;
} _cmsMemPluginChunkType;
// Copy memory management function pointers from plug-in to chunk, taking care of missing routines
void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr);
// Internal structure for context
struct _cmsContext_struct {
struct _cmsContext_struct* Next; // Points to next context in the new style
_cmsSubAllocator* MemPool; // The memory pool that stores context data
void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator.
// If NULL, then it reverts to global Context0
_cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overriden
};
// Returns a pointer to a valid context structure, including the global one if id is zero.
// Verifies the magic number.
struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID);
// Returns the block assigned to the specific zone.
void* _cmsContextGetClientChunk(cmsContext id, _cmsMemoryClient mc);
// Chunks of context memory by plug-in client -------------------------------------------------------
// Those structures encapsulates all variables needed by the several context clients (mostly plug-ins)
// Container for error logger -- not a plug-in
typedef struct {
cmsLogErrorHandlerFunction LogErrorHandler; // Set to NULL for Context0 fallback
} _cmsLogErrorChunkType;
// The global Context0 storage for error logger
extern _cmsLogErrorChunkType _cmsLogErrorChunk;
// Allocate and init error logger container.
void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// Container for alarm codes -- not a plug-in
typedef struct {
cmsUInt16Number AlarmCodes[cmsMAXCHANNELS];
} _cmsAlarmCodesChunkType;
// The global Context0 storage for alarm codes
extern _cmsAlarmCodesChunkType _cmsAlarmCodesChunk;
// Allocate and init alarm codes container.
void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// Container for adaptation state -- not a plug-in
typedef struct {
cmsFloat64Number AdaptationState;
} _cmsAdaptationStateChunkType;
// The global Context0 storage for adaptation state
extern _cmsAdaptationStateChunkType _cmsAdaptationStateChunk;
// Allocate and init adaptation state container.
void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// The global Context0 storage for memory management
extern _cmsMemPluginChunkType _cmsMemPluginChunk;
// Allocate and init memory management container.
void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// Container for interpolation plug-in
typedef struct {
cmsInterpFnFactory Interpolators;
} _cmsInterpPluginChunkType;
// The global Context0 storage for interpolation plug-in
extern _cmsInterpPluginChunkType _cmsInterpPluginChunk;
// Allocate and init interpolation container.
void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// Container for parametric curves plug-in
typedef struct {
struct _cmsParametricCurvesCollection_st* ParametricCurves;
} _cmsCurvesPluginChunkType;
// The global Context0 storage for tone curves plug-in
extern _cmsCurvesPluginChunkType _cmsCurvesPluginChunk;
// Allocate and init parametric curves container.
void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// Container for formatters plug-in
typedef struct {
struct _cms_formatters_factory_list* FactoryList;
} _cmsFormattersPluginChunkType;
// The global Context0 storage for formatters plug-in
extern _cmsFormattersPluginChunkType _cmsFormattersPluginChunk;
// Allocate and init formatters container.
void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// This chunk type is shared by TagType plug-in and MPE Plug-in
typedef struct {
struct _cmsTagTypeLinkedList_st* TagTypes;
} _cmsTagTypePluginChunkType;
// The global Context0 storage for tag types plug-in
extern _cmsTagTypePluginChunkType _cmsTagTypePluginChunk;
// The global Context0 storage for mult process elements plug-in
extern _cmsTagTypePluginChunkType _cmsMPETypePluginChunk;
// Allocate and init Tag types container.
void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// Allocate and init MPE container.
void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// Container for tag plug-in
typedef struct {
struct _cmsTagLinkedList_st* Tag;
} _cmsTagPluginChunkType;
// The global Context0 storage for tag plug-in
extern _cmsTagPluginChunkType _cmsTagPluginChunk;
// Allocate and init Tag container.
void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// Container for intents plug-in
typedef struct {
struct _cms_intents_list* Intents;
} _cmsIntentsPluginChunkType;
// The global Context0 storage for intents plug-in
extern _cmsIntentsPluginChunkType _cmsIntentsPluginChunk;
// Allocate and init intents container.
void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// Container for optimization plug-in
typedef struct {
struct _cmsOptimizationCollection_st* OptimizationCollection;
} _cmsOptimizationPluginChunkType;
// The global Context0 storage for optimizers plug-in
extern _cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk;
// Allocate and init optimizers container.
void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// Container for transform plug-in
typedef struct {
struct _cmsTransformCollection_st* TransformCollection;
} _cmsTransformPluginChunkType;
// The global Context0 storage for full-transform replacement plug-in
extern _cmsTransformPluginChunkType _cmsTransformPluginChunk;
// Allocate and init transform container.
void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// Container for mutex plug-in
typedef struct {
_cmsCreateMutexFnPtrType CreateMutexPtr;
_cmsDestroyMutexFnPtrType DestroyMutexPtr;
_cmsLockMutexFnPtrType LockMutexPtr;
_cmsUnlockMutexFnPtrType UnlockMutexPtr;
} _cmsMutexPluginChunkType;
// The global Context0 storage for mutex plug-in
extern _cmsMutexPluginChunkType _cmsMutexPluginChunk;
// Allocate and init mutex container.
void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
// ----------------------------------------------------------------------------------
// MLU internal representation
typedef struct {
@ -347,10 +760,14 @@ typedef struct _cms_iccprofile_struct {
cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked
void * TagPtrs[MAX_TABLE_TAG];
cmsTagTypeHandler* TagTypeHandlers[MAX_TABLE_TAG]; // Same structure may be serialized on different types
// depending on profile version, so we keep track of the // type handler for each tag in the list.
// depending on profile version, so we keep track of the
// type handler for each tag in the list.
// Special
cmsBool IsWrite;
// Keep a mutex for cmsReadTag -- Note that this only works if the user includes a mutex plugin
void * UsrMutex;
} _cmsICCPROFILE;
// IO helpers for profiles
@ -359,9 +776,9 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSp
int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks);
// Tag types
cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig);
cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig);
cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig);
cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig);
cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig);
// Error logging ---------------------------------------------------------------------------------------------------------
@ -372,7 +789,7 @@ void _cmsTagSignature2String(char String[5], cmsTagSignature sig
cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
void _cmsFreeInterpParams(cmsInterpParams* p);
cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p);
cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p);
// Curves ----------------------------------------------------------------------------------------------------------------
@ -503,7 +920,8 @@ cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space,
cmsUInt16Number **Black,
cmsUInt32Number *nOutputs);
cmsBool _cmsOptimizePipeline(cmsPipeline** Lut,
cmsBool _cmsOptimizePipeline(cmsContext ContextID,
cmsPipeline** Lut,
int Intent,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
@ -528,7 +946,8 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type);
cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type);
cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
cmsFormatter _cmsGetFormatter(cmsContext ContextID,
cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
cmsFormatterDirection Dir,
cmsUInt32Number dwFlags);

View File

@ -231,6 +231,7 @@ typedef void* (* _cmsDupUserDataFn)(cmsContext ContextID, const void* Data);
#define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH'
#define cmsPluginOptimizationSig 0x6F707448 // 'optH'
#define cmsPluginTransformSig 0x7A666D48 // 'xfmH'
#define cmsPluginMutexSig 0x6D747A48 // 'mtxH'
typedef struct _cmsPluginBaseStruct {
@ -247,19 +248,28 @@ typedef struct _cmsPluginBaseStruct {
//----------------------------------------------------------------------------------------------------------
// Memory handler. Each new plug-in type replaces current behaviour
typedef void* (* _cmsMallocFnPtrType)(cmsContext ContextID, cmsUInt32Number size);
typedef void (* _cmsFreeFnPtrType)(cmsContext ContextID, void *Ptr);
typedef void* (* _cmsReallocFnPtrType)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize);
typedef void* (* _cmsMalloZerocFnPtrType)(cmsContext ContextID, cmsUInt32Number size);
typedef void* (* _cmsCallocFnPtrType)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size);
typedef void* (* _cmsDupFnPtrType)(cmsContext ContextID, const void* Org, cmsUInt32Number size);
typedef struct {
cmsPluginBase base;
// Required
void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size);
void (* FreePtr)(cmsContext ContextID, void *Ptr);
void * (* ReallocPtr)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize);
_cmsMallocFnPtrType MallocPtr;
_cmsFreeFnPtrType FreePtr;
_cmsReallocFnPtrType ReallocPtr;
// Optional
void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size);
void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size);
void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size);
_cmsMalloZerocFnPtrType MallocZeroPtr;
_cmsCallocFnPtrType CallocPtr;
_cmsDupFnPtrType DupPtr;
} cmsPluginMemHandler;
@ -622,6 +632,29 @@ typedef struct {
} cmsPluginTransform;
//----------------------------------------------------------------------------------------------------------
// Mutex
typedef void* (* _cmsCreateMutexFnPtrType)(cmsContext ContextID);
typedef void (* _cmsDestroyMutexFnPtrType)(cmsContext ContextID, void* mtx);
typedef cmsBool (* _cmsLockMutexFnPtrType)(cmsContext ContextID, void* mtx);
typedef void (* _cmsUnlockMutexFnPtrType)(cmsContext ContextID, void* mtx);
typedef struct {
cmsPluginBase base;
_cmsCreateMutexFnPtrType CreateMutexPtr;
_cmsDestroyMutexFnPtrType DestroyMutexPtr;
_cmsLockMutexFnPtrType LockMutexPtr;
_cmsUnlockMutexFnPtrType UnlockMutexPtr;
} cmsPluginMutex;
CMSAPI void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID);
CMSAPI void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx);
CMSAPI cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx);
CMSAPI void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx);
#ifndef CMS_USE_CPP_API
# ifdef __cplusplus

View File

@ -55,7 +55,6 @@ class XWindow extends XBaseWindow implements X11ComponentPeer {
*/
private final static int AWT_MULTICLICK_SMUDGE = 4;
// ButtonXXX events stuff
static int rbutton = 0;
static int lastX = 0, lastY = 0;
static long lastTime = 0;
static long lastButton = 0;
@ -632,23 +631,6 @@ class XWindow extends XBaseWindow implements X11ComponentPeer {
return res;
}
/**
* Returns true if this event is disabled and shouldn't be passed to Java.
* Default implementation returns false for all events.
*/
static int getRightButtonNumber() {
if (rbutton == 0) { // not initialized yet
XToolkit.awtLock();
try {
rbutton = XlibWrapper.XGetPointerMapping(XToolkit.getDisplay(), XlibWrapper.ibuffer, 3);
}
finally {
XToolkit.awtUnlock();
}
}
return rbutton;
}
static int getMouseMovementSmudge() {
//TODO: It's possible to read corresponding settings
return AWT_MULTICLICK_SMUDGE;
@ -716,11 +698,7 @@ class XWindow extends XBaseWindow implements X11ComponentPeer {
/*
Check for popup trigger !!
*/
if (lbutton == getRightButtonNumber() || lbutton > 2) {
popupTrigger = true;
} else {
popupTrigger = false;
}
popupTrigger = (lbutton == 3);
}
button = XConstants.buttons[lbutton - 1];

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -31,12 +31,14 @@ public class XRSolidSrcPict {
XRSurfaceData srcPict;
XRColor xrCol;
int curPixVal = -1;
int curPixVal;
public XRSolidSrcPict(XRBackend con, int parentXid) {
this.con = con;
xrCol = new XRColor();
curPixVal = 0xFF000000;
int solidPixmap = con.createPixmap(parentXid, 32, 1, 1);
int solidSrcPictXID = con.createPicture(solidPixmap, XRUtils.PictStandardARGB32);
con.setPictureRepeat(solidSrcPictXID, XRUtils.RepeatNormal);

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2007, 2008, 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.
*/
#include "D3DPipeline.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

View File

@ -1,60 +0,0 @@
/*
* Copyright (c) 2002, 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.
*/
#include "sun_awt_windows_WBufferStrategy.h"
#include "jni_util.h"
static jmethodID getBackBufferID;
/*
* Class: sun_awt_windows_WBufferStrategy
* Method: initIDs
* Signature: (Ljava/lang/Class;)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_windows_WBufferStrategy_initIDs(JNIEnv *env, jclass wbs,
jclass componentClass)
{
getBackBufferID = env->GetMethodID(componentClass, "getBackBuffer",
"()Ljava/awt/Image;");
}
/**
* Native method of WBufferStrategy.java. Given a Component
* object, this method will find the back buffer associated
* with the Component's BufferStrategy and return a handle
* to it.
*/
extern "C" JNIEXPORT jobject JNICALL
Java_sun_awt_windows_WBufferStrategy_getDrawBuffer(JNIEnv *env, jclass wbs,
jobject component)
{
if (!JNU_IsNull(env, getBackBufferID)) {
return env->CallObjectMethod(component, getBackBufferID);
} else {
return NULL;
}
}

View File

@ -1335,66 +1335,94 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
int maxNotifications,
long timeout)
throws IOException, ClassNotFoundException {
IOException org;
boolean retried = false;
while (true) { // used for a successful re-connection
// or a transient network problem
try {
return connection.fetchNotifications(clientSequenceNumber,
maxNotifications,
timeout);
timeout); // return normally
} catch (IOException ioe) {
org = ioe;
// Examine the chain of exceptions to determine whether this
// is a deserialization issue. If so - we propagate the
// appropriate exception to the caller, who will then
// proceed with fetching notifications one by one
rethrowDeserializationException(ioe);
// inform of IOException
try {
communicatorAdmin.gotIOException(ioe);
// The connection should be re-established.
continue;
// reconnection OK, back to "while" to do again
} catch (IOException ee) {
// No more fetch, the Exception will be re-thrown.
break;
} // never reached
} // never reached
}
boolean toClose = false;
// specially treating for an UnmarshalException
if (org instanceof UnmarshalException) {
UnmarshalException ume = (UnmarshalException)org;
synchronized (this) {
if (terminated) {
// the connection is closed.
throw ioe;
} else if (retried) {
toClose = true;
}
}
if (ume.detail instanceof ClassNotFoundException)
throw (ClassNotFoundException) ume.detail;
if (toClose) {
// JDK-8049303
// We received an IOException - but the communicatorAdmin
// did not close the connection - possibly because
// the original exception was raised by a transient network
// problem?
// We already know that this exception is not due to a deserialization
// issue as we already took care of that before involving the
// communicatorAdmin. Moreover - we already made one retry attempt
// at fetching the same batch of notifications - and the
// problem persisted.
// Since trying again doesn't seem to solve the issue, we will now
// close the connection. Doing otherwise might cause the
// NotifFetcher thread to die silently.
final Notification failedNotif =
new JMXConnectionNotification(
JMXConnectionNotification.FAILED,
this,
connectionId,
clientNotifSeqNo++,
"Failed to communicate with the server: " + ioe.toString(),
ioe);
/* In Sun's RMI implementation, if a method return
contains an unserializable object, then we get
UnmarshalException wrapping WriteAbortedException
wrapping NotSerializableException. In that case we
extract the NotSerializableException so that our
caller can realize it should try to skip past the
notification that presumably caused it. It's not
certain that every other RMI implementation will
generate this exact exception sequence. If not, we
will not detect that the problem is due to an
unserializable object, and we will stop trying to
receive notifications from the server. It's not
clear we can do much better. */
if (ume.detail instanceof WriteAbortedException) {
WriteAbortedException wae =
(WriteAbortedException) ume.detail;
if (wae.detail instanceof IOException)
throw (IOException) wae.detail;
sendNotification(failedNotif);
try {
close(true);
} catch (Exception e) {
// OK.
// We are closing
}
throw ioe; // the connection is closed here.
} else {
// JDK-8049303 possible transient network problem,
// let's try one more time
retried = true;
}
}
}
} else if (org instanceof MarshalException) {
}
}
private void rethrowDeserializationException(IOException ioe)
throws ClassNotFoundException, IOException {
// specially treating for an UnmarshalException
if (ioe instanceof UnmarshalException) {
throw ioe; // the fix of 6937053 made ClientNotifForwarder.fetchNotifs
// fetch one by one with UnmarshalException
} else if (ioe instanceof MarshalException) {
// IIOP will throw MarshalException wrapping a NotSerializableException
// when a server fails to serialize a response.
MarshalException me = (MarshalException)org;
MarshalException me = (MarshalException)ioe;
if (me.detail instanceof NotSerializableException) {
throw (NotSerializableException)me.detail;
}
}
// Not serialization problem, simply re-throw the orginal exception
throw org;
// Not serialization problem, return.
}
protected Integer addListenerForMBeanRemovedNotif()

View File

@ -25,7 +25,6 @@
package org.ietf.jgss;
import sun.security.jgss.spi.*;
import java.io.InputStream;
import java.io.OutputStream;

View File

@ -25,10 +25,6 @@
package org.ietf.jgss;
import sun.security.jgss.spi.*;
import java.util.Vector;
import java.util.Enumeration;
/**
* This interface encapsulates a single GSS-API principal entity. The
* application obtains an implementation of this interface

View File

@ -25,7 +25,6 @@
package sun.net.www.protocol.http.spnego;
import com.sun.security.jgss.ExtendedGSSContext;
import java.io.IOException;
import org.ietf.jgss.GSSContext;
@ -36,6 +35,7 @@ import org.ietf.jgss.Oid;
import sun.net.www.protocol.http.HttpCallerInfo;
import sun.net.www.protocol.http.Negotiator;
import sun.security.jgss.GSSManagerImpl;
import sun.security.jgss.GSSContextImpl;
import sun.security.jgss.GSSUtil;
import sun.security.jgss.HttpCaller;
@ -102,8 +102,8 @@ public class NegotiatorImpl extends Negotiator {
GSSContext.DEFAULT_LIFETIME);
// Always respect delegation policy in HTTP/SPNEGO.
if (context instanceof ExtendedGSSContext) {
((ExtendedGSSContext)context).requestDelegPolicy(true);
if (context instanceof GSSContextImpl) {
((GSSContextImpl)context).requestDelegPolicy(true);
}
oneToken = context.initSecContext(new byte[0], 0, 0);
}

View File

@ -33,7 +33,8 @@ import java.io.OutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import com.sun.security.jgss.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* This class represents the JGSS security context and its associated
@ -87,10 +88,10 @@ import com.sun.security.jgss.*;
* per-message operations are returned in an instance of the MessageProp
* class, which is used as an argument in these calls.</dl>
*/
class GSSContextImpl implements ExtendedGSSContext {
public class GSSContextImpl implements GSSContext {
private final GSSManagerImpl gssManager;
private final boolean initiator;
private GSSManagerImpl gssManager;
private boolean initiator;
// private flags for the context state
private static final int PRE_INIT = 1;
@ -122,6 +123,22 @@ class GSSContextImpl implements ExtendedGSSContext {
private boolean reqAnonState = false;
private boolean reqDelegPolicyState = false;
public GSSContextImpl() {
// Useless
}
// Used by new ExtendedGSSContext.ExtendedGSSContextImpl(ctxt)
protected GSSContextImpl(GSSContextImpl src) {
for (Field f: GSSContextImpl.class.getDeclaredFields()) {
if (!Modifier.isStatic(f.getModifiers())) {
try {
f.set(this, f.get(src));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
/**
* Creates a GSSContextImp on the context initiator's side.
*/
@ -613,7 +630,7 @@ class GSSContextImpl implements ExtendedGSSContext {
"No mechanism context yet!");
GSSCredentialSpi delCredElement = mechCtxt.getDelegCred();
return (delCredElement == null ?
null : new GSSCredentialImpl(gssManager, delCredElement));
null : GSSManagerImpl.wrap(new GSSCredentialImpl(gssManager, delCredElement)));
}
public boolean isInitiator() throws GSSException {
@ -633,25 +650,18 @@ class GSSContextImpl implements ExtendedGSSContext {
// ExtendedGSSContext methods:
@Override
public Object inquireSecContext(InquireType type) throws GSSException {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(new InquireSecContextPermission(type.toString()));
}
public Object inquireSecContext(String type) throws GSSException {
if (mechCtxt == null) {
throw new GSSException(GSSException.NO_CONTEXT);
}
return mechCtxt.inquireSecContext(type);
}
@Override
public void requestDelegPolicy(boolean state) throws GSSException {
if (mechCtxt == null && initiator)
reqDelegPolicyState = state;
}
@Override
public boolean getDelegPolicyState() {
if (mechCtxt != null)
return mechCtxt.getDelegPolicyState();

View File

@ -27,11 +27,11 @@ package sun.security.jgss;
import org.ietf.jgss.*;
import sun.security.jgss.spi.*;
import java.util.*;
import com.sun.security.jgss.*;
import sun.security.jgss.spnego.SpNegoCredElement;
public class GSSCredentialImpl implements ExtendedGSSCredential {
public class GSSCredentialImpl implements GSSCredential {
private GSSManagerImpl gssManager = null;
private boolean destroyed = false;
@ -47,6 +47,18 @@ public class GSSCredentialImpl implements ExtendedGSSCredential {
// XXX Optimization for single mech usage
private GSSCredentialSpi tempCred = null;
public GSSCredentialImpl() {
// Useless
}
// Used by new ExtendedGSSCredential.ExtendedGSSCredentialImpl(cred)
protected GSSCredentialImpl(GSSCredentialImpl src) {
this.gssManager = src.gssManager;
this.destroyed = src.destroyed;
this.hashtable = src.hashtable;
this.tempCred = src.tempCred;
}
GSSCredentialImpl(GSSManagerImpl gssManager, int usage)
throws GSSException {
this(gssManager, null, GSSCredential.DEFAULT_LIFETIME,
@ -140,7 +152,7 @@ public class GSSCredentialImpl implements ExtendedGSSCredential {
((GSSNameImpl)name).getElement(mech));
GSSCredentialSpi cred = tempCred.impersonate(nameElement);
return (cred == null ?
null : new GSSCredentialImpl(gssManager, cred));
null : GSSManagerImpl.wrap(new GSSCredentialImpl(gssManager, cred)));
}
public GSSName getName() throws GSSException {

View File

@ -145,35 +145,35 @@ public class GSSManagerImpl extends GSSManager {
public GSSCredential createCredential(int usage)
throws GSSException {
return new GSSCredentialImpl(this, usage);
return wrap(new GSSCredentialImpl(this, usage));
}
public GSSCredential createCredential(GSSName aName,
int lifetime, Oid mech, int usage)
throws GSSException {
return new GSSCredentialImpl(this, aName, lifetime, mech, usage);
return wrap(new GSSCredentialImpl(this, aName, lifetime, mech, usage));
}
public GSSCredential createCredential(GSSName aName,
int lifetime, Oid mechs[], int usage)
throws GSSException {
return new GSSCredentialImpl(this, aName, lifetime, mechs, usage);
return wrap(new GSSCredentialImpl(this, aName, lifetime, mechs, usage));
}
public GSSContext createContext(GSSName peer, Oid mech,
GSSCredential myCred, int lifetime)
throws GSSException {
return new GSSContextImpl(this, peer, mech, myCred, lifetime);
return wrap(new GSSContextImpl(this, peer, mech, myCred, lifetime));
}
public GSSContext createContext(GSSCredential myCred)
throws GSSException {
return new GSSContextImpl(this, myCred);
return wrap(new GSSContextImpl(this, myCred));
}
public GSSContext createContext(byte[] interProcessToken)
throws GSSException {
return new GSSContextImpl(this, interProcessToken);
return wrap(new GSSContextImpl(this, interProcessToken));
}
public void addProviderAtFront(Provider p, Oid mech)
@ -257,4 +257,20 @@ public class GSSManagerImpl extends GSSManager {
}
return result;
}
static {
// Load the extended JGSS interfaces if exist
try {
Class.forName("com.sun.security.jgss.Extender");
} catch (Exception e) {
}
}
static GSSCredential wrap(GSSCredentialImpl cred) {
return sun.security.jgss.JgssExtender.getExtender().wrap(cred);
}
static GSSContext wrap(GSSContextImpl ctxt) {
return sun.security.jgss.JgssExtender.getExtender().wrap(ctxt);
}
}

View File

@ -0,0 +1,81 @@
/*
* 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
* 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 sun.security.jgss;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
/**
* The extending point of basic JGSS-API.
* <p>
* If a module wants to extend basic JGSS-API classes, it should extends this
* class and register itself as "the extender" using the setExtender method.
* When various GSSManager.createXXX methods are called, they will call
* "the extender"'s wrap methods to create objects of extended types
* instead of basic types.
* <p>
* We have only one extension now defined in com.sun.security.jgss, and the
* registering process is triggered in {@link GSSManagerImpl} by calling
* Class.forName("com.sun.security.jgss.Extender"). Only GSSContext
* and GSSCredential are extended now.
* <p>
* The setExtender method should be called before any JGSS call.
*/
public class JgssExtender {
// "The extender"
private static volatile JgssExtender theOne = new JgssExtender();
/**
* Gets "the extender". GSSManager calls this method so that it can
* wrap basic objects into extended objects.
* @return the extender
*/
public static JgssExtender getExtender() {
return theOne;
}
/**
* Set "the extender" so that GSSManager can create extended objects.
*/
protected static void setExtender(JgssExtender theOne) {
JgssExtender.theOne = theOne;
}
/**
* Wraps a plain GSSCredential object into an extended type.
*/
public GSSCredential wrap(GSSCredential cred) {
return cred;
}
/**
* Wraps a plain GSSContext object into an extended type.
*/
public GSSContext wrap(GSSContext ctxt) {
return ctxt;
}
}

View File

@ -25,7 +25,6 @@
package sun.security.jgss.krb5;
import com.sun.security.jgss.AuthorizationDataEntry;
import org.ietf.jgss.*;
import java.io.InputStream;
import java.io.IOException;
@ -152,17 +151,7 @@ class InitSecContextToken extends InitialToken {
new KerberosTime(apReq.getCreds().getAuthTime()).toString());
context.setTktFlags(apReq.getCreds().getFlags());
AuthorizationData ad = apReq.getCreds().getAuthzData();
if (ad == null) {
context.setAuthzData(null);
} else {
AuthorizationDataEntry[] authzData =
new AuthorizationDataEntry[ad.count()];
for (int i=0; i<ad.count(); i++) {
authzData[i] = new AuthorizationDataEntry(
ad.item(i).adType, ad.item(i).adData);
}
context.setAuthzData(authzData);
}
context.setAuthzData(ad);
}
public final KrbApReq getKrbApReq() {

View File

@ -25,7 +25,6 @@
package sun.security.jgss.krb5;
import com.sun.security.jgss.InquireType;
import org.ietf.jgss.*;
import sun.misc.HexDumpEncoder;
import sun.security.jgss.GSSUtil;
@ -48,6 +47,7 @@ import javax.security.auth.kerberos.KerberosCredMessage;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KerberosTicket;
import sun.security.krb5.internal.Ticket;
import sun.security.krb5.internal.AuthorizationData;
/**
* Implements the mechanism specific context class for the Kerberos v5
@ -1419,30 +1419,30 @@ class Krb5Context implements GSSContextSpi {
/**
* Return the mechanism-specific attribute associated with {@code type}.
*/
public Object inquireSecContext(InquireType type)
public Object inquireSecContext(String type)
throws GSSException {
if (!isEstablished()) {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"Security context not established.");
}
switch (type) {
case KRB5_GET_SESSION_KEY:
case "KRB5_GET_SESSION_KEY":
return new KerberosSessionKey(key);
case KRB5_GET_SESSION_KEY_EX:
case "KRB5_GET_SESSION_KEY_EX":
return new javax.security.auth.kerberos.EncryptionKey(
key.getBytes(), key.getEType());
case KRB5_GET_TKT_FLAGS:
case "KRB5_GET_TKT_FLAGS":
return tktFlags.clone();
case KRB5_GET_AUTHZ_DATA:
case "KRB5_GET_AUTHZ_DATA":
if (isInitiator()) {
throw new GSSException(GSSException.UNAVAILABLE, -1,
"AuthzData not available on initiator side.");
} else {
return (authzData==null)?null:authzData.clone();
return authzData;
}
case KRB5_GET_AUTHTIME:
case "KRB5_GET_AUTHTIME":
return authTime;
case KRB5_GET_KRB_CRED:
case "KRB5_GET_KRB_CRED":
if (!isInitiator()) {
throw new GSSException(GSSException.UNAVAILABLE, -1,
"KRB_CRED not available on acceptor side.");
@ -1470,7 +1470,7 @@ class Krb5Context implements GSSContextSpi {
// Helpers for inquireSecContext
private boolean[] tktFlags;
private String authTime;
private com.sun.security.jgss.AuthorizationDataEntry[] authzData;
private AuthorizationData authzData;
public void setTktFlags(boolean[] tktFlags) {
this.tktFlags = tktFlags;
@ -1480,7 +1480,7 @@ class Krb5Context implements GSSContextSpi {
this.authTime = authTime;
}
public void setAuthzData(com.sun.security.jgss.AuthorizationDataEntry[] authzData) {
public void setAuthzData(AuthorizationData authzData) {
this.authzData = authzData;
}

View File

@ -34,7 +34,6 @@ import org.ietf.jgss.*;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Provider;
import com.sun.security.jgss.*;
/**
* This interface is implemented by a mechanism specific instance of a GSS
@ -403,6 +402,6 @@ public interface GSSContextSpi {
* @throws GSSException see {@link ExtendedGSSContext#inquireSecContext}
* for details
*/
public Object inquireSecContext(InquireType type)
public Object inquireSecContext(String type)
throws GSSException;
}

View File

@ -25,8 +25,6 @@
package sun.security.jgss.spnego;
import com.sun.security.jgss.ExtendedGSSContext;
import com.sun.security.jgss.InquireType;
import java.io.*;
import java.security.Provider;
import org.ietf.jgss.*;
@ -174,9 +172,9 @@ public class SpNegoContext implements GSSContextSpi {
*/
public final boolean getDelegPolicyState() {
if (isInitiator() && mechContext != null &&
mechContext instanceof ExtendedGSSContext &&
mechContext instanceof GSSContextImpl &&
(state == STATE_IN_PROCESS || state == STATE_DONE)) {
return ((ExtendedGSSContext)mechContext).getDelegPolicyState();
return ((GSSContextImpl)mechContext).getDelegPolicyState();
} else {
return delegPolicyState;
}
@ -850,7 +848,7 @@ public class SpNegoContext implements GSSContextSpi {
myCred.getInternalCred());
}
mechContext =
factory.manager.createContext(serverName,
factory.manager.createContext(serverName,
internal_mech, cred, GSSContext.DEFAULT_LIFETIME);
mechContext.requestConf(confState);
mechContext.requestInteg(integState);
@ -858,8 +856,8 @@ public class SpNegoContext implements GSSContextSpi {
mechContext.requestMutualAuth(mutualAuthState);
mechContext.requestReplayDet(replayDetState);
mechContext.requestSequenceDet(sequenceDetState);
if (mechContext instanceof ExtendedGSSContext) {
((ExtendedGSSContext)mechContext).requestDelegPolicy(
if (mechContext instanceof GSSContextImpl) {
((GSSContextImpl)mechContext).requestDelegPolicy(
delegPolicyState);
}
}
@ -890,8 +888,7 @@ public class SpNegoContext implements GSSContextSpi {
cred = new GSSCredentialImpl(factory.manager,
myCred.getInternalCred());
}
mechContext =
factory.manager.createContext(cred);
mechContext = factory.manager.createContext(cred);
}
// pass token to mechanism acceptSecContext
@ -1217,14 +1214,14 @@ public class SpNegoContext implements GSSContextSpi {
/**
* Retrieve attribute of the context for {@code type}.
*/
public Object inquireSecContext(InquireType type)
public Object inquireSecContext(String type)
throws GSSException {
if (mechContext == null) {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"Underlying mech not established.");
}
if (mechContext instanceof ExtendedGSSContext) {
return ((ExtendedGSSContext)mechContext).inquireSecContext(type);
if (mechContext instanceof GSSContextImpl) {
return ((GSSContextImpl)mechContext).inquireSecContext(type);
} else {
throw new GSSException(GSSException.BAD_MECH, -1,
"inquireSecContext not supported by underlying mech.");

View File

@ -27,8 +27,6 @@ package sun.security.jgss.spnego;
import org.ietf.jgss.*;
import java.security.Provider;
import sun.security.jgss.GSSUtil;
import sun.security.jgss.ProviderList;
import sun.security.jgss.GSSCredentialImpl;
import sun.security.jgss.spi.GSSNameSpi;
import sun.security.jgss.spi.GSSCredentialSpi;

View File

@ -36,7 +36,6 @@ import sun.security.util.ObjectIdentifier;
import sun.security.jgss.spnego.NegTokenInit;
import sun.security.jgss.spnego.NegTokenTarg;
import javax.security.auth.kerberos.DelegationPermission;
import com.sun.security.jgss.InquireType;
import java.io.*;
@ -623,7 +622,7 @@ class NativeGSSContext implements GSSContextSpi {
dispose();
}
public Object inquireSecContext(InquireType type)
public Object inquireSecContext(String type)
throws GSSException {
throw new GSSException(GSSException.UNAVAILABLE, -1,
"Inquire type not supported.");

View File

@ -27,6 +27,8 @@ package java.sql;
import java.time.Instant;
import java.time.LocalDate;
import sun.misc.SharedSecrets;
import sun.misc.JavaLangAccess;
/**
* <P>A thin wrapper around a millisecond value that allows
@ -42,6 +44,8 @@ import java.time.LocalDate;
*/
public class Date extends java.util.Date {
private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
/**
* Constructs a <code>Date</code> object initialized with the given
* year, month, and day.
@ -108,31 +112,27 @@ public class Date extends java.util.Date {
* JDBC date escape format (yyyy-[m]m-[d]d)
*/
public static Date valueOf(String s) {
if (s == null) {
throw new java.lang.IllegalArgumentException();
}
final int YEAR_LENGTH = 4;
final int MONTH_LENGTH = 2;
final int DAY_LENGTH = 2;
final int MAX_MONTH = 12;
final int MAX_DAY = 31;
int firstDash;
int secondDash;
Date d = null;
if (s == null) {
throw new java.lang.IllegalArgumentException();
}
firstDash = s.indexOf('-');
secondDash = s.indexOf('-', firstDash + 1);
int firstDash = s.indexOf('-');
int secondDash = s.indexOf('-', firstDash + 1);
int len = s.length();
if ((firstDash > 0) && (secondDash > 0) && (secondDash < s.length() - 1)) {
String yyyy = s.substring(0, firstDash);
String mm = s.substring(firstDash + 1, secondDash);
String dd = s.substring(secondDash + 1);
if (yyyy.length() == YEAR_LENGTH &&
(mm.length() >= 1 && mm.length() <= MONTH_LENGTH) &&
(dd.length() >= 1 && dd.length() <= DAY_LENGTH)) {
int year = Integer.parseInt(yyyy);
int month = Integer.parseInt(mm);
int day = Integer.parseInt(dd);
if ((firstDash > 0) && (secondDash > 0) && (secondDash < len - 1)) {
if (firstDash == YEAR_LENGTH &&
(secondDash - firstDash > 1 && secondDash - firstDash <= MONTH_LENGTH + 1) &&
(len - secondDash > 1 && len - secondDash <= DAY_LENGTH + 1)) {
int year = Integer.parseInt(s, 0, firstDash, 10);
int month = Integer.parseInt(s, firstDash + 1, secondDash, 10);
int day = Integer.parseInt(s, secondDash + 1, len, 10);
if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) {
d = new Date(year - 1900, month - 1, day);
@ -159,17 +159,34 @@ public class Date extends java.util.Date {
int month = super.getMonth() + 1;
int day = super.getDate();
char buf[] = "2000-00-00".toCharArray();
buf[0] = Character.forDigit(year/1000,10);
buf[1] = Character.forDigit((year/100)%10,10);
buf[2] = Character.forDigit((year/10)%10,10);
buf[3] = Character.forDigit(year%10,10);
buf[5] = Character.forDigit(month/10,10);
buf[6] = Character.forDigit(month%10,10);
buf[8] = Character.forDigit(day/10,10);
buf[9] = Character.forDigit(day%10,10);
char buf[] = new char[10];
formatDecimalInt(year, buf, 0, 4);
buf[4] = '-';
Date.formatDecimalInt(month, buf, 5, 2);
buf[7] = '-';
Date.formatDecimalInt(day, buf, 8, 2);
return new String(buf);
return jla.newStringUnsafe(buf);
}
/**
* Formats an unsigned integer into a char array in decimal output format.
* Numbers will be zero-padded or truncated if the string representation
* of the integer is smaller than or exceeds len, respectively.
*
* Should consider moving this to Integer and expose it through
* JavaLangAccess similar to Integer::formatUnsignedInt
* @param val Value to convert
* @param buf Array containing converted value
* @param offset Starting pos in buf
* @param len length of output value
*/
static void formatDecimalInt(int val, char[] buf, int offset, int len) {
int charPos = offset + len;
do {
buf[--charPos] = (char)('0' + (val % 10));
val /= 10;
} while (charPos > offset);
}
// Override all the time operations inherited from java.util.Date;

View File

@ -27,6 +27,8 @@ package java.sql;
import java.time.Instant;
import java.time.LocalTime;
import sun.misc.SharedSecrets;
import sun.misc.JavaLangAccess;
/**
* <P>A thin wrapper around the <code>java.util.Date</code> class that allows the JDBC
@ -39,6 +41,8 @@ import java.time.LocalTime;
*/
public class Time extends java.util.Date {
private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
/**
* Constructs a <code>Time</code> object initialized with the
* given values for the hour, minute, and second.
@ -90,22 +94,19 @@ public class Time extends java.util.Date {
* @return a corresponding <code>Time</code> object
*/
public static Time valueOf(String s) {
if (s == null) throw new java.lang.IllegalArgumentException();
int hour;
int minute;
int second;
int firstColon;
int secondColon;
if (s == null) throw new java.lang.IllegalArgumentException();
firstColon = s.indexOf(':');
secondColon = s.indexOf(':', firstColon+1);
if ((firstColon > 0) & (secondColon > 0) &
(secondColon < s.length()-1)) {
hour = Integer.parseInt(s.substring(0, firstColon));
minute =
Integer.parseInt(s.substring(firstColon+1, secondColon));
second = Integer.parseInt(s.substring(secondColon+1));
int firstColon = s.indexOf(':');
int secondColon = s.indexOf(':', firstColon + 1);
int len = s.length();
if (firstColon > 0 && secondColon > 0 &&
secondColon < len - 1) {
hour = Integer.parseInt(s, 0, firstColon, 10);
minute = Integer.parseInt(s, firstColon + 1, secondColon, 10);
second = Integer.parseInt(s, secondColon + 1, len, 10);
} else {
throw new java.lang.IllegalArgumentException();
}
@ -123,26 +124,15 @@ public class Time extends java.util.Date {
int hour = super.getHours();
int minute = super.getMinutes();
int second = super.getSeconds();
String hourString;
String minuteString;
String secondString;
if (hour < 10) {
hourString = "0" + hour;
} else {
hourString = Integer.toString(hour);
}
if (minute < 10) {
minuteString = "0" + minute;
} else {
minuteString = Integer.toString(minute);
}
if (second < 10) {
secondString = "0" + second;
} else {
secondString = Integer.toString(second);
}
return (hourString + ":" + minuteString + ":" + secondString);
char[] buf = new char[8];
Date.formatDecimalInt(hour, buf, 0, 2);
buf[2] = ':';
Date.formatDecimalInt(minute, buf, 3, 2);
buf[5] = ':';
Date.formatDecimalInt(second, buf, 6, 2);
return jla.newStringUnsafe(buf);
}
// Override all the date operations inherited from java.util.Date;

View File

@ -27,7 +27,8 @@ package java.sql;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.StringTokenizer;
import sun.misc.SharedSecrets;
import sun.misc.JavaLangAccess;
/**
* <P>A thin wrapper around <code>java.util.Date</code> that allows
@ -71,6 +72,8 @@ import java.util.StringTokenizer;
*/
public class Timestamp extends java.util.Date {
private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
/**
* Constructs a <code>Timestamp</code> object initialized
* with the given values.
@ -171,9 +174,6 @@ public class Timestamp extends java.util.Date {
final int DAY_LENGTH = 2;
final int MAX_MONTH = 12;
final int MAX_DAY = 31;
String date_s;
String time_s;
String nanos_s;
int year = 0;
int month = 0;
int day = 0;
@ -184,49 +184,38 @@ public class Timestamp extends java.util.Date {
int firstDash;
int secondDash;
int dividingSpace;
int firstColon = 0;
int secondColon = 0;
int period = 0;
int firstColon;
int secondColon;
int period;
String formatError = "Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]";
String zeros = "000000000";
String delimiterDate = "-";
String delimiterTime = ":";
if (s == null) throw new java.lang.IllegalArgumentException("null string");
// Split the string into date and time components
s = s.trim();
dividingSpace = s.indexOf(' ');
if (dividingSpace > 0) {
date_s = s.substring(0,dividingSpace);
time_s = s.substring(dividingSpace+1);
} else {
if (dividingSpace < 0) {
throw new java.lang.IllegalArgumentException(formatError);
}
// Parse the date
firstDash = date_s.indexOf('-');
secondDash = date_s.indexOf('-', firstDash+1);
firstDash = s.indexOf('-');
secondDash = s.indexOf('-', firstDash+1);
// Parse the time
if (time_s == null)
throw new java.lang.IllegalArgumentException(formatError);
firstColon = time_s.indexOf(':');
secondColon = time_s.indexOf(':', firstColon+1);
period = time_s.indexOf('.', secondColon+1);
firstColon = s.indexOf(':', dividingSpace + 1);
secondColon = s.indexOf(':', firstColon + 1);
period = s.indexOf('.', secondColon + 1);
// Convert the date
boolean parsedDate = false;
if ((firstDash > 0) && (secondDash > 0) && (secondDash < date_s.length() - 1)) {
String yyyy = date_s.substring(0, firstDash);
String mm = date_s.substring(firstDash + 1, secondDash);
String dd = date_s.substring(secondDash + 1);
if (yyyy.length() == YEAR_LENGTH &&
(mm.length() >= 1 && mm.length() <= MONTH_LENGTH) &&
(dd.length() >= 1 && dd.length() <= DAY_LENGTH)) {
year = Integer.parseInt(yyyy);
month = Integer.parseInt(mm);
day = Integer.parseInt(dd);
if (firstDash > 0 && secondDash > 0 && secondDash < dividingSpace - 1) {
if (firstDash == YEAR_LENGTH &&
(secondDash - firstDash > 1 && secondDash - firstDash <= MONTH_LENGTH + 1) &&
(dividingSpace - secondDash > 1 && dividingSpace - secondDash <= DAY_LENGTH + 1)) {
year = Integer.parseInt(s, 0, firstDash, 10);
month = Integer.parseInt(s, firstDash + 1, secondDash, 10);
day = Integer.parseInt(s, secondDash + 1, dividingSpace, 10);
if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) {
parsedDate = true;
@ -238,25 +227,27 @@ public class Timestamp extends java.util.Date {
}
// Convert the time; default missing nanos
if ((firstColon > 0) & (secondColon > 0) &
(secondColon < time_s.length()-1)) {
hour = Integer.parseInt(time_s.substring(0, firstColon));
minute =
Integer.parseInt(time_s.substring(firstColon+1, secondColon));
if ((period > 0) & (period < time_s.length()-1)) {
second =
Integer.parseInt(time_s.substring(secondColon+1, period));
nanos_s = time_s.substring(period+1);
if (nanos_s.length() > 9)
int len = s.length();
if (firstColon > 0 && secondColon > 0 && secondColon < len - 1) {
hour = Integer.parseInt(s, dividingSpace + 1, firstColon, 10);
minute = Integer.parseInt(s, firstColon + 1, secondColon, 10);
if (period > 0 && period < len - 1) {
second = Integer.parseInt(s, secondColon + 1, period, 10);
int nanoPrecision = len - (period + 1);
if (nanoPrecision > 9)
throw new java.lang.IllegalArgumentException(formatError);
if (!Character.isDigit(nanos_s.charAt(0)))
if (!Character.isDigit(s.charAt(period + 1)))
throw new java.lang.IllegalArgumentException(formatError);
nanos_s = nanos_s + zeros.substring(0,9-nanos_s.length());
a_nanos = Integer.parseInt(nanos_s);
int tmpNanos = Integer.parseInt(s, period + 1, len, 10);
while (nanoPrecision < 9) {
tmpNanos *= 10;
nanoPrecision++;
}
a_nanos = tmpNanos;
} else if (period > 0) {
throw new java.lang.IllegalArgumentException(formatError);
} else {
second = Integer.parseInt(time_s.substring(secondColon+1));
second = Integer.parseInt(s, secondColon + 1, len, 10);
}
} else {
throw new java.lang.IllegalArgumentException(formatError);
@ -274,95 +265,53 @@ public class Timestamp extends java.util.Date {
* <code>yyyy-mm-dd hh:mm:ss.fffffffff</code> format
*/
@SuppressWarnings("deprecation")
public String toString () {
public String toString() {
int year = super.getYear() + 1900;
int month = super.getMonth() + 1;
int day = super.getDate();
int hour = super.getHours();
int minute = super.getMinutes();
int second = super.getSeconds();
String yearString;
String monthString;
String dayString;
String hourString;
String minuteString;
String secondString;
String nanosString;
String zeros = "000000000";
String yearZeros = "0000";
StringBuffer timestampBuf;
if (year < 1000) {
// Add leading zeros
yearString = "" + year;
yearString = yearZeros.substring(0, (4-yearString.length())) +
yearString;
int trailingZeros = 0;
int tmpNanos = nanos;
if (tmpNanos == 0) {
trailingZeros = 8;
} else {
yearString = "" + year;
}
if (month < 10) {
monthString = "0" + month;
} else {
monthString = Integer.toString(month);
}
if (day < 10) {
dayString = "0" + day;
} else {
dayString = Integer.toString(day);
}
if (hour < 10) {
hourString = "0" + hour;
} else {
hourString = Integer.toString(hour);
}
if (minute < 10) {
minuteString = "0" + minute;
} else {
minuteString = Integer.toString(minute);
}
if (second < 10) {
secondString = "0" + second;
} else {
secondString = Integer.toString(second);
}
if (nanos == 0) {
nanosString = "0";
} else {
nanosString = Integer.toString(nanos);
// Add leading zeros
nanosString = zeros.substring(0, (9-nanosString.length())) +
nanosString;
// Truncate trailing zeros
char[] nanosChar = new char[nanosString.length()];
nanosString.getChars(0, nanosString.length(), nanosChar, 0);
int truncIndex = 8;
while (nanosChar[truncIndex] == '0') {
truncIndex--;
while (tmpNanos % 10 == 0) {
tmpNanos /= 10;
trailingZeros++;
}
nanosString = new String(nanosChar, 0, truncIndex + 1);
}
// do a string buffer here instead.
timestampBuf = new StringBuffer(20+nanosString.length());
timestampBuf.append(yearString);
timestampBuf.append("-");
timestampBuf.append(monthString);
timestampBuf.append("-");
timestampBuf.append(dayString);
timestampBuf.append(" ");
timestampBuf.append(hourString);
timestampBuf.append(":");
timestampBuf.append(minuteString);
timestampBuf.append(":");
timestampBuf.append(secondString);
timestampBuf.append(".");
timestampBuf.append(nanosString);
// 8058429: To comply with current JCK tests, we need to deal with year
// being any number between 0 and 292278995
int count = 10000;
int yearSize = 4;
do {
if (year < count) {
break;
}
yearSize++;
count *= 10;
} while (count < 1000000000);
return (timestampBuf.toString());
char[] buf = new char[25 + yearSize - trailingZeros];
Date.formatDecimalInt(year, buf, 0, yearSize);
buf[yearSize] = '-';
Date.formatDecimalInt(month, buf, yearSize + 1, 2);
buf[yearSize + 3] = '-';
Date.formatDecimalInt(day, buf, yearSize + 4, 2);
buf[yearSize + 6] = ' ';
Date.formatDecimalInt(hour, buf, yearSize + 7, 2);
buf[yearSize + 9] = ':';
Date.formatDecimalInt(minute, buf, yearSize + 10, 2);
buf[yearSize + 12] = ':';
Date.formatDecimalInt(second, buf, yearSize + 13, 2);
buf[yearSize + 15] = '.';
Date.formatDecimalInt(tmpNanos, buf, yearSize + 16, 9 - trailingZeros);
return jla.newStringUnsafe(buf);
}
/**

View File

@ -1 +1 @@
sun.util.cldr.CLDRLocaleDataMetaInfo
sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo

View File

@ -26,6 +26,8 @@
package com.sun.security.jgss;
import org.ietf.jgss.*;
import sun.security.jgss.GSSContextImpl;
import sun.security.krb5.internal.AuthorizationData;
/**
* The extended GSSContext interface for supporting additional
@ -34,13 +36,48 @@ import org.ietf.jgss.*;
*/
@jdk.Exported
public interface ExtendedGSSContext extends GSSContext {
// The impl is almost identical to GSSContextImpl with only 2 differences:
// 1. It implements the extended interface
// 2. It translates result to data types here in inquireSecContext
static class ExtendedGSSContextImpl extends GSSContextImpl
implements ExtendedGSSContext {
public ExtendedGSSContextImpl(GSSContextImpl old) {
super(old);
}
@Override
public Object inquireSecContext(InquireType type) throws GSSException {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(
new InquireSecContextPermission(type.toString()));
}
Object output = super.inquireSecContext(type.name());
if (output != null) {
if (type == InquireType.KRB5_GET_AUTHZ_DATA) {
AuthorizationData ad = (AuthorizationData) output;
AuthorizationDataEntry[] authzData =
new AuthorizationDataEntry[ad.count()];
for (int i = 0; i < ad.count(); i++) {
authzData[i] = new AuthorizationDataEntry(
ad.item(i).adType, ad.item(i).adData);
}
output = authzData;
}
}
return output;
}
}
/**
* Return the mechanism-specific attribute associated with {@code type}.
* <p>
* If there is a security manager, an {@link InquireSecContextPermission}
* with the name {@code type.mech} must be granted. Otherwise, this could
* result in a {@link SecurityException}.<p>
*
* result in a {@link SecurityException}.
* <p>
* Example:
* <pre>
* GSSContext ctxt = m.createContext(...)

View File

@ -26,6 +26,7 @@
package com.sun.security.jgss;
import org.ietf.jgss.*;
import sun.security.jgss.GSSCredentialImpl;
/**
* The extended GSSCredential interface for supporting additional
@ -34,6 +35,15 @@ import org.ietf.jgss.*;
*/
@jdk.Exported
public interface ExtendedGSSCredential extends GSSCredential {
static class ExtendedGSSCredentialImpl extends GSSCredentialImpl
implements ExtendedGSSCredential {
public ExtendedGSSCredentialImpl(GSSCredentialImpl old) {
super(old);
}
}
/**
* Impersonates a principal. In Kerberos, this can be implemented
* using the Microsoft S4U2self extension.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
* 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
@ -23,27 +23,34 @@
* questions.
*/
package com.sun.security.jgss;
package sun.awt.windows;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import sun.security.jgss.GSSContextImpl;
import sun.security.jgss.GSSCredentialImpl;
import sun.security.jgss.JgssExtender;
import java.awt.Image;
import java.awt.Component;
/**
* This sun-private class exists solely to get a handle to
* the back buffer associated with a Component. If that
* Component has a BufferStrategy with >1 buffer, then the
* Image subclass associated with that buffer will be returned.
* Note: the class is used by the JAWT3d.
*/
public final class WBufferStrategy {
private static native void initIDs(Class <?> componentClass);
// The com.sun.security.jgss extension to JGSS-API
class Extender extends JgssExtender {
static {
initIDs(Component.class);
JgssExtender.setExtender(new Extender());
}
public static native Image getDrawBuffer(Component comp);
public GSSCredential wrap(GSSCredential cred) {
if (cred instanceof ExtendedGSSCredential.ExtendedGSSCredentialImpl) {
return cred;
} else {
return new ExtendedGSSCredential.ExtendedGSSCredentialImpl((GSSCredentialImpl)cred);
}
}
public GSSContext wrap(GSSContext ctxt) {
if (ctxt instanceof ExtendedGSSContext.ExtendedGSSContextImpl) {
return ctxt;
} else {
return new ExtendedGSSContext.ExtendedGSSContextImpl((GSSContextImpl)ctxt);
}
}
}

View File

@ -139,9 +139,6 @@ com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java aix-all
com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java aix-all
javax/management/MBeanServer/OldMBeanServerTest.java aix-all
# 8050115
javax/management/monitor/GaugeMonitorDeadlockTest.java generic-all
############################################################################
# jdk_math

View File

@ -8,7 +8,7 @@ keys=2d dnd i18n
othervm.dirs=java/awt java/beans javax/accessibility javax/imageio javax/sound javax/print javax/management com/sun/awt sun/awt sun/java2d sun/pisces
# Tests that cannot run concurrently
exclusiveAccess.dirs=java/rmi/Naming java/util/prefs sun/management/jmxremote sun/tools/jstatd sun/security/mscapi
exclusiveAccess.dirs=java/rmi/Naming java/util/prefs sun/management/jmxremote sun/tools/jstatd sun/security/mscapi java/util/stream
# Group definitions
groups=TEST.groups [closed/TEST.groups]

View File

@ -0,0 +1,76 @@
/*
* 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.
*
* 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.
*/
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
/**
* @test
* @bug 8056009
* @summary tests whether Graphics.setColor-calls with Color.white are ignored directly
* after pipeline initialization for a certain set of operations.
* @author ceisserer
*/
public class WhiteTextColorTest extends Frame {
public static volatile boolean success = false;
public WhiteTextColorTest() {
Image dstImg = getGraphicsConfiguration()
.createCompatibleVolatileImage(30, 20);
Graphics g = dstImg.getGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, dstImg.getWidth(null), dstImg.getHeight(null));
g.setColor(Color.WHITE);
g.drawString("Test", 0, 15);
BufferedImage readBackImg = new BufferedImage(dstImg.getWidth(null),
dstImg.getHeight(null), BufferedImage.TYPE_INT_RGB);
readBackImg.getGraphics().drawImage(dstImg, 0, 0, null);
for (int x = 0; x < readBackImg.getWidth(); x++) {
for (int y = 0; y < readBackImg.getHeight(); y++) {
int pixel = readBackImg.getRGB(x, y);
// In case a single white pixel is found, the
// setColor(Color.WHITE)
// call before was not ignored and the bug is not present
if (pixel == 0xFFFFFFFF) {
return;
}
}
}
throw new RuntimeException("Test Failed");
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new WhiteTextColorTest();
}
});
}
}

View File

@ -0,0 +1,293 @@
/*
* 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.
*
* 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.
*/
import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
/*
@test
@summary Toplevel should be correctly positioned as relative to a component:
so that their centers coincide
or, if the component is hidden, centered on the screen.
@bug 8036915
@library ../../../../lib/testlibrary
@build ExtendedRobot
@run main/timeout=1200 SetLocationRelativeToTest
*/
public class SetLocationRelativeToTest {
private static int delay = 500;
private static boolean testEverything = false;// NB: change this to true to test everything
java.util.List<Window> awtToplevels = new ArrayList<Window>();
java.util.List<Window> swingToplevels = new ArrayList<Window>();
java.util.List<Window> allToplevels = new ArrayList<Window>();
java.util.List<Component> awtComponents = new ArrayList<Component>();
java.util.List<Component> swingComponents = new ArrayList<Component>();
java.util.List<Component> allComponents = new ArrayList<Component>();
Label placeholder = new Label();
JLabel jplaceholder = new JLabel();
JFrame jcontainer;
public SetLocationRelativeToTest() {
Frame frame = new Frame("Frame");
frame.setSize(200,100);
Frame uframe = new Frame("U.Frame");
uframe.setUndecorated(true);
uframe.setSize(200,100);
Window window = new Window(frame);
window.setSize(200,100);
Dialog dialog = new Dialog(frame, "Dialog");
dialog.setSize(200,100);
awtToplevels.add(frame);
awtToplevels.add(uframe);
awtToplevels.add(window);
awtToplevels.add(dialog);
awtComponents.add(new TextArea("Am a TextArea"));
awtComponents.add(new TextField("Am a TextField"));
awtComponents.add(new Button("Press"));
awtComponents.add(new Label("Label"));
Choice aChoice = new Choice();
aChoice.add("One");
aChoice.add("Two");
awtComponents.add(aChoice);
awtComponents.add(new Canvas());
awtComponents.add(new List(4));
awtComponents.add(new Checkbox("Me CheckBox"));
awtComponents.add(new Scrollbar());
swingComponents.add(new JTextArea("Am a JTextArea"));
swingComponents.add(new JTextField("Am a JTextField"));
swingComponents.add(new JButton("Press"));
swingComponents.add(new JLabel("JLabel"));
JComboBox jcombo = new JComboBox();
swingComponents.add(jcombo);
swingComponents.add(new JPanel());
swingComponents.add(new JList());
swingComponents.add(new JCheckBox("Me JCheckBox"));
swingComponents.add(new JScrollBar());
}
public static void main(String args[]) {
SetLocationRelativeToTest test = new SetLocationRelativeToTest();
test.doAWTTest(true);
test.doAWTTest(false);
try {
test.doSwingTest(true);
test.doSwingTest(false);
}catch(InterruptedException ie) {
ie.printStackTrace();
}catch(java.lang.reflect.InvocationTargetException ite) {
ite.printStackTrace();
throw new RuntimeException("InvocationTarget?");
}
return;
}
// In regular testing, we select just few components to test
// randomly. If full testing required, select many ("all").
void selectObjectsToTest(boolean doSwing) {
allToplevels.clear();
allComponents.clear();
if(testEverything) {
allToplevels.addAll(0, awtToplevels);
allComponents.addAll(0, awtComponents);
if(doSwing) {
allToplevels.addAll(allToplevels.size(), swingToplevels);
allComponents.addAll(allComponents.size(), swingComponents);
}
}else{
//select a random of each
int i = (int)(java.lang.Math.random()*awtToplevels.size());
allToplevels.add(awtToplevels.get(i));
i = (int)(java.lang.Math.random()*awtComponents.size());
allComponents.add(awtComponents.get(i));
if(doSwing) {
i = (int)(java.lang.Math.random()*swingToplevels.size());
allToplevels.add(swingToplevels.get(i));
i = (int)(java.lang.Math.random()*swingComponents.size());
allComponents.add(swingComponents.get(i));
}
}
}
// create Frame, add an AWT component to it,
// hide it (or not) and position a new toplevel
// relativeTo
void doAWTTest(boolean isHidden) {
boolean res;
ExtendedRobot robot;
try {
robot = new ExtendedRobot();
}catch(Exception ex) {
ex.printStackTrace();
throw new RuntimeException("Failed: "+ex.getMessage());
}
Frame container = new Frame("Frame");
container.setBounds(100,100,300,300);
container.setLayout(new GridLayout(3,1));
container.add(placeholder);
container.setVisible(true);
selectObjectsToTest(false);
for(Component c: allComponents) {
placeholder.setText((isHidden ? "Hidden: " : "Below is ")+ c.getClass().getName());
c.setVisible(true);
container.add(c);
container.doLayout();
if(isHidden) {
c.setVisible(false);
}
robot.waitForIdle(delay);
for(Window w: allToplevels) {
w.setLocationRelativeTo(c);
w.setVisible(true);
robot.waitForIdle(delay);
res = compareLocations(w, c, robot);
System.out.println(c.getClass().getName()+" \t: "+w.getClass().getName()+
((w instanceof Frame) && (((Frame)w).isUndecorated()) ? " undec\t\t:" : "\t\t:")+" "+
(res ? "" : "Failed"));
if(!res) {
throw new RuntimeException("Test failed.");
}
w.dispose();
}
container.remove(c);
robot.waitForIdle(delay);
}
container.dispose();
}
// Create JFrame, add an AWT or Swing component to it,
// hide it (or not) and position a new toplevel
// relativeTo
void doSwingTest(boolean isHidden) throws InterruptedException,
java.lang.reflect.InvocationTargetException {
boolean res;
ExtendedRobot robot;
try {
robot = new ExtendedRobot();
}catch(Exception ex) {
ex.printStackTrace();
throw new RuntimeException("Failed: "+ex.getMessage());
}
EventQueue.invokeAndWait( () -> {
JFrame jframe = new JFrame("jframe");
jframe.setSize(200,100);
swingToplevels.add(jframe);
JFrame ujframe = new JFrame("ujframe");
ujframe.setSize(200,100);
ujframe.setUndecorated(true);
swingToplevels.add(ujframe);
JWindow jwin = new JWindow();
jwin.setSize(200,100);
swingToplevels.add(jwin);
JDialog jdia = new JDialog((Frame)null, "JDialog");
jdia.setSize(200,100);
swingToplevels.add(jdia);
jcontainer = new JFrame("JFrame");
jcontainer.setBounds(100,100,300,300);
jcontainer.setLayout(new GridLayout(3,1));
jcontainer.add(jplaceholder);
jcontainer.setVisible(true);
selectObjectsToTest(true);
});
robot.waitForIdle(delay);
for(Component c: allComponents) {
EventQueue.invokeAndWait( () -> {
jplaceholder.setText((isHidden ? "Hidden: " : "Below is: ")+ c.getClass().getName());
c.setVisible(true);
jcontainer.add(c);
jcontainer.doLayout();
if(isHidden) {
c.setVisible(false);
}
});
robot.waitForIdle(delay);
for(Window w: allToplevels) {
EventQueue.invokeAndWait( () -> {
w.setLocationRelativeTo(c);
w.setVisible(true);
});
robot.waitForIdle(delay);
res = compareLocations(w, c, robot);
System.out.println(c.getClass().getName()+" \t: "+w.getClass().getName()+
((w instanceof Frame) && (((Frame)w).isUndecorated()) ? " undec\t\t:" : "\t\t:")+" "+
(res ? "" : "Failed"));
EventQueue.invokeAndWait( () -> {
w.dispose();
});
robot.waitForIdle();
if(!res) {
throw new RuntimeException("Test failed.");
}
}
EventQueue.invokeAndWait( () -> {
jcontainer.remove(c);
});
robot.waitForIdle(delay);
}
EventQueue.invokeAndWait( () -> {
jcontainer.dispose();
});
}
// Check, finally, if w either is concentric with c
// or sits in the center of the screen (if c is hidden)
boolean compareLocations(final Window w, final Component c, ExtendedRobot robot) {
final Point pc = new Point();
final Point pw = new Point();
try {
EventQueue.invokeAndWait( () -> {
pw.setLocation(w.getLocationOnScreen());
pw.translate(w.getWidth()/2, w.getHeight()/2);
if(!c.isVisible()) {
Rectangle screenRect = w.getGraphicsConfiguration().getBounds();
pc.setLocation(screenRect.x+screenRect.width/2,
screenRect.y+screenRect.height/2);
}else{
pc.setLocation(c.getLocationOnScreen());
pc.translate(c.getWidth()/2, c.getHeight()/2);
}
});
} catch(InterruptedException ie) {
throw new RuntimeException("Interrupted");
} catch(java.lang.reflect.InvocationTargetException ite) {
ite.printStackTrace();
throw new RuntimeException("InvocationTarget?");
}
robot.waitForIdle(delay);
// Compare with 1 tolerance to forgive possible rounding errors
if(pc.x - pw.x > 1 ||
pc.x - pw.x < -1 ||
pc.y - pw.y > 1 ||
pc.y - pw.y < -1 ) {
System.out.println("Center of "+(c.isVisible() ? "Component:" : "screen:")+pc);
System.out.println("Center of Window:"+pw);
System.out.println("Centers of "+w+" and "+c+" do not coincide");
return false;
}
return true;
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2014 Google Inc. 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.
*
* 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.
*/
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.text.AttributedString;
import javax.imageio.ImageIO;
/**
* Manual test for:
* JDK-8057986: freetype code to get glyph outline does not handle initial control point properly
*
* Manual repro recipe:
* (cd test/java/awt/font/GlyphVector/ && javac GlyphVectorOutline.java && wget -q -O/tmp/msgothic.ttc https://browserlinux-jp.googlecode.com/files/msgothic.ttc && java GlyphVectorOutline /tmp/msgothic.ttc /tmp/katakana.png)
*
* Then examine the two rendered Japanese characters in the png file.
*
* Renders text to a PNG by
* 1. using the native Graphics2D#drawGlyphVector implementation
* 2. filling in the result of GlyphVector#getOutline
*
* Should be the same but is different for some CJK characters
* (e.g. Katakana character \u30AF).
*
* @author ikopylov@google.com (Igor Kopylov)
*/
public class GlyphVectorOutline {
public static void main(String[] args) throws Exception {
if (args.length != 2) {
throw new Error("Usage: java GlyphVectorOutline fontfile outputfile");
}
writeImage(new File(args[0]),
new File(args[1]),
"\u30AF");
}
public static void writeImage(File fontFile, File outputFile, String value) throws Exception {
BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.setColor(Color.BLACK);
Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile);
font = font.deriveFont(Font.PLAIN, 72f);
FontRenderContext frc = new FontRenderContext(null, false, false);
GlyphVector gv = font.createGlyphVector(frc, value);
g.drawGlyphVector(gv, 10, 80);
g.fill(gv.getOutline(10, 180));
ImageIO.write(image, "png", outputFile);
}
private static void drawString(Graphics2D g, Font font, String value, float x, float y) {
AttributedString str = new AttributedString(value);
str.addAttribute(TextAttribute.FOREGROUND, Color.BLACK);
str.addAttribute(TextAttribute.FONT, font);
FontRenderContext frc = new FontRenderContext(null, true, true);
TextLayout layout = new LineBreakMeasurer(str.getIterator(), frc).nextLayout(Integer.MAX_VALUE);
layout.draw(g, x, y);
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.
*
* 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.
*/
import java.lang.invoke.MethodHandle;
import java.lang.reflect.InvocationTargetException;
/**
* Abstract class for lambda forms caching testing.
*
* @author kshefov
*/
public abstract class LFCachingTestCase extends LambdaFormTestCase {
/**
* Constructor for lambda forms caching test case.
*
* @param testMethod A method from {@code j.l.i.MethodHandles} class that
* returns a {@code j.l.i.MethodHandle} instance.
*/
protected LFCachingTestCase(TestMethods testMethod) {
super(testMethod);
}
/**
* Checks that the lambda forms of the two adapter method handles adapter1
* and adapter2 are the same.
*
* @param adapter1 First method handle.
* @param adapter2 Second method handle.
*/
public void checkLFCaching(MethodHandle adapter1, MethodHandle adapter2) {
try {
if (!adapter1.type().equals(adapter2.type())) {
throw new Error("TESTBUG: Types of the two method handles are not the same");
}
Object lambdaForm0 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter1);
Object lambdaForm1 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter2);
if (lambdaForm0 == null || lambdaForm1 == null) {
throw new Error("Unexpected error: One or both lambda forms of the method handles are null");
}
if (lambdaForm0 != lambdaForm1) {
System.err.println("Lambda form 0 toString is:");
System.err.println(lambdaForm0);
System.err.println("Lambda form 1 toString is:");
System.err.println(lambdaForm1);
throw new AssertionError("Error: Lambda forms of the two method handles"
+ " are not the same. LF cahing does not work");
}
} catch (IllegalAccessException | IllegalArgumentException |
SecurityException | InvocationTargetException ex) {
throw new Error("Unexpected exception: ", ex);
}
}
}

View File

@ -0,0 +1,103 @@
/*
* 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.
*
* 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.
*/
/*
* @test LFGarbageCollectedTest
* @bug 8046703
* @summary Test verifies that lambda forms are garbage collected
* @author kshefov
* @ignore 8057020
* @library /lib/testlibrary/jsr292 /lib/testlibrary
* @build TestMethods
* @build LambdaFormTestCase
* @build LFGarbageCollectedTest
* @run main/othervm/timeout=600 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true -DtestLimit=150 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI LFGarbageCollectedTest
*/
import java.lang.invoke.MethodHandle;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Map;
/**
* Lambda forms garbage collection test class.
*/
public final class LFGarbageCollectedTest extends LambdaFormTestCase {
/**
* Constructor for a lambda forms garbage collection test case.
*
* @param testMethod A method from {@code j.l.i.MethodHandles} class that
* returns a {@code j.l.i.MethodHandle} instance.
*/
public LFGarbageCollectedTest(TestMethods testMethod) {
super(testMethod);
}
@Override
public void doTest() {
try {
Map<String, Object> data = getTestMethod().getTestCaseData();
MethodHandle adapter;
try {
adapter = getTestMethod().getTestCaseMH(data, TestMethods.Kind.ONE);
} catch (NoSuchMethodException ex) {
throw new Error("Unexpected exception: ", ex);
}
Object lambdaForm = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter);
if (lambdaForm == null) {
throw new Error("Unexpected error: Lambda form of the method handle is null");
}
ReferenceQueue rq = new ReferenceQueue();
PhantomReference ph = new PhantomReference(lambdaForm, rq);
lambdaForm = null;
data = null;
adapter = null;
for (int i = 0; i < 1000 && !ph.isEnqueued(); i++) {
System.gc();
}
if (!ph.isEnqueued()) {
throw new AssertionError("Error: Lambda form is not garbage collected");
}
} catch (IllegalAccessException | IllegalArgumentException |
InvocationTargetException ex) {
throw new Error("Unexpected exception: ", ex);
}
}
/**
* Main routine for lambda forms garbage collection test.
*
* @param args Accepts no arguments.
*/
public static void main(String[] args) {
// The "identity" and "constant" methods should be removed from this test,
// because their lambda forms are stored in a static filed and are not GC'ed.
// There can be only 5 such LFs for each method, so no memory leak happens.
EnumSet<TestMethods> testMethods = EnumSet.complementOf(EnumSet.of(TestMethods.IDENTITY, TestMethods.CONSTANT));
LambdaFormTestCase.runTests(LFGarbageCollectedTest::new, testMethods);
}
}

View File

@ -0,0 +1,111 @@
/*
* 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.
*
* 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.
*/
/*
* @test LFMultiThreadCachingTest
* @bug 8046703
* @summary Test verifies that lambda forms are cached when run with multiple threads
* @author kshefov
* @library /lib/testlibrary/jsr292 /lib/testlibrary
* @build TestMethods
* @build LambdaFormTestCase
* @build LFCachingTestCase
* @build LFMultiThreadCachingTest
* @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFMultiThreadCachingTest
*/
import java.lang.invoke.MethodHandle;
import java.util.EnumSet;
import java.util.Map;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
/**
* Multiple threaded lambda forms caching test class.
*/
public final class LFMultiThreadCachingTest extends LFCachingTestCase {
private static final TestMethods.Kind[] KINDS;
static {
EnumSet<TestMethods.Kind> set = EnumSet.complementOf(EnumSet.of(TestMethods.Kind.EXCEPT));
KINDS = set.toArray(new TestMethods.Kind[set.size()]);
if (KINDS.length < 2) {
throw new Error("TESTBUG: KINDS.length[" + KINDS.length + "] should be at least 2");
}
}
private static final int CORES = Math.max(KINDS.length, Runtime.getRuntime().availableProcessors());
/**
* Constructor a for multiple threaded lambda forms caching test case.
*
* @param testMethod A method from {@code j.l.i.MethodHandles} class that
* returns a {@code j.l.i.MethodHandle} instance.
*/
public LFMultiThreadCachingTest(TestMethods testMethod) {
super(testMethod);
}
@Override
public void doTest() {
Map<String, Object> data = getTestMethod().getTestCaseData();
ConcurrentLinkedQueue<MethodHandle> adapters = new ConcurrentLinkedQueue<>();
CyclicBarrier begin = new CyclicBarrier(CORES);
CountDownLatch end = new CountDownLatch(CORES);
for (int i = 0; i < CORES; ++i) {
TestMethods.Kind kind = KINDS[i % KINDS.length];
new Thread(() -> {
try {
begin.await();
adapters.add(getTestMethod().getTestCaseMH(data, kind));
} catch (InterruptedException | BrokenBarrierException | IllegalAccessException | NoSuchMethodException ex) {
throw new Error("Unexpected exception: ", ex);
} finally {
end.countDown();
}
}).start();
}
try {
end.await();
} catch (InterruptedException ex) {
throw new Error("Unexpected exception: ", ex);
}
if (adapters.size() < CORES) {
throw new Error("adapters size[" + adapters.size() + "] is less than " + CORES);
}
MethodHandle prev = adapters.poll();
for (MethodHandle current : adapters) {
checkLFCaching(prev, current);
prev = current;
}
}
/**
* Main routine for multiple threaded lambda forms caching test.
*
* @param args Accepts no arguments.
*/
public static void main(String[] args) {
LambdaFormTestCase.runTests(LFMultiThreadCachingTest::new, EnumSet.allOf(TestMethods.class));
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.
*
* 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.
*/
/*
* @test LFSingleThreadCachingTest
* @bug 8046703
* @summary Test verifies that lambda forms are cached when run with single thread
* @author kshefov
* @library /lib/testlibrary/jsr292 /lib/testlibrary
* @build TestMethods
* @build LambdaFormTestCase
* @build LFCachingTestCase
* @build LFSingleThreadCachingTest
* @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFSingleThreadCachingTest
*/
import java.lang.invoke.MethodHandle;
import java.util.EnumSet;
import java.util.Map;
/**
* Single threaded lambda forms caching test class.
*/
public final class LFSingleThreadCachingTest extends LFCachingTestCase {
/**
* Constructor for a single threaded lambda forms caching test case.
*
* @param testMethod A method from {@code j.l.i.MethodHandles} class that
* returns a {@code j.l.i.MethodHandle} instance.
*/
public LFSingleThreadCachingTest(TestMethods testMethod) {
super(testMethod);
}
@Override
public void doTest() {
MethodHandle adapter1;
MethodHandle adapter2;
Map<String, Object> data = getTestMethod().getTestCaseData();
try {
adapter1 = getTestMethod().getTestCaseMH(data, TestMethods.Kind.ONE);
adapter2 = getTestMethod().getTestCaseMH(data, TestMethods.Kind.TWO);
} catch (NoSuchMethodException | IllegalAccessException ex) {
throw new Error("Unexpected exception: ", ex);
}
checkLFCaching(adapter1, adapter2);
}
/**
* Main routine for single threaded lambda forms caching test.
*
* @param args Accepts no arguments.
*/
public static void main(String[] args) {
LambdaFormTestCase.runTests(LFSingleThreadCachingTest::new, EnumSet.allOf(TestMethods.class));
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.
*
* 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.
*/
import com.oracle.testlibrary.jsr292.Helper;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.function.Function;
/**
* Lambda forms caching test case class. Contains all necessary test routines to
* test lambda forms caching in method handles returned by methods of
* MethodHandles class.
*
* @author kshefov
*/
public abstract class LambdaFormTestCase {
private final static String METHOD_HANDLE_CLASS_NAME = "java.lang.invoke.MethodHandle";
private final static String INTERNAL_FORM_METHOD_NAME = "internalForm";
/**
* Reflection link to {@code j.l.i.MethodHandle.internalForm} method. It is
* used to get a lambda form from a method handle.
*/
protected final static Method INTERNAL_FORM;
static {
try {
Class mhClass = Class.forName(METHOD_HANDLE_CLASS_NAME);
INTERNAL_FORM = mhClass.getDeclaredMethod(INTERNAL_FORM_METHOD_NAME);
INTERNAL_FORM.setAccessible(true);
} catch (Exception ex) {
throw new Error("Unexpected exception: ", ex);
}
}
private final TestMethods testMethod;
/**
* Test case constructor. Generates test cases with random method types for
* given methods form {@code j.l.i.MethodHandles} class.
*
* @param testMethod A method from {@code j.l.i.MethodHandles} class which
* returns a {@code j.l.i.MethodHandle}.
*/
protected LambdaFormTestCase(TestMethods testMethod) {
this.testMethod = testMethod;
}
public TestMethods getTestMethod() {
return testMethod;
}
/**
* Routine that executes a test case.
*/
public abstract void doTest();
/**
* Runs a number of test cases defined by the size of testCases list.
*
* @param ctor constructor of LambdaFormCachingTest or its child classes
* object.
* @param testMethods list of test methods
*/
public static void runTests(Function<TestMethods, LambdaFormTestCase> ctor, Collection<TestMethods> testMethods) {
boolean passed = true;
int testCounter = 0;
int failCounter = 0;
long iterations = Math.max(1, Helper.TEST_LIMIT / testMethods.size());
for (long i = 0; i < iterations; i++) {
System.err.println(String.format("Iteration %d:", i));
for (TestMethods testMethod : testMethods) {
LambdaFormTestCase testCase = ctor.apply(testMethod);
try {
System.err.printf("Tested LF caching feature with MethodHandles.%s method.%n",
testCase.getTestMethod().name);
testCase.doTest();
System.err.println("PASSED");
} catch (Throwable t) {
t.printStackTrace();
System.err.println("FAILED");
passed = false;
failCounter++;
}
testCounter++;
}
}
if (!passed) {
throw new Error(String.format("%d of %d test cases FAILED! %n"
+ "Rerun the test with the same \"-Dseed=\" option as in the log file!",
failCounter, testCounter));
} else {
System.err.println(String.format("All %d test cases PASSED!", testCounter));
}
}
}

View File

@ -0,0 +1,698 @@
/*
* 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.
*
* 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.
*/
import com.oracle.testlibrary.jsr292.Helper;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Enumeration containing information about methods from
* {@code j.l.i.MethodHandles} class that are used for testing lambda forms
* caching.
*
* @author kshefov
*/
public enum TestMethods {
FOLD_ARGUMENTS("foldArguments") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
// Arity after reducing because of long and double take 2 slots.
int realArity = mtTarget.parameterCount();
int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1);
data.put("modifierMHArgNum", modifierMHArgNum);
Class<?> combinerReturnType;
if (realArity == 0) {
combinerReturnType = void.class;
} else {
combinerReturnType = Helper.RNG.nextBoolean() ? void.class : mtTarget.parameterType(0);
}
data.put("combinerReturnType", combinerReturnType);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException {
MethodType mtTarget = (MethodType) data.get("mtTarget");
Class<?> combinerReturnType = (Class) data.get("combinerReturnType");
int modifierMHArgNum = (int) data.get("modifierMHArgNum");
MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(),
mtTarget.parameterList(), kind);
Class<?> rType = mtTarget.returnType();
int combListStart = (combinerReturnType == void.class) ? 0 : 1;
if (modifierMHArgNum < combListStart) {
modifierMHArgNum = combListStart;
}
MethodHandle combiner = TestMethods.methodHandleGenerator(combinerReturnType,
mtTarget.parameterList().subList(combListStart,
modifierMHArgNum), kind);
return MethodHandles.foldArguments(target, combiner);
}
},
DROP_ARGUMENTS("dropArguments") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
// Arity after reducing because of long and double take 2 slots.
int realArity = mtTarget.parameterCount();
int dropArgsPos = Helper.RNG.nextInt(realArity + 1);
data.put("dropArgsPos", dropArgsPos);
MethodType mtDropArgs = TestMethods.randomMethodTypeGenerator(
Helper.RNG.nextInt(Helper.MAX_ARITY - realArity));
data.put("mtDropArgs", mtDropArgs);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException {
MethodType mtTarget = (MethodType) data.get("mtTarget");
MethodType mtDropArgs = (MethodType) data.get("mtDropArgs");
int dropArgsPos = (int) data.get("dropArgsPos");
MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(),
mtTarget.parameterList(), kind);
int mtTgtSlotsCount = TestMethods.argSlotsCount(mtTarget);
int mtDASlotsCount = TestMethods.argSlotsCount(mtDropArgs);
List<Class<?>> fakeParList;
if (mtTgtSlotsCount + mtDASlotsCount > Helper.MAX_ARITY - 1) {
fakeParList = TestMethods.reduceArgListToSlotsCount(mtDropArgs.parameterList(),
Helper.MAX_ARITY - mtTgtSlotsCount - 1);
} else {
fakeParList = mtDropArgs.parameterList();
}
return MethodHandles.dropArguments(target, dropArgsPos, fakeParList);
}
},
EXPLICIT_CAST_ARGUMENTS("explicitCastArguments") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
// Arity after reducing because of long and double take 2 slots.
int realArity = mtTarget.parameterCount();
MethodType mtExcplCastArgs = TestMethods.randomMethodTypeGenerator(realArity);
if (mtTarget.returnType() == void.class) {
mtExcplCastArgs = MethodType.methodType(void.class,
mtExcplCastArgs.parameterArray());
}
if (mtExcplCastArgs.returnType() == void.class) {
mtExcplCastArgs = MethodType.methodType(mtTarget.returnType(),
mtExcplCastArgs.parameterArray());
}
data.put("mtExcplCastArgs", mtExcplCastArgs);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException {
MethodType mtTarget = (MethodType) data.get("mtTarget");
MethodType mtExcplCastArgs = (MethodType) data.get("mtExcplCastArgs");
MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(),
mtTarget.parameterList(), kind);
return MethodHandles.explicitCastArguments(target, mtExcplCastArgs);
}
},
FILTER_ARGUMENTS("filterArguments") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
// Arity after reducing because of long and double take 2 slots.
int realArity = mtTarget.parameterCount();
int filterArgsPos = Helper.RNG.nextInt(realArity + 1);
data.put("filterArgsPos", filterArgsPos);
int filtersArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - filterArgsPos);
data.put("filtersArgsArrayLength", filtersArgsArrayLength);
MethodType mtFilter = TestMethods.randomMethodTypeGenerator(filtersArgsArrayLength);
data.put("mtFilter", mtFilter);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException {
MethodType mtTarget = (MethodType) data.get("mtTarget");
MethodType mtFilter = (MethodType) data.get("mtFilter");
int filterArgsPos = (int) data.get("filterArgsPos");
int filtersArgsArrayLength = (int) data.get("filtersArgsArrayLength");
MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(),
mtTarget.parameterList(), kind);
MethodHandle[] filters = new MethodHandle[filtersArgsArrayLength];
for (int i = 0; i < filtersArgsArrayLength; i++) {
filters[i] = TestMethods.filterGenerator(mtFilter.parameterType(i),
mtTarget.parameterType(filterArgsPos + i), kind);
}
return MethodHandles.filterArguments(target, filterArgsPos, filters);
}
},
FILTER_RETURN_VALUE("filterReturnValue") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
// Arity after reducing because of long and double take 2 slots.
int realArity = mtTarget.parameterCount();
int filterArgsPos = Helper.RNG.nextInt(realArity + 1);
int filtersArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - filterArgsPos);
MethodType mtFilter = TestMethods.randomMethodTypeGenerator(filtersArgsArrayLength);
data.put("mtFilter", mtFilter);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException {
MethodType mtTarget = (MethodType) data.get("mtTarget");
MethodType mtFilter = (MethodType) data.get("mtFilter");
MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(),
mtTarget.parameterList(), kind);
MethodHandle filter = TestMethods.filterGenerator(mtTarget.returnType(),
mtFilter.returnType(), kind);
return MethodHandles.filterReturnValue(target, filter);
}
},
INSERT_ARGUMENTS("insertArguments") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
// Arity after reducing because of long and double take 2 slots.
int realArity = mtTarget.parameterCount();
int insertArgsPos = Helper.RNG.nextInt(realArity + 1);
data.put("insertArgsPos", insertArgsPos);
int insertArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - insertArgsPos);
MethodType mtInsertArgs = MethodType.methodType(void.class, mtTarget.parameterList()
.subList(insertArgsPos, insertArgsPos + insertArgsArrayLength));
data.put("mtInsertArgs", mtInsertArgs);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException {
MethodType mtTarget = (MethodType) data.get("mtTarget");
MethodType mtInsertArgs = (MethodType) data.get("mtInsertArgs");
int insertArgsPos = (int) data.get("insertArgsPos");
MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(),
mtTarget.parameterList(), kind);
Object[] insertList = Helper.randomArgs(mtInsertArgs.parameterList());
return MethodHandles.insertArguments(target, insertArgsPos, insertList);
}
},
PERMUTE_ARGUMENTS("permuteArguments") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
// Arity after reducing because of long and double take 2 slots.
int realArity = mtTarget.parameterCount();
int[] permuteArgsReorderArray = new int[realArity];
int mtParmuteArgsNum = Helper.RNG.nextInt(Helper.MAX_ARITY);
mtParmuteArgsNum = mtParmuteArgsNum == 0 ? 1 : mtParmuteArgsNum;
MethodType mtPermuteArgs = TestMethods.randomMethodTypeGenerator(mtParmuteArgsNum);
mtTarget = mtTarget.changeReturnType(mtPermuteArgs.returnType());
for (int i = 0; i < realArity; i++) {
int mtPermuteArgsParNum = Helper.RNG.nextInt(mtPermuteArgs.parameterCount());
permuteArgsReorderArray[i] = mtPermuteArgsParNum;
mtTarget = mtTarget.changeParameterType(
i, mtPermuteArgs.parameterType(mtPermuteArgsParNum));
}
data.put("mtTarget", mtTarget);
data.put("permuteArgsReorderArray", permuteArgsReorderArray);
data.put("mtPermuteArgs", mtPermuteArgs);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException {
MethodType mtTarget = (MethodType) data.get("mtTarget");
MethodType mtPermuteArgs = (MethodType) data.get("mtPermuteArgs");
int[] permuteArgsReorderArray = (int[]) data.get("permuteArgsReorderArray");
MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(),
mtTarget.parameterList(), kind);
return MethodHandles.permuteArguments(target, mtPermuteArgs, permuteArgsReorderArray);
}
},
THROW_EXCEPTION("throwException") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) {
MethodType mtTarget = (MethodType) data.get("mtTarget");
Class<?> rType = mtTarget.returnType();
return MethodHandles.throwException(rType, Exception.class
);
}
},
GUARD_WITH_TEST("guardWithTest") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
// Arity after reducing because of long and double take 2 slots.
int realArity = mtTarget.parameterCount();
int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1);
data.put("modifierMHArgNum", modifierMHArgNum);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException {
MethodType mtTarget = (MethodType) data.get("mtTarget");
int modifierMHArgNum = (int) data.get("modifierMHArgNum");
TestMethods.Kind targetKind;
TestMethods.Kind fallbackKind;
if (kind.equals(TestMethods.Kind.ONE)) {
targetKind = TestMethods.Kind.ONE;
fallbackKind = TestMethods.Kind.TWO;
} else {
targetKind = TestMethods.Kind.TWO;
fallbackKind = TestMethods.Kind.ONE;
}
MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(),
mtTarget.parameterList(), targetKind);
MethodHandle fallback = TestMethods.methodHandleGenerator(mtTarget.returnType(),
mtTarget.parameterList(), fallbackKind);
MethodHandle test = TestMethods.methodHandleGenerator(boolean.class,
mtTarget.parameterList().subList(0, modifierMHArgNum), kind);
return MethodHandles.guardWithTest(test, target, fallback);
}
},
CATCH_EXCEPTION("catchException") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
// Arity after reducing because of long and double take 2 slots.
int realArity = mtTarget.parameterCount();
int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1);
data.put("modifierMHArgNum", modifierMHArgNum);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException {
MethodType mtTarget = (MethodType) data.get("mtTarget");
int modifierMHArgNum = (int) data.get("modifierMHArgNum");
MethodHandle target;
if (kind.equals(TestMethods.Kind.ONE)) {
target = TestMethods.methodHandleGenerator(mtTarget.returnType(),
mtTarget.parameterList(), TestMethods.Kind.ONE);
} else {
target = TestMethods.methodHandleGenerator(mtTarget.returnType(),
mtTarget.parameterList(), TestMethods.Kind.EXCEPT);
}
List<Class<?>> handlerParamList = new ArrayList<>(mtTarget.parameterCount() + 1);
handlerParamList.add(Exception.class);
handlerParamList.addAll(mtTarget.parameterList().subList(0, modifierMHArgNum));
MethodHandle handler = TestMethods.methodHandleGenerator(
mtTarget.returnType(), handlerParamList, TestMethods.Kind.TWO);
return MethodHandles.catchException(target, Exception.class, handler);
}
},
INVOKER("invoker") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) {
MethodType mtTarget = (MethodType) data.get("mtTarget");
return MethodHandles.invoker(mtTarget);
}
},
EXACT_INVOKER("exactInvoker") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) {
MethodType mtTarget = (MethodType) data.get("mtTarget");
return MethodHandles.exactInvoker(mtTarget);
}
},
SPREAD_INVOKER("spreadInvoker") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
// Arity after reducing because of long and double take 2 slots.
int realArity = mtTarget.parameterCount();
int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1);
data.put("modifierMHArgNum", modifierMHArgNum);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) {
MethodType mtTarget = (MethodType) data.get("mtTarget");
int modifierMHArgNum = (int) data.get("modifierMHArgNum");
return MethodHandles.spreadInvoker(mtTarget, modifierMHArgNum);
}
},
ARRAY_ELEMENT_GETTER("arrayElementGetter") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) {
MethodType mtTarget = (MethodType) data.get("mtTarget");
Class<?> rType = mtTarget.returnType();
if (rType == void.class) {
rType = Object.class;
}
return MethodHandles.arrayElementGetter(Array.newInstance(rType, 2).getClass());
}
},
ARRAY_ELEMENT_SETTER("arrayElementSetter") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) {
MethodType mtTarget = (MethodType) data.get("mtTarget");
Class<?> rType = mtTarget.returnType();
if (rType == void.class) {
rType = Object.class;
}
return MethodHandles.arrayElementSetter(Array.newInstance(rType, 2).getClass());
}
},
CONSTANT("constant") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) {
MethodType mtTarget = (MethodType) data.get("mtTarget");
Class<?> rType = mtTarget.returnType();
if (rType == void.class) {
rType = Object.class;
}
if (rType.equals(boolean.class)) {
// There should be the same return values because for default values there are special "zero" forms
return MethodHandles.constant(rType, true);
} else {
return MethodHandles.constant(rType, kind.getValue(rType));
}
}
},
IDENTITY("identity") {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY);
MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity);
data.put("mtTarget", mtTarget);
return data;
}
@Override
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) {
MethodType mtTarget = (MethodType) data.get("mtTarget");
Class<?> rType = mtTarget.returnType();
if (rType == void.class) {
rType = Object.class;
}
return MethodHandles.identity(rType);
}
};
/**
* Test method's name.
*/
public final String name;
private TestMethods(String name) {
this.name = name;
}
protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException {
throw new UnsupportedOperationException("TESTBUG: getMH method is not implemented for test method " + this);
}
/**
* Creates an adapter method handle depending on a test method from
* MethodHandles class. Adapter is what is returned by the test method. This
* method is able to create two kinds of adapters, their type will be the
* same, but return values are different.
*
* @param data a Map containing data to create a method handle, can be
* obtained by {@link #getTestCaseData} method
* @param kind defines whether adapter ONE or adapter TWO will be
* initialized. Should be equal to TestMethods.Kind.ONE or
* TestMethods.Kind.TWO
* @return Method handle adapter that behaves according to
* TestMethods.Kind.ONE or TestMethods.Kind.TWO
* @throws java.lang.NoSuchMethodException
* @throws java.lang.IllegalAccessException
*/
public MethodHandle getTestCaseMH(Map<String, Object> data, TestMethods.Kind kind)
throws NoSuchMethodException, IllegalAccessException {
if (data == null) {
throw new Error(String.format("TESTBUG: Data for test method %s is not prepared",
this.name));
}
if (!kind.equals(TestMethods.Kind.ONE) && !kind.equals(TestMethods.Kind.TWO)) {
throw new IllegalArgumentException("TESTBUG: Wrong \"kind\" (" + kind
+ ") arg to getTestCaseMH function."
+ " Should be Kind.ONE or Kind.TWO");
}
return getMH(data, kind);
}
/**
* Returns a data Map needed for {@link #getTestCaseMH} method.
*
* @return data Map needed for {@link #getTestCaseMH} method
*/
public Map<String, Object> getTestCaseData() {
throw new UnsupportedOperationException(
"TESTBUG: getTestCaseData method is not implemented for test method " + this);
}
/**
* Enumeration used in methodHandleGenerator to define whether a MH returned
* by this method returns "2" in different type representations, "4", or
* throw an Exception.
*/
public static enum Kind {
ONE(2),
TWO(4),
EXCEPT(0);
private final int value;
private Object getValue(Class<?> cl) {
return Helper.castToWrapper(value, cl);
}
private MethodHandle getBasicMH(Class<?> rType) throws NoSuchMethodException, IllegalAccessException {
MethodHandle result = null;
switch (this) {
case ONE:
case TWO:
if (rType.equals(void.class)) {
result = MethodHandles.lookup().findVirtual(Kind.class, "returnVoid", MethodType.methodType(void.class));
result = MethodHandles.insertArguments(result, 0, this);
} else {
result = MethodHandles.constant(rType, getValue(rType));
}
break;
case EXCEPT:
result = MethodHandles.throwException(rType, Exception.class);
result = MethodHandles.insertArguments(result, 0, new Exception());
break;
}
return result;
}
private void returnVoid() {
}
private Kind(int value) {
this.value = value;
}
}
/**
* Routine used to obtain a randomly generated method type.
*
* @param arity Arity of returned method type.
* @return MethodType generated randomly.
*/
private static MethodType randomMethodTypeGenerator(int arity) {
final Class<?>[] CLASSES = {
Object.class,
int.class,
boolean.class,
byte.class,
short.class,
char.class,
long.class,
float.class,
double.class
};
if (arity > Helper.MAX_ARITY) {
throw new IllegalArgumentException(
String.format("Arity should not exceed %d!", Helper.MAX_ARITY));
}
List<Class<?>> list = Helper.randomClasses(CLASSES, arity);
list = Helper.getParams(list, false, arity);
int i = Helper.RNG.nextInt(CLASSES.length + 1);
Class<?> rtype = i == CLASSES.length ? void.class : CLASSES[i];
return MethodType.methodType(rtype, list);
}
/**
* Routine used to obtain a method handles of a given type an kind (return
* value).
*
* @param returnType Type of MH return value.
* @param argTypes Types of MH args.
* @param kind Defines whether the obtained MH returns "1" or "2".
* @return Method handle of the given type.
* @throws NoSuchMethodException
* @throws IllegalAccessException
*/
private static MethodHandle methodHandleGenerator(Class<?> returnType,
List<Class<?>> argTypes, TestMethods.Kind kind)
throws NoSuchMethodException, IllegalAccessException {
MethodHandle result;
result = kind.getBasicMH(returnType);
return Helper.addTrailingArgs(result, argTypes.size(), argTypes);
}
/**
* Routine that generates filter method handles to test
* MethodHandles.filterArguments method.
*
* @param inputType Filter's argument type.
* @param returnType Filter's return type.
* @param kind Filter's return value definer.
* @return A filter method handle, that takes one argument.
* @throws NoSuchMethodException
* @throws IllegalAccessException
*/
private static MethodHandle filterGenerator(Class<?> inputType, Class<?> returnType,
TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException {
MethodHandle tmpMH = kind.getBasicMH(returnType);
if (inputType.equals(void.class)) {
return tmpMH;
}
ArrayList<Class<?>> inputTypeList = new ArrayList<>(1);
inputTypeList.add(inputType);
return Helper.addTrailingArgs(tmpMH, 1, inputTypeList);
}
private static int argSlotsCount(MethodType mt) {
int result = 0;
for (Class cl : mt.parameterArray()) {
if (cl.equals(long.class) || cl.equals(double.class)) {
result += 2;
} else {
result++;
}
}
return result;
}
private static List<Class<?>> reduceArgListToSlotsCount(List<Class<?>> list,
int desiredSlotCount) {
List<Class<?>> result = new ArrayList<>(desiredSlotCount);
int count = 0;
for (Class<?> cl : list) {
if (count >= desiredSlotCount) {
break;
}
if (cl.equals(long.class) || cl.equals(double.class)) {
count += 2;
} else {
count++;
}
result.add(cl);
}
return result;
}
}

View File

@ -42,6 +42,7 @@ import java.util.function.Supplier;
public class CatchExceptionTest {
private static final List<Class<?>> ARGS_CLASSES;
protected static final int MAX_ARITY = Helper.MAX_ARITY - 1;
static {
Class<?> classes[] = {
Object.class,
@ -52,11 +53,8 @@ public class CatchExceptionTest {
double[].class,
String.class,
};
List<Class<?>> list = new ArrayList<>(MAX_ARITY);
for (int i = 0; i < MAX_ARITY; ++i) {
list.add(classes[Helper.RNG.nextInt(classes.length)]);
}
ARGS_CLASSES = Collections.unmodifiableList(list);
ARGS_CLASSES = Collections.unmodifiableList(
Helper.randomClasses(classes, MAX_ARITY));
}
private final TestCase testCase;
@ -66,7 +64,6 @@ public class CatchExceptionTest {
private int dropped;
private MethodHandle thrower;
public CatchExceptionTest(TestCase testCase, final boolean isVararg, final int argsCount,
final int catchDrops) {
this.testCase = testCase;
@ -107,37 +104,7 @@ public class CatchExceptionTest {
}
private List<Class<?>> getThrowerParams(boolean isVararg, int argsCount) {
boolean unmodifiable = true;
List<Class<?>> classes;
classes = ARGS_CLASSES.subList(0,
Math.min(argsCount, (MAX_ARITY / 2) - 1));
int extra = 0;
if (argsCount >= MAX_ARITY / 2) {
classes = new ArrayList<>(classes);
unmodifiable = false;
extra = (int) classes.stream().filter(Helper::isDoubleCost).count();
int i = classes.size();
while (classes.size() + extra < argsCount) {
Class<?> aClass = ARGS_CLASSES.get(i);
if (Helper.isDoubleCost(aClass)) {
++extra;
if (classes.size() + extra >= argsCount) {
break;
}
}
classes.add(aClass);
}
}
if (isVararg && classes.size() > 0) {
if (unmodifiable) {
classes = new ArrayList<>(classes);
}
int last = classes.size() - 1;
Class<?> aClass = classes.get(classes.size() - 1);
aClass = Array.newInstance(aClass, 2).getClass();
classes.set(last, aClass);
}
return classes;
return Helper.getParams(ARGS_CLASSES, isVararg, argsCount);
}

View File

@ -37,8 +37,6 @@ import java.util.Map;
* support infrastructure to invoke a java class from the command line
*/
class LUtils {
static final sun.tools.jar.Main jarTool =
new sun.tools.jar.Main(System.out, System.err, "jar-tool");
static final com.sun.tools.javac.Main javac =
new com.sun.tools.javac.Main();
static final File cwd = new File(".").getAbsoluteFile();
@ -49,6 +47,10 @@ class LUtils {
static final File JAVA_BIN_FILE = new File(JAVAHOME, "bin");
static final File JAVA_CMD = new File(JAVA_BIN_FILE,
isWindows ? "java.exe" : "java");
static final File JAR_BIN_FILE =
new File(new File(JAVAHOME).getParentFile(), "bin");
static final File JAR_CMD = new File(JAR_BIN_FILE,
isWindows ? "jar.exe" : "jar");
protected LUtils() {
}

View File

@ -67,12 +67,17 @@ public class LambdaAccessControlDoPrivilegedTest extends LUtils {
compile(javacArgs);
File jarFile = new File("foo.jar");
String[] jargs = {"cvf", jarFile.getName(), doprivClass.getName()};
jarTool.run(jargs);
TestResult tr = doExec(JAR_CMD.getAbsolutePath(),
"cvf", jarFile.getName(),
doprivClass.getName());
if (tr.exitValue != 0){
throw new RuntimeException(tr.toString());
}
doprivJava.delete();
doprivClass.delete();
TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
"-Xbootclasspath/p:foo.jar",
"-cp", ".", "Bar");
tr = doExec(JAVA_CMD.getAbsolutePath(),
"-Xbootclasspath/p:foo.jar",
"-cp", ".", "Bar");
tr.assertZero("testDoPrivileged fails");
barJava.delete();
barClass.delete();

View File

@ -23,8 +23,10 @@
/*
* @test
* @bug 4902952 4905407 4916149
* @summary Tests that the scale of zero is propagated properly and has the proper effect.
* @bug 4902952 4905407 4916149 8057793
* @summary Tests that the scale of zero is propagated properly and has the
* proper effect and that setting the scale to zero does not mutate the
* BigDecimal.
* @author Joseph D. Darcy
*/
@ -445,6 +447,16 @@ public class ZeroScalingTests {
return failures;
}
static int setScaleDoesNotMutateTest() {
BigDecimal total = new BigDecimal("258815507198903607775511093103396443816569106750031264155319238473795838680758514810110764742309284477206138527975952150289602995045050194333030191178778772026538699925775139201970526695485362661420908248887297829319881475178467494779683293036572059595504702727301324759997409522995072582369210284334718757260859794972695026582432867589093687280300148141501712013226636373167978223780290547640482160818746599330924736802844173226042389174403401903999447463440670236056324929325189403433689"
+ ".426167432065785331444814035799717606745777287606858873045971898862329763544687891847664736523584843544347118836628373041412918374550458884706686730726101338872517021688769782894793734049819222924171842793485919753186993388451909096042127903835765393729547730953942175461146061715108701615615142134282261293656760570061554783195726716403304101469782303957325142638493327692352838806741611887655695029948975509680496573999174402058593454203190963443179532640446352828089016874853634851387762579319853267317320515941105912189838719919259277721994880193541634872882180184303434360412344059435559680494807415573269199203376126242271766939666939316648575065702750502798973418978204972336924254702551350654650573582614211506856383897692911422458286912085339575875324832979140870119455620532272318122103640233069115700020760625493816902806241630788230268031695140687964931377988962507263990468276009750998066442971308866347136022907166625330623130307555914930120150437900510530537258665172619821272937026713977709974434967165159545592482710663639966781678268622620229577009317698254134914742098420792313931843709810905414336383757407675429663714210967924767434203021205270369316797752411974617662200898086335322218191674846795163102021505555508444216708745911194321674887527227200297039471799580744303346354057273540730643842091810899490590914195225087593013834388801018488174855060306804024894292757613618190472234110859436472645203753139820658279559340251226992556744343475086923568365637919479462424794554522865559888240039662899509652221329892034706445253487898044421278283079233226845124525434586324657471286953226255430662125870993375281512713207125720748163498642795960457639954616530163959004770092547297392499137383176609646505351001304840762905826237024982330597805063521162285806541220110524989649256399233792799406995068469271941269511818994954109392839548141262324660472253632382325038836831429045617036015122388070240133760858500132713255407855625837956886349324981003917084922808187223285051144454915441134217743066575863563572152133978905444998209075763950909784148142018992367290485890072303179512881131769414783097454103103347826517701720263541869335631166977965013552647906729408522950996105479525445916501155305220090853891226367184989434453290788068397817927893708837722255115237672194162924260945492012622891770365546831236789867922136747819364833843397165107825773447549885351449899330007200651144003961228091210630807333236718793283427788965479074476288255387824982443633190938302785760754436525586544523339170400053128503337395428393881357669568532722167493096151221381017320147344991331421789379785964440840684363041795410525097564979585773948558651896834067324427900848255265001498890329859444233861478388742393060996236783742654761350763876989363052609107226398858310051497856931093693697981165801539060516895227818925342535261227134364063673285588256280386915163875872231395348293505967057794409379709079685798908660258077792158532257603211711587587586356431658240229896344639704");
if (total.setScale(0, RoundingMode.DOWN).equals(total.setScale(0, RoundingMode.DOWN))) {
return 0;
} else {
return 1;
}
}
public static void main(String argv[]) {
int failures = 0;
@ -455,6 +467,7 @@ public class ZeroScalingTests {
failures += setScaleTests();
failures += toEngineeringStringTests();
failures += ulpTests();
failures += setScaleDoesNotMutateTest();
if (failures > 0 ) {
throw new RuntimeException("Incurred " + failures + " failures" +

View File

@ -71,6 +71,7 @@ public class BigIntegerTest {
static final int BITS_TOOM_COOK_SQUARE = 6912;
static final int BITS_SCHOENHAGE_BASE = 640;
static final int BITS_BURNIKEL_ZIEGLER = 2560;
static final int BITS_BURNIKEL_ZIEGLER_OFFSET = 1280;
static final int ORDER_SMALL = 60;
static final int ORDER_MEDIUM = 100;
@ -288,19 +289,19 @@ public class BigIntegerTest {
* where {@code abs(u) > abs(v)} and {@code a > b && b > 0}, then if
* {@code w/z = q1*z + r1} and {@code u/v = q2*v + r2}, then
* {@code q1 = q2*pow(2,a-b)} and {@code r1 = r2*pow(2,b)}. The test
* ensures that {@code v} is just under the B-Z threshold and that {@code w}
* and {@code z} are both over the threshold. This implies that {@code u/v}
* uses the standard division algorithm and {@code w/z} uses the B-Z
* algorithm. The results of the two algorithms are then compared using the
* observation described in the foregoing and if they are not equal a
* failure is logged.
* ensures that {@code v} is just under the B-Z threshold, that {@code z} is
* over the threshold and {@code w} is much larger than {@code z}. This
* implies that {@code u/v} uses the standard division algorithm and
* {@code w/z} uses the B-Z algorithm. The results of the two algorithms
* are then compared using the observation described in the foregoing and
* if they are not equal a failure is logged.
*/
public static void divideLarge() {
int failCount = 0;
BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER - 33);
BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 33);
for (int i=0; i<SIZE; i++) {
BigInteger addend = new BigInteger(BITS_BURNIKEL_ZIEGLER - 34, rnd);
BigInteger addend = new BigInteger(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 34, rnd);
BigInteger v = base.add(addend);
BigInteger u = v.multiply(BigInteger.valueOf(2 + rnd.nextInt(Short.MAX_VALUE - 1)));
@ -312,14 +313,14 @@ public class BigIntegerTest {
v = v.negate();
}
int a = 17 + rnd.nextInt(16);
int a = BITS_BURNIKEL_ZIEGLER_OFFSET + rnd.nextInt(16);
int b = 1 + rnd.nextInt(16);
BigInteger w = u.multiply(BigInteger.valueOf(1L << a));
BigInteger z = v.multiply(BigInteger.valueOf(1L << b));
BigInteger w = u.multiply(BigInteger.ONE.shiftLeft(a));
BigInteger z = v.multiply(BigInteger.ONE.shiftLeft(b));
BigInteger[] divideResult = u.divideAndRemainder(v);
divideResult[0] = divideResult[0].multiply(BigInteger.valueOf(1L << (a - b)));
divideResult[1] = divideResult[1].multiply(BigInteger.valueOf(1L << b));
divideResult[0] = divideResult[0].multiply(BigInteger.ONE.shiftLeft(a - b));
divideResult[1] = divideResult[1].multiply(BigInteger.ONE.shiftLeft(b));
BigInteger[] bzResult = w.divideAndRemainder(z);
if (divideResult[0].compareTo(bzResult[0]) != 0 ||

View File

@ -22,7 +22,9 @@
*/
/* @test
* @bug 4405354 6594296
* @bug 4405354 6594296 8058216
* @run main Test
* @run main/othervm -Djava.net.preferIPv4Stack=true Test
* @summary Basic tests for NetworkInterface
*/
import java.net.NetworkInterface;

View File

@ -0,0 +1,62 @@
/*
* 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.
*
* 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.
*/
/* @test
* @bug 8054029
* @summary Block devices should not report size=0 on Linux
*/
import java.io.RandomAccessFile;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.channels.FileChannel;
import java.nio.file.AccessDeniedException;
import java.nio.file.NoSuchFileException;
import static java.nio.file.StandardOpenOption.*;
public class BlockDeviceSize {
private static final String BLK_FNAME = "/dev/sda1";
private static final Path BLK_PATH = Paths.get(BLK_FNAME);
public static void main(String[] args) throws Throwable {
try (FileChannel ch = FileChannel.open(BLK_PATH, READ);
RandomAccessFile file = new RandomAccessFile(BLK_FNAME, "r")) {
long size1 = ch.size();
long size2 = file.length();
if (size1 != size2) {
throw new RuntimeException("size differs when retrieved" +
" in different ways: " + size1 + " != " + size2);
}
System.out.println("OK");
} catch (NoSuchFileException nsfe) {
System.err.println("File " + BLK_FNAME + " not found." +
" Skipping test");
} catch (AccessDeniedException ade) {
System.err.println("Access to " + BLK_FNAME + " is denied." +
" Run test as root.");
}
}
}

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2013,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.
*
* 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.
*/
/*
* @test
* @bug 8050281
* @summary Test that NullPointerException is thrown if any element of perms
* parameter is null
* @run testng LimitedDoPrivilegedWithNullPerms
*/
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.PropertyPermission;
import org.testng.annotations.Test;
public class LimitedDoPrivilegedWithNullPerms {
AccessControlContext acc = AccessController.getContext();
Permission p1 = new PropertyPermission("user.name", "read");
@Test(expectedExceptions = NullPointerException.class)
public void test1() {
AccessController.doPrivileged(
(PrivilegedAction<Void>) () -> null, acc, null);
}
@Test(expectedExceptions = NullPointerException.class)
public void test2() {
AccessController.doPrivileged(
(PrivilegedAction<Void>) () -> null, acc, p1, null);
}
@Test(expectedExceptions = NullPointerException.class)
public void test3() {
AccessController.doPrivilegedWithCombiner(
(PrivilegedAction<Void>) () -> null, acc, null);
}
@Test(expectedExceptions = NullPointerException.class)
public void test4() {
AccessController.doPrivilegedWithCombiner(
(PrivilegedAction<Void>) () -> null, acc, p1, null);
}
@Test(expectedExceptions = NullPointerException.class)
public void test5() throws PrivilegedActionException {
AccessController.doPrivileged(
(PrivilegedExceptionAction<Void>) () -> null,
acc, null);
}
@Test(expectedExceptions = NullPointerException.class)
public void test6() throws PrivilegedActionException {
AccessController.doPrivileged(
(PrivilegedExceptionAction<Void>) () -> null,
acc, p1, null);
}
@Test(expectedExceptions = NullPointerException.class)
public void test7() throws PrivilegedActionException {
AccessController.doPrivilegedWithCombiner(
(PrivilegedExceptionAction<Void>) () -> null,
acc, null);
}
@Test(expectedExceptions = NullPointerException.class)
public void test8() throws PrivilegedActionException {
AccessController.doPrivilegedWithCombiner(
(PrivilegedExceptionAction<Void>) () -> null,
acc, p1, null);
}
}

Some files were not shown because too many files have changed in this diff Show More