Merge
This commit is contained in:
commit
76fe0bf4de
@ -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), \
|
||||
|
@ -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)
|
||||
|
||||
|
38
jdk/make/gensrc/Gensrc-jdk.localedata.gmk
Normal file
38
jdk/make/gensrc/Gensrc-jdk.localedata.gmk
Normal 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
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
################################################################################
|
@ -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++
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
159
jdk/make/src/classes/build/tools/module/GenModulesList.java
Normal file
159
jdk/make/src/classes/build/tools/module/GenModulesList.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
178
jdk/make/src/classes/build/tools/module/Module.java
Normal file
178
jdk/make/src/classes/build/tools/module/Module.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
165
jdk/make/src/classes/build/tools/module/ModulesXmlReader.java
Normal file
165
jdk/make/src/classes/build/tools/module/ModulesXmlReader.java
Normal 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);
|
||||
}
|
||||
}
|
179
jdk/make/src/classes/build/tools/module/ModulesXmlWriter.java
Normal file
179
jdk/make/src/classes/build/tools/module/ModulesXmlWriter.java
Normal 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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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"),
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
package org.ietf.jgss;
|
||||
|
||||
import sun.security.jgss.spi.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.");
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.");
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1 +1 @@
|
||||
sun.util.cldr.CLDRLocaleDataMetaInfo
|
||||
sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo
|
||||
|
@ -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(...)
|
@ -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.
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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]
|
||||
|
76
jdk/test/java/awt/Graphics2D/WhiteTextColorTest.java
Normal file
76
jdk/test/java/awt/Graphics2D/WhiteTextColorTest.java
Normal 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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
91
jdk/test/java/awt/font/GlyphVector/GlyphVectorOutline.java
Normal file
91
jdk/test/java/awt/font/GlyphVector/GlyphVectorOutline.java
Normal 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);
|
||||
}
|
||||
}
|
78
jdk/test/java/lang/invoke/LFCaching/LFCachingTestCase.java
Normal file
78
jdk/test/java/lang/invoke/LFCaching/LFCachingTestCase.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
103
jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java
Normal file
103
jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
117
jdk/test/java/lang/invoke/LFCaching/LambdaFormTestCase.java
Normal file
117
jdk/test/java/lang/invoke/LFCaching/LambdaFormTestCase.java
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
698
jdk/test/java/lang/invoke/LFCaching/TestMethods.java
Normal file
698
jdk/test/java/lang/invoke/LFCaching/TestMethods.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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() {
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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" +
|
||||
|
@ -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 ||
|
||||
|
@ -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;
|
||||
|
62
jdk/test/java/nio/channels/FileChannel/BlockDeviceSize.java
Normal file
62
jdk/test/java/nio/channels/FileChannel/BlockDeviceSize.java
Normal 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.");
|
||||
}
|
||||
}
|
||||
}
|
@ -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
Loading…
Reference in New Issue
Block a user