From 48c91afd16ba1864cef9c62eb384aeb56de7fc02 Mon Sep 17 00:00:00 2001 From: Brian Matzon Date: Sun, 10 Jun 2007 20:30:03 +0000 Subject: [PATCH] initial checking on AppletLoader --- res/appletlogo.png | Bin 0 -> 5512 bytes res/appletprogress.gif | Bin 0 -> 8872 bytes .../lwjgl/test/applet/AppletLoaderTest.java | 75 ++ .../org/lwjgl/util/applet/AppletLoader.java | 907 ++++++++++++++++++ 4 files changed, 982 insertions(+) create mode 100644 res/appletlogo.png create mode 100644 res/appletprogress.gif create mode 100644 src/java/org/lwjgl/test/applet/AppletLoaderTest.java create mode 100644 src/java/org/lwjgl/util/applet/AppletLoader.java diff --git a/res/appletlogo.png b/res/appletlogo.png new file mode 100644 index 0000000000000000000000000000000000000000..626e7b4e0dc9a19fd625635dc9fde67a20f205c4 GIT binary patch literal 5512 zcmV;36?f{1P)5)=CU{(^vjetdl7^7*i?uk!i)jmhSL!{nUM>f+$wF`m=P z=JQZZPQBmoNJU26+}wnLf(41naBgluJwJGMcaxEk-SGJfjLT$UVsdbCJvlm9RaVo| z()<1XTv=M6((5QBCXkMf=JfjE;NV0+LSS89dwF_jWoLkWe!srHh=zv4!ozuYcdVdV7?Tlg-S`XJlnJ zpwzRnvMwqsOGikUmY2T0y|&%(UtC?hy1ONq(5R-T!N9=({{2!;P;YE)pPioD?)P`3hsdO(q&hb^ z5|7M2Iy=VX^AC;7MngnHKtNemSTZg!fq#ExV`N7}MQ&?s8x|OagM`u0(WKPtB9_ow zSXx3qKu$_aKRi7V4Gv34Nu<;3gOI zP5k@(=;!C)-{7gIsL;>P&dtsC_4V%U?%dnk&(6+PQ&h;u$JW)=!ok74yS&)f*wWF` zV_;!wXK2*Z)5OEXa&K_7v$L?Tu$h;bp`W13%FB_DkQ5IQjf;$lhlpNVT+q+Zm6MZ3 zsMqP~>34K>FDop$xVZlO{G-$B@a*g6<>mA9^Tfl$_xt_a+uZy1^yK5@=H=$??d{*+ z-@(7Y@$vB@9v|Z2;nvmG-QC^t{r~0U>Ob<8S+h1i88+w-|Inwv{dUlkK!eoX z-P7}syFnWE%4@&sGvMCsze;Kd^JQC@yL8*fKlBN31BM6A^~9jT<|%#BuMdFpp5h)B z=IJh-E0r1y2KPe@Ov9?ty&v3v{`Z?7dT$xMaL~+|D~639xiQckp*vLiQ7;GguR*{5 z%fI~&>v;S1R}2hmmJaOA;9hKyNQ@cP*{g5f)yL$yY`*GBsh4e@47ybx_Fiyx>poX1 zl^TsnOE#TOXHrU{$OQwfayMm0uLYMRQ4)AFD>d4yWdCp}qco*6do8$oCNsfnS`V`S zhbN5KmHPJUmEeB$CWz4Sv6(Hmp(_^1h@Etpod;YWO11Q0>e}`CNwQtPC_3?FYAQ9F zbC%Ql{!n`TDXgz`@Ps3GD|hMr#>lLl3-(Z}Q%{EU1l+5`-u&Hh6Ca$Wx*3kHWsWY) zw|kx9g%+Nth*<1e&=S$it9WO_VGG^fXMOkUDHW*CB3bRhbcfW?UC})P*MAE5wOT3Q z%ALp{jAX2xbbq(t4$$jn!*_fOUQ1d;53Z1&8DEF@UY5{%o?4GOTE4Y#+Bc~G4x-oh zge|xHemHQ^3PeulhsFmo;7UL3)`#9ouZw|1IlS&X+s#`b_Hud)(4G?!ovyI(S~@)t zfyk3R0Qb%a=@zg=AaY8{ZN}jo!Ajjfc7tuVkv^m1S^!3_`P#W}SSRN@ypE zt7zz^eIrgP3zFCVd|D`SHBGFgFtFgd5xQc|c?1_h>Mh~C6P@%#uE>CiXwQ0zINM1R zr)l{+TZH6~Lg0obhT8}CvDDWvQubq!P~?uWfzK4{$$8GQm2o&lbEV}WvQZW>1XO!O z-`~PB@8xLE&J>Z1h#aJ<5IK)hwUOu)gYAMFFw4`|FdTFU4vx@1VCH-fXw5s6u6nn7 zt}JV$$#XQBESMLH4ESd}BfV)YrTZ+g%VoC#h3B)sQ_ez{Ary-(^9+M*`t?m zE5|x+`=wa2$Y4WV%4x175LW^ZnjF_N18zMW%G>l;AuAn9k8MX|>nIG_NU7ei1@2EC zKcPI{$ZdyyKLvn%!O3aYv9^LW;ZR+EFAlB^aV7JNl{D?gpSKy^{{c^8(cv6!!cH*) znb~+mPp8-&T}L+B02i*&sdJZKe*t|j@0kn9ccas3ls2r~hhccCPx`SqxVPwKe`M(U zG(FUYPGt^-eK%;&)1c>u4#yeg2!^E65zYn70oB`x=b8#lgwmwbsEY4jevXE+)>J3x zv?dmy(##(FAe<|0fs-q^TnP$jI)^u}MItVXH!&-{07VB!8->rQM_g&SV*}hdGsIxl zXm#eAsO|rZ2LG16tF}n1(<-U(z!c3|xlx85fSXM3c@fL`5p>6wym`w+4LE2;0RZ&Y z3V0C?-hvSD`5`vIWm*MHsnO{a53Na}OCAxcjT)U+YvsxrBT9P!4sm4!+d;>wl5^q* z9Lrnog76%nTyA8@EDuGVGY+$OqTnjIe&kok&@xPLD%EZA6|4F8E)BB}PL8~eG`1%N z(nal}5x9gOpRdEXl8IT%M7XjJIiMB~8{h&8HC(+|O!e-F%bqvAOD4SEYaEgDm9FiE zD{C&WJ&R$7f(qw?a$K^qTn3X*e?DI<0w;ApN+v*Ah{1FVzcFEv>V*w(50%`QTelo) zSe;2{Qtw;7<0)^^NRG()&J`^hRPwp<%sx6+y-40#O~>T^ti2GZ8JsKY_8}s*8?H>T zmHo=(+BCC?@)g$WV5$=8&`r)4uwtFB)F5ROv%X=6-Vk}_q)xv2aH^#>z7wd=M>^yu zP=8w7fP*y{S9TdO3oh3)?MN0D7Fqmkf#ZpsvXf+;1~w{yI&}Uqzjox-y}n}M+Wi}; zVkFcnVS!=^uylIuLF-F-d615O>Omg5aZwOBi7t8mJnNA_u4GPe1AbCuJAiSe+RFyG zm-D$IXQD!`E>2WH=}<}JX4*Y~PD;P;S4;^s7~D%sw~2+~8w6f*Xa?*#4dfNfU7Z=` zkHLlJExXXNzqnwHke!AJL)Ty~K#oHf@?*C-f+*xmn za3xakJ21nQ0DBgLHS8^&&te9A&Vm-Q-Jl=w36?}?JdGtUQ>_PANllDHM5e8bbEcLj za#VgznEN741md1cJ6hRf%A2DXirjZ7y#P0?Ni>ky>(={y>4t=_i+mj_3Dqo=E(1O# z^p>HnZDmA`N>!&9Z^*^Cl8IRpT5N$!;o?xLNs+6YZ4v2v=?pD zh-G-5gzl=0wBD}(1#+KYsV$gs&cXd;Cbe~io6Lk##w7c)&)5L>ypS()q*RFn;-uig zoaaQUu%*>0Gb$&H2@%IOsY1Y&;3~4#*bP;f0pEZ{reGKDF0RDokJOKdOSe+QXK1Xz zRw3lPndkjewk1ng;USb26k{}?e5O*P)takgC%cN6`RPbkJ{L(%3R}F)>Po`13ShVr zzPoQQHl$=CLCBSstG2-9Xv{*9TQ4GV+IYZIqm-2>%3hLnLYyn-iHITHqH$s{6^)}^ zeu;A>o%x@Ks6Cvtk&%>B@Bj@(JJ|yFW08p~azBzHmn|Z4I(Yb5yb&ek$K?M9e%G-T zB8mS4*qU4SF(RAt7#E{FIZQ{#;z&UXisi;|a(dt5T$yaUKG#;H!=%oXTTdltgd%6w zz=sKwE0mRB()l=7ax?eitn<}L)3Mc*3O<1};wR7|s&K9ZDC#CnK8((g6FrgQN;Nkn zChDPh6{xK6bd=z_2-D4^$oWHgHi^m2R}r{JPxsvwEx?iO5x8e1paEwX5$1^QaYJjQ zY7&C*Xd%HB%kQZ!c3WBXA6KJ8DntuKPHRi#yhP5F8eEKf^mHFL2wBh0jl2LbV+RA! z$!MEYO1pkGhYwkq8v>bvN#jv!>@6%!)NR=~z%ScG737qPet*$ zT*(}F!UUJ;);82tJZ~x6Tx>R`*$_ER1`G#}i;A3*xW?Y)qDnZP2*9`KvV`(?U5gMU zxlG5?@%)mhHO1OoCK#iW%as<ypwjI_zm)aCLk*Xa;US_@1VBv64Fp#0hjhGCR z5KLqcj}}!Kd0WI3REH1%mDz3W6vZ~R*-m9OQ)f%$JhY-Br^PhmPT?@=Dm7H2OX$#C ztiTL7otmw{cc|i&SQ7;ZZexi}UVG18+4#RIbbJg-<-c?za=JEa+*YO#w4vma7Il&r zoh7tHoQb3;h4D%QyY8p&R1C8GO>*vjvSve>RIQ0O!ew#PvZzjlNK^gI?$-=y)mkl= z|1>Jf9@U9kIi)1Xn)=^;g5P$Ndy&bh{@wmax?ABaFOHd)pWNQo*7j_ST)3Yzt~;jZ zoNomIUT_%E%it4o?gH9WSG}$Q^C?<$oTj?5VpS&f zq5*xtqzmGEzChi@Y4>H>&jdGML}{sX+iL?jo!25%rrN(kD`&&8w0=+49(jXQ(zWz+ z%c*ZC>MwDW&6g7TdyjhwW2w(Kp!S?6BC@VKOVq_8wE@snPTIgblJ?@1pL=p(g_Qcy zz^t|0FBG2siGJNnzY-NW({y%bj4=er244mZ*MiTCRr}3xl07;oe-Q$n%9`b%Ij9L- zx(7f~%S*5!&TA5=QcWiPC?E9%Q19CQ+&=)kJVhRgD|wJr>V2v2lg@1G0y*$$4!&6D zO75VG`X;W5a0cMg-rYqj=QMy9jig5vd@Zyg^unpJA;AAdx8Pof6`VtcDWZk$uSLNr z6aLE1s3jfYhX-4ov*#N-_7M9j9&eT;6dcd$sJXZ`@%{3taiLf8LT=S4HayQbd@wud zC=u5Lz;#ROxzh*Llj91`9DaQ6_sW0 zp%bWI9ln>yt#Av-z7pjXU!#7!H!^qJY`+t#9o-lF$J12~clVJZC4eC&F_|-+Zm=dN zNq=fuO?%NMXW~+9&83WKEs~B?8QaSig%_Sz9J@O|&2lFtTVA%*nb_-Q^vO=45}>F~K?{*pmuqxcQaERkzJ(Z?T(qFjEmLy8(+$)`E(0Kla6Wdp zYjwFZu_S2GtudA%5t7NF)e~dmW!;1GMn7!{Gn9@J6angEzY>u;-4b>}xS|QvM?Z2? z0sW$viUXk%=L3bnXVKP_ebpV?6V~a2C)B)8oIfjBFs%%fN4-!}b(^M&%&#-Ru1JuZ zUpPiz1CGrGAeDFq@`_R=X`n*xq+2!&LVsh-SYmJ*u?f74iB~+mrAj39WW@Iy5TEfim0Xvr zRNvIbR}m4pYX6LwB;xjgBLC_uZ6sT~N4$0HVdQu1#F6s2i{weV5iydKAw)X>cZp29 zAK85HsV7^VlCGM`uW~d`&ed?;PNlkw)nsnVq6*UVvX}4aEw@h=fbcw!zTukF5@&g` zEAW|?KW(@E9GIL~7~!-2#GK@iq+^*N>9d_x;A+Y^H)qhMZvuBVj4PmO0t>#ovaG6c zNmO3ui-@i7y4-WK~a(+y< z@gu=69WTdXZYQk6a+;4mD%_?^o_=g;@c)84;v72`^aR`wqc}xxcf*q{f;m4eSD|#7 zS^Et9GMo7OoiR$v`Ch?rXuP*z($o8gp;xU@OzKtOz^f|^o;W&EaSjvyuq7ltSEJK@ zo(OsuH~uK=IaZGj~YLIRR2NV?||Od9RJPW0OtVb0OtVb0OtVb0OtVb z0OtVb0OtVb0OtVre*w;W^cQ`mjrQh(^M0c*o!A@R9B`xi7C(;Wfcv6vf&0P%&H>H= z&H>H=?q`GR({`?Jc_`lA|9^Z-N66y<=K$vb=K$vb*C*TG1sDJff!OKfE48Bl0000< KMNUMnLSTYg4)~4$ literal 0 HcmV?d00001 diff --git a/res/appletprogress.gif b/res/appletprogress.gif new file mode 100644 index 0000000000000000000000000000000000000000..709157cf196d3fb7018fdc8881c5e0651c8ec949 GIT binary patch literal 8872 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 NbJL`aG#47s`7gC~db9ul literal 0 HcmV?d00001 diff --git a/src/java/org/lwjgl/test/applet/AppletLoaderTest.java b/src/java/org/lwjgl/test/applet/AppletLoaderTest.java new file mode 100644 index 00000000..c270693e --- /dev/null +++ b/src/java/org/lwjgl/test/applet/AppletLoaderTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2006 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.lwjgl.test.applet; + +import java.applet.Applet; +import java.awt.BorderLayout; +import java.awt.Canvas; + +import org.lwjgl.opengl.AWTInputAdapter; + +public class AppletLoaderTest extends Applet { + + Test test = null; + + public void destroy() { + super.destroy(); + System.out.println("*** destroy ***"); + AWTInputAdapter.destroy(); + } + + public void start() { + super.start(); + System.out.println("*** start ***"); + } + + public void stop() { + super.stop(); + System.out.println("*** stop ***"); + test.stop(); + } + + public void init() { + System.out.println("*** init ***"); + + setLayout(new BorderLayout()); + try { + test = (Test) Class.forName(getParameter("test")).newInstance(); + Canvas canvas = (Canvas) test; + canvas.setSize(getWidth(), getHeight()); + add(canvas); + } catch (Exception e) { + e.printStackTrace(); + } + test.start(); + } +} diff --git a/src/java/org/lwjgl/util/applet/AppletLoader.java b/src/java/org/lwjgl/util/applet/AppletLoader.java new file mode 100644 index 00000000..a813d76a --- /dev/null +++ b/src/java/org/lwjgl/util/applet/AppletLoader.java @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2002-2007 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.lwjgl.util.applet; + +import java.applet.Applet; +import java.applet.AppletStub; +import java.awt.Color; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.Toolkit; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLConnection; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; +import java.security.cert.Certificate; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + *

+ * The AppletLoader enables deployment of LWJGL to applets in an easy + * and polished way. The loader will display a configurable logo and progressbar + * while the relevant jars (generic and native) are downloaded from a specified source. + *

+ *

+ * The downloaded are extracted to the users temporary directory - and if enabled, cached for + * faster loading in future uses. + *

+ *

+ * The following applet parameters are required: + *

    + *
  • al_main - [String] Full package and class the applet to instantiate and display when loaded.
  • + *
  • al_logo - [String Path of of the logo resource to paint while loading.
  • + *
  • al_progressbar - [String] Path of the progressbar resource to paint on top of the logo, width clipped by percentage.
  • + *
  • al_jars - [String] Comma seperated list of jars to download.
  • + *
  • al_windows - [String] Jar containing native files for windows.
  • + *
  • al_linux - [String] Jar containing native files for linux.
  • + *
  • al_mac - [String] Jar containing native files for mac.
  • + *
+ *

+ *

+ * Additionally the following parameters can be supplied to tweak the behaviour of the AppletLoader. + *

    + *
  • al_version - [int or float] Version of deployment. If this is specified, the jars will be cached and + * reused if the version matches. If version doesn't match all of the files are reloaded.
  • + *
  • al_bgcolor - [String] Hex formated color to use as background. Default: ffffff.
  • + *
  • al_fgcolor - [String] Hex formated color to use as foreground. Default: 000000.
  • + *
  • al_errorcolor - [String] Hex formated color to use as foreground color on error. Default: ff0000.
  • + *
  • al_debug - [boolean] Whether to enable debug mode. Default: false.
  • + *
+ *

+ * @author kappaOne + * @author Brian Matzon + * @version $Revision$ + * $Id$ + */ +public class AppletLoader extends Applet implements Runnable, AppletStub { + /** initializing */ + public static final int STATE_INIT = 1; + + /** determining which packages that are required */ + public static final int STATE_DETERMINING_PACKAGES = 2; + + /** checking for already downloaded files */ + public static final int STATE_CHECKING_CACHE = 3; + + /** downloading packages */ + public static final int STATE_DOWNLOADING = 4; + + /** extracting packages */ + public static final int STATE_EXTRACTING_PACKAGES = 5; + + /** updating the classpath */ + public static final int STATE_UPDATING_CLASSPATH = 6; + + /** switching to real applet */ + public static final int STATE_SWITCHING_APPLET = 7; + + /** initializing real applet */ + public static final int STATE_INITIALIZE_REAL_APPLET = 8; + + /** stating real applet */ + public static final int STATE_START_REAL_APPLET = 9; + + /** done */ + public static final int STATE_DONE = 10; + + /** used to calculate length of progress bar */ + protected int percentage; + + /** current size of download in bytes */ + protected int currentSizeDownload; + + /** total size of download in bytes */ + protected int totalSizeDownload; + + /** current size of extracted in bytes */ + protected int currentSizeExtract; + + /** total size of extracted in bytes */ + protected int totalSizeExtract; + + /** logo to be shown while loading */ + protected Image logo; + + /** progressbar to render while loading */ + protected Image progressbar; + + /** offscreen image used */ + protected Image offscreen; + + /** background color of applet */ + protected Color bgColor = Color.white; + + /** Color to write errors in */ + protected Color errorColor = Color.red; + + /** color to write forground in */ + protected Color fgColor = Color.black; + + /** urls of the jars to download */ + protected URL[] urlList; + + /** list of jars to download */ + protected String jarList; + + /** actual thread that does the loading */ + protected Thread loaderThread; + + /** animation thread that renders our loaderscreen while loading */ + protected Thread animationThread; + + /** applet to load after all downloads are complete */ + protected Applet lwjglApplet; + + /** whether a fatal error occured */ + protected boolean fatalError; + + /** fatal error that occured */ + protected String fatalErrorDescription; + + /** whether we're running in debug mode */ + protected boolean debugMode; + + /** String to display as a subtask */ + protected String subtaskMessage = ""; + + /** state of applet loader */ + protected int state = STATE_INIT; + + /** generic error message to display on error */ + protected String[] genericErrorMessage = { "An error occured while loading the applet.", + "Plese contact support to resolve this issue.", + ""}; + + /* + * @see java.applet.Applet#init() + */ + public void init() { + + // sanity check + String[] requiredArgs = {"al_main", "al_logo", "al_progressbar", "al_jars"}; + for(int i=0; i 0) { + messageX = (getWidth() - fm.stringWidth(subtaskMessage)) / 2; + og.drawString(subtaskMessage, messageX, messageY+20); + } + + // draw loading bar, clipping it depending on percentage done + int barSize = (progressbar.getWidth(this) * percentage) / 100; + og.clipRect(0, 0, x + barSize, getHeight()); + og.drawImage(progressbar, x, y, null); + } + + og.dispose(); + + // finally draw it all + g.drawImage(offscreen, 0, 0, null); + } + + /** + * Reads list of jars to download and adds the urls to urlList + * also finds out which OS you are on and adds appropriate native + * jar to the urlList + */ + protected void loadJarURLs() { + state = STATE_DETERMINING_PACKAGES; + + StringTokenizer jar = new StringTokenizer(jarList, ", "); + + int jarCount = jar.countTokens() + 1; + + urlList = new URL[jarCount]; + + try { + URL path = getCodeBase(); + + // set jars urls + for (int i = 0; i < jarCount - 1; i++) { + urlList[i] = new URL(path, jar.nextToken()); + } + + // native jar url + String osName = System.getProperty("os.name"); + String nativeJar = null; + + if (osName.startsWith("Win")) { + nativeJar = getParameter("al_windows"); + } else if (osName.startsWith("Linux") || osName.startsWith("FreeBSD") || osName.startsWith("SunOS")) { + nativeJar = getParameter("al_linux"); + } else if (osName.startsWith("Mac")) { + nativeJar = getParameter("al_mac"); + } else { + fatalErrorOccured("OS (" + osName + ") not supported"); + } + + if (nativeJar == null) { + fatalErrorOccured("no lwjgl natives files found"); + } else { + urlList[jarCount - 1] = new URL(path, nativeJar); + } + + } catch (MalformedURLException e) { + fatalErrorOccured(e.getMessage()); + } + } + + /** + * 4 steps + * + * 1) check version of applet and decide whether to download jars + * 2) download the jars + * 3) extract natives + * 4) add to jars to class path + * 5) switch applets + * + */ + public void run() { + + state = STATE_CHECKING_CACHE; + + percentage = 5; + + try { + if(debugMode) { + sleep(2000); + } + + // get path where applet will be stored + String path = (String) AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws Exception { + return System.getProperty("java.io.tmpdir") + File.separator + getParameter("al_title") + File.separator; + } + }); + + File dir = new File(path); + + // create directory + if (!dir.exists()) { + dir.mkdir(); + } + dir = new File(dir, "version"); + + // if applet already available don't download anything + boolean cacheAvailable = false; + + // version of applet + String version = getParameter("al_version"); + float latestVersion = 0; + + // if applet version specifed, check if you have latest version of applet + if (version != null) { + + latestVersion = Float.parseFloat(version); + + // if version file exists + if (dir.exists()) { + // compare to new version + if (latestVersion <= readVersionFile(dir)) { + cacheAvailable = true; + percentage = 90; + if(debugMode) { + sleep(2000); + } + } + } + } + + // if jars not available or need updating download them + if (!cacheAvailable) { + // downloads jars from the server + downloadJars(path); // 10-65% + + // Extracts Native Files + extractNatives(path); // 65-85% + + // add version information once jars downloaded successfully + if (version != null) { + percentage = 90; + writeVersionFile(dir, latestVersion); + } + } + + // add the downloaded jars and natives to classpath + updateClassPath(path); + + // switch to LWJGL Applet + switchApplet(); + + state = STATE_DONE; + } catch (AccessControlException ace) { + fatalErrorOccured(ace.getMessage()); + } catch (Exception e) { + fatalErrorOccured(e.getMessage()); + } finally { + loaderThread = null; + } + } + + /** + * read the current version file + * + * @param file the file to read + * @return the version value of saved file + * @throws Exception if it fails to read value + */ + protected float readVersionFile(File file) throws Exception { + DataInputStream dis = new DataInputStream(new FileInputStream(file)); + float version = dis.readFloat(); + dis.close(); + return version; + } + + /** + * write out version file of applet + * + * @param file the file to write out to + * @param version the version of the applet as a float + * @throws Exception if it fails to write file + */ + protected void writeVersionFile(File file, float version) throws Exception { + DataOutputStream dos = new DataOutputStream(new FileOutputStream(file)); + dos.writeFloat(version); + dos.close(); + } + + /** + * Edits the ClassPath at runtime to include the jars + * that have just been downloaded and then adds the + * lwjgl natives folder property. + * + * @param path location where applet is stored + * @throws Exception if it fails to add classpath + */ + protected void updateClassPath(String path) throws Exception { + + state = STATE_UPDATING_CLASSPATH; + + percentage = 95; + + Class[] parameters = new Class[] { URL.class}; + + // modify class path by adding downloaded jars to it + for (int i = 0; i < urlList.length; i++) { + // get location of jar as a url + URL u = new URL("file:" + path + getFileName(urlList[i])); + + // add to class path + Method method = URLClassLoader.class.getDeclaredMethod("addURL", parameters); + method.setAccessible(true); + method.invoke((URLClassLoader) ClassLoader.getSystemClassLoader(), new Object[] { u}); + } + + if(debugMode) { + sleep(2000); + } + + // add natives files path to native class path + System.setProperty("org.lwjgl.librarypath", path + "natives"); + + // Make sure jinput knows about the new path too + System.setProperty("net.java.games.input.librarypath", path + "natives"); + + // replace security system to avoid bug where vm fails to + // recognise downloaded jars as signed, when they are + System.setSecurityManager(null); + } + + /** + * replace the current applet with the lwjgl applet + * using AppletStub and initialise and start it + */ + protected void switchApplet() throws Exception { + + state = STATE_SWITCHING_APPLET; + percentage = 100; + + if(debugMode) { + sleep(2000); + } + + Class appletClass = Class.forName(getParameter("al_main")); + lwjglApplet = (Applet) appletClass.newInstance(); + + lwjglApplet.setStub(this); + + setLayout(new GridLayout(1, 1)); + add(lwjglApplet); + validate(); + + state = STATE_INITIALIZE_REAL_APPLET; + lwjglApplet.init(); + + state = STATE_START_REAL_APPLET; + lwjglApplet.start(); + } + + /** + * Will download the jars from the server using the list of urls + * in urlList, while at the same time updating progress bar + * + * @param path location of the directory to save to + * @throws Exception if download fails + */ + protected void downloadJars(String path) throws Exception { + + state = STATE_DOWNLOADING; + + URLConnection urlconnection; + + // calculate total size of jars to download + for (int i = 0; i < urlList.length; i++) { + urlconnection = urlList[i].openConnection(); + totalSizeDownload += urlconnection.getContentLength(); + } + + int initialPercentage = percentage = 10; + + // download each jar + byte buffer[] = new byte[65536]; + for (int i = 0; i < urlList.length; i++) { + if(debugMode) { + sleep(2000); + } + + urlconnection = urlList[i].openConnection(); + + String currentFile = getFileName(urlList[i]); + InputStream inputstream = urlconnection.getInputStream(); + FileOutputStream fos = new FileOutputStream(path + currentFile); + + + int bufferSize; + while ((bufferSize = inputstream.read(buffer, 0, buffer.length)) != -1) { + if(debugMode) { + sleep(10); + } + fos.write(buffer, 0, bufferSize); + currentSizeDownload += bufferSize; + percentage = initialPercentage + ((currentSizeDownload * 55) / totalSizeDownload); + subtaskMessage = "Retrieving: " + currentFile + " " + ((currentSizeDownload * 100) / totalSizeDownload) + "%"; + } + } + subtaskMessage = ""; + } + + /** + * This method will extract all file from the native jar and extract them + * to the subdirectory called "natives" in the local path, will also check + * to see if the native jar files is signed properly + * + * @param path base folder containing all downloaded jars + * @throws Exception if it fails to extract files + */ + protected void extractNatives(String path) throws Exception { + + state = STATE_EXTRACTING_PACKAGES; + + int initialPercentage = percentage; + + // get name of jar file with natives from urlList, it will be the last url + String nativeJar = getFileName(urlList[urlList.length - 1]); + + // get the current certificate to compare against native files + Certificate[] certificate = AppletLoader.class.getProtectionDomain().getCodeSource().getCertificates(); + + // create native folder + File nativeFolder = new File(path + "natives"); + if (!nativeFolder.exists()) { + nativeFolder.mkdir(); + } + + // open jar file + JarFile jarFile = new JarFile(path + nativeJar, true); + + // get list of files in jar + Enumeration entities = jarFile.entries(); + + totalSizeExtract = 0; + + // calculate the size of the files to extract for progress bar + while (entities.hasMoreElements()) { + JarEntry entry = (JarEntry) entities.nextElement(); + + // skip directories and anything in directories + // conveniently ignores the manifest + if (entry.isDirectory() || entry.getName().indexOf('/') != -1) { + continue; + } + totalSizeExtract += entry.getSize(); + } + + currentSizeExtract = 0; + + // reset point to begining by getting list of file again + entities = jarFile.entries(); + + // extract all files from the jar + while (entities.hasMoreElements()) { + JarEntry entry = (JarEntry) entities.nextElement(); + + // skip directories and anything in directories + // conveniently ignores the manifest + if (entry.isDirectory() || entry.getName().indexOf('/') != -1) { + continue; + } + + // check if native file already exists if so delete it to make room for new one + // useful when using the reload button on the browser + File f = new File(path + "natives" + File.separator + entry.getName()); + if (f.exists()) { + if (!f.delete()) { + continue; // unable to delete file, it is in use, skip extracting it + } + } + + if(debugMode) { + sleep(1000); + } + + InputStream in = jarFile.getInputStream(jarFile.getEntry(entry.getName())); + OutputStream out = new FileOutputStream(path + "natives" + File.separator + entry.getName()); + + int bufferSize; + byte buffer[] = new byte[65536]; + + while ((bufferSize = in.read(buffer, 0, buffer.length)) != -1) { + if(debugMode) { + sleep(10); + } + out.write(buffer, 0, bufferSize); + currentSizeExtract += bufferSize; + + // update progress bar + percentage = initialPercentage + ((currentSizeExtract * 20) / totalSizeExtract); + subtaskMessage = "Extracting: " + entry.getName() + " " + ((currentSizeExtract * 100) / totalSizeExtract) + "%"; + } + + // validate if the certificate for native file is correct + validateCertificateChain(certificate, entry.getCertificates()); + + in.close(); + out.close(); + } + subtaskMessage = ""; + + jarFile.close(); + } + + /** + * Validates the certificate chain for a single file + * + * @param ownCerts Chain of certificates to check against + * @param native_certs Chain of certificates to check + * @return true if the chains match + */ + protected static void validateCertificateChain(Certificate[] ownCerts, Certificate[] native_certs) throws Exception { + if (native_certs == null) + throw new Exception("Unable to validate certificate chain. Native entry did not have a certificate chain at all"); + + if (ownCerts.length != native_certs.length) + throw new Exception("Unable to validate certificate chain. Chain differs in length [" + ownCerts.length + " vs " + native_certs.length + "]"); + + for (int i = 0; i < ownCerts.length; i++) { + if (!ownCerts[i].equals(native_certs[i])) { + throw new Exception("Certificate mismatch: " + ownCerts[i] + " != " + native_certs[i]); + } + } + } + + /** + * Get Image from path provided + * + * @param s location of the image + * @return the Image file + */ + protected Image getImage(String s) { + try { + DataInputStream datainputstream = new DataInputStream(getClass().getResourceAsStream(s)); + byte abyte0[] = new byte[datainputstream.available()]; + datainputstream.readFully(abyte0); + datainputstream.close(); + return Toolkit.getDefaultToolkit().createImage(abyte0); + } catch (Exception e) { + /* */ + } + return null; + } + + + /** + * Get file name portion of URL. + * + * @param url Get file name from this url + * @return file name as string + */ + protected String getFileName(URL url) { + String fileName = url.getFile(); + return fileName.substring(fileName.lastIndexOf('/') + 1); + } + + /** + * Retrieves the color + * + * @param color Color to load + * @param defaultColor Default color to use if no color to load + * @return Color to use + */ + protected Color getColor(String color, Color defaultColor) { + String param_color = getParameter(color); + if (param_color != null) { + return new Color(Integer.parseInt(param_color, 16)); + } + return defaultColor; + } + + /** + * Retrieves the boolean value for the applet + * @param name Name of parameter + * @param defaultValue default value to return if no such parameter + * @return value of parameter or defaultValue + */ + protected boolean getBooleanParameter(String name, boolean defaultValue) { + String parameter = getParameter(name); + if(parameter != null) { + return Boolean.parseBoolean(parameter); + } + return defaultValue; + } + + /** + * Sets the state of the loaded and prints some debug information + * + * @param error Error message to print + * @param state State to enter + */ + protected void fatalErrorOccured(String error) { + fatalError = true; + fatalErrorDescription = "Fatal error occured (" + state + "): " + error; + System.out.println(fatalErrorDescription); + repaint(); + } + + /** + * Utility method for sleeping + * @param ms milliseconds to sleep + */ + protected void sleep(long ms) { + try { + Thread.sleep(ms); + } catch (Exception e) { + /* ignored */ + } + } +} \ No newline at end of file