clean: ; rm -rf build; rm .preprocessor
dist-clean:
- rm -rf .jikes .configure* .install* build .compile .build*
+ rm -rf .configure* .install* build .compile .build*
find upstream -name config.cache -exec rm {} \;
test -e upstream/nestedvm && make -C upstream/nestedvm clean
rm .install_nestedvm
target_bin_extension := $(target_bin_extension_$(platform))
target_bin := ibex.$(target_bin_extension)
-jikes_flags := -nowarn
+javac := javac -classpath upstream/bcel-5.1/src/bcel-5.1.jar:build/class -d build/class/ -sourcepath build/java/:upstream/mips:upstream/mips/build:src
gcc_optimizations := -Os
#gcc_optimizations := -O9 -ffast-math -fomit-frame-pointer -foptimize-sibling-calls
#gcc_optimizations += -finline-functions -funroll-loops -ffunction-sections -fdata-sections
java_classes := $(java_sources:build/java/%.java=build/class/%.class)
java_classes += build/class/gnu/regexp/CharUnit.class build/class/gnu/regexp/IntPair.class
-build/java/org/xwt/mips/%: .install_nestedvm
- mkdir -p build/java/org/xwt/mips
- cd build/java/org/xwt/mips; ln -sf ../../../../../upstream/nestedvm/src/org/xwt/mips/* .
- cd build/java/org/xwt/mips; ln -sf ../../../../../upstream/nestedvm/build/org/xwt/mips/*.java .
-
-
### Java Source Files ##############################################################################
+build/java/gnu/regexp: .download_gnu.regexp-1.1.4
+ mkdir -p $(@D); cd $(@D); ln -sf ../../../upstream/gnu.regexp-1.1.4/src/src/gnu/regexp
+build/java/org/xwt/mips: .download_nestedvm
+ mkdir -p $(@D); cd $(@D); ln -sf ../../../../upstream/nestedvm/src/org/xwt/mips
+build/java/org/ibex/crypto: .download_org.ibex.crypto
+ mkdir -p $(@D); cd $(@D); ln -sf ../../../../upstream/org.ibex.crypto/src/org/ibex/crypto
+ mkdir -p build/java/org/ibex/net;
+ cd build/java/org/ibex/net; ln -sf ../../../../../upstream/org.ibex.crypto/src/org/ibex/net/SSL.java
+ cd build/java/org/ibex/net; ln -sf ../../../../../upstream/org.ibex.crypto/src/org/ibex/net/ssl
+
ifeq ($(platform),Java2)
-.preprocessor: src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java src/gnu/regexp/*.java
- @make .jikes
+.preprocessor: build/java/gnu/regexp src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java build/java/org/xwt/mips build/java/org/ibex/crypto
+
@mkdir -p build/class/org/ibex/util build/class/gnu/regexp
- ./.jikes $^ -d build/class
+ $(javac) src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java build/java/gnu/regexp/*.java -d build/class
@touch $@
else
-.preprocessor: src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java src/gnu/regexp/*.java
+.preprocessor: build/java/gnu/regexp src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java build/java/org/xwt/mips build/java/org/ibex/crypto
@mkdir -p build/class/org/ibex/util build/class/gnu/regexp
- $(gcj) -Isrc -C $^ -d build/class
+ $(gcj) -Isrc -C src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java build/java/gnu/regexp/*.java -d build/class
@touch $@
endif
build/cc/%.cc: src/%.c ; @echo linking $@; mkdir -p $(@D); ln -fs `echo $(@D)/ | sed 's_[^/]*//*_../_g'`/$< $@
build/res/%: src/% ; @echo linking $@; mkdir -p $(@D); ln -fs `echo $(@D)/ | sed 's_[^/]*//*_../_g'`/$< $@
build/java/org/ibex/%.java: src/org/ibex/%.java .preprocessor
@echo -e "\n\033[1mpreprocessing .java -> .java: $<\033[0m"
- mkdir -p `dirname $@`; java -cp build/class org.ibex.util.Preprocessor < $^ > $@
+ mkdir -p `dirname $@`; java -cp build/class:build/java org.ibex.util.Preprocessor < $^ > $@
build/java/%.java: src/%.java ; @echo linking $@; mkdir -p $(@D); ln -fs `echo $(@D)/ | sed 's_[^/]*//*_../_g'`/$< $@
### Java Class Files ##############################################################################
-build/class/org/ibex/translators/MIPSApps.class: build/mips/mipsapps.mips .install_nestedvm .jikes
- mkdir -p build/java/org/ibex/translators
+build/class/org/ibex/util/MIPSApps.class: build/mips/mipsapps.mips .install_nestedvm
+ mkdir -p build/java/org/ibex/util
@echo -e "\n\033[1mtranslating .mips -> .class: $<\033[0m"
java -cp upstream/nestedvm/build:upstream/nestedvm/upstream/build/bcel-5.1/bcel-5.1.jar \
org.xwt.mips.Compiler org.ibex.translators.MIPSApps $< -outfile $@
.compile: .download_nestedvm .download_bcel-5.1 $(java_sources) $(java_classes); touch $@
ifeq ($(platform),Java2)
-build/class/%.class: build/java/%.java .preprocessor .jikes
+build/class/%.class: build/java/%.java .preprocessor
@echo -e "\n\033[1mcompiling .java -> .class: $<\033[0m"
mkdir -p build/class
- @./.jikes $< -d build/class
+ @$(javac) $< -d build/class
else
build/class/%.class: build/java/%.java
@echo -e "\n\033[1mcompiling .java -> .class: $<\033[0m"
$(gcj) -I$(bcel_jar) -C -O0 $< -d build/class
endif
-build/Java2/ibex.jar: .compile build/res/builtin.jar build/class/org/ibex/translators/MIPSApps.class
+build/Java2/ibex.jar: .compile build/res/builtin.jar build/class/org/ibex/util/MIPSApps.class
@echo -e "\n\033[1marchiving .class -> .jar: build/Java2/ibex.jar\033[0m"
mkdir -p build/Java2
echo -e "Manifest-Version: 1.0\nMain-Class: org.ibex.Main\n" > build/Java2/.manifest
### Builtin Resources ##############################################################################
-builtin_src := $(shell find src/org/ibex/builtin -name '*.*' \! -name '*.xcf')
+builtin_src := $(shell find src/org/ibex/core/builtin -name '*.*' \! -name '*.xcf')
build/res/fonts/vera: .download_vera-1.10
mkdir -p build/res/fonts/vera
cd build/res/fonts/vera; ln -fs ../../../../upstream/vera-1.10/ttf-bitstream-vera-1.10/Vera.ttf
cd build/res/fonts/vera; ln -fs ../../../../upstream/vera-1.10/ttf-bitstream-vera-1.10/VeraSe.ttf
build/res/builtin.jar: $(builtin_src:src/%=build/res/%) build/res/fonts/vera
@echo -e "\n\033[1mzipping res/* -> .jar: builtin.jar\033[0m"
- cd build/res; $(jar) cf builtin.jar org/ibex/builtin/scar.png fonts
+ cd build/res; $(jar) cf builtin.jar org/ibex/core/builtin/scar.png fonts
build/$(platform)/builtin.o: build/res/builtin.jar
@echo -e "\n\033[1mwrapping .jar -> .o: resources.o\033[0m"
@mkdir -p $(@D)
-Iupstream/libmspack-20030726/src/mspack \
-c -o $@ $<
-build/mips/mipsapps.mips: build/mips/org/ibex/translators/Freetype.c.o build/mips/org/ibex/translators/MSPack.c.o build/mips/org/ibex/translators/main.c.o
+build/mips/mipsapps.mips: build/mips/org/ibex/graphics/Freetype.c.o build/mips/org/ibex/util/MSPack.c.o
make .install_freetype-2.1.4_mips-unknown-elf target=mips-unknown-elf
make .install_libmspack-20030726_mips-unknown-elf target=mips-unknown-elf
@echo -e "\n\033[1mlinking .o -> .mips: $@\033[0m"
url_freetype-2.1.4 := http://unc.dl.sourceforge.net/sourceforge/freetype/freetype-2.1.4.tar.gz
url_gcc-3.3 := http://mirrors.rcn.net/pub/sourceware/gcc/releases/gcc-3.3/gcc-3.3.tar.gz
url_jpeg-6b := http://www.ijg.org/files/jpegsrc.v6b.tar.gz
-url_jikes-1.18 := http://dist.xwt.org/jikes-1.18.tgz
url_libmspack-20030726 := http://www.kyz.uklinux.net/downloads/libmspack-20030726.tar.gz
url_vera-1.10 := http://fgo-temp.acc.umu.se/pub/GNOME/sources/ttf-bitstream-vera/1.10/ttf-bitstream-vera-1.10.tar.gz
url_WindowMaker-0.80.2 := http://windowmaker.org/pub/source/release/WindowMaker-0.80.2.tar.gz
url_bcel-5.1 := http://www.apache.org/dist/jakarta/bcel/binaries/bcel-5.1.tar.gz
+url_gnu.regexp-1.1.4 := ftp://ftp.tralfamadore.com/pub/java/gnu.regexp-1.1.4.tar.gz
.install_binutils-2.13.2.1_powerpc-apple-darwin: .vendor
rm -rf upstream/darwin-linker/src
touch .install_gcc-3.3_mips-unknown-elf
touch .install_binutils-2.13.2.1_mips-unknown-elf
+.download_org.ibex.crypto:
+ mkdir -p upstream/org.ibex.crypto
+ cd upstream/org.ibex.crypto; wget -l 99 -nH -r http://crypto.ibex.org/
+ touch $@
+
# vendor-supplied binaries and headers; this is stuff that comes with various OSes
vendor: .vendor; @true
.vendor:
make $(make_install_$*_$(target)) install $(setcc) $(environment_$*_$(target))
touch $@
-# jikes has a special target to autodetect a pre-installed jikes, and to autodetect the JVM's $CLASSPATH
-.jikes:
- @echo -e "\n\033[1mdetecting your jikes installation...\033[0m"
- echo "#!/bin/sh" > .jikes
-ifeq ($(shell javac -version 2>&1 | head -n 1),javac 1.5.0-beta)
- echo -n 'PATH=upstream/install/bin:$$PATH javac -classpath upstream/bcel-5.1/src/bcel-5.1.jar:build/class $$@ -d build/class/ -sourcepath build/java/:upstream/mips:upstream/mips/build:src' >> .jikes
-else
- echo -n 'PATH=upstream/install/bin:$$PATH jikes -classpath upstream/bcel-5.1/src/bcel-5.1.jar:build/class $$@ -d build/class/ -sourcepath build/java/:upstream/mips:upstream/mips/build:src ' >> .jikes
- (type jikes && (jikes --version | grep "Version 1.18")) || make .install_jikes-1.18_ target=
- echo -n "$(jikes_flags) -bootclasspath " >> .jikes
- echo "public class GetBootClassPath { public static void main(String[] s) { " > GetBootClassPath.java
- echo "System.out.println(System.getProperty(\"sun.boot.class.path\")); } }" >> GetBootClassPath.java
- javac GetBootClassPath.java
- java -cp . GetBootClassPath >> .jikes
- rm GetBootClassPath.*
-endif
- echo 'EXIT=$$?' >> .jikes
- echo 'exit $$EXIT' >> .jikes
- mv .jikes .jikes+
- cp .jikes+ .jikes
- chmod +x .jikes
+
+
// FIXME
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.core;
// FIXME: are traps on x/y meaningful?
// FIXME: if we trap on cols, then set rows to 0 (forcing cols to 1), does the cols trap get triggered?
import java.util.*;
import org.ibex.js.*;
import org.ibex.util.*;
-import org.ibex.translators.*;
+import org.ibex.graphics.*;
/**
* <p>
* trigger a Surface.abort; if rendering were done in the same pass,
* rendering work done prior to the Surface.abort would be wasted.
*/
-public final class Box extends JSScope implements Scheduler.Task {
+public final class Box extends JSScope implements Task {
// Macros //////////////////////////////////////////////////////////////////////
//#define CHECKSET_BOOLEAN(prop) boolean nu = toBoolean(value); if (nu == prop) break; prop = nu;
//#define CHECKSET_STRING(prop) if ((value==null&&prop==null)||(value!=null&&JS.toString(value).equals(prop))) break; prop=JS.toString(value);
- protected Box() { super(null); }
+ public Box() { super(null); }
// FIXME memory leak
static Hash boxToCursor = new Hash(500, 3);
/*
private VectorGraphics.VectorPath path = null;
- private VectorGraphics.Affine transform = null;
+ private Affine transform = null;
private VectorGraphics.RasterPath rpath = null;
- private VectorGraphics.Affine rtransform = null;
+ private Affine rtransform = null;
*/
//#define DIRTY dirty()
// Reflow ////////////////////////////////////////////////////////////////////////////////////////
/** should only be invoked on the root box */
- void reflow() { pack(); resize(x, y, maxwidth, maxheight); place(); }
+ public void reflow() { pack(); resize(x, y, maxwidth, maxheight); place(); }
private static Box[] frontier = new Box[65535];
/** pack the boxes into rows and columns, compute contentwidth */
- void pack() {
+ public void pack() {
if (!test(REPACK)) { constrain(); return; }
boolean haskid = false;
for(Box child = getChild(0); child != null; child = child.nextSibling()) { haskid = true; child.pack(); }
// Rendering Pipeline /////////////////////////////////////////////////////////////////////
/** Renders self and children within the specified region. All rendering operations are clipped to xIn,yIn,wIn,hIn */
- void render(int parentx, int parenty, int cx1, int cy1, int cx2, int cy2, PixelBuffer buf, VectorGraphics.Affine a) {
+ public void render(int parentx, int parenty, int cx1, int cy1, int cx2, int cy2, PixelBuffer buf, Affine a) {
if (!test(VISIBLE)) return;
int globalx = parentx + (parent == null ? 0 : x);
int globaly = parenty + (parent == null ? 0 : y);
case "distanceto": return METHOD;
case "text": return text;
case "path": throw new JSExn("cannot read from the path property");
- case "fill": return colorToString(fillcolor);
- case "strokecolor": return colorToString(strokecolor);
- case "textcolor": return colorToString(strokecolor);
+ case "fill": return Color.colorToString(fillcolor);
+ case "strokecolor": return Color.colorToString(strokecolor);
+ case "textcolor": return Color.colorToString(strokecolor);
case "font": return font == null ? null : font.stream;
case "fontsize": return font == null ? N(10) : N(font.pointsize);
case "strokewidth": return N(strokewidth);
//#switch(name)
case "thisbox": if (value == null) removeSelf();
case "text": if (value == null) value = ""; CHECKSET_STRING(text); RECONSTRAIN(); DIRTY;
- case "strokecolor": value = N(stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY;
- case "textcolor": value = N(stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY;
+ case "strokecolor": value = N(Color.stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY;
+ case "textcolor": value = N(Color.stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY;
case "strokewidth": CHECKSET_SHORT(strokewidth); DIRTY;
case "shrink": CHECKSET_FLAG(HSHRINK | VSHRINK); RECONSTRAIN();
case "hshrink": CHECKSET_FLAG(HSHRINK); RECONSTRAIN();
texture = null;
fillcolor = 0;
} else if (value instanceof String) {
- int newfillcolor = stringToColor((String)value);
+ int newfillcolor = Color.stringToColor((String)value);
if (newfillcolor == fillcolor) return;
fillcolor = newfillcolor;
texture = null;
putAndTriggerTrapsAndCatchExceptions(name.substring(1), value);
}
- private static int stringToColor(String s) {
- // FIXME support three-char strings by doubling digits
- if (s == null) return 0x00000000;
- else if (SVG.colors.get(s) != null) return 0xFF000000 | toInt(SVG.colors.get(s));
- else if (s.length() == 7 && s.charAt(0) == '#') try {
- // FEATURE alpha
- return 0xFF000000 |
- (Integer.parseInt(s.substring(1, 3), 16) << 16) |
- (Integer.parseInt(s.substring(3, 5), 16) << 8) |
- Integer.parseInt(s.substring(5, 7), 16);
- } catch (NumberFormatException e) {
- Log.info(Box.class, "invalid color " + s);
- return 0;
- }
- else return 0; // FEATURE: error?
- }
-
- private static String colorToString(int argb) {
- if ((argb & 0xFF000000) == 0) return null;
- String red = Integer.toHexString((argb & 0x00FF0000) >> 16);
- String green = Integer.toHexString((argb & 0x0000FF00) >> 8);
- String blue = Integer.toHexString(argb & 0x000000FF);
- if (red.length() < 2) red = "0" + red;
- if (blue.length() < 2) blue = "0" + blue;
- if (green.length() < 2) green = "0" + green;
- return "#" + red + green + blue;
- }
-
/** figures out what box in this subtree of the Box owns the pixel at x,y relitave to the Surface */
public static Box whoIs(Box cur, int x, int y) {
// Tree Manipulation /////////////////////////////////////////////////////////////////////
- void removeSelf() {
+ public void removeSelf() {
if (parent != null) { parent.removeChild(parent.indexNode(this)); return; }
Surface surface = Surface.fromBox(this);
if (surface != null) surface.dispose(true);
putAndTriggerTrapsAndCatchExceptions("ChildChange", b);
}
}
-
- void putAndTriggerTrapsAndCatchExceptions(Object name, Object val) {
+
+ public void putAndTriggerTrapsAndCatchExceptions(Object name, Object val) {
try {
putAndTriggerTraps(name, val);
} catch (JSExn e) {
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.core;
import java.io.*;
import org.ibex.js.*;
import org.ibex.util.*;
-import org.bouncycastle.util.encoders.Base64;
+import org.ibex.graphics.*;
+import org.ibex.plat.*;
+import org.ibex.net.*;
+import org.ibex.crypto.*;
/** Singleton class that provides all functionality in the ibex.* namespace */
public final class Ibex extends JS.Cloneable {
public void put(Object name, final Object value) throws JSExn {
//#switch(name)
- case "thread": Scheduler.add((Scheduler.Task)value); return;
+ case "thread": Scheduler.add((Task)value); return;
case "ui.clipboard": Platform.setClipBoard((String)value); return;
case "ui.frame": Platform.createSurface((Box)value, true, true); return;
case "ui.window": Platform.createSurface((Box)value, false, true); return;
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.core;
import java.io.*;
import org.ibex.util.*;
-import org.bouncycastle.util.encoders.Base64;
+import org.ibex.crypto.*;
/** Manages access to ~/.ibex */
public class LocalStorage {
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.core;
import java.net.*;
import java.io.*;
import java.util.*;
import org.ibex.js.*;
import org.ibex.util.*;
+import org.ibex.plat.*;
+import org.ibex.graphics.*;
/** Entry point for the Ibex Engine; handles splash screen, initial xwar loading, and argument processing */
public class Main {
public static String initialTemplate = null;
public static final Stream builtin = new Stream.Zip(new Stream.Builtin());
- public static Picture scarImage = null;
public static void printUsage() {
System.err.println("Usage: ibex [-lawp] [ url | file | directory ]");
if (Log.on) Log.info(Main.class, "loading xwar");
final Ibex ibex = new Ibex(rr);
- scarImage =
+ org.ibex.graphics.Surface.scarImage =
Picture.load((Stream)Main.builtin.get("org/ibex/builtin/scar.png"),
- new Scheduler.Task() { public void perform() throws JSExn, UnknownHostException {
+ new Task() { public void perform() throws JSExn, UnknownHostException {
if (Log.on) Log.info(Main.class, "invoking initial template");
ibex.resolveString(startupTemplate, false).call(new Box(), null, null, null, 1);
} });
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.core;
import java.io.*;
import java.util.*;
* @param pboxes a vector of all box parents on which to put $-references
* @param ptemplates a vector of the fileNames to recieve private references on the pboxes
*/
- void apply(Box b) throws JSExn {
+ public void apply(Box b) throws JSExn {
try {
apply(b, null);
} catch (IOException e) {
--- /dev/null
+// FIXME
+// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
+package org.ibex.graphics;
+import java.util.*;
+
+/** an affine transform; all operations are destructive */
+public final class Affine {
+
+ // [ a b e ]
+ // [ c d f ]
+ // [ 0 0 1 ]
+ public float a, b, c, d, e, f;
+
+ Affine(float _a, float _b, float _c, float _d, float _e, float _f) { a = _a; b = _b; c = _c; d = _d; e = _e; f = _f; }
+ public String toString() { return "[ " + a + ", " + b + ", " + c + ", " + d + ", " + e + ", " + f + " ]"; }
+ public Affine copy() { return new Affine(a, b, c, d, e, f); }
+ public static Affine identity() { return new Affine(1, 0, 0, 1, 0, 0); }
+ public static Affine scale(float sx, float sy) { return new Affine(sx, 0, 0, sy, 0, 0); }
+ public static Affine shear(float degrees) {
+ return new Affine(1, 0, (float)Math.tan(degrees * (float)(Math.PI / 180.0)), 1, 0, 0); }
+ public static Affine translate(float tx, float ty) { return new Affine(1, 0, 0, 1, tx, ty); }
+ public static Affine flip(boolean horiz, boolean vert) { return new Affine(horiz ? -1 : 1, 0, 0, vert ? -1 : 1, 0, 0); }
+ public float multiply_px(float x, float y) { return x * a + y * c + e; }
+ public float multiply_py(float x, float y) { return x * b + y * d + f; }
+ public boolean equalsIgnoringTranslation(Affine x) { return a == x.a && b == x.b && c == x.c && d == x.d; }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof Affine)) return false;
+ Affine x = (Affine)o;
+ return a == x.a && b == x.b && c == x.c && d == x.d && e == x.e && f == x.f;
+ }
+
+ public static Affine rotate(float degrees) {
+ float s = (float)Math.sin(degrees * (float)(Math.PI / 180.0));
+ float c = (float)Math.cos(degrees * (float)(Math.PI / 180.0));
+ return new Affine(c, s, -s, c, 0, 0);
+ }
+
+ /** this = this * a */
+ public Affine multiply(Affine A) {
+ float _a = this.a * A.a + this.b * A.c;
+ float _b = this.a * A.b + this.b * A.d;
+ float _c = this.c * A.a + this.d * A.c;
+ float _d = this.c * A.b + this.d * A.d;
+ float _e = this.e * A.a + this.f * A.c + A.e;
+ float _f = this.e * A.b + this.f * A.d + A.f;
+ a = _a; b = _b; c = _c; d = _d; e = _e; f = _f;
+ return this;
+ }
+
+ public void invert() {
+ float det = 1 / (a * d - b * c);
+ float _a = d * det;
+ float _b = -1 * b * det;
+ float _c = -1 * c * det;
+ float _d = a * det;
+ float _e = -1 * e * a - f * c;
+ float _f = -1 * e * b - f * d;
+ a = _a; b = _b; c = _c; d = _d; e = _e; f = _f;
+ }
+
+ public static Affine parse(String t) {
+ if (t == null) return null;
+ t = t.trim();
+ Affine ret = Affine.identity();
+ while (t.length() > 0) {
+ if (t.startsWith("skewX(")) {
+ // FIXME
+
+ } else if (t.startsWith("shear(")) {
+ // FIXME: nonstandard; remove this
+ ret.multiply(Affine.shear(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(')')))));
+
+ } else if (t.startsWith("skewY(")) {
+ // FIXME
+
+ } else if (t.startsWith("rotate(")) {
+ String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
+ if (sub.indexOf(',') != -1) {
+ float angle = Float.parseFloat(sub.substring(0, sub.indexOf(',')));
+ sub = sub.substring(sub.indexOf(',') + 1);
+ float cx = Float.parseFloat(sub.substring(0, sub.indexOf(',')));
+ sub = sub.substring(sub.indexOf(',') + 1);
+ float cy = Float.parseFloat(sub);
+ ret.multiply(Affine.translate(cx, cy));
+ ret.multiply(Affine.rotate(angle));
+ ret.multiply(Affine.translate(-1 * cx, -1 * cy));
+ } else {
+ ret.multiply(Affine.rotate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(')')))));
+ }
+
+ } else if (t.startsWith("translate(")) {
+ String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
+ if (sub.indexOf(',') > -1) {
+ ret.multiply(Affine.translate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))),
+ Float.parseFloat(t.substring(t.indexOf(',') + 1, t.indexOf(')')))));
+ } else {
+ ret.multiply(Affine.translate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))), 0));
+ }
+
+ } else if (t.startsWith("flip(")) {
+ String which = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
+ ret.multiply(Affine.flip(which.equals("horizontal"), which.equals("vertical")));
+
+ } else if (t.startsWith("scale(")) {
+ String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
+ if (sub.indexOf(',') > -1) {
+ ret.multiply(Affine.scale(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))),
+ Float.parseFloat(t.substring(t.indexOf(',') + 1, t.indexOf(')')))));
+ } else {
+ ret.multiply(Affine.scale(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))),
+ Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(',')))));
+ }
+
+ } else if (t.startsWith("matrix(")) {
+ // FIXME: is this mapped right?
+ float d[] = new float[6];
+ StringTokenizer st = new StringTokenizer(t, ",", false);
+ for(int i=0; i<6; i++)
+ d[i] = Float.parseFloat(st.nextToken());
+ ret.multiply(new Affine(d[0], d[1], d[2], d[3], d[4], d[5]));
+ }
+ t = t.substring(t.indexOf(')') + 1).trim();
+ }
+ return ret;
+ }
+
+}
--- /dev/null
+// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+package org.ibex.graphics;
+import java.util.*;
+import org.ibex.util.*;
+
+public class Color {
+
+ public static int stringToColor(String s) {
+ // FIXME support three-char strings by doubling digits
+ if (s == null) return 0x00000000;
+ else if (standard.get(s) != null) return 0xFF000000 | org.ibex.js.JS.toInt(standard.get(s));
+ else if (s.length() == 7 && s.charAt(0) == '#') try {
+ // FEATURE alpha
+ return 0xFF000000 |
+ (Integer.parseInt(s.substring(1, 3), 16) << 16) |
+ (Integer.parseInt(s.substring(3, 5), 16) << 8) |
+ Integer.parseInt(s.substring(5, 7), 16);
+ } catch (NumberFormatException e) {
+ Log.info(Color.class, "invalid color " + s);
+ return 0;
+ }
+ else return 0; // FEATURE: error?
+ }
+
+ public static String colorToString(int argb) {
+ if ((argb & 0xFF000000) == 0) return null;
+ String red = Integer.toHexString((argb & 0x00FF0000) >> 16);
+ String green = Integer.toHexString((argb & 0x0000FF00) >> 8);
+ String blue = Integer.toHexString(argb & 0x000000FF);
+ if (red.length() < 2) red = "0" + red;
+ if (blue.length() < 2) blue = "0" + blue;
+ if (green.length() < 2) green = "0" + green;
+ return "#" + red + green + blue;
+ }
+
+ /** Copied verbatim from the SVG specification */
+ private static Hashtable standard = new Hashtable(400);
+ static {
+ standard.put("aliceblue", new Integer((240 << 16) | (248 << 8) | 255));
+ standard.put("antiquewhite", new Integer((250 << 16) | (235 << 8) | 215));
+ standard.put("aqua", new Integer((0 << 16) | (255 << 8) | 255));
+ standard.put("aquamarine", new Integer((127 << 16) | (255 << 8) | 212));
+ standard.put("azure", new Integer((240 << 16) | (255 << 8) | 255));
+ standard.put("beige", new Integer((245 << 16) | (245 << 8) | 220));
+ standard.put("bisque", new Integer((255 << 16) | (228 << 8) | 196));
+ standard.put("black", new Integer((0 << 16) | (0 << 8) | 0));
+ standard.put("blanchedalmond", new Integer((255 << 16) | (235 << 8) | 205));
+ standard.put("blue", new Integer((0 << 16) | (0 << 8) | 255));
+ standard.put("blueviolet", new Integer((138 << 16) | (43 << 8) | 226));
+ standard.put("brown", new Integer((165 << 16) | (42 << 8) | 42));
+ standard.put("burlywood", new Integer((222 << 16) | (184 << 8) | 135));
+ standard.put("cadetblue", new Integer((95 << 16) | (158 << 8) | 160));
+ standard.put("chartreuse", new Integer((127 << 16) | (255 << 8) | 0));
+ standard.put("chocolate", new Integer((210 << 16) | (105 << 8) | 30));
+ standard.put("coral", new Integer((255 << 16) | (127 << 8) | 80));
+ standard.put("cornflowerblue", new Integer((100 << 16) | (149 << 8) | 237));
+ standard.put("cornsilk", new Integer((255 << 16) | (248 << 8) | 220));
+ standard.put("crimson", new Integer((220 << 16) | (20 << 8) | 60));
+ standard.put("cyan", new Integer((0 << 16) | (255 << 8) | 255));
+ standard.put("darkblue", new Integer((0 << 16) | (0 << 8) | 139));
+ standard.put("darkcyan", new Integer((0 << 16) | (139 << 8) | 139));
+ standard.put("darkgoldenrod", new Integer((184 << 16) | (134 << 8) | 11));
+ standard.put("darkgray", new Integer((169 << 16) | (169 << 8) | 169));
+ standard.put("darkgreen", new Integer((0 << 16) | (100 << 8) | 0));
+ standard.put("darkgrey", new Integer((169 << 16) | (169 << 8) | 169));
+ standard.put("darkkhaki", new Integer((189 << 16) | (183 << 8) | 107));
+ standard.put("darkmagenta", new Integer((139 << 16) | (0 << 8) | 139));
+ standard.put("darkolivegreen", new Integer((85 << 16) | (107 << 8) | 47));
+ standard.put("darkorange", new Integer((255 << 16) | (140 << 8) | 0));
+ standard.put("darkorchid", new Integer((153 << 16) | (50 << 8) | 204));
+ standard.put("darkred", new Integer((139 << 16) | (0 << 8) | 0));
+ standard.put("darksalmon", new Integer((233 << 16) | (150 << 8) | 122));
+ standard.put("darkseagreen", new Integer((143 << 16) | (188 << 8) | 143));
+ standard.put("darkslateblue", new Integer((72 << 16) | (61 << 8) | 139));
+ standard.put("darkslategray", new Integer((47 << 16) | (79 << 8) | 79));
+ standard.put("darkslategrey", new Integer((47 << 16) | (79 << 8) | 79));
+ standard.put("darkturquoise", new Integer((0 << 16) | (206 << 8) | 209));
+ standard.put("darkviolet", new Integer((148 << 16) | (0 << 8) | 211));
+ standard.put("deeppink", new Integer((255 << 16) | (20 << 8) | 147));
+ standard.put("deepskyblue", new Integer((0 << 16) | (191 << 8) | 255));
+ standard.put("dimgray", new Integer((105 << 16) | (105 << 8) | 105));
+ standard.put("dimgrey", new Integer((105 << 16) | (105 << 8) | 105));
+ standard.put("dodgerblue", new Integer((30 << 16) | (144 << 8) | 255));
+ standard.put("firebrick", new Integer((178 << 16) | (34 << 8) | 34));
+ standard.put("floralwhite", new Integer((255 << 16) | (250 << 8) | 240));
+ standard.put("forestgreen", new Integer((34 << 16) | (139 << 8) | 34));
+ standard.put("fuchsia", new Integer((255 << 16) | (0 << 8) | 255));
+ standard.put("gainsboro", new Integer((220 << 16) | (220 << 8) | 220));
+ standard.put("ghostwhite", new Integer((248 << 16) | (248 << 8) | 255));
+ standard.put("gold", new Integer((255 << 16) | (215 << 8) | 0));
+ standard.put("goldenrod", new Integer((218 << 16) | (165 << 8) | 32));
+ standard.put("gray", new Integer((128 << 16) | (128 << 8) | 128));
+ standard.put("grey", new Integer((128 << 16) | (128 << 8) | 128));
+ standard.put("green", new Integer((0 << 16) | (128 << 8) | 0));
+ standard.put("greenyellow", new Integer((173 << 16) | (255 << 8) | 47));
+ standard.put("honeydew", new Integer((240 << 16) | (255 << 8) | 240));
+ standard.put("hotpink", new Integer((255 << 16) | (105 << 8) | 180));
+ standard.put("indianred", new Integer((205 << 16) | (92 << 8) | 92));
+ standard.put("indigo", new Integer((75 << 16) | (0 << 8) | 130));
+ standard.put("ivory", new Integer((255 << 16) | (255 << 8) | 240));
+ standard.put("khaki", new Integer((240 << 16) | (230 << 8) | 140));
+ standard.put("lavender", new Integer((230 << 16) | (230 << 8) | 250));
+ standard.put("lavenderblush", new Integer((255 << 16) | (240 << 8) | 245));
+ standard.put("lawngreen", new Integer((124 << 16) | (252 << 8) | 0));
+ standard.put("lemonchiffon", new Integer((255 << 16) | (250 << 8) | 205));
+ standard.put("lightblue", new Integer((173 << 16) | (216 << 8) | 230));
+ standard.put("lightcoral", new Integer((240 << 16) | (128 << 8) | 128));
+ standard.put("lightcyan", new Integer((224 << 16) | (255 << 8) | 255));
+ standard.put("lightgoldenrodyellow", new Integer((250 << 16) | (250 << 8) | 210));
+ standard.put("lightgray", new Integer((211 << 16) | (211 << 8) | 211));
+ standard.put("lightgreen", new Integer((144 << 16) | (238 << 8) | 144));
+ standard.put("lightgrey", new Integer((211 << 16) | (211 << 8) | 211));
+ standard.put("lightpink", new Integer((255 << 16) | (182 << 8) | 193));
+ standard.put("lightsalmon", new Integer((255 << 16) | (160 << 8) | 122));
+ standard.put("lightseagreen", new Integer((32 << 16) | (178 << 8) | 170));
+ standard.put("lightskyblue", new Integer((135 << 16) | (206 << 8) | 250));
+ standard.put("lightslategray", new Integer((119 << 16) | (136 << 8) | 153));
+ standard.put("lightslategrey", new Integer((119 << 16) | (136 << 8) | 153));
+ standard.put("lightsteelblue", new Integer((176 << 16) | (196 << 8) | 222));
+ standard.put("lightyellow", new Integer((255 << 16) | (255 << 8) | 224));
+ standard.put("lime", new Integer((0 << 16) | (255 << 8) | 0));
+ standard.put("limegreen", new Integer((50 << 16) | (205 << 8) | 50));
+ standard.put("linen", new Integer((250 << 16) | (240 << 8) | 230));
+ standard.put("magenta", new Integer((255 << 16) | (0 << 8) | 255));
+ standard.put("maroon", new Integer((128 << 16) | (0 << 8) | 0));
+ standard.put("mediumaquamarine", new Integer((102 << 16) | (205 << 8) | 170));
+ standard.put("mediumblue", new Integer((0 << 16) | (0 << 8) | 205));
+ standard.put("mediumorchid", new Integer((186 << 16) | (85 << 8) | 211));
+ standard.put("mediumpurple", new Integer((147 << 16) | (112 << 8) | 219));
+ standard.put("mediumseagreen", new Integer((60 << 16) | (179 << 8) | 113));
+ standard.put("mediumslateblue", new Integer((123 << 16) | (104 << 8) | 238));
+ standard.put("mediumspringgreen", new Integer((0 << 16) | (250 << 8) | 154));
+ standard.put("mediumturquoise", new Integer((72 << 16) | (209 << 8) | 204));
+ standard.put("mediumvioletred", new Integer((199 << 16) | (21 << 8) | 133));
+ standard.put("midnightblue", new Integer((25 << 16) | (25 << 8) | 112));
+ standard.put("mintcream", new Integer((245 << 16) | (255 << 8) | 250));
+ standard.put("mistyrose", new Integer((255 << 16) | (228 << 8) | 225));
+ standard.put("moccasin", new Integer((255 << 16) | (228 << 8) | 181));
+ standard.put("navajowhite", new Integer((255 << 16) | (222 << 8) | 173));
+ standard.put("navy", new Integer((0 << 16) | (0 << 8) | 128));
+ standard.put("oldlace", new Integer((253 << 16) | (245 << 8) | 230));
+ standard.put("olive", new Integer((128 << 16) | (128 << 8) | 0));
+ standard.put("olivedrab", new Integer((107 << 16) | (142 << 8) | 35));
+ standard.put("orange", new Integer((255 << 16) | (165 << 8) | 0));
+ standard.put("orangered", new Integer((255 << 16) | (69 << 8) | 0));
+ standard.put("orchid", new Integer((218 << 16) | (112 << 8) | 214));
+ standard.put("palegoldenrod", new Integer((238 << 16) | (232 << 8) | 170));
+ standard.put("palegreen", new Integer((152 << 16) | (251 << 8) | 152));
+ standard.put("paleturquoise", new Integer((175 << 16) | (238 << 8) | 238));
+ standard.put("palevioletred", new Integer((219 << 16) | (112 << 8) | 147));
+ standard.put("papayawhip", new Integer((255 << 16) | (239 << 8) | 213));
+ standard.put("peachpuff", new Integer((255 << 16) | (218 << 8) | 185));
+ standard.put("peru", new Integer((205 << 16) | (133 << 8) | 63));
+ standard.put("pink", new Integer((255 << 16) | (192 << 8) | 203));
+ standard.put("plum", new Integer((221 << 16) | (160 << 8) | 221));
+ standard.put("powderblue", new Integer((176 << 16) | (224 << 8) | 230));
+ standard.put("purple", new Integer((128 << 16) | (0 << 8) | 128));
+ standard.put("red", new Integer((255 << 16) | (0 << 8) | 0));
+ standard.put("rosybrown", new Integer((188 << 16) | (143 << 8) | 143));
+ standard.put("royalblue", new Integer((65 << 16) | (105 << 8) | 225));
+ standard.put("saddlebrown", new Integer((139 << 16) | (69 << 8) | 19));
+ standard.put("salmon", new Integer((250 << 16) | (128 << 8) | 114));
+ standard.put("sandybrown", new Integer((244 << 16) | (164 << 8) | 96));
+ standard.put("seagreen", new Integer((46 << 16) | (139 << 8) | 87));
+ standard.put("seashell", new Integer((255 << 16) | (245 << 8) | 238));
+ standard.put("sienna", new Integer((160 << 16) | (82 << 8) | 45));
+ standard.put("silver", new Integer((192 << 16) | (192 << 8) | 192));
+ standard.put("skyblue", new Integer((135 << 16) | (206 << 8) | 235));
+ standard.put("slateblue", new Integer((106 << 16) | (90 << 8) | 205));
+ standard.put("slategray", new Integer((112 << 16) | (128 << 8) | 144));
+ standard.put("slategrey", new Integer((112 << 16) | (128 << 8) | 144));
+ standard.put("snow", new Integer((255 << 16) | (250 << 8) | 250));
+ standard.put("springgreen", new Integer((0 << 16) | (255 << 8) | 127));
+ standard.put("steelblue", new Integer((70 << 16) | (130 << 8) | 180));
+ standard.put("tan", new Integer((210 << 16) | (180 << 8) | 140));
+ standard.put("teal", new Integer((0 << 16) | (128 << 8) | 128));
+ standard.put("thistle", new Integer((216 << 16) | (191 << 8) | 216));
+ standard.put("tomato", new Integer((255 << 16) | (99 << 8) | 71));
+ standard.put("turquoise", new Integer((64 << 16) | (224 << 8) | 208));
+ standard.put("violet", new Integer((238 << 16) | (130 << 8) | 238));
+ standard.put("wheat", new Integer((245 << 16) | (222 << 8) | 179));
+ standard.put("white", new Integer((255 << 16) | (255 << 8) | 255));
+ standard.put("whitesmoke", new Integer((245 << 16) | (245 << 8) | 245));
+ standard.put("yellow", new Integer((255 << 16) | (255 << 8) | 0));
+ standard.put("yellowgreen", new Integer((154 << 16) | (205 << 8) | 50));
+ }
+}
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
-import org.ibex.translators.*;
+package org.ibex.graphics;
import org.ibex.util.*;
import java.io.*;
import java.util.Hashtable;
-
-import org.ibex.js.JSExn;
+import org.ibex.js.*;
+import org.xwt.mips.*;
+import org.ibex.plat.*;
// FEATURE: this could be cleaner
/** encapsulates a single font (a set of Glyphs) */
public int height = -1; ///< the height of the glyph
public byte[] data = null; ///< the alpha channel samples for this font
void render() {
- if (!isLoaded) try { freetype.renderGlyph(this); } catch (IOException e) { Log.info(Freetype.class, e); }
+ if (!isLoaded) try { renderGlyph(this); } catch (IOException e) { Log.info(Font.class, e); }
isLoaded = true;
}
}
// Statics //////////////////////////////////////////////////////////////////////
- static final Freetype freetype = new Freetype();
static final Hashtable glyphsToBeCached = new Hashtable();
static final Hashtable glyphsToBeDisplayed = new Hashtable();
private static Cache fontCache = new Cache(100);
return ret;
}
- static final Scheduler.Task glyphRenderingTask = new Scheduler.Task() { public void perform() {
+ static final Task glyphRenderingTask = new Task() { public void perform() {
// FIXME: this should be a low-priority task
glyphRenderingTaskIsScheduled = false;
if (glyphsToBeCached.isEmpty()) return;
glyphRenderingTaskIsScheduled = true;
Scheduler.add(this);
} };
+
+
+ // FreeType Interface //////////////////////////////////////////////////////////////////////////////
+
+ // FEATURE: use streams, not memoryfont's
+ // FEATURE: kerning pairs
+ private static int mem_allocated = 0;
+ private static org.xwt.mips.Runtime vm = null;
+ private static Stream loadedStream = null;
+
+ public static void loadFontByteStream(Stream res) {
+ try {
+ Log.info(Font.class, "loading font " + res);
+ loadedStream = res;
+ InputStream is = Stream.getInputStream(res);
+ byte[] fontstream = InputStreamToByteArray.convert(is);
+ vm = (org.xwt.mips.Runtime)Class.forName("org.ibex.util.MIPSApps").newInstance();
+ int baseAddr = vm.sbrk(fontstream.length);
+ vm.copyout(fontstream, baseAddr, fontstream.length);
+ vm.setUserInfo(0, baseAddr);
+ vm.setUserInfo(1, fontstream.length);
+ vm.start(new String[]{ "freetype" });
+ vm.execute();
+ if(vm.getState() == org.xwt.mips.Runtime.DONE) throw new Error("Freetype VM exited: " + vm.exitStatus());
+ } catch (Exception e) {
+ Log.info(Font.class, e);
+ }
+ }
+
+ public static synchronized void renderGlyph(Font.Glyph glyph) throws IOException {
+ try {
+ Log.debug(Font.class, "rasterizing glyph " + glyph.c + " of font " + glyph.font);
+ if (loadedStream != glyph.font.stream) loadFontByteStream(glyph.font.stream);
+ vm.setUserInfo(2, (int)glyph.c);
+ vm.setUserInfo(3, (int)glyph.c);
+ vm.setUserInfo(4, glyph.font.pointsize);
+ long start = System.currentTimeMillis();
+ vm.execute();
+ glyph.font.max_ascent = vm.getUserInfo(8);
+ glyph.font.max_descent = vm.getUserInfo(9);
+ glyph.baseline = vm.getUserInfo(10);
+ glyph.advance = vm.getUserInfo(11);
+
+ glyph.width = vm.getUserInfo(6);
+ glyph.height = vm.getUserInfo(7);
+
+ glyph.data = new byte[glyph.width * glyph.height];
+ int addr = vm.getUserInfo(5);
+ vm.copyin(addr, glyph.data, glyph.width * glyph.height);
+ glyph.isLoaded = true;
+
+ } catch (Exception e) {
+ Log.info(Font.class, e);
+ }
+ }
}
#include <unistd.h>
#include <freetype/freetype.h>
+char *user_info[1024];
+
/* NOTE: _user_info is defined in crt0.c. It points to a 4096 byte
block of memory that contains 1024 32-bit values that can be set
with the setUserInfo() method of MIPSEmu.
*/
-extern char *user_info[1024];
-
#define FT_Check(expr) do { \
if((expr) != 0) { \
errprint(#expr " failed\n"); \
}
old_glyph_index = glyph_index;
*/
+
+
+extern int mspack_main();
+int main(int argc, char **argv) {
+ if(argc < 1) return 1;
+ if(strcmp(argv[0],"mspack")==0) return mspack_main();
+ if(strcmp(argv[0],"freetype")==0) return freetype_main();
+ return 1;
+}
* terms specified in this license.
*
*/
-package org.ibex.translators;
+package org.ibex.graphics;
import org.ibex.*;
import org.ibex.util.*;
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.translators;
+package org.ibex.graphics;
import java.util.*;
import java.net.*;
* hereby granted.
*/
-package org.ibex.translators;
+package org.ibex.graphics;
import org.ibex.*;
import org.ibex.util.*;
--- /dev/null
+// FIXME
+// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
+package org.ibex.graphics;
+import java.util.*;
+
+public abstract class Paint {
+ public abstract void fillTrapezoid(int tx1, int tx2, int ty1, int tx3, int tx4, int ty2, PixelBuffer buf);
+
+ public static class SingleColorPaint extends Paint {
+ int color;
+ public SingleColorPaint(int color) { this.color = color; }
+ public void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, PixelBuffer buf) {
+ buf.fillTrapezoid(x1, x2, y1, x3, x4, y2, color);
+ }
+ }
+
+
+ /*
+ public static abstract class GradientPaint extends Paint {
+ public GradientPaint(boolean reflect, boolean repeat, Affine gradientTransform,
+ int[] stop_colors, float[] stop_offsets) {
+ this.reflect = reflect; this.repeat = repeat;
+ this.gradientTransform = gradientTransform;
+ this.stop_colors = stop_colors;
+ this.stop_offsets = stop_offsets;
+ }
+ Affine gradientTransform = Affine.identity();
+ boolean useBoundingBox = false; // FIXME not supported
+ boolean patternUseBoundingBox = false; // FIXME not supported
+
+ // it's invalid for both of these to be true
+ boolean reflect = false; // FIXME not supported
+ boolean repeat = false; // FIXME not supported
+ int[] stop_colors;
+ float[] stop_offsets;
+
+ public void fillTrapezoid(float tx1, float tx2, float ty1, float tx3, float tx4, float ty2, PixelBuffer buf) {
+ Affine a = buf.a;
+ Affine inverse = a.copy().invert();
+ float slope1 = (tx3 - tx1) / (ty2 - ty1);
+ float slope2 = (tx4 - tx2) / (ty2 - ty1);
+ for(float y=ty1; y<ty2; y++) {
+ float _x1 = (y - ty1) * slope1 + tx1;
+ float _x2 = (y - ty1) * slope2 + tx2;
+ if (_x1 > _x2) { float _x0 = _x1; _x1 = _x2; _x2 = _x0; }
+
+ for(float x=_x1; x<_x2; x++) {
+
+ float distance = isLinear ?
+ // length of projection of <x,y> onto the gradient vector == {<x,y> \dot {grad \over |grad|}}
+ (x * (x2 - x1) + y * (y2 - y1)) / (float)Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) :
+
+ // radial form is simple! FIXME, not quite right
+ (float)Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
+
+ // FIXME: offsets are 0..1, not 0..length(gradient)
+ int i = 0; for(; i<stop_offsets.length; i++) if (distance < stop_offsets[i]) break;
+
+ // FIXME: handle points beyond the bounds
+ if (i < 0 || i >= stop_offsets.length) continue;
+
+ // gradate from offsets[i - 1] to offsets[i]
+ float percentage = ((distance - stop_offsets[i - 1]) / (stop_offsets[i] - stop_offsets[i - 1]));
+
+ int a = (int)((((stop_colors[i] >> 24) & 0xff) - ((stop_colors[i - 1] >> 24) & 0xff)) * percentage) +
+ ((stop_colors[i - 1] >> 24) & 0xff);
+ int r = (int)((((stop_colors[i] >> 16) & 0xff) - ((stop_colors[i - 1] >> 16) & 0xff)) * percentage) +
+ ((stop_colors[i - 1] >> 16) & 0xff);
+ int g = (int)((((stop_colors[i] >> 8) & 0xff) - ((stop_colors[i - 1] >> 8) & 0xff)) * percentage) +
+ ((stop_colors[i - 1] >> 8) & 0xff);
+ int b = (int)((((stop_colors[i] >> 0) & 0xff) - ((stop_colors[i - 1] >> 0) & 0xff)) * percentage) +
+ ((stop_colors[i - 1] >> 0) & 0xff);
+ int argb = (a << 24) | (r << 16) | (g << 8) | b;
+ buf.drawPoint((int)x, (int)Math.floor(y), argb);
+ }
+ }
+ }
+ }
+
+ public static class LinearGradientPaint extends GradientPaint {
+ public LinearGradientPaint(float x1, float y1, float x2, float y2, boolean reflect, boolean repeat,
+ Affine gradientTransform, int[] stop_colors, float[] stop_offsets) {
+ super(reflect, repeat, gradientTransform, stop_colors, stop_offsets);
+ this.x1 = x1; this.x2 = x2; this.y1 = y1; this.y2 = y2;
+ }
+ float x1 = 0, y1 = 0, x2 = 300, y2 = 300;
+ }
+
+ public static class RadialGradientPaint extends GradientPaint {
+ public RadialGradientPaint(float cx, float cy, float fx, float fy, float r, boolean reflect, boolean repeat,
+ Affine gradientTransform, int[] stop_colors, float[] stop_offsets) {
+ super(reflect, repeat, gradientTransform, stop_colors, stop_offsets);
+ this.cx = cx; this.cy = cy; this.fx = fx; this.fy = fy; this.r = r;
+ }
+
+ float cx, cy, r, fx, fy;
+
+ }
+ */
+
+
+}
// FIXME
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
+package org.ibex.graphics;
import java.util.*;
-// FIXME: offer a "subpixel" mode where we pass floats to the Platform and don't do any snapping
-// FIXME: fracture when realizing instead of when parsing?
-
-/*
- v1.0
- - textpath
- - gradients
- - patterns
- - clipping/masking
- - filters (filtering of a group must be performed AFTER the group is assembled; sep. canvas)
-
- v1.1
- - bump caps [requires Paint that can fill circles...] [remember to distinguish between closed/unclosed]
- - line joins
- - mitre (hard)
- - bevel (easy)
- - bump (easy, but requires 'round' Paint)
- - subtree sharing? otherwise the memory consumption might be outrageous... clone="" attribute?
- - better clipping
- - intersect clip regions (linearity)
- - clip on trapezoids, not pixels
- - faster gradients and patterns:
- - transform each corner of the trapezoid and then interpolate
-*/
-
-/** Ibex's fully conformant Static SVG Viewer; see SVG spec, section G.7 */
-public final class VectorGraphics {
-
- // Private Constants ///////////////////////////////////////////////////////////////////
+/** an abstract path; may contain splines and arcs */
+public class Path {
+ public static final float PX_PER_INCH = 72;
+ public static final float INCHES_PER_CM = (float)0.3937;
+ public static final float INCHES_PER_MM = INCHES_PER_CM / 10;
private static final int DEFAULT_PATHLEN = 1000;
private static final float PI = (float)Math.PI;
+ // the number of vertices on this path
+ int numvertices = 0;
- // Public entry points /////////////////////////////////////////////////////////////////
-
- public static VectorPath parseVectorPath(String s) {
- if (s == null) return null;
- PathTokenizer t = new PathTokenizer(s);
- VectorPath ret = new VectorPath();
- char last_command = 'M';
- boolean first = true;
- while(t.hasMoreTokens()) {
- char command = t.parseCommand();
- if (first && command != 'M') throw new RuntimeException("the first command of a path must be 'M'");
- first = false;
- boolean relative = Character.toLowerCase(command) == command;
- command = Character.toLowerCase(command);
- ret.parseSingleCommandAndArguments(t, command, relative);
- last_command = command;
- }
- return ret;
- }
-
-
- // Affine //////////////////////////////////////////////////////////////////////////////
-
- /** an affine transform; all operations are destructive */
- public static final class Affine {
-
- // [ a b e ]
- // [ c d f ]
- // [ 0 0 1 ]
- public float a, b, c, d, e, f;
-
- Affine(float _a, float _b, float _c, float _d, float _e, float _f) { a = _a; b = _b; c = _c; d = _d; e = _e; f = _f; }
- public String toString() { return "[ " + a + ", " + b + ", " + c + ", " + d + ", " + e + ", " + f + " ]"; }
- public Affine copy() { return new Affine(a, b, c, d, e, f); }
- public static Affine identity() { return new Affine(1, 0, 0, 1, 0, 0); }
- public static Affine scale(float sx, float sy) { return new Affine(sx, 0, 0, sy, 0, 0); }
- public static Affine shear(float degrees) {
- return new Affine(1, 0, (float)Math.tan(degrees * (float)(Math.PI / 180.0)), 1, 0, 0); }
- public static Affine translate(float tx, float ty) { return new Affine(1, 0, 0, 1, tx, ty); }
- public static Affine flip(boolean horiz, boolean vert) { return new Affine(horiz ? -1 : 1, 0, 0, vert ? -1 : 1, 0, 0); }
- public float multiply_px(float x, float y) { return x * a + y * c + e; }
- public float multiply_py(float x, float y) { return x * b + y * d + f; }
- public boolean equalsIgnoringTranslation(Affine x) { return a == x.a && b == x.b && c == x.c && d == x.d; }
-
- public boolean equals(Object o) {
- if (!(o instanceof Affine)) return false;
- Affine x = (Affine)o;
- return a == x.a && b == x.b && c == x.c && d == x.d && e == x.e && f == x.f;
- }
+ // the vertices of the path
+ float[] x = new float[DEFAULT_PATHLEN];
+ float[] y = new float[DEFAULT_PATHLEN];
- public static Affine rotate(float degrees) {
- float s = (float)Math.sin(degrees * (float)(Math.PI / 180.0));
- float c = (float)Math.cos(degrees * (float)(Math.PI / 180.0));
- return new Affine(c, s, -s, c, 0, 0);
- }
+ // the type of each edge; type[i] is the type of the edge from x[i],y[i] to x[i+1],y[i+1]
+ byte[] type = new byte[DEFAULT_PATHLEN];
- /** this = this * a */
- public Affine multiply(Affine A) {
- float _a = this.a * A.a + this.b * A.c;
- float _b = this.a * A.b + this.b * A.d;
- float _c = this.c * A.a + this.d * A.c;
- float _d = this.c * A.b + this.d * A.d;
- float _e = this.e * A.a + this.f * A.c + A.e;
- float _f = this.e * A.b + this.f * A.d + A.f;
- a = _a; b = _b; c = _c; d = _d; e = _e; f = _f;
- return this;
- }
-
- public void invert() {
- float det = 1 / (a * d - b * c);
- float _a = d * det;
- float _b = -1 * b * det;
- float _c = -1 * c * det;
- float _d = a * det;
- float _e = -1 * e * a - f * c;
- float _f = -1 * e * b - f * d;
- a = _a; b = _b; c = _c; d = _d; e = _e; f = _f;
- }
- }
+ // bezier control points
+ float[] c1x = new float[DEFAULT_PATHLEN]; // or rx (arcto)
+ float[] c1y = new float[DEFAULT_PATHLEN]; // or ry (arcto)
+ float[] c2x = new float[DEFAULT_PATHLEN]; // or x-axis-rotation (arcto)
+ float[] c2y = new float[DEFAULT_PATHLEN]; // or large-arc << 1 | sweep (arcto)
+ boolean closed = false;
- // PathTokenizer //////////////////////////////////////////////////////////////////////////////
+ static final byte TYPE_MOVETO = 0;
+ static final byte TYPE_LINETO = 1;
+ static final byte TYPE_ARCTO = 2;
+ static final byte TYPE_CUBIC = 3;
+ static final byte TYPE_QUADRADIC = 4;
- public static Affine parseTransform(String t) {
- if (t == null) return null;
- t = t.trim();
- Affine ret = VectorGraphics.Affine.identity();
- while (t.length() > 0) {
- if (t.startsWith("skewX(")) {
- // FIXME
-
- } else if (t.startsWith("shear(")) {
- // FIXME: nonstandard; remove this
- ret.multiply(VectorGraphics.Affine.shear(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(')')))));
-
- } else if (t.startsWith("skewY(")) {
- // FIXME
-
- } else if (t.startsWith("rotate(")) {
- String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
- if (sub.indexOf(',') != -1) {
- float angle = Float.parseFloat(sub.substring(0, sub.indexOf(',')));
- sub = sub.substring(sub.indexOf(',') + 1);
- float cx = Float.parseFloat(sub.substring(0, sub.indexOf(',')));
- sub = sub.substring(sub.indexOf(',') + 1);
- float cy = Float.parseFloat(sub);
- ret.multiply(VectorGraphics.Affine.translate(cx, cy));
- ret.multiply(VectorGraphics.Affine.rotate(angle));
- ret.multiply(VectorGraphics.Affine.translate(-1 * cx, -1 * cy));
- } else {
- ret.multiply(VectorGraphics.Affine.rotate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(')')))));
- }
-
- } else if (t.startsWith("translate(")) {
- String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
- if (sub.indexOf(',') > -1) {
- ret.multiply(VectorGraphics.Affine.translate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))),
- Float.parseFloat(t.substring(t.indexOf(',') + 1, t.indexOf(')')))));
- } else {
- ret.multiply(VectorGraphics.Affine.translate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))), 0));
- }
-
- } else if (t.startsWith("flip(")) {
- String which = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
- ret.multiply(VectorGraphics.Affine.flip(which.equals("horizontal"), which.equals("vertical")));
-
- } else if (t.startsWith("scale(")) {
- String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
- if (sub.indexOf(',') > -1) {
- ret.multiply(VectorGraphics.Affine.scale(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))),
- Float.parseFloat(t.substring(t.indexOf(',') + 1, t.indexOf(')')))));
- } else {
- ret.multiply(VectorGraphics.Affine.scale(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))),
- Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(',')))));
- }
-
- } else if (t.startsWith("matrix(")) {
- // FIXME: is this mapped right?
- float d[] = new float[6];
- StringTokenizer st = new StringTokenizer(t, ",", false);
- for(int i=0; i<6; i++)
- d[i] = Float.parseFloat(st.nextToken());
- ret.multiply(new VectorGraphics.Affine(d[0], d[1], d[2], d[3], d[4], d[5]));
- }
- t = t.substring(t.indexOf(')') + 1).trim();
- }
- return ret;
- }
-
- public static final float PX_PER_INCH = 72;
- public static final float INCHES_PER_CM = (float)0.3937;
- public static final float INCHES_PER_MM = INCHES_PER_CM / 10;
-
- public static class PathTokenizer {
+ public static class Tokenizer {
// FIXME: check array bounds exception for improperly terminated string
String s;
int i = 0;
char lastCommand = 'M';
- public PathTokenizer(String s) { this.s = s; }
+ public Tokenizer(String s) { this.s = s; }
+
+ public static Path parse(String s) {
+ if (s == null) return null;
+ Tokenizer t = new Tokenizer(s);
+ Path ret = new Path();
+ char last_command = 'M';
+ boolean first = true;
+ while(t.hasMoreTokens()) {
+ char command = t.parseCommand();
+ if (first && command != 'M') throw new RuntimeException("the first command of a path must be 'M'");
+ first = false;
+ boolean relative = Character.toLowerCase(command) == command;
+ command = Character.toLowerCase(command);
+ ret.parseSingleCommandAndArguments(t, command, relative);
+ last_command = command;
+ }
+ return ret;
+ }
+
private void consumeWhitespace() {
while(i < s.length() && (Character.isWhitespace(s.charAt(i)))) i++;
if (i < s.length() && s.charAt(i) == ',') i++;
}
}
+ /** Creates a concrete vector path transformed through the given matrix. */
+ public Raster realize(Affine a) {
+
+ Raster ret = new Raster();
+ int NUMSTEPS = 5; // FIXME
+ ret.numvertices = 1;
+ ret.x[0] = (int)Math.round(a.multiply_px(x[0], y[0]));
+ ret.y[0] = (int)Math.round(a.multiply_py(x[0], y[0]));
+
+ for(int i=1; i<numvertices; i++) {
+ if (type[i] == TYPE_LINETO) {
+ float rx = x[i];
+ float ry = y[i];
+ ret.x[ret.numvertices] = (int)Math.round(a.multiply_px(rx, ry));
+ ret.y[ret.numvertices] = (int)Math.round(a.multiply_py(rx, ry));
+ ret.edges[ret.numedges++] = ret.numvertices - 1; ret.numvertices++;
+
+ } else if (type[i] == TYPE_MOVETO) {
+ float rx = x[i];
+ float ry = y[i];
+ ret.x[ret.numvertices] = (int)Math.round(a.multiply_px(rx, ry));
+ ret.y[ret.numvertices] = (int)Math.round(a.multiply_py(rx, ry));
+ ret.numvertices++;
+
+ } else if (type[i] == TYPE_ARCTO) {
+ float rx = c1x[i];
+ float ry = c1y[i];
+ float phi = c2x[i];
+ float fa = ((int)c2y[i]) >> 1;
+ float fs = ((int)c2y[i]) & 1;
+ float x1 = x[i];
+ float y1 = y[i];
+ float x2 = x[i+1];
+ float y2 = y[i+1];
+
+ // F.6.5: given x1,y1,x2,y2,fa,fs, compute cx,cy,theta1,dtheta
+ float x1_ = (float)Math.cos(phi) * (x1 - x2) / 2 + (float)Math.sin(phi) * (y1 - y2) / 2;
+ float y1_ = -1 * (float)Math.sin(phi) * (x1 - x2) / 2 + (float)Math.cos(phi) * (y1 - y2) / 2;
+ float tmp = (float)Math.sqrt((rx * rx * ry * ry - rx * rx * y1_ * y1_ - ry * ry * x1_ * x1_) /
+ (rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_));
+ float cx_ = (fa == fs ? -1 : 1) * tmp * (rx * y1_ / ry);
+ float cy_ = (fa == fs ? -1 : 1) * -1 * tmp * (ry * x1_ / rx);
+ float cx = (float)Math.cos(phi) * cx_ - (float)Math.sin(phi) * cy_ + (x1 + x2) / 2;
+ float cy = (float)Math.sin(phi) * cx_ + (float)Math.cos(phi) * cy_ + (y1 + y2) / 2;
+
+ // F.6.4 Conversion from center to endpoint parameterization
+ float ux = 1, uy = 0, vx = (x1_ - cx_) / rx, vy = (y1_ - cy_) / ry;
+ float det = ux * vy - uy * vx;
+ float theta1 = (det < 0 ? -1 : 1) *
+ (float)Math.acos((ux * vx + uy * vy) /
+ ((float)Math.sqrt(ux * ux + uy * uy) * (float)Math.sqrt(vx * vx + vy * vy)));
+ ux = (x1_ - cx_) / rx; uy = (y1_ - cy_) / ry;
+ vx = (-1 * x1_ - cx_) / rx; vy = (-1 * y1_ - cy_) / ry;
+ det = ux * vy - uy * vx;
+ float dtheta = (det < 0 ? -1 : 1) *
+ (float)Math.acos((ux * vx + uy * vy) /
+ ((float)Math.sqrt(ux * ux + uy * uy) * (float)Math.sqrt(vx * vx + vy * vy)));
+ dtheta = dtheta % (float)(2 * Math.PI);
+
+ if (fs == 0 && dtheta > 0) theta1 -= 2 * PI;
+ if (fs == 1 && dtheta < 0) theta1 += 2 * PI;
+
+ if (fa == 1 && dtheta < 0) dtheta = 2 * PI + dtheta;
+ else if (fa == 1 && dtheta > 0) dtheta = -1 * (2 * PI - dtheta);
+
+ // FIXME: integrate F.6.6
+ // FIXME: isn't quite ending where it should...
+
+ // F.6.3: Parameterization alternatives
+ float theta = theta1;
+ for(int j=0; j<NUMSTEPS; j++) {
+ float rasterx = rx * (float)Math.cos(theta) * (float)Math.cos(phi) -
+ ry * (float)Math.sin(theta) * (float)Math.sin(phi) + cx;
+ float rastery = rx * (float)Math.cos(theta) * (float)Math.sin(phi) +
+ ry * (float)Math.cos(phi) * (float)Math.sin(theta) + cy;
+ ret.x[ret.numvertices] = (int)Math.round(a.multiply_px(rasterx, rastery));
+ ret.y[ret.numvertices] = (int)Math.round(a.multiply_py(rasterx, rastery));
+ ret.edges[ret.numedges++] = ret.numvertices - 1; ret.numvertices++;
+ theta += dtheta / NUMSTEPS;
+ }
- // Abstract Path //////////////////////////////////////////////////////////////////////////////
-
- /** an abstract path; may contain splines and arcs */
- public static class VectorPath {
-
- // the number of vertices on this path
- int numvertices = 0;
-
- // the vertices of the path
- float[] x = new float[DEFAULT_PATHLEN];
- float[] y = new float[DEFAULT_PATHLEN];
-
- // the type of each edge; type[i] is the type of the edge from x[i],y[i] to x[i+1],y[i+1]
- byte[] type = new byte[DEFAULT_PATHLEN];
-
- // bezier control points
- float[] c1x = new float[DEFAULT_PATHLEN]; // or rx (arcto)
- float[] c1y = new float[DEFAULT_PATHLEN]; // or ry (arcto)
- float[] c2x = new float[DEFAULT_PATHLEN]; // or x-axis-rotation (arcto)
- float[] c2y = new float[DEFAULT_PATHLEN]; // or large-arc << 1 | sweep (arcto)
-
- boolean closed = false;
-
- static final byte TYPE_MOVETO = 0;
- static final byte TYPE_LINETO = 1;
- static final byte TYPE_ARCTO = 2;
- static final byte TYPE_CUBIC = 3;
- static final byte TYPE_QUADRADIC = 4;
-
- /** Creates a concrete vector path transformed through the given matrix. */
- public RasterPath realize(Affine a) {
-
- RasterPath ret = new RasterPath();
- int NUMSTEPS = 5; // FIXME
- ret.numvertices = 1;
- ret.x[0] = (int)Math.round(a.multiply_px(x[0], y[0]));
- ret.y[0] = (int)Math.round(a.multiply_py(x[0], y[0]));
+ } else if (type[i] == TYPE_CUBIC) {
- for(int i=1; i<numvertices; i++) {
- if (type[i] == TYPE_LINETO) {
- float rx = x[i];
- float ry = y[i];
+ float ax = x[i+1] - 3 * c2x[i] + 3 * c1x[i] - x[i];
+ float bx = 3 * c2x[i] - 6 * c1x[i] + 3 * x[i];
+ float cx = 3 * c1x[i] - 3 * x[i];
+ float dx = x[i];
+ float ay = y[i+1] - 3 * c2y[i] + 3 * c1y[i] - y[i];
+ float by = 3 * c2y[i] - 6 * c1y[i] + 3 * y[i];
+ float cy = 3 * c1y[i] - 3 * y[i];
+ float dy = y[i];
+
+ for(float t=0; t<1; t += 1 / (float)NUMSTEPS) {
+ float rx = ax * t * t * t + bx * t * t + cx * t + dx;
+ float ry = ay * t * t * t + by * t * t + cy * t + dy;
ret.x[ret.numvertices] = (int)Math.round(a.multiply_px(rx, ry));
ret.y[ret.numvertices] = (int)Math.round(a.multiply_py(rx, ry));
ret.edges[ret.numedges++] = ret.numvertices - 1; ret.numvertices++;
+ }
+
+
+ } else if (type[i] == TYPE_QUADRADIC) {
- } else if (type[i] == TYPE_MOVETO) {
- float rx = x[i];
- float ry = y[i];
+ float bx = x[i+1] - 2 * c1x[i] + x[i];
+ float cx = 2 * c1x[i] - 2 * x[i];
+ float dx = x[i];
+ float by = y[i+1] - 2 * c1y[i] + y[i];
+ float cy = 2 * c1y[i] - 2 * y[i];
+ float dy = y[i];
+
+ for(float t=0; t<1; t += 1 / (float)NUMSTEPS) {
+ float rx = bx * t * t + cx * t + dx;
+ float ry = by * t * t + cy * t + dy;
ret.x[ret.numvertices] = (int)Math.round(a.multiply_px(rx, ry));
ret.y[ret.numvertices] = (int)Math.round(a.multiply_py(rx, ry));
- ret.numvertices++;
-
- } else if (type[i] == TYPE_ARCTO) {
- float rx = c1x[i];
- float ry = c1y[i];
- float phi = c2x[i];
- float fa = ((int)c2y[i]) >> 1;
- float fs = ((int)c2y[i]) & 1;
- float x1 = x[i];
- float y1 = y[i];
- float x2 = x[i+1];
- float y2 = y[i+1];
-
- // F.6.5: given x1,y1,x2,y2,fa,fs, compute cx,cy,theta1,dtheta
- float x1_ = (float)Math.cos(phi) * (x1 - x2) / 2 + (float)Math.sin(phi) * (y1 - y2) / 2;
- float y1_ = -1 * (float)Math.sin(phi) * (x1 - x2) / 2 + (float)Math.cos(phi) * (y1 - y2) / 2;
- float tmp = (float)Math.sqrt((rx * rx * ry * ry - rx * rx * y1_ * y1_ - ry * ry * x1_ * x1_) /
- (rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_));
- float cx_ = (fa == fs ? -1 : 1) * tmp * (rx * y1_ / ry);
- float cy_ = (fa == fs ? -1 : 1) * -1 * tmp * (ry * x1_ / rx);
- float cx = (float)Math.cos(phi) * cx_ - (float)Math.sin(phi) * cy_ + (x1 + x2) / 2;
- float cy = (float)Math.sin(phi) * cx_ + (float)Math.cos(phi) * cy_ + (y1 + y2) / 2;
-
- // F.6.4 Conversion from center to endpoint parameterization
- float ux = 1, uy = 0, vx = (x1_ - cx_) / rx, vy = (y1_ - cy_) / ry;
- float det = ux * vy - uy * vx;
- float theta1 = (det < 0 ? -1 : 1) *
- (float)Math.acos((ux * vx + uy * vy) /
- ((float)Math.sqrt(ux * ux + uy * uy) * (float)Math.sqrt(vx * vx + vy * vy)));
- ux = (x1_ - cx_) / rx; uy = (y1_ - cy_) / ry;
- vx = (-1 * x1_ - cx_) / rx; vy = (-1 * y1_ - cy_) / ry;
- det = ux * vy - uy * vx;
- float dtheta = (det < 0 ? -1 : 1) *
- (float)Math.acos((ux * vx + uy * vy) /
- ((float)Math.sqrt(ux * ux + uy * uy) * (float)Math.sqrt(vx * vx + vy * vy)));
- dtheta = dtheta % (float)(2 * Math.PI);
-
- if (fs == 0 && dtheta > 0) theta1 -= 2 * PI;
- if (fs == 1 && dtheta < 0) theta1 += 2 * PI;
-
- if (fa == 1 && dtheta < 0) dtheta = 2 * PI + dtheta;
- else if (fa == 1 && dtheta > 0) dtheta = -1 * (2 * PI - dtheta);
-
- // FIXME: integrate F.6.6
- // FIXME: isn't quite ending where it should...
-
- // F.6.3: Parameterization alternatives
- float theta = theta1;
- for(int j=0; j<NUMSTEPS; j++) {
- float rasterx = rx * (float)Math.cos(theta) * (float)Math.cos(phi) -
- ry * (float)Math.sin(theta) * (float)Math.sin(phi) + cx;
- float rastery = rx * (float)Math.cos(theta) * (float)Math.sin(phi) +
- ry * (float)Math.cos(phi) * (float)Math.sin(theta) + cy;
- ret.x[ret.numvertices] = (int)Math.round(a.multiply_px(rasterx, rastery));
- ret.y[ret.numvertices] = (int)Math.round(a.multiply_py(rasterx, rastery));
- ret.edges[ret.numedges++] = ret.numvertices - 1; ret.numvertices++;
- theta += dtheta / NUMSTEPS;
- }
-
- } else if (type[i] == TYPE_CUBIC) {
-
- float ax = x[i+1] - 3 * c2x[i] + 3 * c1x[i] - x[i];
- float bx = 3 * c2x[i] - 6 * c1x[i] + 3 * x[i];
- float cx = 3 * c1x[i] - 3 * x[i];
- float dx = x[i];
- float ay = y[i+1] - 3 * c2y[i] + 3 * c1y[i] - y[i];
- float by = 3 * c2y[i] - 6 * c1y[i] + 3 * y[i];
- float cy = 3 * c1y[i] - 3 * y[i];
- float dy = y[i];
-
- for(float t=0; t<1; t += 1 / (float)NUMSTEPS) {
- float rx = ax * t * t * t + bx * t * t + cx * t + dx;
- float ry = ay * t * t * t + by * t * t + cy * t + dy;
- ret.x[ret.numvertices] = (int)Math.round(a.multiply_px(rx, ry));
- ret.y[ret.numvertices] = (int)Math.round(a.multiply_py(rx, ry));
- ret.edges[ret.numedges++] = ret.numvertices - 1; ret.numvertices++;
- }
-
-
- } else if (type[i] == TYPE_QUADRADIC) {
-
- float bx = x[i+1] - 2 * c1x[i] + x[i];
- float cx = 2 * c1x[i] - 2 * x[i];
- float dx = x[i];
- float by = y[i+1] - 2 * c1y[i] + y[i];
- float cy = 2 * c1y[i] - 2 * y[i];
- float dy = y[i];
-
- for(float t=0; t<1; t += 1 / (float)NUMSTEPS) {
- float rx = bx * t * t + cx * t + dx;
- float ry = by * t * t + cy * t + dy;
- ret.x[ret.numvertices] = (int)Math.round(a.multiply_px(rx, ry));
- ret.y[ret.numvertices] = (int)Math.round(a.multiply_py(rx, ry));
- ret.edges[ret.numedges++] = ret.numvertices - 1; ret.numvertices++;
- }
+ ret.edges[ret.numedges++] = ret.numvertices - 1; ret.numvertices++;
+ }
- }
+ }
- }
+ }
- if (ret.numedges > 0) ret.sort(0, ret.numedges - 1, false);
- return ret;
- }
+ if (ret.numedges > 0) ret.sort(0, ret.numedges - 1, false);
+ return ret;
+ }
- protected void parseSingleCommandAndArguments(PathTokenizer t, char command, boolean relative) {
- if (numvertices == 0 && command != 'm') throw new RuntimeException("first command MUST be an 'm'");
- if (numvertices > x.length - 2) {
- float[] new_x = new float[x.length * 2]; System.arraycopy(x, 0, new_x, 0, x.length); x = new_x;
- float[] new_y = new float[y.length * 2]; System.arraycopy(y, 0, new_y, 0, y.length); y = new_y;
- }
- switch(command) {
+ protected void parseSingleCommandAndArguments(Tokenizer t, char command, boolean relative) {
+ if (numvertices == 0 && command != 'm') throw new RuntimeException("first command MUST be an 'm'");
+ if (numvertices > x.length - 2) {
+ float[] new_x = new float[x.length * 2]; System.arraycopy(x, 0, new_x, 0, x.length); x = new_x;
+ float[] new_y = new float[y.length * 2]; System.arraycopy(y, 0, new_y, 0, y.length); y = new_y;
+ }
+ switch(command) {
case 'z': {
int where;
type[numvertices-1] = TYPE_LINETO;
default:
// FIXME
- }
+ }
- /*
- // invariant: after this loop, no two lines intersect other than at a vertex
- // FIXME: cleanup
- int index = numvertices - 2;
- for(int i=0; i<Math.min(numvertices - 3, index); i++) {
- for(int j = index; j < numvertices - 1; j++) {
+ /*
+ // invariant: after this loop, no two lines intersect other than at a vertex
+ // FIXME: cleanup
+ int index = numvertices - 2;
+ for(int i=0; i<Math.min(numvertices - 3, index); i++) {
+ for(int j = index; j < numvertices - 1; j++) {
- // I'm not sure how to deal with vertical lines...
- if (x[i+1] == x[i] || x[j+1] == x[j]) continue;
+ // I'm not sure how to deal with vertical lines...
+ if (x[i+1] == x[i] || x[j+1] == x[j]) continue;
- float islope = (y[i+1] - y[i]) / (x[i+1] - x[i]);
- float jslope = (y[j+1] - y[j]) / (x[j+1] - x[j]);
- if (islope == jslope) continue; // parallel lines can't intersect
+ float islope = (y[i+1] - y[i]) / (x[i+1] - x[i]);
+ float jslope = (y[j+1] - y[j]) / (x[j+1] - x[j]);
+ if (islope == jslope) continue; // parallel lines can't intersect
- float _x = (islope * x[i] - jslope * x[j] + y[j] - y[i]) / (islope - jslope);
- float _y = islope * (_x - x[i]) + y[i];
+ float _x = (islope * x[i] - jslope * x[j] + y[j] - y[i]) / (islope - jslope);
+ float _y = islope * (_x - x[i]) + y[i];
- if (_x > Math.min(x[i+1], x[i]) && _x < Math.max(x[i+1], x[i]) &&
- _x > Math.min(x[j+1], x[j]) && _x < Math.max(x[j+1], x[j])) {
- // FIXME: something's not right in here. See if we can do without fracturing line 'i'.
- for(int k = ++numvertices; k>i; k--) { x[k] = x[k - 1]; y[k] = y[k - 1]; }
- x[i+1] = _x;
- y[i+1] = _y;
- x[numvertices] = x[numvertices - 1]; x[numvertices - 1] = _x;
- y[numvertices] = y[numvertices - 1]; y[numvertices - 1] = _y;
- edges[numedges++] = numvertices - 1; numvertices++;
- index++;
- break; // actually 'continue' the outermost loop
- }
- }
- }
- */
+ if (_x > Math.min(x[i+1], x[i]) && _x < Math.max(x[i+1], x[i]) &&
+ _x > Math.min(x[j+1], x[j]) && _x < Math.max(x[j+1], x[j])) {
+ // FIXME: something's not right in here. See if we can do without fracturing line 'i'.
+ for(int k = ++numvertices; k>i; k--) { x[k] = x[k - 1]; y[k] = y[k - 1]; }
+ x[i+1] = _x;
+ y[i+1] = _y;
+ x[numvertices] = x[numvertices - 1]; x[numvertices - 1] = _x;
+ y[numvertices] = y[numvertices - 1]; y[numvertices - 1] = _y;
+ edges[numedges++] = numvertices - 1; numvertices++;
+ index++;
+ break; // actually 'continue' the outermost loop
+ }
+ }
+ }
+ */
- }
}
-
-
// Rasterized Vector Path //////////////////////////////////////////////////////////////////////////////
/** a vector path */
- public static class RasterPath {
+ public static class Raster {
// the vertices of this path
int[] x = new int[DEFAULT_PATHLEN];
}
ratio = actualLength / segLength;
}
- PathTokenizer pt = new PathTokenizer(dashArray);
+ Tokenizer pt = new Tokenizer(dashArray);
Vector v = new Vector();
while (pt.hasMoreTokens()) v.addElement(new Float(pt.parseFloat()));
float[] dashes = new float[v.size() % 2 == 0 ? v.size() : 2 * v.size()];
return ret;
}
}
-
-
- // Paint //////////////////////////////////////////////////////////////////////////////
- public static interface Paint {
- public abstract void
- fillTrapezoid(int tx1, int tx2, int ty1, int tx3, int tx4, int ty2, PixelBuffer buf);
- }
-
- public static class SingleColorPaint implements Paint {
- int color;
- public SingleColorPaint(int color) { this.color = color; }
- public void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, PixelBuffer buf) {
- buf.fillTrapezoid(x1, x2, y1, x3, x4, y2, color);
- }
- }
}
-
-
-
-
-
-
-
-
-
- /*
- public static abstract class GradientPaint extends Paint {
- public GradientPaint(boolean reflect, boolean repeat, Affine gradientTransform,
- int[] stop_colors, float[] stop_offsets) {
- this.reflect = reflect; this.repeat = repeat;
- this.gradientTransform = gradientTransform;
- this.stop_colors = stop_colors;
- this.stop_offsets = stop_offsets;
- }
- Affine gradientTransform = Affine.identity();
- boolean useBoundingBox = false; // FIXME not supported
- boolean patternUseBoundingBox = false; // FIXME not supported
-
- // it's invalid for both of these to be true
- boolean reflect = false; // FIXME not supported
- boolean repeat = false; // FIXME not supported
- int[] stop_colors;
- float[] stop_offsets;
-
- public void fillTrapezoid(float tx1, float tx2, float ty1, float tx3, float tx4, float ty2, PixelBuffer buf) {
- Affine a = buf.a;
- Affine inverse = a.copy().invert();
- float slope1 = (tx3 - tx1) / (ty2 - ty1);
- float slope2 = (tx4 - tx2) / (ty2 - ty1);
- for(float y=ty1; y<ty2; y++) {
- float _x1 = (y - ty1) * slope1 + tx1;
- float _x2 = (y - ty1) * slope2 + tx2;
- if (_x1 > _x2) { float _x0 = _x1; _x1 = _x2; _x2 = _x0; }
-
- for(float x=_x1; x<_x2; x++) {
-
- float distance = isLinear ?
- // length of projection of <x,y> onto the gradient vector == {<x,y> \dot {grad \over |grad|}}
- (x * (x2 - x1) + y * (y2 - y1)) / (float)Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) :
-
- // radial form is simple! FIXME, not quite right
- (float)Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
-
- // FIXME: offsets are 0..1, not 0..length(gradient)
- int i = 0; for(; i<stop_offsets.length; i++) if (distance < stop_offsets[i]) break;
-
- // FIXME: handle points beyond the bounds
- if (i < 0 || i >= stop_offsets.length) continue;
-
- // gradate from offsets[i - 1] to offsets[i]
- float percentage = ((distance - stop_offsets[i - 1]) / (stop_offsets[i] - stop_offsets[i - 1]));
-
- int a = (int)((((stop_colors[i] >> 24) & 0xff) - ((stop_colors[i - 1] >> 24) & 0xff)) * percentage) +
- ((stop_colors[i - 1] >> 24) & 0xff);
- int r = (int)((((stop_colors[i] >> 16) & 0xff) - ((stop_colors[i - 1] >> 16) & 0xff)) * percentage) +
- ((stop_colors[i - 1] >> 16) & 0xff);
- int g = (int)((((stop_colors[i] >> 8) & 0xff) - ((stop_colors[i - 1] >> 8) & 0xff)) * percentage) +
- ((stop_colors[i - 1] >> 8) & 0xff);
- int b = (int)((((stop_colors[i] >> 0) & 0xff) - ((stop_colors[i - 1] >> 0) & 0xff)) * percentage) +
- ((stop_colors[i - 1] >> 0) & 0xff);
- int argb = (a << 24) | (r << 16) | (g << 8) | b;
- buf.drawPoint((int)x, (int)Math.floor(y), argb);
- }
- }
- }
- }
-
- public static class LinearGradientPaint extends GradientPaint {
- public LinearGradientPaint(float x1, float y1, float x2, float y2, boolean reflect, boolean repeat,
- Affine gradientTransform, int[] stop_colors, float[] stop_offsets) {
- super(reflect, repeat, gradientTransform, stop_colors, stop_offsets);
- this.x1 = x1; this.x2 = x2; this.y1 = y1; this.y2 = y2;
- }
- float x1 = 0, y1 = 0, x2 = 300, y2 = 300;
- }
-
- public static class RadialGradientPaint extends GradientPaint {
- public RadialGradientPaint(float cx, float cy, float fx, float fy, float r, boolean reflect, boolean repeat,
- Affine gradientTransform, int[] stop_colors, float[] stop_offsets) {
- super(reflect, repeat, gradientTransform, stop_colors, stop_offsets);
- this.cx = cx; this.cy = cy; this.fx = fx; this.fy = fy; this.r = r;
- }
-
- float cx, cy, r, fx, fy;
-
- }
- */
-
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.graphics;
import java.io.*;
import org.ibex.js.*;
+import org.ibex.plat.*;
import org.ibex.util.*;
-import org.ibex.translators.*;
+import org.ibex.core.*;
/**
* The in-memory representation of a PNG or GIF image. It is
protected void loaded() { isLoaded = true; }
/** turns a stream into a Picture.Source and passes it to the callback */
- public static Picture load(final JS stream, final Scheduler.Task callback) {
+ public static Picture load(final JS stream, final Task callback) {
Picture ret = (Picture)cache.get(stream);
if (ret == null) cache.put(stream, ret = Platform.createPicture(stream));
final Picture p = ret;
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.graphics;
/**
* <p>
public abstract class PixelBuffer {
/** draw the picture at (dx1, dy1), cropping to (cx1, cy1, cx2, cy2) */
- protected abstract void drawPicture(Picture source, int dx1, int dy1, int cx1, int cy1, int cx2, int cy2);
+ public abstract void drawPicture(Picture source, int dx1, int dy1, int cx1, int cy1, int cx2, int cy2);
/** fill a trapezoid whose top and bottom edges are horizontal */
public abstract void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int color);
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.translators;
+package org.ibex.graphics;
import java.util.*;
+
+// FIXME: offer a "subpixel" mode where we pass floats to the Platform and don't do any snapping
+// FIXME: fracture when realizing instead of when parsing?
+
+/*
+ v1.0
+ - textpath
+ - gradients
+ - patterns
+ - clipping/masking
+ - filters (filtering of a group must be performed AFTER the group is assembled; sep. canvas)
+
+ v1.1
+ - bump caps [requires Paint that can fill circles...] [remember to distinguish between closed/unclosed]
+ - line joins
+ - mitre (hard)
+ - bevel (easy)
+ - bump (easy, but requires 'round' Paint)
+ - subtree sharing? otherwise the memory consumption might be outrageous... clone="" attribute?
+ - better clipping
+ - intersect clip regions (linearity)
+ - clip on trapezoids, not pixels
+ - faster gradients and patterns:
+ - transform each corner of the trapezoid and then interpolate
+*/
+
// FIXME: need to support style sheets and the 'style=' attribute
// FIXME: need to convert markers into subboxes
public class SVG {
}
*/
-
- /** Copied verbatim from the SVG specification */
- public static Hashtable colors = new Hashtable(400);
- static {
- colors.put("aliceblue", new Integer((240 << 16) | (248 << 8) | 255));
- colors.put("antiquewhite", new Integer((250 << 16) | (235 << 8) | 215));
- colors.put("aqua", new Integer((0 << 16) | (255 << 8) | 255));
- colors.put("aquamarine", new Integer((127 << 16) | (255 << 8) | 212));
- colors.put("azure", new Integer((240 << 16) | (255 << 8) | 255));
- colors.put("beige", new Integer((245 << 16) | (245 << 8) | 220));
- colors.put("bisque", new Integer((255 << 16) | (228 << 8) | 196));
- colors.put("black", new Integer((0 << 16) | (0 << 8) | 0));
- colors.put("blanchedalmond", new Integer((255 << 16) | (235 << 8) | 205));
- colors.put("blue", new Integer((0 << 16) | (0 << 8) | 255));
- colors.put("blueviolet", new Integer((138 << 16) | (43 << 8) | 226));
- colors.put("brown", new Integer((165 << 16) | (42 << 8) | 42));
- colors.put("burlywood", new Integer((222 << 16) | (184 << 8) | 135));
- colors.put("cadetblue", new Integer((95 << 16) | (158 << 8) | 160));
- colors.put("chartreuse", new Integer((127 << 16) | (255 << 8) | 0));
- colors.put("chocolate", new Integer((210 << 16) | (105 << 8) | 30));
- colors.put("coral", new Integer((255 << 16) | (127 << 8) | 80));
- colors.put("cornflowerblue", new Integer((100 << 16) | (149 << 8) | 237));
- colors.put("cornsilk", new Integer((255 << 16) | (248 << 8) | 220));
- colors.put("crimson", new Integer((220 << 16) | (20 << 8) | 60));
- colors.put("cyan", new Integer((0 << 16) | (255 << 8) | 255));
- colors.put("darkblue", new Integer((0 << 16) | (0 << 8) | 139));
- colors.put("darkcyan", new Integer((0 << 16) | (139 << 8) | 139));
- colors.put("darkgoldenrod", new Integer((184 << 16) | (134 << 8) | 11));
- colors.put("darkgray", new Integer((169 << 16) | (169 << 8) | 169));
- colors.put("darkgreen", new Integer((0 << 16) | (100 << 8) | 0));
- colors.put("darkgrey", new Integer((169 << 16) | (169 << 8) | 169));
- colors.put("darkkhaki", new Integer((189 << 16) | (183 << 8) | 107));
- colors.put("darkmagenta", new Integer((139 << 16) | (0 << 8) | 139));
- colors.put("darkolivegreen", new Integer((85 << 16) | (107 << 8) | 47));
- colors.put("darkorange", new Integer((255 << 16) | (140 << 8) | 0));
- colors.put("darkorchid", new Integer((153 << 16) | (50 << 8) | 204));
- colors.put("darkred", new Integer((139 << 16) | (0 << 8) | 0));
- colors.put("darksalmon", new Integer((233 << 16) | (150 << 8) | 122));
- colors.put("darkseagreen", new Integer((143 << 16) | (188 << 8) | 143));
- colors.put("darkslateblue", new Integer((72 << 16) | (61 << 8) | 139));
- colors.put("darkslategray", new Integer((47 << 16) | (79 << 8) | 79));
- colors.put("darkslategrey", new Integer((47 << 16) | (79 << 8) | 79));
- colors.put("darkturquoise", new Integer((0 << 16) | (206 << 8) | 209));
- colors.put("darkviolet", new Integer((148 << 16) | (0 << 8) | 211));
- colors.put("deeppink", new Integer((255 << 16) | (20 << 8) | 147));
- colors.put("deepskyblue", new Integer((0 << 16) | (191 << 8) | 255));
- colors.put("dimgray", new Integer((105 << 16) | (105 << 8) | 105));
- colors.put("dimgrey", new Integer((105 << 16) | (105 << 8) | 105));
- colors.put("dodgerblue", new Integer((30 << 16) | (144 << 8) | 255));
- colors.put("firebrick", new Integer((178 << 16) | (34 << 8) | 34));
- colors.put("floralwhite", new Integer((255 << 16) | (250 << 8) | 240));
- colors.put("forestgreen", new Integer((34 << 16) | (139 << 8) | 34));
- colors.put("fuchsia", new Integer((255 << 16) | (0 << 8) | 255));
- colors.put("gainsboro", new Integer((220 << 16) | (220 << 8) | 220));
- colors.put("ghostwhite", new Integer((248 << 16) | (248 << 8) | 255));
- colors.put("gold", new Integer((255 << 16) | (215 << 8) | 0));
- colors.put("goldenrod", new Integer((218 << 16) | (165 << 8) | 32));
- colors.put("gray", new Integer((128 << 16) | (128 << 8) | 128));
- colors.put("grey", new Integer((128 << 16) | (128 << 8) | 128));
- colors.put("green", new Integer((0 << 16) | (128 << 8) | 0));
- colors.put("greenyellow", new Integer((173 << 16) | (255 << 8) | 47));
- colors.put("honeydew", new Integer((240 << 16) | (255 << 8) | 240));
- colors.put("hotpink", new Integer((255 << 16) | (105 << 8) | 180));
- colors.put("indianred", new Integer((205 << 16) | (92 << 8) | 92));
- colors.put("indigo", new Integer((75 << 16) | (0 << 8) | 130));
- colors.put("ivory", new Integer((255 << 16) | (255 << 8) | 240));
- colors.put("khaki", new Integer((240 << 16) | (230 << 8) | 140));
- colors.put("lavender", new Integer((230 << 16) | (230 << 8) | 250));
- colors.put("lavenderblush", new Integer((255 << 16) | (240 << 8) | 245));
- colors.put("lawngreen", new Integer((124 << 16) | (252 << 8) | 0));
- colors.put("lemonchiffon", new Integer((255 << 16) | (250 << 8) | 205));
- colors.put("lightblue", new Integer((173 << 16) | (216 << 8) | 230));
- colors.put("lightcoral", new Integer((240 << 16) | (128 << 8) | 128));
- colors.put("lightcyan", new Integer((224 << 16) | (255 << 8) | 255));
- colors.put("lightgoldenrodyellow", new Integer((250 << 16) | (250 << 8) | 210));
- colors.put("lightgray", new Integer((211 << 16) | (211 << 8) | 211));
- colors.put("lightgreen", new Integer((144 << 16) | (238 << 8) | 144));
- colors.put("lightgrey", new Integer((211 << 16) | (211 << 8) | 211));
- colors.put("lightpink", new Integer((255 << 16) | (182 << 8) | 193));
- colors.put("lightsalmon", new Integer((255 << 16) | (160 << 8) | 122));
- colors.put("lightseagreen", new Integer((32 << 16) | (178 << 8) | 170));
- colors.put("lightskyblue", new Integer((135 << 16) | (206 << 8) | 250));
- colors.put("lightslategray", new Integer((119 << 16) | (136 << 8) | 153));
- colors.put("lightslategrey", new Integer((119 << 16) | (136 << 8) | 153));
- colors.put("lightsteelblue", new Integer((176 << 16) | (196 << 8) | 222));
- colors.put("lightyellow", new Integer((255 << 16) | (255 << 8) | 224));
- colors.put("lime", new Integer((0 << 16) | (255 << 8) | 0));
- colors.put("limegreen", new Integer((50 << 16) | (205 << 8) | 50));
- colors.put("linen", new Integer((250 << 16) | (240 << 8) | 230));
- colors.put("magenta", new Integer((255 << 16) | (0 << 8) | 255));
- colors.put("maroon", new Integer((128 << 16) | (0 << 8) | 0));
- colors.put("mediumaquamarine", new Integer((102 << 16) | (205 << 8) | 170));
- colors.put("mediumblue", new Integer((0 << 16) | (0 << 8) | 205));
- colors.put("mediumorchid", new Integer((186 << 16) | (85 << 8) | 211));
- colors.put("mediumpurple", new Integer((147 << 16) | (112 << 8) | 219));
- colors.put("mediumseagreen", new Integer((60 << 16) | (179 << 8) | 113));
- colors.put("mediumslateblue", new Integer((123 << 16) | (104 << 8) | 238));
- colors.put("mediumspringgreen", new Integer((0 << 16) | (250 << 8) | 154));
- colors.put("mediumturquoise", new Integer((72 << 16) | (209 << 8) | 204));
- colors.put("mediumvioletred", new Integer((199 << 16) | (21 << 8) | 133));
- colors.put("midnightblue", new Integer((25 << 16) | (25 << 8) | 112));
- colors.put("mintcream", new Integer((245 << 16) | (255 << 8) | 250));
- colors.put("mistyrose", new Integer((255 << 16) | (228 << 8) | 225));
- colors.put("moccasin", new Integer((255 << 16) | (228 << 8) | 181));
- colors.put("navajowhite", new Integer((255 << 16) | (222 << 8) | 173));
- colors.put("navy", new Integer((0 << 16) | (0 << 8) | 128));
- colors.put("oldlace", new Integer((253 << 16) | (245 << 8) | 230));
- colors.put("olive", new Integer((128 << 16) | (128 << 8) | 0));
- colors.put("olivedrab", new Integer((107 << 16) | (142 << 8) | 35));
- colors.put("orange", new Integer((255 << 16) | (165 << 8) | 0));
- colors.put("orangered", new Integer((255 << 16) | (69 << 8) | 0));
- colors.put("orchid", new Integer((218 << 16) | (112 << 8) | 214));
- colors.put("palegoldenrod", new Integer((238 << 16) | (232 << 8) | 170));
- colors.put("palegreen", new Integer((152 << 16) | (251 << 8) | 152));
- colors.put("paleturquoise", new Integer((175 << 16) | (238 << 8) | 238));
- colors.put("palevioletred", new Integer((219 << 16) | (112 << 8) | 147));
- colors.put("papayawhip", new Integer((255 << 16) | (239 << 8) | 213));
- colors.put("peachpuff", new Integer((255 << 16) | (218 << 8) | 185));
- colors.put("peru", new Integer((205 << 16) | (133 << 8) | 63));
- colors.put("pink", new Integer((255 << 16) | (192 << 8) | 203));
- colors.put("plum", new Integer((221 << 16) | (160 << 8) | 221));
- colors.put("powderblue", new Integer((176 << 16) | (224 << 8) | 230));
- colors.put("purple", new Integer((128 << 16) | (0 << 8) | 128));
- colors.put("red", new Integer((255 << 16) | (0 << 8) | 0));
- colors.put("rosybrown", new Integer((188 << 16) | (143 << 8) | 143));
- colors.put("royalblue", new Integer((65 << 16) | (105 << 8) | 225));
- colors.put("saddlebrown", new Integer((139 << 16) | (69 << 8) | 19));
- colors.put("salmon", new Integer((250 << 16) | (128 << 8) | 114));
- colors.put("sandybrown", new Integer((244 << 16) | (164 << 8) | 96));
- colors.put("seagreen", new Integer((46 << 16) | (139 << 8) | 87));
- colors.put("seashell", new Integer((255 << 16) | (245 << 8) | 238));
- colors.put("sienna", new Integer((160 << 16) | (82 << 8) | 45));
- colors.put("silver", new Integer((192 << 16) | (192 << 8) | 192));
- colors.put("skyblue", new Integer((135 << 16) | (206 << 8) | 235));
- colors.put("slateblue", new Integer((106 << 16) | (90 << 8) | 205));
- colors.put("slategray", new Integer((112 << 16) | (128 << 8) | 144));
- colors.put("slategrey", new Integer((112 << 16) | (128 << 8) | 144));
- colors.put("snow", new Integer((255 << 16) | (250 << 8) | 250));
- colors.put("springgreen", new Integer((0 << 16) | (255 << 8) | 127));
- colors.put("steelblue", new Integer((70 << 16) | (130 << 8) | 180));
- colors.put("tan", new Integer((210 << 16) | (180 << 8) | 140));
- colors.put("teal", new Integer((0 << 16) | (128 << 8) | 128));
- colors.put("thistle", new Integer((216 << 16) | (191 << 8) | 216));
- colors.put("tomato", new Integer((255 << 16) | (99 << 8) | 71));
- colors.put("turquoise", new Integer((64 << 16) | (224 << 8) | 208));
- colors.put("violet", new Integer((238 << 16) | (130 << 8) | 238));
- colors.put("wheat", new Integer((245 << 16) | (222 << 8) | 179));
- colors.put("white", new Integer((255 << 16) | (255 << 8) | 255));
- colors.put("whitesmoke", new Integer((245 << 16) | (245 << 8) | 245));
- colors.put("yellow", new Integer((255 << 16) | (255 << 8) | 0));
- colors.put("yellowgreen", new Integer((154 << 16) | (205 << 8) | 50));
- }
-
}
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.graphics;
import org.ibex.js.*;
import org.ibex.util.*;
+import org.ibex.plat.*;
+
+import org.ibex.core.*; // FIXME
/**
* A Surface, as described in the Ibex Reference.
* Platform subclasses should include an inner class subclass of
* Surface to return from the Platform._createSurface() method
*/
-public abstract class Surface extends PixelBuffer implements Scheduler.Task {
+public abstract class Surface extends PixelBuffer implements Task {
// Static Data ////////////////////////////////////////////////////////////////////////////////
public static Vec allSurfaces = new Vec();
/** When set to true, render() should abort as soon as possible and restart the rendering process */
- volatile boolean abort = false;
+ public volatile boolean abort = false;
// these three variables are used to ensure that user resizes trump programmatic resizes
- volatile boolean syncRootBoxToSurface = false;
- volatile int pendingWidth = 0;
- volatile int pendingHeight = 0;
+ public volatile boolean syncRootBoxToSurface = false;
+ public volatile int pendingWidth = 0;
+ public volatile int pendingHeight = 0;
public static boolean alt = false; ///< true iff the alt button is pressed down
public static boolean control = false; ///< true iff the control button is pressed down
public void setMinimumSize(int minx, int miny, boolean resizable) { }
protected void setSize(int w, int h) { _setSize(w, h); }
+ public static Picture scarImage = null;
// Helper methods for subclasses ////////////////////////////////////////////////////////////
if (button == 1) new Message("_Press1", T, root);
else if (button == 2) new Message("_Press2", T, root);
else if (button == 3) {
- Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn {
+ Scheduler.add(new Task() { public void perform() throws JSExn {
Platform.clipboardReadEnabled = true;
try {
root.putAndTriggerTraps("_Press3", T);
}
/** we enqueue ourselves in the Scheduler when we have a Move message to deal with */
- private Scheduler.Task mover = new Scheduler.Task() {
+ private Task mover = new Task() {
public void perform() {
if (mousex == newmousex && mousey == newmousey) return;
int oldmousex = mousex; mousex = newmousex;
// FEATURE: can we avoid creating objects here?
protected final void PosChange(final int x, final int y) {
- Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn {
+ Scheduler.add(new Task() { public void perform() throws JSExn {
root.x = x;
root.y = y;
root.putAndTriggerTrapsAndCatchExceptions("PosChange", T);
public Surface(Box root) {
this.root = root;
- root.setMaxWidth(JS.N(Math.min(Platform.getScreenWidth(), root.maxwidth)));
- root.setMaxHeight(JS.N(Math.min(Platform.getScreenHeight(), root.maxheight)));
+ root.setWidth(root.minwidth, Math.min(Platform.getScreenWidth(), root.maxwidth));
+ root.setHeight(root.minheight, Math.min(Platform.getScreenHeight(), root.maxheight));
Surface old = fromBox(root);
if (old != null) old.dispose(false);
else root.removeSelf();
Refresh();
}
- private static VectorGraphics.Affine identity = VectorGraphics.Affine.identity();
+ private static Affine identity = Affine.identity();
/** runs the prerender() and render() pipelines in the root Box to regenerate the backbuffer, then blits it to the screen */
public synchronized void render() {
abort = false;
root.pack();
if (syncRootBoxToSurface) {
- root.setMaxWidth(JS.N(pendingWidth));
- root.setMaxHeight(JS.N(pendingHeight));
+ root.setWidth(root.minwidth, pendingWidth);
+ root.setHeight(root.minheight, pendingHeight);
syncRootBoxToSurface = false;
}
if (root.maxwidth != root.width || root.maxheight != root.height) {
// dirty the place where the scar used to be and where it is now
- dirty(0, root.height - Main.scarImage.height, Main.scarImage.width, Main.scarImage.height);
- dirty(0, root.maxheight - Main.scarImage.height, Main.scarImage.width, Main.scarImage.height);
+ dirty(0, root.height - scarImage.height, scarImage.width, scarImage.height);
+ dirty(0, root.maxheight - scarImage.height, scarImage.width, scarImage.height);
}
root.reflow();
setSize(root.width, root.height);
if (w <= 0 || h <= 0) continue;
root.render(0, 0, x, y, x + w, y + h, this, identity);
- drawPicture(Main.scarImage, 0, root.height - Main.scarImage.height, x, y, x+w, y+h);
+ drawPicture(scarImage, 0, root.height - scarImage.height, x, y, x+w, y+h);
if (abort) {
// x,y,w,h is only partially reconstructed, so we must be careful not to re-blit it
}
// FEATURE: reinstate recycler
- public class Message implements Scheduler.Task {
+ public class Message implements Task {
private Box boxContainingMouse;
private Object value;
return new JS.UnpauseCallback(i);
}
- public static class UnpauseCallback implements Scheduler.Task {
+ public static class UnpauseCallback implements Task {
Interpreter i;
UnpauseCallback(Interpreter i) { this.i = i; }
public void perform() throws JSExn { unpause(null); }
package org.ibex.js;
import java.io.*;
+import org.ibex.util.*;
/** A JavaScript function, compiled into bytecode */
-class JSFunction extends JS implements ByteCodes, Tokens, org.ibex.Scheduler.Task {
+class JSFunction extends JS implements ByteCodes, Tokens, Task {
// Fields and Accessors ///////////////////////////////////////////////
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.js;
import java.io.*;
import java.util.zip.*;
-import org.ibex.js.*;
import org.ibex.util.*;
-import org.ibex.translators.MSPack;
+import org.ibex.plat.*;
+import org.ibex.net.*;
/**
* Essentiall an InputStream "factory". You can repeatedly ask a
// Private Interface //////////////////////////////////////////////////////////////////////////////
- protected abstract InputStream getInputStream() throws IOException;
+ public abstract InputStream getInputStream() throws IOException;
protected String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); }
/** HTTP or HTTPS resource */
public static class HTTP extends Stream {
private String url;
public String toString() { return "Stream.HTTP:" + url; }
- HTTP(String url) { while (url.endsWith("/")) url = url.substring(0, url.length() - 1); this.url = url; }
+ public HTTP(String url) { while (url.endsWith("/")) url = url.substring(0, url.length() - 1); this.url = url; }
public Object _get(Object key) { return new HTTP(url + "/" + (String)key); }
public String getCacheKey(Vec path) throws NotCacheableException { return url; }
- public InputStream getInputStream() throws IOException { return new org.ibex.HTTP(url).GET(); }
+ public InputStream getInputStream() throws IOException { return new org.ibex.net.HTTP(url).GET(); }
}
/** byte arrays */
public static class ByteArray extends Stream {
private byte[] bytes;
private String cacheKey;
- ByteArray(byte[] bytes, String cacheKey) { this.bytes = bytes; this.cacheKey = cacheKey; }
+ public ByteArray(byte[] bytes, String cacheKey) { this.bytes = bytes; this.cacheKey = cacheKey; }
public String getCacheKey() throws NotCacheableException {
if (cacheKey == null) throw new NotCacheableException(); return cacheKey; }
public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(bytes); }
/** a file */
public static class File extends Stream {
private String path;
- File(String path) { this.path = path; }
+ public File(String path) { this.path = path; }
public String toString() { return "file:" + path; }
public String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); /* already on disk */ }
public InputStream getInputStream() throws IOException { return new FileInputStream(path); }
public static class Zip extends Stream {
private Stream parent;
private String path;
- Zip(Stream parent) { this(parent, null); }
- Zip(Stream parent, String path) {
+ public Zip(Stream parent) { this(parent, null); }
+ public Zip(Stream parent, String path) {
while(path != null && path.startsWith("/")) path = path.substring(1);
this.parent = parent;
this.path = path;
public static class Cab extends Stream {
private Stream parent;
private String path;
- Cab(Stream parent) { this(parent, null); }
- Cab(Stream parent, String path) { this.parent = parent; this.path = path; }
+ public Cab(Stream parent) { this(parent, null); }
+ public Cab(Stream parent, String path) { this.parent = parent; this.path = path; }
public String getCacheKey() throws NotCacheableException { return parent.getCacheKey() + "!cab:"; }
public Object _get(Object key) { return new Cab(parent, path==null?(String)key:path+'/'+(String)key); }
public InputStream getInputStream() throws IOException { return new MSPack(parent.getInputStream()).getInputStream(path); }
public static class ProgressWatcher extends Stream {
final Stream watchee;
JS callback;
- ProgressWatcher(Stream watchee, JS callback) { this.watchee = watchee; this.callback = callback; }
+ public ProgressWatcher(Stream watchee, JS callback) { this.watchee = watchee; this.callback = callback; }
public String getCacheKey() throws NotCacheableException { return watchee.getCacheKey(); }
public InputStream getInputStream() throws IOException {
final InputStream is = watchee.getInputStream();
public int read(byte[] b, int off, int len) throws IOException {
int ret = super.read(b, off, len);
if (ret != 1) bytesDownloaded += ret;
- Scheduler.add(new Scheduler.Task() { public void perform() throws IOException, JSExn {
+ Scheduler.add(new Task() { public void perform() throws IOException, JSExn {
callback.call(N(bytesDownloaded),
N(is instanceof KnownLength ? ((KnownLength)is).getLength() : 0), null, null, 2);
} });
if (!disk) {
cis = new CachedInputStream(parent.getInputStream());
} else {
- java.io.File f = LocalStorage.Cache.getCacheFileForKey(key);
+ java.io.File f = org.ibex.core.LocalStorage.Cache.getCacheFileForKey(key);
if (f.exists()) return new FileInputStream(f);
cis = new CachedInputStream(parent.getInputStream(), f);
}
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.net;
import java.net.*;
import java.io.*;
import java.util.*;
import org.ibex.js.*;
import org.ibex.util.*;
-import org.bouncycastle.util.encoders.Base64;
-import org.bouncycastle.crypto.digests.*;
+import org.ibex.plat.*;
+import org.ibex.core.*;
+import org.ibex.crypto.*;
/**
* This object encapsulates a *single* HTTP connection. Multiple requests may be pipelined over a connection (thread-safe),
private String H(String s) throws IOException {
byte[] b = s.getBytes("UTF8");
- MD5Digest md5 = new MD5Digest();
+ MD5 md5 = new MD5();
md5.update(b, 0, b.length);
byte[] out = new byte[md5.getDigestSize()];
md5.doFinal(out, 0);
if (authorization != oldAuth) return;
if (Log.on) Log.info(Authorization.class, "displaying proxy authorization dialog");
- Scheduler.add(new Scheduler.Task() {
+ Scheduler.add(new Task() {
public void perform() throws IOException, JSExn {
Box b = new Box();
Template t = null;
public static byte[] getNTLM2SessionResponse(String password,
byte[] challenge, byte[] clientChallenge) throws UnsupportedEncodingException {
byte[] ntlmHash = ntlmHash(password);
- MD5Digest md5 = new MD5Digest();
+ MD5 md5 = new MD5();
md5.update(challenge, 0, challenge.length);
md5.update(clientChallenge, 0, clientChallenge.length);
byte[] sessionHash = new byte[8];
* of the NTLM Response and the NTLMv2 and LMv2 Hashes.
*/
private static byte[] ntlmHash(String password) throws UnsupportedEncodingException {
+ // FIXME
+ /*
byte[] unicodePassword = password.getBytes("UnicodeLittleUnmarked");
- MD4Digest md4 = new MD4Digest();
+ MD4 md4 = new MD4();
md4.update(unicodePassword, 0, unicodePassword.length);
byte[] ret = new byte[md4.getDigestSize()];
return ret;
+ */
+ return null;
}
/**
byte[] content = new byte[data.length + 64];
System.arraycopy(ipad, 0, content, 0, 64);
System.arraycopy(data, 0, content, 64, data.length);
- MD5Digest md5 = new MD5Digest();
+ MD5 md5 = new MD5();
md5.update(content, 0, content.length);
data = new byte[md5.getDigestSize()];
md5.doFinal(data, 0);
content = new byte[data.length + 64];
System.arraycopy(opad, 0, content, 0, 64);
System.arraycopy(data, 0, content, 64, data.length);
- md5 = new MD5Digest();
+ md5 = new MD5();
md5.update(content, 0, content.length);
byte[] ret = new byte[md5.getDigestSize()];
md5.doFinal(ret, 0);
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.net;
import java.io.*;
import java.util.*;
import org.ibex.js.*;
import org.ibex.util.*;
-import org.bouncycastle.util.encoders.Base64;
+import org.ibex.crypto.*;
/**
* A partial RPC-style SOAP 1.1 client. Implemented from the SOAP 1.1
* <li> WSDL support
* </ul>
*/
-class SOAP extends XMLRPC {
+public class SOAP extends XMLRPC {
/** the desired content of the SOAPAction header */
String action = null;
return content.toString();
}
- SOAP(String url, String methodname, String action, String nameSpace) {
+ public SOAP(String url, String methodname, String action, String nameSpace) {
super(url, methodname);
this.action = action;
this.nameSpace = nameSpace;
}
- SOAP(String url, String methodname, SOAP httpSource, String action, String nameSpace) {
+ public SOAP(String url, String methodname, SOAP httpSource, String action, String nameSpace) {
super(url, methodname, httpSource);
this.action = action;
this.nameSpace = nameSpace;
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.net;
import java.io.*;
import java.util.*;
import org.ibex.js.*;
import org.ibex.util.*;
-import org.bouncycastle.util.encoders.Base64;
+import org.ibex.crypto.*;
/**
* An XML-RPC client implemented as a JavaScript Host Object. See the
* convert.
* </ol>
*/
-class XMLRPC extends JS {
+public class XMLRPC extends JS {
public XMLRPC(String url, String method) {
this.http = url.startsWith("stdio:") ? HTTP.stdio : new HTTP(url);
try {
new Helper().parse(br);
final Object result = fault ? new JSExn(objects.elementAt(0)) : objects.size() == 0 ? null : objects.elementAt(0);
- Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn { callback.unpause(result); }});
+ Scheduler.add(new Task() { public void perform() throws JSExn { callback.unpause(result); }});
} finally {
tracker.clear();
objects.setSize(0);
}
} catch (final JSExn e) {
final Exception e2 = e;
- Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn { callback.unpause(e2); }});
+ Scheduler.add(new Task() { public void perform() throws JSExn { callback.unpause(e2); }});
} catch (final IOException e) {
final Exception e2 = e;
- Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2)); }});
+ Scheduler.add(new Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2)); }});
} catch (final XML.Exn e) {
final Exception e2 = e;
- Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2)); }});
+ Scheduler.add(new Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2)); }});
}
}
}
import java.awt.datatransfer.*;
import java.awt.image.*;
import java.awt.event.*;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
/** Platform subclass for all VM's providing AWT 1.1 functionality */
public class AWT extends JVM {
// Inner Classes /////////////////////////////////////////////////////////////////////////////////////
- protected org.ibex.Font.Glyph _createGlyph(org.ibex.Font f, char c) { return new AWTGlyph(f, c); }
- protected static class AWTGlyph extends org.ibex.Font.Glyph {
+ protected org.ibex.graphics.Font.Glyph _createGlyph(org.ibex.graphics.Font f, char c) { return new AWTGlyph(f, c); }
+ protected static class AWTGlyph extends org.ibex.graphics.Font.Glyph {
private Image i = null;
private static ColorModel cmodel = new DirectColorModel(32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
};
*/
- public AWTGlyph(org.ibex.Font f, char c) { super(f, c); }
+ public AWTGlyph(org.ibex.graphics.Font f, char c) { super(f, c); }
Image getImage() {
if (i == null && isLoaded) {
}
/** implemented with java.awt 1.1's setXORMode() */
- public void drawGlyph(org.ibex.Font.Glyph source, int dx, int dy, int cx1, int cy1, int cx2, int cy2, int rgb) {
+ public void drawGlyph(org.ibex.graphics.Font.Glyph source, int dx, int dy, int cx1, int cy1, int cx2, int cy2, int rgb) {
// XOR the target region
- g.setXORMode(new Color((rgb & 0x00ff0000) >> 16, (rgb & 0x0000ff00) >> 8, rgb & 0x000000ff));
- g.setColor(new Color(0x0, 0x0, 0x0));
+ g.setXORMode(new java.awt.Color((rgb & 0x00ff0000) >> 16, (rgb & 0x0000ff00) >> 8, rgb & 0x000000ff));
+ g.setColor(new java.awt.Color(0x0, 0x0, 0x0));
g.fillRect(cx1, cy1, cx2 - cx1, cy2 - cy1);
// blacken the area we want the glyph to cover
g.setClip(0, 0, i.getWidth(null), i.getHeight(null));
// XOR back, turning black into the chosen rgb color
- g.setXORMode(new Color((rgb & 0x00ff0000) >> 16, (rgb & 0x0000ff00) >> 8, rgb & 0x000000ff));
- g.setColor(new Color(0x0, 0x0, 0x0));
+ g.setXORMode(new java.awt.Color((rgb & 0x00ff0000) >> 16, (rgb & 0x0000ff00) >> 8, rgb & 0x000000ff));
+ g.setColor(new java.awt.Color(0x0, 0x0, 0x0));
g.fillRect(cx1, cy1, cx2 - cx1, cy2 - cy1);
// restore the graphics context
// FIXME: try to use os acceleration
public void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int argb) {
- g.setColor(new Color((argb & 0x00FF0000) >> 16, (argb & 0x0000FF00) >> 8, (argb & 0x000000FF)));
+ g.setColor(new java.awt.Color((argb & 0x00FF0000) >> 16, (argb & 0x0000FF00) >> 8, (argb & 0x000000FF)));
if (x1 == x3 && x2 == x4) {
g.fillRect(x1, y1, x4 - x1, y2 - y1);
} else for(int y=y1; y<y2; y++) {
if (oldfill != root.fillcolor) {
oldfill = root.fillcolor;
window.setBackground((root.fillcolor & 0xFF000000) == 0 ?
- Color.white :
- new Color((root.fillcolor >> 16) & 0xff,
+ java.awt.Color.white :
+ new java.awt.Color((root.fillcolor >> 16) & 0xff,
(root.fillcolor >> 8) & 0xff,
(root.fillcolor) & 0xff));
}
import org.ibex.util.*;
import org.ibex.js.*;
import org.ibex.*;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
public class Darwin extends POSIX {
private static final Class openGLClass = OpenGL.class;
import java.io.*;
import java.security.*;
import java.security.cert.*;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
/** common superclass for all platforms that use GCJ to compile a native binary */
public abstract class GCJ extends Platform {
package org.ibex.plat;
import org.ibex.*;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
/** common superclass for all platforms that run in a "real" JVM */
public abstract class JVM extends Platform {
import org.ibex.util.*;
import org.ibex.*;
import java.lang.reflect.*;
-
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
/** Platform class for most reasonable Java1.2+ Java2s */
public class Java2 extends AWT {
}
/** this is done with reflection in case a new version of the plugin comes out that doesn't let us pull the sun.plugin.* trick */
- protected synchronized org.ibex.HTTP.Proxy _detectProxy() {
- return (org.ibex.HTTP.Proxy)java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {
+ protected synchronized org.ibex.net.HTTP.Proxy _detectProxy() {
+ return (org.ibex.net.HTTP.Proxy)java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {
public Object run() {
try {
- org.ibex.HTTP.Proxy pi = new org.ibex.HTTP.Proxy();
+ org.ibex.net.HTTP.Proxy pi = new org.ibex.net.HTTP.Proxy();
Class PluginProxyHandler = Class.forName("sun.plugin.protocol.PluginProxyHandler");
Method getDefaultProxyHandler = PluginProxyHandler.getMethod("getDefaultProxyHandler", new Class[] { });
private DataBuffer buf = null;
// this doens't seem to work on Windows
- public void drawGlyph(org.ibex.Font.Glyph source, int dx, int dy, int cx1, int cy1, int cx2, int cy2, int rgb) {
+ public void drawGlyph(org.ibex.graphics.Font.Glyph source, int dx, int dy, int cx1, int cy1, int cx2, int cy2, int rgb) {
Image i2 = ((AWTGlyph)source).getImage();
Graphics2D g2 = (Graphics2D)i.getGraphics();
g2.setComposite(AlphaComposite.DstOut);
g2.setClip(cx1, cy1, cx2 - cx1, cy2 - cy1);
g2.drawImage(i2, dx, dy, null);
g2.setComposite(AlphaComposite.DstOver);
- g2.setColor(new Color((rgb & 0x00FF0000) >> 16, (rgb & 0x0000FF00) >> 8, (rgb & 0x000000FF)));
+ g2.setColor(new java.awt.Color((rgb & 0x00FF0000) >> 16, (rgb & 0x0000FF00) >> 8, (rgb & 0x000000FF)));
g2.fillRect(dx, dy, cx2 - dx, cy2 - dy);
g2.drawImage(i2, 0, 0, null);
g2.setClip(0, 0, i.getWidth(null), i.getHeight(null));
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
package org.ibex.plat;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
+
/** Linux with an X11 display */
public class Linux extends X11 {
import org.ibex.*;
import org.ibex.js.*;
import org.ibex.util.*;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
abstract class OpenGL {
static final boolean pretendToBeACrappyVideoCard = false;
public void deleteTexture(final int tex) {
// CHECKME: Is this safe to do from finalize()?
// natDeleteTexture MUST be run from the message queue thread
- Scheduler.add(new Scheduler.Task() { public void perform() { natDeleteTexture(tex); }});
+ Scheduler.add(new Task() { public void perform() { natDeleteTexture(tex); }});
}
private static abstract class GLPicture {
package org.ibex.plat;
import java.util.*;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
/** Platform implementation for POSIX compliant operating systems */
public class POSIX extends GCJ {
package org.ibex.plat;
import org.ibex.*;
import java.io.*;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
/** Platform class for PalmOS devices */
public class PalmOS extends Platform {
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.plat;
import java.lang.reflect.*;
import java.net.*;
import java.io.*;
import org.ibex.js.*;
import org.ibex.util.*;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
/**
* Abstracts away the small irregularities in JVM implementations.
// Static Data /////////////////////////////////////////////////////////////////////////////////////
- static boolean clipboardReadEnabled = false; ///< true iff inside a C-v/A-v/Press3 trap handler
- static Platform platform = null; ///< The appropriate Platform object for this JVM
- static boolean alreadyDetectedProxy = false; ///< true if proxy autodetection has already been run
- static org.ibex.HTTP.Proxy cachedProxyInfo = null; ///< the result of proxy autodetection
+ public static boolean clipboardReadEnabled = false; ///< true iff inside a C-v/A-v/Press3 trap handler
+ public static Platform platform = null; ///< The appropriate Platform object for this JVM
+ public static boolean alreadyDetectedProxy = false; ///< true if proxy autodetection has already been run
+ public static org.ibex.net.HTTP.Proxy cachedProxyInfo = null; ///< the result of proxy autodetection
public static String build = "unknown"; ///< the current build
// VM Detection Logic /////////////////////////////////////////////////////////////////////
protected Surface _createSurface(Box b, boolean framed) { return null; }
protected Picture _createPicture(JS r) { return null; }
protected PixelBuffer _createPixelBuffer(int w, int h, Surface owner) { return null; }
- protected Font.Glyph _createGlyph(org.ibex.Font f, char c) { return new DefaultGlyph(f, c); }
+ protected Font.Glyph _createGlyph(org.ibex.graphics.Font f, char c) { return new DefaultGlyph(f, c); }
public static PixelBuffer createPixelBuffer(int w, int h, Surface s) { return platform._createPixelBuffer(w, h, s); }
public static Picture createPicture(JS r) { return platform._createPicture(r); }
- public static Font.Glyph createGlyph(org.ibex.Font f, char c) { return platform._createGlyph(f, c); }
+ public static Font.Glyph createGlyph(org.ibex.graphics.Font f, char c) { return platform._createGlyph(f, c); }
public static Surface createSurface(Box b, boolean framed, boolean refreshable) {
Surface ret = platform._createSurface(b, framed);
ret.setInvisible(false);
}
/** detects proxy settings */
- protected synchronized org.ibex.HTTP.Proxy _detectProxy() { return null; }
- public static synchronized org.ibex.HTTP.Proxy detectProxy() {
+ protected synchronized org.ibex.net.HTTP.Proxy _detectProxy() { return null; }
+ public static synchronized org.ibex.net.HTTP.Proxy detectProxy() {
if (cachedProxyInfo != null) return cachedProxyInfo;
if (alreadyDetectedProxy) return null;
alreadyDetectedProxy = true;
Log.info(Platform.class, "attempting environment-variable DNS proxy detection");
- cachedProxyInfo = org.ibex.HTTP.Proxy.detectProxyViaManual();
+ cachedProxyInfo = org.ibex.net.HTTP.Proxy.detectProxyViaManual();
if (cachedProxyInfo != null) return cachedProxyInfo;
Log.info(Platform.class, "attempting " + platform.getClass().getName() + " proxy detection");
// FEATURE: be more efficient for many of the subclasses
public static class DefaultGlyph extends Font.Glyph {
private Picture p = null;
- public DefaultGlyph(org.ibex.Font f, char c) { super(f, c); }
+ public DefaultGlyph(org.ibex.graphics.Font f, char c) { super(f, c); }
public Picture getPicture() {
if (p == null && isLoaded) {
Picture p = createPicture(null);
import org.ibex.util.*;
import java.util.*;
import org.ibex.js.*;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
/** Platform specific code for GCJ-compiled Win32 binaries */
public class Win32 extends GCJ {
import java.util.*;
import org.ibex.js.*;
import org.ibex.util.*;
+import org.ibex.graphics.*;
+import org.ibex.core.*;
+import org.ibex.net.*;
import org.ibex.*;
/** Platform implementation for POSIX compliant operating systems with an X11 Server */
/** the number of elements in the tree */
public final int treeSize() { return root == 0 ? 0 : size[root]; }
-
+
/** clamps index to [0..treeSize()] and inserts object o *before* the specified index */
public final synchronized void insertNode(int index, Object o) {
if(o == null) throw new Error("can't insert nulls in the balanced tree");
// collisions when a single Object is inserted into multiple
// trees
int dest = Math.abs(o.hashCode() ^ this.hashCode()) % objects.length;
- if (dest == 0) dest = 1;
Object search = alloc ? null : o;
int odest = dest;
boolean plus = true;
int tries = 1;
while (objects[dest] != search || !(alloc || root(dest) == root)) {
+ if (dest == 0) dest++;
dest = Math.abs((odest + (plus ? 1 : -1) * tries * tries) % objects.length);
- if (dest == 0) dest=1;
if (plus) tries++;
plus = !plus;
// FEATURE: GROW - if(tries > MAX_SLOT_DISTANCE) return -1;
int c = left[d];
if (d <= 0) throw new Error("rotation error");
left[d] = b;
- right[b] = c <= 0 ? -d : c;
+ if(size[b] <= 3) // b is now a leaf
+ right[b] = -d;
+ else
+ right[b] = c;
parent[b] = d;
parent[d] = p;
if(c > 0) parent[c] = b;
-
if (p == 0) root = d;
else if (left[p] == b) left[p] = d;
else if (right[p] == b) right[p] = d;
// we found the node to delete
} else {
+
// fast path: it has no children
if (left[slot] <= 0 && right[slot] <= 0) {
if (p == 0) root = 0;
int[] side = left[p] == slot ? left : right;
side[p] = side[slot]; // fix parent's pointer
}
+
// fast path: it has no left child, so we replace it with its right child
} else if (left[slot] <= 0) {
if (p == 0) root = right[slot];
--- /dev/null
+package org.ibex.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * BrowserLauncher is a class that provides one static method, openURL, which opens the default
+ * web browser for the current user of the system to the given URL. It may support other
+ * protocols depending on the system -- mailto, ftp, etc. -- but that has not been rigorously
+ * tested and is not guaranteed to work.
+ * <p>
+ * Yes, this is platform-specific code, and yes, it may rely on classes on certain platforms
+ * that are not part of the standard JDK. What we're trying to do, though, is to take something
+ * that's frequently desirable but inherently platform-specific -- opening a default browser --
+ * and allow programmers (you, for example) to do so without worrying about dropping into native
+ * code or doing anything else similarly evil.
+ * <p>
+ * Anyway, this code is completely in Java and will run on all JDK 1.1-compliant systems without
+ * modification or a need for additional libraries. All classes that are required on certain
+ * platforms to allow this to run are dynamically loaded at runtime via reflection and, if not
+ * found, will not cause this to do anything other than returning an error when opening the
+ * browser.
+ * <p>
+ * There are certain system requirements for this class, as it's running through Runtime.exec(),
+ * which is Java's way of making a native system call. Currently, this requires that a Macintosh
+ * have a Finder which supports the GURL event, which is true for Mac OS 8.0 and 8.1 systems that
+ * have the Internet Scripting AppleScript dictionary installed in the Scripting Additions folder
+ * in the Extensions folder (which is installed by default as far as I know under Mac OS 8.0 and
+ * 8.1), and for all Mac OS 8.5 and later systems. On Windows, it only runs under Win32 systems
+ * (Windows 95, 98, and NT 4.0, as well as later versions of all). On other systems, this drops
+ * back from the inherently platform-sensitive concept of a default browser and simply attempts
+ * to launch Netscape via a shell command.
+ * <p>
+ * This code is Copyright 1999-2001 by Eric Albert (ejalbert@cs.stanford.edu) and may be
+ * redistributed or modified in any form without restrictions as long as the portion of this
+ * comment from this paragraph through the end of the comment is not removed. The author
+ * requests that he be notified of any application, applet, or other binary that makes use of
+ * this code, but that's more out of curiosity than anything and is not required. This software
+ * includes no warranty. The author is not repsonsible for any loss of data or functionality
+ * or any adverse or unexpected effects of using this software.
+ * <p>
+ * Credits:
+ * <br>Steven Spencer, JavaWorld magazine (<a href="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java Tip 66</a>)
+ * <br>Thanks also to Ron B. Yeh, Eric Shapiro, Ben Engber, Paul Teitlebaum, Andrea Cantatore,
+ * Larry Barowski, Trevor Bedzek, Frank Miedrich, and Ron Rabakukk
+ *
+ * @author Eric Albert (<a href="mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu</a>)
+ * @version 1.4b1 (Released June 20, 2001)
+ */
+public class EjAlbertBrowserLauncher {
+
+ /**
+ * The Java virtual machine that we are running on. Actually, in most cases we only care
+ * about the operating system, but some operating systems require us to switch on the VM. */
+ private static int jvm;
+
+ /** The browser for the system */
+ private static Object browser;
+
+ /**
+ * Caches whether any classes, methods, and fields that are not part of the JDK and need to
+ * be dynamically loaded at runtime loaded successfully.
+ * <p>
+ * Note that if this is <code>false</code>, <code>openURL()</code> will always return an
+ * IOException.
+ */
+ private static boolean loadedWithoutErrors;
+
+ /** The com.apple.mrj.MRJFileUtils class */
+ private static Class mrjFileUtilsClass;
+
+ /** The com.apple.mrj.MRJOSType class */
+ private static Class mrjOSTypeClass;
+
+ /** The com.apple.MacOS.AEDesc class */
+ private static Class aeDescClass;
+
+ /** The <init>(int) method of com.apple.MacOS.AETarget */
+ private static Constructor aeTargetConstructor;
+
+ /** The <init>(int, int, int) method of com.apple.MacOS.AppleEvent */
+ private static Constructor appleEventConstructor;
+
+ /** The <init>(String) method of com.apple.MacOS.AEDesc */
+ private static Constructor aeDescConstructor;
+
+ /** The findFolder method of com.apple.mrj.MRJFileUtils */
+ private static Method findFolder;
+
+ /** The getFileCreator method of com.apple.mrj.MRJFileUtils */
+ private static Method getFileCreator;
+
+ /** The getFileType method of com.apple.mrj.MRJFileUtils */
+ private static Method getFileType;
+
+ /** The openURL method of com.apple.mrj.MRJFileUtils */
+ private static Method openURL;
+
+ /** The makeOSType method of com.apple.MacOS.OSUtils */
+ private static Method makeOSType;
+
+ /** The putParameter method of com.apple.MacOS.AppleEvent */
+ private static Method putParameter;
+
+ /** The sendNoReply method of com.apple.MacOS.AppleEvent */
+ private static Method sendNoReply;
+
+ /** Actually an MRJOSType pointing to the System Folder on a Macintosh */
+ private static Object kSystemFolderType;
+
+ /** The keyDirectObject AppleEvent parameter type */
+ private static Integer keyDirectObject;
+
+ /** The kAutoGenerateReturnID AppleEvent code */
+ private static Integer kAutoGenerateReturnID;
+
+ /** The kAnyTransactionID AppleEvent code */
+ private static Integer kAnyTransactionID;
+
+ /** The linkage object required for JDirect 3 on Mac OS X. */
+ private static Object linkage;
+
+ /** The framework to reference on Mac OS X */
+ private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
+
+ /** JVM constant for MRJ 2.0 */
+ private static final int MRJ_2_0 = 0;
+
+ /** JVM constant for MRJ 2.1 or later */
+ private static final int MRJ_2_1 = 1;
+
+ /** JVM constant for Java on Mac OS X 10.0 (MRJ 3.0) */
+ private static final int MRJ_3_0 = 3;
+
+ /** JVM constant for MRJ 3.1 */
+ private static final int MRJ_3_1 = 4;
+
+ /** JVM constant for any Windows NT JVM */
+ private static final int WINDOWS_NT = 5;
+
+ /** JVM constant for any Windows 9x JVM */
+ private static final int WINDOWS_9x = 6;
+
+ /** JVM constant for any other platform */
+ private static final int OTHER = -1;
+
+ /**
+ * The file type of the Finder on a Macintosh. Hardcoding "Finder" would keep non-U.S. English
+ * systems from working properly.
+ */
+ private static final String FINDER_TYPE = "FNDR";
+
+ /**
+ * The creator code of the Finder on a Macintosh, which is needed to send AppleEvents to the
+ * application.
+ */
+ private static final String FINDER_CREATOR = "MACS";
+
+ /** The name for the AppleEvent type corresponding to a GetURL event. */
+ private static final String GURL_EVENT = "GURL";
+
+ /**
+ * The first parameter that needs to be passed into Runtime.exec() to open the default web
+ * browser on Windows.
+ */
+ private static final String FIRST_WINDOWS_PARAMETER = "/c";
+
+ /** The second parameter for Runtime.exec() on Windows. */
+ private static final String SECOND_WINDOWS_PARAMETER = "start";
+
+ /**
+ * The third parameter for Runtime.exec() on Windows. This is a "title"
+ * parameter that the command line expects. Setting this parameter allows
+ * URLs containing spaces to work.
+ */
+ private static final String THIRD_WINDOWS_PARAMETER = "\"\"";
+
+ /**
+ * The shell parameters for Netscape that opens a given URL in an already-open copy of Netscape
+ * on many command-line systems.
+ */
+ private static final String NETSCAPE_REMOTE_PARAMETER = "-remote";
+ private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
+ private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
+
+ /**
+ * The message from any exception thrown throughout the initialization process.
+ */
+ private static String errorMessage;
+
+ /**
+ * An initialization block that determines the operating system and loads the necessary
+ * runtime data.
+ */
+ static {
+ loadedWithoutErrors = true;
+ String osName = System.getProperty("os.name");
+ if (osName.startsWith("Mac OS")) {
+ String mrjVersion = System.getProperty("mrj.version");
+ String majorMRJVersion = mrjVersion.substring(0, 3);
+ try {
+ double version = Double.valueOf(majorMRJVersion).doubleValue();
+ if (version == 2) {
+ jvm = MRJ_2_0;
+ } else if (version >= 2.1 && version < 3) {
+ // Assume that all 2.x versions of MRJ work the same. MRJ 2.1 actually
+ // works via Runtime.exec() and 2.2 supports that but has an openURL() method
+ // as well that we currently ignore.
+ jvm = MRJ_2_1;
+ } else if (version == 3.0) {
+ jvm = MRJ_3_0;
+ } else if (version >= 3.1) {
+ // Assume that all 3.1 and later versions of MRJ work the same.
+ jvm = MRJ_3_1;
+ } else {
+ loadedWithoutErrors = false;
+ errorMessage = "Unsupported MRJ version: " + version;
+ }
+ } catch (NumberFormatException nfe) {
+ loadedWithoutErrors = false;
+ errorMessage = "Invalid MRJ version: " + mrjVersion;
+ }
+ } else if (osName.startsWith("Windows")) {
+ if (osName.indexOf("9") != -1) {
+ jvm = WINDOWS_9x;
+ } else {
+ jvm = WINDOWS_NT;
+ }
+ } else {
+ jvm = OTHER;
+ }
+
+ if (loadedWithoutErrors) { // if we haven't hit any errors yet
+ loadedWithoutErrors = loadClasses();
+ }
+ }
+
+ /**
+ * This class should be never be instantiated; this just ensures so.
+ */
+ private EjAlbertBrowserLauncher() { }
+
+ /**
+ * Called by a static initializer to load any classes, fields, and methods required at runtime
+ * to locate the user's web browser.
+ * @return <code>true</code> if all intialization succeeded
+ * <code>false</code> if any portion of the initialization failed
+ */
+ private static boolean loadClasses() {
+ switch (jvm) {
+ case MRJ_2_0:
+ try {
+ Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
+ Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
+ Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent");
+ Class aeClass = Class.forName("com.apple.MacOS.ae");
+ aeDescClass = Class.forName("com.apple.MacOS.AEDesc");
+
+ aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class [] { int.class });
+ appleEventConstructor = appleEventClass.getDeclaredConstructor(new Class[] { int.class, int.class, aeTargetClass, int.class, int.class });
+ aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class[] { String.class });
+
+ makeOSType = osUtilsClass.getDeclaredMethod("makeOSType", new Class [] { String.class });
+ putParameter = appleEventClass.getDeclaredMethod("putParameter", new Class[] { int.class, aeDescClass });
+ sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply", new Class[] { });
+
+ Field keyDirectObjectField = aeClass.getDeclaredField("keyDirectObject");
+ keyDirectObject = (Integer) keyDirectObjectField.get(null);
+ Field autoGenerateReturnIDField = appleEventClass.getDeclaredField("kAutoGenerateReturnID");
+ kAutoGenerateReturnID = (Integer) autoGenerateReturnIDField.get(null);
+ Field anyTransactionIDField = appleEventClass.getDeclaredField("kAnyTransactionID");
+ kAnyTransactionID = (Integer) anyTransactionIDField.get(null);
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ } catch (NoSuchFieldException nsfe) {
+ errorMessage = nsfe.getMessage();
+ return false;
+ } catch (IllegalAccessException iae) {
+ errorMessage = iae.getMessage();
+ return false;
+ }
+ break;
+ case MRJ_2_1:
+ try {
+ mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
+ mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType");
+ Field systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType");
+ kSystemFolderType = systemFolderField.get(null);
+ findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class[] { mrjOSTypeClass });
+ getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class[] { File.class });
+ getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class[] { File.class });
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchFieldException nsfe) {
+ errorMessage = nsfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ } catch (SecurityException se) {
+ errorMessage = se.getMessage();
+ return false;
+ } catch (IllegalAccessException iae) {
+ errorMessage = iae.getMessage();
+ return false;
+ }
+ break;
+ case MRJ_3_0:
+ try {
+ Class linker = Class.forName("com.apple.mrj.jdirect.Linker");
+ Constructor constructor = linker.getConstructor(new Class[]{ Class.class });
+ linkage = constructor.newInstance(new Object[] { EjAlbertBrowserLauncher.class });
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ } catch (InvocationTargetException ite) {
+ errorMessage = ite.getMessage();
+ return false;
+ } catch (InstantiationException ie) {
+ errorMessage = ie.getMessage();
+ return false;
+ } catch (IllegalAccessException iae) {
+ errorMessage = iae.getMessage();
+ return false;
+ }
+ break;
+ case MRJ_3_1:
+ try {
+ mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
+ openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class[] { String.class });
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Attempts to locate the default web browser on the local system. Caches results so it
+ * only locates the browser once for each use of this class per JVM instance.
+ * @return The browser for the system. Note that this may not be what you would consider
+ * to be a standard web browser; instead, it's the application that gets called to
+ * open the default web browser. In some cases, this will be a non-String object
+ * that provides the means of calling the default browser.
+ */
+ private static Object locateBrowser() {
+ if (browser != null) {
+ return browser;
+ }
+ switch (jvm) {
+ case MRJ_2_0:
+ try {
+ Integer finderCreatorCode = (Integer) makeOSType.invoke(null, new Object[] { FINDER_CREATOR });
+ Object aeTarget = aeTargetConstructor.newInstance(new Object[] { finderCreatorCode });
+ Integer gurlType = (Integer) makeOSType.invoke(null, new Object[] { GURL_EVENT });
+ Object appleEvent = appleEventConstructor.newInstance(new Object[] { gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID });
+ // Don't set browser = appleEvent because then the next time we call
+ // locateBrowser(), we'll get the same AppleEvent, to which we'll already have
+ // added the relevant parameter. Instead, regenerate the AppleEvent every time.
+ // There's probably a way to do this better; if any has any ideas, please let
+ // me know.
+ return appleEvent;
+ } catch (IllegalAccessException iae) {
+ browser = null;
+ errorMessage = iae.getMessage();
+ return browser;
+ } catch (InstantiationException ie) {
+ browser = null;
+ errorMessage = ie.getMessage();
+ return browser;
+ } catch (InvocationTargetException ite) {
+ browser = null;
+ errorMessage = ite.getMessage();
+ return browser;
+ }
+ case MRJ_2_1:
+ File systemFolder;
+ try {
+ systemFolder = (File) findFolder.invoke(null, new Object[] { kSystemFolderType });
+ } catch (IllegalArgumentException iare) {
+ browser = null;
+ errorMessage = iare.getMessage();
+ return browser;
+ } catch (IllegalAccessException iae) {
+ browser = null;
+ errorMessage = iae.getMessage();
+ return browser;
+ } catch (InvocationTargetException ite) {
+ browser = null;
+ errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
+ return browser;
+ }
+ String[] systemFolderFiles = systemFolder.list();
+ // Avoid a FilenameFilter because that can't be stopped mid-list
+ for(int i = 0; i < systemFolderFiles.length; i++) {
+ try {
+ File file = new File(systemFolder, systemFolderFiles[i]);
+ if (!file.isFile()) {
+ continue;
+ }
+ // We're looking for a file with a creator code of 'MACS' and
+ // a type of 'FNDR'. Only requiring the type results in non-Finder
+ // applications being picked up on certain Mac OS 9 systems,
+ // especially German ones, and sending a GURL event to those
+ // applications results in a logout under Multiple Users.
+ Object fileType = getFileType.invoke(null, new Object[] { file });
+ if (FINDER_TYPE.equals(fileType.toString())) {
+ Object fileCreator = getFileCreator.invoke(null, new Object[] { file });
+ if (FINDER_CREATOR.equals(fileCreator.toString())) {
+ browser = file.toString(); // Actually the Finder, but that's OK
+ return browser;
+ }
+ }
+ } catch (IllegalArgumentException iare) {
+ browser = browser;
+ errorMessage = iare.getMessage();
+ return null;
+ } catch (IllegalAccessException iae) {
+ browser = null;
+ errorMessage = iae.getMessage();
+ return browser;
+ } catch (InvocationTargetException ite) {
+ browser = null;
+ errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
+ return browser;
+ }
+ }
+ browser = null;
+ break;
+ case MRJ_3_0:
+ case MRJ_3_1:
+ browser = ""; // Return something non-null
+ break;
+ case WINDOWS_NT:
+ browser = "cmd.exe";
+ break;
+ case WINDOWS_9x:
+ browser = "command.com";
+ break;
+ case OTHER:
+ default:
+ browser = "netscape";
+ break;
+ }
+ return browser;
+ }
+
+ /**
+ * Attempts to open the default web browser to the given URL.
+ * @param url The URL to open
+ * @throws IOException If the web browser could not be located or does not run
+ */
+ public static void openURL(String url) throws IOException {
+ if (!loadedWithoutErrors) {
+ throw new IOException("Exception in finding browser: " + errorMessage);
+ }
+ Object browser = locateBrowser();
+ if (browser == null) {
+ throw new IOException("Unable to locate browser: " + errorMessage);
+ }
+
+ switch (jvm) {
+ case MRJ_2_0:
+ Object aeDesc = null;
+ try {
+ aeDesc = aeDescConstructor.newInstance(new Object[] { url });
+ putParameter.invoke(browser, new Object[] { keyDirectObject, aeDesc });
+ sendNoReply.invoke(browser, new Object[] { });
+ } catch (InvocationTargetException ite) {
+ throw new IOException("InvocationTargetException while creating AEDesc: " + ite.getMessage());
+ } catch (IllegalAccessException iae) {
+ throw new IOException("IllegalAccessException while building AppleEvent: " + iae.getMessage());
+ } catch (InstantiationException ie) {
+ throw new IOException("InstantiationException while creating AEDesc: " + ie.getMessage());
+ } finally {
+ aeDesc = null; // Encourage it to get disposed if it was created
+ browser = null; // Ditto
+ }
+ break;
+ case MRJ_2_1:
+ Runtime.getRuntime().exec(new String[] { (String) browser, url } );
+ break;
+ case MRJ_3_0:
+ int[] instance = new int[1];
+ int result = ICStart(instance, 0);
+ if (result == 0) {
+ int[] selectionStart = new int[] { 0 };
+ byte[] urlBytes = url.getBytes();
+ int[] selectionEnd = new int[] { urlBytes.length };
+ result = ICLaunchURL(instance[0], new byte[] { 0 }, urlBytes,
+ urlBytes.length, selectionStart,
+ selectionEnd);
+ if (result == 0) {
+ // Ignore the return value; the URL was launched successfully
+ // regardless of what happens here.
+ ICStop(instance);
+ } else {
+ throw new IOException("Unable to launch URL: " + result);
+ }
+ } else {
+ throw new IOException("Unable to create an Internet Config instance: " + result);
+ }
+ break;
+ case MRJ_3_1:
+ try {
+ openURL.invoke(null, new Object[] { url });
+ } catch (InvocationTargetException ite) {
+ throw new IOException("InvocationTargetException while calling openURL: " + ite.getMessage());
+ } catch (IllegalAccessException iae) {
+ throw new IOException("IllegalAccessException while calling openURL: " + iae.getMessage());
+ }
+ break;
+ case WINDOWS_NT:
+ case WINDOWS_9x:
+ // Add quotes around the URL to allow ampersands and other special
+ // characters to work.
+ Process process = Runtime.getRuntime().exec(new String[] { (String) browser,
+ FIRST_WINDOWS_PARAMETER,
+ SECOND_WINDOWS_PARAMETER,
+ THIRD_WINDOWS_PARAMETER,
+ '"' + url + '"' });
+ // This avoids a memory leak on some versions of Java on Windows.
+ // That's hinted at in <http://developer.java.sun.com/developer/qow/archive/68/>.
+ try {
+ process.waitFor();
+ process.exitValue();
+ } catch (InterruptedException ie) {
+ throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
+ }
+ break;
+ case OTHER:
+ // Assume that we're on Unix and that Netscape is installed
+
+ // First, attempt to open the URL in a currently running session of Netscape
+ process = Runtime.getRuntime().exec(new String[] { (String) browser,
+ NETSCAPE_REMOTE_PARAMETER,
+ NETSCAPE_OPEN_PARAMETER_START +
+ url +
+ NETSCAPE_OPEN_PARAMETER_END });
+ try {
+ int exitCode = process.waitFor();
+ if (exitCode != 0) { // if Netscape was not open
+ Runtime.getRuntime().exec(new String[] { (String) browser, url });
+ }
+ } catch (InterruptedException ie) {
+ throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
+ }
+ break;
+ default:
+ // This should never occur, but if it does, we'll try the simplest thing possible
+ Runtime.getRuntime().exec(new String[] { (String) browser, url });
+ break;
+ }
+ }
+
+ /**
+ * Methods required for Mac OS X. The presence of native methods does not cause
+ * any problems on other platforms.
+ */
+ /*
+ private native static int ICStart(int[] instance, int signature);
+ private native static int ICStop(int[] instance);
+ private native static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len,
+ int[] selectionStart, int[] selectionEnd);
+ */
+ private static int ICStart(int[] instance, int signature) { return 0; }
+ private static int ICStop(int[] instance) { return 0; }
+ private static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len,
+ int[] selectionStart, int[] selectionEnd) { return 0; }
+}
-package org.ibex.translators;
+package org.ibex.util;
-import org.ibex.Main;
+import org.ibex.core.Main;
import org.ibex.util.*;
import org.xwt.mips.*;
import java.io.*;
public MSPack(InputStream cabIS) throws IOException {
try {
- Runtime vm = (Runtime)Class.forName("org.ibex.translators.MIPSApps").newInstance();
+ Runtime vm = (Runtime)Class.forName("org.ibex.util.MIPSApps").newInstance();
byte[] cab = InputStreamToByteArray.convert(cabIS);
int cabAddr = vm.sbrk(cab.length);
if(cabAddr < 0) throw new MSPackException("sbrk failed");
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-
-import org.bouncycastle.crypto.AsymmetricBlockCipher;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.params.RSAKeyParameters;
-import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.crypto.params.KeyParameter;
-import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.MD5Digest;
-import org.bouncycastle.crypto.digests.MD2Digest;
-import org.bouncycastle.crypto.engines.RSAEngine;
-import org.bouncycastle.crypto.engines.RC4Engine;
-import org.bouncycastle.util.encoders.Base64;
-import org.bouncycastle.asn1.DERInputStream;
-import org.bouncycastle.asn1.DEROutputStream;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.BERInputStream;
-import org.bouncycastle.asn1.x509.X509CertificateStructure;
-import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.asn1.x509.TBSCertificateStructure;
-import org.bouncycastle.asn1.x509.X509Name;
-import org.bouncycastle.asn1.x509.X509Extensions;
-import org.bouncycastle.asn1.x509.X509Extension;
-import org.bouncycastle.asn1.x509.BasicConstraints;
-import org.ibex.util.Log;
-import java.net.*;
-import java.io.*;
-import java.util.*;
-import java.math.*;
-import java.text.*;
-
-/**
-
- TinySSL: a tiny SSL implementation in Java, built on the
- bouncycastle.org lightweight crypto library.
-
- This class implements an SSLv3 client-side socket, with the
- SSL_RSA_EXPORT_WITH_RC4_40_MD5 and SSL_RSA_WITH_RC4_128_MD5 cipher
- suites, as well as certificate chain verification against a
- collection of 93 built-in Trusted Root CA public keys (the same 93
- included with Microsoft Internet Explorer 5.5 SP2).
-
- As of 07-Dec-01, the zipped bytecode for this class is 43k, and the
- subset of bouncycastle it requires is 82k.
-
- This class should work correctly on any Java 1.1 compliant
- platform. The java.security.* classes are not used.
-
- The main design goal for this class was the smallest possible body
- of code capable of connecting to 99% of all active HTTPS
- servers. Although this class is useful in many other situations
- (IMAPS, Secure SMTP, etc), the author will refuse all feature
- requests and submitted patches which go beyond this scope.
-
- Because of the limited goals of this class, certain abstractions
- have been avoided, and certain parameters have been
- hard-coded. "Magic numbers" are often used instead of "static final
- int"'s, although they are usually accompanied by a descriptive
- comment. Numeric offsets into byte arrays are also favored over
- DataInputStream(ByteArrayInputStream(foo))'s.
-
- Much thanks and credit go to the BouncyCastle team for producing
- such a first-class library, and for helping me out on the
- dev-crypto mailing list while I was writing this.
-
- Revision History:
-
- 1.0 07-Dec-01 Initial Release
-
- 1.01 15-Mar-02 Added PKCS1 class to avoid dependancy on java.security.SecureRandom
-
- 1.02 27-Mar-02 Fixed a bug which would hang the connection when more than one
- Handshake message appeared in the same TLS Record
-
- 1.03 10-Aug-02 Fixed a vulnerability outlined at
- http://online.securityfocus.com/archive/1/286290
-
- 1.04 12-Dec-03 Renamed to org.ibex.SSL, fixed race condition
-
-*/
-
-public class SSL extends Socket {
-
- // Simple Test //////////////////////////////////////////////
-
- public static void main(String[] args) {
- Log.on = true;
- try {
- Socket s = new SSL("www.paypal.com", 443);
- PrintWriter pw = new PrintWriter(s.getOutputStream());
- BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
- pw.println("GET / HTTP/1.0");
- pw.println("");
- pw.flush();
-
- while(true) {
- String s2 = br.readLine();
- if (s2 == null) return;
- Log.info(SSL.class, s2);
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- // Static Data //////////////////////////////////////////////
-
- public static class SSLException extends IOException { public SSLException(String s) { super(s); } }
- static SubjectPublicKeyInfo[] trusted_CA_public_keys;
- static String[] trusted_CA_public_key_identifiers;
- public static byte[] pad1 = new byte[48];
- public static byte[] pad2 = new byte[48];
- public static byte[] pad1_sha = new byte[40];
- public static byte[] pad2_sha = new byte[40];
- static byte[] randpool;
- static long randcnt = 0;
-
- // Cipher State //////////////////////////////////////////////
-
- public byte[] server_random = new byte[32];
- public byte[] client_random = new byte[32];
- public byte[] client_write_MAC_secret = new byte[16];
- public byte[] server_write_MAC_secret = new byte[16];
- public byte[] client_write_key = null;
- public byte[] server_write_key = null;
- public byte[] master_secret = null;
-
- /** the bytes of the ServerKeyExchangeMessage, null if none recieved */
- public byte[] serverKeyExchange = null;
-
- /** true iff the server asked for a certificate */
- public boolean cert_requested = false;
-
- public X509CertificateStructure server_cert = null;
-
- public SSLOutputStream os = null;
- public SSLInputStream is = null;
-
- String hostname;
-
- /** if true, we don't mind if the server's cert isn't signed by a CA. USE WITH CAUTION! */
- boolean ignoreUntrustedCert = false;
-
- /** the concatenation of all the bytes of all handshake messages sent or recieved */
- public byte[] handshakes = new byte[] { };
-
- /** true iff we're using SSL_RSA_EXPORT_WITH_RC4_40_MD5 */
- boolean export = false;
-
- public InputStream getInputStream() throws IOException { return is != null ? is : super.getInputStream(); }
- public OutputStream getOutputStream() throws IOException { return os != null ? os : super.getOutputStream(); }
-
- public SSL(String host, int port) throws IOException { this(host, port, true, false); }
- public SSL(String host, int port, boolean negotiateImmediately) throws IOException { this(host, port, negotiateImmediately, false); }
- public SSL(String host, int port, boolean negotiateImmediately, boolean ignoreUntrustedCert) throws IOException {
- super(host, port);
- if (!initializationFinished) {
- synchronized(SSL.class) {
- while (!initializationFinished)
- try { SSL.class.wait(); } catch (Exception e) { }
- }
- }
- hostname = host;
- this.ignoreUntrustedCert = ignoreUntrustedCert;
- if (negotiateImmediately) negotiate();
- }
-
- /** negotiates the SSL connection */
- public void negotiate() throws IOException {
- os = new SSLOutputStream(super.getOutputStream());
- is = new SSLInputStream(super.getInputStream());
- os.writeClientHello();
- is.readServerHandshakes();
- os.sendClientHandshakes();
- is.readServerFinished();
- }
-
- class SSLInputStream extends InputStream {
-
- /** the underlying inputstream */
- DataInputStream raw;
-
- /** the server's sequence number */
- public int seq_num = 0;
-
- /** the decryption engine */
- public RC4Engine rc4 = null;
-
- /** pending bytes -- decrypted, but not yet fed to consumer */
- byte[] pend = null;
- int pendstart = 0;
- int pendlen = 0;
-
- public void mark() { }
- public void reset() { }
- public boolean markSupported() { return false; }
- public long skip(long l) throws IOException { for(long i=0; i<l; i++) read(); return l; }
- public SSLInputStream(InputStream raw) { this.raw = new DataInputStream(raw); }
- public int available() throws IOException { return pendlen; }
-
- public int read() throws IOException {
- byte[] singlebyte = new byte[1];
- int numread = read(singlebyte);
- if (numread != 1) return -1;
- return (int)singlebyte[0];
- }
-
- public int read(byte[] b, int off, int len) throws IOException {
- if (pendlen == 0) {
- pend = readRecord();
- if (pend == null) return -1;
- pendstart = 0;
- pendlen = pend.length;
- }
- int ret = Math.min(len, pendlen);
- System.arraycopy(pend, pendstart, b, off, ret);
- pendlen -= ret;
- pendstart += ret;
- return ret;
- }
-
- /** reads and decrypts exactly one record; blocks if unavailable */
- public byte[] readRecord() throws IOException {
-
- // we only catch EOFException here, because anywhere else
- // would be "unusual", and we *want* and EOFException in
- // those cases
- byte type;
- try { type = raw.readByte();
- } catch (EOFException e) {
- if (Log.on) Log.info(this, "got EOFException reading packet type");
- return null;
- }
-
- byte ver_major = raw.readByte();
- byte ver_minor = raw.readByte();
- short len = raw.readShort();
- if (Log.on) Log.info(this, "got record of type " + type + ", SSLv" + ver_major + "." + ver_minor + ", length=" + len);
-
- byte[] ret = new byte[len];
- raw.readFully(ret);
-
- // simply ignore ChangeCipherSpec messages -- we change as soon as we send ours
- if (type == 20) {
- if (Log.on) Log.info(this, "got ChangeCipherSpec; ignoring");
- seq_num = 0;
- return readRecord();
- }
-
- byte[] decrypted_payload;
-
- // if crypto hasn't been enabled yet; skip crypt and hash
- if (rc4 == null) decrypted_payload = ret;
- else {
- // decrypt the payload
- decrypted_payload = new byte[len - 16];
- rc4.processBytes(ret, 0, len - 16, decrypted_payload, 0);
-
- // check the MAC
- byte[] MAC = new byte[16];
- rc4.processBytes(ret, len - 16, 16, MAC, 0);
- byte[] ourMAC = computeMAC(type, decrypted_payload, 0, decrypted_payload.length, server_write_MAC_secret, seq_num++);
- for(int i=0; i<MAC.length; i++)
- if (MAC[i] != ourMAC[i])
- throw new SSLException("MAC mismatch on byte " + i + ": got " + MAC[i] + ", expecting " + ourMAC[i]);
- }
-
- if (type == 21) {
- if (decrypted_payload[1] > 1) {
- throw new SSLException("got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
- } else if (decrypted_payload[1] == 0) {
- if (Log.on) Log.info(this, "server requested connection closure; returning null");
- return null;
- } else {
- if (Log.on) Log.info(this, "got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
- return readRecord();
- }
-
- } else if (type == 22) {
- if (Log.on) Log.info(this, "read a handshake");
-
- } else if (type != 23) {
- if (Log.on) Log.info(this, "unexpected record type: " + type + "; skipping");
- return readRecord();
-
- }
-
- if (Log.on) Log.info(this, " returning " + decrypted_payload.length + " byte record payload");
- return decrypted_payload;
- }
-
- private byte[] readHandshake() throws IOException {
- // acquire a handshake message
- byte type = (byte)read();
- int len = ((read() & 0xff) << 16) | ((read() & 0xff) << 8) | (read() & 0xff);
- byte[] rec = new byte[len + 4];
- rec[0] = type;
- rec[1] = (byte)(((len & 0x00ff0000) >> 16) & 0xff);
- rec[2] = (byte)(((len & 0x0000ff00) >> 8) & 0xff);
- rec[3] = (byte)((len & 0x000000ff) & 0xff);
- if (len > 0) read(rec, 4, len);
- return rec;
- }
-
- /** This reads the ServerHello, Certificate, and ServerHelloDone handshake messages */
- public void readServerHandshakes() throws IOException {
- for(;;) {
-
- byte[] rec = readHandshake();
- handshakes = concat(new byte[][] { handshakes, rec });
-
- switch(rec[0]) {
- case 2: // ServerHello
- if (Log.on) Log.info(this, "got ServerHello");
- byte ver_major = rec[4];
- byte ver_minor = rec[5];
- System.arraycopy(rec, 6, server_random, 0, server_random.length);
- short cipher_high = rec[6 + server_random.length + rec[6 + server_random.length] + 1];
- short cipher_low = rec[6 + server_random.length + rec[6 + server_random.length] + 2];
-
- if (cipher_low == 0x04 || cipher_high != 0x00) {
- export = false;
- if (Log.on) Log.info(this, "using SSL_RSA_WITH_RC4_128_MD5");
-
- } else if (cipher_low == 0x03 || cipher_high != 0x00) {
- export = true;
- if (Log.on) Log.info(this, "using SSL_RSA_EXPORT_WITH_RC4_40_MD5");
-
- } else throw new SSLException("server asked for cipher " + ((cipher_high << 8) | cipher_low) +
- " but we only do SSL_RSA_WITH_RC4_128_MD5 (0x0004) and " +
- "SSL_RSA_EXPORT_WITH_RC4_40_MD5 (0x0003)");
-
- byte compressionMethod = rec[6 + server_random.length + rec[6 + server_random.length] + 3];
- if (compressionMethod != 0x0) throw new SSLException("server asked for compression method " + compressionMethod +
- " but we don't support compression");
- break;
-
- case 11: // Server's certificate(s)
- if (Log.on) Log.info(this, "got Server Certificate(s)");
- int numcertbytes = ((rec[4] & 0xff) << 16) | ((rec[5] & 0xff) << 8) | (rec[6] & 0xff);
- int numcerts = 0;
- X509CertificateStructure last_cert = null;
- X509CertificateStructure this_cert = null;
-
- for(int i=0; i<numcertbytes;) {
- int certlen = ((rec[7 + i] & 0xff) << 16) | ((rec[7 + i + 1] & 0xff) << 8) | (rec[7 + i + 2] & 0xff);
- try {
- DERInputStream dIn = new DERInputStream(new ByteArrayInputStream(rec, 7 + i + 3, certlen));
- this_cert = new X509CertificateStructure((DERSequence)dIn.readObject());
- } catch (Exception e) {
- SSLException t = new SSLException("error decoding server certificate: " + e);
- t.fillInStackTrace();
- throw t;
- }
-
- if (server_cert == null) {
- server_cert = this_cert;
- TBSCertificateStructure tbs = server_cert.getTBSCertificate();
-
- // gross hack to extract the Common Name so we can compare it to the server hostname
- String CN = tbs.getSubject().toString() + " ";
- boolean good = false;
- for(int j=0; j<CN.length() - 3; j++)
- if (CN.substring(j, j+3).equals("CN=")) {
- good = true;
- CN = CN.substring(j+3, CN.indexOf(' ', j+3));
- break;
- }
-
- if (!good) throw new SSLException("server certificate does not seem to have a CN: " + CN);
- if (!ignoreUntrustedCert && !CN.equalsIgnoreCase(hostname))
- throw new SSLException("connecting to host " + hostname + " but server certificate was issued for " + CN);
-
- SimpleDateFormat dateF = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss-z");
-
- // the following idiocy is a result of the brokenness of the GNU Classpath's SimpleDateFormat
- String s = tbs.getStartDate().getTime();
- s = s.substring(0, 4) + "-" + s.substring(4, 6) + "-" + s.substring(6, 8) + "-" +
- s.substring(8, 10) + "-" + s.substring(10, 12) + "-" +
- s.substring(12, 14) + "-" + s.substring(14);
-
- Date startDate = dateF.parse(s, new ParsePosition(0));
-
- s = tbs.getEndDate().getTime();
- s = s.substring(2, 4) + "-" + s.substring(4, 6) + "-" + s.substring(0, 2) + "-" + s.substring(6, 8) + "-" +
- s.substring(8, 10) + "-" + s.substring(10, 12) + "-" + s.substring(12);
- Date endDate = dateF.parse(s, new ParsePosition(0));
-
- Date now = new Date();
- if (!ignoreUntrustedCert && now.after(endDate))
- throw new SSLException("server certificate expired on " + endDate);
- if (!ignoreUntrustedCert && now.before(startDate))
- throw new SSLException("server certificate will not be valid until " + startDate);
-
- Log.info(this, "server cert (name, validity dates) checks out okay");
-
- } else {
-
- // don't check the top cert since some very old root certs lack a BasicConstraints field.
- if (certlen + 3 + i < numcertbytes) {
- // defend against Mike Benham's attack
- X509Extension basicConstraints = this_cert.getTBSCertificate().getExtensions().getExtension(X509Extensions.BasicConstraints);
- if (basicConstraints == null) throw new SSLException("certificate did not contain a basic constraints block");
- DERInputStream dis = new DERInputStream(new ByteArrayInputStream(basicConstraints.getValue().getOctets()));
- BasicConstraints bc = new BasicConstraints((DERSequence)dis.readObject());
- if (!bc.isCA()) throw new SSLException("non-CA certificate used for signing");
- }
-
- if (!isSignedBy(last_cert, this_cert.getSubjectPublicKeyInfo()))
- throw new SSLException("the server sent a broken chain of certificates");
- }
-
- last_cert = this_cert;
- i += certlen + 3;
- numcerts++;
- }
- if (Log.on) Log.info(this, " Certificate (" + numcerts + " certificates)");
-
- if (ignoreUntrustedCert) break;
-
- boolean good = false;
-
- // pass 1 -- only check CA's whose subject is a partial match
- String subject = this_cert.getSubject().toString();
- for(int i=0; i<trusted_CA_public_keys.length; i++) {
- if (subject.indexOf(trusted_CA_public_key_identifiers[i]) != -1 && isSignedBy(this_cert, trusted_CA_public_keys[i])) {
- if (Log.on) Log.info(this, "pass 1: server cert was signed by trusted CA " + i);
- good = true;
- break;
- }
- }
-
- // pass 2 -- try all certs
- if (!good)
- for(int i=0; i<trusted_CA_public_keys.length; i++) {
- if (isSignedBy(this_cert, trusted_CA_public_keys[i])) {
- if (Log.on) Log.info(this, "pass 2: server cert was signed by trusted CA " + i);
- good = true;
- break;
- }
- }
-
- if (!good) throw new SSLException("server cert was not signed by a trusted CA");
- break;
-
- case 12:
- if (Log.on) Log.info(this, "got ServerKeyExchange");
- serverKeyExchange = rec;
- break;
-
- case 13:
- if (Log.on) Log.info(this, "got Request for Client Certificates");
- cert_requested = true;
- break;
-
- case 14: if (Log.on) Log.info(this, " ServerHelloDone"); return;
- default: throw new SSLException("unknown handshake of type " + rec[0]);
- }
- }
- }
-
- public void readServerFinished() throws IOException {
-
- byte[] rec = readHandshake();
- if (rec[0] != 20) throw new SSLException("expecting server Finished message, but got message of type " + rec[0]);
-
- byte[] expectedFinished = concat(new byte[][] {
- md5(new byte[][] { master_secret, pad2,
- md5(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
- master_secret, pad1 }) }),
- sha(new byte[][] { master_secret, pad2_sha,
- sha(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
- master_secret, pad1_sha } ) } ) } );
-
- for(int i=0; i<expectedFinished.length; i++)
- if (expectedFinished[i] != rec[i + 4])
- throw new SSLException("server Finished message mismatch!");
-
- if (Log.on) Log.info(this, "server finished message checked out okay!");
- }
-
- }
-
- class SSLOutputStream extends OutputStream {
-
- /** the underlying outputstream */
- DataOutputStream raw;
-
- /** the sequence number for sending */
- public long seq_num = 0;
-
- /** the encryption engine for sending */
- RC4Engine rc4 = null;
-
- public SSLOutputStream(OutputStream raw) { this.raw = new DataOutputStream(raw); }
- public void flush() throws IOException { raw.flush(); }
- public void write(int b) throws IOException { write(new byte[] { (byte)b }, 0, 1); }
- public void write(byte[] b, int off, int len) throws IOException { write(b, off, len, (byte)23); }
- public void close() throws IOException {
- write(new byte[] { 0x1, 0x0 }, 0, 2, (byte)21);
- raw.close();
- }
-
- /** writes a single SSL Record */
- public void write(byte[] payload, int off, int len, byte type) throws IOException {
-
- // largest permissible frame is 2^14 octets
- if (len > 1 << 14) {
- write(payload, off, 1 << 14, type);
- write(payload, off + 1 << 14, len - 1 << 14, type);
- return;
- }
-
- raw.writeByte(type);
- raw.writeShort(0x0300);
-
- if (rc4 == null) {
- raw.writeShort(len);
- raw.write(payload, off, len);
-
- } else {
- byte[] MAC = computeMAC(type, payload, off, len, client_write_MAC_secret, seq_num);
- byte[] encryptedPayload = new byte[MAC.length + len];
- rc4.processBytes(payload, off, len, encryptedPayload, 0);
- rc4.processBytes(MAC, 0, MAC.length, encryptedPayload, len);
- raw.writeShort(encryptedPayload.length);
- raw.write(encryptedPayload);
-
- }
-
- seq_num++;
- }
-
- /** tacks a handshake header onto payload before sending it */
- public void writeHandshake(int type, byte[] payload) throws IOException {
- byte[] real_payload = new byte[payload.length + 4];
- System.arraycopy(payload, 0, real_payload, 4, payload.length);
- real_payload[0] = (byte)(type & 0xFF);
- intToBytes(payload.length, real_payload, 1, 3);
- handshakes = concat(new byte[][] { handshakes, real_payload });
- write(real_payload, 0, real_payload.length, (byte)22);
- }
-
- public void sendClientHandshakes() throws IOException {
-
- if (Log.on) Log.info(this, "shaking hands");
- if (cert_requested) {
- if (Log.on) Log.info(this, "telling the server we have no certificates");
- writeHandshake(11, new byte[] { 0x0, 0x0, 0x0 });
- }
-
- // generate the premaster secret
- byte[] pre_master_secret = new byte[48];
- pre_master_secret[0] = 0x03; // first two bytes of premaster secret are our version number
- pre_master_secret[1] = 0x00;
- getRandomBytes(pre_master_secret, 2, pre_master_secret.length - 2);
-
- // encrypt and send the pre_master_secret
- try {
- byte[] encrypted_pre_master_secret;
-
- SubjectPublicKeyInfo pki = server_cert.getSubjectPublicKeyInfo();
- RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERSequence)pki.getPublicKey());
- BigInteger modulus = rsa_pks.getModulus();
- BigInteger exponent = rsa_pks.getPublicExponent();
-
- if (serverKeyExchange != null) {
-
- AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
- rsa.init(false, new RSAKeyParameters(false, modulus, exponent));
-
- int modulus_size = ((serverKeyExchange[4] & 0xff) << 8) | (serverKeyExchange[5] & 0xff);
- byte[] b_modulus = new byte[modulus_size];
- System.arraycopy(serverKeyExchange, 6, b_modulus, 0, modulus_size);
- modulus = new BigInteger(1, b_modulus);
-
- int exponent_size = ((serverKeyExchange[6 + modulus_size] & 0xff) << 8) | (serverKeyExchange[7 + modulus_size] & 0xff);
- byte[] b_exponent = new byte[exponent_size];
- System.arraycopy(serverKeyExchange, 8 + modulus_size, b_exponent, 0, exponent_size);
- exponent = new BigInteger(1, b_exponent);
-
- byte[] server_params = new byte[modulus_size + exponent_size + 4];
- System.arraycopy(serverKeyExchange, 4, server_params, 0, server_params.length);
-
- byte[] expectedSignature = concat(new byte[][] { md5(new byte[][] { client_random, server_random, server_params } ),
- sha(new byte[][] { client_random, server_random, server_params } ) } );
-
- byte[] recievedSignature = rsa.processBlock(serverKeyExchange, 6 + server_params.length,
- serverKeyExchange.length - 6 - server_params.length);
-
- for(int i=0; i<expectedSignature.length; i++)
- if (expectedSignature[i] != recievedSignature[i])
- throw new SSLException("ServerKeyExchange message had invalid signature " + i);
-
- if (Log.on) Log.info(this, "ServerKeyExchange successfully processed");
- }
-
- AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
- rsa.init(true, new RSAKeyParameters(false, modulus, exponent));
-
- encrypted_pre_master_secret = rsa.processBlock(pre_master_secret, 0, pre_master_secret.length);
- writeHandshake(16, encrypted_pre_master_secret);
-
- } catch (Exception e) {
- SSLException t = new SSLException("exception encrypting premaster secret");
- t.fillInStackTrace();
- throw t;
- }
-
- // ChangeCipherSpec
- if (Log.on) Log.info(this, "Handshake complete; sending ChangeCipherSpec");
- write(new byte[] { 0x01 }, 0, 1, (byte)20);
- seq_num = 0;
-
- // compute master_secret
- master_secret = concat(new byte[][] {
- md5(new byte[][] { pre_master_secret,
- sha(new byte[][] { new byte[] { 0x41 }, pre_master_secret, client_random, server_random })}),
- md5(new byte[][] { pre_master_secret,
- sha(new byte[][] { new byte[] { 0x42, 0x42 }, pre_master_secret, client_random, server_random })}),
- md5(new byte[][] { pre_master_secret,
- sha(new byte[][] { new byte[] { 0x43, 0x43, 0x43 }, pre_master_secret, client_random, server_random })})
- } );
-
- // construct the key material
- byte[] key_material = new byte[] { };
- for(int i=0; key_material.length < 72; i++) {
- byte[] crap = new byte[i + 1];
- for(int j=0; j<crap.length; j++) crap[j] = (byte)(((byte)0x41) + ((byte)i));
- key_material = concat(new byte[][] { key_material,
- md5(new byte[][] { master_secret,
- sha(new byte[][] { crap, master_secret, server_random, client_random }) }) });
- }
-
- client_write_key = new byte[export ? 5 : 16];
- server_write_key = new byte[export ? 5 : 16];
-
- System.arraycopy(key_material, 0, client_write_MAC_secret, 0, 16);
- System.arraycopy(key_material, 16, server_write_MAC_secret, 0, 16);
- System.arraycopy(key_material, 32, client_write_key, 0, export ? 5 : 16);
- System.arraycopy(key_material, export ? 37 : 48, server_write_key, 0, export ? 5 : 16);
-
- if (export) {
- // see SSLv3 spec, 6.2.2 for explanation
- byte[] client_untrimmed = md5(new byte[][] { concat(new byte[][] { client_write_key, client_random, server_random } ) });
- byte[] server_untrimmed = md5(new byte[][] { concat(new byte[][] { server_write_key, server_random, client_random } ) });
- client_write_key = new byte[16];
- server_write_key = new byte[16];
- System.arraycopy(client_untrimmed, 0, client_write_key, 0, 16);
- System.arraycopy(server_untrimmed, 0, server_write_key, 0, 16);
- }
-
- rc4 = new RC4Engine();
- rc4.init(true, new KeyParameter(client_write_key));
- is.rc4 = new RC4Engine();
- is.rc4.init(false, new KeyParameter(server_write_key));
-
- // send Finished
- writeHandshake(20, concat(new byte[][] {
- md5(new byte[][] { master_secret, pad2,
- md5(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
- master_secret, pad1 }) }),
- sha(new byte[][] { master_secret, pad2_sha,
- sha(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
- master_secret, pad1_sha } ) })
- }));
- raw.flush();
- if (Log.on) Log.info(this, "wrote Finished message");
-
- }
-
- public void writeClientHello() throws IOException {
-
- if (Log.on) Log.info(this, "sending ClientHello");
- int unixtime = (int)(System.currentTimeMillis() / (long)1000);
-
- byte[] out = new byte[] {
- 0x03, 0x00, // client version (SSLv3.0)
-
- // space for random bytes
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
-
- 0x0, // empty vector for sessionid
- 0x0, 0x4, 0x0, 0x4, 0x0, 0x3, // we support two ciphersuites: SSL_RSA_WITH_RC4_128_MD5 and SSL_RSA_EXPORT_WITH_RC4_40_MD5
- 0x1, 0x0 // we only support one compression method: none
- };
-
- // don't need to use secure random here since it's sent in the clear
- Random rand = new Random(System.currentTimeMillis());
- rand.nextBytes(client_random);
- intToBytes(unixtime, client_random, 0, 4);
- System.arraycopy(client_random, 0, out, 2, client_random.length);
-
- writeHandshake(1, out);
- flush();
- }
- }
-
- // Static Helpers ////////////////////////////////////////////////////////////////////
-
- /** copy the least significant num bytes of val into byte array b, startint at offset */
- public static void intToBytes(long val, byte[] b, int offset, int num) {
- for(int i=0; i<num; i++)
- b[offset + num - i - 1] = (byte)((val & (0xFFL << (i * 8))) >> (i * 8));
- }
-
- /** fills b with random bytes */
- public static synchronized void getRandomBytes(byte[] b, int offset, int len) {
- MD5Digest md5 = new MD5Digest();
- byte[] b2 = new byte[16];
- while(len > 0) {
- md5.reset();
- md5.update(randpool, 0, randpool.length);
- intToBytes(randcnt++, b2, 0, 8);
- md5.update(b2, 0, 8);
- md5.doFinal(b2, 0);
- int n = len < 16 ? len : 16;
- System.arraycopy(b2, 0, b, offset, n);
- len -= n;
- offset += n;
- }
- }
-
- public static byte[] computeMAC(byte type, byte[] payload, int off, int len, byte[] MAC_secret, long seq_num) {
- byte[] MAC = new byte[16];
- MD5Digest md5 = new MD5Digest();
- md5.update(MAC_secret, 0, MAC_secret.length);
- md5.update(pad1, 0, pad1.length);
-
- byte[] b = new byte[11];
- intToBytes(seq_num, b, 0, 8);
- b[8] = type;
- intToBytes(len, b, 9, 2);
- md5.update(b, 0, b.length);
-
- md5.update(payload, off, len);
- md5.doFinal(MAC, 0);
- md5.reset();
- md5.update(MAC_secret, 0, MAC_secret.length);
- md5.update(pad2, 0, pad2.length);
- md5.update(MAC, 0, MAC.length);
- md5.doFinal(MAC, 0);
-
- return MAC;
- }
-
- public static byte[] concat(byte[][] inputs) {
- int total = 0;
- for(int i=0; i<inputs.length; i++) total += inputs[i].length;
- byte[] ret = new byte[total];
- int pos = 0;
- for(int i=0; i<inputs.length; i++) {
- System.arraycopy(inputs[i], 0, ret, pos, inputs[i].length);
- pos += inputs[i].length;
- }
- return ret;
- }
-
- SHA1Digest master_sha1 = new SHA1Digest();
- public byte[] sha(byte[][] inputs) {
- master_sha1.reset();
- for(int i=0; i<inputs.length; i++) master_sha1.update(inputs[i], 0, inputs[i].length);
- byte[] ret = new byte[master_sha1.getDigestSize()];
- master_sha1.doFinal(ret, 0);
- return ret;
- }
-
- MD5Digest master_md5 = new MD5Digest();
- public byte[] md5(byte[][] inputs) {
- master_md5.reset();
- for(int i=0; i<inputs.length; i++) master_md5.update(inputs[i], 0, inputs[i].length);
- byte[] ret = new byte[master_md5.getDigestSize()];
- master_md5.doFinal(ret, 0);
- return ret;
- }
-
- // FEATURE: improve error reporting in here
- /** returns true iff certificate "signee" is signed by public key "signer" */
- public static boolean isSignedBy(X509CertificateStructure signee, SubjectPublicKeyInfo signer) throws SSLException {
-
- Digest hash = null;
-
- String signature_algorithm_oid = signee.getSignatureAlgorithm().getObjectId().getId();
- if (signature_algorithm_oid.equals("1.2.840.113549.1.1.4")) hash = new MD5Digest();
- else if (signature_algorithm_oid.equals("1.2.840.113549.1.1.2")) hash = new MD2Digest();
- else if (signature_algorithm_oid.equals("1.2.840.113549.1.1.5")) hash = new SHA1Digest();
- else throw new SSLException("unsupported signing algorithm: " + signature_algorithm_oid);
-
- try {
- // decrypt the signature using the signer's public key
- byte[] ED = signee.getSignature().getBytes();
- SubjectPublicKeyInfo pki = signer;
- RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERSequence)pki.getPublicKey());
- BigInteger modulus = rsa_pks.getModulus();
- BigInteger exponent = rsa_pks.getPublicExponent();
- AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
- rsa.init(false, new RSAKeyParameters(false, modulus, exponent));
-
- // Decode the embedded octet string
- byte[] D = rsa.processBlock(ED, 0, ED.length);
- BERInputStream beris = new BERInputStream(new ByteArrayInputStream(D));
- DERObject derob = beris.readObject();
- DERSequence dercs = (DERSequence)derob;
- DEROctetString deros = (DEROctetString)dercs.getObjectAt(1);
- byte[] MD = deros.getOctets();
-
- // generate our own hash
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- DEROutputStream dos = new DEROutputStream(baos);
- dos.writeObject(signee.getTBSCertificate());
- dos.flush();
- byte[] b = baos.toByteArray();
- hash.update(b, 0, b.length);
- byte[] md_out = new byte[MD.length];
- hash.doFinal(md_out, 0);
-
- // compare our hash to the signed hash
- for(int j=0; j<MD.length; j++) if (md_out[j] != MD[j]) return false;
- return true;
-
- } catch (Exception e) {
- return false;
-
- }
- }
-
- // Embedded Trusted Public Keys //////////////////////////////////////////////
-
- /** base64-encoded sequence of DER-encoded PKCS7 certs for all the "trusted root CA's" included with IE5.5 */
- static String[] base64_encoded_trusted_CA_public_keys = new String[] {
-
- "CN=ABA.ECOM Root CA",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdMR4HlVQwcITMsFQgDiDYNGPe" +
- "STurYG0w1ZvT7BzkNnAYohqO+8zNCizLBVllOEZgUA2kRJgNhUCqUlhpTtY1b/cGyjoRnS" +
- "eL5oKkReL8/MGF5HvDqxRj0e8LksNF+MfEwIKZ1AVes8fYPetfD3ioMOoUy0OqWzX1oil+" +
- "wZm8EFaP3mt6mRlCzkeEgkGiUZOuuVnDkKis9CsvAc1V/7a+1oVns5LHI4sO6TqdN7dzzr" +
- "cQOpOEoWbIkqytozE3nCVYztnLvyy1sQ+C5hNcYpTCrQKmPRZVm0+M359ACEtldChZ0yqP" +
- "kqVPv/eEG8vXEo9LuQvP+WNATjRZ6hRihAgQIDAQAB",
-
- "O=ViaCode",
- "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCws2enlrV2g+kWA9kaoHbVdOecBdJRP9" +
- "tPGaGoOU7LJH1hxB5qIK4Pgd7quDn9Gx9rNkDtTSEl8qPZoVHYbMAblvjUQpTUp84bj9NU" +
- "JqKE7zKFr0o/8TI2rz3mOifrA8IlfvRhK62KGkvmmzZo1C/l0oiU3Baq2sIVTGzD4RmRyQ" +
- "IBAw==",
-
- "CN=Xcert EZ by DST",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArVQY3rS/963odKrti3yPwtR1Gt" +
- "WEubZi/Inv5JdhkvsduOFaRzSengYi+9PqOMu4iwf3GqAXdwdaMBzUKTgg1ydA2FCTQ7/S" +
- "GKIpdgVyqmu2aZireR4cZfVqi/zFFqqictpg7U5uGSV6Ch0w41CbQjxE66GwIB7bAn7+PR" +
- "+/0ACK20B2philFadXtlLCAReYd4+KgcYatGoq5q+p1gCsz9gVSXzbG6H+gfqH+dOQwQLA" +
- "+dBC6ZFoJV/Gv4c56ZUAYCi/gyzA51621zYW52CHdujnJ7IlDYt65aod5VnNzgsOb8bInO" +
- "MQ2YU507eb+sa6fHTSXXVWq3SkolG/UnzucQIDAQAB",
-
- "CN=Certiposte Classe A Personne",
- "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQAox3xaJSN48rMAR0Biy2+MQlCfnl" +
- "7UXA5lC1hWlSvjRtBhNuAtRpuCy5Hu0pV8mpKvBAp+pp/g17HDRfmYQRs5redW19m2f867" +
- "OS4sO8+2cwODzhNdMmpjottb+Esz6FBsy6gX7J6TuWwGSyYLdx6e+eWMiTfS0bv9qYwrLJ" +
- "wQMdhLjM23cX44LCnjF7JP6FK245I80v3hAtphEHTSGvPI0dFmB1/EhGNpva5s3GUjHLf7" +
- "98YTLoN+P6nlCyBtAQo34lzait4icOkN4HQ9xOtxm2Eq4g0Ui0xGN0wm0mjWVsNXqqJgN6" +
- "9fnaCzgILmQypMgAAJUNmoanNtA/5ec5LlAgMBAAE=",
-
- "CN=Certiposte Serveur",
- "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQA+p3gzOJHiylaV0ZFGsiPcpVZ/D8" +
- "eXuOKekS4oFi6O80e2XIPE8Ob+ZxqTZH1ACdgdaADs1BHu2GOJAyPphF/HVQ5K4nK7KcFV" +
- "ZHao45LN9/ZuQlYYUjOJ+YAUqBlRfsd3v3qoMcB9F25DTtVmyQU+S+Ll4lUbdKpRHarMmB" +
- "F3pOvbKg4nx9XNSOzcfk5J50HNmQvRS14YGw06CpstmznHQAzQdgd8fI9+XHKOh9W+8qa5" +
- "3r/dnxJ5R3zFyZdARgCS0xNak0+dfthfTMFdSEnZLZg8/MynhyHwPo5yfVk4NhYaDEi+of" +
- "LVPqgWDCBZz84PM4M9rav1/93X/WkIiADvAgMBAAE=",
-
- "OU=Certisign - Autoridade Certificadora - AC2",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5MMyl65DWVpRnM4mDbUa+cJeTF04KJ3" +
- "DOycXyxdIt0RGcdzJsdNOSb/rp1bhhmqpMEz41OvDuCTbZ0Zcxx16sQUm/SG1OIFPJe2qj" +
- "ljFrsm6ozy9yTAatMs9aCPN9EJyqu7pz+fPwuCRvqGW2Iv4FWxBVRMIDHa3RIswIbfuMyw" +
- "IDAQAB",
-
- "OU=Certisign - Autoridade Certificadora - AC4",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDsg9TMg5A/X+y+wenQx1hGWR/xk0qyFx" +
- "MLzymZqwRFM+PRXr68jiV3Yt2bkpsxCkBFedXys91suUD9mH9Aoi3pspO9S9XB3unR+nH3" +
- "P0G89BSvzWvIOUqdYGW0hNBqQeljrptp6rlGHNsYCDtiTN5B156GfxNyEdTc6t5gpbvdGw" +
- "IDAQAB",
-
- "OU=Certisign Autoridade Certificadora AC1S",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwwJXro8VB+JtvcWOOkRFX+QPHaJoanG" +
- "Hwww8Ml2KIfiYBNX398W9PF5WqfvK7vO/idnNhlTZRgz6E6D+6VzY3lBNskmQflA3rVC9R" +
- "WuUoXvCShufkbSF6XzcL51u9LQKogfk/yxTIvKTF49HLN9yr5Yeq8guYLnrPzB7Cf+j9AQ" +
- "IDAQAB",
-
- "OU=Certisign Autoridade Certificadora AC3S",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOZE7Wz658mCeY7yjvujTDNRqd0mYecf" +
- "Hkli0nFzmQRY8t7+bVR6nhg4F8Pihx+oC7XfhDaxkQwZhvFZ4trklkROyEGmlZFleyPZLY" +
- "Zku/ma1DGMc4yYuOLAQus0trk/adH4SyzeYAwr42pbxZtZ+LGSD/5agopFW2irayxddE4w" +
- "IDAQAB",
-
- "O=Certplus, CN=Class 1 Primary CA",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw2spyC7HrnxSBemTiVYKWnnJzN" +
- "wl74eKLQXYgRcEGzpF+HkODUnUgUHIq0X7dcgV8uLQvNlhbISkExmn2fnySdxMD8Z9V7QT" +
- "3B4JcSk2nYBY9BvYiRTr09KTSyrxd+dqZb0Z5ar9DEpj4cKZtA8EtlobNjw3PL/F5V7xX1" +
- "cOH8f9LOfkb2qbYpY5EZtm8Cy2UtzhJ//bbf7rq2MUHWOIY+IWDPkgVA+b3RVqdoNPvSeL" +
- "U6Y30ofyR1BSO2bp0XgaG7I7afBZPDhb0SpMM14Oylal7S1bgoNN1jhOila2ai8kaxIwpi" +
- "rerwy7qkQSHBPFZQ/j/dgaMUvkPwx8RegWMwIDAQAB",
-
- "O=Certplus, CN=Class 2 Primary CA",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3FCW0BL4NdIIeHq2UnD9b+7PuR" +
- "HLXXfh7Ol+BI3WzG9zQ1dgrDMKROwDXxyAJJHlqJFWEoL34Cv0265hLokQjWtsurMCvdU2" +
- "xUg3I+LwWjdSMxcS4tFgTb4vQRHj9hclDIuRwBuZe5lWDa/u0rxHV+N5SXs0iSckhN6x7O" +
- "lYTv5O31q+Qa2sCMUYDu/SU+5s0J0SARON3IBi95WpRIhKcU5gVZ7bIxl5VgcMP2MLXLDi" +
- "vn4V/JQzWEE4dMThj4vfJqwftYs7t0NZa7Akpm2Qi8Ry6l0zmLfL3l5775TxGz7KySHBxZ" +
- "gCqqL2W3eb9X6WVTQcZ2nA8ULjR6z8KBxmVQIDAQAB",
-
- "O=Certplus, CN=Class 3 Primary CA",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt5QwbtBM2X5eYOVvuybKUm9rbI" +
- "WZpQvvABpvG01YtRgH+t17+MssUt38nLiNUum5sgt89Y9bmUgJWN7NSJWGJYkFNCcwC1e2" +
- "DHdjKctsqj65mVESDZhwdkdM+UmWIgj5a+qqADajFaccHp+Mylp5eyHaiR9jfnmSUAkEKK" +
- "3O420ESUqZsT9FCXhYIO+N/oDIBO0pLKBYjYQCJZc/oBPXe4sj45+4x7hCQDgbkkq9SpRV" +
- "x1YVDYF3zJ+iN4krW4UNi3f4xIv7EMuUx+kaVhKXZhTEu9d9bQIbv3FiJhjpSYr6o97hhK" +
- "2AykriIoxqCGGDsiLHCYg4Vl3RMavwCZ8TWQIDAQAB",
-
- "CN=Autoridad Certificadora de la Asociacion Nacional del Notariado Mexicano",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7tlrVYRxJvaOrUG71tLeY+ryP2" +
- "XyOxPBrlEm9L94j8ZMSay/Qd71KMco55/XgOXU7iMrk5U9yY9q9coA6RDHiIIabqNf8DRS" +
- "ISVoKPiV8ICVoiyxP2r2KNbihP0WZ5wluXXb5cZZA7SrQgeI1VxIRaIJA8muZ5KoolPHyq" +
- "t+mhKVWgVXjRBklicRsOYyMFvNPQygGxMtuxqr3TnOkmuiBNQTX213Z1Q5qHtpisZfeMoH" +
- "GGlu+cDT0IqOrx4waO742KhmDIR9I2qJPGJNFHSs25uc/LCD/gcw8factEjI5jpCJQko91" +
- "bCsdejmHcCh+qKwV3axIonB4VeSExVKEDtCQIDAQAB",
-
- "O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhA" +
- "wL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lw" +
- "dd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpw" +
- "IDAQAB",
-
- "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhA" +
- "wL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lw" +
- "dd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpw" +
- "IDAQAB",
-
- "C=FR, O=Certplus, CN=Class 3P Primary CA",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqzf/62CbQXhp9UlYsN4fcWmmK+" +
- "OuUMapvJPpIL7kxBOCVu/wQzIJypt1A498T+HgT3aeC61kehQ6mp2/LxYLZRyp7py84xpl" +
- "y0+F6pJWdWbWVUDv+8zWOD+rHO9CjRmJ9reVhsKnHen3KfEq2WV5/Cv1jsoad36e6Kz5Zr" +
- "9F++gTnV+2c+V9e477EnRdHwZehRumXhhEALq8027RUg4GrevutbTBu7zrOA9IIpHHb9K4" +
- "cju6f8CNbLe8R3MhKoX/rNYoohnVl2o6uaxtRezmTcPbqF3FXYKYrEpaquYrCAwQdLxi9j" +
- "pJBGbYURwmpth1n5y/rmBRPVy8ok97iWfNUwIDAQAB",
-
- "C=FR, O=Certplus, CN=Class 3TS Primary CA",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvWWaI0MAPPklAUOYW0Y0N2c39F" +
- "tXjqPezYwvQbMVPeWYi/LMXKfHrzXHs6dPxxApV+kDiYNyBnZSwXACN0Dt8M6LsbGJrAKo" +
- "W93c1UNFBtwotulRG2ru83tIxZ0Rro2mcpPAJUKRqD5G4mhMgUCwQtN6vntH0kdQDKQSps" +
- "rkEtDAfDo8AanKApbeglrF+xm6PJzYD3QfmBiulFAyB1IQEUpL7FhVLNSeS5R7BdJy3wbw" +
- "jcsInuTutEStgvEbYWrxs/gWMTZCJLqQv7V+YW7CWQxUebRMiCgezBvfhIsjyL6vB/KRst" +
- "qNyoxffCg8fIlsBlm9Ps7FgtNqyaxoVe7FrwIDAQAB",
-
- "C=US, O=RSA Data Security, Inc., OU=Commercial Certification Authority",
- "MIGbMA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AKT7gWJ7zhAn3ej3vmxuxnCZ27jVBQNpKI" +
- "Kccn+WP47srCmSP4oU+EJ2vr1dA7mQ1NC8BrJRM1/Ewr+2i4+ZtmIiYN3b3yCCtMqiLy1Q" +
- "7ZQy3uBVjdRo4uBM0s0FFi6VZlxhUjgeUaiCocTvJekK5osrjjFm2fjZ/b07adnrAgMBAA" +
- "E=",
-
- "C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 1",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQ3ZsMoBdERA+vIUBzZ1bwPmloEbrZN/" +
- "KBrsMkrGmhzfymGFVW/4ufMsHb53gsOdtggUGl79PNgI0YPOJSDAuf92Se5aDwuGFi9L/g" +
- "o9pYK/0VBGu9Op58nfI92OSVw+xOwvFlqwxL7EeCW+LhUHXY9mG0GFztM6BLHoP7T4S8eQ" +
- "IDAQAB",
-
- "C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 2",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqwujNeCLKRSxFIWvPBDkOW81XU" +
- "qu3ephjZVJ9G9koxpgZqSpQCKE2dSl5XiTDmgBrblNXDrO07ioQkDfz6O6gllqkhusHJra" +
- "CCslJ/lpI0fx4Ossepv1EwLQfjR8wp48AFmr9doM9TI8K6xQ2tbD3oOUyqgMmTIOCEhWW2" +
- "r72uFYWAFJX3JBPBUGAY5draq4k7TNnuun6GotUjTbOu9cdVHa2/Mx+e5xmDLEVBVEDPmb" +
- "Ve2t3xgIoKOGiknuUwWPGUzV3lh5m9JqHEKrxdWnz2gPluThYZh2YciRfNY+AOKRUIfhnQ" +
- "rmrZfSHcY6fcu82gM01Y5bAfVqB7cWtm5KfwIDAQAB",
-
- "C=US, O=Digital Signature Trust Co., OU=DST (ANX Network) CA",
- "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC0SBGAWKDVpZkP9jcsRLZu0XzzKmueEb" +
- "aIIwRccSWeahJ3EW6/aDllqPay9qIYsokVoGe3eowiSGv2hDQftsr3G3LL8ltI04ceInYT" +
- "BLSsbJZ/5w4IyTJRMC3VgOghZ7rzXggkLAdZnZAa7kbJtaQelrRBkdR/0o04JrBvQ24JfQ" +
- "IBAw==",
-
- "OU=National Retail Federation, CN=DST (NRF) RootCA",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2aybd/pQ08zcuUCsuXJqAIcj/A" +
- "+WIdAmr+TitV/606Z9ITAuzBeCj5h0/Gekpt+Il6JCKfWn2xGT+14jMMKqvCLnQRvl7SXe" +
- "yD/b3ldFeEBGg7LVGj3fD0Vt1WMCddgvxm6rlZF0Nw3LTQlc0dRbOtrdDshrmdjVOczfhV" +
- "XEklMCo+H3gMlwo9rcM8R/okcIHDWWH6EDHDCD9MTM/5jDsEZEosC/rdvSgfZMmCynXiTz" +
- "hspj1bp98JrAStAbWO7sqWfPaQJsIsBgLCzRyCDqyC373Zy7y1FM3OdXBDtUmxGlMnTsdA" +
- "HzkBVbL3wsk2W5Zme0gYg15Z6RGH+BqEHIywIDAQAB",
-
- "OU=United Parcel Service, CN=DST (UPS) RootCA",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7xfsrynm2SsnwNt7JJ9m9ASjwq" +
- "0KyrDNhCuqN/OAoWDvQo/lXXdfV0JU3SvbYbJxXpN7b1/rJCvnpPLr8XOzC431Wdcy36yQ" +
- "jk4xuiVNtgym8eWvDOHlb1IDFcHfvn5KpqYYRnA/76dNqNz1dNlhekA8oZQo6sKUiMs3FQ" +
- "UZPJViuhwt+yiM0ciekjxbEVQ7eNlHO5stSuY+e2vf9PYFzyj2upg2AJ48N4UKnN63pIXF" +
- "Y/23YhRtFx7MioCFQjIRsCHinXfJgBZBnuvlFIl/t8O8T8Gfh5uW7GP2+ZBWDpWjIwqMZN" +
- "qbuxx3sExd5sjo9X15LVckP8zjPSyYzxKfFwIDAQAB",
-
- "CN=Autoridad Certificadora del Colegio Nacional de Correduria Publica Mexicana",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmO0dhYH7/jd0viOAJ18bQX6856" +
- "WK2HNdlkjqq1iqfaUdz/4gCtnydQnts9X9+JMqGaleqLEU8tZChkFBXk/FVqeaokJvLihI" +
- "6i6r2cHZmvClnotdEWeaNzdTYGbxIv93d0fp3dwYRu4u3+LBluDqWN6H65OIaZmwPm52KU" +
- "Bhwyhmc3+sMXb0OM3WMo9zMhAVNNJ8RND8eQwAnX0P4+P3RPWedEknrRvXMshTrm8qsNe1" +
- "LRgsbjs6TUzb9Wi1L7AMkPk93HU2msLgv7uWiMJr7hjXTlA/V4tnaKS+AzNdWRI0if52yN" +
- "kVdgFUZP2s41DvEMjQ7l/sHd9PBZg8tBReAQIDAQAB",
-
- "CN=DST RootCA X1",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0sYmtuelPcHEaNVQb1PFb0kTCb" +
- "ivLEiNFGqjF19a+dMudS/YKGLRky/8TdSrh+UIx5nnkj91vesltBXBmxk90kSN13QgbTcC" +
- "j2mTW4rEGZ30sg78Fmy5sQWSg9GFLGCUPkVVoNmrCCHmYOg7dPKZUFFo0AMtsYC+o9hSsE" +
- "TNQ0pwjliFleFOLNYtQW/WhOfImETKR9ssJKVpJs9ruCdiw/TJepIj7RNngq5FLkXlfnI/" +
- "hZ2UYhDmPJGhrXcA4BXs84SAcnqObmCXxyRZEDSDW+GlpGm2VzUceFnG0y86c2fulMoEEw" +
- "ViBnAjs/R87kXZZAtbSaqkQ84mxEQSbLjdeQIDAQAB",
-
- "OU=DSTCA X2, CN=DST RootCA X2",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3HXwjMB1lprAYh8m98ThmurgVn" +
- "Nbmc0BRKgIttWn2hoEGDmSSnijgcL1d3pQtHD/mqvGx8pug09CmPsmC9rcbdapmVVSZ+ko" +
- "A5Lc5bAFmg8V+WtZclby+jn8qmjuDx8Qgy/8nfoXlt2C4+ZFfcBLgEQf7SzghP2RXJJUaS" +
- "XlYmnc5e4AUr0zC611AoWnZFAtxRkZMMAm28nT/S6ZrVm1C03UQa6FSENZ3Leo4qLew4/X" +
- "uKFipmhQUuTPMaeUhdqfRjIXVuXy62Y9Ev9D25jvd8/LgY00scZQSibR5D5BUK9sriI0Lt" +
- "VrboO6ebh2ZUjaCSlkYyK5+0d2hYyGRMsJ2wIDAQAB",
-
- "C=US, O=Digital Signature Trust Co., OU=DST-Entrust GTI CA",
- "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC2HfdLjQ8T4xL1Cf4GMg6vTEH1fdRHPS" +
- "oK34MF3t595gMW9lE6y0caSq1+xP0dtL50injdC4OOtIQTxPv4bSmuoeEPD0PjtV5gafqD" +
- "lPx55tx27dFEK479Erv+F3cXDIntp+9RfcTtOMM7o3r74k2gYLXy/RNl08bsP741nD0i7w" +
- "IBAw==",
-
- "C=US, O=Digital Signature Trust Co., OU=DSTCA E1",
- "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodG" +
- "BmE5gGHKlREmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth" +
- "zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQ" +
- "IBAw==",
-
- "C=US, O=Digital Signature Trust Co., OU=DSTCA E2",
- "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+S" +
- "SmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e" +
- "ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQ" +
- "IBAw==",
-
- "CN=Entrust.net Certification Authority (2048)",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvw" +
- "tKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtL" +
- "A/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj/L24Sc" +
- "F2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLPKQP5L6RQstRIzgUy" +
- "VYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUiVBcAkCaTvA5JaJ" +
- "G/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQAB",
-
- "CN=Entrust.net Client Certification Authority",
- "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/" +
- "Bo6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDe" +
- "g7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173iw" +
- "IBAw==",
-
- "CN=Entrust.net Secure Server Certification Authority",
- "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO" +
- "2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc" +
- "1lB5gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQw" +
- "IBAw==",
-
- "C=US, O=Equifax, OU=Equifax Secure Certificate Authority",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBXbFYZwhi7qCaLR8IbZEUaJgKHv7aBG" +
- "8ThGIhw9F8zp8F4LgB8E407OKKlQRkrPFrU18Fs8tngL9CAo7+3QEJ7OEAFE/8+/AM3UO6" +
- "WyvhH4BwmRVXkxbxD5dqt8JoIxzMTVkwrFEeO68r1u5jRXvF2V9Q0uNQDzqI578U/eDHuQ" +
- "IDAQAB",
-
- "C=US, O=Equifax Secure Inc., CN=Equifax Secure eBusiness CA-1",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOLxm8F7d33pOpX1oNF080GgyY9CLZWd" +
- "TEaEbwtDXFhQMgxq9FpSFRRUHrFlg2Mm/iUGJk+f1RnKok2fSdgyqHCiHTEjg0bI0Ablqg" +
- "2ULuGiGV+VJMVVrFDzhPRvpt+C411h186+LwsHWAyKkTrL6I7zpuq18qOGICsBJ7/o+mAw" +
- "IDAQAB",
-
- "CN=Baltimore EZ by DST",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvMyzPUN5uEf5FbduJrFMkph57c" +
- "Vw8zrp1d0D9Co/YIyW5UcWAvc2svGeJoj1nkJlng+uf+PMsW4h9fGIInTWH7J3BDkyuke1" +
- "NcATXQFyowVDzE7aJpqHqGFj9GanwxVG6tHR6jDDu3Fqm8FDhsE5H8ZWYAIb/Ig6oJm7jN" +
- "d4YdBeV4+RO4CLbv/JZYEKObuQEyA1SD+l4b8twXGDhSDtIIfLtv4ZjATd7Sld3woSzolW" +
- "8h9aGTFYtv1jNurJI96nkZcnZXKZbMd6RMRfvpsfHsqeWBymqiNq4wYbkiTYVyIJUBWQRv" +
- "CDXraATBKBPWZvBFU6iGvQ71aHUKC51lUbnQIDAQAB",
-
- "C=US, O=Equifax Secure, OU=Equifax Secure eBusiness CA-2",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkOTmTHlIGGyg2+LKjKcXtjrIRvf7r57" +
- "R0wo//BefZnQa/Esg/DvLW0SSyEd7RcwmK1LEsmAkNHlBGsoOmRY1iaLuFGyBwMqpAzaaW" +
- "X8RxNz8E87dBJDkHGh4uYVigEgvlpd/Fq+o3ccwcyDc6uZdSp6zFaiSUTpx7z8Bq1t8hvQ" +
- "IDAQAB",
-
- "C=US, O=Equifax Secure Inc., CN=Equifax Secure Global eBusiness CA-1",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC65xeQAmWxNFU8ScJR1d+n0TeP0eeBc0" +
- "FSYJudoRcmeK3HsegmlDK13jONOi/b8pp6WnOYo1zp+4pzG1znw7+AbM2p9NYrwPf5mapj" +
- "orFHAg/U5FE6EjxsilpUhHDbwcWQz3JFy6hZwM0znT+jluuFMyEcPh4+YG52nGeFxcjDYQ" +
- "IDAQAB",
-
- "O=EUnet International, CN=EUnet International Root CA",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeQTvZQUmLKJxZFPdQaCh7TQhcZ/+FHg" +
- "umzzoyArB8fEqftokCIQxKmYvLZFF+eFq2XqlTt+/vx9+lIVmXTuIH5S18GdUqysgz05YQ" +
- "Lt2gAJ/9yuhhqVPKth0YPpwR4GPnKmdbyESV8BNVSLu+VbhnN83LABMN/E9pFGpRlOy8Jw" +
- "IDAQAB",
-
- "CN=FESTE, Public Notary Certs, EmailAddress=feste@feste.org",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhg/ObLsnn4cf0VAXNdkD+tLMTvucVXo" +
- "Ym6EB3GlU/0QMmjPqHX6TF+f61MonGf0GR2BVATnBS8PHa+GI1mV4clFNhzD5iwINdWNH4" +
- "SBFxbPewd+EYl7QHKDCRMcdPVPOEnsxZiUVtfrTJ245ClWbU3x4YTfylD9YahDnEyvK98w" +
- "IDAQAB",
-
- "CN=FESTE, Verified Certs",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqY58fOBqEBISzS5MZhKJ7YsOnqyzsYE" +
- "5VEeIEMicgNfkaeB8nZ6fggrAF6Capm4pEVr9LhFOjIqYOFlO5f68QyDMYVNnGTHzRW1ZS" +
- "U4amWz8T8sMB0jGhM1y8XeTcYjzKI5dPcPuBjrDZnq+T6raxJI0ELVFDPDjsJ0Nxh+g8xw" +
- "IDAQAB",
-
- "CN=First Data Digital Certificates Inc. Certification Authority",
- "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDfHBQeCbm/pEByIJl5toQi9NeFksUEJO" +
- "gHLgLkF5UFN5V2Pfyx5Q+HDmK5LDCXJuELFWcAphXe6I3LlewCWFLAR2UzTFafCh8EwDdQ" +
- "gVe63/rya2fry9CAD9lXlRBlewZFWOuutF7jkxUrmby2KS/7Qp9HKy5M6zQoMpkO7/9voQ" +
- "IBAw==",
-
- "C=ES, O=FNMT, OU=FNMT Clase 2 CA",
- "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCYP60ZNpM9Pv52QhT9NW/x+q0ieljjRt" +
- "Bdxlr5Yi2PMV7+tDD+UHSs1p0d4GLGSd0UEn1xC6wGwT/XBofgkInW5eMDsvInsZ8zyKpr" +
- "NkqjxD95QZ2JRi8rPmPUOFaRqh2xDUJ1TfOHTuMPTcy0bL9iE4fq0JuOtuL/GfSUCdWWYQ" +
- "IBAw==",
-
- "CN=Belgacom E-Trust Primary CA",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq2bmz1U9qTcVB0HsEYWqLcYEH2mTjWG" +
- "4nVcKtzhew/PqSjQjwHHL/ssMx/uBqh5dMzENXpyh5OrWDXaQdavFqxT4UIh1ZBm/wpjF3" +
- "3LBJOObLDA/+qnI0iNooOiFa7nQrG6TbWxMWtXNfw66M0sA+PbDL8OyLhgvCwUQYWmOo1Q" +
- "IDAQAB",
-
- "C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2g7mmY3Oo+NPin778YuDJWvqSB" +
- "/xKrC5lREEvfBj0eJnZs8c3c8bSCvujYmOmq8pgGWr6cctEsurHExwB6E9CjDNFY1P+N3U" +
- "jFAVHO9Q7sQu9/zpUvKRfeBt1TUwjl5Dc/JB6dVq47KJOlY5OG8GPIhpWypNxadUuGyJzJ" +
- "v5PMrl/Yn1EjySeJbW3HRuk0Rh0Y3HRrJ1DoboGYrVbWzVeBaVounICjjr8iQTT3NUkxOF" +
- "Ohu8HjS1iwWMuXeLsdsfIJGrCVNukM57N3S5cEeRIlFjFnmusa5BJgjIGSvRRqpI1mQq14" +
- "M0/ywqwWwZQ0oHhefTfPYhaO/q8lKff5OQzwIDAQAB",
-
- "CN=GTE CyberTrust Global Root",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9p" +
- "TAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6" +
- "XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQ" +
- "IDAQAB",
-
- "CN=GTE CyberTrust Root",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6jr11kBL65Xl0stn3JtQOQR3pNgdWct" +
- "W4adpU1LHWeG2q4zs9o4Q3JcevrwTcsyKx6W2+gm3rjS+9tK5wHqLWbiAxUeZWXHNSsiNQ" +
- "Trz7mmdAxIYRRsdDIrrqAE9scs1hnN7L+u4w0ub6W53Fmdwg+Dm/ZIwHVju93Gxe9r/h2Q" +
- "IDAQAB",
-
- "C=US, O=GTE Corporation, CN=GTE CyberTrust Root",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7" +
- "pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3" +
- "FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44Aw" +
- "IDAQAB",
-
- "OU=ValiCert Class 3 Policy Validation Authority",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFl" +
- "LWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2" +
- "bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPw" +
- "IDAQAB",
-
- "OU=ValiCert Class 1 Policy Validation Authority",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSL" +
- "wxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+Fiw" +
- "nRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQ" +
- "IDAQAB",
-
- "OU=ValiCert Class 2 Policy Validation Authority",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZU" +
- "cOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XB" +
- "hVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9w" +
- "IDAQAB",
-
- "C=hk, O=C&W HKT SecureNet CA Class A",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBuiCqVMc2NGUUh0Y6i0jBbb9M" +
- "hn3qFIAv/Lo8+n39mxMeDjLihxBKZkWsZc/tCnuOo+Ctr7EX9/JCheyIqsbniqyKIYOZ5M" +
- "UNHwmLXvpLIbYGu/+XO0C3X5Irvp5YGgldJ2THzTp/5dlRXtB9TH3mAwAO7yLpTxhjLlWV" +
- "Ho34CiKgDvPIhdEeMAX1TkDEcQbLD1+DN2HDRmW9S7NGM502aUOuzNIinz9hK71CEpN6VE" +
- "Td+JDAQMfUF7h/MWwUMpZLTWRWerhkxljwG36mOMTnhUREcaU4aMaxgnIQvFVmYOJfbgea" +
- "xoAHTpmmQ8SU6e4B3IiBtQBvddCfiNixP9XQIDAQAB",
-
- "CN=IPS SERVIDORES",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyYXZhkJAk8IbPMGb" +
- "WOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1gf/+rHhwLWjhOgeYlQJU" +
- "3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4Nu+z4cYgjui0OLzhPvYR3oydAQ" +
- "IDAQAB",
-
- "CN=Microsoft Root Authority",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQK9wXDmO/JOGyifl3heMOqiqY" +
- "0lX/j+lUyjt/6doiA+fFGim6KPYDJr0UJkee6sdslU2vLrnIYcj5+EZrPFa3piI9YdPN4P" +
- "AZLolsS/LWaammgmmdA6LL8MtVgmwUbnCj44liypKDmo7EmDQuOED7uabFVhrIJ8oWAtd0" +
- "zpmbRkO5pQHDEIJBSfqeeRKxjmPZhjFGBYBWWfHTdSh/en75QCxhvTv1VFs4mAvzrsVJRO" +
- "rv2nem10Tq8YzJYJKCEAV5BgaTe7SxIHPFb/W/ukZgoIptKBVlfvtjteFoF3BNr2vq6Alf" +
- "6wzX/WpxpyXDzKvPAIoyIwswaFybMgdxOF3wIDAQAB",
-
- "CN=Microsoft Root Certificate Authority",
- "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA8136gGfUWqepDCyQINA1CDx1hM" +
- "23B4mcidrezsNg+pFoWp6UcSkYdnzC4MgldpQOWPoENDbm36/3gLrpWAsrk+WdBeN3IpH3" +
- "NGQ8IpEdXuEJkLwU/vx1WBnhebcHkqOuiFkI2J8HygNY/GgpbTLX0qjLS/zhC0gyT+bruK" +
- "1P5FxvE5SZ25XVdduoGreUkbR3W/VIDI9qeX0UcAR9ba+Q9dpw2Ee3v5svbOcFt+ERYKx5" +
- "kRR8xdam5OF+1cN+5ZLSPAC1NoLeeeFt87Vu+J8zyctSfXOYNtuLoWuilZebo97CTSb/Bp" +
- "ZnJQbI56zk7hIzlTGZyDUITjTKeVPVtb5jMllANsClTgRNPdtbBzPkWL/vP1Nk2EJZNVf9" +
- "D0V8JARNntY4dBGXIpDOaER0km/VS2+whuPHNkKg0PzBwFr5o2G5MEdxlgoWsJHAQpXvEH" +
- "8oauMqH7HkzQM/d3EExyD8SQ8dRYik18t+iK2OLexF28RRBMkq/OyGnpoRl1vezlOI5uK3" +
- "/ayVwihA2+8EkN+BMznZskWlI4cGpVWJMbsGLWAOQRh9Hy61l8sR6xXVJKWU7xUUif1Lc/" +
- "oyW/zRMwD5WWJwBzLqLqtALXvK3SFnGzCZjxaqI6hB0bBuEZs2xN5AdJzhWGXBYB56WzjI" +
- "j7sEJnzUFkDltmtsqob9AL/OwTUCAwEAAQ==",
-
- "CN=NetLock Expressz (Class C) Tanusitvanykiado",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDr7LBsYYojJa9gIOPZn/yTC9tdjbChs0" +
- "A6gs79deB4MgOGWoaVke1T+p1A/Obo3dlbegO9XfM7DMNReZutVaDp0AMQrwq6FELZUiYR" +
- "IsfSIMyCpJqp/riBdp1qt9I2dT6xhgn2bm1+Trd67K5xhPYEMwglMut0rBZExuRAkx1/rQ" +
- "IDAQAB",
-
- "CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeL" +
- "Vu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX" +
- "9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8Wg" +
- "D/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7tqyF" +
- "/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCo" +
- "R64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQAB",
-
- "OU=Tanusitvanykiadok, CN=NetLock Uzleti (Class B) Tanusitvanykiado",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBN" +
- "wcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX" +
- "iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvcQ7GhaQ" +
- "IDAQAB",
-
- "CN=Post.Trust Root CA",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1n8T5A0k2Nj76bbDsVKjTty3O+" +
- "L3Dl+B5gHwpuY2cNgTc6H/UgiQ8hW88jIcqNfhBhB7QaiUxz89RBXcgFHnMP5TSPWQX21t" +
- "JeBgu6D71sYp+E1wUBo3oA7NeCq2aPOZ1AyOXhJi/8JfWporiEequ6HZdfAsXP5twrFbMc" +
- "yDhxqnvpAO6BBUU1ILnEnzgAL+byemo1cwuNu40AAEA+Tl1EMG66toTWgm0pk0ueASln9L" +
- "u2tuIXHmCEVKHWYNN8kD4dHK3LEvcPa3gWKWG2Sn/rvhhutBn6ic2Mqg4dYv+A/hukA492" +
- "3RpcpMGciW3MxJHAq206iROvna7B3Nc0okPwIDAQAB",
-
- "CN=PTT Post Root CA, 0.9.2342.19200300.100.1.3=ca@ptt-post.nl",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsH7iOgHxSK1T1HHO276A4FCtma" +
- "KEeto6JyQ6EYE2Eg3mo5mOpMwmtQ5hxu4oq22G3y6XYfpAacmNjMQxe/pSXlZMIJ5gGl9s" +
- "SnjJiTyflYasd2cOpg5C6CxiSTJLBD4yQ5AOCiLKyHQOhe+DgcVb8ttshQhvTialBqt245" +
- "iiTl7EgODo+8zpMGzycmGuJ35T1BWUD9KPeYLZ9o+rxhPmHJh0SwBhDnlpVPKQsqMJAWX3" +
- "BEdsTvopK/AOBheT3ILAEd6PsDBGWUhKZs42r8fPMdGSdBQj1aq64InbEtHs1GkjuAsWST" +
- "POGvninF98aB13uwGqZ+Ixxv/WOmn9DBt8IwIDAQAB",
-
- "CN=Saunalahden Serveri CA, EmailAddress=gold-certs@saunalahti.fi",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5wQp3NbgUtPWTwCvHIGIvzxUcv" +
- "OeeWP9y2DaDHxyL8obqeIQaWd6OZ/CoCXMg4ONgxEcuP3n26mIowySIVfBquLqM35KZgO8" +
- "c43SHCn9x39D7Y/rV3uhQb9NczFKNyi0GFdYPGhwUJO6EB14zZPDwoLvuN8PDFjVMFdDOh" +
- "QlKjhZBrREzdvJXkbyS7gcQ0GB0j5Dsq4hnhtKgHymyrP0JqkuLPi39zwYD5sybxEJc8TN" +
- "L+jT7Ek284GN2ML/0Bpt3dgUvzLQ6cMNPgiv7dpLnWrPE4uQgmn612cjYUtb/aWAZB1696" +
- "XT2ncceLtR++dGgJBxcbYW+EO0Gb0Yq952ewIDAQAB",
-
- "CN=Saunalahden Serveri CA, EmailAddress=silver-certs@saunalahti.fi",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0neMvIdsNk5TqmhgRbgjd2fj7k" +
- "mC5mx/XpJdtRxhUteoYEsW+ut5fp1MkulXe16GMKkoPH030SHidhoZw++q2u74AZ4aOSov" +
- "k3UDZj9uKU2NhGOMpx8VlLQ0SbTk00GruvvEXLWecvUoyjKCY0zHRPi0HcSKCldVkK8wiV" +
- "QOp2gm00AHIrPOPKP7mNckPN58gkm0NIx9JNtkbmSy6f+GyKx+q1Pk0kH0EYTuR0wIHUTm" +
- "Vk0AfNqJQjnveAjRhea+XJ4zuTX/HM70g7XyZMUxSKm0rMXYPIwabab/Qq3z+EvOrNrFir" +
- "APAyPB9fPHWX8w8d9mHVoxBaJGHTnkVbOtDwIDAQAB",
-
- "C=hk, O=C&W HKT SecureNet CA Class B",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn+AlkQ8EV8LHXLFlAmYPqP3YMQ" +
- "5vgmz5wx6w46C9OERSx4x2EnhMfsIrjIrk+dwK4JVF3+seftJE+AMVAOzEsTx6tk22lgp3" +
- "vAdg7/C3N/6J/bLYB6tS/oI/vDVnM9n7LNy1WGGiDLF9lNGohGkkPZfNmwhMUImBmh/Swi" +
- "BvzD8OZcThSEncO/nlKjEHbqZrR6gZWq7ToXS1vMLbOT36q7DwySIJ1DxGaGwuLh/4qIwR" +
- "oXY1UpLXq4gh3L3pnNn4Pt4wMUwCIi9XZrtWcjk3UJmvV9D0S9Qp7alvxtOyhpGLHRBtaB" +
- "Zk8Q5tv15n/bKOcGXnb3K8RHWrAXb/N2RFIQIDAQAB",
-
- "C=US, O=RSA Data Security, Inc., OU=Secure Server Certification Authority",
- "MIGbMA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6z" +
- "V4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXAT" +
- "cXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAA" +
- "E=",
-
- "C=au, O=SecureNet CA Class A",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqaN8+JCzjoRM4Aq+qxIqjQw+L7" +
- "XdmxCIuWq3h3Ugt0vvIiMG6/BWMvfLLXDFA2+3wdDDZhMCvVVJh4fpLZ6l5XY2q+JkJViI" +
- "wxsbAvBdsY+fE03CUim0EDVPNoivCy2BCCRhw2iNWm0x6FQZUxf9pxP2QJmmqCnAn0J7Jy" +
- "nB7tvvjQNkJYGx/pUaHtoQQWIbVn8YGEiY0k1LwRhot2lna2RMbo8CvxRpe/ZEIxDpLrxe" +
- "Ys1bnMyjjoxRgbSiorG8qMnoKpiqu0sVoeHpkHqef+hlBegRcXpv43XeVT/L2OrIAM0llH" +
- "JkHu99ED5NL5F5vQLq15DBSWhuWRQl4t3dCQIDAQAB",
-
- "C=au, O=SecureNet CA Class B",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApmPZxhVadudGZcc0kfl73Va7+J" +
- "Y1LinKp30KHvcxUuhayNPPOQFOW/AfsbhK0rNHQ2Y/AUBOMEnhD/3rEmN4zPYWYhj1b2n9" +
- "fm4zdiGjwIgP6uYl/KmXzBhyxzG2C5vNwsV4YWNFrDSmJ3hoxL1SaM6ETdIkpShsgObK5s" +
- "/mmp5QeM7zNtKjQ1ocBq/LIO7QLMREGJBssZFkZbm3hYNLqJGZxeCc97hQ19OwT5rtY/tN" +
- "9NQoJDqAW3uTjMUFhK87hv6BMce2nV8a6pB7sEZesghSAFcNVVKDeJVK/WiPntlQtktT+v" +
- "KFApVOOPWDp5bUMT8/p8o3U9zFL20adKbMvwIDAQAB",
-
- "C=au, O=SecureNet CA Root",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApyi02Dz1v3oGkb2lQkyzfJ6IZp" +
- "nF2xfURVTDe8DwJFZmmL9E4HkTdmiu3Zp0z6Lpl+bBwKnD9yzVNjtzna+C2twOX1Ov625Q" +
- "16jwqo6rY9Kbdf5VCnzRs8BZk1Eqh2mKGe3k19eOFKu1GVizzmzgTYLTA4TBqwAYekmoFX" +
- "0IyQFgJ5To+wlgntE/Ts0To3j9ZfcRX/abADCMIu0oiWUb0x9he8Mjo+PGgPmD8/e63oZ4" +
- "X/aVw4xqSCJlhdMiefb9RBboD2EENip1xtviZRQnYtyCXJYSMw5MGNX2PJ2xzWEcsYX5A9" +
- "G69kzW7p990ZIh8PYKFqQ0h/dWj5O+l69SpwIDAQAB",
-
- "C=au, O=SecureNet CA SGC Root",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp1uxDYpTIbpSiDiQQmVE/Vbrc8" +
- "WF8wYx5Qj8jLHVescLIwq8WgkiAfinwN5XdDGLrTbMXnP39kTwMcr1LKIF8wocMHqGM+JG" +
- "U/Zk1kersVOUY3fEYtMvC+pfsHUCXvgrzybz3tKt62V/vC5BhPyZmumBG6ecZsf49bKEGy" +
- "B1ciHHhP8CRswPpmmFfVkh1Q6nXVYVT8wfQSx/Zhuv691Bo+yp5lZK/h6nxFwiny/gC3QB" +
- "cMhzgwoHpGie5FEOjXQxL6LG2ggQK+8lPmyGtUbnl4PAq96wrgYa58j7736tjrCaRfGb9b" +
- "HoMbtkAL9/kWbNqK+V6hM6Akxb68CT5EH8rQIDAQAB",
-
- "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA1",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2aHl6pLrn0syNr+" +
- "hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJFuHuBl5KB12rPdFQ" +
- "uJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpXizjwJh8x/M80jo93wT/jq1" +
- "Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwLGZOhl5zjkWkfaOQvfRBtj2euwRCi" +
- "sF5jSpf35niprSa7VMnftO7FntMl3RNoU/mP6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3" +
- "Lg59v5iynDw0orM4mrXCoH/HwjHitPCCL+wQIDAQAB",
-
- "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA1",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2aHl6pLrn0syNr+" +
- "hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJFuHuBl5KB12rPdFQ" +
- "uJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpXizjwJh8x/M80jo93wT/jq1" +
- "Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwLGZOhl5zjkWkfaOQvfRBtj2euwRCi" +
- "sF5jSpf35niprSa7VMnftO7FntMl3RNoU/mP6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3" +
- "Lg59v5iynDw0orM4mrXCoH/HwjHitPCCL+wQIDAQAB",
-
- "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA2",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlnuSIz9g3wk8WIAI42MJl+jkC3" +
- "Vh1M0Oo/LjHkO6g/+6gVwvyN6Qi0wOLyn5B9aOs6Yor4Iqe8K0Zkxx9Ax0GrjbGuhoN6n5" +
- "oaJuHCjNbCY8jyoznp3LtHnE2WQ9lcYzqEf75QcJ3PZtuCVCTMP7Su1bLtQHqOWTECSTWG" +
- "59wdAez+kp19C8X0zwFRbD2MLO41sXW5SLKGsUZyQ79FLsDW58TrSZAtvJ8w+CqwH0jN4W" +
- "cMa8Fwdh/xFAhOosG3o6sANhB6qWjdDauYOO5J1RaXVxZIG0iFXcEIPOLaX1MJZhLjsK/I" +
- "dfnFyCdRMe05jR7cntchYcDAbcWSB+8F3v9wIDAQAB",
-
- "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA2",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlnuSIz9g3wk8WIAI42MJl+jkC3" +
- "Vh1M0Oo/LjHkO6g/+6gVwvyN6Qi0wOLyn5B9aOs6Yor4Iqe8K0Zkxx9Ax0GrjbGuhoN6n5" +
- "oaJuHCjNbCY8jyoznp3LtHnE2WQ9lcYzqEf75QcJ3PZtuCVCTMP7Su1bLtQHqOWTECSTWG" +
- "59wdAez+kp19C8X0zwFRbD2MLO41sXW5SLKGsUZyQ79FLsDW58TrSZAtvJ8w+CqwH0jN4W" +
- "cMa8Fwdh/xFAhOosG3o6sANhB6qWjdDauYOO5J1RaXVxZIG0iFXcEIPOLaX1MJZhLjsK/I" +
- "dfnFyCdRMe05jR7cntchYcDAbcWSB+8F3v9wIDAQAB",
-
- "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA3",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmV4egJZmI2TOnIwAPgqvCOm4BO" +
- "CEuG1TdU02qLXg14xOYFW2A5ebWhqn87o92ZqUMXZ0I8n37BJd2CDUHekbojd2BA8+rBZp" +
- "O+H/EC9WJeQzUBMJzE4Oq/Dkddtx1fxKze3bDzUFFdWwZntCeyblWeK1x8Cyx6FD/Q8vC4" +
- "MlJVeBu7vRNTB0kZCyj59o1dJDt7JFqSPAVtiHEtNz/stZ6q/85x9eVEUcqm2Vk2JHQkFe" +
- "T+s2Bw4oeFQKfMDDJBOGAwK5rHaSSlrdxdzs+LPbK7UbNud4gkyVfiBWsnUcfZfvf5Q4Ka" +
- "IA4tHqseM0NjFAWLiqt86BGgwXgQ3967jTvQIDAQAB",
-
- "C=hk, O=C&W HKT SecureNet CA Root",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBiikFaM1l2/RliRJ+qddeCk66" +
- "JQcIdFSUmSa7c5AEt7qNpA4eYNouA3AUhNznLhXJPTw/mSDSTvSM5HKsutkjqq1pWy8hme" +
- "PpV8j2ACdJMWKGn+O+5deJMcejwj6WE5bMUwLR+EkgVx53TBQkfpMLGjFww2Y89Q0DKoh6" +
- "VAYhQROPvOL40zsIvpjnD7sJ7HXQPu9uWNcjzIvFSSz8qQ38jbrwXx61DK0QWsBbQBFZb1" +
- "6zihafeDQ+g8pl2lLLokFi/7DjJwphLWmTb3axuj5/zHG8jYL3XRNbPpwtaPBB3BtX4EOz" +
- "iJ5KMj8P3KvczrnRcGFXLt0Ob71m+z8Z0+uwIDAQAB",
-
- "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA3",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmV4egJZmI2TOnIwAPgqvCOm4BO" +
- "CEuG1TdU02qLXg14xOYFW2A5ebWhqn87o92ZqUMXZ0I8n37BJd2CDUHekbojd2BA8+rBZp" +
- "O+H/EC9WJeQzUBMJzE4Oq/Dkddtx1fxKze3bDzUFFdWwZntCeyblWeK1x8Cyx6FD/Q8vC4" +
- "MlJVeBu7vRNTB0kZCyj59o1dJDt7JFqSPAVtiHEtNz/stZ6q/85x9eVEUcqm2Vk2JHQkFe" +
- "T+s2Bw4oeFQKfMDDJBOGAwK5rHaSSlrdxdzs+LPbK7UbNud4gkyVfiBWsnUcfZfvf5Q4Ka" +
- "IA4tHqseM0NjFAWLiqt86BGgwXgQ3967jTvQIDAQAB",
-
- "CN=SERVICIOS DE CERTIFICACION - A.N.C.",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsiov7CtZakOTiUYqiuXs+gX64s" +
- "jeQWuvA9sAWu9IN89XifvdyZIQ3ncDlRyQPse2ZyU7VZjv2Tz+JuSKO0SpdDeDCncndLip" +
- "ca3dlxPSyqIuuLqdyb5Z6Nly8oqFZhxHXrSHgtYP32cmpr02sfNdkFBRdjIsOy+qX2Fe41" +
- "TVEl3/DY0Rx4J6Nt/hTBbEdN0tau/QsfAzp/6/N2dDEi55SpSvhPsHEQhOMJN16QFUzsXe" +
- "FIbwrq6bciUPRHfi82yveZwuSceemHYyFpq8AN7gtCAFkRfdgBUU7jZBxCGP7tkAShnGcW" +
- "GlEV0AO+SndGw6Sm6D4HoxXCFl+AiHQodn5QIDAQAB",
-
- "CN=SIA Secure Client CA",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDS/LBAYGpmY1Jm5mkJcY2BmB4dHfPgSQ" +
- "3IK2/Qd1FFxZ1uo1xw3hV4Fh5f4MJi9H0yQ3cI19/S9X83glLGfpOd8U1naMIvwiWIHXHm" +
- "2ArQeORRQjlVBvOAYv6WpW3FRsdB5QASm2bB4o2VPtXHDFj3yGCknHhxlYzeegm/HNX8ow" +
- "IDAQAB",
-
- "C=IT, O=SIA S.p.A., L=Milano, CN=SIA Secure Server CA",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA28ELzCfTEiIuuWQWdKxZJ+IqkA" +
- "CSntWYXCtRbhsTb1RvShCihethC+ztnH7Of2WTbsxsQZzILarGs5v7THCcEXXzcom6iQCt" +
- "xy5J53PagLIs/vKXmfQCGzQvOaqL5u8F/Ln1ulR/ob+OHkg2Mwl0Yac9x5skx8OJzcpOKD" +
- "EjBhxiFY7fTxtrLUri9LDczvOQ/XmBE8E+Lma8+SJNCy9iM42oK+rpb3OnN5QEL+leTQ3p" +
- "7XwyP3lK5jp2KSBQ84+CRHJsMDRIWKpdGz8B6yHs6n6oK4Rd9sExlU8pe7U1t/60BlewFN" +
- "fyVVmMupu5MT/lqqrvJXCVkjZB8VWfwQhEnQIDAQAB",
-
- "OU=Public CA Services",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwOeC2xUTrnnCtF+SjyO8uvfG0Q" +
- "Cv1lRp8V2mYvhh0Zzeyjss6VwWJzTmuNHKdO8leGRt/hzoiXMxU2dnhsStamjnClZEgzpY" +
- "R4l3Gtpv8vkHQMk9Ae9q0dlrhJ7FaytOtyz4pGpXq2gxuhlmuuwbV/vOStZLeMPBgT1Llj" +
- "CZqcMt4uQSJgqkYxIc1HfIgdSnVUMt/ARWndwLrrdsCtozkIgFyX5UgujSMtDXAUkqNZB5" +
- "OXPWi7xhzYdtUBUFTKnoSkcxiwXM5flC1xJg+Do/o6k2GqWGNiymBIMJ9lLFsH0fiEGQmM" +
- "VlaJYQshPJFkm9Kr6wSKfC/S1eVtA3TVhR+wIDAQAB",
-
- "OU=TC TrustCenter Class 1 CA",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwKeu0drOu17ZbtF7nveOxnEkEV1uhq9" +
- "l/Exv9umGr2Odx3y0AlF1RSH0j73VihJA8Ch9ZEXQvjoCl/TACPSlSzXIaSSGcvMtSjkih" +
- "Y5bIEIUwaVd0RcBahsbVPeBoV30xaiSNRZc+MX5oZjJuJG3sMjbJQcrwMUTIo2HKG6A2Hw" +
- "IDAQAB",
-
- "OU=TC TrustCenter Class 2 CA",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaOOjtMgApcYMBDb+MAdzaxq05pKmKL9" +
- "WLXGhfUMZi9Wa9ypEi7KodUdc9s1Gyg05dy0mw8ExV5Wstx4ULMBySToLUygLt92++3ODj" +
- "FLgFU/Ka9FaLWp6Fk9G0glauTbuoS1cWvP74WJ74KY2we814yU+si2cM8Zz7/FebV1xPDQ" +
- "IDAQAB",
-
- "OU=TC TrustCenter Class 3 CA",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2tME1BS4NjeygQGocDiemUJJrUBsH3i" +
- "7ndszg2vyEqF6MY2orTdlOAnYRwQvyjXnKALbxsA7X+6QXPa+raXqWJ7+vM6GaKlmqxLU3" +
- "CPISpTG2Q/UylnEoKKuNKIbfu+7jDH0w1sNSq49dJ5xrwKPnBWtXSUSzbupkz9KOelB3dw" +
- "IDAQAB",
-
- "OU=TC TrustCenter Class 4 CA",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/L2PWNnuyDdNV9WRs5iVdxrTIFLolOI" +
- "PrVmKlVallo/QjmcJLudDNVGemo6CjqTMrduS9rXey7VwSdMPFtg9SmnKTQ5BiZhUPRaXd" +
- "4N24b0BuV8F5cqNgqrp2HRKJU1r8Ar7hCRPFSi/cPYsZrdeLJEX7TPTNXDUdKUxR8/JsVQ" +
- "IDAQAB",
-
- "CN=Thawte Premium Server CA",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSNjZqi9fCW57agUFijzjuSQRV1tDvHB" +
- "uVFkfvGEg1OlL0K2oGjzsv6lbjr4aNnhf3nrRldQJN78sJoiFR2JvQZ9C6DZIGFHPUk8uX" +
- "KgCcXE4MvPoVUvzyRG7aEUpuCJ8vLeP5qjqGc7ZGU1jIiQW9gxG4cz+qB430Qk3nQJ0cNw" +
- "IDAQAB",
-
- "C=hk, O=C&W HKT SecureNet CA SGC Root",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqFNPj0Pdr+zBtA0bX7cIoprIQu" +
- "Nt1yUa3+DKvC8iJPlpIr0arVHncfe1dtTzPsg+EdBNe5keGLeezT5hG0URS1sm3Ck8AE0R" +
- "2h2Pnh903hVAvDDJD9/4LXzYjZ2g4J+wzydgzzgRCO82L3xONh0mAqf01FBDgUnr3beWFD" +
- "BjMtEDzSG8N5EePmWuFoL2FWBLUTuW5RnowvemBYE6qH8YWD53w1kAg/T1eUlgpy4DPgH9" +
- "heLfoZqJ2fhkCiuEzUPNJTUAXjBmdKHHCHWsSSeC17CVNW4dmYDrkqAtWtY4u7VHJ6sazL" +
- "9TU8FGsm/o101XEd2wNUgfqybqVg24CjC22wIDAQAB",
-
- "CN=Thawte Server CA",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTpFBuyP9Wa+bPXbbqDGh1R6KqwtqEJf" +
- "yo9EdR2oW1IHSUhh4PdcnpCGH1Bm0wbhUZAulSwGLbTZme4moMRDjN/r7jZAlwxf6xaym2" +
- "L0nIO9QnBCUQly/nkG3AKEKZ10xD3sP1IW1Un13DWOHA5NlbsLjctHvfNjrCtWYiEtaHDQ" +
- "IDAQAB",
-
- "CN=UTN - DATACorp SGC",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLi" +
- "t6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZD0/W" +
- "w5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK4ESGoE1O1k" +
- "duSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykqlXvY8qdOD1R8oQ2A" +
- "swkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv33i+Ybqypa4ETLyorG" +
- "kVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB",
-
- "CN=UTN-USERFirst-Hardware",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsffDOD+0qH/POYJRZ9Btn9L/WP" +
- "PnnyvsDYlUmbk4mRb34CF5SMK7YXQSlh08anLVPBBnOjntKxPNZuuVCTOkbJex6MbswXV5" +
- "nEZejavQav25KlUXEFSzGfCa9vGxXbanbfvgcRdrooj7AN/+GjF3DJoBerEy4ysBBzhuw6" +
- "VeI7xFm3tQwckwj9vlK3rTW/szQB6g1ZgXvIuHw4nTXaCOsqqq9o5piAbF+okh8widaS4J" +
- "M5spDUYPjMxJNLBpUb35Bs1orWZMvD6sYb0KiA7I3z3ufARMnQpea5HW7sftKI2rTYeJc9" +
- "BupNAeFosU4XZEA39jrOTNSZzFkvSrMqFIWwIDAQAB",
-
- "CN=UTN-USERFirst-Network Applications",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/uRoeQ2VYWsBjRboJpYsvi1Dw" +
- "V3g64ysXaSaOwjSsl2P+Octjd5A7mraY0HJbYZZ+SwGxhzYUrofs3TL2TjpnwM+heAow1H" +
- "iU9RcS/u/D/5uBaAh4mTJSCaQ4JpJHYoWTWhHcB/gwZkFiAs00mkhbTAYX9RCPhoFZGAy6" +
- "XV7js69IQEXmBZp4w0cu64eMXROxJKb35lJ7mkVcW5b0OkxR0smcBSpHhMFbNAmAhrQ8YB" +
- "sHp79WscIj/L7/+o0DpLdhWe0tHGLuPbVxsyorhv6IamP3Cr5XCSq0QeQFD7nKNi5GxuoM" +
- "je4oBC+ukv6M4yBI98jbccozU8Fd2ew66XpQIDAQAB",
-
- "CN=VeriSign Class 3 Public Primary Certification Authority - G3",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy7qcUvx4Hxoebxs3c734yWuUEj" +
- "BP8DZH9dCRCvUXyKVhwRZATfuKYZDldiDBEQZ9qyxupvURQY76La0qYVmkZyZM0Oi8Ultw" +
- "IARY0XrJpGm8gxdkrQWLvNBYzo2M9evwQkkLnZcnZzJu4a6TFRxwvCBNLxjekojobIVXER" +
- "rpfuMmEVSiRZZVg8owiejc2KPtKoA/f3llVz4VIGYIL5WTv6pHL6hGl/AS4v7CCitR5nbm" +
- "t0a34g2mzKjDTFlVieboU1wc6p3wYhYLp8lfDPDewnbOr/dq8vpBpqIzFMnlemPTnmI31Y" +
- "Vlng7mUyR0G14dElNbxyzng0k7Fa6KaLlXlwIDAQAB",
-
- "CN=VeriSign Class 4 Public Primary Certification Authority - G3",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArculEWnGWavxj7UZD1bOzLUfIO" +
- "SeJiVL4HNliVne0IPk9Q+1u63xfOgh/OToDO58RSIZdpK0E7cgWwn6Ya6o8qWNhcIq1t5m" +
- "NtKbAvSokmB8nGm0jyQe0IZS9jKcQVgeIr3NRWKVCG7QZt1ToszwENxUc4sEoUYzM1wXQL" +
- "meTdPzvlWD6LGJjlp8mpYikDuIJfLSU4gCDAt48uY3F0swRgfkgG2m2JYu6Cz4EbM4DWam" +
- "m+rJI1vbjuLzE44aWS2qAvDspIdm3ME/9di59OyCxtI9lR3lwE+EydmjRCgGatdFrPBrau" +
- "9OX/gRgh44YzRmUNQ+k3P6MMNmrf+TLZfvAwIDAQAB",
-
- "OU=VeriSign Trust Network",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRN" +
- "zjMHPVKmIquNDMHO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDH" +
- "qGKB3FtKqsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHw" +
- "IDAQAB",
-
- "OU=VeriSign Trust Network",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRN" +
- "zjMHPVKmIquNDMHO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDH" +
- "qGKB3FtKqsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHw" +
- "IDAQAB",
-
- "OU=VeriSign Trust Network",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm" +
- "1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71" +
- "lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZw" +
- "IDAQAB",
-
- "OU=VeriSign Trust Network",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm" +
- "1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71" +
- "lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZw" +
- "IDAQAB"
- };
-
- public static boolean alwaysFalse = false;
-
- static class entropySpinner extends Thread {
- volatile boolean stop = false;
- byte counter = 0;
- entropySpinner() { start(); }
- public void run() {
- while (true) {
- counter++;
-
- // without this line, GCJ will over-optimize this loop into an infinite loop. Argh.
- if (alwaysFalse) stop = true;
-
- if (stop) return;
- }
- }
- }
-
- private static volatile boolean initializationFinished = false;
- static {
- entropySpinner[] spinners = new entropySpinner[10];
- for(int i=0; i<spinners.length; i++) spinners[i] = new entropySpinner();
-
- for(int i=0; i<pad1.length; i++) pad1[i] = (byte)0x36;
- for(int i=0; i<pad2.length; i++) pad2[i] = (byte)0x5C;
- for(int i=0; i<pad1_sha.length; i++) pad1_sha[i] = (byte)0x36;
- for(int i=0; i<pad2_sha.length; i++) pad2_sha[i] = (byte)0x5C;
-
- try {
- if (Log.on) Log.info(SSL.class, "reading in trusted root public keys...");
- trusted_CA_public_keys = new SubjectPublicKeyInfo[base64_encoded_trusted_CA_public_keys.length / 2];
- trusted_CA_public_key_identifiers = new String[base64_encoded_trusted_CA_public_keys.length / 2];
- for(int i=0; i<base64_encoded_trusted_CA_public_keys.length; i+=2) {
- trusted_CA_public_key_identifiers[i/2] = base64_encoded_trusted_CA_public_keys[i];
- byte[] b = Base64.decode(base64_encoded_trusted_CA_public_keys[i+1]);
- DERInputStream dIn = new DERInputStream(new ByteArrayInputStream(b));
- trusted_CA_public_keys[i/2] = new SubjectPublicKeyInfo((DERSequence)dIn.readObject());
- }
-
- } catch (Exception e) {
- if (Log.on) Log.info(SSL.class, e);
- }
-
- if (Log.on) Log.info(SSL.class, "generating entropy...");
- randpool = new byte[10];
- try { Thread.sleep(100); } catch (Exception e) { }
- for(int i=0; i<spinners.length; i++) {
- spinners[i].stop = true;
- randpool[i] = spinners[i].counter;
- }
-
- MD5Digest md5 = new MD5Digest();
- md5.update(randpool, 0, randpool.length);
- intToBytes(System.currentTimeMillis(), randpool, 0, 4); md5.update(randpool, 0, 4);
- intToBytes(Runtime.getRuntime().freeMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
- intToBytes(Runtime.getRuntime().totalMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
- intToBytes(System.identityHashCode(SSL.class), randpool, 0, 4); md5.update(randpool, 0, 4);
- Properties p = System.getProperties();
- for(Enumeration e = p.propertyNames(); e.hasMoreElements();) {
- String s = (String)e.nextElement();
- byte[] b = s.getBytes();
- md5.update(b, 0, b.length);
- b = p.getProperty(s).getBytes();
- md5.update(b, 0, b.length);
- }
- randpool = new byte[md5.getDigestSize()];
- md5.doFinal(randpool, 0);
-
- if (Log.on) Log.info(SSL.class, "SSL is initialized.");
- initializationFinished = true;
- SSL.class.notifyAll();
- }
-
-
- /**
- * A PKCS1 encoder which uses SSL's built-in PRNG instead of java.security.SecureRandom.
- * This code was derived from BouncyCastle's org.bouncycastle.crypto.encoding.PKCS1Encoding.
- */
- private static class PKCS1 implements AsymmetricBlockCipher {
- private static int HEADER_LENGTH = 10;
- private AsymmetricBlockCipher engine;
- private boolean forEncryption;
- private boolean forPrivateKey;
-
- public PKCS1(AsymmetricBlockCipher cipher) { this.engine = cipher; }
- public AsymmetricBlockCipher getUnderlyingCipher() { return engine; }
-
- public void init(boolean forEncryption, CipherParameters param) {
- engine.init(forEncryption, (AsymmetricKeyParameter)param);
- this.forPrivateKey = ((AsymmetricKeyParameter)param).isPrivate();
- this.forEncryption = forEncryption;
- }
-
- public int getInputBlockSize() { return engine.getInputBlockSize() - (forEncryption ? HEADER_LENGTH : 0); }
- public int getOutputBlockSize() { return engine.getOutputBlockSize() - (forEncryption ? 0 : HEADER_LENGTH); }
-
- public byte[] processBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
- return forEncryption ? encodeBlock(in, inOff, inLen) : decodeBlock(in, inOff, inLen);
- }
-
- private byte[] encodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
- byte[] block = new byte[engine.getInputBlockSize()];
- if (forPrivateKey) {
- block[0] = 0x01; // type code 1
- for (int i = 1; i != block.length - inLen - 1; i++)
- block[i] = (byte)0xFF;
- } else {
- getRandomBytes(block, 0, block.length);
- block[0] = 0x02; // type code 2
-
- // a zero byte marks the end of the padding, so all
- // the pad bytes must be non-zero.
- for (int i = 1; i != block.length - inLen - 1; i++)
- while (block[i] == 0)
- getRandomBytes(block, i, 1);
- }
-
- block[block.length - inLen - 1] = 0x00; // mark the end of the padding
- System.arraycopy(in, inOff, block, block.length - inLen, inLen);
- return engine.processBlock(block, 0, block.length);
- }
-
- private byte[] decodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
- byte[] block = engine.processBlock(in, inOff, inLen);
- if (block.length < getOutputBlockSize())
- throw new InvalidCipherTextException("block truncated");
- if (block[0] != 1 && block[0] != 2)
- throw new InvalidCipherTextException("unknown block type");
-
- // find and extract the message block.
- int start;
- for (start = 1; start != block.length; start++)
- if (block[start] == 0)
- break;
- start++; // data should start at the next byte
-
- if (start >= block.length || start < HEADER_LENGTH)
- throw new InvalidCipherTextException("no data in block");
-
- byte[] result = new byte[block.length - start];
- System.arraycopy(block, start, result, 0, result.length);
- return result;
- }
- }
-
-}
-
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex;
+package org.ibex.util;
import java.io.IOException;
import org.ibex.js.*;
import org.ibex.util.*;
+import org.ibex.graphics.*;
+import org.ibex.plat.*;
/** Implements cooperative multitasking */
public class Scheduler {
// Public API Exposed to org.ibex /////////////////////////////////////////////////
private static Scheduler singleton;
- public static interface Task { public abstract void perform() throws IOException, JSExn; }
public static void add(Task t) { Log.debug(Scheduler.class, "scheduling " + t); Scheduler.runnable.append(t); }
public static void init() { if (singleton == null) (singleton = Platform.getScheduler()).run(); }
* Surface.renderAll() more often than that if it so chooses.
*/
public void run() { defaultRun(); }
- protected Scheduler() { }
+ public Scheduler() { }
// Default Implementation //////////////////////////////////////////////////////
--- /dev/null
+// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
+package org.ibex.util;
+import java.io.IOException;
+import org.ibex.js.*;
+
+public interface Task {
+ public abstract void perform() throws IOException, JSExn;
+}