commit 2ca6e75aac9723221e4b48b1ee31cf8921435bf7 Author: Victor Date: Wed Nov 14 19:08:50 2018 +0200 Initial diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..42f9da5 --- /dev/null +++ b/build.xml @@ -0,0 +1,91 @@ + + + + + + Builds, tests, and runs the project . + + + + + + + + + + + diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml new file mode 100644 index 0000000..90b2ab5 --- /dev/null +++ b/nbproject/build-impl.xml @@ -0,0 +1,1430 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Classpath to J2ME Ant extension library (libs.j2me_ant_ext.classpath property) is not set. For example: location of mobility/modules/org-netbeans-mobility-antext.jar file in the IDE installation directory. + Platform home (platform.home property) is not set. Value of this property should be ${platform.active.description} emulator home directory location. + Platform boot classpath (platform.bootclasspath property) is not set. Value of this property should be ${platform.active.description} emulator boot classpath containing all J2ME classes provided by emulator. + Must set src.dir + Must set build.dir + Must set dist.dir + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set preprocessed.dir + + + + + + + + + + + + + + + + + + Must set build.classes.dir + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + Must set obfuscated.classes.dir + + + + Must set obfuscated.classes.dir + Must set obfuscator.srcjar + Must set obfuscator.destjar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set preverify.classes.dir + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MicroEdition-Configuration: ${platform.configuration} + + MicroEdition-Configuration: ${platform.configuration} + + + + MicroEdition-Profile: ${platform.profile} + + MicroEdition-Profile: ${platform.profile} + + + + Must set dist.jad + + + + + + + + + + + + + + + + + + + + + + + + ${manifest.midlets}${evaluated.manifest.apipermissions}${evaluated.manifest.pushregistry}${manifest.others}${manifest.jad} + ${manifest.midlets}${evaluated.manifest.apipermissions}${evaluated.manifest.pushregistry}${manifest.others}${manifest.manifest} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Starting emulator with port number ${active.debug.port} + + + + + + + + + + + + + + + + + Starting emulator with port number ${active.debug.port} + + + + + + + + + + + + + + + + + Must set dist.javadoc.dir + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${all.configurations} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Property deployment.${deployment.method}.scriptfile not set. The property should point to an Ant script providing ${deployment.method} deployment. + + + + + + + + Classpath to Ant Contrib library (libs.ant-contrib.classpath property) is not set. + + + + + + + + + Active project configuration: @{cfg} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Property build.root.dir is not set. By default its value should be \"build\". + Property dist.root.dir is not set. By default its value should be \"dist\". + + + + + diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties new file mode 100644 index 0000000..6cafbdd --- /dev/null +++ b/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +build.xml.data.CRC32=cc72bae4 +build.xml.script.CRC32=f1a8f107 +build.xml.stylesheet.CRC32=03eab09b +nbproject/build-impl.xml.data.CRC32=cc72bae4 +nbproject/build-impl.xml.script.CRC32=b89822d1 +nbproject/build-impl.xml.stylesheet.CRC32=7a0aeb65 diff --git a/nbproject/private/private.properties b/nbproject/private/private.properties new file mode 100644 index 0000000..0085955 --- /dev/null +++ b/nbproject/private/private.properties @@ -0,0 +1,9 @@ +#Tue, 14 Sep 2010 19:03:15 +0300 +app-version.autoincrement=true +config.active=ReleaseFull +deployment.counter=1398 +deployment.number=1397 +file.reference.motorola_jsr.jar=E\:\\MOBILE\\Programming\\Java\\Libraries_n_API\\API\\motorola_jsr.jar +file.reference.SiemensAPI.zip=E\:\\MOBILE\\Programming\\Java\\Libraries_n_API\\API\\SiemensAPI.zip +javadoc.preview=true +netbeans.user=C:\\Users\\aNNiMON\\.netbeans\\7.0beta2 diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml new file mode 100644 index 0000000..8505fc1 --- /dev/null +++ b/nbproject/private/private.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/nbproject/project.properties b/nbproject/project.properties new file mode 100644 index 0000000..80bb003 --- /dev/null +++ b/nbproject/project.properties @@ -0,0 +1,152 @@ +abilities=MMAPI=1.1,SATSAJCRMI=1.0,SATSACRYPTO=1.0,JSR82=1.1,NOKIAUI=1.0,JSR226=1.0,MIDP=2.1,capuchin=1.0,JSR229=1.1.0,SATSAAPDU=1.0,CLDC=1.1,JSR177=1.0,JSR179=1.0.1,eSWT=1.1,J2MEWS=1.0,VSCL=2.1,WMA=2.0,JSR172=1.0,JSR256=true,SEMC_EXT_JP8=1.0,ColorScreen,NokiaUI=true,OBEX=1.0,JSR238=1.0,JSR239=1.0,JSR211=1.0,JSR234=1.0,MascotV3=1.0,ScreenWidth=240,IAPInfo=1.0,JSR75=auto,JSR184=1.1,SATSAPKI=1.0,ScreenHeight=321,ScreenColorDepth=8,JSR180=1.0.1,J2MEXMLRPC=1.0 +all.configurations=\ ,ReleaseFull,ReleaseLite +application.args= +application.description= +application.description.detail= +application.name= +application.vendor=Vendor +build.classes.dir=${build.dir}/compiled +build.classes.excludes=**/*.java,**/*.form,**/*.class,**/.nbintdb,**/*.mvd,**/*.wsclient,**/*.vmd +build.dir=build/${config.active} +build.root.dir=build +configs.ReleaseFull.filter.exclude.tests=false +configs.ReleaseFull.filter.excludes= +configs.ReleaseFull.filter.more.excludes=**/overview.html,**/package.html,**/Thumbs.db +configs.ReleaseFull.filter.use.standard=true +configs.ReleaseFull.obfuscation.custom=-dontusemixedcaseclassnames\n-overloadaggressively\n-optimizations !class/merging/*\n-keep public class * extends javax.microedition.midlet.MIDlet\n-keep public class AccelImpl\n-keep class mcp.*\n-adaptresourcefilecontents config/**,lang/**\n-adaptclassstrings\n-keep,allowobfuscation,allowoptimization class * extends com.one.Container\n-keep class * implements com.one.Application\n-keep class * implements com.one.FileSource\n-keep class * implements com.one.OptionStorage\n-dontpreverify\n-applymapping C:\\Users\\aNNiMON\\Documents\\NetBeansProjects\\UniFM\\proguard.map\n-printmapping C:\\Users\\aNNiMON\\Documents\\NetBeansProjects\\UniFM\\proguard.map +configs.ReleaseFull.obfuscation.level=1 +configs.ReleaseLite.obfuscation.custom=-dontusemixedcaseclassnames\n-overloadaggressively\n-optimizations !class/merging/*\n-keep public class * extends javax.microedition.midlet.MIDlet\n-keep public class AccelImpl\n-keep class mcp.*\n-adaptresourcefilecontents\n-adaptclassstrings\n-keep,allowobfuscation,allowoptimization class com.one.Container\n-keep,allowobfuscation,allowoptimization class com.one.Application\n-keep,allowobfuscation,allowoptimization class com.one.FileSource\n-keep,allowobfuscation,allowoptimization class com.one.OptionStorage\n-keep,allowobfuscation,allowoptimization class com.classpath.zip.ZipFile\n-keep,allowobfuscation,allowoptimization class com.one.PlainPackage\n-keep class modules.color.*\n-keep class modules.text.TextModule\n-keep class modules.text.TextFileSource\n-keep class modules.text.TextOptions\n-dontpreverify\n-applymapping C:\\UniFM\\proguard.map\n-printmapping C:\\UniFM\\proguard.map\n +configs.ReleaseLite.obfuscation.level=1 +debug.level=debug +debugger.timeout= +deployment.copy.target=deploy +deployment.instance=default +deployment.jarurl=${dist.jar} +deployment.method=NONE +deployment.override.jarurl=false +dist.dir=dist/${config.active} +dist.jad=UniFM.jad +dist.jar=UniFM.jar +dist.javadoc.dir=${dist.dir}/doc +dist.root.dir=dist +extra.classpath=${file.reference.SiemensAPI.zip};${file.reference.motorola_jsr.jar} +file.reference.builtin.ks=${netbeans.user}/config/j2me/builtin.ks +file.reference.UniFM-res=res +filter.exclude.tests=false +filter.excludes= +filter.more.excludes=**/overview.html,**/package.html,**/Thumbs.db +filter.use.standard=true +jar.compress=true +javac.debug=true +javac.deprecation=false +javac.encoding=UTF-8 +javac.optimize=false +javac.source=1.3 +javac.target=1.3 +javadoc.author=false +javadoc.encoding= +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +libs.classpath=${file.reference.SiemensAPI.zip};${file.reference.motorola_jsr.jar};${file.reference.UniFM-res} +main.class= +main.class.class=applet +manifest.apipermissions= +manifest.file=manifest.mf +manifest.is.liblet=false +manifest.jad= +manifest.manifest= +manifest.midlets=MIDlet-4: Test canvas,,Test\nMIDlet-3: Reset RMS,,ResetRMS\nMIDlet-2: Legacy version,/img/icon.png,Browser\nMIDlet-1: Full version,/img/icon.png,UniFM\n +manifest.others=MIDlet-Vendor: SilentKnight, VMX, DiHLoS\nPointer-Translate-Y: 0\nDeployment-Number: ${deployment.number}\nPointer-Translate-X: 0\nMIDlet-Name: UniFM\nPointer-Soft-Width: 2.0\nMIDlet-Icon: /img/icon.png\nPointer-Cell-Height: 1.0\nPointer-Cell-Width: 2.0\nMIDlet-Version: 1.2\nDefault-Encoding: cp1251\nArchive-Encoding: cp866\nID3-Encoding: cp1252\n +manifest.pushregistry= +name=UniFM +no.dependencies=false +nokiaS80.application.icon= +nsicom.application.monitorhost= +nsicom.application.runremote= +nsicom.application.runverbose= +nsicom.remoteapp.location=\\My Documents\\NetBeans Applications +nsicom.remotevm.location=\\Windows\\creme\\bin\\CrEme.exe +obfuscated.classes.dir=${build.dir}/obfuscated +obfuscation.custom= +obfuscation.level=0 +obfuscator.destjar=${build.dir}/obfuscated.jar +obfuscator.srcjar=${build.dir}/before-obfuscation.jar +platform.active=Sony_Ericsson_SDK_2_5_0_6_for_the_Java_TM__ME_Platform_Emulator_ +platform.active.description=Sony Ericsson SDK 2.5.0.6 for the Java(TM) ME Platform(Emulator) +platform.apis=JSR234-1.0,SATSA-APDU-1.0,capuchin-1.0,J2ME-WS-1.0,J2ME-XMLRPC-1.0,SATSA-JCRMI-1.0,SATSA-CRYPTO-1.0,JSR239-1.0,MascotV3-1.0,JSR238-1.0,MMAPI-1.1,JSR256-1.1,NokiaUI-1.0,IAPInfo-1.0,JSR229-1.1.0,SATSA-PKI-1.0,JSR180-1.0.1,JSR226-1.0,SEMC_EXT_JP8-1.0,VSCL-2.0,VSCL-2.1,eSWT-1.1,JSR75-1.0,JSR184-1.1,WMA-2.0,JSR211-1.0,JSR82-1.1,JSR177-1.0,JSR179-1.0.1 +platform.bootclasspath=${platform.home}/lib/eswt.jar:${platform.home}/lib/mascotv3.jar:${platform.home}/lib/jsr226.jar:${platform.home}/lib/jsr256.jar:${platform.home}/lib/satsa-crypto.jar:${platform.home}/lib/jsr229.jar:${platform.home}/lib/jsr238.jar:${platform.home}/lib/j2me-xmlrpc.jar:${platform.home}/lib/jsr211.jar:${platform.home}/lib/vscl21.jar:${platform.home}/lib/satsa-jcrmi.jar:${platform.home}/lib/jsr082.jar:${platform.home}/lib/satsa-apdu.jar:${platform.home}/lib/jsr184.jar:${platform.home}/lib/nokiaext.jar:${platform.home}/lib/capuchin.jar:${platform.home}/lib/jsr239.jar:${platform.home}/lib/jsr75.jar:${platform.home}/lib/satsa-pki.jar:${platform.home}/lib/jsr179.jar:${platform.home}/lib/jsr180.jar:${platform.home}/lib/iapinfo.jar:${platform.home}/lib/vscl.jar:${platform.home}/lib/mmapi.jar:${platform.home}/lib/j2me-ws.jar:${platform.home}/lib/wma20.jar:${platform.home}/lib/jsr234.jar:${platform.home}/lib/semc_ext_jp8.jar:${platform.home}/lib/cldcapi11.jar:${platform.home}/lib/midpapi20.jar +platform.configuration=CLDC-1.1 +platform.device=SonyEricsson_JP8_240x320_Emu +platform.fat.jar=true +platform.profile=MIDP-2.0 +platform.trigger=CLDC +platform.type=UEI-1.0.1 +preprocessed.dir=${build.dir}/preprocessed +preverify.classes.dir=${build.dir}/preverified +preverify.sources.dir=${build.dir}/preverifysrc +resources.dir=resources +ricoh.application.email= +ricoh.application.fax= +ricoh.application.icon= +ricoh.application.target-jar= +ricoh.application.telephone= +ricoh.application.uid=25863700 +ricoh.application.version= +ricoh.dalp.application-desc.auto-run=false +ricoh.dalp.application-desc.energy-save= +ricoh.dalp.application-desc.exec-auth= +ricoh.dalp.application-desc.visible=true +ricoh.dalp.argument= +ricoh.dalp.codebase= +ricoh.dalp.display-mode.color=true +ricoh.dalp.display-mode.is-4line-support=false +ricoh.dalp.display-mode.is-hvga-support=true +ricoh.dalp.display-mode.is-vga-support=false +ricoh.dalp.display-mode.is-wvga-support=false +ricoh.dalp.information.abbreviation= +ricoh.dalp.information.icon.basepath= +ricoh.dalp.information.icon.location= +ricoh.dalp.information.is-icon-used=true +ricoh.dalp.install.destination=hdd +ricoh.dalp.install.mode.auto=true +ricoh.dalp.install.work-dir=hdd +ricoh.dalp.is-managed=true +ricoh.dalp.resources.dsdk.version=2.0 +ricoh.dalp.resources.jar.basepath= +ricoh.dalp.resources.jar.version= +ricoh.dalp.version= +ricoh.icon.invert=false +ricoh.platform.target.version= +run.cmd.options= +run.jvmargs= +run.method=STANDARD +run.security.domain=manufacturer +run.use.security.domain=false +savaje.application.icon= +savaje.application.icon.focused= +savaje.application.icon.small= +savaje.application.uid=TBD +savaje.bundle.base= +savaje.bundle.debug=false +savaje.bundle.debug.port= +semc.application.caps= +semc.application.icon= +semc.application.icon.count= +semc.application.icon.splash= +semc.application.icon.splash.installonly=false +semc.application.uid=E7786584 +semc.certificate.path= +semc.private.key.password= +semc.private.key.path= +sign.alias=minimal +sign.enabled=false +sign.keystore=${file.reference.builtin.ks} +src.dir=src +use.emptyapis=true +use.preprocessor=true diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..a62b205 --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,10 @@ + + + org.netbeans.modules.kjava.j2meproject + + + UniFM + 1.6 + + + diff --git a/other/fishlabs-uncoder/config/modules.ini b/other/fishlabs-uncoder/config/modules.ini new file mode 100644 index 0000000..e0276e1 --- /dev/null +++ b/other/fishlabs-uncoder/config/modules.ini @@ -0,0 +1,55 @@ +; This file describes modules in general. +; Sections, like [Container] or [Application], define type of a module. Containers are used to transparently open various archives and packages of files, Applications are used to display file contents to the user and to edit those contents. +; FileSources are used to create new files. ContainerSources are technically similar to FileSources, but are used to create containers rather than simple files and are stored in separate internal list. + +; Each record in this file has the following syntax: +; module.package.ModuleClass = [, icon_file.ext [@ x, y, width, height]] + +; If you plan to obfuscate your module, don't forget to tell your obfuscator to adapt the contents of this file. +; For ProGuard it is done like that: -adaptresourcefilecontents config/* + +[Container] + +a.e.c.k = # 211, icons.png @ 80, 0, 16, 16 +a.a.a.b = # 325, icons.png @ 80, 0, 16, 16 +a.b.ad = # 212, icons.png @ 80, 0, 16, 16 + +[Application] + +;modules.PlatformRequestModule = # 317, icons.png @ 0, 0, 16, 16 +modules.audio.AudioModule = # 213, icons.png @ 16, 0, 16, 16 +modules.image.ImageModule = # 214, icons.png @ 32, 0, 16, 16 +modules.video.VideoModule = # 215, icons.png @ 48, 0, 16, 16 +modules.text.TextModule = # 216, icons.png @ 64, 0, 16, 16 +modules.TMOModule = # 217, icons.png @ 96, 0, 16, 16 +modules.audio.TrackerModule = # 218, icons.png @ 16, 0, 16, 16 +modules.color.ColorModule = # 219, icons.png @ 32, 0, 16, 16 +modules.image.VectorModule = # 220, icons.png @ 32, 0, 16, 16 +modules.mascot.MascotViewer = # 0, icons.png @ 32, 0, 16, 16 +modules.mascot.AnimationViewer = # 1, icons.png @ 48, 0, 16, 16 +modules.mascot.TextureLoader = # 2, icons.png @ 32, 0, 16, 16 +modules.id3Editor = # 113, icons.png @ 16, 0, 16, 16 +modules.playlist.M3UModule = # 281, icons.png @ 16, 0, 16, 16 +modules.FileSplitter = # 1, icons.png @ 0, 0, 16, 16 +modules.FishlabsUncoder = # 0, icons.png @ 0, 0, 16, 16 +modules.langpack.StringUnpacker = # 0, icons.png @ 400, 0, 16, 16 +modules.langpack.StringPacker = # 1, icons.png @ 528, 0, 16, 16 + +;modules.DummyModule = Dummy module, icons.png @ 0, 0, 16, 16 + +[FileSource] + +modules.text.TextFileSource = # 235, icons.png @ 64, 0, 16, 16 +modules.NullFileSource = # 282, icons.png @ 0, 0, 16, 16 +modules.FileSplicer = # 0, icons.png @ 0, 0, 16, 16 +modules.playlist.M3UFileSource = # 204, icons.png @ 16, 0, 16, 16 +modules.color.ColorFileSource = # 152, icons.png @ 32, 0, 16, 16 + +[ContainerSource] + +modules.ZipFileSource = # 287, icons.png @ 80, 0, 16, 16 +modules.PPKFileSource = # 288, icons.png @ 80, 0, 16, 16 + +;[Operation] + +;test.TestModule = TestName, icons.png \ No newline at end of file diff --git a/other/fishlabs-uncoder/lang/en/offsets.ini b/other/fishlabs-uncoder/lang/en/offsets.ini new file mode 100644 index 0000000..8d7c328 --- /dev/null +++ b/other/fishlabs-uncoder/lang/en/offsets.ini @@ -0,0 +1,17 @@ +; class.package.ClassName = + +; If you plan to obfuscate your module, don't forget to tell your obfuscator to adapt the contents of this file. +; For ProGuard it is done like that: -adaptresourcefilecontents lang/** + +modules.langpack.StringUnpacker = 1000 +modules.langpack.StringPacker = 1000 + +modules.FileSplicer = 2000 +modules.FileSplitter = 2000 + +modules.mascot.MascotViewer = 3000 +modules.mascot.AnimationViewer = 3000 +modules.mascot.TextureLoader = 3000 +modules.mascot.a = 3000 + +modules.FishlabsUncoder = 3500 \ No newline at end of file diff --git a/other/fishlabs-uncoder/lang/en/strings.ini b/other/fishlabs-uncoder/lang/en/strings.ini new file mode 100644 index 0000000..05e5456 --- /dev/null +++ b/other/fishlabs-uncoder/lang/en/strings.ini @@ -0,0 +1,362 @@ +0 = Select disk: +1 = Favourites +2 = Options +3 = Exit +4 = Disk +5 = Disk information +6 = Total size: +7 = Kb +8 = bytes +9 = Available: +10 = Select +11 = Delete +12 = Delete all +13 = Back +14 = File name must not contain any of the following characters: %A +15 = Confirmation +16 = Delete entry from Favourites? +17 = Delete all entries from Favourites? +18 = Yes +19 = No +20 = Save +21 = Clear +22 = Error! +23 = File %A already exist! +24 = File %A not copied: %B\n\n +25 = File %A not moved: %B\n\n +26 = This file format is not supported! +27 = Open +28 = Paste +29 = Properties +30 = Rename +31 = Copy +32 = Move +33 = Folder... +34 = File... +35 = Add to Favourites +36 = Disk info +37 = Escaped strings +38 = Preferences +39 = Help +40 = OK +41 = Cancel +42 = Added to Clipboard +43 = Information: +44 = Folder name: +45 = File name: +46 = Size: +47 = Attributes: +48 = Last modified: +49 = Rename +50 = Name: +51 = File(folder) with this name already exist! Select another name. +52 = File %A is read only! +53 = Not renamed! +54 = Show hidden files and folders +55 = Visual effects +56 = Browse options: +57 = Extended menu +58 = Rotate by %A° +59 = Show error messages +60 = Create folder +61 = Create file +62 = Folder not created! +63 = Please wait... +64 = Wait +65 = In current folder +66 = On current disk +67 = On all disks +68 = scaled +69 = Attention! +70 = File %A copied. Source file is read-only.\n\n +71 = Delete selected file (folder)? +72 = Delete marked files? +73 = Folder deleted! +74 = Folder not empty. Delete recursively? +75 = File deleted. +76 = File %A not deleted! +77 = License agreement +78 = File type: +79 = File not saved! Exit? +80 = File saved +81 = Clipboard +82 = %A - copy +83 = %A - copy (%B) +84 = Operation complete successfully. +85 = File +86 = File not saved! Check 'Read Only' attribute. +87 = Gb +88 = Mark +89 = Mark all +90 = Unmark all +91 = Open not supported files as text +92 = Sort list +93 = Screen rotation +94 = Restart will be required for the new settings to take effect. +95 = Extract... +96 = Extract all... +97 = Extract to: +98 = Folder does not exist and cannot be created! +99 = Files extracted successfully. +100 = Yes for all +101 = No for all +102 = Vibration on key press, ms +103 = Compressed: +104 = File +105 = Archive +106 = Properties +107 = Operations +108 = Create +109 = Interface +110 = Minimize visual effects +111 = Archive... +112 = Compression level +113 = ID3v1 editor +114 = Title +115 = Artist +116 = Album +117 = Year +118 = Comment +119 = Track no +120 = Genre +121 = Mb +122 = Joy Left +123 = Joy Right +124 = Joy Up +125 = Joy Down +126 = Left softkey +127 = Right softkey +128 = Joy press +129 = Dial +130 = NoDial +131 = Prev screen +132 = Next screen +133 = Prev file +134 = Next file +135 = Hot keys +136 = Additional +137 = Panels +138 = Panel 1 +139 = Panel 2 +140 = Panel 3 +141 = Panel 4 +142 = Panel 5 +143 = Panel 6 +144 = Panel 7 +145 = Panel 8 +146 = Panel 9 +147 = Panel 10 +148 = Fullscreen +149 = no action +150 = Keyboard... +151 = Language +152 = Color scheme +153 = Check file attributes +154 = Accurate directory check +155 = Sort file list +156 = Read only +157 = Hidden +158 = Contents +159 = %A folders, %B files +160 = Player options +161 = ID3 encoding +162 = Show play progress +163 = Tracker module buffer size, sec. +164 = Done +165 = Text editor options +166 = Show CR symbol +167 = Show LF symbol +168 = Substitute tabulation with spaces +169 = Go to +170 = Scroll by pages instead of lines +171 = Key mapping +172 = Initial setup +173 = Clock mode +174 = Switch +175 = Next panel +176 = Prev. panel +177 = Next free +178 = Prev. free +179 = Swap panels +180 = Edit +181 = Search +182 = Font +183 = Encoding +184 = Recursive search +185 = Hash-sum +186 = Crypt +187 = Password +188 = Use crypt operation again with the same password for decryption. +189 = Small +190 = Medium +191 = Large +192 = Face +193 = Style +194 = Bold +195 = Italic +196 = Monospace +197 = Proportional +198 = System +199 = Underlined +200 = Show menu numbers +201 = Shuffle playback +202 = Transcode +203 = Custom +204 = Playlist +205 = Search inside archives +206 = Audio +207 = Video +208 = Save path +209 = Absolute +210 = Relative +211 = ZIP archiver +212 = PPK archiver +213 = Audioplayer +214 = Image viewer +215 = Videoplayer +216 = Text editor +217 = Note editor +218 = Tracker player +219 = Color scheme installer +220 = Vector image viewer +221 = Frame cursor +222 = No change +223 = Set +224 = Reset +225 = Background image +226 = Name template +227 = Minimize +228 = Save changes? +229 = Save as... +230 = Edit +231 = Undo +232 = Redo +233 = Find +234 = Find next +235 = Text +236 = Archive encoding +237 = Line number +238 = Remember explored paths +239 = Templates +240 = Use UTF BOM signature +241 = File end is reached. Continue search from the beginning? +242 = To start +243 = To end +244 = Add +245 = Play message signals +246 = Swap soft keys in menus +247 = Ignore case +248 = Don't sort +249 = By name +250 = By type +251 = By date +252 = By size +253 = Sort options +254 = Reverse order +255 = Restart +256 = Move cursor on mark +257 = Replace +258 = Replace all +259 = Replace with +260 = Alter clock position +261 = matches +262 = Equalizer +263 = Hz +264 = KHz +265 = dB +266 = Use accelerometer +267 = Backlight always on +268 = Tracker module sample rate +269 = Tracker module resample quality +270 = Low +271 = Medium +272 = High +273 = Disabled +274 = Enabled +275 = Automatic +276 = Escape +277 = Unescape +278 = Clipboard is empty! +279 = Modules +280 = Packing file %A... +281 = Playlist +282 = Stub +283 = Character +284 = Text box title +285 = Normal +286 = Ticker tape +287 = ZIP archive +288 = PPK archive +289 = Unpacking file %A... +290 = Memory monitor +291 = Update +292 = Fill +293 = Used +294 = Total +295 = Memory monitor step, ms +296 = Garbage collector threshold, % +297 = Containers +298 = Close +299 = Close all +300 = Writing file %A... +301 = Palette +302 = Color selector +303 = %A refer., %B depend. +304 = Long item scroll speed +305 = Installing color scheme... +306 = Refined gradients +307 = Transparency in gradients +308 = Text buffer size, char. +309 = Full file names +310 = In Clipboard +311 = In Favourites +312 = Enter +313 = Key assignment +314 = User-defined keys +315 = Key editor +316 = Key code +317 = Device internal handler +318 = Abbreviation +319 = Press a key... +320 = Hot %A +321 = Held %A +322 = Root +323 = File list +324 = Bit bucket +325 = RAR archiver +326 = Assign +327 = Reset +328 = Cache code pages +329 = Large font +330 = In file list +331 = In menu +332 = "Exit" in drive list +333 = Metadata format +334 = Show metadata captions +335 = Regular expressions +336 = Multiline matching +337 = Replace backreferences + +[1000] + +0 = Lang pack decompiler +1 = Lang pack compiler + +[2000] + +0 = File splice +1 = File splitter +2 = Parts count +3 = Part size +4 = File size unknown, split impossible. + +[3000] + +0 = MascotCapsule model viewer +1 = MascotCapsule animation viewer +2 = MascotCapsule texture loader +3 = S %A Rx %D° Ry %E° Px %G Py %H F %J + +[3500] + +0 = FishlabsUncoder \ No newline at end of file diff --git a/other/fishlabs-uncoder/lang/ru/offsets.ini b/other/fishlabs-uncoder/lang/ru/offsets.ini new file mode 100644 index 0000000..8d7c328 --- /dev/null +++ b/other/fishlabs-uncoder/lang/ru/offsets.ini @@ -0,0 +1,17 @@ +; class.package.ClassName = + +; If you plan to obfuscate your module, don't forget to tell your obfuscator to adapt the contents of this file. +; For ProGuard it is done like that: -adaptresourcefilecontents lang/** + +modules.langpack.StringUnpacker = 1000 +modules.langpack.StringPacker = 1000 + +modules.FileSplicer = 2000 +modules.FileSplitter = 2000 + +modules.mascot.MascotViewer = 3000 +modules.mascot.AnimationViewer = 3000 +modules.mascot.TextureLoader = 3000 +modules.mascot.a = 3000 + +modules.FishlabsUncoder = 3500 \ No newline at end of file diff --git a/other/fishlabs-uncoder/lang/ru/strings.ini b/other/fishlabs-uncoder/lang/ru/strings.ini new file mode 100644 index 0000000..728456c --- /dev/null +++ b/other/fishlabs-uncoder/lang/ru/strings.ini @@ -0,0 +1,362 @@ +0 = Âûáîð äèñêà: +1 = Èçáðàííîå +2 = Îïöèè +3 = Âûõîä +4 = Äèñê +5 = Èíôîðìàöèÿ î äèñêå +6 = Îáùèé ðàçìåð: +7 = Êá +8 = áàéò +9 = Ñâîáîäíî: +10 = Âûáîð +11 = Óäàëèòü +12 = Óäàëèòü âñå +13 = Íàçàä +14 = Èìÿ ôàéëà íå äîëæíî ñîäåðæàòü ñëåäóþùèõ ñèìâîëîâ: %A +15 = Ïîäòâåðæäåíèå +16 = Óäàëèòü çàïèñü èç Èçáðàííîãî? +17 = Óäàëèòü âñå èç Èçáðàííîãî? +18 = Äà +19 = Íåò +20 = Ñîõðàíèòü +21 = Î÷èñòèòü +22 = Îøèáêà! +23 = Ôàéë %A óæå ñóùåñòâóåò. Ïåðåçàïèñàòü? +24 = Ôàéë %A íå ñêîïèðîâàí: %B\n\n +25 = Ôàéë %A íå ïåðåìåùåí: %B\n\n +26 = Äàííûé ôîðìàò ôàéëà íå ïîääåðæèâàåòñÿ! +27 = Îòêðûòü +28 = Âñòàâèòü +29 = Ñâîéñòâà +30 = Ïåðåèìåíîâàòü +31 = Êîïèðîâàòü +32 = Ïåðåìåñòèòü +33 = Ïàïêó... +34 = Ôàéë... +35 =  èçáðàííîå +36 = Èíôî î äèñêå +37 = Ýêðàíèðîâàííûå ñòðîêè +38 = Íàñòðîéêè +39 = Ïîìîùü +40 = ÎÊ +41 = Îòìåíà +42 = Äîáàâëåí(û) â áóôåð îáìåíà +43 = Èíôîðìàöèÿ +44 = Èìÿ ïàïêè +45 = Èìÿ ôàéëà +46 = Ðàçìåð +47 = Àòðèáóòû +48 = Ïîñëåäíåå èçìåíåíèå +49 = Ïåðåèìåíîâàòü +50 = Èìÿ: +51 = Ýòîò ôàéë (ïàïêà) óæå ñóùåñòâóåò, âûáåðèòå äðóãîå èìÿ. +52 = Ôàéë %A òîëüêî äëÿ ÷òåíèÿ! +53 = Íå ïåðåèìåíîâàí! +54 = Ïîêàçûâàòü ñêðûòûå ôàéëû è ïàïêè +55 = Âèçóàëüíûå ýôôåêòû +56 = Ïðîñìîòð è âûïîëíåíèå +57 = Ðàñøèðåííîå ìåíþ +58 = Ïîâåðíóòü íà %A° +59 = Ïîêàçûâàòü ñîîáùåíèÿ îá îøèáêàõ +60 = Ñîçäàòü ïàïêó +61 = Ñîçäàòü ôàéë +62 = Ïàïêà íå ñîçäàíà! +63 = Ïîæàëóéñòà, ïîäîæäèòå... +64 = Ïîäîæäèòå +65 =  òåêóùåé ïàïêå +66 = Íà òåêóùåì äèñêå +67 = Íà âñåõ äèñêàõ +68 = ìàñø. +69 = Âíèìàíèå! +70 = Ôàéë %A ñêîïèðîâàí, èñõîäíûé ôàéë òîëüêî äëÿ ÷òåíèÿ.\n\n +71 = Óäàëèòü âûáðàííûé ôàéë (ïàïêó)? +72 = Óäàëèòü îòìå÷åííûå ôàéëû? +73 = Ïàïêà óäàëåíà! +74 = Ïàïêà íå ïóñòà. Óäàëèòü ðåêóðñèâíî? +75 = Ôàéë óäàëåí. +76 = Íåâîçìîæíî óäàëèòü ôàéë %A! +77 = Ëèöåíç. ñîãëàøåíèå +78 = Òèï ôàéëà: +79 = Ôàéë íå ñîõðàíåí! Âûéòè? +80 = Ôàéë ñîõðàíåí +81 = Áóôåð îáìåíà +82 = %A - êîïèÿ +83 = %A - êîïèÿ (%B) +84 = Îïåðàöèÿ óñïåøíî âûïîëíåíà. +85 = Ôàéë +86 = Ôàéë íå ñîõðàíåí! Ñíèìèòå àòðèáóò Read Only. +87 = Ãá +88 = Âûäåëèòü +89 = Âûäåëèòü âñ¸ +90 = Ñáðîñèòü âñ¸ +91 = Îòêðûâàòü íåïîääåðæèâàåìûå òèïû ôàéëîâ êàê òåêñò +92 = Ñîðòèðîâêà +93 = Ïîâîðîò ýêðàíà +94 = Äëÿ ïðèìåíåíèÿ íàñòðîåê ïîòðåáóåòñÿ ïåðåçàïóñê. +95 = Èçâëå÷ü... +96 = Èçâëå÷ü âñ¸... +97 = Èçâëå÷ü â: +98 = Ïàïêà íå ñóùåñòâóåò è ñîçäàòü å¸ íåâîçìîæíî! +99 = Ôàéëû óñïåøíî èçâëå÷åíû. +100 = Äà äëÿ âñåõ +101 = Íåò äëÿ âñåõ +102 = Âèáðàöèÿ ïðè íàæàòèè êëàâèø, ìñ +103 = Óïàêîâàí: +104 = Ôàéë +105 = Àðõèâ +106 = Ñâîéñòâà +107 = Îïåðàöèè +108 = Ñîçäàòü +109 = Èíòåðôåéñ +110 = Ìèíèìóì âèçóàëüíûõ ýôôåêòîâ +111 = Àðõèâ... +112 = Óðîâåíü ñæàòèÿ +113 = Ðåäàêòîð ID3v1 +114 = Íàçâàíèå +115 = Èñïîëíèòåëü +116 = Àëüáîì +117 = Ãîä +118 = Êîììåíòàðèé +119 = Íîìåð òðåêà +120 = Æàíð +121 = Ìá +122 = Âëåâî +123 = Âïðàâî +124 = Ââåðõ +125 = Âíèç +126 = Ëåâàÿ ñîôò +127 = Ïðàâàÿ ñîôò +128 = Äæîéñòèê +129 = Çâîíîê +130 = Îòìåíà +131 = Ââåðõ íà ýêðàí +132 = Âíèç íà ýêðàí +133 = Ââåðõ íà ôàéë +134 = Âíèç íà ôàéë +135 = Ãîð. êëàâèøè +136 = Äîïîëíèòåëüíî +137 = Ïàíåëè +138 = Ïàíåëü 1 +139 = Ïàíåëü 2 +140 = Ïàíåëü 3 +141 = Ïàíåëü 4 +142 = Ïàíåëü 5 +143 = Ïàíåëü 6 +144 = Ïàíåëü 7 +145 = Ïàíåëü 8 +146 = Ïàíåëü 9 +147 = Ïàíåëü 10 +148 = Âî âåñü ýêðàí +149 = ïóñòî +150 = Êëàâèàòóðà... +151 = ßçûê / Language +152 = Öâåòîâàÿ ñõåìà +153 = Ïðîâåðÿòü àòòðèáóòû ôàéëîâ +154 = Òî÷íàÿ ïðîâåðêà äèðåêòîðèé +155 = Ñîðòèðîâêà ñïèñêà ôàéëîâ +156 = Òîëüêî ÷òåíèå +157 = Ñêðûòûé +158 = Ñîäåðæèò +159 = %A ïàïîê, %B ôàéëîâ +160 = Íàñòðîéêè ïëååðà +161 = Êîäèðîâêà ID3 +162 = Ïîêàçûâàòü ïðîãðåññ-áàð +163 = Ðàçìåð áóôåðà òðåêåðíûõ ìîäóëåé, ñåê. +164 = Âûïîëíåíî +165 = Íàñòðîéêè òåêñòîâîãî ðåäàêòîðà +166 = Ïîêàçûâàòü ñèìâîë CR +167 = Ïîêàçûâàòü ñèìâîë LF +168 = Çàìåíÿòü òàáóëÿöèþ ïðîáåëàìè +169 = Ïåðåõîä +170 = Ïîñòðàíè÷íàÿ ïðîêðóòêà âìåñòî ïîñòðî÷íîé +171 = Ðàñêëàäêà êëàâèàòóðû +172 = Íà÷àëüíàÿ íàñòðîéêà +173 = Ðåæèì ÷àñîâ +174 = Ïåðåêëþ÷åíèå +175 = Ñëåä. ïàíåëü +176 = Ïðåä. ïàíåëü +177 = Ñëåä. ïóñòàÿ +178 = Ïðåä. ïóñòàÿ +179 = Îáìåí ïàíåëåé +180 = Èçìåíèòü +181 = Ïîèñê +182 = Øðèôò +183 = Êîäèðîâêà +184 = Ðåêóðñèâíûé ïîèñê +185 = Õåø-ñóììà +186 = Øèôðîâàíèå +187 = Ïàðîëü +188 = Èñïîëüçóéòå ïîâòîðíîå øèôðîâàíèå ñ òåì æå ïàðîëåì äëÿ ðàñøèôðîâêè. +189 = Ìàëûé +190 = Ñðåäíèé +191 = Áîëüøîé +192 = Òèï +193 = Ñòèëü +194 = Æèðíûé +195 = Êóðñèâ +196 = Ìîíîøèðèííûé +197 = Ïðîïîðöèîíàëüíûé +198 = Ñèñòåìíûé +199 = Ïîä÷åðêíóòûé +200 = Ïîêàçûâàòü íîìåðà ïóíêòîâ ìåíþ +201 = Âîñïðîèçâåäåíèå â ñëó÷àéíîì ïîðÿäêå +202 = Ïåðåêîäèðîâàòü +203 = Çàêàçíàÿ +204 = Ïëåéëèñò +205 = Èñêàòü â àðõèâàõ +206 = Àóäèî +207 = Âèäåî +208 = Ñîõðàíÿòü ïóòè +209 = Àáñîëþòíûå +210 = Îòíîñèòåëüíûå +211 = Àðõèâàòîð ZIP +212 = Àðõèâàòîð PPK +213 = Àóäèîïðîèãðûâàòåëü +214 = Ïðîñìîòð èçîáðàæåíèé +215 = Âèäåîïðîèãðûâàòåëü +216 = Òåêñòîâûé ðåäàêòîð +217 = Ðåäàêòîð çàìåòîê +218 = Òðåêåðíûé ïðîèãðûâàòåëü +219 = Óñòàíîâùèê öâåòîâûõ ñõåì +220 = Ïðîñìîòð âåêòîðíûõ èçîáðàæåíèé +221 = Êóðñîð â âèäå ðàìêè +222 = Áåç èçìåíåíèé +223 = Óñòàíîâèòü +224 = Ñáðîñèòü +225 = Ôîíîâîå èçîáðàæåíèå +226 = Øàáëîí èìåíè +227 = Ñâåðíóòü +228 = Ñîõðàíèòü èçìåíåíèÿ? +229 = Ñîõðàíèòü êàê... +230 = Ïðàâêà +231 = Îòìåíèòü +232 = Ïîâòîðèòü +233 = Íàéòè +234 = Íàéòè äàëåå +235 = Òåêñò +236 = Êîäèðîâêà àðõèâîâ +237 = Íîìåð ñòðîêè +238 = Çàïîìèíàòü îòêðûòûå ïóòè +239 = Øàáëîíû +240 = Èñïîëüçîâàòü UTF BOM ñèãíàòóðó +241 = Äîñòèãíóò êîíåö ôàéëà. Ïðîäîëæèòü ïîèñê ñ íà÷àëà? +242 =  íà÷àëî +243 =  êîíåö +244 = Äîáàâèòü +245 = Ïðîèãðûâàòü ñèãíàëû â ñîîáùåíèÿõ +246 = Ïîìåíÿòü ìåñòàìè ñîôò-êëàâèøè â ìåíþ +247 = Íå ó÷èòûâàòü ðåãèñòð +248 = Íå ñîðòèðîâàòü +249 = Ïî èìåíè +250 = Ïî òèïó +251 = Ïî äàòå èçìåíåíèÿ +252 = Ïî ðàçìåðó +253 = Îïöèè ñîðòèðîâêè +254 =  îáðàòíîì ïîðÿäêå +255 = Ïåðåçàïóñê +256 = Ïåðåâîäèòü êóðñîð ïðè âûäåëåíèè +257 = Çàìåíèòü +258 = Çàìåíèòü âñå +259 = Çàìåíèòü íà +260 = Ïåðåìåñòèòü ÷àñû +261 = ñîâïàäåíèé +262 = Ýêâàëàéçåð +263 = Ãö +264 = ÊÃö +265 = äÁ +266 = Èñïîëüçîâàòü àêñåëåðîìåòð +267 = Ïîñòîÿííàÿ ïîäñâåòêà +268 = ×àñòîòà äèñêðåòèçàöèè òðåêåðíûõ ìîäóëåé +269 = Êà÷åñòâî ðåñåìïëèíãà òðåêåðíûõ ìîäóëåé +270 = Íèçêîå +271 = Ñðåäíåå +272 = Âûñîêîå +273 = Îòêëþ÷åíî +274 = Âêëþ÷åíî +275 = Àâòîìàòè÷åñêè +276 = Ýêðàíèðîâàòü +277 = Ðàçýêðàíèðîâàòü +278 = Áóôåð îáìåíà ïóñò! +279 = Ìîäóëè +280 = Óïàêîâêà ôàéëà %A... +281 = Ñïèñêè âîñïðîèçâåäåíèÿ +282 = Çàãëóøêà +283 = Ñèìâîë +284 = Çàãîëîâîê òåêñòîâîãî îêíà +285 = Îáû÷íûé +286 = Áåãóùàÿ ñòðîêà +287 = Àðõèâ ZIP +288 = Àðõèâ PPK +289 = Ðàñïàêîâêà ôàéëà %A... +290 = Ìîíèòîð ïàìÿòè +291 = Îáíîâèòü +292 = Çàïîëíèòü +293 = Çàíÿòî +294 = Âñåãî +295 = Øàã ìîíèòîðà ïàìÿòè, ìñ +296 = Ïîðîã ñáîðùèêà ìóñîðà, % +297 = Êîíòåéíåðû +298 = Çàêðûòü +299 = Çàêðûòü âñå +300 = Çàïèñü ôàéëà %A... +301 = Ïàëèòðà +302 = Ïîäáîð öâåòà +303 = %A îáðàù., %B çàâèñ. +304 = Ñêîðîñòü ïðîêðóòêè äëèííûõ ýëåìåíòîâ +305 = Óñòàíîâêà öâåòîâîé ñõåìû... +306 = Óëó÷øåííûå ãðàäèåíòû +307 = Ïðîçðà÷íîñòü â ãðàäèåíòàõ +308 = Ðàçìåð òåêñòîâîãî áóôåðà, ñèìâ. +309 = Ïîëíûå èìåíà ôàéëîâ +310 =  Áóôåðå îáìåíà +311 =  Èçáðàííîì +312 = Ââîä +313 = Íàçíà÷åíèå êëàâèø +314 = Ïîëüçîâàòåëüñêèå êëàâèøè +315 = Ðåäàêòîð êëàâèø +316 = Êîä êëàâèøè +317 = Ñîáñòâåííûé îáðàáîò÷èê óñòðîéñòâà +318 = Àááðåâèàòóðà +319 = Íàæìèòå êëàâèøó... +320 = Ãîð. %A +321 = Óäåðæ. %A +322 = Êîðåíü +323 = Ñïèñîê ôàéëîâ +324 = Êîðçèíà +325 = Àðõèâàòîð RAR +326 = Íàçíà÷èòü +327 = Ñáðîñèòü +328 = Êåøèðîâàòü êîäîâûå ñòðàíèöû +329 = Êðóïíûé øðèôò +330 =  ñïèñêå ôàéëîâ +331 =  ìåíþ +332 = "Âûõîä" â ñïèñêå äèñêîâ +333 = Ôîðìàò ìåòàäàííûõ +334 = Ïîêàçûâàòü çàãîëîâêè ìåòàäàííûõ +335 = Ðåãóëÿðíûå âûðàæåíèÿ +336 = Ìíîãîñòðî÷íîå ñðàâíåíèå +337 = Çàìåíÿòü îáðàòíûå ññûëêè + +[1000] + +0 = Ðàñïàêîâùèê ÿçûêîâûõ ïàêåòîâ +1 = Çàïàêîâùèê ÿçûêîâûõ ïàêåòîâ + +[2000] + +0 = Ñêëåéêà ôàéëîâ +1 = Äåëèòåëü ôàéëîâ +2 = Êîëè÷åñòâî ÷àñòåé +3 = Ðàçìåð ÷àñòè +4 = Ðàçìåð ôàéëà íåèçâåñòåí, ðàçäåëåíèå íåâîçìîæíî. + +[3000] + +0 = Ïðîñìîòð ìîäåëåé MascotCapsule +1 = Ïðîñìîòð àíèìàöèè MascotCapsule +2 = Çàãðóç÷èê òåêñòóð MascotCapsule +3 = S %A Rx %D° Ry %E° Px %G Py %H F %J + +[3500] + +0 = Ïåðåêîäèðîâùèê Fishlabs \ No newline at end of file diff --git a/other/fishlabs-uncoder/modules/FishlabsUncoder.class b/other/fishlabs-uncoder/modules/FishlabsUncoder.class new file mode 100644 index 0000000..7a4184a Binary files /dev/null and b/other/fishlabs-uncoder/modules/FishlabsUncoder.class differ diff --git a/other/image/ImageContainer.java b/other/image/ImageContainer.java new file mode 100644 index 0000000..1df7572 --- /dev/null +++ b/other/image/ImageContainer.java @@ -0,0 +1,194 @@ +package modules.image; + +import com.one.ImageProcessor; +import com.one.vector.VectorImage; +import filemanager.images; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; + +public interface ImageContainer +{ + public int getWidth(); + public int getHeight(); + + public void scale(int width, int height); + public void paint(Graphics g, int x, int y, int transform); + + public long getFrameDelay(); + public int currentFrame(); + public void gotoFrame(int target); + public boolean nextFrame(); + public boolean prevFrame(); +} + +class TestImageContainer implements ImageContainer +{ + protected Image image; + + public TestImageContainer() + { + scale(768, 576); + } + + public int getWidth() + { + return image.getWidth(); + } + + public int getHeight() + { + return image.getHeight(); + } + + public void scale(int width, int height) + { + image = Image.createImage(width, height); + Graphics g = image.getGraphics(); + + g.setColor(0xFF000000); + g.fillRect(0, 0, width, height); + + images.drawVColorTest(g, 0, 0, width, height); + + g.setColor(0xFFFFFFFF); + g.drawRect(0, 0, width - 1, height - 1); + } + + public void paint(Graphics g, int x, int y, int transform) + { + g.drawRegion(image, 0, 0, image.getWidth(), image.getHeight(), transform, x, y, Graphics.LEFT | Graphics.TOP); + } + + public long getFrameDelay() + { + return 0; + } + + public int currentFrame() + { + return 0; + } + + public void gotoFrame(int target) + { + } + + public boolean nextFrame() + { + return false; + } + + public boolean prevFrame() + { + return false; + } +} + +class GenericImageContainer implements ImageContainer +{ + protected Image image; + + public GenericImageContainer(Image image) + { + this.image = image; + } + + public int getWidth() + { + return image.getWidth(); + } + + public int getHeight() + { + return image.getHeight(); + } + + public void scale(int width, int height) + { + image = ImageProcessor.scaleImage(image, width, height, false, true); + } + + public void paint(Graphics g, int x, int y, int transform) + { + g.drawRegion(image, 0, 0, image.getWidth(), image.getHeight(), transform, x, y, Graphics.LEFT | Graphics.TOP); + } + + public long getFrameDelay() + { + return 0; + } + + public int currentFrame() + { + return 0; + } + + public void gotoFrame(int target) + { + } + + public boolean nextFrame() + { + return false; + } + + public boolean prevFrame() + { + return false; + } +} + +class VectorImageContainer implements ImageContainer +{ + protected VectorImage image; + + public VectorImageContainer(VectorImage image) + { + this.image = image; + } + + public int getWidth() + { + return image.getWidth(); + } + + public int getHeight() + { + return image.getHeight(); + } + + public void scale(int width, int height) + { + image.scale(width, height); + } + + public void paint(Graphics g, int width, int height, int transform) + { + image.paint(g, width, height); + } + + public long getFrameDelay() + { + return image.getFrameDelay(); + } + + public int currentFrame() + { + return image.currentFrame(); + } + + public void gotoFrame(int target) + { + image.gotoFrame(target); + } + + public boolean nextFrame() + { + return image.nextFrame(); + } + + public boolean prevFrame() + { + return image.prevFrame(); + } +} diff --git a/other/image/ImageModule.java b/other/image/ImageModule.java new file mode 100644 index 0000000..251fd52 --- /dev/null +++ b/other/image/ImageModule.java @@ -0,0 +1,19 @@ +package modules.image; + +import com.one.Application; +import com.one.PlayList; + +public class ImageModule implements Application +{ + public void openFile(String filename, PlayList filelist) + { + cvsImageView imageView = cvsImageView.getInstance(); + + if(filelist != null) + { + imageView.setPlayList(filelist); + } + + imageView.displayImage(filename); + } +} diff --git a/other/image/ImageOptions.java b/other/image/ImageOptions.java new file mode 100644 index 0000000..c8d713d --- /dev/null +++ b/other/image/ImageOptions.java @@ -0,0 +1,111 @@ +package modules.image; + +import com.one.ModuleRegistry; +import com.one.OptionStorage; +import com.vmx.Locale; +import filemanager.main; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import javax.microedition.lcdui.Choice; +import javax.microedition.lcdui.ChoiceGroup; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; + +public class ImageOptions implements CommandListener, OptionStorage +{ + public static int rotateMode = 0; + public static boolean scaleImages = true; + public static boolean useAccelerometer = false; + + protected Object parent; + + protected ChoiceGroup cgPlayer; + + public void showEditor(Object parent) + { + this.parent = parent; + + restoreOptions(); + + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + // *** ÐаÑтройки плеера *** + cgPlayer = new ChoiceGroup(null, Choice.MULTIPLE); + + // ИÑпользовать акÑелерометр + cgPlayer.append(Locale.getString(this, Locale.PREF_USE_ACCELEROMETER), null); + cgPlayer.setSelectedIndex(0, useAccelerometer); + + form.append(cgPlayer); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 2)); + + form.setCommandListener(this); + + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable d) + { + if(c.getCommandType() == Command.OK) + { + useAccelerometer = cgPlayer.isSelected(0); + + saveOptions(); + } + + main.dsp.setCurrent(parent); + } + + public void restoreOptions() + { + try + { + byte[] data = ModuleRegistry.getModuleData(getClass().getName()); + + if(data == null || data.length == 0) + { + return; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data)); + + rotateMode = dis.readInt(); + scaleImages = dis.readBoolean(); + useAccelerometer = dis.readBoolean(); + + dis.close(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + + public void saveOptions() + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(rotateMode); + dos.writeBoolean(scaleImages); + dos.writeBoolean(useAccelerometer); + + byte[] data = baos.toByteArray(); + dos.close(); + + ModuleRegistry.setModuleData(getClass().getName(), data); + } + catch(Exception e) + { + e.printStackTrace(); + } + } +} diff --git a/other/image/VectorModule.java b/other/image/VectorModule.java new file mode 100644 index 0000000..f78acda --- /dev/null +++ b/other/image/VectorModule.java @@ -0,0 +1,19 @@ +package modules.image; + +import com.one.Application; +import com.one.PlayList; + +public class VectorModule implements Application +{ + public void openFile(String filename, PlayList filelist) + { + cvsImageView imageView = cvsImageView.getInstance(); + + if(filelist != null) + { + imageView.setPlayList(filelist); + } + + imageView.displayVectorImage(filename); + } +} diff --git a/other/image/cvsImageView.java b/other/image/cvsImageView.java new file mode 100644 index 0000000..e2c6b07 --- /dev/null +++ b/other/image/cvsImageView.java @@ -0,0 +1,780 @@ +package modules.image; // переведен + +import javax.microedition.lcdui.*; +import javax.microedition.lcdui.game.*; +import java.util.Timer; +import java.io.*; +import com.vmx.*; +import com.one.*; +import com.one.vector.*; + +import com.one.file.*; +import filemanager.ColorScheme; +import filemanager.images; +import filemanager.main; +import java.util.Enumeration; +import java.util.TimerTask; + +/** + * КлаÑÑ - проÑмотрщик картинок + */ +public class cvsImageView extends gkcCanvas implements Runnable +{ + public static final int MODE_NULL = 0; + public static final int MODE_NORMAL = 1; + public static final int MODE_VECTOR = 2; + + private ImageContainer currentImage = null; + private int mode; + + private boolean rotate; + private int trans; + private boolean scaled; + + private boolean enableUI = true; + private int pictureWidth, pictureHeight; + private int currWidth, currHeight; + private double pictureAspect; + private int w, h; + private double aspect; + private int curposx, curposy; + private String OnlyFileName = ""; + private Font nameFont; + private int hstep, vstep; + private int navx, navy, navw, navh; // большой прÑмоугольник + private int navcx, navcy, navcw, navch; // малый примоугольник + private Timer timer = null; + private boolean isshown; + private int runpanel; + private PlayList playlist; + private boolean allowKeyRelease = true; + + protected static class AnimationTask extends TimerTask + { + protected ImageContainer image; + protected PaintableObject canvas; + + public AnimationTask(ImageContainer image, PaintableObject canvas) + { + this.image = image; + this.canvas = canvas; + } + + public void run() + { + synchronized(image) + { + image.nextFrame(); + } + + canvas.repaint(); + canvas.serviceRepaints(); + } + } + + private static cvsImageView instance; + + public static void loadInstance() + { + if(instance == null) + { + instance = new cvsImageView(); + } + } + + public static cvsImageView getInstance() + { + loadInstance(); + return instance; + } + + /** + * КонÑтруктор + */ + public cvsImageView() + { + setFullScreenMode(true); + + w = getWidth(); + h = getHeight(); + + aspect = (double)w / (double)h; + + nameFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); + + //fgimage = images.createUI(w, h); + + runpanel = -1; + } + + public void setPlayList(PlayList newlist) + { + playlist = newlist; + } + + public void setPlayList(Enumeration newlist) + { + playlist = new PlayList(newlist); + } + + protected void initPanels() + { + if(timer != null) + { + timer.cancel(); + timer = null; + } + + mode = MODE_NULL; + currentImage = null; + + if(runpanel < 0) + { + runpanel = main.manager.currentPanel(); + } + + main.manager.setCurrent(this, runpanel); + main.manager.updateAssociation(runpanel, playlist.getCurrentElement()); + main.manager.changePanel(runpanel); + } + + protected void initPlayList(String file) + { + OnlyFileName = file.substring(file.lastIndexOf('/') + 1); + + if(playlist == null) + { + playlist = new PlayList(file); + } + + playlist.selectElement(file); + } + + protected void initDisplay() + { + // ПрÑчем картинку за пределы Ñкрана на Ð²Ñ€ÐµÐ¼Ñ + curposx = w; + curposy = h; + + pictureWidth = currentImage.getWidth(); + pictureHeight = currentImage.getHeight(); + + switch(ImageOptions.rotateMode) + { + default: + case 0: + rotate = false; + trans = Sprite.TRANS_NONE; + break; + + case 1: + rotate = true; + trans = Sprite.TRANS_ROT90; + break; + + case 2: + rotate = false; + trans = Sprite.TRANS_ROT180; + break; + + case 3: + rotate = true; + trans = Sprite.TRANS_ROT270; + break; + + case 4: + if(pictureWidth > pictureHeight) + { + rotate = true; + trans = Sprite.TRANS_ROT90; + } + break; + + case 5: + if(pictureWidth > pictureHeight) + { + rotate = true; + trans = Sprite.TRANS_ROT270; + } + break; + } + + if(ImageOptions.scaleImages) + { + pictureAspect = (double)pictureWidth / (double)pictureHeight; + + if(rotate) //еÑли поворачиваем + { + /* Ñкран повернут, так что ширина Ñто h и выÑота Ñто w */ + + if(pictureAspect > (1 / aspect)) //впиÑываем по ширине + { + currentImage.scale(h, (int)(h / pictureAspect)); + } + else //впиÑываем по выÑоте + { + currentImage.scale((int)(w * pictureAspect), w); + } + } + else //еÑли не поворачиваем + { + if(pictureAspect > aspect) //впиÑываем по ширине + { + currentImage.scale(w, (int)(w / pictureAspect)); + } + else //впиÑываем по выÑоте + { + currentImage.scale((int)(h * pictureAspect), h); + } + } + + // SHIT! Что-то мне подÑказывает, что Ñто можно было Ñделать проще... + } + + currWidth = currentImage.getWidth(); + currHeight = currentImage.getHeight(); + + if(currWidth != pictureWidth || currHeight != pictureHeight) + { + scaled = true; + hstep = vstep = 0; + } + else + { + scaled = false; + hstep = vstep = (w + h) / 6; + } + + if(rotate) + { + currWidth ^= currHeight; + currHeight ^= currWidth; + currWidth ^= currHeight; + } + + if(currWidth > currHeight) // изображение горизонтальное + { + navw = w / 4; + navh = navw * currHeight / currWidth; + } + else + { + navh = w / 4; + navw = navh * currWidth / currHeight; + } + + navx = w - navw - 4; + navy = 3; + + curposx = (w - currWidth) / 2; + curposy = (h - currHeight) / 2; + } + + public void displayImageFromStream(InputStream is, String imgName) + { + initPanels(); + + mode = MODE_NORMAL; + + initPlayList(imgName); + + repaint(); + serviceRepaints(); + + try + { + currentImage = new GenericImageContainer(Image.createImage(is)); + is.close(); + } + catch(Exception x) + { + ErrScreen.showErrMsg(123, x); + +// x.printStackTrace(); +// +// currentImage = new TestImageContainer(); +// OnlyFileName = x.toString(); + } + + initDisplay(); + + repaint(); + } + + public void displayImage(String imgName) + { + try + { + FileConnection fc = (FileConnection)Connector.open("file:///" + imgName, Connector.READ); + displayImageFromStream(fc.openInputStream(), imgName); + } + catch(Exception e) + { + } + } + + public void displayVectorImageFromStream(InputStream is, String imgName) + { + initPanels(); + + mode = MODE_VECTOR; + currentImage = null; + + initPlayList(imgName); + repaint(); + + try + { + is = new DataInputStream(is); + currentImage = new VectorImageContainer(new VectorImage((DataInputStream)is)); + is.close(); + } + catch(Exception x) + { + ErrScreen.showErrMsg(124, x); + +// x.printStackTrace(); +// +// currentImage = new TestImageContainer(); +// OnlyFileName = x.toString(); + } + + initDisplay(); + + repaint(); + } + + public void displayVectorImage(String imgName) + { + try + { + FileConnection fc = (FileConnection)Connector.open("file:///" + imgName, Connector.READ); + displayVectorImageFromStream(fc.openInputStream(), imgName); + } + catch(Exception e) + { + } + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð¸Ñовки + */ + public void paint(Graphics g) + { + g.setColor(images.cImgBack); // 0x000000); + g.fillRect(0, 0, w, h); + + // фон + if(currentImage != null) + { + currentImage.paint(g, curposx, curposy, trans); + } + + if(enableUI) + { + if(currentImage != null && (currWidth > w || currHeight > h)) + { + // ----- прÑмоугольники в правом верхнем углу ----- + + g.setColor(ColorScheme.colors[ColorScheme.back1]); + g.fillRect(navx, navy, navw, navh); + + if(currWidth > w) + { + navcw = navw * w / currWidth; + navcx = navx - curposx * navw / currWidth; + } + else + { + navcw = navw; + navcx = navx; + } + + if(currHeight > h) + { + navch = navh * h / currHeight; + navcy = navy - curposy * navh / currHeight; + } + else + { + navch = navh; + navcy = navy; + } + + /* - такого не должно быть - Ñм. уÑÐ»Ð¾Ð²Ð¸Ñ Ð²Ñ‹ÑˆÐµ + if(navcw > navw) + { + navcw = navw; + } + + if(navch > navh) + { + navch = navh; + } + + if(navcx < navx) + { + navcx = navx; + } + else if(navcx + navcw > navx + navw) + { + navcx = navx + navw - navcw; + } + + if(navcy < navy) + { + navcy = navy; + } + else if(navcy + navch > navy + navh) + { + navcy = navy + navh - navch; + } + */ + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.fillRect(navcx + 1, navcy + 1, navcw, navch); + + g.setColor(ColorScheme.colors[ColorScheme.dkborder]); + g.drawRect(navx, navy, navw, navh); + + // ----- закончилиÑÑŒ прÑмоугольники ----- + } + + if(images.minUI != null) + { + g.drawImage(images.minUI, 0, h, Graphics.LEFT | Graphics.BOTTOM); + } + + g.setFont(nameFont); + + g.setColor(images.cPlayFore1); //0x800000); + g.drawString(OnlyFileName, w / 2, h - images.uiBottomHeight + images.uiBottomVSpace, Graphics.TOP | Graphics.HCENTER); + + if(currentImage != null) + { + String tmp = pictureWidth + " x " + pictureHeight + " ("; + + if(scaled) + { + tmp += Locale.getString(this, Locale.IMAGEVIEW_SCALED) + ", "; + } + + if(mode == MODE_VECTOR && currentImage != null) + { + tmp += Integer.toString(currentImage.currentFrame()); + } + else + { + switch(trans) + { + case Sprite.TRANS_NONE: + tmp += "0°"; + break; + + case Sprite.TRANS_ROT90: + tmp += "90°"; + break; + + case Sprite.TRANS_ROT180: + tmp += "180°"; + break; + + case Sprite.TRANS_ROT270: + tmp += "270°"; + break; + } + } + + tmp += ")"; + + g.setColor(images.cPlayFore2); //0x000080); + g.drawString(tmp, w / 2, h - images.uiBottomVSpace, Graphics.BOTTOM | Graphics.HCENTER); + } + } + } + + public void keyReleased(int keyCode) + { + if(allowKeyRelease) + { + handleKeyAction(keyCode); + } + else + { + allowKeyRelease = true; + } + } + + public void keyRepeated(int keyCode) + { + allowKeyRelease = false; + handleKeyAction(keyCode); + } + + /** + * Обработчик нажатий клавиш + */ + public void handleKeyAction(int keyCode) + { + keyCode = rotateKey(keyCode, trans); + + if(keyCode == KEY_POUND) + { + enableUI = !enableUI; + repaint(); + } + else if(keyCode == KEY_DOWN || keyCode == KEY_RIGHT) // Ð¡Ð»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + { + nextPicture(); + } + else if(keyCode == KEY_UP || keyCode == KEY_LEFT) // Предыдущ картинка + { + prevPicture(); + } + else if(keyCode == KEY_LSK) + { + if(mode == MODE_VECTOR) + { + if(timer != null) + { + timer.cancel(); + timer = null; + } + else + { + timer = new Timer(); + timer.scheduleAtFixedRate(new AnimationTask(currentImage, this), 0, currentImage.getFrameDelay()); + } + } + } + else if(keyCode == KEY_RSK) // Выход + { + if(timer != null) + { + timer.cancel(); + timer = null; + } + + mode = MODE_NULL; + + playlist.cancelSearch(); + playlist = null; + + main.manager.ret(); + runpanel = -1; + } + else if(keyCode == KEY_CANCEL) // ÑворачиваемÑÑ + { + main.manager.minimizePanel(); + } + else if(keyCode == KEY_NUM4) + { + curposx += hstep; + + if(curposx > 0) + { + curposx = 0; + } + + repaint(); + } + else if(keyCode == KEY_NUM6) + { + curposx -= hstep; + + if(curposx < w - currWidth) + { + curposx = w - currWidth; + } + + repaint(); + } + else if(keyCode == KEY_NUM2) + { + curposy += vstep; + + if(curposy > 0) + { + curposy = 0; + } + + repaint(); + } + else if(keyCode == KEY_NUM8) + { + curposy -= vstep; + + if(curposy < h - currHeight) + { + curposy = h - currHeight; + } + + repaint(); + } + else if(keyCode == KEY_NUM5) + { + curposx = (w - currWidth) / 2; + curposy = (h - currHeight) / 2; + + repaint(); + } + else if(keyCode == KEY_STAR) + { + if(++ImageOptions.rotateMode > 3) + { + ImageOptions.rotateMode = 0; + } + + redisplay(); + } + else if(keyCode == KEY_NUM0) + { + // еÑли не вышло маÑштабировать, + // то нечего и переключать + + boolean wasrunning = timer != null; + int prevframe = currentImage.currentFrame(); + + if(wasrunning) + { + timer.cancel(); + timer = null; + } + + ImageOptions.scaleImages = !scaled; + redisplay(); + + currentImage.gotoFrame(prevframe); + + if(wasrunning) + { + timer = new Timer(); + timer.scheduleAtFixedRate(new AnimationTask(currentImage, this), 0, currentImage.getFrameDelay()); + } + } + else if(keyCode == KEY_NUM1) + { + if(timer == null) + { + if(mode == MODE_VECTOR) + { + currentImage.prevFrame(); + repaint(); + } + } + } + else if(keyCode == KEY_NUM3) + { + if(timer == null) + { + if(mode == MODE_VECTOR) + { + currentImage.nextFrame(); + repaint(); + } + } + } + else if(keyCode == KEY_NUM7) + { + if(timer == null) + { + if(mode == MODE_VECTOR) + { + currentImage.gotoFrame(currentImage.currentFrame() - 10); + repaint(); + } + } + } + else if(keyCode == KEY_NUM9) + { + if(timer == null) + { + if(mode == MODE_VECTOR) + { + currentImage.gotoFrame(currentImage.currentFrame() + 10); + repaint(); + } + } + } + } + + /** + * ÑÐ»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + */ + public void nextPicture() + { + playlist.nextElement(false); + main.FileSelect.executeFile(playlist, null, runpanel); + } + + /** + * Ð¿Ñ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + */ + public void prevPicture() + { + playlist.prevElement(false); + main.FileSelect.executeFile(playlist, null, runpanel); + } + + private void redisplay() + { + if(mode == MODE_VECTOR) + { + currentImage.scale(-1, -1); + + initDisplay(); + + repaint(); + } + else + { + main.FileSelect.executeFile(playlist, null, runpanel); + } + } + + public void showNotify() + { + isshown = true; + + if(ImageOptions.useAccelerometer) + { + (new Thread(this, "ImageView/AccelEvent")).start(); + } + } + + public void hideNotify() + { + isshown = false; + } + + public void run() + { + while(isshown) + { + int delta = main.accelerometer.getDelta(0, 1200); + + if(currentImage != null || currentImage != null) + { + if(delta != 0) + { + if(delta > 0) + { + nextPicture(); + } + else + { + prevPicture(); + } + } + } + + try + { + Thread.sleep(300); + } + catch(InterruptedException ie) + { + } + } + } +} diff --git a/other/modules/DummyModule.java b/other/modules/DummyModule.java new file mode 100644 index 0000000..cc26820 --- /dev/null +++ b/other/modules/DummyModule.java @@ -0,0 +1,34 @@ +package modules; + +import com.one.Application; +import com.one.ModuleRegistry; +import com.one.PlayList; +import com.vmx.Locale; +import filemanager.main; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; + +public class DummyModule implements Application, CommandListener +{ + protected Object parent; + + public void openFile(String filename, PlayList filelist) + { + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + form.append(filename); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + form.setCommandListener(this); + + parent = main.dsp.getCurrent(); + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable dp) + { + main.dsp.setCurrent(parent); + } +} diff --git a/other/modules/color/ColorFileSource.java b/other/modules/color/ColorFileSource.java new file mode 100644 index 0000000..8203cee --- /dev/null +++ b/other/modules/color/ColorFileSource.java @@ -0,0 +1,34 @@ +package modules.color; + +import com.one.BufferedInputStream; +import com.one.FileSource; +import com.one.PlainPackage; +import com.one.file.Connector; +import com.one.file.FileConnection; +import filemanager.ColorScheme; +import filemanager.main; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class ColorFileSource implements FileSource +{ + public void createFile(String filename) throws IOException + { + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + + PlainPackage ppk = new PlainPackage(); + ppk.init(fc, true); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ColorScheme.saveColorScheme(baos); + + byte[] data = baos.toByteArray(); + baos.close(); + + ppk.addEntry(new BufferedInputStream(data), "scheme.ini", -1, true, null); + + ppk.close(); + + main.FileSelect.showWait(filename.substring(filename.lastIndexOf('/') + 1)); + } +} diff --git a/other/modules/color/ColorModule.java b/other/modules/color/ColorModule.java new file mode 100644 index 0000000..aff5671 --- /dev/null +++ b/other/modules/color/ColorModule.java @@ -0,0 +1,80 @@ +package modules.color; + +import com.one.Application; +import com.one.PlainPackage; +import com.one.PlayList; +import com.one.ProgressBar; +import com.one.TextProcessor; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.Locale; +import com.vmx.ProgressCallback; +import filemanager.ColorScheme; +import filemanager.main; +import filemanager.options; +import java.io.DataInputStream; +import java.io.IOException; + +public class ColorModule implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + options.colorScheme = ColorScheme.SCHEME_CUSTOM; + + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + DataInputStream dis = fc.openDataInputStream(); + + byte[] sig = new byte[3]; + dis.readFully(sig); + + String s = TextProcessor.byteArrayToString(sig); + + if(s.equals("MCS") || s.equals("Ths")) + { + ColorScheme.loadLegacyColorScheme(dis); + + dis.close(); + fc.close(); + + if(main.dsp.getCurrent() != main.FileSelect) + { + main.dsp.setCurrent(main.FileSelect); + } + + //main.FileSelect.updateGradients(); + main.FileSelect.repaint(); + } + else + { + dis.close(); + + ProgressCallback callback = ProgressBar.getProgressCallback(); + callback.setProgress(0); + callback.setText(Locale.getString(getClass().getName(), Locale.INSTALLING_COLOR_SCHEME)); + + PlainPackage ppk = new PlainPackage(); + ppk.init(fc, false); + + if(ColorScheme.loadModernColorScheme(ppk)) + { + //main.FileSelect.updateGradients(); + main.FileSelect.updateModuleList(); + main.FileSelect.showWait(main.currentFile); + } + else + { + if(main.dsp.getCurrent() != main.FileSelect) + { + main.dsp.setCurrent(main.FileSelect); + } + + //main.FileSelect.updateGradients(); + main.FileSelect.repaint(); + } + + ppk.close(); + } + } + + +} diff --git a/other/modules/playlist/M3UFileSource.java b/other/modules/playlist/M3UFileSource.java new file mode 100644 index 0000000..65c509f --- /dev/null +++ b/other/modules/playlist/M3UFileSource.java @@ -0,0 +1,151 @@ +package modules.playlist; + +import com.one.ErrScreen; +import com.one.FileSource; +import com.one.ModuleRegistry; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.AuxClass; +import com.vmx.Locale; +import com.vmx.OutputStreamEncoder; +import com.vmx.StringEncoder; +import filemanager.Buffer; +import filemanager.main; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; +import javax.microedition.lcdui.AlertType; +import javax.microedition.lcdui.Choice; +import javax.microedition.lcdui.ChoiceGroup; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; + +public class M3UFileSource implements FileSource, CommandListener +{ + protected Object parent; + protected String filename; + + protected ChoiceGroup cgType; + + public void createFile(String filename) throws IOException + { + this.filename = filename; + + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + cgType = new ChoiceGroup(/* Locale.getString(this, Locale.FILE_TYPE) */ null, Choice.EXCLUSIVE); + + Enumeration groups = ModuleRegistry.listSimalarityGroups(); + String group; + + while(groups.hasMoreElements()) + { + group = (String)groups.nextElement(); + cgType.append(group, ModuleRegistry.getIcon((String)ModuleRegistry.listSimilars(group).nextElement())); + } + + cgType.setSelectedIndex(0, true); + + form.append(cgType); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.CANCEL, 2)); + form.setCommandListener(this); + + parent = main.dsp.getCurrent(); + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable dp) + { + if(c.getCommandType() == Command.OK) + { + try + { + if(Buffer.getSize() == 0) + { + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.BUFFER_EMPTY), AlertType.WARNING, 3000, main.dsp.getCurrent()); + return; + } + + Vector group = AuxClass.enumerationToVector(ModuleRegistry.listSimilars(cgType.getString(cgType.getSelectedIndex())), null); + + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + + if(fc.exists()) + { + fc.truncate(0); + } + else + { + fc.create(); + } + + OutputStreamEncoder ose = new OutputStreamEncoder(fc.openOutputStream(), StringEncoder.ENC_DEFAULT); + + ose.writeBOM(); + + String disk = filename.substring(0, filename.indexOf('/')); + String path = filename.substring(0, filename.lastIndexOf('/') + 1); + + int dlen = disk.length(); + int plen = path.length(); + + Buffer.flattenBuffer(); + //Buffer.sortBuffer(); + + Enumeration buf = Buffer.getBuffer(); + String s, module; + int index; + + while(buf.hasMoreElements()) + { + s = (String)buf.nextElement(); + + index = s.lastIndexOf('.'); + + if(index >= 0) + { + module = ModuleRegistry.getModule(s.substring(index + 1)); + + if(module != null && group.contains(module)) + { + if(s.startsWith(path)) + { + ose.writeString(s.substring(plen).replace('/', '\\')); + } + else if(s.startsWith(disk)) + { + ose.writeString(s.substring(dlen).replace('/', '\\')); + } + else + { + ose.writeString(s.replace('/', '\\')); + } + + ose.writeChar('\r'); + ose.writeChar('\n'); + } + } + } + + ose.close(); + fc.close(); + + Buffer.clear(); + + main.FileSelect.showWait(filename.substring(filename.lastIndexOf('/') + 1)); + } + catch(Exception e) + { + ErrScreen.showErrMsg(20400, e); + } + } + else + { + main.dsp.setCurrent(parent); + } + } +} diff --git a/other/modules/playlist/M3UModule.java b/other/modules/playlist/M3UModule.java new file mode 100644 index 0000000..bb7143e --- /dev/null +++ b/other/modules/playlist/M3UModule.java @@ -0,0 +1,54 @@ +package modules.playlist; + +import com.one.Application; +import com.one.IniFile; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.InputStreamDecoder; +import com.one.PlayList; +import filemanager.main; +import java.io.IOException; +import java.util.Vector; + +public class M3UModule implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + InputStreamDecoder isd = InputStreamDecoder.getFileDecoder(fc); + + String disk = filename.substring(0, filename.indexOf('/')); + String path = filename.substring(0, filename.lastIndexOf('/') + 1); + + Vector files = new Vector(); + String s; + + while((s = IniFile.readIniLine(isd)) != null) + { + if(s.startsWith("#")) + { + continue; + } + + s = s.replace('\\', '/'); + + if(s.indexOf(':') >= 0) + { + files.addElement(s); + } + else if(s.startsWith("/")) + { + files.addElement(disk + s); + } + else + { + files.addElement(path + s); + } + } + + isd.close(); + fc.close(); + + main.FileSelect.executeFile(new PlayList(files.elements()), null, main.manager.currentPanel()); + } +} diff --git a/other/uni_icons/Blue_green.ncs b/other/uni_icons/Blue_green.ncs new file mode 100644 index 0000000..54fbda2 Binary files /dev/null and b/other/uni_icons/Blue_green.ncs differ diff --git a/other/uni_icons/Default icons.ncs b/other/uni_icons/Default icons.ncs new file mode 100644 index 0000000..890c88b Binary files /dev/null and b/other/uni_icons/Default icons.ncs differ diff --git a/other/uni_icons/Gray.ncs b/other/uni_icons/Gray.ncs new file mode 100644 index 0000000..64121f2 Binary files /dev/null and b/other/uni_icons/Gray.ncs differ diff --git a/other/uni_icons/Pink.ncs b/other/uni_icons/Pink.ncs new file mode 100644 index 0000000..3d71232 Binary files /dev/null and b/other/uni_icons/Pink.ncs differ diff --git a/other/uni_icons/SkyFor icons.ncs b/other/uni_icons/SkyFor icons.ncs new file mode 100644 index 0000000..78f7eea Binary files /dev/null and b/other/uni_icons/SkyFor icons.ncs differ diff --git a/other/uni_icons/Vista icons.ncs b/other/uni_icons/Vista icons.ncs new file mode 100644 index 0000000..849dcd6 Binary files /dev/null and b/other/uni_icons/Vista icons.ncs differ diff --git a/res/chars/chars.dat b/res/chars/chars.dat new file mode 100644 index 0000000..e4c8ac2 Binary files /dev/null and b/res/chars/chars.dat differ diff --git a/res/config/genres.ini b/res/config/genres.ini new file mode 100644 index 0000000..cecb593 --- /dev/null +++ b/res/config/genres.ini @@ -0,0 +1,126 @@ +0 = Blues +1 = Classic Rock +2 = Country +3 = Dance +4 = Disco +5 = Funk +6 = Grunge +7 = Hip-Hop +8 = Jazz +9 = Metal +10 = New Age +11 = Oldies +12 = Other +13 = Pop +14 = R&B +15 = Rap +16 = Reggae +17 = Rock +18 = Techno +19 = Industrial +20 = Alternative +21 = Ska +22 = Death Metal +23 = Pranks +24 = Soundtrack +25 = Euro-Techno +26 = Ambient +27 = Trip-Hop +28 = Vocal +29 = Jazz+Funk +30 = Fusion +31 = Trance +32 = Classical +33 = Instrumental +34 = Acid +35 = House +36 = Game +37 = Sound Clip +38 = Gospel +39 = Noise +40 = AlternRock +41 = Bass +42 = Soul +43 = Punk +44 = Space +45 = Meditative +46 = Instrumental Pop +47 = Instrumental Rock +48 = Ethnic +49 = Gothic +50 = Darkwave +51 = Techno-Industrial +52 = Electronic +53 = Pop-Folk +54 = Eurodance +55 = Dream +56 = Southern Rock +57 = Comedy +58 = Cult +59 = Gangsta +60 = Top 40 +61 = Christian Rap +62 = Pop/Funk +63 = Jungle +64 = Native American +65 = Cabaret +66 = New Wave +67 = Psychadelic +68 = Rave +69 = Showtunes +70 = Trailer +71 = Lo-Fi +72 = Tribal +73 = Acid Punk +74 = Acid Jazz +75 = Polka +76 = Retro +77 = Musical +78 = Rock & Roll +79 = Hard Rock +80 = Folk +81 = Folk-Rock +82 = National Folk +83 = Swing +84 = Fast Fusion +85 = Bebob +86 = Latin +87 = Revival +88 = Celtic +89 = Bluegrass +90 = Avantgarde +91 = Gothic Rock +92 = Progressive Rock +93 = Psychedelic Rock +94 = Symphonic Rock +95 = Slow Rock +96 = Big Band +97 = Chorus +98 = Easy Listening +99 = Acoustic +100 = Humour +101 = Speech +102 = Chanson +103 = Opera +104 = Chamber Music +105 = Sonata +106 = Symphony +107 = Booty Bass +108 = Primus +109 = Porn Groove +110 = Satire +111 = Slow Jam +112 = Club +113 = Tango +114 = Samba +115 = Folklore +116 = Ballad +117 = Power Ballad +118 = Rhythmic Soul +119 = Freestyle +120 = Duet +121 = Punk Rock +122 = Drum Solo +123 = A capella +124 = Euro-House +125 = Dance Hall diff --git a/res/config/groups.ini b/res/config/groups.ini new file mode 100644 index 0000000..cc42a18 --- /dev/null +++ b/res/config/groups.ini @@ -0,0 +1,3 @@ +Audio = modules.audio.AudioModule, modules.audio.TrackerModule +Video = modules.video.VideoModule +Image = modules.image.ImageModule, modules.image.VectorModule \ No newline at end of file diff --git a/res/config/keymap.ini b/res/config/keymap.ini new file mode 100644 index 0000000..0ccc7d1 --- /dev/null +++ b/res/config/keymap.ini @@ -0,0 +1,12 @@ +; Something = UP DOWN LEFT RIGHT FIRE LSK RSK DIAL CANCEL BACK CLEAR + +; Siemens = -59 -60 -61 -62 -26 -1 -4 -11 -12 0 0 +; Sony Ericsson = -1 -2 -3 -4 -5 -6 -7 0 0 -11 -8 +; Motorola = -1 -6 -2 -5 -20 -21 -22 -10 0 0 0 + +; Something = UP DOWN LEFT RIGHT FIRE LSK RSK GREEN RED + +Sony Ericsson (JP-7) = -1 -2 -3 -4 -5 -6 -7 -8 -11 +Sony Ericsson (JP-8) = -1 -2 -3 -4 -5 -6 -7 -8 -10 +Siemens = -59 -60 -61 -62 -26 -1 -4 -11 -12 +Motorola = -1 -6 -2 -5 -20 -21 -22 -10 0 \ No newline at end of file diff --git a/res/config/mime.ini b/res/config/mime.ini new file mode 100644 index 0000000..ce104dd --- /dev/null +++ b/res/config/mime.ini @@ -0,0 +1,22 @@ +; Here we map file extensions with MIME types. +; This mapping is used when opening sounds and videos from streams. + +; audio +.mid = audio/midi +.midi = audio/midi +.kar = audio/midi +.imy = audio/imy +.bas = audio/bas +.wav = audio/x-wav +.wave = audio/x-wav +.amr = audio/amr +.mp3 = audio/mpeg +.m4a = audio/m4a +.aac = audio/aac +.wma = audio/x-ms-wma + +; video +.3gp = video/3gpp +.mp4 = video/mp4 +.wmv = video/x-ms-wmv +.mpeg = video/mpeg \ No newline at end of file diff --git a/res/config/modules.ini b/res/config/modules.ini new file mode 100644 index 0000000..15789bc --- /dev/null +++ b/res/config/modules.ini @@ -0,0 +1,58 @@ +; This file describes modules in general. +; Sections, like [Container] or [Application], define type of a module. Containers are used to transparently open various archives and packages of files, Applications are used to display file contents to the user and to edit those contents. +; FileSources are used to create new files. ContainerSources are technically similar to FileSources, but are used to create containers rather than simple files and are stored in separate internal list. + +; Each record in this file has the following syntax: +; module.package.ModuleClass = [, icon_file.ext [@ x, y, width, height]] + +; If you plan to obfuscate your module, don't forget to tell your obfuscator to adapt the contents of this file. +; For ProGuard it is done like that: -adaptresourcefilecontents config/* + +[Container] + +com.classpath.zip.ZipFile = # 211, icons.png @ 80, 0, 16, 16 +com.innosystec.unrar.Archive = # 325, icons.png @ 80, 0, 16, 16 +com.one.PlainPackage = # 212, icons.png @ 80, 0, 16, 16 + +[Application] + +;modules.PlatformRequestModule = # 317, icons.png @ 0, 0, 16, 16 +modules.audio.AudioModule = # 213, icons.png @ 16, 0, 16, 16 +modules.image.ImageModule = # 214, icons.png @ 32, 0, 16, 16 +modules.video.VideoModule = # 215, icons.png @ 48, 0, 16, 16 +modules.text.TextModule = # 216, icons.png @ 64, 0, 16, 16 +modules.TMOModule = # 217, icons.png @ 96, 0, 16, 16 +modules.audio.TrackerModule = # 218, icons.png @ 16, 0, 16, 16 +modules.color.ColorModule = # 219, icons.png @ 32, 0, 16, 16 +modules.image.VectorModule = # 220, icons.png @ 32, 0, 16, 16 +modules.mascot.MascotViewer = # 0, icons.png @ 32, 0, 16, 16 +modules.mascot.AnimationViewer = # 1, icons.png @ 48, 0, 16, 16 +modules.mascot.TextureLoader = # 2, icons.png @ 32, 0, 16, 16 +modules.id3Editor = # 113, icons.png @ 16, 0, 16, 16 +modules.playlist.M3UModule = # 281, icons.png @ 16, 0, 16, 16 +modules.FileSplitter = # 1, icons.png @ 0, 0, 16, 16 +modules.FishlabsUncoder = # 0, icons.png @ 0, 0, 16, 16 +modules.mocha.Decompiler = # 1, icons.png @ 64, 0, 16, 16 +modules.SWFViewer = # 2, icons.png @ 32, 0, 16, 16 +modules.HideFile = # 3, icons.png @ 0, 0, 16, 16 +modules.langpack.StringUnpacker = # 0, icons.png @ 400, 0, 16, 16 +modules.langpack.StringPacker = # 1, icons.png @ 528, 0, 16, 16 + +;modules.DummyModule = Dummy module, icons.png @ 0, 0, 16, 16 + +[FileSource] + +modules.text.TextFileSource = # 235, icons.png @ 64, 0, 16, 16 +modules.NullFileSource = # 282, icons.png @ 0, 0, 16, 16 +modules.FileSplicer = # 0, icons.png @ 0, 0, 16, 16 +modules.playlist.M3UFileSource = # 204, icons.png @ 16, 0, 16, 16 +modules.color.ColorFileSource = # 152, icons.png @ 32, 0, 16, 16 + +[ContainerSource] + +modules.ZipFileSource = # 287, icons.png @ 80, 0, 16, 16 +modules.PPKFileSource = # 288, icons.png @ 80, 0, 16, 16 + +;[Operation] + +;test.TestModule = TestName, icons.png \ No newline at end of file diff --git a/res/config/options.ini b/res/config/options.ini new file mode 100644 index 0000000..0419ed4 --- /dev/null +++ b/res/config/options.ini @@ -0,0 +1,15 @@ +; This file contains a list of OptionStorages. +; OptionStorage is a special submodule responsible for management of it's main module settings. + +; Each record in this file has the following syntax: +; module.package.ModuleClass = + +; If you plan to obfuscate your module, don't forget to tell your obfuscator to adapt the contents of this file. +; For ProGuard it is done like that: -adaptresourcefilecontents config/* + +modules.ZipOptions = # 211 +modules.RarOptions = # 325 +modules.audio.AudioOptions = # 213 +modules.video.VideoOptions = # 215 +modules.image.ImageOptions = # 214 +modules.text.TextOptions = # 216 diff --git a/res/config/palette.ini b/res/config/palette.ini new file mode 100644 index 0000000..fe0c38b --- /dev/null +++ b/res/config/palette.ini @@ -0,0 +1,58 @@ +COLS = 8 +ROWS = 6 + +0 = FFFF8080 +1 = FFFF0000 +2 = FF804040 +3 = FF800000 +4 = FF400000 +5 = FF000000 + +6 = FFFFFF80 +7 = FFFFFF00 +8 = FFFF8040 +9 = FFFF8000 +10 = FF804000 +11 = FF808000 + +12 = FF80FF80 +13 = FF80FF00 +14 = FF00FF00 +15 = FF008000 +16 = FF004000 +17 = FF808040 + +18 = FF00FF80 +19 = FF00FF40 +20 = FF008080 +21 = FF008040 +22 = FF004040 +23 = FF808080 + +24 = FF80FFFF +25 = FF00FFFF +26 = FF004080 +27 = FF0000FF +28 = FF000080 +29 = FF408080 + +30 = FF0080FF +31 = FF0080C0 +32 = FF8080FF +33 = FF0000A0 +34 = FF000040 +35 = FFC0C0C0 + +36 = FFFF80C0 +37 = FF8080C0 +38 = FF800040 +39 = FF800080 +40 = FF400040 +41 = FF400040 + +42 = FFFF80FF +43 = FFFF00FF +44 = FFFF0080 +45 = FF8000FF +46 = FF400080 +47 = FFFFFFFF \ No newline at end of file diff --git a/res/config/types.ini b/res/config/types.ini new file mode 100644 index 0000000..1474d17 --- /dev/null +++ b/res/config/types.ini @@ -0,0 +1,52 @@ +; Here we map file extensions with modules used to open files with such extensions. +; Module names are the same as in modules.ini + +; Each record has the following syntax: +; ext1 [ext2 [ext3 ...]] = module.package.ModuleClass + +[Open] + +zip jar sdt scs nth = com.classpath.zip.ZipFile +rar = com.innosystec.unrar.Archive +ppk = com.one.PlainPackage + +mid amr wav aac mp3 imy m4a xmf awb midi wma ra = modules.audio.AudioModule +jpg jpe gif png bmx jpeg wbmp ico = modules.image.ImageModule +3gp mp4 m4v wmv rm = modules.video.VideoModule +txt jad log ini inf cdf xml col j java jcc mf = modules.text.TextModule +tmo vcs vnt = modules.TMOModule +mod xm s3m = modules.audio.TrackerModule +ncs mcs ths = modules.color.ColorModule +mvi = modules.image.VectorModule +mbac = modules.mascot.MascotViewer +mtra = modules.mascot.AnimationViewer +bmp = modules.mascot.TextureLoader +m3u = modules.playlist.M3UModule +class = modules.mocha.Decompiler +swf = modules.SWFViewer +;htm html mht mhtml wml = modules.PlatformRequestModule + +; Next, we need to map extensions to file creation modules. The syntax is expectingly reversed, +; but note that there must be only one extension for each module: +; module.package.ModuleClass = ext + +; All extensions assigned here are just the default ones, user will be able to edit them when creating file. +; If some module is not mentioned down there, then no default file extension will be assigned to it. + +[Create] + +modules.ZipFileSource = zip +modules.PPKFileSource = ppk + +modules.text.TextFileSource = txt +modules.playlist.M3UFileSource = m3u +modules.color.ColorFileSource = ncs +modules.NullFileSource = stub +modules.FileSplicer = splice + +; The same as previous section, except that these modules don't create anything, +; but some other modules need to know, which files are opened with them. + +[Special] + +modules.mascot.MascotViewer = mbac \ No newline at end of file diff --git a/res/config/unipalette.ini b/res/config/unipalette.ini new file mode 100644 index 0000000..498269b --- /dev/null +++ b/res/config/unipalette.ini @@ -0,0 +1,256 @@ +0 = FF000000 +1 = FF800000 +2 = FF008000 +3 = FF808000 +4 = FF000080 +5 = FF800080 +6 = FF008080 +7 = FF808080 +8 = FFC0C0C0 +9 = FFFF0000 +10 = FF00FF00 +11 = FFFFFF00 +12 = FF0000FF +13 = FFFF00FF +14 = FF00FFFF +15 = FFFFFFFF +16 = FF000000 +17 = FF000000 +18 = FF000000 +19 = FF000000 +20 = FF000000 +21 = FF000000 +22 = FF000000 +23 = FF000000 +24 = FF000000 +25 = FF000000 +26 = FF000000 +27 = FF000000 +28 = FF000000 +29 = FF000000 +30 = FF000000 +31 = FF000000 +32 = FF000000 +33 = FF000000 +34 = FF000000 +35 = FF000000 +36 = FF000000 +37 = FF000000 +38 = FF000000 +39 = FF000000 +40 = FF000000 +41 = FF000033 +42 = FF000066 +43 = FF000099 +44 = FF0000CC +45 = FF0000FF +46 = FF003300 +47 = FF003333 +48 = FF003366 +49 = FF003399 +50 = FF0033CC +51 = FF0033FF +52 = FF006600 +53 = FF006633 +54 = FF006666 +55 = FF006699 +56 = FF0066CC +57 = FF0066FF +58 = FF009900 +59 = FF009933 +60 = FF009966 +61 = FF009999 +62 = FF0099CC +63 = FF0099FF +64 = FF00CC00 +65 = FF00CC33 +66 = FF00CC66 +67 = FF00CC99 +68 = FF00CCCC +69 = FF00CCFF +70 = FF00FF00 +71 = FF00FF33 +72 = FF00FF66 +73 = FF00FF99 +74 = FF00FFCC +75 = FF00FFFF +76 = FF330000 +77 = FF330033 +78 = FF330066 +79 = FF330099 +80 = FF3300CC +81 = FF3300FF +82 = FF333300 +83 = FF333333 +84 = FF333366 +85 = FF333399 +86 = FF3333CC +87 = FF3333FF +88 = FF336600 +89 = FF336633 +90 = FF336666 +91 = FF336699 +92 = FF3366CC +93 = FF3366FF +94 = FF339900 +95 = FF339933 +96 = FF339966 +97 = FF339999 +98 = FF3399CC +99 = FF3399FF +100 = FF33CC00 +101 = FF33CC33 +102 = FF33CC66 +103 = FF33CC99 +104 = FF33CCCC +105 = FF33CCFF +106 = FF33FF00 +107 = FF33FF33 +108 = FF33FF66 +109 = FF33FF99 +110 = FF33FFCC +111 = FF33FFFF +112 = FF660000 +113 = FF660033 +114 = FF660066 +115 = FF660099 +116 = FF6600CC +117 = FF6600FF +118 = FF663300 +119 = FF663333 +120 = FF663366 +121 = FF663399 +122 = FF6633CC +123 = FF6633FF +124 = FF666600 +125 = FF666633 +126 = FF666666 +127 = FF666699 +128 = FF6666CC +129 = FF6666FF +130 = FF669900 +131 = FF669933 +132 = FF669966 +133 = FF669999 +134 = FF6699CC +135 = FF6699FF +136 = FF66CC00 +137 = FF66CC33 +138 = FF66CC66 +139 = FF66CC99 +140 = FF66CCCC +141 = FF66CCFF +142 = FF66FF00 +143 = FF66FF33 +144 = FF66FF66 +145 = FF66FF99 +146 = FF66FFCC +147 = FF66FFFF +148 = FF990000 +149 = FF990033 +150 = FF990066 +151 = FF990099 +152 = FF9900CC +153 = FF9900FF +154 = FF993300 +155 = FF993333 +156 = FF993366 +157 = FF993399 +158 = FF9933CC +159 = FF9933FF +160 = FF996600 +161 = FF996633 +162 = FF996666 +163 = FF996699 +164 = FF9966CC +165 = FF9966FF +166 = FF999900 +167 = FF999933 +168 = FF999966 +169 = FF999999 +170 = FF9999CC +171 = FF9999FF +172 = FF99CC00 +173 = FF99CC33 +174 = FF99CC66 +175 = FF99CC99 +176 = FF99CCCC +177 = FF99CCFF +178 = FF99FF00 +179 = FF99FF33 +180 = FF99FF66 +181 = FF99FF99 +182 = FF99FFCC +183 = FF99FFFF +184 = FFCC0000 +185 = FFCC0033 +186 = FFCC0066 +187 = FFCC0099 +188 = FFCC00CC +189 = FFCC00FF +190 = FFCC3300 +191 = FFCC3333 +192 = FFCC3366 +193 = FFCC3399 +194 = FFCC33CC +195 = FFCC33FF +196 = FFCC6600 +197 = FFCC6633 +198 = FFCC6666 +199 = FFCC6699 +200 = FFCC66CC +201 = FFCC66FF +202 = FFCC9900 +203 = FFCC9933 +204 = FFCC9966 +205 = FFCC9999 +206 = FFCC99CC +207 = FFCC99FF +208 = FFCCCC00 +209 = FFCCCC33 +210 = FFCCCC66 +211 = FFCCCC99 +212 = FFCCCCCC +213 = FFCCCCFF +214 = FFCCFF00 +215 = FFCCFF33 +216 = FFCCFF66 +217 = FFCCFF99 +218 = FFCCFFCC +219 = FFCCFFFF +220 = FFFF0000 +221 = FFFF0033 +222 = FFFF0066 +223 = FFFF0099 +224 = FFFF00CC +225 = FFFF00FF +226 = FFFF3300 +227 = FFFF3333 +228 = FFFF3366 +229 = FFFF3399 +230 = FFFF33CC +231 = FFFF33FF +232 = FFFF6600 +233 = FFFF6633 +234 = FFFF6666 +235 = FFFF6699 +236 = FFFF66CC +237 = FFFF66FF +238 = FFFF9900 +239 = FFFF9933 +240 = FFFF9966 +241 = FFFF9999 +242 = FFFF99CC +243 = FFFF99FF +244 = FFFFCC00 +245 = FFFFCC33 +246 = FFFFCC66 +247 = FFFFCC99 +248 = FFFFCCCC +249 = FFFFCCFF +250 = FFFFFF00 +251 = FFFFFF33 +252 = FFFFFF66 +253 = FFFFFF99 +254 = FFFFFFCC +255 = FFFFFFFF diff --git a/res/enc/ReadMe.txt b/res/enc/ReadMe.txt new file mode 100644 index 0000000..17b0c77 --- /dev/null +++ b/res/enc/ReadMe.txt @@ -0,0 +1,10 @@ +Encodings, or code pages (CP), are now supported as text files along with binary files. Here only text variation is described, binaries are considered as obsolete. + +A typical code page would consist of 128 lines - for 128 bytes from 0x80 to 0xFF. It's those bytes the meaning of which varies from CP to CP, the meaning of the upper half of the code page (bytes 0x0 to 0x7F) is constant. +Each line maps byte value to Unicode character value, like that: + +80 = 20AC ; ˆ + +Here 80 is a byte value, 20AC is a character value, and the rest - semicolon and actual symbol - is an optional comment, placed here just to make code page easier for human reading. All numbers are hexadecimal. + +All code pages must be either in Unicode with BOM, or in a one-byte encoding denoted in enc.ini (see) as DEFAULT. \ No newline at end of file diff --git a/res/enc/cp1251.ini b/res/enc/cp1251.ini new file mode 100644 index 0000000..55a6c84 --- /dev/null +++ b/res/enc/cp1251.ini @@ -0,0 +1,128 @@ +80 = 402 ; Ђ +81 = 403 ; Ѓ +82 = 201A ; ‚ +83 = 453 ; Ñ“ +84 = 201E ; „ +85 = 2026 ; … +86 = 2020 ; † +87 = 2021 ; ‡ +88 = 20AC ; € +89 = 2030 ; ‰ +8A = 409 ; Љ +8B = 2039 ; ‹ +8C = 40A ; Њ +8D = 40C ; ÐŒ +8E = 40B ; Ћ +8F = 40F ; Ð +90 = 452 ; Ñ’ +91 = 2018 ; ‘ +92 = 2019 ; ’ +93 = 201C ; “ +94 = 201D ; †+95 = 2022 ; • +96 = 2013 ; – +97 = 2014 ; — +98 = 20 ; +99 = 2122 ; â„¢ +9A = 459 ; Ñ™ +9B = 203A ; › +9C = 45A ; Ñš +9D = 45C ; Ñœ +9E = 45B ; Ñ› +9F = 45F ; ÑŸ +A0 = A0 ;   +A1 = 40E ; ÐŽ +A2 = 45E ; Ñž +A3 = 408 ; Ј +A4 = A4 ; ¤ +A5 = 490 ; Ò +A6 = A6 ; ¦ +A7 = A7 ; § +A8 = 401 ; Ð +A9 = A9 ; © +AA = 404 ; Є +AB = AB ; « +AC = AC ; ¬ +AD = AD ; ­ +AE = AE ; ® +AF = 407 ; Ї +B0 = B0 ; ° +B1 = B1 ; ± +B2 = 406 ; І +B3 = 456 ; Ñ– +B4 = 491 ; Ò‘ +B5 = B5 ; µ +B6 = B6 ; ¶ +B7 = B7 ; · +B8 = 451 ; Ñ‘ +B9 = 2116 ; â„– +BA = 454 ; Ñ” +BB = BB ; » +BC = 458 ; ј +BD = 405 ; Ð… +BE = 455 ; Ñ• +BF = 457 ; Ñ— +C0 = 410 ; Ð +C1 = 411 ; Б +C2 = 412 ; Ð’ +C3 = 413 ; Г +C4 = 414 ; Д +C5 = 415 ; Е +C6 = 416 ; Ж +C7 = 417 ; З +C8 = 418 ; И +C9 = 419 ; Й +CA = 41A ; К +CB = 41B ; Л +CC = 41C ; Ðœ +CD = 41D ; Ð +CE = 41E ; О +CF = 41F ; П +D0 = 420 ; Р +D1 = 421 ; С +D2 = 422 ; Т +D3 = 423 ; У +D4 = 424 ; Ф +D5 = 425 ; Ð¥ +D6 = 426 ; Ц +D7 = 427 ; Ч +D8 = 428 ; Ш +D9 = 429 ; Щ +DA = 42A ; Ъ +DB = 42B ; Ы +DC = 42C ; Ь +DD = 42D ; Э +DE = 42E ; Ю +DF = 42F ; Я +E0 = 430 ; а +E1 = 431 ; б +E2 = 432 ; в +E3 = 433 ; г +E4 = 434 ; д +E5 = 435 ; е +E6 = 436 ; ж +E7 = 437 ; з +E8 = 438 ; и +E9 = 439 ; й +EA = 43A ; к +EB = 43B ; л +EC = 43C ; м +ED = 43D ; н +EE = 43E ; о +EF = 43F ; п +F0 = 440 ; Ñ€ +F1 = 441 ; Ñ +F2 = 442 ; Ñ‚ +F3 = 443 ; у +F4 = 444 ; Ñ„ +F5 = 445 ; Ñ… +F6 = 446 ; ц +F7 = 447 ; ч +F8 = 448 ; ш +F9 = 449 ; щ +FA = 44A ; ÑŠ +FB = 44B ; Ñ‹ +FC = 44C ; ÑŒ +FD = 44D ; Ñ +FE = 44E ; ÑŽ +FF = 44F ; Ñ diff --git a/res/enc/cp1252.ini b/res/enc/cp1252.ini new file mode 100644 index 0000000..fbd161a --- /dev/null +++ b/res/enc/cp1252.ini @@ -0,0 +1,128 @@ +80 = 20AC ; € +81 = 20 ; +82 = 201A ; ‚ +83 = 192 ; Æ’ +84 = 201E ; „ +85 = 2026 ; … +86 = 2020 ; † +87 = 2021 ; ‡ +88 = 2C6 ; ˆ +89 = 2030 ; ‰ +8A = 160 ; Å  +8B = 2039 ; ‹ +8C = 152 ; Å’ +8D = 20 ; +8E = 17D ; Ž +8F = 20 ; +90 = 20 ; +91 = 2018 ; ‘ +92 = 2019 ; ’ +93 = 201C ; “ +94 = 201D ; †+95 = 2022 ; • +96 = 2013 ; – +97 = 2014 ; — +98 = 2DC ; Ëœ +99 = 2122 ; â„¢ +9A = 161 ; Å¡ +9B = 203A ; › +9C = 153 ; Å“ +9D = 20 ; +9E = 17E ; ž +9F = 178 ; Ÿ +A0 = A0 ;   +A1 = A1 ; ¡ +A2 = A2 ; ¢ +A3 = A3 ; £ +A4 = A4 ; ¤ +A5 = A5 ; Â¥ +A6 = A6 ; ¦ +A7 = A7 ; § +A8 = A8 ; ¨ +A9 = A9 ; © +AA = AA ; ª +AB = AB ; « +AC = AC ; ¬ +AD = AD ; ­ +AE = AE ; ® +AF = AF ; ¯ +B0 = B0 ; ° +B1 = B1 ; ± +B2 = B2 ; ² +B3 = B3 ; ³ +B4 = B4 ; ´ +B5 = B5 ; µ +B6 = B6 ; ¶ +B7 = B7 ; · +B8 = B8 ; ¸ +B9 = B9 ; ¹ +BA = BA ; º +BB = BB ; » +BC = BC ; ¼ +BD = BD ; ½ +BE = BE ; ¾ +BF = BF ; ¿ +C0 = C0 ; À +C1 = C1 ; à +C2 = C2 ;  +C3 = C3 ; à +C4 = C4 ; Ä +C5 = C5 ; Ã… +C6 = C6 ; Æ +C7 = C7 ; Ç +C8 = C8 ; È +C9 = C9 ; É +CA = CA ; Ê +CB = CB ; Ë +CC = CC ; ÃŒ +CD = CD ; à +CE = CE ; ÃŽ +CF = CF ; à +D0 = D0 ; à +D1 = D1 ; Ñ +D2 = D2 ; Ã’ +D3 = D3 ; Ó +D4 = D4 ; Ô +D5 = D5 ; Õ +D6 = D6 ; Ö +D7 = D7 ; × +D8 = D8 ; Ø +D9 = D9 ; Ù +DA = DA ; Ú +DB = DB ; Û +DC = DC ; Ãœ +DD = DD ; à +DE = DE ; Þ +DF = DF ; ß +E0 = E0 ; à +E1 = E1 ; á +E2 = E2 ; â +E3 = E3 ; ã +E4 = E4 ; ä +E5 = E5 ; Ã¥ +E6 = E6 ; æ +E7 = E7 ; ç +E8 = E8 ; è +E9 = E9 ; é +EA = EA ; ê +EB = EB ; ë +EC = EC ; ì +ED = ED ; í +EE = EE ; î +EF = EF ; ï +F0 = F0 ; ð +F1 = F1 ; ñ +F2 = F2 ; ò +F3 = F3 ; ó +F4 = F4 ; ô +F5 = F5 ; õ +F6 = F6 ; ö +F7 = F7 ; ÷ +F8 = F8 ; ø +F9 = F9 ; ù +FA = FA ; ú +FB = FB ; û +FC = FC ; ü +FD = FD ; ý +FE = FE ; þ +FF = FF ; ÿ diff --git a/res/enc/cp437.ini b/res/enc/cp437.ini new file mode 100644 index 0000000..b94beca --- /dev/null +++ b/res/enc/cp437.ini @@ -0,0 +1,128 @@ +80 = C7 ; Ç +81 = FC ; ü +82 = E9 ; é +83 = E2 ; â +84 = E4 ; ä +85 = E0 ; à +86 = E5 ; Ã¥ +87 = E7 ; ç +88 = EA ; ê +89 = EB ; ë +8A = E8 ; è +8B = EF ; ï +8C = EE ; î +8D = EC ; ì +8E = C4 ; Ä +8F = C5 ; Ã… +90 = C9 ; É +91 = E6 ; æ +92 = C6 ; Æ +93 = F4 ; ô +94 = F6 ; ö +95 = F2 ; ò +96 = FB ; û +97 = F9 ; ù +98 = FF ; ÿ +99 = D6 ; Ö +9A = DC ; Ãœ +9B = A2 ; ¢ +9C = A3 ; £ +9D = A5 ; Â¥ +9E = 20A7 ; ₧ +9F = 192 ; Æ’ +A0 = E1 ; á +A1 = ED ; í +A2 = F3 ; ó +A3 = FA ; ú +A4 = F1 ; ñ +A5 = D1 ; Ñ +A6 = AA ; ª +A7 = BA ; º +A8 = BF ; ¿ +A9 = 2310 ; ⌠+AA = AC ; ¬ +AB = BD ; ½ +AC = BC ; ¼ +AD = A1 ; ¡ +AE = AB ; « +AF = BB ; » +B0 = 2591 ; â–‘ +B1 = 2592 ; â–’ +B2 = 2593 ; â–“ +B3 = 2502 ; │ +B4 = 2524 ; ┤ +B5 = 2561 ; â•¡ +B6 = 2562 ; â•¢ +B7 = 2556 ; â•– +B8 = 2555 ; â•• +B9 = 2563 ; â•£ +BA = 2551 ; â•‘ +BB = 2557 ; â•— +BC = 255D ; â• +BD = 255C ; â•œ +BE = 255B ; â•› +BF = 2510 ; â” +C0 = 2514 ; â”” +C1 = 2534 ; â”´ +C2 = 252C ; ┬ +C3 = 251C ; ├ +C4 = 2500 ; ─ +C5 = 253C ; ┼ +C6 = 255E ; â•ž +C7 = 255F ; â•Ÿ +C8 = 255A ; â•š +C9 = 2554 ; â•” +CA = 2569 ; â•© +CB = 2566 ; ╦ +CC = 2560 ; â•  +CD = 2550 ; â• +CE = 256C ; ╬ +CF = 2567 ; ╧ +D0 = 2568 ; ╨ +D1 = 2564 ; ╤ +D2 = 2565 ; â•¥ +D3 = 2559 ; â•™ +D4 = 2558 ; ╘ +D5 = 2552 ; â•’ +D6 = 2553 ; â•“ +D7 = 256B ; â•« +D8 = 256A ; ╪ +D9 = 2518 ; ┘ +DA = 250C ; ┌ +DB = 2588 ; â–ˆ +DC = 2584 ; â–„ +DD = 258C ; â–Œ +DE = 2590 ; â– +DF = 2580 ; â–€ +E0 = 3B1 ; α +E1 = DF ; ß +E2 = 393 ; Γ +E3 = 3C0 ; Ï€ +E4 = 3A3 ; Σ +E5 = 3C3 ; σ +E6 = B5 ; µ +E7 = 3C4 ; Ï„ +E8 = 3A6 ; Φ +E9 = 398 ; Θ +EA = 3A9 ; Ω +EB = 3B4 ; δ +EC = 221E ; ∞ +ED = 3C6 ; φ +EE = 3B5 ; ε +EF = 2229 ; ∩ +F0 = 2261 ; ≡ +F1 = B1 ; ± +F2 = 2265 ; ≥ +F3 = 2264 ; ≤ +F4 = 2320 ; ⌠ +F5 = 2321 ; ⌡ +F6 = F7 ; ÷ +F7 = 2248 ; ≈ +F8 = B0 ; ° +F9 = 2219 ; ∙ +FA = B7 ; · +FB = 221A ; √ +FC = 207F ; â¿ +FD = B2 ; ² +FE = 25A0 ; â–  +FF = A0 ;   diff --git a/res/enc/cp866.ini b/res/enc/cp866.ini new file mode 100644 index 0000000..d87f74e --- /dev/null +++ b/res/enc/cp866.ini @@ -0,0 +1,128 @@ +80 = 410 ; Ð +81 = 411 ; Б +82 = 412 ; Ð’ +83 = 413 ; Г +84 = 414 ; Д +85 = 415 ; Е +86 = 416 ; Ж +87 = 417 ; З +88 = 418 ; И +89 = 419 ; Й +8A = 41A ; К +8B = 41B ; Л +8C = 41C ; Ðœ +8D = 41D ; Ð +8E = 41E ; О +8F = 41F ; П +90 = 420 ; Р +91 = 421 ; С +92 = 422 ; Т +93 = 423 ; У +94 = 424 ; Ф +95 = 425 ; Ð¥ +96 = 426 ; Ц +97 = 427 ; Ч +98 = 428 ; Ш +99 = 429 ; Щ +9A = 42A ; Ъ +9B = 42B ; Ы +9C = 42C ; Ь +9D = 42D ; Э +9E = 42E ; Ю +9F = 42F ; Я +A0 = 430 ; а +A1 = 431 ; б +A2 = 432 ; в +A3 = 433 ; г +A4 = 434 ; д +A5 = 435 ; е +A6 = 436 ; ж +A7 = 437 ; з +A8 = 438 ; и +A9 = 439 ; й +AA = 43A ; к +AB = 43B ; л +AC = 43C ; м +AD = 43D ; н +AE = 43E ; о +AF = 43F ; п +B0 = 2591 ; â–‘ +B1 = 2592 ; â–’ +B2 = 2593 ; â–“ +B3 = 2502 ; │ +B4 = 2524 ; ┤ +B5 = 2561 ; â•¡ +B6 = 2562 ; â•¢ +B7 = 2556 ; â•– +B8 = 2555 ; â•• +B9 = 2563 ; â•£ +BA = 2551 ; â•‘ +BB = 2557 ; â•— +BC = 255D ; â• +BD = 255C ; â•œ +BE = 255B ; â•› +BF = 2510 ; â” +C0 = 2514 ; â”” +C1 = 2534 ; â”´ +C2 = 252C ; ┬ +C3 = 251C ; ├ +C4 = 2500 ; ─ +C5 = 253C ; ┼ +C6 = 255E ; â•ž +C7 = 255F ; â•Ÿ +C8 = 255A ; â•š +C9 = 2554 ; â•” +CA = 2569 ; â•© +CB = 2566 ; ╦ +CC = 2560 ; â•  +CD = 2550 ; â• +CE = 256C ; ╬ +CF = 2567 ; ╧ +D0 = 2568 ; ╨ +D1 = 2564 ; ╤ +D2 = 2565 ; â•¥ +D3 = 2559 ; â•™ +D4 = 2558 ; ╘ +D5 = 2552 ; â•’ +D6 = 2553 ; â•“ +D7 = 256B ; â•« +D8 = 256A ; ╪ +D9 = 2518 ; ┘ +DA = 250C ; ┌ +DB = 2588 ; â–ˆ +DC = 2584 ; â–„ +DD = 258C ; â–Œ +DE = 2590 ; â– +DF = 2580 ; â–€ +E0 = 440 ; Ñ€ +E1 = 441 ; Ñ +E2 = 442 ; Ñ‚ +E3 = 443 ; у +E4 = 444 ; Ñ„ +E5 = 445 ; Ñ… +E6 = 446 ; ц +E7 = 447 ; ч +E8 = 448 ; ш +E9 = 449 ; щ +EA = 44A ; ÑŠ +EB = 44B ; Ñ‹ +EC = 44C ; ÑŒ +ED = 44D ; Ñ +EE = 44E ; ÑŽ +EF = 44F ; Ñ +F0 = 401 ; Ð +F1 = 451 ; Ñ‘ +F2 = 404 ; Є +F3 = 454 ; Ñ” +F4 = 407 ; Ї +F5 = 457 ; Ñ— +F6 = 40E ; ÐŽ +F7 = 45E ; Ñž +F8 = B0 ; ° +F9 = 2219 ; ∙ +FA = B7 ; · +FB = 221A ; √ +FC = 2216 ; ∖ +FD = A4 ; ¤ +FE = 25A0 ; â–  +FF = A0 ;   diff --git a/res/enc/enc.ini b/res/enc/enc.ini new file mode 100644 index 0000000..41ee603 --- /dev/null +++ b/res/enc/enc.ini @@ -0,0 +1,20 @@ +; Unicode encodings are hard-coded, +; they are assigned with following indices: + +; Unicode UTF-8 -1 +; Unicode UTF-16 (Network Order) -2 +; Unicode UTF-16 (Little Endian) -3 + +; One-byte encodings are listed below: + +Windows Latin = cp1252 ; 0 +Windows Cyrillic = cp1251 ; 1 +DOS Latin = cp437 ; 2 +DOS Cyrillic = cp866 ; 3 +KOI-8 Russian = koi8r ; 4 + +; Internal resource encoding, +; encoding of files' names inside archives + +DEFAULT = 1 +ARCHIVE = 3 ; -1? diff --git a/res/enc/koi8r.ini b/res/enc/koi8r.ini new file mode 100644 index 0000000..94ceb2d --- /dev/null +++ b/res/enc/koi8r.ini @@ -0,0 +1,128 @@ +80 = 2500 ; ─ +81 = 2502 ; │ +82 = 250C ; ┌ +83 = 2510 ; â” +84 = 2514 ; â”” +85 = 2518 ; ┘ +86 = 251C ; ├ +87 = 2524 ; ┤ +88 = 252C ; ┬ +89 = 2534 ; â”´ +8A = 253C ; ┼ +8B = 2580 ; â–€ +8C = 2584 ; â–„ +8D = 2588 ; â–ˆ +8E = 258C ; â–Œ +8F = 2590 ; â– +90 = 2591 ; â–‘ +91 = 2592 ; â–’ +92 = 2593 ; â–“ +93 = 2320 ; ⌠ +94 = 25A0 ; â–  +95 = 2219 ; ∙ +96 = 221A ; √ +97 = 2248 ; ≈ +98 = 2264 ; ≤ +99 = 2265 ; ≥ +9A = A0 ;   +9B = 2321 ; ⌡ +9C = B0 ; ° +9D = B2 ; ² +9E = B7 ; · +9F = F7 ; ÷ +A0 = 2550 ; â• +A1 = 2551 ; â•‘ +A2 = 2552 ; â•’ +A3 = 451 ; Ñ‘ +A4 = 2553 ; â•“ +A5 = 2554 ; â•” +A6 = 2555 ; â•• +A7 = 2556 ; â•– +A8 = 2557 ; â•— +A9 = 2558 ; ╘ +AA = 2559 ; â•™ +AB = 255A ; â•š +AC = 255B ; â•› +AD = 255C ; â•œ +AE = 255D ; â• +AF = 255E ; â•ž +B0 = 255F ; â•Ÿ +B1 = 2560 ; â•  +B2 = 2561 ; â•¡ +B3 = 401 ; Ð +B4 = 2562 ; â•¢ +B5 = 2563 ; â•£ +B6 = 2564 ; ╤ +B7 = 2565 ; â•¥ +B8 = 2566 ; ╦ +B9 = 2567 ; ╧ +BA = 2568 ; ╨ +BB = 2569 ; â•© +BC = 256A ; ╪ +BD = 256B ; â•« +BE = 256C ; ╬ +BF = A9 ; © +C0 = 44E ; ÑŽ +C1 = 430 ; а +C2 = 431 ; б +C3 = 446 ; ц +C4 = 434 ; д +C5 = 435 ; е +C6 = 444 ; Ñ„ +C7 = 433 ; г +C8 = 445 ; Ñ… +C9 = 438 ; и +CA = 439 ; й +CB = 43A ; к +CC = 43B ; л +CD = 43C ; м +CE = 43D ; н +CF = 43E ; о +D0 = 43F ; п +D1 = 44F ; Ñ +D2 = 440 ; Ñ€ +D3 = 441 ; Ñ +D4 = 442 ; Ñ‚ +D5 = 443 ; у +D6 = 436 ; ж +D7 = 432 ; в +D8 = 44C ; ÑŒ +D9 = 44B ; Ñ‹ +DA = 437 ; з +DB = 448 ; ш +DC = 44D ; Ñ +DD = 449 ; щ +DE = 447 ; ч +DF = 44A ; ÑŠ +E0 = 42E ; Ю +E1 = 410 ; Ð +E2 = 411 ; Б +E3 = 426 ; Ц +E4 = 414 ; Д +E5 = 415 ; Е +E6 = 424 ; Ф +E7 = 413 ; Г +E8 = 425 ; Ð¥ +E9 = 418 ; И +EA = 419 ; Й +EB = 41A ; К +EC = 41B ; Л +ED = 41C ; Ðœ +EE = 41D ; Ð +EF = 41E ; О +F0 = 41F ; П +F1 = 42F ; Я +F2 = 420 ; Р +F3 = 421 ; С +F4 = 422 ; Т +F5 = 423 ; У +F6 = 416 ; Ж +F7 = 412 ; Ð’ +F8 = 42C ; Ь +F9 = 42B ; Ы +FA = 417 ; З +FB = 428 ; Ш +FC = 42D ; Э +FD = 429 ; Щ +FE = 427 ; Ч +FF = 42A ; Ъ diff --git a/res/img/Thumbs.db b/res/img/Thumbs.db new file mode 100644 index 0000000..ffb7821 Binary files /dev/null and b/res/img/Thumbs.db differ diff --git a/res/img/about.png b/res/img/about.png new file mode 100644 index 0000000..cabebf9 Binary files /dev/null and b/res/img/about.png differ diff --git a/res/img/icon.png b/res/img/icon.png new file mode 100644 index 0000000..cb30f53 Binary files /dev/null and b/res/img/icon.png differ diff --git a/res/img/icons.ini b/res/img/icons.ini new file mode 100644 index 0000000..9f09c5f --- /dev/null +++ b/res/img/icons.ini @@ -0,0 +1,38 @@ +; The syntax is the same as in modules.ini: +; icon_file.ext [@ x, y, width, height]] + +; Comments like iFile or iCrypt are optional and placed here just to make this file easier for human reading and editing. + +0 = icons.png @ 0, 0, 16, 16 ; iFile +1 = icons.png @ 112, 0, 16, 16 ; iFolder +2 = icons.png @ 128, 0, 16, 16 ; iHiddenFolder +3 = icons.png @ 144, 0, 16, 16 ; iDisk +4 = icons.png @ 176, 0, 16, 16 ; iFavorites +5 = icons.png @ 192, 0, 16, 16 ; iUp +6 = icons.png @ 208, 0, 16, 16 ; iClipboard +7 = icons.png @ 224, 0, 16, 16 ; iSieFM +8 = icons.png @ 240, 0, 16, 16 ; iCopy +9 = icons.png @ 256, 0, 16, 16 ; iMove +10 = icons.png @ 272, 0, 16, 16 ; iPaste +11 = icons.png @ 288, 0, 16, 16 ; iProperties +12 = icons.png @ 304, 0, 16, 16 ; iOptions +13 = icons.png @ 320, 0, 16, 16 ; iRename +14 = icons.png @ 336, 0, 16, 16 ; iHelp +15 = icons.png @ 352, 0, 16, 16 ; iDelete +17 = icons.png @ 384, 0, 16, 16 ; iNext +18 = icons.png @ 400, 0, 16, 16 ; iUnpack +19 = icons.png @ 416, 0, 16, 16 ; iMark +20 = icons.png @ 432, 0, 16, 16 ; iMarkAll +21 = icons.png @ 448, 0, 16, 16 ; iDemarkAll +22 = icons.png @ 464, 0, 16, 16 ; iNoMute +23 = icons.png @ 480, 0, 16, 16 ; iMute +24 = icons.png @ 496, 0, 16, 16 ; iSelect +25 = icons.png @ 512, 0, 16, 16 ; iMoveIt +26 = icons.png @ 528, 0, 16, 16 ; iPack +27 = icons.png @ 544, 0, 16, 16 ; iKey +28 = icons.png @ 560, 0, 16, 16 ; iMenu + +31 = icons_new.png @ 0, 0, 16, 16 ; iCrypt +16 = icons_new.png @ 16, 0, 16, 16 ; iExit +30 = icons_new.png @ 32, 0, 16, 16 ; iMinimize +29 = icons_new.png @ 48, 0, 16, 16 ; iSearch \ No newline at end of file diff --git a/res/img/icons.png b/res/img/icons.png new file mode 100644 index 0000000..0e4cd7e Binary files /dev/null and b/res/img/icons.png differ diff --git a/res/img/icons_new.png b/res/img/icons_new.png new file mode 100644 index 0000000..e55adc0 Binary files /dev/null and b/res/img/icons_new.png differ diff --git a/res/img/layout.ini b/res/img/layout.ini new file mode 100644 index 0000000..be4c65a --- /dev/null +++ b/res/img/layout.ini @@ -0,0 +1,34 @@ +; This file is a replacement for obsolete layout.dat + +[Colors] + +cPlayTitle = FFFFFFFF +cPlayFore1 = FF800000 +cPlayFore2 = FF000080 +cImgBack = FF000000 +cVisArrowCap = FF000080 +cVisArrowLine = FFEFEFFF +cVisBack1 = FFD0D0E0 +cVisBack2 = FFB0B0C0 + +[Positions] + +iconWidth = 16 +iconHeight = 16 +uiTopHeight = 20 +uiBottomHeight = 28 +uiTopHSpace = 6 +uiTopVSpace = 0 +uiBottomHOffset = 7 +uiBottomVOffset = 2 +uiBottomVSpace = 0 +btnX = 28 +btnY = 22 +btnWidth = 23 +btnHeight = 23 +playAnimWidth = 101 +playAnimHeight = 36 +playAnimFrames = 4 +waitAnimWidth = 32 +waitAnimHeight = 32 +waitAnimFrames = 4 \ No newline at end of file diff --git a/res/img/mb_critical.png b/res/img/mb_critical.png new file mode 100644 index 0000000..1f7f412 Binary files /dev/null and b/res/img/mb_critical.png differ diff --git a/res/img/mb_exclamation.png b/res/img/mb_exclamation.png new file mode 100644 index 0000000..af81bc8 Binary files /dev/null and b/res/img/mb_exclamation.png differ diff --git a/res/img/mb_information.png b/res/img/mb_information.png new file mode 100644 index 0000000..e494753 Binary files /dev/null and b/res/img/mb_information.png differ diff --git a/res/img/mb_question.png b/res/img/mb_question.png new file mode 100644 index 0000000..c8023ac Binary files /dev/null and b/res/img/mb_question.png differ diff --git a/res/img/player_bg.png b/res/img/player_bg.png new file mode 100644 index 0000000..c5e8e91 Binary files /dev/null and b/res/img/player_bg.png differ diff --git a/res/img/player_ui.png b/res/img/player_ui.png new file mode 100644 index 0000000..a8f5e5d Binary files /dev/null and b/res/img/player_ui.png differ diff --git a/res/img/splash.txt b/res/img/splash.txt new file mode 100644 index 0000000..21209ba --- /dev/null +++ b/res/img/splash.txt @@ -0,0 +1 @@ +Somebody please create new splash.png image... \ No newline at end of file diff --git a/res/img/wait.png b/res/img/wait.png new file mode 100644 index 0000000..8b0cd15 Binary files /dev/null and b/res/img/wait.png differ diff --git a/res/lang/ReadMe.txt b/res/lang/ReadMe.txt new file mode 100644 index 0000000..8d0cc15 --- /dev/null +++ b/res/lang/ReadMe.txt @@ -0,0 +1,60 @@ +Here we store translated text and strings used in program. + +Each translation is stored in separate subfolder, which name should (yet doesn't have to) be a two-letter language code. Following this rule will enable that language to be auto-detected on first program run. + +Each language subfolder must contain following files: + +1. strings.ini - an ini-formatted file containing numeric string identifiers and strings assigned to them. +2. about.txt - some sort of description of the program, possibly containing some help info. +3. license.txt - no comments. + +Additionally there may be file named offsets.ini - an ini-formatted file containing class names and string table offset values assigned for those classes. + +Next, in order for the program to see those translations, there is a file lang.ini. It maps two-letter language codes with human-readable language names. + +All files listed above may be saved either in Unicode UTF-8 or UTF-16 (both big endian and little endian) text encodings with BOM signature, or in one-byte encoding for which there is a codepage and which is marked as default (see ReadMe.txt in enc folder). + +Files about.txt and license.txt are simple text files, just like this one, and require no special discussion. But the other two do. + +Here is the most complicated strings.ini file example possible: + +;-------------------------------------------------------------- + +[0] ; offset of zero - no offset for strings below + +0 = Zero string ; tabs are used +1 = First string ; spaces +2=Second string ; no spaces at all + +-1 = String one ; negative identifiers are allowed +-2 = String two + +100 = File %A in folder %B is %C, whih caused an error %D ; This string contains placeholders for runtime substitution. And some parts of this program expect some strings to contain such placeholders in order to display something really usefull, e.g. "File some_filename.txt is read-only!" instead of "File is read-only!". +101 = Operation %B failed: %A ; Another example of placeholders. As you can see, they do not have to follow in alphabetical order at all. More even, you can relatively painless omit some or even all. As the payback the program will become less informative. + +102 = This is \n multiline \n\n string, \t containing \t tabs, slashes \\, \\ and \\\\, octal symbols \007 \000 \015 \177, and unicode symbols \u263A \u263C \u00B0 ; This string contains escaped characters. When strings are loaded into runtime string table, they are unescaped, so it is possible to have multiline strings in string table and some specific characters in strings. Just don't forget to replace every \ with \\. + +; Those strings above will be stored in runtime string table with indices 0, 1 and 2, just as the are. +; But ones below will be stored with indices 1001, 1002, 1010, 1041. +; This offset stuff is introduced to enable convinient movement of string blocks along the table. Why wold someone bother to do so is discussed further in this document. + +[1000] ; offset of 1000 for strings below + +1 = Alpha +2 = Beta +10 = Gamma +41 = Delta + +;-------------------------------------------------------------- + +And the same for offsets.ini file: + +;-------------------------------------------------------------- + +filemanager.cvsFileSelect = 0 ; redundant thing, we could have just skipped this line with the same result +filemanager.cvsTextView = 1000 ; now if something in class cvsTextView asks the Locale class for string identified by number 15, it will return string identified by number 1015 +filemanager.cvsImageView = -1000 ; same here, except that instead of string #15 string #-985 will be returned. + +;-------------------------------------------------------------- + +Offsets are introduced to resolve string identifier conflicts. Imagine that someone developed a module and used string identifiers from 250 to 300, and another someone developed another module with string identifiers from 275 to 315. Obviously we can't put both string sets into one string table, because they overlap. So we assign an offset of, say, 1000 to all classes (if there are more than one) of one module in offsets.ini and place those strings in strings.ini under offset [1000]. Now, for example, first module is still using strings form 250 to 300, and second module is using strings from 1275 to 1315, without overlapping. \ No newline at end of file diff --git a/res/lang/en/about.txt b/res/lang/en/about.txt new file mode 100644 index 0000000..1f5718b --- /dev/null +++ b/res/lang/en/about.txt @@ -0,0 +1,44 @@ + UniFM stands for the "Unified File Manager" for mobile phones which support file system access from Java. It allows to view, copy, move and delete files and folders in your phone. + + The key feature of UniFM in comparison with other file managers is modular structure. That is, users can define what functionality do they need, and select components which will be included into the program according to their requirements. The minimum set - only the file kernel performing basic operations with files and folders. The maximum configuration is limited by nothing (only by phone resources, actually). For instance, this version includes a standard "gentleman's set" of modules for viewing pictures and videos, music playback and text editing. + + The unique system of interoperation with archives is implemented in UniFM, also on a modular basis. It means that theoretically support for any types of archives can be added into the program, and for users those will look the same way as ordinary folders in the file system do. In is possible to perform usual copyings, movings, renamings and removals of files within archives, viewing and editing of texts, music playback and etc. Besides, nested archives are supported. Possibilities, again, are limited only by phone resources. + + Technically UniFM is the further development of SieFM (Siemens File Manager) project and hence inherits many of its' features. The main functions of the program are listed below: + + There is a possibility of deleting read-only files, viewing of hidden folders, recursive removal of folders. The program has the multiwindow interface - up to 10 windows between which it is possible to switch. File viewers are launched in the same windows, so that it is possible to start a player in one window, switch to another and carry on. + + The image viewing module supports all graphics formats recognised by phone, and viewing of vector animations in MVI format (file format of program VIArt) is supported. Similarly, the audioplayer except playback of the files which are played back by certain phone, supports playback of music in tracker formats MOD (ProTracker), XM (FastTracker 2) and S3M (ScreamTracker). + + Text viewing and editing is possible in Unicode encoding in formats UTF-8 and UTF-16, and also in all most often used one-byte encodings (CP1251, CP866, KOI-8). Text is shown from the position on which it was quitted last time, quick transition to any position and resizing of font are possible. The text editor supports undoing of changes brought in the text, search and replacement of fragments of the text, conversion of texts from one encoding in another. + + Types of files supported by this version: +Images: .jpg .jpe .gif .png .bmx .jpeg .wbmp .ico .bmp +Audio: .mid .amr .wav .aac .mp3 .imy .m4a .xmf .awb .midi .wma + .xm .mod .s3m +Video: .3gp .mp4 .m4v .wmv .rm +Text: .j .txt .jad .log .ini .inf .cdf .xml .col .java .jcc + .tmo .vcs .vnt +Archives: .zip .jar .sdt .scs .nth + .gz .gzip + .pak .res + + Here are listed extensions of all file types for which appropriate icons are displayed. Nevertheless, ability of the program to handle some file type is determined by a set of the modules contained in it. + + You can always download the latest version of the midlet from site http://projectd8.narod.ru, in section of Java Programs. + + Also look for midlet discussion at Siemens-club forums (http://forum.siemens-club.org, http://forum.s-c.ru) and SEclub's(http://seclub.org/forum/index.php). + + P.S. Thanks to all for responses and testing SieFM and UniFM! Send wishes on projectd8@yandex.ru. + + © SilentKnight 2008+, VMX 2006, DiHLoS 2005 + + Thanks are expressed to: + +* GNU Project - for library for working with ZIP as a part of GNU Classpath +* Edmund Wagner (innoSysTec GmbH) - for library for unpacking RAR +* Apache Jakarta Project - for library for working with reqular expressions +* Martin Cameron - for IBXM library for tracker music playback +* Sergey Bochkanov (ALGLIB project) - for bicubic interpolation library +* aNNiMON - for visualisation in the player (the second and third modes) and accelerometer-based controls +* DOMr - got FileManager x65 sources from DiHLoS %) +* Spider13 - started Vista style idea +* SkyFor - for new UI icons + +...and also to all developers who took part in modules writing. \ No newline at end of file diff --git a/res/lang/en/colors.ini b/res/lang/en/colors.ini new file mode 100644 index 0000000..7f1bbf2 --- /dev/null +++ b/res/lang/en/colors.ini @@ -0,0 +1,27 @@ +Fore = Text +AltFore = Clock +HLFore = Mark +LTBorder = Element border +MDBorder = Border in file list +DKBorder = Border around menu +Disabled = Inactive menu item +Back1 = Background, top color +Back2 = Background, bottom color +SelFore = Selected text +SelBack1 = Selection, left color +SelBack2 = Selection, right color +MnFore = Menu text +MnAltFore = Menu item numbers +MnBack1 = Menu background, top color +MnBack2 = Menu background, bottom color +MnSelFore = Selected menu text +MnSelBack1 = Menu selection, left color +MnSelBack2 = Menu selection, right color +SKFore = Text on soft buttons +SKSelFore = Selected text on soft buttons +SKSelBack1 = Selected soft button, edge color +SKSelBack2 = Selected soft button, center color +Drap = Screen drapery +SBLine = Scrollbar +SBFore = Scrollbar slider + diff --git a/res/lang/en/license.txt b/res/lang/en/license.txt new file mode 100644 index 0000000..a2e773d --- /dev/null +++ b/res/lang/en/license.txt @@ -0,0 +1,7 @@ +Midlet is distributed by principle AS IS. + +You may CRASH your mobile phone if you don't know what you do. + +No claim amitted. + +Do you accept this terms? \ No newline at end of file diff --git a/res/lang/en/offsets.ini b/res/lang/en/offsets.ini new file mode 100644 index 0000000..7a66090 --- /dev/null +++ b/res/lang/en/offsets.ini @@ -0,0 +1,20 @@ +; class.package.ClassName = + +; If you plan to obfuscate your module, don't forget to tell your obfuscator to adapt the contents of this file. +; For ProGuard it is done like that: -adaptresourcefilecontents lang/** + +modules.langpack.StringUnpacker = 1000 +modules.langpack.StringPacker = 1000 + +modules.FileSplicer = 2000 +modules.FileSplitter = 2000 + +modules.mascot.MascotViewer = 3000 +modules.mascot.AnimationViewer = 3000 +modules.mascot.TextureLoader = 3000 +modules.mascot.Lib_mcv3 = 3000 + +modules.FishlabsUncoder = 3500 +modules.mocha.Decompiler = 3500 +modules.SWFViewer = 3500 +modules.HideFile = 3500 \ No newline at end of file diff --git a/res/lang/en/strings.ini b/res/lang/en/strings.ini new file mode 100644 index 0000000..8d19d7f --- /dev/null +++ b/res/lang/en/strings.ini @@ -0,0 +1,365 @@ +0 = Select disk: +1 = Favourites +2 = Options +3 = Exit +4 = Disk +5 = Disk information +6 = Total size: +7 = Kb +8 = bytes +9 = Available: +10 = Select +11 = Delete +12 = Delete all +13 = Back +14 = File name must not contain any of the following characters: %A +15 = Confirmation +16 = Delete entry from Favourites? +17 = Delete all entries from Favourites? +18 = Yes +19 = No +20 = Save +21 = Clear +22 = Error! +23 = File %A already exist! +24 = File %A not copied: %B\n\n +25 = File %A not moved: %B\n\n +26 = This file format is not supported! +27 = Open +28 = Paste +29 = Properties +30 = Rename +31 = Copy +32 = Move +33 = Folder... +34 = File... +35 = Add to Favourites +36 = Disk info +37 = Escaped strings +38 = Preferences +39 = Help +40 = OK +41 = Cancel +42 = Added to Clipboard +43 = Information: +44 = Folder name: +45 = File name: +46 = Size: +47 = Attributes: +48 = Last modified: +49 = Rename +50 = Name: +51 = File(folder) with this name already exist! Select another name. +52 = File %A is read only! +53 = Not renamed! +54 = Show hidden files and folders +55 = Visual effects +56 = Browse options: +57 = Extended menu +58 = Rotate by %A° +59 = Show error messages +60 = Create folder +61 = Create file +62 = Folder not created! +63 = Please wait... +64 = Wait +65 = In current folder +66 = On current disk +67 = On all disks +68 = scaled +69 = Attention! +70 = File %A copied. Source file is read-only.\n\n +71 = Delete selected file (folder)? +72 = Delete marked files? +73 = Folder deleted! +74 = Folder not empty. Delete recursively? +75 = File deleted. +76 = File %A not deleted! +77 = License agreement +78 = File type: +79 = File not saved! Exit? +80 = File saved +81 = Clipboard +82 = %A - copy +83 = %A - copy (%B) +84 = Operation complete successfully. +85 = File +86 = File not saved! Check 'Read Only' attribute. +87 = Gb +88 = Mark +89 = Mark all +90 = Unmark all +91 = Open not supported files as text +92 = Sort list +93 = Screen rotation +94 = Restart will be required for the new settings to take effect. +95 = Extract... +96 = Extract all... +97 = Extract to: +98 = Folder does not exist and cannot be created! +99 = Files extracted successfully. +100 = Yes for all +101 = No for all +102 = Vibration on key press, ms +103 = Compressed: +104 = File +105 = Archive +106 = Properties +107 = Operations +108 = Create +109 = Interface +110 = Minimize visual effects +111 = Archive... +112 = Compression level +113 = ID3v1 editor +114 = Title +115 = Artist +116 = Album +117 = Year +118 = Comment +119 = Track no +120 = Genre +121 = Mb +122 = Joy Left +123 = Joy Right +124 = Joy Up +125 = Joy Down +126 = Left softkey +127 = Right softkey +128 = Joy press +129 = Dial +130 = NoDial +131 = Prev screen +132 = Next screen +133 = Prev file +134 = Next file +135 = Hot keys +136 = Additional +137 = Panels +138 = Panel 1 +139 = Panel 2 +140 = Panel 3 +141 = Panel 4 +142 = Panel 5 +143 = Panel 6 +144 = Panel 7 +145 = Panel 8 +146 = Panel 9 +147 = Panel 10 +148 = Fullscreen +149 = no action +150 = Keyboard... +151 = Language +152 = Color scheme +153 = Check file attributes +154 = Accurate directory check +155 = Sort file list +156 = Read only +157 = Hidden +158 = Contents +159 = %A folders, %B files +160 = Player options +161 = ID3 encoding +162 = Show play progress +163 = Tracker module buffer size, sec. +164 = Done +165 = Text editor options +166 = Show CR symbol +167 = Show LF symbol +168 = Substitute tabulation with spaces +169 = Go to +170 = Scroll by pages instead of lines +171 = Key mapping +172 = Initial setup +173 = Clock mode +174 = Switch +175 = Next panel +176 = Prev. panel +177 = Next free +178 = Prev. free +179 = Swap panels +180 = Edit +181 = Search +182 = Font +183 = Encoding +184 = Recursive search +185 = Hash-sum +186 = Crypt +187 = Password +188 = Use crypt operation again with the same password for decryption. +189 = Small +190 = Medium +191 = Large +192 = Face +193 = Style +194 = Bold +195 = Italic +196 = Monospace +197 = Proportional +198 = System +199 = Underlined +200 = Show menu numbers +201 = Shuffle playback +202 = Transcode +203 = Custom +204 = Playlist +205 = Search inside archives +206 = Audio +207 = Video +208 = Save path +209 = Absolute +210 = Relative +211 = ZIP archiver +212 = PPK archiver +213 = Audioplayer +214 = Image viewer +215 = Videoplayer +216 = Text editor +217 = Note editor +218 = Tracker player +219 = Color scheme installer +220 = Vector image viewer +221 = Frame cursor +222 = No change +223 = Set +224 = Reset +225 = Background image +226 = Name template +227 = Minimize +228 = Save changes? +229 = Save as... +230 = Edit +231 = Undo +232 = Redo +233 = Find +234 = Find next +235 = Text +236 = Archive encoding +237 = Line number +238 = Remember explored paths +239 = Templates +240 = Use UTF BOM signature +241 = File end is reached. Continue search from the beginning? +242 = To start +243 = To end +244 = Add +245 = Play message signals +246 = Swap soft keys in menus +247 = Ignore case +248 = Don't sort +249 = By name +250 = By type +251 = By date +252 = By size +253 = Sort options +254 = Reverse order +255 = Restart +256 = Move cursor on mark +257 = Replace +258 = Replace all +259 = Replace with +260 = Alter clock position +261 = matches +262 = Equalizer +263 = Hz +264 = KHz +265 = dB +266 = Use accelerometer +267 = Backlight always on +268 = Tracker module sample rate +269 = Tracker module resample quality +270 = Low +271 = Medium +272 = High +273 = Disabled +274 = Enabled +275 = Automatic +276 = Escape +277 = Unescape +278 = Clipboard is empty! +279 = Modules +280 = Packing file %A... +281 = Playlist +282 = Stub +283 = Character +284 = Text box title +285 = Normal +286 = Ticker tape +287 = ZIP archive +288 = PPK archive +289 = Unpacking file %A... +290 = Memory monitor +291 = Update +292 = Fill +293 = Used +294 = Total +295 = Memory monitor step, ms +296 = Garbage collector threshold, % +297 = Containers +298 = Close +299 = Close all +300 = Writing file %A... +301 = Palette +302 = Color selector +303 = %A refer., %B depend. +304 = Long item scroll speed +305 = Installing color scheme... +306 = Refined gradients +307 = Transparency in gradients +308 = Text buffer size, char. +309 = Full file names +310 = In Clipboard +311 = In Favourites +312 = Enter +313 = Key assignment +314 = User-defined keys +315 = Key editor +316 = Key code +317 = Device internal handler +318 = Abbreviation +319 = Press a key... +320 = Hot %A +321 = Held %A +322 = Root +323 = File list +324 = Bit bucket +325 = RAR archiver +326 = Assign +327 = Reset +328 = Cache code pages +329 = Large font +330 = In file list +331 = In menu +332 = "Exit" in drive list +333 = Metadata format +334 = Show metadata captions +335 = Regular expressions +336 = Multiline matching +337 = Replace backreferences + +[1000] + +0 = Lang pack decompiler +1 = Lang pack compiler + +[2000] + +0 = File splice +1 = File splitter +2 = Parts count +3 = Part size +4 = File size unknown, split impossible. + +[3000] + +0 = MascotCapsule model viewer +1 = MascotCapsule animation viewer +2 = MascotCapsule texture loader +3 = S %A Rx %D° Ry %E° Px %G Py %H F %J + +[3500] + +0 = FishlabsUncoder +1 = JavaDecompiler +2 = Flash (swf) Viewer +3 = Hide File \ No newline at end of file diff --git a/res/lang/lang.ini b/res/lang/lang.ini new file mode 100644 index 0000000..dac9a36 --- /dev/null +++ b/res/lang/lang.ini @@ -0,0 +1,2 @@ +ru = Ðóññêèé +en = English diff --git a/res/lang/ru/about.txt b/res/lang/ru/about.txt new file mode 100644 index 0000000..8b837bf --- /dev/null +++ b/res/lang/ru/about.txt @@ -0,0 +1,44 @@ + UniFM (Unified File Manager) - óíèôèöèðîâàííûé ôàéëîâûé ìåíåäæåð äëÿ òåëåôîíîâ ñ ïîääåðæêîé äîñòóïà ê ôàéëîâîé ñèñòåìå èç Java. Îí ïîçâîëÿåò ïðîñìàòðèâàòü, êîïèðîâàòü, ïåðåìåùàòü è óäàëÿòü ôàéëû è ïàïêè â Âàøåì òåëåôîíå. + + Ãëàâíàÿ îñîáåííîñòü UniFM ïî ñðàâíåíèþ ñ äðóãèìè ôàéëîâûìè ìåíåäæåðàìè - ìîäóëüíàÿ ñòðóêòóðà. Òî åñòü, ïîëüçîâàòåëè ìîãóò ñàìè îïðåäåëÿòü, êàêàÿ ôóíêöèîíàëüíîñòü èì òðåáóåòñÿ, è â ñîîòâåòñòâèè ñî ñâîèìè ïîòðåáíîñòÿìè âûáèðàòü êîìïîíåíòû, êîòîðûå âîéäóò â ñîñòàâ ïðîãðàììû. Ìèíèìàëüíûé íàáîð - òîëüêî ôàéëîâîå ÿäðî, âûïîëíÿþùåå áàçîâûå îïåðàöèè íàä ôàéëàìè è ïàïêàìè. Ìàêñèìàëüíàÿ æå êîíôèãóðàöèÿ íå îãðàíè÷åíà íè÷åì (ôàêòè÷åñêè - òîëüêî ðåñóðñàìè òåëåôîíà). Íàïðèìåð, äàííàÿ âåðñèÿ âêëþ÷àåò â ñåáÿ ñòàíäàðòíûé "äæåíòåëüìåíñêèé íàáîð" ìîäóëåé äëÿ ïðîñìîòðà êàðòèíîê è âèäåî, ïðîñëóøèâàíèÿ ìóçûêè è ðåäàêòèðîâàíèÿ òåêñòà. + +  UniFM ðåàëèçîâàíà óíèêàëüíàÿ ñèñòåìà ïðîçðà÷íîãî âçàèìîäåéñòâèÿ ñ àðõèâàìè, òàêæå íà ìîäóëüíîé îñíîâå. Ýòî îçíà÷àåò, ÷òî â ïðîãðàììó òåîðåòè÷åñêè ìîæåò áûòü äîáàâëåíà ïîääåðæêà ëþáûõ òèïîâ àðõèâîâ, ïðè÷åì äëÿ ïîëüçîâàòåëÿ îíè áóäóò íåîòëè÷èìû îò îáû÷íûõ ïàïîê â ôàéëîâîé ñèñòåìå. Âíóòðè àðõèâîâ ìîæíî âûïîëíÿòü ïðèâû÷íûå îïåðàöèè êîïèðîâàíèÿ, ïåðåìåùåíèÿ, ïåðåèìåíîâàíèÿ è óäàëåíèÿ ôàéëîâ, ïðîñìàòðèâàòü è ðåäàêòèðîâàòü òåêñòû, âîñïðîèçâîäèòü ìóçûêó è ò.ä. Êðîìå òîãî, ïîääåðæèâàþòñÿ âëîæåííûå àðõèâû. Âîçìîæíîñòè, îïÿòü-òàêè, îãðàíè÷åíû òîëüêî ðåñóðñàìè òåëåôîíà. + + Òåõíè÷åñêè UniFM ÿâëÿåòñÿ ðàçâèòèåì ïðîåêòà SieFM (Siemens File Manager), è ïîýòîìó íàñëåäóåò ìíîãèå åãî ÷åðòû. Íèæå ïåðå÷èñëåíû îñíîâíûå âîçìîæíîñòè ïðîãðàììû: + + Èìååòñÿ âîçìîæíîñòü óäàëåíèÿ ôàéëîâ read-only (òîëüêî äëÿ ÷òåíèÿ), ïðîñìîòðà ñêðûòûõ ïàïîê, ðåêóðñèâíîãî óäàëåíèÿ ïàïîê. Ïðîãðàììà èìååò ìíîãîîêîííûé èíòåðôåéñ - äî 10 îêîí, ìåæäó êîòîðûìè ìîæíî ïåðåêëþ÷àòüñÿ. Ñðåäñòâà ïðîñìîòðà ôàéëîâ çàïóñêàþòñÿ â òåõ æå ñàìûõ îêíàõ, òî åñòü ìîæíî çàïóñòèòü ïðîèãðûâàòåëü â îäíîì îêíå, ïåðåêëþ÷èòüñÿ íà äðóãîå è ïðîäîëæèòü ðàáîòó. + + Ìîäóëü ïðîñìîòðà èçîáðàæåíèé ïîääåðæèâàåò âñå ãðàôè÷åñêèå ôîðìàòû, êîòîðûå ðàñïîçíàþòñÿ ñàìèì òåëåôîíîì, êðîìå òîãî, ïîääåðæèâàåòñÿ ïðîñìîòð âåêòîðíîé àíèìàöèè â ôîðìàòå MVI (ôîðìàò ïðîãðàììû VIArt). Àíàëîãè÷íî, àóäèîïðîèãðûâàòåëü êðîìå âîñïðîèçâåäåíèÿ ôàéëîâ, âîñïðîèçâîäèìûõ äàííûì òåëåôîíîì, ïîääåðæèâàåò âîñïðîèçâåäåíèå ìóçûêè â òðåêåðíûõ ôîðìàòàõ MOD (ProTracker), XM (FastTracker 2) è S3M (ScreamTracker). + + Ïðîñìîòð è ðåäàêòèðîâàíèå òåêñòà âîçìîæíî â êîäèðîâêå Unicode â ôîðìàòàõ UTF-8 è UTF-16, à òàêæå âî âñåõ íàèáîëåå ÷àñòî èñïîëüçóåìûõ îäíîáàéòîâûõ êîäèðîâêàõ (CP1251, CP866, KOI-8). Ïðîñìîòð òåêñòà íà÷èíàåòñÿ ñ òîé ïîçèöèè, íà êîòîðîé îí áûë â ïðîøëûé ðàç çàâåðøåí, âîçìîæåí áûñòðûé ïåðåõîä íà ïðîèçâîëüíóþ ïîçèöèþ, èçìåíåíèå ðàçìåðà øðèôòà. Òåêñòîâûé ðåäàêòîð ïîääåðæèâàåò îòìåíó âíîñèìûõ â òåêñò èçìåíåíèé, ïîèñê è çàìåíó ôðàãìåíòîâ òåêñòà, ïðåîáðàçîâàíèå òåêñòîâ èç îäíîé êîäèðîâêè â äðóãóþ. + + Ïîääåðæèâàåìûå äàííîé âåðñèåé òèïû ôàéëîâ: +Ãðàôè÷åñêèå: .jpg .jpe .gif .png .bmx .jpeg .wbmp .ico .bmp +Ìóçûêàëüíûå: .mid .amr .wav .aac .mp3 .imy .m4a .xmf .awb .midi .wma + .xm .mod .s3m +Âèäåî: .3gp .mp4 .m4v .wmv .rm +Òåêñòîâûå: .j .txt .jad .log .ini .inf .cdf .xml .col .java .jcc + .tmo .vcs .vnt +Àðõèâû: .zip .jar .sdt .scs .nth + .gz .gzip + .pak .res + +  ñïèñêå ïðèâåäåíû ðàñøèðåíèÿ ôàéëîâ, äëÿ êîòîðûõ îòîáðàæàþòñÿ ñîîòâåòñòâóþùèå çíà÷êè. Òåì íå ìåíåå, ñïîñîáíîñòü ïðîãðàììû îáðàáàòûâàòü òîò èëè èíîé òèï ôàéëîâ îïðåäåëÿåòñÿ íàáîðîì ìîäóëåé, ñîäåðæàùèõñÿ â íåé. + + Ïîñëåäíþþ âåðñèþ ìèäëåòà âû âñåãäà ìîæåòå ñêà÷àòü ñ ñàéòà http://projectd8.narod.ru, â ðàçäåëå Ïðîãðàììû Java. + + Òàêæå ñìîòðèòå îáñóæäåíèå ìèäëåòà íà ôîðóìàõ Ñèìåíñ-Êëóáà (http://forum.siemens-club.org, http://forum.s-c.ru) è SEclub'à (http://seclub.org/forum/index.php). + + P.S. Ñïàñèáî âñåì çà îòçûâû è òåñòèðîâàíèå SieFM è UniFM! Øëèòå ïîæåëàíèÿ íà projectd8@yandex.ru. + + © SilentKnight 2008+, VMX 2006, DiHLoS 2005 + + Áëàãîäàðíîñòè âûðàæàþòñÿ: + +* GNU Project - çà áèáëèîòåêó äëÿ ðàáîòû ñ ZIP â ñîñòàâå GNU Classpath +* Edmund Wagner (innoSysTec GmbH) - çà áèáëèîòåêó äëÿ ðàñïàêîâêè RAR +* Apache Jakarta Project - çà áèáëèîòåêó äëÿ ðàáîòû ñ ðåãóëÿðíûìè âûðàæåíèÿìè +* Martin Cameron - çà áèáëèîòåêó IBXM äëÿ âîñïðîèçâåäåíèÿ òðåêåðíîé ìóçûêè +* Sergey Bochkanov (ALGLIB project) - çà áèáëèîòåêó áèêóáè÷åñêîé èíòåðïîëÿöèè +* aNNiMON - çà âèçóàëèçàöèþ â ïëååðå (âòîðîé è òðåòèé ðåæèìû) è óïðàâëåíèå ñ ïîìîùüþ àêñåëåðîìåòðà +* DOMr - äîãîâîðèëñÿ ñ DiHLoS-îì î ñîðöàõ +* Spider13 - ñòàðòàíóë èíòåðôåéñ â ñòèëå Vista +* SkyFor - çà íîâûå çíà÷êè èíòåðôåéñà + +...à òàêæå âñåì ðàçðàáîò÷èêàì, ïðèíÿâøèì ó÷àñòèå â íàïèñàíèè ìîäóëåé. diff --git a/res/lang/ru/colors.ini b/res/lang/ru/colors.ini new file mode 100644 index 0000000..bc1c074 --- /dev/null +++ b/res/lang/ru/colors.ini @@ -0,0 +1,27 @@ +Fore = Òåêñò +AltFore = ×àñû +HLFore = Îòìåòêà +LTBorder = Ðàìêà ýëåìåíòîâ +MDBorder = Ðàìêà â ñïèñêå ôàéëîâ +DKBorder = Ðàìêà âîêðóã ìåíþ +Disabled = Íåàêòèâíûé ïóíêò ìåíþ +Back1 = Ôîí, öâåò ñâåðõó +Back2 = Ôîí, öâåò ñíèçó +SelFore = Âûäåëåííûé òåêñò +SelBack1 = Âûäåëåíèå, öâåò ñëåâà +SelBack2 = Âûäåëåíèå, öâåò ñïðàâà +MnFore = Òåêñò ìåíþ +MnAltFore = Íîìåðà ïóíêòîâ ìåíþ +MnBack1 = Ôîí ìåíþ, öâåò ñâåðõó +MnBack2 = Ôîí ìåíþ, öâåò ñíèçó +MnSelFore = Âûäåëåííûé òåêñò ìåíþ +MnSelBack1 = Âûäåëåíèå â ìåíþ, öâåò ñëåâà +MnSelBack2 = Âûäåëåíèå â ìåíþ, öâåò ñïðàâà +SKFore = Òåêñò íà ñîôò-êíîïêàõ +SKSelFore = Âûäåëåííûé òåêñò íà ñîôò-êíîïêàõ +SKSelBack1 = Âûäåëåííàÿ ñîôò-êíîïêà, öâåò ñ êðàþ +SKSelBack2 = Âûäåëåííàÿ ñîôò-êíîïêà, öâåò â öåíòðå +Drap = Äðàïèðîâêà ýêðàíà +SBLine = Ïîëîñà ïðîêðóòêè +SBFore = Ïîëçóíîê ïîëîñû ïðîêðóòêè + diff --git a/res/lang/ru/license.txt b/res/lang/ru/license.txt new file mode 100644 index 0000000..42d3b90 --- /dev/null +++ b/res/lang/ru/license.txt @@ -0,0 +1,6 @@ +Ìèäëåò ïîñòàâëÿåòñÿ ïî ïðèíöèïó AS IS (êàê åñòü). +Ïðè íåóìåëîì îáðàùåíèè ñ ìèäëåòîì âû ìîæåòå ÍÀÂÐÅÄÈÒÜ ñâîåìó ìîáèëüíîìó òåëåôîíó. + +Çà ïðèíåñåííûé ìîðàëüíûé è ìàòåðèàëüíûé óùåðá àâòîð ìèäëåòà îòâåòñòâåííîñòè ÍÅ íåñåò. + +Âû ñîãëàñíû ñ óñëîâèÿìè äàííîãî ñîãëàøåíèÿ? \ No newline at end of file diff --git a/res/lang/ru/offsets.ini b/res/lang/ru/offsets.ini new file mode 100644 index 0000000..7a66090 --- /dev/null +++ b/res/lang/ru/offsets.ini @@ -0,0 +1,20 @@ +; class.package.ClassName = + +; If you plan to obfuscate your module, don't forget to tell your obfuscator to adapt the contents of this file. +; For ProGuard it is done like that: -adaptresourcefilecontents lang/** + +modules.langpack.StringUnpacker = 1000 +modules.langpack.StringPacker = 1000 + +modules.FileSplicer = 2000 +modules.FileSplitter = 2000 + +modules.mascot.MascotViewer = 3000 +modules.mascot.AnimationViewer = 3000 +modules.mascot.TextureLoader = 3000 +modules.mascot.Lib_mcv3 = 3000 + +modules.FishlabsUncoder = 3500 +modules.mocha.Decompiler = 3500 +modules.SWFViewer = 3500 +modules.HideFile = 3500 \ No newline at end of file diff --git a/res/lang/ru/strings.ini b/res/lang/ru/strings.ini new file mode 100644 index 0000000..859d47d --- /dev/null +++ b/res/lang/ru/strings.ini @@ -0,0 +1,365 @@ +0 = Âûáîð äèñêà: +1 = Èçáðàííîå +2 = Îïöèè +3 = Âûõîä +4 = Äèñê +5 = Èíôîðìàöèÿ î äèñêå +6 = Îáùèé ðàçìåð: +7 = Êá +8 = áàéò +9 = Ñâîáîäíî: +10 = Âûáîð +11 = Óäàëèòü +12 = Óäàëèòü âñå +13 = Íàçàä +14 = Èìÿ ôàéëà íå äîëæíî ñîäåðæàòü ñëåäóþùèõ ñèìâîëîâ: %A +15 = Ïîäòâåðæäåíèå +16 = Óäàëèòü çàïèñü èç Èçáðàííîãî? +17 = Óäàëèòü âñå èç Èçáðàííîãî? +18 = Äà +19 = Íåò +20 = Ñîõðàíèòü +21 = Î÷èñòèòü +22 = Îøèáêà! +23 = Ôàéë %A óæå ñóùåñòâóåò. Ïåðåçàïèñàòü? +24 = Ôàéë %A íå ñêîïèðîâàí: %B\n\n +25 = Ôàéë %A íå ïåðåìåùåí: %B\n\n +26 = Äàííûé ôîðìàò ôàéëà íå ïîääåðæèâàåòñÿ! +27 = Îòêðûòü +28 = Âñòàâèòü +29 = Ñâîéñòâà +30 = Ïåðåèìåíîâàòü +31 = Êîïèðîâàòü +32 = Ïåðåìåñòèòü +33 = Ïàïêó... +34 = Ôàéë... +35 =  èçáðàííîå +36 = Èíôî î äèñêå +37 = Ýêðàíèðîâàííûå ñòðîêè +38 = Íàñòðîéêè +39 = Ïîìîùü +40 = ÎÊ +41 = Îòìåíà +42 = Äîáàâëåí(û) â áóôåð îáìåíà +43 = Èíôîðìàöèÿ +44 = Èìÿ ïàïêè +45 = Èìÿ ôàéëà +46 = Ðàçìåð +47 = Àòðèáóòû +48 = Ïîñëåäíåå èçìåíåíèå +49 = Ïåðåèìåíîâàòü +50 = Èìÿ: +51 = Ýòîò ôàéë (ïàïêà) óæå ñóùåñòâóåò, âûáåðèòå äðóãîå èìÿ. +52 = Ôàéë %A òîëüêî äëÿ ÷òåíèÿ! +53 = Íå ïåðåèìåíîâàí! +54 = Ïîêàçûâàòü ñêðûòûå ôàéëû è ïàïêè +55 = Âèçóàëüíûå ýôôåêòû +56 = Ïðîñìîòð è âûïîëíåíèå +57 = Ðàñøèðåííîå ìåíþ +58 = Ïîâåðíóòü íà %A° +59 = Ïîêàçûâàòü ñîîáùåíèÿ îá îøèáêàõ +60 = Ñîçäàòü ïàïêó +61 = Ñîçäàòü ôàéë +62 = Ïàïêà íå ñîçäàíà! +63 = Ïîæàëóéñòà, ïîäîæäèòå... +64 = Ïîäîæäèòå +65 =  òåêóùåé ïàïêå +66 = Íà òåêóùåì äèñêå +67 = Íà âñåõ äèñêàõ +68 = ìàñø. +69 = Âíèìàíèå! +70 = Ôàéë %A ñêîïèðîâàí, èñõîäíûé ôàéë òîëüêî äëÿ ÷òåíèÿ.\n\n +71 = Óäàëèòü âûáðàííûé ôàéë (ïàïêó)? +72 = Óäàëèòü îòìå÷åííûå ôàéëû? +73 = Ïàïêà óäàëåíà! +74 = Ïàïêà íå ïóñòà. Óäàëèòü ðåêóðñèâíî? +75 = Ôàéë óäàëåí. +76 = Íåâîçìîæíî óäàëèòü ôàéë %A! +77 = Ëèöåíç. ñîãëàøåíèå +78 = Òèï ôàéëà: +79 = Ôàéë íå ñîõðàíåí! Âûéòè? +80 = Ôàéë ñîõðàíåí +81 = Áóôåð îáìåíà +82 = %A - êîïèÿ +83 = %A - êîïèÿ (%B) +84 = Îïåðàöèÿ óñïåøíî âûïîëíåíà. +85 = Ôàéë +86 = Ôàéë íå ñîõðàíåí! Ñíèìèòå àòðèáóò Read Only. +87 = Ãá +88 = Âûäåëèòü +89 = Âûäåëèòü âñ¸ +90 = Ñáðîñèòü âñ¸ +91 = Îòêðûâàòü íåïîääåðæèâàåìûå òèïû ôàéëîâ êàê òåêñò +92 = Ñîðòèðîâêà +93 = Ïîâîðîò ýêðàíà +94 = Äëÿ ïðèìåíåíèÿ íàñòðîåê ïîòðåáóåòñÿ ïåðåçàïóñê. +95 = Èçâëå÷ü... +96 = Èçâëå÷ü âñ¸... +97 = Èçâëå÷ü â: +98 = Ïàïêà íå ñóùåñòâóåò è ñîçäàòü å¸ íåâîçìîæíî! +99 = Ôàéëû óñïåøíî èçâëå÷åíû. +100 = Äà äëÿ âñåõ +101 = Íåò äëÿ âñåõ +102 = Âèáðàöèÿ ïðè íàæàòèè êëàâèø, ìñ +103 = Óïàêîâàí: +104 = Ôàéë +105 = Àðõèâ +106 = Ñâîéñòâà +107 = Îïåðàöèè +108 = Ñîçäàòü +109 = Èíòåðôåéñ +110 = Ìèíèìóì âèçóàëüíûõ ýôôåêòîâ +111 = Àðõèâ... +112 = Óðîâåíü ñæàòèÿ +113 = Ðåäàêòîð ID3v1 +114 = Íàçâàíèå +115 = Èñïîëíèòåëü +116 = Àëüáîì +117 = Ãîä +118 = Êîììåíòàðèé +119 = Íîìåð òðåêà +120 = Æàíð +121 = Ìá +122 = Âëåâî +123 = Âïðàâî +124 = Ââåðõ +125 = Âíèç +126 = Ëåâàÿ ñîôò +127 = Ïðàâàÿ ñîôò +128 = Äæîéñòèê +129 = Çâîíîê +130 = Îòìåíà +131 = Ââåðõ íà ýêðàí +132 = Âíèç íà ýêðàí +133 = Ââåðõ íà ôàéë +134 = Âíèç íà ôàéë +135 = Ãîð. êëàâèøè +136 = Äîïîëíèòåëüíî +137 = Ïàíåëè +138 = Ïàíåëü 1 +139 = Ïàíåëü 2 +140 = Ïàíåëü 3 +141 = Ïàíåëü 4 +142 = Ïàíåëü 5 +143 = Ïàíåëü 6 +144 = Ïàíåëü 7 +145 = Ïàíåëü 8 +146 = Ïàíåëü 9 +147 = Ïàíåëü 10 +148 = Âî âåñü ýêðàí +149 = ïóñòî +150 = Êëàâèàòóðà... +151 = ßçûê / Language +152 = Öâåòîâàÿ ñõåìà +153 = Ïðîâåðÿòü àòòðèáóòû ôàéëîâ +154 = Òî÷íàÿ ïðîâåðêà äèðåêòîðèé +155 = Ñîðòèðîâêà ñïèñêà ôàéëîâ +156 = Òîëüêî ÷òåíèå +157 = Ñêðûòûé +158 = Ñîäåðæèò +159 = %A ïàïîê, %B ôàéëîâ +160 = Íàñòðîéêè ïëååðà +161 = Êîäèðîâêà ID3 +162 = Ïîêàçûâàòü ïðîãðåññ-áàð +163 = Ðàçìåð áóôåðà òðåêåðíûõ ìîäóëåé, ñåê. +164 = Âûïîëíåíî +165 = Íàñòðîéêè òåêñòîâîãî ðåäàêòîðà +166 = Ïîêàçûâàòü ñèìâîë CR +167 = Ïîêàçûâàòü ñèìâîë LF +168 = Çàìåíÿòü òàáóëÿöèþ ïðîáåëàìè +169 = Ïåðåõîä +170 = Ïîñòðàíè÷íàÿ ïðîêðóòêà âìåñòî ïîñòðî÷íîé +171 = Ðàñêëàäêà êëàâèàòóðû +172 = Íà÷àëüíàÿ íàñòðîéêà +173 = Ðåæèì ÷àñîâ +174 = Ïåðåêëþ÷åíèå +175 = Ñëåä. ïàíåëü +176 = Ïðåä. ïàíåëü +177 = Ñëåä. ïóñòàÿ +178 = Ïðåä. ïóñòàÿ +179 = Îáìåí ïàíåëåé +180 = Èçìåíèòü +181 = Ïîèñê +182 = Øðèôò +183 = Êîäèðîâêà +184 = Ðåêóðñèâíûé ïîèñê +185 = Õåø-ñóììà +186 = Øèôðîâàíèå +187 = Ïàðîëü +188 = Èñïîëüçóéòå ïîâòîðíîå øèôðîâàíèå ñ òåì æå ïàðîëåì äëÿ ðàñøèôðîâêè. +189 = Ìàëûé +190 = Ñðåäíèé +191 = Áîëüøîé +192 = Òèï +193 = Ñòèëü +194 = Æèðíûé +195 = Êóðñèâ +196 = Ìîíîøèðèííûé +197 = Ïðîïîðöèîíàëüíûé +198 = Ñèñòåìíûé +199 = Ïîä÷åðêíóòûé +200 = Ïîêàçûâàòü íîìåðà ïóíêòîâ ìåíþ +201 = Âîñïðîèçâåäåíèå â ñëó÷àéíîì ïîðÿäêå +202 = Ïåðåêîäèðîâàòü +203 = Çàêàçíàÿ +204 = Ïëåéëèñò +205 = Èñêàòü â àðõèâàõ +206 = Àóäèî +207 = Âèäåî +208 = Ñîõðàíÿòü ïóòè +209 = Àáñîëþòíûå +210 = Îòíîñèòåëüíûå +211 = Àðõèâàòîð ZIP +212 = Àðõèâàòîð PPK +213 = Àóäèîïðîèãðûâàòåëü +214 = Ïðîñìîòð èçîáðàæåíèé +215 = Âèäåîïðîèãðûâàòåëü +216 = Òåêñòîâûé ðåäàêòîð +217 = Ðåäàêòîð çàìåòîê +218 = Òðåêåðíûé ïðîèãðûâàòåëü +219 = Óñòàíîâùèê öâåòîâûõ ñõåì +220 = Ïðîñìîòð âåêòîðíûõ èçîáðàæåíèé +221 = Êóðñîð â âèäå ðàìêè +222 = Áåç èçìåíåíèé +223 = Óñòàíîâèòü +224 = Ñáðîñèòü +225 = Ôîíîâîå èçîáðàæåíèå +226 = Øàáëîí èìåíè +227 = Ñâåðíóòü +228 = Ñîõðàíèòü èçìåíåíèÿ? +229 = Ñîõðàíèòü êàê... +230 = Ïðàâêà +231 = Îòìåíèòü +232 = Ïîâòîðèòü +233 = Íàéòè +234 = Íàéòè äàëåå +235 = Òåêñò +236 = Êîäèðîâêà àðõèâîâ +237 = Íîìåð ñòðîêè +238 = Çàïîìèíàòü îòêðûòûå ïóòè +239 = Øàáëîíû +240 = Èñïîëüçîâàòü UTF BOM ñèãíàòóðó +241 = Äîñòèãíóò êîíåö ôàéëà. Ïðîäîëæèòü ïîèñê ñ íà÷àëà? +242 =  íà÷àëî +243 =  êîíåö +244 = Äîáàâèòü +245 = Ïðîèãðûâàòü ñèãíàëû â ñîîáùåíèÿõ +246 = Ïîìåíÿòü ìåñòàìè ñîôò-êëàâèøè â ìåíþ +247 = Íå ó÷èòûâàòü ðåãèñòð +248 = Íå ñîðòèðîâàòü +249 = Ïî èìåíè +250 = Ïî òèïó +251 = Ïî äàòå èçìåíåíèÿ +252 = Ïî ðàçìåðó +253 = Îïöèè ñîðòèðîâêè +254 =  îáðàòíîì ïîðÿäêå +255 = Ïåðåçàïóñê +256 = Ïåðåâîäèòü êóðñîð ïðè âûäåëåíèè +257 = Çàìåíèòü +258 = Çàìåíèòü âñå +259 = Çàìåíèòü íà +260 = Ïåðåìåñòèòü ÷àñû +261 = ñîâïàäåíèé +262 = Ýêâàëàéçåð +263 = Ãö +264 = ÊÃö +265 = äÁ +266 = Èñïîëüçîâàòü àêñåëåðîìåòð +267 = Ïîñòîÿííàÿ ïîäñâåòêà +268 = ×àñòîòà äèñêðåòèçàöèè òðåêåðíûõ ìîäóëåé +269 = Êà÷åñòâî ðåñåìïëèíãà òðåêåðíûõ ìîäóëåé +270 = Íèçêîå +271 = Ñðåäíåå +272 = Âûñîêîå +273 = Îòêëþ÷åíî +274 = Âêëþ÷åíî +275 = Àâòîìàòè÷åñêè +276 = Ýêðàíèðîâàòü +277 = Ðàçýêðàíèðîâàòü +278 = Áóôåð îáìåíà ïóñò! +279 = Ìîäóëè +280 = Óïàêîâêà ôàéëà %A... +281 = Ñïèñêè âîñïðîèçâåäåíèÿ +282 = Çàãëóøêà +283 = Ñèìâîë +284 = Çàãîëîâîê òåêñòîâîãî îêíà +285 = Îáû÷íûé +286 = Áåãóùàÿ ñòðîêà +287 = Àðõèâ ZIP +288 = Àðõèâ PPK +289 = Ðàñïàêîâêà ôàéëà %A... +290 = Ìîíèòîð ïàìÿòè +291 = Îáíîâèòü +292 = Çàïîëíèòü +293 = Çàíÿòî +294 = Âñåãî +295 = Øàã ìîíèòîðà ïàìÿòè, ìñ +296 = Ïîðîã ñáîðùèêà ìóñîðà, % +297 = Êîíòåéíåðû +298 = Çàêðûòü +299 = Çàêðûòü âñå +300 = Çàïèñü ôàéëà %A... +301 = Ïàëèòðà +302 = Ïîäáîð öâåòà +303 = %A îáðàù., %B çàâèñ. +304 = Ñêîðîñòü ïðîêðóòêè äëèííûõ ýëåìåíòîâ +305 = Óñòàíîâêà öâåòîâîé ñõåìû... +306 = Óëó÷øåííûå ãðàäèåíòû +307 = Ïðîçðà÷íîñòü â ãðàäèåíòàõ +308 = Ðàçìåð òåêñòîâîãî áóôåðà, ñèìâ. +309 = Ïîëíûå èìåíà ôàéëîâ +310 =  Áóôåðå îáìåíà +311 =  Èçáðàííîì +312 = Ââîä +313 = Íàçíà÷åíèå êëàâèø +314 = Ïîëüçîâàòåëüñêèå êëàâèøè +315 = Ðåäàêòîð êëàâèø +316 = Êîä êëàâèøè +317 = Ñîáñòâåííûé îáðàáîò÷èê óñòðîéñòâà +318 = Àááðåâèàòóðà +319 = Íàæìèòå êëàâèøó... +320 = Ãîð. %A +321 = Óäåðæ. %A +322 = Êîðåíü +323 = Ñïèñîê ôàéëîâ +324 = Êîðçèíà +325 = Àðõèâàòîð RAR +326 = Íàçíà÷èòü +327 = Ñáðîñèòü +328 = Êåøèðîâàòü êîäîâûå ñòðàíèöû +329 = Êðóïíûé øðèôò +330 =  ñïèñêå ôàéëîâ +331 =  ìåíþ +332 = "Âûõîä" â ñïèñêå äèñêîâ +333 = Ôîðìàò ìåòàäàííûõ +334 = Ïîêàçûâàòü çàãîëîâêè ìåòàäàííûõ +335 = Ðåãóëÿðíûå âûðàæåíèÿ +336 = Ìíîãîñòðî÷íîå ñðàâíåíèå +337 = Çàìåíÿòü îáðàòíûå ññûëêè + +[1000] + +0 = Ðàñïàêîâùèê ÿçûêîâûõ ïàêåòîâ +1 = Çàïàêîâùèê ÿçûêîâûõ ïàêåòîâ + +[2000] + +0 = Ñêëåéêà ôàéëîâ +1 = Äåëèòåëü ôàéëîâ +2 = Êîëè÷åñòâî ÷àñòåé +3 = Ðàçìåð ÷àñòè +4 = Ðàçìåð ôàéëà íåèçâåñòåí, ðàçäåëåíèå íåâîçìîæíî. + +[3000] + +0 = Ïðîñìîòð ìîäåëåé MascotCapsule +1 = Ïðîñìîòð àíèìàöèè MascotCapsule +2 = Çàãðóç÷èê òåêñòóð MascotCapsule +3 = S %A Rx %D° Ry %E° Px %G Py %H F %J + +[3500] + +0 = Ïåðåêîäèðîâùèê Fishlabs +1 = Äåêîìïèëÿòîð Java +2 = Ïðîñìîòð Flash (swf) +3 = Ñêðûòü ôàéë \ No newline at end of file diff --git a/res/style/Cold Steel.ncs b/res/style/Cold Steel.ncs new file mode 100644 index 0000000..6fc00eb Binary files /dev/null and b/res/style/Cold Steel.ncs differ diff --git a/res/style/Default.ncs b/res/style/Default.ncs new file mode 100644 index 0000000..326b1e6 Binary files /dev/null and b/res/style/Default.ncs differ diff --git a/res/style/Just Blue.ncs b/res/style/Just Blue.ncs new file mode 100644 index 0000000..462a160 Binary files /dev/null and b/res/style/Just Blue.ncs differ diff --git a/res/style/style.ini b/res/style/style.ini new file mode 100644 index 0000000..d0f7d47 --- /dev/null +++ b/res/style/style.ini @@ -0,0 +1,3 @@ +Default +Cold Steel +Just Blue diff --git a/res/temp/html.tpl b/res/temp/html.tpl new file mode 100644 index 0000000..11de5af --- /dev/null +++ b/res/temp/html.tpl @@ -0,0 +1,24 @@ + + + + + + + + +Title + + + + + + + + + + + \ No newline at end of file diff --git a/res/temp/php-wml.tpl b/res/temp/php-wml.tpl new file mode 100644 index 0000000..fb8cdad --- /dev/null +++ b/res/temp/php-wml.tpl @@ -0,0 +1,24 @@ +'; +echo ''; +echo ''; +echo "\r\n\r\n"; +echo ''; +echo '

'; + + + + + + +echo '

'; +?> \ No newline at end of file diff --git a/res/temp/php-xhtml.tpl b/res/temp/php-xhtml.tpl new file mode 100644 index 0000000..7456957 --- /dev/null +++ b/res/temp/php-xhtml.tpl @@ -0,0 +1,32 @@ +'; +echo ' +'; +echo ''; +echo ''; +echo ''; +echo ''; +echo ''; +echo ''; +echo ''; +echo ''; +echo ''; +echo ''; +echo 'Title'; +echo ''; + + + + + +echo ''; +?> \ No newline at end of file diff --git a/res/temp/php.tpl b/res/temp/php.tpl new file mode 100644 index 0000000..dcdb979 --- /dev/null +++ b/res/temp/php.tpl @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/res/temp/template.ini b/res/temp/template.ini new file mode 100644 index 0000000..d86ae90 --- /dev/null +++ b/res/temp/template.ini @@ -0,0 +1,6 @@ +HTML Page = html +XHTML Page = xhtml +WML Page = wml +PHP Script = php +PHP XHTML Script = php-xhtml +PHP WML Script = php-wml \ No newline at end of file diff --git a/res/temp/wml.tpl b/res/temp/wml.tpl new file mode 100644 index 0000000..c5ad7ad --- /dev/null +++ b/res/temp/wml.tpl @@ -0,0 +1,13 @@ + + + + + + +

+ + + + + +

\ No newline at end of file diff --git a/res/temp/xhtml.tpl b/res/temp/xhtml.tpl new file mode 100644 index 0000000..82a911a --- /dev/null +++ b/res/temp/xhtml.tpl @@ -0,0 +1,21 @@ + + + + + + + + + + + + + +Title + + + + + + + \ No newline at end of file diff --git a/src/AccelImpl.java b/src/AccelImpl.java new file mode 100644 index 0000000..de50b6c --- /dev/null +++ b/src/AccelImpl.java @@ -0,0 +1,94 @@ + +import com.one.Accelerometer; + +//#if JSR256 == "true" + +import com.vmx.AuxClass; +import javax.microedition.sensor.*; +import javax.microedition.io.Connector; +import java.io.IOException; + +public class AccelImpl implements Accelerometer +{ + protected int[] channels = new int[3]; + protected String[] channelNames = new String[3]; + protected SensorConnection sensor; + + public AccelImpl() throws ClassNotFoundException, IOException + { + if(!AuxClass.classExists("javax.microedition.sensor.SensorConnection")) + { + throw new ClassNotFoundException(); + } + + SensorInfo[] info = SensorManager.findSensors("acceleration", null); + ChannelInfo[] ci = info[0].getChannelInfos(); + + for(int r = 0; r < ci.length; r++) + { + channelNames[r] = ci[r].getName(); + } + + sensor = (SensorConnection)Connector.open(info[0].getUrl()); + + if(sensor == null) + { + throw new ClassNotFoundException(); + } + } + + public int getValue(int channel) + { + getDelta(channel, 0); + return channels[channel]; + } + + public int getDelta(int channel, int threshold) + { + int delta = 0; + + try + { + Data[] data = sensor.getData(1, -1, false, false, false); + int drx = 0; + + for(int i = 0; i < data.length; i++) + { + if(data[i].getChannelInfo().getName().equals(channelNames[channel])) + { + drx = data[i].getIntValues()[0]; + } + } + + delta = channels[channel] - drx; + channels[channel] = drx; + + if(Math.abs(delta) < threshold) + { + delta = 0; + } + } + catch(Throwable t) + { + } + + return delta; + } +} + +//#else +//# +//# public class AccelImpl implements Accelerometer +//# { +//# public int getValue( int channel) +//# { +//# return 0; +//# } +//# +//# public int getDelta(int channel, int threshold) +//# { +//# return 0; +//# } +//# } +//# +//#endif \ No newline at end of file diff --git a/src/Browser.java b/src/Browser.java new file mode 100644 index 0000000..b4047a9 --- /dev/null +++ b/src/Browser.java @@ -0,0 +1,64 @@ +import com.one.Accelerometer; +import com.one.file.ConnectionProvider; +import com.one.file.GenericConnectionProvider; +import javax.microedition.midlet.MIDlet; +import javax.microedition.lcdui.Display; +import java.io.InputStream; +import javax.microedition.midlet.MIDletStateChangeException; + +public class Browser extends MIDlet implements com.one.RootLoader +{ + protected Browser ref; + protected filemanager.main app; + + public Browser() + { + ref = this; + app = new filemanager.main(this); + } + + public void startApp() throws MIDletStateChangeException + { + app.startApp(); + } + + public void pauseApp() + { + app.pauseApp(); + } + + public void destroyApp(boolean unc) throws MIDletStateChangeException + { + app.destroyApp(unc); + } + + public void restartApp() + { + app.restartApp(); + } + + public Display getDisplay() + { + return Display.getDisplay(this); + } + + public InputStream getResourceAsStream(String resource) + { + return ref.getClass().getResourceAsStream(resource); + } + + public Accelerometer getAccelerometer() + { + return null; + } + + public ConnectionProvider getConnectionProvider() + { + return new GenericConnectionProvider(); + } + + public boolean useNoEffects() + { + return true; + } +} diff --git a/src/ResetRMS.java b/src/ResetRMS.java new file mode 100644 index 0000000..81df9e7 --- /dev/null +++ b/src/ResetRMS.java @@ -0,0 +1,104 @@ + +import com.vmx.AuxClass; +import javax.microedition.lcdui.Choice; +import javax.microedition.lcdui.ChoiceGroup; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Display; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; +import javax.microedition.midlet.*; +import javax.microedition.rms.RecordStore; +import javax.microedition.rms.RecordStoreNotFoundException; + +public class ResetRMS extends MIDlet implements CommandListener +{ + protected Form form; + protected ChoiceGroup cgrms; + + protected static final Command cmdClear = new Command("Clear", Command.OK, 1); + protected static final Command cmdClearAll = new Command("Clear all", Command.OK, 2); + protected static final Command cmdExit = new Command("Exit", Command.EXIT, 3); + + public ResetRMS() + { + form = new Form("Reset RMS"); + + form.append("If you are encountering a problem running this application due to incorrectly done settings or wrong stored data, you might want to clear some or all of the RMS storages listed below. Clearing a storage will cause the program to re-write it with the appropriate data, as if it was the first time it was launched."); + + cgrms = new ChoiceGroup("RMS storages", Choice.MULTIPLE, AuxClass.STORE_NAMES, null); + form.append(cgrms); + + form.addCommand(cmdClear); + form.addCommand(cmdClearAll); + form.addCommand(cmdExit); + form.setCommandListener(this); + } + + public void startApp() + { + Display.getDisplay(this).setCurrent(form); + } + + public void pauseApp() + { + notifyPaused(); + } + + public void destroyApp(boolean unconditional) + { + notifyDestroyed(); + } + + public void commandAction(Command c, Displayable dp) + { + boolean flag = true; + + if(c == cmdClear) + { + for(int i = 0; i < AuxClass.STORE_NAMES.length; i++) + { + if(cgrms.isSelected(i)) + { + try + { + RecordStore.deleteRecordStore(AuxClass.getStoreName(i)); + } + catch(RecordStoreNotFoundException rsnfe) + { + } + catch(Exception e) + { + form.append(e.toString()); + flag = false; + } + } + } + } + else if(c == cmdClearAll) + { + String[] stores = RecordStore.listRecordStores(); + + for(int i = 0; i < stores.length; i++) + { + try + { + RecordStore.deleteRecordStore(stores[i]); + } + catch(RecordStoreNotFoundException rsnfe) + { + } + catch(Exception e) + { + form.append(e.toString()); + flag = false; + } + } + } + + if(flag) + { + destroyApp(false); + } + } +} diff --git a/src/Test.java b/src/Test.java new file mode 100644 index 0000000..d4f7e08 --- /dev/null +++ b/src/Test.java @@ -0,0 +1,34 @@ +import com.one.DisplayManager; +import com.one.PaintableObject; +import com.one.TestCanvas; +import javax.microedition.lcdui.Display; +import javax.microedition.midlet.*; + +public class Test extends MIDlet +{ + DisplayManager dsp; + TestCanvas tc; + + public Test() + { + dsp = new DisplayManager(Display.getDisplay(this)); + PaintableObject.setRenderer(dsp.getRenderer()); + + tc = new TestCanvas(); + } + + public void startApp() + { + dsp.setCurrent(tc); + } + + public void pauseApp() + { + notifyPaused(); + } + + public void destroyApp(boolean unconditional) + { + notifyDestroyed(); + } +} diff --git a/src/UniFM.java b/src/UniFM.java new file mode 100644 index 0000000..0f54605 --- /dev/null +++ b/src/UniFM.java @@ -0,0 +1,81 @@ +import com.one.Accelerometer; +import com.one.file.ConnectionProvider; +import com.one.file.GenericConnectionProvider; +import javax.microedition.midlet.MIDlet; +import javax.microedition.lcdui.Display; +import java.io.InputStream; +import javax.microedition.midlet.MIDletStateChangeException; +import mcp.MultiConnectionProvider; + +public class UniFM extends MIDlet implements com.one.RootLoader +{ + protected UniFM ref; + protected filemanager.main app; + + public UniFM() + { + ref = this; + app = new filemanager.main(this); + } + + public void startApp() throws MIDletStateChangeException + { + app.startApp(); + } + + public void pauseApp() + { + app.pauseApp(); + } + + public void destroyApp(boolean unc) throws MIDletStateChangeException + { + app.destroyApp(unc); + } + + public void restartApp() + { + app.restartApp(); + } + + public Display getDisplay() + { + return Display.getDisplay(this); + } + + public InputStream getResourceAsStream(String resource) + { + return ref.getClass().getResourceAsStream(resource); + } + + public Accelerometer getAccelerometer() + { + try + { + return new AccelImpl(); + } + catch(Throwable t) + { + t.printStackTrace(); + return null; + } + } + + public ConnectionProvider getConnectionProvider() + { + try + { + return new MultiConnectionProvider(); + } + catch(Throwable t) + { + t.printStackTrace(); + return new GenericConnectionProvider(); + } + } + + public boolean useNoEffects() + { + return false; + } +} diff --git a/src/com/classpath/io/PipedInputStream.java b/src/com/classpath/io/PipedInputStream.java new file mode 100644 index 0000000..51f0b74 --- /dev/null +++ b/src/com/classpath/io/PipedInputStream.java @@ -0,0 +1,456 @@ +/* PipedInputStream.java -- Read portion of piped streams. +Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package com.classpath.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; + +// NOTE: This implementation is very similar to that of PipedReader. If you +// fix a bug in here, chances are you should make a similar change to the +// PipedReader code. +/** + * An input stream that reads its bytes from an output stream + * to which it is connected. + *

+ * Data is read and written to an internal buffer. It is highly recommended + * that the PipedInputStream and connected + * PipedOutputStream + * be part of different threads. If they are not, the read and write + * operations could deadlock their thread. + * + * @specnote The JDK implementation appears to have some undocumented + * functionality where it keeps track of what thread is writing + * to pipe and throws an IOException if that thread susequently + * dies. This behaviour seems dubious and unreliable - we don't + * implement it. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class PipedInputStream extends InputStream +{ + /** PipedOutputStream to which this is connected. Null only if this + * InputStream hasn't been connected yet. */ + PipedOutputStream source; + /** Set to true if close() has been called on this InputStream. */ + boolean closed; + /** Exception passed by the source. */ + IOException exception; + /** + * The size of the internal buffer used for input/output. + */ + /* The "Constant Field Values" Javadoc of the Sun J2SE 1.4 + * specifies 1024. + */ + protected static final int PIPE_SIZE = 1024; + /** + * This is the internal circular buffer used for storing bytes written + * to the pipe and from which bytes are read by this stream + */ + protected byte[] buffer = null; + /** + * The index into buffer where the next byte from the connected + * PipedOutputStream will be written. If this variable is + * equal to out, then the buffer is full. If set to < 0, + * the buffer is empty. + */ + protected int in = -1; + /** + * This index into the buffer where bytes will be read from. + */ + protected int out = 0; + /** Buffer used to implement single-argument read/receive */ + private byte[] read_buf = new byte[1]; + + /** + * Creates a new PipedInputStream that is not connected to a + * PipedOutputStream. It must be connected before bytes can + * be read from this stream. + */ + public PipedInputStream() + { + this(PIPE_SIZE); + } + + /** + * Creates a new PipedInputStream of the given size that is not + * connected to a PipedOutputStream. + * It must be connected before bytes can be read from this stream. + * + * @since 1.6 + * @since IllegalArgumentException If pipeSize <= 0. + */ + public PipedInputStream(int pipeSize) throws IllegalArgumentException + { + if(pipeSize <= 0) + { + throw new IllegalArgumentException("pipeSize must be > 0"); + } + + this.buffer = new byte[pipeSize]; + } + + /** + * This constructor creates a new PipedInputStream and connects + * it to the passed in PipedOutputStream. The stream is then + * ready for reading. + * + * @param source The PipedOutputStream to connect this + * stream to + * + * @exception IOException If source is already connected. + */ + public PipedInputStream(PipedOutputStream source) throws IOException + { + this(); + connect(source); + } + + /** + * This constructor creates a new PipedInputStream of the given + * size and connects it to the passed in PipedOutputStream. + * The stream is then ready for reading. + * + * @param source The PipedOutputStream to connect this + * stream to + * + * @since 1.6 + * @exception IOException If source is already connected. + */ + public PipedInputStream(PipedOutputStream source, int pipeSize) + throws IOException + { + this(pipeSize); + connect(source); + } + + /** + * This method connects this stream to the passed in + * PipedOutputStream. + * This stream is then ready for reading. If this stream is already + * connected or has been previously closed, then an exception is thrown + * + * @param source The PipedOutputStream to connect this stream to + * + * @exception IOException If this PipedInputStream or source + * has been connected already. + */ + public void connect(PipedOutputStream source) throws IOException + { + // The JDK (1.3) does not appear to check for a previously closed + // connection here. + + if(this.source != null || source.sink != null) + { + throw new IOException("Already connected"); + } + + source.sink = this; + this.source = source; + } + + /** + * This method receives a byte of input from the source PipedOutputStream. + * If the internal circular buffer is full, this method blocks. + * + * @param val The byte to write to this stream + * + * @exception IOException if error occurs + * @specnote Weird. This method must be some sort of accident. + */ + synchronized void receive(int val) throws IOException + { + read_buf[0] = (byte) (val & 0xff); + receive(read_buf, 0, 1); + } + + /** + * This method is used by the connected PipedOutputStream to + * write bytes into the buffer. + * + * @param buf The array containing bytes to write to this stream + * @param offset The offset into the array to start writing from + * @param len The number of bytes to write. + * + * @exception IOException If an error occurs + * @specnote This code should be in PipedOutputStream.write, but we + * put it here in order to support that bizarre recieve(int) + * method. + */ + synchronized void receive(byte[] buf, int offset, int len) + throws IOException + { + if(closed) + { + throw new IOException("Pipe closed"); + } + + int bufpos = offset; + int copylen; + + while(len > 0) + { + try + { + while(in == out) + { + // The pipe is full. Wake up any readers and wait for them. + notifyAll(); + wait(); + // The pipe could have been closed while we were waiting. + if(closed) + { + throw new IOException("Pipe closed"); + } + } + } + catch(InterruptedException ix) + { + throw new InterruptedIOException(); + } + + if(in < 0) // The pipe is empty. + { + in = 0; + } + + // Figure out how many bytes from buf can be copied without + // overrunning out or going past the length of the buffer. + if(in < out) + { + copylen = Math.min(len, out - in); + } + else + { + copylen = Math.min(len, buffer.length - in); + } + + // Copy bytes until the pipe is filled, wrapping if necessary. + System.arraycopy(buf, bufpos, buffer, in, copylen); + len -= copylen; + bufpos += copylen; + in += copylen; + if(in == buffer.length) + { + in = 0; + } + } + // Notify readers that new data is in the pipe. + notifyAll(); + } + + /** + * This method reads one byte from the stream. + * -1 is returned to indicated that no bytes can be read + * because the end of the stream was reached. If the stream is already + * closed, a -1 will again be returned to indicate the end of the stream. + * + *

This method will block if no byte is available to be read.

+ * + * @return the value of the read byte value, or -1 of the end of the stream + * was reached + * + * @throws IOException if an error occured + */ + public int read() throws IOException + { + // Method operates by calling the multibyte overloaded read method + // Note that read_buf is an internal instance variable. I allocate it + // there to avoid constant reallocation overhead for applications that + // call this method in a loop at the cost of some unneeded overhead + // if this method is never called. + + int r = read(read_buf, 0, 1); + return r != -1 ? (read_buf[0] & 0xff) : -1; + } + + /** + * This method reads bytes from the stream into a caller supplied buffer. + * It starts storing bytes at position offset into the + * buffer and + * reads a maximum of len bytes. Note that this method + * can actually + * read fewer than len bytes. The actual number of bytes + * read is + * returned. A -1 is returned to indicated that no bytes can be read + * because the end of the stream was reached - ie close() was called on the + * connected PipedOutputStream. + *

+ * This method will block if no bytes are available to be read. + * + * @param buf The buffer into which bytes will be stored + * @param offset The index into the buffer at which to start writing. + * @param len The maximum number of bytes to read. + * + * @exception IOException If close() was called on this Piped + * InputStream. + */ + public synchronized int read(byte[] buf, int offset, int len) + throws IOException + { + if(source == null) + { + throw new IOException("Not connected"); + } + if(closed) + { + throw new IOException("Pipe closed"); + } + if(exception != null) + { + throw exception; + } + + // Don't block if nothing was requested. + if(len == 0) + { + return 0; + } + + // If the buffer is empty, wait until there is something in the pipe + // to read. + try + { + while(in < 0) + { + if(source.closed) + { + return -1; + } + wait(); + } + } + catch(InterruptedException ix) + { + throw new InterruptedIOException(); + } + + int total = 0; + int copylen; + + while(true) + { + // Figure out how many bytes from the pipe can be copied without + // overrunning in or going past the length of buf. + if(out < in) + { + copylen = Math.min(len, in - out); + } + else + { + copylen = Math.min(len, buffer.length - out); + } + + System.arraycopy(buffer, out, buf, offset, copylen); + offset += copylen; + len -= copylen; + out += copylen; + total += copylen; + + if(out == buffer.length) + { + out = 0; + } + + if(out == in) + { + // Pipe is now empty. + in = -1; + out = 0; + } + + // If output buffer is filled or the pipe is empty, we're done. + if(len == 0 || in == -1) + { + // Notify any waiting outputstream that there is now space + // to write. + notifyAll(); + return total; + } + } + } + + /** + * This method returns the number of bytes that can be read from this stream + * before blocking could occur. This is the number of bytes that are + * currently unread in the internal circular buffer. Note that once this + * many additional bytes are read, the stream may block on a subsequent + * read, but it not guaranteed to block. + * + * @return The number of bytes that can be read before blocking might occur + * + * @exception IOException If an error occurs + */ + public synchronized int available() throws IOException + { + // The JDK 1.3 implementation does not appear to check for the closed or + // unconnected stream conditions here. + + if(in < 0) + { + return 0; + } + else if(out < in) + { + return in - out; + } + else + { + return (buffer.length - out) + in; + } + } + + /** + * This methods closes the stream so that no more data can be read + * from it. + * + * @exception IOException If an error occurs + */ + public synchronized void close() throws IOException + { + closed = true; + // Wake any thread which may be in receive() waiting to write data. + notifyAll(); + } + + public boolean isPipeClosed() + { + return source.closed; + } +} + diff --git a/src/com/classpath/io/PipedOutputStream.java b/src/com/classpath/io/PipedOutputStream.java new file mode 100644 index 0000000..1747692 --- /dev/null +++ b/src/com/classpath/io/PipedOutputStream.java @@ -0,0 +1,212 @@ +/* PipedOutputStream.java -- Write portion of piped streams. +Copyright (C) 1998, 2000, 2001, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package com.classpath.io; + +import java.io.IOException; +import java.io.OutputStream; + +// NOTE: This implementation is very similar to that of PipedWriter. If you +// fix a bug in here, chances are you should make a similar change to the +// PipedWriter code. +/** + * This class writes its bytes to a PipedInputStream to + * which it is connected. + *

+ * It is highly recommended that a PipedOutputStream and its + * connected PipedInputStream be in different threads. If + * they are in the same thread, read and write operations could deadlock + * the thread. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class PipedOutputStream extends OutputStream +{ + /** Target PipedInputStream to which this is connected. Null only if this + * OutputStream hasn't been connected yet. */ + PipedInputStream sink; + /** Set to true if close() has been called on this OutputStream. */ + boolean closed; + + /** + * Create an unconnected PipedOutputStream. It must be connected + * to a PipedInputStream using the connect + * method prior to writing any data or an exception will be thrown. + */ + public PipedOutputStream() + { + } + + /** + * Create a new PipedOutputStream instance + * to write to the specified PipedInputStream. This stream + * is then ready for writing. + * + * @param sink The PipedInputStream to connect this stream to. + * + * @exception IOException If sink has already been connected + * to a different PipedOutputStream. + */ + public PipedOutputStream(PipedInputStream sink) throws IOException + { + sink.connect(this); + } + + /** + * Connects this object to the specified PipedInputStream + * object. This stream will then be ready for writing. + * + * @param sink The PipedInputStream to connect this stream to + * + * @exception IOException If the stream has not been connected or has + * been closed. + */ + public void connect(PipedInputStream sink) throws IOException + { + if(this.sink != null || sink.source != null) + { + throw new IOException("Already connected"); + } + sink.connect(this); + } + + /** + * Write a single byte of date to the stream. Note that this method will + * block if the PipedInputStream to which this object is + * connected has a full buffer. + * + * @param b The byte of data to be written, passed as an int. + * + * @exception IOException If the stream has not been connected or has + * been closed. + */ + public void write(int b) throws IOException + { + if(sink == null) + { + throw new IOException("Not connected"); + } + if(closed) + { + throw new IOException("Pipe closed"); + } + + sink.receive(b); + } + + /** + * This method writes len bytes of data from the byte array + * buf starting at index offset in the array + * to the stream. Note that this method will block if the + * PipedInputStream to which this object is connected has + * a buffer that cannot hold all of the bytes to be written. + * + * @param buffer The array containing bytes to write to the stream. + * @param offset The index into the array to start writing bytes from. + * @param len The number of bytes to write. + * + * @exception IOException If the stream has not been connected or has + * been closed. + */ + public void write(byte[] buffer, int offset, int len) throws IOException + { + if(sink == null) + { + throw new IOException("Not connected"); + } + if(closed) + { + throw new IOException("Pipe closed"); + } + + sink.receive(buffer, offset, len); + } + + /** + * This method does nothing. + * + * @exception IOException If the stream is closed. + * @specnote You'd think that this method would block until the sink + * had read all available data. Thats not the case - this method + * appears to be a no-op? + */ + public void flush() throws IOException + { + } + + /** + * This method closes this stream so that no more data can be written + * to it. Any further attempts to write to this stream may throw an + * exception + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + // A close call on an unconnected PipedOutputStream has no effect. + if(sink != null) + { + closed = true; + // Notify any waiting readers that the stream is now closed. + synchronized(sink) + { + sink.notifyAll(); + } + } + } + + /** + * Test if connected stream was closed. + * + * @return true, if connected stream is closed. + */ + public boolean isPipeClosed() + { + return sink.closed; + } + + /** + * Pass an IOException to the connected stream, + * so that it will be thrown on the next read() invocation. + * + * @param exception IOException instance + */ + public void passException(IOException exception) + { + sink.exception = exception; + } +} diff --git a/src/com/classpath/util/Arrays.java b/src/com/classpath/util/Arrays.java new file mode 100644 index 0000000..00f7811 --- /dev/null +++ b/src/com/classpath/util/Arrays.java @@ -0,0 +1,229 @@ +/* Arrays.java -- Utility class with methods to operate on arrays +Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, +Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package com.classpath.util; + +import java.util.Vector; + +/** + * This class contains various static utility methods performing operations on + * arrays, and a method to provide a List "view" of an array to facilitate + * using arrays with Collection-based APIs. All methods throw a + * {@link NullPointerException} if the parameter array is null. + *

+ * + * Implementations may use their own algorithms, but must obey the general + * properties; for example, the sort must be stable and n*log(n) complexity. + * Sun's implementation of sort, and therefore ours, is a tuned quicksort, + * adapted from Jon L. Bentley and M. Douglas McIlroy's "Engineering a Sort + * Function", Software-Practice and Experience, Vol. 23(11) P. 1249-1265 + * (November 1993). This algorithm offers n*log(n) performance on many data + * sets that cause other quicksorts to degrade to quadratic performance. + * + * @author Original author unknown + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Comparable + * @see Comparator + * @since 1.2 + * @status updated to 1.4 + */ +public class Arrays +{ + /** + * This class is non-instantiable. + */ + private Arrays() + { + } + + /** + * Compare two byte arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @return true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(byte[] a1, byte[] a2) + { + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if(a1 == a2) + { + return true; + } + + if(null == a1 || null == a2) + { + return false; + } + + // If they're the same length, test each element + if(a1.length == a2.length) + { + int i = a1.length; + while(--i >= 0) + { + if(a1[i] != a2[i]) + { + return false; + } + } + return true; + } + return false; + } + + /** + * Fill an array with an int value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(int[] a, int val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with an int value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(int[] a, int fromIndex, int toIndex, int val) + { + if(fromIndex > toIndex) + { + throw new IllegalArgumentException(); + } + for(int i = fromIndex; i < toIndex; i++) + { + a[i] = val; + } + } + + /** + * Fill an array with a byte value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(byte[] a, byte val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a byte value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(byte[] a, int fromIndex, int toIndex, byte val) + { + if(fromIndex > toIndex) + { + throw new IllegalArgumentException(); + } + for(int i = fromIndex; i < toIndex; i++) + { + a[i] = val; + } + } + + /** + * Fill an array with an Object value. + * + * @param a the array to fill + * @param val the value to fill it with + * @throws ClassCastException if val is not an instance of the element + * type of a. + */ + public static void fill(Object[] a, Object val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with an Object value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws ClassCastException if val is not an instance of the element + * type of a. + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(Object[] a, int fromIndex, int toIndex, Object val) + { + if(fromIndex > toIndex) + { + throw new IllegalArgumentException(); + } + for(int i = fromIndex; i < toIndex; i++) + { + a[i] = val; + } + } + + public static Vector asList(Object[] a) + { + Vector res = new Vector(a.length); + + for(int i = 0; i < a.length; i++) + { + res.addElement(a[i]); + } + + return res; + } +} diff --git a/src/com/classpath/util/ByteCache.java b/src/com/classpath/util/ByteCache.java new file mode 100644 index 0000000..aeb50ca --- /dev/null +++ b/src/com/classpath/util/ByteCache.java @@ -0,0 +1,29 @@ +package com.classpath.util; + +public final class ByteCache +{ + // This caches Byte values, and is used by boxing conversions via + // valueOf(). We're required to cache all possible values here. + private static Byte[] byteCache = new Byte[Byte.MAX_VALUE - Byte.MIN_VALUE + 1]; + + static + { + for(int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) + { + byteCache[i - Byte.MIN_VALUE] = new Byte((byte) i); + } + } + + /** + * Returns a Byte object wrapping the value. + * In contrast to the Byte constructor, this method + * will cache some values. It is used by boxing conversion. + * + * @param val the value to wrap + * @return the Byte + */ + public static Byte valueOf(byte val) + { + return byteCache[val - Byte.MIN_VALUE]; + } +} diff --git a/src/com/classpath/util/Characters.java b/src/com/classpath/util/Characters.java new file mode 100644 index 0000000..9dd2eed --- /dev/null +++ b/src/com/classpath/util/Characters.java @@ -0,0 +1,2995 @@ +/* java.lang.UnicodeCharacter -- Wrapper class for char, and Unicode subsets +Copyright (C) 1998, 1999, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package com.classpath.util; + +import com.vmx.AuxClass; +import java.io.DataInputStream; +import java.io.IOException; + +/** + * Wrapper class for the primitive char data type. In addition, this class + * allows one to retrieve property information and perform transformations + * on the defined characters in the Unicode Standard, Version 4.0.0. + * java.lang.UnicodeCharacter is designed to be very dynamic, and as such, it + * retrieves information on the Unicode character set from a separate + * database, gnu.java.lang.CharData, which can be easily upgraded. + * + *

For predicates, boundaries are used to describe + * the set of characters for which the method will return true. + * This syntax uses fairly normal regular expression notation. + * See 5.13 of the Unicode Standard, Version 4.0, for the + * boundary specification. + * + *

See http://www.unicode.org + * for more information on the Unicode Standard. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Paul N. Fisher + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see CharData + * @since 1.0 + * @status partly updated to 1.5; some things still missing + */ +public final class Characters +{ + /** + * A class to encompass all the properties of characters in the + * private use blocks in the Unicode standard. This class extends + * UnassignedCharacters because the return type from getType() is + * different. + * @author Anthony Balkissoon abalkiss at redhat dot com + * + */ + private static class PrivateUseCharacters extends UnassignedCharacters + { + /** + * Returns the type of the character cp. + */ + static int getType(int cp) + { + // The upper 2 code points in any plane are considered unassigned, + // even in the private-use planes. + if((cp & 0xffff) >= 0xfffe) + { + return UnassignedCharacters.getType(cp); + } + return PRIVATE_USE; + } + + /** + * Returns true if the character cp is defined. + */ + static boolean isDefined(int cp) + { + // The upper 2 code points in any plane are considered unassigned, + // even in the private-use planes. + if((cp & 0xffff) >= 0xfffe) + { + return UnassignedCharacters.isDefined(cp); + } + return true; + } + + /** + * Gets the directionality for the character cp. + */ + static byte getDirectionality(int cp) + { + if((cp & 0xffff) >= 0xfffe) + { + return UnassignedCharacters.getDirectionality(cp); + } + return DIRECTIONALITY_LEFT_TO_RIGHT; + } + } + + /** + * A class to encompass all the properties of code points that are + * currently undefined in the Unicode standard. + * @author Anthony Balkissoon abalkiss at redhat dot com + * + */ + private static class UnassignedCharacters + { + /** + * Returns the numeric value for the unassigned characters. + * @param cp the character + * @param radix the radix (not used) + * @return the numeric value of this character in this radix + */ + static int digit(int cp, int radix) + { + return -1; + } + + /** + * Returns the Unicode directionality property for unassigned + * characters. + * @param cp the character + * @return DIRECTIONALITY_UNDEFINED + */ + static byte getDirectionality(int cp) + { + return DIRECTIONALITY_UNDEFINED; + } + + /** + * Returns -1, the numeric value for unassigned Unicode characters. + * @param cp the character + * @return -1 + */ + static int getNumericValue(int cp) + { + return -1; + } + + /** + * Returns UNASSIGNED, the type of unassigned Unicode characters. + * @param cp the character + * @return UNASSIGNED + */ + static int getType(int cp) + { + return UNASSIGNED; + } + + /** + * Returns false to indiciate that the character is not defined in the + * Unicode standard. + * @param cp the character + * @return false + */ + static boolean isDefined(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not a digit. + * @param cp the character + * @return false + */ + static boolean isDigit(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot be ignored + * within an identifier + * @param cp the character + * @return false + */ + static boolean isIdentifierIgnorable(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot be part of a + * Java identifier. + * @param cp the character + * @return false + */ + static boolean isJavaIdentifierPart(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot be start a + * Java identifier. + * @param cp the character + * @return false + */ + static boolean isJavaIdentiferStart(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not a letter. + * @param cp the character + * @return false + */ + static boolean isLetter(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot is neither a letter + * nor a digit. + * @param cp the character + * @return false + */ + static boolean isLetterOrDigit(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not a lowercase letter. + * @param cp the character + * @return false + */ + static boolean isLowerCase(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot is not mirrored. + * @param cp the character + * @return false + */ + static boolean isMirrored(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not a space character. + * @param cp the character + * @return false + */ + static boolean isSpaceChar(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character it not a titlecase letter. + * @param cp the character + * @return false + */ + static boolean isTitleCase(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot be part of a + * Unicode identifier. + * @param cp the character + * @return false + */ + static boolean isUnicodeIdentifierPart(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot start a + * Unicode identifier. + * @param cp the character + * @return false + */ + static boolean isUnicodeIdentifierStart(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not an uppercase letter. + * @param cp the character + * @return false + */ + static boolean isUpperCase(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not a whitespace + * character. + * @param cp the character + * @return false + */ + static boolean isWhiteSpace(int cp) + { + return false; + } + + /** + * Returns cp to indicate this character has no lowercase conversion. + * @param cp the character + * @return cp + */ + static int toLowerCase(int cp) + { + return cp; + } + + /** + * Returns cp to indicate this character has no titlecase conversion. + * @param cp the character + * @return cp + */ + static int toTitleCase(int cp) + { + return cp; + } + + /** + * Returns cp to indicate this character has no uppercase conversion. + * @param cp the character + * @return cp + */ + static int toUpperCase(int cp) + { + return cp; + } + } + /** + * Smallest value allowed for radix arguments in Java. This value is 2. + * + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see Integer#toString(int, int) + * @see Integer#valueOf(String) + */ + public static final int MIN_RADIX = 2; + /** + * Largest value allowed for radix arguments in Java. This value is 36. + * + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see Integer#toString(int, int) + * @see Integer#valueOf(String) + */ + public static final int MAX_RADIX = 36; + /** + * The minimum value the char data type can hold. + * This value is '\\u0000'. + */ + public static final char MIN_VALUE = '\u0000'; + /** + * The maximum value the char data type can hold. + * This value is '\\uFFFF'. + */ + public static final char MAX_VALUE = '\uFFFF'; + /** + * The minimum Unicode 4.0 code point. This value is 0. + * @since 1.5 + */ + public static final int MIN_CODE_POINT = 0; + /** + * The maximum Unicode 4.0 code point, which is greater than the range + * of the char data type. + * This value is 0x10FFFF. + * @since 1.5 + */ + public static final int MAX_CODE_POINT = 0x10FFFF; + /** + * The minimum Unicode high surrogate code unit, or + * leading-surrogate, in the UTF-16 character encoding. + * This value is '\uD800'. + * @since 1.5 + */ + public static final char MIN_HIGH_SURROGATE = '\uD800'; + /** + * The maximum Unicode high surrogate code unit, or + * leading-surrogate, in the UTF-16 character encoding. + * This value is '\uDBFF'. + * @since 1.5 + */ + public static final char MAX_HIGH_SURROGATE = '\uDBFF'; + /** + * The minimum Unicode low surrogate code unit, or + * trailing-surrogate, in the UTF-16 character encoding. + * This value is '\uDC00'. + * @since 1.5 + */ + public static final char MIN_LOW_SURROGATE = '\uDC00'; + /** + * The maximum Unicode low surrogate code unit, or + * trailing-surrogate, in the UTF-16 character encoding. + * This value is '\uDFFF'. + * @since 1.5 + */ + public static final char MAX_LOW_SURROGATE = '\uDFFF'; + /** + * The minimum Unicode surrogate code unit in the UTF-16 character encoding. + * This value is '\uD800'. + * @since 1.5 + */ + public static final char MIN_SURROGATE = MIN_HIGH_SURROGATE; + /** + * The maximum Unicode surrogate code unit in the UTF-16 character encoding. + * This value is '\uDFFF'. + * @since 1.5 + */ + public static final char MAX_SURROGATE = MAX_LOW_SURROGATE; + /** + * The lowest possible supplementary Unicode code point (the first code + * point outside the basic multilingual plane (BMP)). + * This value is 0x10000. + */ + public static final int MIN_SUPPLEMENTARY_CODE_POINT = 0x10000; + /** + * The number of bits needed to represent a char. + * @since 1.5 + */ + public static final int SIZE = 16; + /** + * Lu = Letter, Uppercase (Informative). + * + * @since 1.1 + */ + public static final byte UPPERCASE_LETTER = 1; + /** + * Ll = Letter, Lowercase (Informative). + * + * @since 1.1 + */ + public static final byte LOWERCASE_LETTER = 2; + /** + * Lt = Letter, Titlecase (Informative). + * + * @since 1.1 + */ + public static final byte TITLECASE_LETTER = 3; + /** + * Mn = Mark, Non-Spacing (Normative). + * + * @since 1.1 + */ + public static final byte NON_SPACING_MARK = 6; + /** + * Mc = Mark, Spacing Combining (Normative). + * + * @since 1.1 + */ + public static final byte COMBINING_SPACING_MARK = 8; + /** + * Me = Mark, Enclosing (Normative). + * + * @since 1.1 + */ + public static final byte ENCLOSING_MARK = 7; + /** + * Nd = Number, Decimal Digit (Normative). + * + * @since 1.1 + */ + public static final byte DECIMAL_DIGIT_NUMBER = 9; + /** + * Nl = Number, Letter (Normative). + * + * @since 1.1 + */ + public static final byte LETTER_NUMBER = 10; + /** + * No = Number, Other (Normative). + * + * @since 1.1 + */ + public static final byte OTHER_NUMBER = 11; + /** + * Zs = Separator, Space (Normative). + * + * @since 1.1 + */ + public static final byte SPACE_SEPARATOR = 12; + /** + * Zl = Separator, Line (Normative). + * + * @since 1.1 + */ + public static final byte LINE_SEPARATOR = 13; + /** + * Zp = Separator, Paragraph (Normative). + * + * @since 1.1 + */ + public static final byte PARAGRAPH_SEPARATOR = 14; + /** + * Cc = Other, Control (Normative). + * + * @since 1.1 + */ + public static final byte CONTROL = 15; + /** + * Cf = Other, Format (Normative). + * + * @since 1.1 + */ + public static final byte FORMAT = 16; + /** + * Cs = Other, Surrogate (Normative). + * + * @since 1.1 + */ + public static final byte SURROGATE = 19; + /** + * Co = Other, Private Use (Normative). + * + * @since 1.1 + */ + public static final byte PRIVATE_USE = 18; + /** + * Cn = Other, Not Assigned (Normative). + * + * @since 1.1 + */ + public static final byte UNASSIGNED = 0; + /** + * Lm = Letter, Modifier (Informative). + * + * @since 1.1 + */ + public static final byte MODIFIER_LETTER = 4; + /** + * Lo = Letter, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_LETTER = 5; + /** + * Pc = Punctuation, Connector (Informative). + * + * @since 1.1 + */ + public static final byte CONNECTOR_PUNCTUATION = 23; + /** + * Pd = Punctuation, Dash (Informative). + * + * @since 1.1 + */ + public static final byte DASH_PUNCTUATION = 20; + /** + * Ps = Punctuation, Open (Informative). + * + * @since 1.1 + */ + public static final byte START_PUNCTUATION = 21; + /** + * Pe = Punctuation, Close (Informative). + * + * @since 1.1 + */ + public static final byte END_PUNCTUATION = 22; + /** + * Pi = Punctuation, Initial Quote (Informative). + * + * @since 1.4 + */ + public static final byte INITIAL_QUOTE_PUNCTUATION = 29; + /** + * Pf = Punctuation, Final Quote (Informative). + * + * @since 1.4 + */ + public static final byte FINAL_QUOTE_PUNCTUATION = 30; + /** + * Po = Punctuation, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_PUNCTUATION = 24; + /** + * Sm = Symbol, Math (Informative). + * + * @since 1.1 + */ + public static final byte MATH_SYMBOL = 25; + /** + * Sc = Symbol, Currency (Informative). + * + * @since 1.1 + */ + public static final byte CURRENCY_SYMBOL = 26; + /** + * Sk = Symbol, Modifier (Informative). + * + * @since 1.1 + */ + public static final byte MODIFIER_SYMBOL = 27; + /** + * So = Symbol, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_SYMBOL = 28; + /** + * Undefined bidirectional character type. Undefined char values have + * undefined directionality in the Unicode specification. + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_UNDEFINED = -1; + /** + * Strong bidirectional character type "L". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT = 0; + /** + * Strong bidirectional character type "R". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT = 1; + /** + * Strong bidirectional character type "AL". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = 2; + /** + * Weak bidirectional character type "EN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER = 3; + /** + * Weak bidirectional character type "ES". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = 4; + /** + * Weak bidirectional character type "ET". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = 5; + /** + * Weak bidirectional character type "AN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_ARABIC_NUMBER = 6; + /** + * Weak bidirectional character type "CS". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = 7; + /** + * Weak bidirectional character type "NSM". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_NONSPACING_MARK = 8; + /** + * Weak bidirectional character type "BN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 9; + /** + * Neutral bidirectional character type "B". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10; + /** + * Neutral bidirectional character type "S". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_SEGMENT_SEPARATOR = 11; + /** + * Strong bidirectional character type "WS". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_WHITESPACE = 12; + /** + * Neutral bidirectional character type "ON". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_OTHER_NEUTRALS = 13; + /** + * Strong bidirectional character type "LRE". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14; + /** + * Strong bidirectional character type "LRO". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15; + /** + * Strong bidirectional character type "RLE". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16; + /** + * Strong bidirectional character type "RLO". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17; + /** + * Weak bidirectional character type "PDF". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18; + /** + * The character shift amount to look up the block offset. In other words, + * (char) (BLOCKS.value[ch >> SHIFT[p]] + ch) is the index + * where ch is described in DATA if ch + * is in Unicode plane p. Note that p is simply + * the integer division of ch and 0x10000. + */ + private static int[] SHIFT; + /** + * Stores unicode block offset lookup table. Exploit package visibility of + * String.value to avoid copying the array. + * @see #readCodePoint(int) + * @see CharData#BLOCKS + */ + private static char[][] blocks; + /** + * Stores unicode attribute offset lookup table. Exploit package visibility + * of String.value to avoid copying the array. + * @see CharData#DATA + */ + private static char[][] data; + + static + { + try + { + DataInputStream dis = new DataInputStream(AuxClass.getResourceAsStream("/chars/chars.dat")); + + SHIFT = new int[dis.readInt()]; + + for(int i = 0; i < SHIFT.length; i++) + { + SHIFT[i] = dis.readInt(); + } + + blocks = new char[dis.readInt()][]; + + for(int i = 0; i < blocks.length; i++) + { + blocks[i] = readDeltaCodedString(dis); + } + + data = new char[dis.readInt()][]; + + for(int i = 0; i < data.length; i++) + { + data[i] = readDeltaCodedString(dis); + } + + dis.close(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + + public static char[] readDeltaCodedString(DataInputStream dis) throws IOException + { + char[] cs = new char[dis.readInt()]; + + if(cs.length > 0) + { + cs[0] = dis.readChar(); + + for(int i = 1; i < cs.length; i++) + { + cs[i] = (char)(cs[i - 1] + dis.readChar()); + } + } + + return cs; + } +// /** +// * Stores unicode numeric value attribute table. Exploit package visibility +// * of String.value to avoid copying the array. +// * @see CharData#NUM_VALUE +// */ +// private static final char[][] numValue = +// new char[][] +// { +// CharData.NUM_VALUE[0].toCharArray(), +// CharData.NUM_VALUE[1].toCharArray(), +// CharData.NUM_VALUE[2].toCharArray(), +// CharData.NUM_VALUE[3].toCharArray(), +// CharData.NUM_VALUE[4].toCharArray(), +// CharData.NUM_VALUE[5].toCharArray(), +// CharData.NUM_VALUE[6].toCharArray(), +// CharData.NUM_VALUE[7].toCharArray(), +// CharData.NUM_VALUE[8].toCharArray(), +// CharData.NUM_VALUE[9].toCharArray(), +// CharData.NUM_VALUE[10].toCharArray(), +// CharData.NUM_VALUE[11].toCharArray(), +// CharData.NUM_VALUE[12].toCharArray(), +// CharData.NUM_VALUE[13].toCharArray(), +// CharData.NUM_VALUE[14].toCharArray(), +// CharData.NUM_VALUE[15].toCharArray(), +// CharData.NUM_VALUE[16].toCharArray() +// }; +// /** +// * Stores unicode uppercase attribute table. Exploit package visibility +// * of String.value to avoid copying the array. +// * @see CharData#UPPER +// */ +// private static final char[][] upper = +// new char[][] +// { +// CharData.UPPER[0].toCharArray(), +// CharData.UPPER[1].toCharArray(), +// CharData.UPPER[2].toCharArray(), +// CharData.UPPER[3].toCharArray(), +// CharData.UPPER[4].toCharArray(), +// CharData.UPPER[5].toCharArray(), +// CharData.UPPER[6].toCharArray(), +// CharData.UPPER[7].toCharArray(), +// CharData.UPPER[8].toCharArray(), +// CharData.UPPER[9].toCharArray(), +// CharData.UPPER[10].toCharArray(), +// CharData.UPPER[11].toCharArray(), +// CharData.UPPER[12].toCharArray(), +// CharData.UPPER[13].toCharArray(), +// CharData.UPPER[14].toCharArray(), +// CharData.UPPER[15].toCharArray(), +// CharData.UPPER[16].toCharArray() +// }; +// /** +// * Stores unicode lowercase attribute table. Exploit package visibility +// * of String.value to avoid copying the array. +// * @see CharData#LOWER +// */ +// private static final char[][] lower = +// new char[][] +// { +// CharData.LOWER[0].toCharArray(), +// CharData.LOWER[1].toCharArray(), +// CharData.LOWER[2].toCharArray(), +// CharData.LOWER[3].toCharArray(), +// CharData.LOWER[4].toCharArray(), +// CharData.LOWER[5].toCharArray(), +// CharData.LOWER[6].toCharArray(), +// CharData.LOWER[7].toCharArray(), +// CharData.LOWER[8].toCharArray(), +// CharData.LOWER[9].toCharArray(), +// CharData.LOWER[10].toCharArray(), +// CharData.LOWER[11].toCharArray(), +// CharData.LOWER[12].toCharArray(), +// CharData.LOWER[13].toCharArray(), +// CharData.LOWER[14].toCharArray(), +// CharData.LOWER[15].toCharArray(), +// CharData.LOWER[16].toCharArray() +// }; +// /** +// * Stores unicode direction attribute table. Exploit package visibility +// * of String.value to avoid copying the array. +// * @see CharData#DIRECTION +// */ +// // Package visible for use by String. +// static final char[][] direction = +// new char[][] +// { +// CharData.DIRECTION[0].toCharArray(), +// CharData.DIRECTION[1].toCharArray(), +// CharData.DIRECTION[2].toCharArray(), +// CharData.DIRECTION[3].toCharArray(), +// CharData.DIRECTION[4].toCharArray(), +// CharData.DIRECTION[5].toCharArray(), +// CharData.DIRECTION[6].toCharArray(), +// CharData.DIRECTION[7].toCharArray(), +// CharData.DIRECTION[8].toCharArray(), +// CharData.DIRECTION[9].toCharArray(), +// CharData.DIRECTION[10].toCharArray(), +// CharData.DIRECTION[11].toCharArray(), +// CharData.DIRECTION[12].toCharArray(), +// CharData.DIRECTION[13].toCharArray(), +// CharData.DIRECTION[14].toCharArray(), +// CharData.DIRECTION[15].toCharArray(), +// CharData.DIRECTION[16].toCharArray() +// }; +// /** +// * Stores unicode titlecase table. Exploit package visibility of +// * String.value to avoid copying the array. +// * @see CharData#TITLE +// */ +// private static final char[] title = CharData.TITLE.toCharArray(); + /** + * Mask for grabbing the type out of the contents of data. + * @see CharData#DATA + */ + private static final int TYPE_MASK = 0x1F; + /** + * Mask for grabbing the non-breaking space flag out of the contents of + * data. + * @see CharData#DATA + */ + private static final int NO_BREAK_MASK = 0x20; + /** + * Mask for grabbing the mirrored directionality flag out of the contents + * of data. + * @see CharData#DATA + */ + private static final int MIRROR_MASK = 0x40; + + /** + * Grabs an attribute offset from the Unicode attribute database. The lower + * 5 bits are the character type, the next 2 bits are flags, and the top + * 9 bits are the offset into the attribute tables. + * + * @param codePoint the character to look up + * @return the character's attribute offset and type + * @see #TYPE_MASK + * @see #NO_BREAK_MASK + * @see #MIRROR_MASK + * @see CharData#DATA + * @see CharData#SHIFT + */ + // Package visible for use in String. + static char readCodePoint(int codePoint) + { + int plane = codePoint >>> 16; + + + char offset = (char) (codePoint & 0xffff); + + + return data[plane][(char) (blocks[plane][offset >> SHIFT[plane]] + offset)]; + + + } + + /** + * Determines if a character is a Unicode lowercase letter. For example, + * 'a' is lowercase. Returns true if getType() returns + * LOWERCASE_LETTER. + *
+ * lowercase = [Ll] + * + * @param ch character to test + * @return true if ch is a Unicode lowercase letter, else false + * @see #isUpperCase(char) + * @see #isTitleCase(char) + * @see #toLowerCase(char) + * @see #getType(char) + */ + public static boolean isLowerCase(char ch) + { + return isLowerCase((int) ch); + + + } + + /** + * Determines if a character is a Unicode lowercase letter. For example, + * 'a' is lowercase. Returns true if getType() returns + * LOWERCASE_LETTER. + *
+ * lowercase = [Ll] + * + * @param codePoint character to test + * @return true if ch is a Unicode lowercase letter, else false + * @see #isUpperCase(char) + * @see #isTitleCase(char) + * @see #toLowerCase(char) + * @see #getType(char) + * + * @since 1.5 + */ + public static boolean isLowerCase(int codePoint) + { + return getType(codePoint) == LOWERCASE_LETTER; + + + } + + /** + * Determines if a character is a Unicode uppercase letter. For example, + * 'A' is uppercase. Returns true if getType() returns + * UPPERCASE_LETTER. + *
+ * uppercase = [Lu] + * + * @param ch character to test + * @return true if ch is a Unicode uppercase letter, else false + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #toUpperCase(char) + * @see #getType(char) + */ + public static boolean isUpperCase(char ch) + { + return isUpperCase((int) ch); + + + } + + /** + * Determines if a character is a Unicode uppercase letter. For example, + * 'A' is uppercase. Returns true if getType() returns + * UPPERCASE_LETTER. + *
+ * uppercase = [Lu] + * + * @param codePoint character to test + * @return true if ch is a Unicode uppercase letter, else false + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #toUpperCase(char) + * @see #getType(char) + * + * @since 1.5 + */ + public static boolean isUpperCase(int codePoint) + { + return getType(codePoint) == UPPERCASE_LETTER; + + + } + + /** + * Determines if a character is a Unicode titlecase letter. For example, + * the character "Lj" (Latin capital L with small letter j) is titlecase. + * True if getType() returns TITLECASE_LETTER. + *
+ * titlecase = [Lt] + * + * @param ch character to test + * @return true if ch is a Unicode titlecase letter, else false + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toTitleCase(char) + * @see #getType(char) + */ + public static boolean isTitleCase(char ch) + { + return isTitleCase((int) ch); + + + } + + /** + * Determines if a character is a Unicode titlecase letter. For example, + * the character "Lj" (Latin capital L with small letter j) is titlecase. + * True if getType() returns TITLECASE_LETTER. + *
+ * titlecase = [Lt] + * + * @param codePoint character to test + * @return true if ch is a Unicode titlecase letter, else false + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toTitleCase(char) + * @see #getType(char) + * + * @since 1.5 + */ + public static boolean isTitleCase(int codePoint) + { + return getType(codePoint) == TITLECASE_LETTER; + + + } + + /** + * Determines if a character is a Unicode decimal digit. For example, + * '0' is a digit. A character is a Unicode digit if + * getType() returns DECIMAL_DIGIT_NUMBER. + *
+ * Unicode decimal digit = [Nd] + * + * @param ch character to test + * @return true if ch is a Unicode decimal digit, else false + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see #getType(char) + */ + public static boolean isDigit(char ch) + { + return isDigit((int) ch); + + + } + + /** + * Determines if a character is a Unicode decimal digit. For example, + * '0' is a digit. A character is a Unicode digit if + * getType() returns DECIMAL_DIGIT_NUMBER. + *
+ * Unicode decimal digit = [Nd] + * + * @param codePoint character to test + * @return true if ch is a Unicode decimal digit, else false + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see #getType(char) + * + * @since 1.5 + */ + public static boolean isDigit(int codePoint) + { + return getType(codePoint) == DECIMAL_DIGIT_NUMBER; + + + } + + /** + * Determines if a character is part of the Unicode Standard. This is an + * evolving standard, but covers every character in the data file. + *
+ * defined = not [Cn] + * + * @param ch character to test + * @return true if ch is a Unicode character, else false + * @see #isDigit(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUpperCase(char) + */ + public static boolean isDefined(char ch) + { + return isDefined((int) ch); + + + } + + /** + * Determines if a character is part of the Unicode Standard. This is an + * evolving standard, but covers every character in the data file. + *
+ * defined = not [Cn] + * + * @param codePoint character to test + * @return true if ch is a Unicode character, else false + * @see #isDigit(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUpperCase(char) + * + * @since 1.5 + */ + public static boolean isDefined(int codePoint) + { + return getType(codePoint) != UNASSIGNED; + + + } + + /** + * Determines if a character is a Unicode letter. Not all letters have case, + * so this may return true when isLowerCase and isUpperCase return false. + * A character is a Unicode letter if getType() returns one of + * UPPERCASE_LETTER, LOWERCASE_LETTER, TITLECASE_LETTER, MODIFIER_LETTER, + * or OTHER_LETTER. + *
+ * letter = [Lu]|[Ll]|[Lt]|[Lm]|[Lo] + * + * @param ch character to test + * @return true if ch is a Unicode letter, else false + * @see #isDigit(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUnicodeIdentifierStart(char) + * @see #isUpperCase(char) + */ + public static boolean isLetter(char ch) + { + return isLetter((int) ch); + + + } + + /** + * Determines if a character is a Unicode letter. Not all letters have case, + * so this may return true when isLowerCase and isUpperCase return false. + * A character is a Unicode letter if getType() returns one of + * UPPERCASE_LETTER, LOWERCASE_LETTER, TITLECASE_LETTER, MODIFIER_LETTER, + * or OTHER_LETTER. + *
+ * letter = [Lu]|[Ll]|[Lt]|[Lm]|[Lo] + * + * @param codePoint character to test + * @return true if ch is a Unicode letter, else false + * @see #isDigit(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUnicodeIdentifierStart(char) + * @see #isUpperCase(char) + * + * @since 1.5 + */ + public static boolean isLetter(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER))) != 0; + + + } + + /** + * Returns the index into the given char subarray that is offset + * codePointOffset code points from index. + * @param a the char array + * @param start the start index of the subarray + * @param count the length of the subarray + * @param index the index to be offset + * @param codePointOffset the number of code points offset from index + * + * @return the index into the char array + * + * @throws NullPointerException if a is null + * @throws IndexOutOfBoundsException if start or count is negative or if + * start + count is greater than the length of the array + * @throws IndexOutOfBoundsException if index is less than start or larger + * than start + count + * @throws IndexOutOfBoundsException if codePointOffset is positive and the + * subarray from index to start + count - 1 has fewer than codePointOffset + * code points. + * @throws IndexOutOfBoundsException if codePointOffset is negative and the + * subarray from start to index - 1 has fewer than (-codePointOffset) code + * points + * + * @since 1.5 + */ + public static int offsetByCodePoints(char[] a, + int start, + int count, + int index, + int codePointOffset) + { + int len = a.length; + + + int end = start + count; + + + if(start < 0 || count < 0 || end > len || index < start || index > end) + { + throw new IndexOutOfBoundsException(); + } + + + + int numToGo = codePointOffset; + + + int offset = index; + + + int adjust = 1; + + + if(numToGo >= 0) + { + for(; numToGo + > 0; offset++) + { + numToGo--; + + + if(isHighSurrogate(a[offset]) + && (offset + 1) < len + && isLowSurrogate(a[offset + 1])) + { + offset++; + } + + + } + return offset; + + + } + else + { + numToGo *= -1; + + + for(; numToGo + > 0;) + { + numToGo--; + offset--; + + if(isLowSurrogate(a[offset]) + && (offset - 1) >= 0 + && isHighSurrogate(a[offset - 1])) + { + offset--; + } + + + if(offset < start) + { + throw new IndexOutOfBoundsException(); + } + + + } + return offset; + + + } + + } + + /** + * Returns the number of Unicode code points in the specified range of the + * given char array. The first char in the range is at position + * offset and the length of the range is count. Paired surrogates + * (supplementary characters are represented by a pair of chars - + * one from the high surrogates and one from the low surrogates) + * count as just one code point. + * @param a the char array to inspect + * @param offset the beginning of the range + * @param count the length of the range + * @return the number of Unicode code points in the given range of the + * array + * @throws NullPointerException if a is null + * @throws IndexOutOfBoundsException if offset or count is negative or if + * offset + countendIndex is larger than the length of a. + * @since 1.5 + */ + public static int codePointCount(char[] a, int offset, + int count) + { + int len = a.length; + + + int end = offset + count; + + + if(offset < 0 || count < 0 || end > len) + { + throw new IndexOutOfBoundsException(); + } + + + + int counter = 0; + + + for(int i = offset; i + < end; i++) + { + counter++; + // If there is a pairing, count it only once. + + + if(isHighSurrogate(a[i]) && (i + 1) < end + && isLowSurrogate(a[i + 1])) + { + i++; + } + + + } + return counter; + + + } + + /** + * Determines if a character is a Unicode letter or a Unicode digit. This + * is the combination of isLetter and isDigit. + *
+ * letter or digit = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nd] + * + * @param ch character to test + * @return true if ch is a Unicode letter or a Unicode digit, else false + * @see #isDigit(char) + * @see #isJavaIdentifierPart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + */ + public static boolean isLetterOrDigit(char ch) + { + return isLetterOrDigit((int) ch); + + + } + + /** + * Determines if a character is a Unicode letter or a Unicode digit. This + * is the combination of isLetter and isDigit. + *
+ * letter or digit = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nd] + * + * @param codePoint character to test + * @return true if ch is a Unicode letter or a Unicode digit, else false + * @see #isDigit(char) + * @see #isJavaIdentifierPart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + * + * @since 1.5 + */ + public static boolean isLetterOrDigit(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER))) != 0; + + + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). + * + * @param ch character to test + * @return true if ch can start a Java identifier, else false + * @deprecated Replaced by {@link #isJavaIdentifierStart(char)} + * @see #isJavaLetterOrDigit(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierStart(char) + */ + public static boolean isJavaLetter(char ch) + { + return isJavaIdentifierStart(ch); + + + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. + * + * @param ch character to test + * @return true if ch can follow the first letter in a Java identifier + * @deprecated Replaced by {@link #isJavaIdentifierPart(char)} + * @see #isJavaLetter(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierPart(char) + * @see #isIdentifierIgnorable(char) + */ + public static boolean isJavaLetterOrDigit(char ch) + { + return isJavaIdentifierPart(ch); + + + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). + *
+ * Java identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc] + * + * @param ch character to test + * @return true if ch can start a Java identifier, else false + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.1 + */ + public static boolean isJavaIdentifierStart(char ch) + { + return isJavaIdentifierStart((int) ch); + + + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). + *
+ * Java identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc] + * + * @param codePoint character to test + * @return true if ch can start a Java identifier, else false + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.5 + */ + public static boolean isJavaIdentifierStart(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION))) != 0; + + + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. + *
+ * Java identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc]|[Mn]|[Mc]|[Nd]|[Cf] + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param ch character to test + * @return true if ch can follow the first letter in a Java identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierStart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isJavaIdentifierPart(char ch) + { + return isJavaIdentifierPart((int) ch); + + + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. + *
+ * Java identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc]|[Mn]|[Mc]|[Nd]|[Cf] + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param codePoint character to test + * @return true if ch can follow the first letter in a Java identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierStart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.5 + */ + public static boolean isJavaIdentifierPart(int codePoint) + { + int category = getType(codePoint); + + + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(codePoint)); + + + } + + /** + * Determines if a character can start a Unicode identifier. Only + * letters can start a Unicode identifier, but this includes characters + * in LETTER_NUMBER. + *
+ * Unicode identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl] + * + * @param ch character to test + * @return true if ch can start a Unicode identifier, else false + * @see #isJavaIdentifierStart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isUnicodeIdentifierStart(char ch) + { + return isUnicodeIdentifierStart((int) ch); + + + } + + /** + * Determines if a character can start a Unicode identifier. Only + * letters can start a Unicode identifier, but this includes characters + * in LETTER_NUMBER. + *
+ * Unicode identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl] + * + * @param codePoint character to test + * @return true if ch can start a Unicode identifier, else false + * @see #isJavaIdentifierStart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.5 + */ + public static boolean isUnicodeIdentifierStart(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER))) != 0; + + + } + + /** + * Determines if a character can follow the first letter in + * a Unicode identifier. This includes letters, connecting punctuation, + * digits, numeric letters, combining marks, non-spacing marks, and + * isIdentifierIgnorable. + *
+ * Unicode identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Mn]|[Mc]|[Nd]|[Pc]|[Cf]| + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param ch character to test + * @return true if ch can follow the first letter in a Unicode identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.1 + */ + public static boolean isUnicodeIdentifierPart(char ch) + { + return isUnicodeIdentifierPart((int) ch); + + + } + + /** + * Determines if a character can follow the first letter in + * a Unicode identifier. This includes letters, connecting punctuation, + * digits, numeric letters, combining marks, non-spacing marks, and + * isIdentifierIgnorable. + *
+ * Unicode identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Mn]|[Mc]|[Nd]|[Pc]|[Cf]| + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param codePoint character to test + * @return true if ch can follow the first letter in a Unicode identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.5 + */ + public static boolean isUnicodeIdentifierPart(int codePoint) + { + int category = getType(codePoint); + + + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(codePoint)); + + + } + + /** + * Determines if a character is ignorable in a Unicode identifier. This + * includes the non-whitespace ISO control characters ('\u0000' + * through '\u0008', '\u000E' through + * '\u001B', and '\u007F' through + * '\u009F'), and FORMAT characters. + *
+ * Unicode identifier ignorable = [Cf]|U+0000-U+0008|U+000E-U+001B + * |U+007F-U+009F + * + * @param ch character to test + * @return true if ch is ignorable in a Unicode or Java identifier + * @see #isJavaIdentifierPart(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isIdentifierIgnorable(char ch) + { + return isIdentifierIgnorable((int) ch); + + + } + + /** + * Determines if a character is ignorable in a Unicode identifier. This + * includes the non-whitespace ISO control characters ('\u0000' + * through '\u0008', '\u000E' through + * '\u001B', and '\u007F' through + * '\u009F'), and FORMAT characters. + *
+ * Unicode identifier ignorable = [Cf]|U+0000-U+0008|U+000E-U+001B + * |U+007F-U+009F + * + * @param codePoint character to test + * @return true if ch is ignorable in a Unicode or Java identifier + * @see #isJavaIdentifierPart(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.5 + */ + public static boolean isIdentifierIgnorable(int codePoint) + { + if((codePoint >= 0 && codePoint <= 0x0008) + || (codePoint >= 0x000E && codePoint <= 0x001B) + || (codePoint >= 0x007F && codePoint <= 0x009F) + || getType(codePoint) == FORMAT) + { + return true; + } + + + return false; + + + } + +// /** +// * Converts a Unicode character into its lowercase equivalent mapping. +// * If a mapping does not exist, then the character passed is returned. +// * Note that isLowerCase(toLowerCase(ch)) does not always return true. +// * +// * @param ch character to convert to lowercase +// * @return lowercase mapping of ch, or ch if lowercase mapping does +// * not exist +// * @see #isLowerCase(char) +// * @see #isUpperCase(char) +// * @see #toTitleCase(char) +// * @see #toUpperCase(char) +// */ +// public static char toLowerCase(char ch) +// { +// return (char) (lower[0][readCodePoint((int) ch) >>> 7] + ch); +// +// +// } +// /** +// * Converts a Unicode character into its lowercase equivalent mapping. +// * If a mapping does not exist, then the character passed is returned. +// * Note that isLowerCase(toLowerCase(ch)) does not always return true. +// * +// * @param codePoint character to convert to lowercase +// * @return lowercase mapping of ch, or ch if lowercase mapping does +// * not exist +// * @see #isLowerCase(char) +// * @see #isUpperCase(char) +// * @see #toTitleCase(char) +// * @see #toUpperCase(char) +// * +// * @since 1.5 +// */ +// public static int toLowerCase(int codePoint) +// { +// // If the code point is unassigned or in one of the private use areas +// // then we delegate the call to the appropriate private static inner class. +// int plane = codePoint >>> 16; +// +// +// if(plane > 2 && plane < 14) +// { +// return UnassignedCharacters.toLowerCase(codePoint); +// } +// +// +// if(plane > 14) +// { +// return PrivateUseCharacters.toLowerCase(codePoint); +// } +// +// // The short value stored in lower[plane] is the signed difference between +// // codePoint and its lowercase conversion. +// +// +// return ((short) lower[plane][readCodePoint(codePoint) >>> 7]) + codePoint; +// +// +// } +// /** +// * Converts a Unicode character into its uppercase equivalent mapping. +// * If a mapping does not exist, then the character passed is returned. +// * Note that isUpperCase(toUpperCase(ch)) does not always return true. +// * +// * @param ch character to convert to uppercase +// * @return uppercase mapping of ch, or ch if uppercase mapping does +// * not exist +// * @see #isLowerCase(char) +// * @see #isUpperCase(char) +// * @see #toLowerCase(char) +// * @see #toTitleCase(char) +// */ +// public static char toUpperCase(char ch) +// { +// return (char) (upper[0][readCodePoint((int) ch) >>> 7] + ch); +// +// +// } +// /** +// * Converts a Unicode character into its uppercase equivalent mapping. +// * If a mapping does not exist, then the character passed is returned. +// * Note that isUpperCase(toUpperCase(ch)) does not always return true. +// * +// * @param codePoint character to convert to uppercase +// * @return uppercase mapping of ch, or ch if uppercase mapping does +// * not exist +// * @see #isLowerCase(char) +// * @see #isUpperCase(char) +// * @see #toLowerCase(char) +// * @see #toTitleCase(char) +// * +// * @since 1.5 +// */ +// public static int toUpperCase(int codePoint) +// { +// // If the code point is unassigned or in one of the private use areas +// // then we delegate the call to the appropriate private static inner class. +// int plane = codePoint >>> 16; +// +// +// if(plane > 2 && plane < 14) +// { +// return UnassignedCharacters.toUpperCase(codePoint); +// } +// +// +// if(plane > 14) +// { +// return PrivateUseCharacters.toUpperCase(codePoint); +// } +// +// // The short value stored in upper[plane] is the signed difference between +// // codePoint and its uppercase conversion. +// +// +// return ((short) upper[plane][readCodePoint(codePoint) >>> 7]) + codePoint; +// +// +// } +// /** +// * Converts a Unicode character into its titlecase equivalent mapping. +// * If a mapping does not exist, then the character passed is returned. +// * Note that isTitleCase(toTitleCase(ch)) does not always return true. +// * +// * @param ch character to convert to titlecase +// * @return titlecase mapping of ch, or ch if titlecase mapping does +// * not exist +// * @see #isTitleCase(char) +// * @see #toLowerCase(char) +// * @see #toUpperCase(char) +// */ +// public static char toTitleCase(char ch) +// { +// // As title is short, it doesn't hurt to exhaustively iterate over it. +// for(int i = title.length - 2; i +// >= 0; i -= 2) +// { +// if(title[i] == ch) +// { +// return title[i + 1]; +// } +// } +// +// +// return toUpperCase(ch); +// +// +// } +// /** +// * Converts a Unicode character into its titlecase equivalent mapping. +// * If a mapping does not exist, then the character passed is returned. +// * Note that isTitleCase(toTitleCase(ch)) does not always return true. +// * +// * @param codePoint character to convert to titlecase +// * @return titlecase mapping of ch, or ch if titlecase mapping does +// * not exist +// * @see #isTitleCase(char) +// * @see #toLowerCase(char) +// * @see #toUpperCase(char) +// * +// * @since 1.5 +// */ +// public static int toTitleCase(int codePoint) +// { +// // As of Unicode 4.0.0 no characters outside of plane 0 have +// // titlecase mappings that are different from their uppercase +// // mapping. +// if(codePoint < 0x10000) +// { +// return (int) toTitleCase((char) codePoint); +// } +// +// +// return toUpperCase(codePoint); +// +// +// } +// /** +// * Converts a character into a digit of the specified radix. If the radix +// * exceeds MIN_RADIX or MAX_RADIX, or if the result of getNumericValue(ch) +// * exceeds the radix, or if ch is not a decimal digit or in the case +// * insensitive set of 'a'-'z', the result is -1. +// *
+// * character argument boundary = [Nd]|U+0041-U+005A|U+0061-U+007A +// * |U+FF21-U+FF3A|U+FF41-U+FF5A +// * +// * @param ch character to convert into a digit +// * @param radix radix in which ch is a digit +// * @return digit which ch represents in radix, or -1 not a valid digit +// * @see #MIN_RADIX +// * @see #MAX_RADIX +// * @see #forDigit(int, int) +// * @see #isDigit(char) +// * @see #getNumericValue(char) +// */ +// public static int digit(char ch, int radix) +// { +// if(radix < MIN_RADIX || radix > MAX_RADIX) +// { +// return -1; +// } +// +// +// char attr = readCodePoint((int) ch); +// +// +// if(((1 << (attr & TYPE_MASK)) +// & ((1 << UPPERCASE_LETTER) +// | (1 << LOWERCASE_LETTER) +// | (1 << DECIMAL_DIGIT_NUMBER))) != 0) +// { +// // Signedness doesn't matter; 0xffff vs. -1 are both rejected. +// int digit = numValue[0][attr >> 7]; +// +// +// return (digit < radix) ? digit : -1; +// +// +// } +// return -1; +// +// +// } +// /** +// * Converts a character into a digit of the specified radix. If the radix +// * exceeds MIN_RADIX or MAX_RADIX, or if the result of getNumericValue(ch) +// * exceeds the radix, or if ch is not a decimal digit or in the case +// * insensitive set of 'a'-'z', the result is -1. +// *
+// * character argument boundary = [Nd]|U+0041-U+005A|U+0061-U+007A +// * |U+FF21-U+FF3A|U+FF41-U+FF5A +// * +// * @param codePoint character to convert into a digit +// * @param radix radix in which ch is a digit +// * @return digit which ch represents in radix, or -1 not a valid digit +// * @see #MIN_RADIX +// * @see #MAX_RADIX +// * @see #forDigit(int, int) +// * @see #isDigit(char) +// * @see #getNumericValue(char) +// */ +// public static int digit(int codePoint, int radix) +// { +// if(radix < MIN_RADIX || radix > MAX_RADIX) +// { +// return -1; +// } +// +// // If the code point is unassigned or in one of the private use areas +// // then we delegate the call to the appropriate private static inner class. +// +// +// int plane = codePoint >>> 16; +// +// +// if(plane > 2 && plane < 14) +// { +// return UnassignedCharacters.digit(codePoint, radix); +// } +// +// +// if(plane > 14) +// { +// return PrivateUseCharacters.digit(codePoint, radix); +// } +// +// +// char attr = readCodePoint(codePoint); +// +// +// if(((1 << (attr & TYPE_MASK)) +// & ((1 << UPPERCASE_LETTER) +// | (1 << LOWERCASE_LETTER) +// | (1 << DECIMAL_DIGIT_NUMBER))) != 0) +// { +// // Signedness doesn't matter; 0xffff vs. -1 are both rejected. +// int digit = numValue[plane][attr >> 7]; +// +// // If digit is less than or equal to -3 then the numerical value was +// // too large to fit into numValue and is stored in CharData.LARGENUMS. +// +// +// if(digit <= -3) +// { +// digit = CharData.LARGENUMS[-digit - 3]; +// } +// +// +// return (digit < radix) ? digit : -1; +// +// +// } +// return -1; +// +// +// } +// /** +// * Returns the Unicode numeric value property of a character. For example, +// * '\\u216C' (the Roman numeral fifty) returns 50. +// * +// *

This method also returns values for the letters A through Z, (not +// * specified by Unicode), in these ranges: '\u0041' +// * through '\u005A' (uppercase); '\u0061' +// * through '\u007A' (lowercase); and '\uFF21' +// * through '\uFF3A', '\uFF41' through +// * '\uFF5A' (full width variants). +// * +// *

If the character lacks a numeric value property, -1 is returned. +// * If the character has a numeric value property which is not representable +// * as a nonnegative integer, such as a fraction, -2 is returned. +// * +// * character argument boundary = [Nd]|[Nl]|[No]|U+0041-U+005A|U+0061-U+007A +// * |U+FF21-U+FF3A|U+FF41-U+FF5A +// * +// * @param ch character from which the numeric value property will +// * be retrieved +// * @return the numeric value property of ch, or -1 if it does not exist, or +// * -2 if it is not representable as a nonnegative integer +// * @see #forDigit(int, int) +// * @see #digit(char, int) +// * @see #isDigit(char) +// * @since 1.1 +// */ +// public static int getNumericValue(char ch) +// { +// // Treat numValue as signed. +// return (short) numValue[0][readCodePoint((int) ch) >> 7]; +// +// +// } +// /** +// * Returns the Unicode numeric value property of a character. For example, +// * '\\u216C' (the Roman numeral fifty) returns 50. +// * +// *

This method also returns values for the letters A through Z, (not +// * specified by Unicode), in these ranges: '\u0041' +// * through '\u005A' (uppercase); '\u0061' +// * through '\u007A' (lowercase); and '\uFF21' +// * through '\uFF3A', '\uFF41' through +// * '\uFF5A' (full width variants). +// * +// *

If the character lacks a numeric value property, -1 is returned. +// * If the character has a numeric value property which is not representable +// * as a nonnegative integer, such as a fraction, -2 is returned. +// * +// * character argument boundary = [Nd]|[Nl]|[No]|U+0041-U+005A|U+0061-U+007A +// * |U+FF21-U+FF3A|U+FF41-U+FF5A +// * +// * @param codePoint character from which the numeric value property will +// * be retrieved +// * @return the numeric value property of ch, or -1 if it does not exist, or +// * -2 if it is not representable as a nonnegative integer +// * @see #forDigit(int, int) +// * @see #digit(char, int) +// * @see #isDigit(char) +// * @since 1.5 +// */ +// public static int getNumericValue(int codePoint) +// { +// // If the code point is unassigned or in one of the private use areas +// // then we delegate the call to the appropriate private static inner class. +// int plane = codePoint >>> 16; +// +// +// if(plane > 2 && plane < 14) +// { +// return UnassignedCharacters.getNumericValue(codePoint); +// } +// +// +// if(plane > 14) +// { +// return PrivateUseCharacters.getNumericValue(codePoint); +// } +// +// // If the value N found in numValue[plane] is less than or equal to -3 +// // then the numeric value was too big to fit into 16 bits and is +// // stored in CharData.LARGENUMS at offset (-N - 3). +// +// +// short num = (short) numValue[plane][readCodePoint(codePoint) >> 7]; +// +// +// if(num <= -3) +// { +// return CharData.LARGENUMS[-num - 3]; +// } +// +// +// return num; +// +// +// } + /** + * Determines if a character is a ISO-LATIN-1 space. This is only the five + * characters '\t', '\n', '\f', + * '\r', and ' '. + *
+ * Java space = U+0020|U+0009|U+000A|U+000C|U+000D + * + * @param ch character to test + * @return true if ch is a space, else false + * @deprecated Replaced by {@link #isWhitespace(char)} + * @see #isSpaceChar(char) + * @see #isWhitespace(char) + */ + public static boolean isSpace(char ch) + { + // Performing the subtraction up front alleviates need to compare longs. + return ch-- <= ' ' && ((1 << ch) + & ((1 << (' ' - 1)) + | (1 << ('\t' - 1)) + | (1 << ('\n' - 1)) + | (1 << ('\r' - 1)) + | (1 << ('\f' - 1)))) != 0; + + + } + + /** + * Determines if a character is a Unicode space character. This includes + * SPACE_SEPARATOR, LINE_SEPARATOR, and PARAGRAPH_SEPARATOR. + *
+ * Unicode space = [Zs]|[Zp]|[Zl] + * + * @param ch character to test + * @return true if ch is a Unicode space, else false + * @see #isWhitespace(char) + * @since 1.1 + */ + public static boolean isSpaceChar(char ch) + { + return isSpaceChar((int) ch); + + + } + + /** + * Determines if a character is a Unicode space character. This includes + * SPACE_SEPARATOR, LINE_SEPARATOR, and PARAGRAPH_SEPARATOR. + *
+ * Unicode space = [Zs]|[Zp]|[Zl] + * + * @param codePoint character to test + * @return true if ch is a Unicode space, else false + * @see #isWhitespace(char) + * @since 1.5 + */ + public static boolean isSpaceChar(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0; + + + } + + /** + * Determines if a character is Java whitespace. This includes Unicode + * space characters (SPACE_SEPARATOR, LINE_SEPARATOR, and + * PARAGRAPH_SEPARATOR) except the non-breaking spaces + * ('\u00A0', '\u2007', and '\u202F'); + * and these characters: '\u0009', '\u000A', + * '\u000B', '\u000C', '\u000D', + * '\u001C', '\u001D', '\u001E', + * and '\u001F'. + *
+ * Java whitespace = ([Zs] not Nb)|[Zl]|[Zp]|U+0009-U+000D|U+001C-U+001F + * + * @param ch character to test + * @return true if ch is Java whitespace, else false + * @see #isSpaceChar(char) + * @since 1.1 + */ + public static boolean isWhitespace(char ch) + { + return isWhitespace((int) ch); + + + } + + /** + * Determines if a character is Java whitespace. This includes Unicode + * space characters (SPACE_SEPARATOR, LINE_SEPARATOR, and + * PARAGRAPH_SEPARATOR) except the non-breaking spaces + * ('\u00A0', '\u2007', and '\u202F'); + * and these characters: '\u0009', '\u000A', + * '\u000B', '\u000C', '\u000D', + * '\u001C', '\u001D', '\u001E', + * and '\u001F'. + *
+ * Java whitespace = ([Zs] not Nb)|[Zl]|[Zp]|U+0009-U+000D|U+001C-U+001F + * + * @param codePoint character to test + * @return true if ch is Java whitespace, else false + * @see #isSpaceChar(char) + * @since 1.5 + */ + public static boolean isWhitespace(int codePoint) + { + int plane = codePoint >>> 16; + + + if(plane > 2 && plane < 14) + { + return UnassignedCharacters.isWhiteSpace(codePoint); + } + + + if(plane > 14) + { + return PrivateUseCharacters.isWhiteSpace(codePoint); + } + + + + int attr = readCodePoint(codePoint); + + + return ((((1 << (attr & TYPE_MASK)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0) + && (attr & NO_BREAK_MASK) == 0) + || (codePoint <= '\u001F' && ((1 << codePoint) + & ((1 << '\t') + | (1 << '\n') + | (1 << '\u000B') + | (1 << '\u000C') + | (1 << '\r') + | (1 << '\u001C') + | (1 << '\u001D') + | (1 << '\u001E') + | (1 << '\u001F'))) != 0); + + + } + + /** + * Determines if a character has the ISO Control property. + *
+ * ISO Control = [Cc] + * + * @param ch character to test + * @return true if ch is an ISO Control character, else false + * @see #isSpaceChar(char) + * @see #isWhitespace(char) + * @since 1.1 + */ + public static boolean isISOControl(char ch) + { + return isISOControl((int) ch); + + + } + + /** + * Determines if the character is an ISO Control character. This is true + * if the code point is in the range [0, 0x001F] or if it is in the range + * [0x007F, 0x009F]. + * @param codePoint the character to check + * @return true if the character is in one of the above ranges + * + * @since 1.5 + */ + public static boolean isISOControl(int codePoint) + { + if((codePoint >= 0 && codePoint <= 0x001F) + || (codePoint >= 0x007F && codePoint <= 0x009F)) + { + return true; + } + + + return false; + + + } + + /** + * Returns the Unicode general category property of a character. + * + * @param ch character from which the general category property will + * be retrieved + * @return the character category property of ch as an integer + * @see #UNASSIGNED + * @see #UPPERCASE_LETTER + * @see #LOWERCASE_LETTER + * @see #TITLECASE_LETTER + * @see #MODIFIER_LETTER + * @see #OTHER_LETTER + * @see #NON_SPACING_MARK + * @see #ENCLOSING_MARK + * @see #COMBINING_SPACING_MARK + * @see #DECIMAL_DIGIT_NUMBER + * @see #LETTER_NUMBER + * @see #OTHER_NUMBER + * @see #SPACE_SEPARATOR + * @see #LINE_SEPARATOR + * @see #PARAGRAPH_SEPARATOR + * @see #CONTROL + * @see #FORMAT + * @see #PRIVATE_USE + * @see #SURROGATE + * @see #DASH_PUNCTUATION + * @see #START_PUNCTUATION + * @see #END_PUNCTUATION + * @see #CONNECTOR_PUNCTUATION + * @see #OTHER_PUNCTUATION + * @see #MATH_SYMBOL + * @see #CURRENCY_SYMBOL + * @see #MODIFIER_SYMBOL + * @see #INITIAL_QUOTE_PUNCTUATION + * @see #FINAL_QUOTE_PUNCTUATION + * @since 1.1 + */ + public static int getType(char ch) + { + return getType((int) ch); + + + } + + /** + * Returns the Unicode general category property of a character. + * + * @param codePoint character from which the general category property will + * be retrieved + * @return the character category property of ch as an integer + * @see #UNASSIGNED + * @see #UPPERCASE_LETTER + * @see #LOWERCASE_LETTER + * @see #TITLECASE_LETTER + * @see #MODIFIER_LETTER + * @see #OTHER_LETTER + * @see #NON_SPACING_MARK + * @see #ENCLOSING_MARK + * @see #COMBINING_SPACING_MARK + * @see #DECIMAL_DIGIT_NUMBER + * @see #LETTER_NUMBER + * @see #OTHER_NUMBER + * @see #SPACE_SEPARATOR + * @see #LINE_SEPARATOR + * @see #PARAGRAPH_SEPARATOR + * @see #CONTROL + * @see #FORMAT + * @see #PRIVATE_USE + * @see #SURROGATE + * @see #DASH_PUNCTUATION + * @see #START_PUNCTUATION + * @see #END_PUNCTUATION + * @see #CONNECTOR_PUNCTUATION + * @see #OTHER_PUNCTUATION + * @see #MATH_SYMBOL + * @see #CURRENCY_SYMBOL + * @see #MODIFIER_SYMBOL + * @see #INITIAL_QUOTE_PUNCTUATION + * @see #FINAL_QUOTE_PUNCTUATION + * + * @since 1.5 + */ + public static int getType(int codePoint) + { + // If the codePoint is unassigned or in one of the private use areas + // then we delegate the call to the appropriate private static inner class. + int plane = codePoint >>> 16; + + + if(plane > 2 && plane < 14) + { + return UnassignedCharacters.getType(codePoint); + } + + + if(plane > 14) + { + return PrivateUseCharacters.getType(codePoint); + } + + + + return readCodePoint(codePoint) & TYPE_MASK; + + + } + +// /** +// * Returns the Unicode directionality property of the character. This +// * is used in the visual ordering of text. +// * +// * @param ch the character to look up +// * @return the directionality constant, or DIRECTIONALITY_UNDEFINED +// * @see #DIRECTIONALITY_UNDEFINED +// * @see #DIRECTIONALITY_LEFT_TO_RIGHT +// * @see #DIRECTIONALITY_RIGHT_TO_LEFT +// * @see #DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC +// * @see #DIRECTIONALITY_EUROPEAN_NUMBER +// * @see #DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR +// * @see #DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR +// * @see #DIRECTIONALITY_ARABIC_NUMBER +// * @see #DIRECTIONALITY_COMMON_NUMBER_SEPARATOR +// * @see #DIRECTIONALITY_NONSPACING_MARK +// * @see #DIRECTIONALITY_BOUNDARY_NEUTRAL +// * @see #DIRECTIONALITY_PARAGRAPH_SEPARATOR +// * @see #DIRECTIONALITY_SEGMENT_SEPARATOR +// * @see #DIRECTIONALITY_WHITESPACE +// * @see #DIRECTIONALITY_OTHER_NEUTRALS +// * @see #DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING +// * @see #DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE +// * @see #DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING +// * @see #DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE +// * @see #DIRECTIONALITY_POP_DIRECTIONAL_FORMAT +// * @since 1.4 +// */ +// public static byte getDirectionality(char ch) +// { +// // The result will correctly be signed. +// return getDirectionality((int) ch); +// +// +// } +// /** +// * Returns the Unicode directionality property of the character. This +// * is used in the visual ordering of text. +// * +// * @param codePoint the character to look up +// * @return the directionality constant, or DIRECTIONALITY_UNDEFINED +// * @see #DIRECTIONALITY_UNDEFINED +// * @see #DIRECTIONALITY_LEFT_TO_RIGHT +// * @see #DIRECTIONALITY_RIGHT_TO_LEFT +// * @see #DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC +// * @see #DIRECTIONALITY_EUROPEAN_NUMBER +// * @see #DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR +// * @see #DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR +// * @see #DIRECTIONALITY_ARABIC_NUMBER +// * @see #DIRECTIONALITY_COMMON_NUMBER_SEPARATOR +// * @see #DIRECTIONALITY_NONSPACING_MARK +// * @see #DIRECTIONALITY_BOUNDARY_NEUTRAL +// * @see #DIRECTIONALITY_PARAGRAPH_SEPARATOR +// * @see #DIRECTIONALITY_SEGMENT_SEPARATOR +// * @see #DIRECTIONALITY_WHITESPACE +// * @see #DIRECTIONALITY_OTHER_NEUTRALS +// * @see #DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING +// * @see #DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE +// * @see #DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING +// * @see #DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE +// * @see #DIRECTIONALITY_POP_DIRECTIONAL_FORMAT +// * @since 1.5 +// */ +// public static byte getDirectionality(int codePoint) +// { +// // If the code point is unassigned or in one of the private use areas +// // then we delegate the call to the appropriate private static inner class. +// int plane = codePoint >>> 16; +// +// +// if(plane > 2 && plane < 14) +// { +// return UnassignedCharacters.getDirectionality(codePoint); +// } +// +// +// if(plane > 14) +// { +// return PrivateUseCharacters.getDirectionality(codePoint); +// } +// +// // The result will correctly be signed. +// +// +// return (byte) (direction[plane][readCodePoint(codePoint) >> 7] >> 2); +// +// +// } + /** + * Determines whether the character is mirrored according to Unicode. For + * example, \u0028 (LEFT PARENTHESIS) appears as '(' in + * left-to-right text, but ')' in right-to-left text. + * + * @param ch the character to look up + * @return true if the character is mirrored + * @since 1.4 + */ + public static boolean isMirrored(char ch) + { + return (readCodePoint((int) ch) & MIRROR_MASK) != 0; + + + } + + /** + * Determines whether the character is mirrored according to Unicode. For + * example, \u0028 (LEFT PARENTHESIS) appears as '(' in + * left-to-right text, but ')' in right-to-left text. + * + * @param codePoint the character to look up + * @return true if the character is mirrored + * @since 1.5 + */ + public static boolean isMirrored(int codePoint) + { + // If the code point is unassigned or part of one of the private use areas + // then we delegate the call to the appropriate private static inner class. + int plane = codePoint >>> 16; + + + if(plane > 2 && plane < 14) + { + return UnassignedCharacters.isMirrored(codePoint); + } + + + if(plane > 14) + { + return PrivateUseCharacters.isMirrored(codePoint); + } + + + + return (readCodePoint(codePoint) & MIRROR_MASK) != 0; + + + } + + /** + * Reverse the bytes in val. + * @since 1.5 + */ + public static char reverseBytes(char val) + { + return (char) (((val >> 8) & 0xff) | ((val << 8) & 0xff00)); + + + } + + /** + * Converts a unicode code point to a UTF-16 representation of that + * code point. + * + * @param codePoint the unicode code point + * + * @return the UTF-16 representation of that code point + * + * @throws IllegalArgumentException if the code point is not a valid + * unicode code point + * + * @since 1.5 + */ + public static char[] toChars(int codePoint) + { + if(!isValidCodePoint(codePoint)) + { + throw new IllegalArgumentException("Illegal Unicode code point : " + + codePoint); + } + + + char[] result = new char[charCount(codePoint)]; + + + int ignore = toChars(codePoint, result, 0); + + + return result; + + + } + + /** + * Converts a unicode code point to its UTF-16 representation. + * + * @param codePoint the unicode code point + * @param dst the target char array + * @param dstIndex the start index for the target + * + * @return number of characters written to dst + * + * @throws IllegalArgumentException if codePoint is not a + * valid unicode code point + * @throws NullPointerException if dst is null + * @throws IndexOutOfBoundsException if dstIndex is not valid + * in dst or if the UTF-16 representation does not + * fit into dst + * + * @since 1.5 + */ + public static int toChars(int codePoint, char[] dst, int dstIndex) + { + if(!isValidCodePoint(codePoint)) + { + throw new IllegalArgumentException("not a valid code point: " + + codePoint); + + + } + + int result; + + + if(isSupplementaryCodePoint(codePoint)) + { + // Write second char first to cause IndexOutOfBoundsException + // immediately. + final int cp2 = codePoint - 0x10000; + dst[dstIndex + 1] = (char) ((cp2 % 0x400) + (int) MIN_LOW_SURROGATE); + dst[dstIndex] = (char) ((cp2 / 0x400) + (int) MIN_HIGH_SURROGATE); + result = 2; + + + } + else + { + dst[dstIndex] = (char) codePoint; + result = 1; + + + } + return result; + + + } + + /** + * Return number of 16-bit characters required to represent the given + * code point. + * + * @param codePoint a unicode code point + * + * @return 2 if codePoint >= 0x10000, 1 otherwise. + * + * @since 1.5 + */ + public static int charCount(int codePoint) + { + return (codePoint >= MIN_SUPPLEMENTARY_CODE_POINT) + ? 2 + : 1; + + + } + + /** + * Determines whether the specified code point is + * in the range 0x10000 .. 0x10FFFF, i.e. the character is within the Unicode + * supplementary character range. + * + * @param codePoint a Unicode code point + * + * @return true if code point is in supplementary range + * + * @since 1.5 + */ + public static boolean isSupplementaryCodePoint(int codePoint) + { + return codePoint >= MIN_SUPPLEMENTARY_CODE_POINT + && codePoint <= MAX_CODE_POINT; + + + } + + /** + * Determines whether the specified code point is + * in the range 0x0000 .. 0x10FFFF, i.e. it is a valid Unicode code point. + * + * @param codePoint a Unicode code point + * + * @return true if code point is valid + * + * @since 1.5 + */ + public static boolean isValidCodePoint(int codePoint) + { + return codePoint >= MIN_CODE_POINT && codePoint <= MAX_CODE_POINT; + + + } + + /** + * Return true if the given character is a high surrogate. + * @param ch the character + * @return true if the character is a high surrogate character + * + * @since 1.5 + */ + public static boolean isHighSurrogate(char ch) + { + return ch >= MIN_HIGH_SURROGATE && ch <= MAX_HIGH_SURROGATE; + + + } + + /** + * Return true if the given character is a low surrogate. + * @param ch the character + * @return true if the character is a low surrogate character + * + * @since 1.5 + */ + public static boolean isLowSurrogate(char ch) + { + return ch >= MIN_LOW_SURROGATE && ch <= MAX_LOW_SURROGATE; + + + } + + /** + * Return true if the given characters compose a surrogate pair. + * This is true if the first character is a high surrogate and the + * second character is a low surrogate. + * @param ch1 the first character + * @param ch2 the first character + * @return true if the characters compose a surrogate pair + * + * @since 1.5 + */ + public static boolean isSurrogatePair(char ch1, char ch2) + { + return isHighSurrogate(ch1) && isLowSurrogate(ch2); + + + } + + /** + * Given a valid surrogate pair, this returns the corresponding + * code point. + * @param high the high character of the pair + * @param low the low character of the pair + * @return the corresponding code point + * + * @since 1.5 + */ + public static int toCodePoint(char high, char low) + { + return ((high - MIN_HIGH_SURROGATE) * 0x400) + + (low - MIN_LOW_SURROGATE) + 0x10000; + + + } + + /** + * Get the code point at the specified index in the CharSequence. + * If the character is the start of a surrogate pair, and there is a + * following character, and this character completes the pair, then + * the corresponding supplementary code point is returned. + * Otherwise, the character at the index is returned. + * + * @param chars the character array in which to look + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public static int codePointAt(char[] chars, int index) + { + return codePointAt(chars, index, chars.length); + + + } + + /** + * Get the code point at the specified index in the CharSequence. + * If the character is the start of a surrogate pair, and there is a + * following character within the specified range, and this + * character completes the pair, then the corresponding + * supplementary code point is returned. Otherwise, the character + * at the index is returned. + * + * @param chars the character array in which to look + * @param index the index of the codepoint to get, starting at 0 + * @param limit the limit past which characters should not be examined + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= + * limit, or if limit is negative or >= the length of the array + * @since 1.5 + */ + public static int codePointAt(char[] chars, int index, int limit) + { + if(index < 0 || index >= limit || limit < 0 || limit > chars.length) + { + throw new IndexOutOfBoundsException(); + } + + + char high = chars[index]; + + + if(!isHighSurrogate(high) || ++index >= limit) + { + return high; + } + + + char low = chars[index]; + + + if(!isLowSurrogate(low)) + { + return high; + } + + + return toCodePoint(high, low); + + + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(char[], int), but checks the characters at + * index-1 and index-2 to see if they form + * a supplementary code point. If they do not, the character at + * index-1 is returned. + * + * @param chars the character array + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public static int codePointBefore(char[] chars, int index) + { + return codePointBefore(chars, index, 1); + + + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(char[], int), but checks the characters at + * index-1 and index-2 to see if they form + * a supplementary code point. If they do not, the character at + * index-1 is returned. The start parameter is used to + * limit the range of the array which may be examined. + * + * @param chars the character array + * @param index the index just past the codepoint to get, starting at 0 + * @param start the index before which characters should not be examined + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is > start or > + * the length of the array, or if limit is negative or >= the + * length of the array + * @since 1.5 + */ + public static int codePointBefore(char[] chars, int index, int start) + { + if(index < start || index > chars.length + || start < 0 || start >= chars.length) + { + throw new IndexOutOfBoundsException(); + } + + + --index; + + + char low = chars[index]; + + + if(!isLowSurrogate(low) || --index < start) + { + return low; + } + + + char high = chars[index]; + + + if(!isHighSurrogate(high)) + { + return low; + } + + + return toCodePoint(high, low); + + + } +} // class UnicodeCharacter + diff --git a/src/com/classpath/zip/Adler32.java b/src/com/classpath/zip/Adler32.java new file mode 100644 index 0000000..6b8bd2b --- /dev/null +++ b/src/com/classpath/zip/Adler32.java @@ -0,0 +1,206 @@ +/* Adler32.java - Computes Adler32 data checksum of a data stream + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +/* + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). + * The actual Adler32 algorithm is taken from RFC 1950. + * Status: Believed complete and correct. + */ + +/** + * Computes Adler32 checksum for a stream of data. An Adler32 + * checksum is not as reliable as a CRC32 checksum, but a lot faster to + * compute. + *

+ * The specification for Adler32 may be found in RFC 1950. + * (ZLIB Compressed Data Format Specification version 3.3) + *

+ *

+ * From that document: + *

+ * "ADLER32 (Adler-32 checksum) + * This contains a checksum value of the uncompressed data + * (excluding any dictionary data) computed according to Adler-32 + * algorithm. This algorithm is a 32-bit extension and improvement + * of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073 + * standard. + *

+ * Adler-32 is composed of two sums accumulated per byte: s1 is + * the sum of all bytes, s2 is the sum of all s1 values. Both sums + * are done modulo 65521. s1 is initialized to 1, s2 to zero. The + * Adler-32 checksum is stored as s2*65536 + s1 in most- + * significant-byte first (network) order." + *

+ * "8.2. The Adler-32 algorithm + *

+ * The Adler-32 algorithm is much faster than the CRC32 algorithm yet + * still provides an extremely low probability of undetected errors. + *

+ * The modulo on unsigned long accumulators can be delayed for 5552 + * bytes, so the modulo operation time is negligible. If the bytes + * are a, b, c, the second sum is 3a + 2b + c + 3, and so is position + * and order sensitive, unlike the first sum, which is just a + * checksum. That 65521 is prime is important to avoid a possible + * large class of two-byte errors that leave the check unchanged. + * (The Fletcher checksum uses 255, which is not prime and which also + * makes the Fletcher check insensitive to single byte changes 0 <-> + * 255.) + *

+ * The sum s1 is initialized to 1 instead of zero to make the length + * of the sequence part of s2, so that the length does not have to be + * checked separately. (Any sequence of zeroes has a Fletcher + * checksum of zero.)" + * + * @author John Leuner, Per Bothner + * @since JDK 1.1 + * + * @see InflaterInputStream + * @see DeflaterOutputStream + */ +public class Adler32 implements Checksum +{ + + /** largest prime smaller than 65536 */ + private static final int BASE = 65521; + + private int checksum; //we do all in int. + + //Note that java doesn't have unsigned integers, + //so we have to be careful with what arithmetic + //we do. We return the checksum as a long to + //avoid sign confusion. + + /** + * Creates a new instance of the Adler32 class. + * The checksum starts off with a value of 1. + */ + public Adler32 () + { + reset (); + } + + /** + * Resets the Adler32 checksum to the initial value. + */ + public void reset () + { + checksum = 1; //Initialize to 1 + } + + /** + * Updates the checksum with the byte b. + * + * @param bval the data value to add. The high byte of the int is ignored. + */ + public void update (int bval) + { + //We could make a length 1 byte array and call update again, but I + //would rather not have that overhead + int s1 = checksum & 0xffff; + int s2 = checksum >>> 16; + + s1 = (s1 + (bval & 0xFF)) % BASE; + s2 = (s1 + s2) % BASE; + + checksum = (s2 << 16) + s1; + } + + /** + * Updates the checksum with the bytes taken from the array. + * + * @param buffer an array of bytes + */ + public void update (byte[] buffer) + { + update (buffer, 0, buffer.length); + } + + /** + * Updates the checksum with the bytes taken from the array. + * + * @param buf an array of bytes + * @param off the start of the data used for this update + * @param len the number of bytes to use for this update + */ + public void update (byte[] buf, int off, int len) + { + //(By Per Bothner) + int s1 = checksum & 0xffff; + int s2 = checksum >>> 16; + + while (len > 0) + { + // We can defer the modulo operation: + // s1 maximally grows from 65521 to 65521 + 255 * 3800 + // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 + int n = 3800; + if (n > len) + n = len; + len -= n; + while (--n >= 0) + { + s1 = s1 + (buf[off++] & 0xFF); + s2 = s2 + s1; + } + s1 %= BASE; + s2 %= BASE; + } + + /*Old implementation, borrowed from somewhere: + int n; + + while (len-- > 0) { + + s1 = (s1 + (bs[offset++] & 0xff)) % BASE; + s2 = (s2 + s1) % BASE; + }*/ + + checksum = (s2 << 16) | s1; + } + + /** + * Returns the Adler32 data checksum computed so far. + */ + public long getValue () + { + return (long) checksum & 0xffffffffL; + } +} diff --git a/src/com/classpath/zip/CRC32.java b/src/com/classpath/zip/CRC32.java new file mode 100644 index 0000000..b550d1b --- /dev/null +++ b/src/com/classpath/zip/CRC32.java @@ -0,0 +1,135 @@ +/* CRC32.java - Computes CRC32 data checksum of a data stream + Copyright (C) 1999. 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +/* + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). + * The actual CRC32 algorithm is taken from RFC 1952. + * Status: Believed complete and correct. + */ + +/** + * Computes CRC32 data checksum of a data stream. + * The actual CRC32 algorithm is described in RFC 1952 + * (GZIP file format specification version 4.3). + * Can be used to get the CRC32 over a stream if used with checked input/output + * streams. + * + * @see InflaterInputStream + * @see DeflaterOutputStream + * + * @author Per Bothner + * @date April 1, 1999. + */ +public class CRC32 implements Checksum +{ + /** The crc data checksum so far. */ + private int crc = 0; + + /** The fast CRC table. Computed once when the CRC32 class is loaded. */ + private static int[] crc_table = make_crc_table (); + + /** Make the table for a fast CRC. */ + private static int[] make_crc_table () + { + int[] crc_table = new int[256]; + for (int n = 0; n < 256; n++) + { + int c = n; + for (int k = 8; --k >= 0; ) + { + if ((c & 1) != 0) + c = 0xedb88320 ^ (c >>> 1); + else + c = c >>> 1; + } + crc_table[n] = c; + } + return crc_table; + } + + /** + * Returns the CRC32 data checksum computed so far. + */ + public long getValue () + { + return (long) crc & 0xffffffffL; + } + + /** + * Resets the CRC32 data checksum as if no update was ever called. + */ + public void reset () + { crc = 0; } + + /** + * Updates the checksum with the int bval. + * + * @param bval (the byte is taken as the lower 8 bits of bval) + */ + + public void update (int bval) + { + int c = ~crc; + c = crc_table[(c ^ bval) & 0xff] ^ (c >>> 8); + crc = ~c; + } + + /** + * Adds the byte array to the data checksum. + * + * @param buf the buffer which contains the data + * @param off the offset in the buffer where the data starts + * @param len the length of the data + */ + public void update (byte[] buf, int off, int len) + { + int c = ~crc; + while (--len >= 0) + c = crc_table[(c ^ buf[off++]) & 0xff] ^ (c >>> 8); + crc = ~c; + } + + /** + * Adds the complete byte array to the data checksum. + */ + public void update (byte[] buf) + { update (buf, 0, buf.length); } +} diff --git a/src/com/classpath/zip/CentralDirectoryEndRecord.java b/src/com/classpath/zip/CentralDirectoryEndRecord.java new file mode 100644 index 0000000..c62e2f8 --- /dev/null +++ b/src/com/classpath/zip/CentralDirectoryEndRecord.java @@ -0,0 +1,66 @@ +package com.classpath.zip; + +import com.vmx.AuxClass; +import com.vmx.StringEncoder; +import java.io.*; + +class CentralDirectoryEndRecord +{ + public int numEntries, // total number of entries in the central dir + centralSize, // size of the central directory + centralOffset; // offset of start of central directory + + public String comment; + + public CentralDirectoryEndRecord() + { + numEntries = 0; + centralSize = 0; + centralOffset = 0; + + comment = ""; + } + + public boolean read(InputStream is) throws IOException + { + if(AuxClass.readLeInt(is) != ZipConstants.ENDSIG) + { + return false; + } + + is.skip(6); + + numEntries = AuxClass.readLeShort(is); + centralSize = AuxClass.readLeInt(is); + centralOffset = AuxClass.readLeInt(is); + + int commentLen = AuxClass.readLeShort(is); + + if(commentLen > 0) + { + comment = StringEncoder.readString(is, commentLen, StringEncoder.ENC_ARCHIVE); + } + else + { + comment = ""; + } + + return true; + } + + public void write(OutputStream os) throws IOException + { + AuxClass.writeLeInt(os, ZipConstants.ENDSIG); + + AuxClass.writeLeShort(os, 0); /* disk number */ + AuxClass.writeLeShort(os, 0); /* disk with start of central dir */ + AuxClass.writeLeShort(os, numEntries); + AuxClass.writeLeShort(os, numEntries); + AuxClass.writeLeInt(os, centralSize); + AuxClass.writeLeInt(os, centralOffset); + + byte[] zipComment = StringEncoder.encodeString(comment, StringEncoder.ENC_ARCHIVE); + AuxClass.writeLeShort(os, zipComment.length); + os.write(zipComment); + } +} diff --git a/src/com/classpath/zip/CheckedInputStream.java b/src/com/classpath/zip/CheckedInputStream.java new file mode 100644 index 0000000..8bce467 --- /dev/null +++ b/src/com/classpath/zip/CheckedInputStream.java @@ -0,0 +1,137 @@ +/* CheckedInputStream.java - Compute checksum of data being read + Copyright (C) 1999, 2000, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +//package java.util.zip; +package com.classpath.zip; + +//import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +/** + * InputStream that computes a checksum of the data being read using a + * supplied Checksum object. + * + * @see Checksum + * + * @author Tom Tromey + * @date May 17, 1999 + */ +public class CheckedInputStream extends InputStream +{ + protected InputStream in; + /** + * Creates a new CheckInputStream on top of the supplied OutputStream + * using the supplied Checksum. + */ + public CheckedInputStream (InputStream in, Checksum sum) + { + this.in = in; + this.sum = sum; + } + + /** + * Returns the Checksum object used. To get the data checksum computed so + * far call getChecksum.getValue(). + */ + public Checksum getChecksum () + { + return sum; + } + + /** + * Reads one byte, updates the checksum and returns the read byte + * (or -1 when the end of file was reached). + */ + public int read () throws IOException + { + int x = in.read(); + if (x != -1) + sum.update(x); + return x; + } + + /** + * Reads at most len bytes in the supplied buffer and updates the checksum + * with it. Returns the number of bytes actually read or -1 when the end + * of file was reached. + */ + public int read (byte[] buf, int off, int len) throws IOException + { + int r = in.read(buf, off, len); + if (r != -1) + sum.update(buf, off, r); + return r; + } + + /** + * Skips n bytes by reading them in a temporary buffer and updating the + * the checksum with that buffer. Returns the actual number of bytes skiped + * which can be less then requested when the end of file is reached. + */ + public long skip (long n) throws IOException + { + if (n == 0) + return 0; + + int min = (int) Math.min(n, 1024); + byte[] buf = new byte[min]; + + long s = 0; + while (n > 0) + { + int r = in.read(buf, 0, min); + if (r == -1) + break; + n -= r; + s += r; + min = (int) Math.min(n, 1024); + sum.update(buf, 0, r); + } + + return s; + } + + /** The checksum object. */ + private Checksum sum; +} diff --git a/src/com/classpath/zip/CheckedOutputStream.java b/src/com/classpath/zip/CheckedOutputStream.java new file mode 100644 index 0000000..c6952fc --- /dev/null +++ b/src/com/classpath/zip/CheckedOutputStream.java @@ -0,0 +1,103 @@ +/* CheckedOutputStream.java - Compute checksum of data being written. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +//package java.util.zip; +package com.classpath.zip; + +//import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +/** + * OutputStream that computes a checksum of data being written using a + * supplied Checksum object. + * + * @see Checksum + * + * @author Tom Tromey + * @date May 17, 1999 + */ +public class CheckedOutputStream extends OutputStream +{ + protected OutputStream out; + + /** + * Creates a new CheckInputStream on top of the supplied OutputStream + * using the supplied Checksum. + */ + public CheckedOutputStream (OutputStream out, Checksum cksum) + { + this.out = out; + this.sum = cksum; + } + + /** + * Returns the Checksum object used. To get the data checksum computed so + * far call getChecksum.getValue(). + */ + public Checksum getChecksum () + { + return sum; + } + + /** + * Writes one byte to the OutputStream and updates the Checksum. + */ + public void write (int bval) throws IOException + { + out.write(bval); + sum.update(bval); + } + + /** + * Writes the byte array to the OutputStream and updates the Checksum. + */ + public void write (byte[] buf, int off, int len) throws IOException + { + out.write(buf, off, len); + sum.update(buf, off, len); + } + + /** The checksum object. */ + private Checksum sum; +} diff --git a/src/com/classpath/zip/Checksum.java b/src/com/classpath/zip/Checksum.java new file mode 100644 index 0000000..41327d6 --- /dev/null +++ b/src/com/classpath/zip/Checksum.java @@ -0,0 +1,87 @@ +/* Checksum.java - Interface to compute a data checksum + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +/* + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). + * Status: Believed complete and correct. + */ + +/** + * Interface to compute a data checksum used by checked input/output streams. + * A data checksum can be updated by one byte or with a byte array. After each + * update the value of the current checksum can be returned by calling + * getValue. The complete checksum object can also be reset + * so it can be used again with new data. + * + * @see CheckedInputStream + * @see CheckedOutputStream + * + * @author Per Bothner + * @author Jochen Hoenicke + */ +public interface Checksum +{ + /** + * Returns the data checksum computed so far. + */ + long getValue (); + + /** + * Resets the data checksum as if no update was ever called. + */ + void reset (); + + /** + * Adds one byte to the data checksum. + * + * @param bval the data value to add. The high byte of the int is ignored. + */ + void update (int bval); + + /** + * Adds the byte array to the data checksum. + * + * @param buf the buffer which contains the data + * @param off the offset in the buffer where the data starts + * @param len the length of the data + */ + void update (byte[] buf, int off, int len); +} diff --git a/src/com/classpath/zip/DataFormatException.java b/src/com/classpath/zip/DataFormatException.java new file mode 100644 index 0000000..b839436 --- /dev/null +++ b/src/com/classpath/zip/DataFormatException.java @@ -0,0 +1,72 @@ +/* DataformatException.java -- thrown when compressed data is corrupt + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +/** + * Exception thrown when compressed data is corrupt. + * + * @author Tom Tromey + * @author John Leuner + * @since 1.1 + * @status updated to 1.4 + */ +public class DataFormatException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 2219632870893641452L; + + /** + * Create an exception without a message. + */ + public DataFormatException() + { + } + + /** + * Create an exception with a message. + * + * @param msg the message + */ + public DataFormatException(String msg) + { + super(msg); + } +} diff --git a/src/com/classpath/zip/Deflater.java b/src/com/classpath/zip/Deflater.java new file mode 100644 index 0000000..733629d --- /dev/null +++ b/src/com/classpath/zip/Deflater.java @@ -0,0 +1,525 @@ +/* Deflater.java - Compress a data stream + Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package com.classpath.zip; + +/** + * This is the Deflater class. The deflater class compresses input + * with the deflate algorithm described in RFC 1951. It has several + * compression levels and three different strategies described below. + * + * This class is not thread safe. This is inherent in the API, due + * to the split of deflate and setInput. + * + * @author Jochen Hoenicke + * @author Tom Tromey + */ +public class Deflater +{ + /** + * The best and slowest compression level. This tries to find very + * long and distant string repetitions. + */ + public static final int BEST_COMPRESSION = 9; + /** + * The worst but fastest compression level. + */ + public static final int BEST_SPEED = 1; + /** + * The default compression level. + */ + public static final int DEFAULT_COMPRESSION = -1; + /** + * This level won't compress at all but output uncompressed blocks. + */ + public static final int NO_COMPRESSION = 0; + + /** + * The default strategy. + */ + public static final int DEFAULT_STRATEGY = 0; + /** + * This strategy will only allow longer string repetitions. It is + * useful for random data with a small character set. + */ + public static final int FILTERED = 1; + + /** + * This strategy will not look for string repetitions at all. It + * only encodes with Huffman trees (which means, that more common + * characters get a smaller encoding. + */ + public static final int HUFFMAN_ONLY = 2; + + /** + * The compression method. This is the only method supported so far. + * There is no need to use this constant at all. + */ + public static final int DEFLATED = 8; + + /* + * The Deflater can do the following state transitions: + * + * (1) -> INIT_STATE ----> INIT_FINISHING_STATE ---. + * / | (2) (5) | + * / v (5) | + * (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3) + * \ | (3) | ,-------' + * | | | (3) / + * v v (5) v v + * (1) -> BUSY_STATE ----> FINISHING_STATE + * | (6) + * v + * FINISHED_STATE + * \_____________________________________/ + * | (7) + * v + * CLOSED_STATE + * + * (1) If we should produce a header we start in INIT_STATE, otherwise + * we start in BUSY_STATE. + * (2) A dictionary may be set only when we are in INIT_STATE, then + * we change the state as indicated. + * (3) Whether a dictionary is set or not, on the first call of deflate + * we change to BUSY_STATE. + * (4) -- intentionally left blank -- :) + * (5) FINISHING_STATE is entered, when flush() is called to indicate that + * there is no more INPUT. There are also states indicating, that + * the header wasn't written yet. + * (6) FINISHED_STATE is entered, when everything has been flushed to the + * internal pending output buffer. + * (7) At any time (7) + * + */ + + private static final int IS_SETDICT = 0x01; + private static final int IS_FLUSHING = 0x04; + private static final int IS_FINISHING = 0x08; + + private static final int INIT_STATE = 0x00; + private static final int SETDICT_STATE = 0x01; + private static final int INIT_FINISHING_STATE = 0x08; + private static final int SETDICT_FINISHING_STATE = 0x09; + private static final int BUSY_STATE = 0x10; + private static final int FLUSHING_STATE = 0x14; + private static final int FINISHING_STATE = 0x1c; + private static final int FINISHED_STATE = 0x1e; + private static final int CLOSED_STATE = 0x7f; + + /** Compression level. */ + private int level; + + /** should we include a header. */ + private boolean noHeader; + + /** The current state. */ + private int state; + + /** The total bytes of output written. */ + private int totalOut; + + /** The pending output. */ + private DeflaterPending pending; + + /** The deflater engine. */ + private DeflaterEngine engine; + + /** + * Creates a new deflater with default compression level. + */ + public Deflater() + { + this(DEFAULT_COMPRESSION, false); + } + + /** + * Creates a new deflater with given compression level. + * @param lvl the compression level, a value between NO_COMPRESSION + * and BEST_COMPRESSION, or DEFAULT_COMPRESSION. + * @exception IllegalArgumentException if lvl is out of range. + */ + public Deflater(int lvl) + { + this(lvl, false); + } + + /** + * Creates a new deflater with given compression level. + * @param lvl the compression level, a value between NO_COMPRESSION + * and BEST_COMPRESSION. + * @param nowrap true, iff we should suppress the deflate header at the + * beginning and the adler checksum at the end of the output. This is + * useful for the GZIP format. + * @exception IllegalArgumentException if lvl is out of range. + */ + public Deflater(int lvl, boolean nowrap) + { + if(lvl == DEFAULT_COMPRESSION) + lvl = 6; + else if(lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) + throw new IllegalArgumentException(); + + pending = new DeflaterPending(); + engine = new DeflaterEngine(pending); + this.noHeader = nowrap; + setStrategy(DEFAULT_STRATEGY); + setLevel(lvl); + reset(); + } + + /** + * Resets the deflater. The deflater acts afterwards as if it was + * just created with the same compression level and strategy as it + * had before. + */ + public void reset() + { + state = (noHeader ? BUSY_STATE : INIT_STATE); + totalOut = 0; + pending.reset(); + engine.reset(); + } + + /** + * Frees all objects allocated by the compressor. There's no + * reason to call this, since you can just rely on garbage + * collection. Exists only for compatibility against Sun's JDK, + * where the compressor allocates native memory. + * If you call any method (even reset) afterwards the behaviour is + * undefined. + * @deprecated Just clear all references to deflater instead. + */ + public void end() + { + engine = null; + pending = null; + state = CLOSED_STATE; + } + + /** + * Gets the current adler checksum of the data that was processed so + * far. + */ + public int getAdler() + { + return engine.getAdler(); + } + + /** + * Gets the number of input bytes processed so far. + */ + public int getTotalIn() + { + return engine.getTotalIn(); + } + + /** + * Gets the number of output bytes so far. + */ + public int getTotalOut() + { + return totalOut; + } + + // /** + // * Finalizes this object. + // */ + // protected void finalize () + // { + // /* Exists solely for compatibility. We don't have any native state. */ + // } + + /** + * Flushes the current input block. Further calls to deflate() will + * produce enough output to inflate everything in the current input + * block. This is not part of Sun's JDK so I have made it package + * private. It is used by DeflaterOutputStream to implement + * flush(). + */ + void flush() + { + state |= IS_FLUSHING; + } + + /** + * Finishes the deflater with the current input block. It is an error + * to give more input after this method was called. This method must + * be called to force all bytes to be flushed. + */ + public void finish() + { + state |= IS_FLUSHING | IS_FINISHING; + } + + /** + * Returns true iff the stream was finished and no more output bytes + * are available. + */ + public boolean finished() + { + return state == FINISHED_STATE && pending.isFlushed(); + } + + /** + * Returns true, if the input buffer is empty. + * You should then call setInput().
+ * + * NOTE: This method can also return true when the stream + * was finished. + */ + public boolean needsInput() + { + return engine.needsInput(); + } + + /** + * Sets the data which should be compressed next. This should be only + * called when needsInput indicates that more input is needed. + * If you call setInput when needsInput() returns false, the + * previous input that is still pending will be thrown away. + * The given byte array should not be changed, before needsInput() returns + * true again. + * This call is equivalent to setInput(input, 0, input.length). + * @param input the buffer containing the input data. + * @exception IllegalStateException if the buffer was finished() or ended(). + */ + public void setInput(byte[] input) + { + setInput(input, 0, input.length); + } + + /** + * Sets the data which should be compressed next. This should be + * only called when needsInput indicates that more input is needed. + * The given byte array should not be changed, before needsInput() returns + * true again. + * @param input the buffer containing the input data. + * @param off the start of the data. + * @param len the length of the data. + * @exception IllegalStateException if the buffer was finished() or ended() + * or if previous input is still pending. + */ + public void setInput(byte[] input, int off, int len) + { + if((state & IS_FINISHING) != 0) + throw new IllegalStateException("finish()/end() already called"); + engine.setInput(input, off, len); + } + + /** + * Sets the compression level. There is no guarantee of the exact + * position of the change, but if you call this when needsInput is + * true the change of compression level will occur somewhere near + * before the end of the so far given input. + * @param lvl the new compression level. + */ + public void setLevel(int lvl) + { + if(lvl == DEFAULT_COMPRESSION) + { + lvl = 6; + } + else if(lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) + { + throw new IllegalArgumentException("Wrong compression level"); + } + + if(level != lvl) + { + level = lvl; + engine.setLevel(lvl); + } + } + + /** + * Sets the compression strategy. Strategy is one of + * DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact + * position where the strategy is changed, the same as for + * setLevel() applies. + * @param stgy the new compression strategy. + */ + public void setStrategy(int stgy) + { + if(stgy != DEFAULT_STRATEGY && stgy != FILTERED + && stgy != HUFFMAN_ONLY) + throw new IllegalArgumentException(); + engine.setStrategy(stgy); + } + + /** + * Deflates the current input block to the given array. It returns + * the number of bytes compressed, or 0 if either + * needsInput() or finished() returns true or length is zero. + * @param output the buffer where to write the compressed data. + */ + public int deflate(byte[] output) + { + return deflate(output, 0, output.length); + } + + /** + * Deflates the current input block to the given array. It returns + * the number of bytes compressed, or 0 if either + * needsInput() or finished() returns true or length is zero. + * @param output the buffer where to write the compressed data. + * @param offset the offset into the output array. + * @param length the maximum number of bytes that may be written. + * @exception IllegalStateException if end() was called. + * @exception IndexOutOfBoundsException if offset and/or length + * don't match the array length. + */ + public int deflate(byte[] output, int offset, int length) + { + int origLength = length; + + if(state == CLOSED_STATE) + throw new IllegalStateException("Deflater closed"); + + if(state < BUSY_STATE) + { + /* output header */ + int header = (DEFLATED + + ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8; + int level_flags = (level - 1) >> 1; + if(level_flags < 0 || level_flags > 3) + level_flags = 3; + header |= level_flags << 6; + if((state & IS_SETDICT) != 0) + /* Dictionary was set */ + header |= DeflaterConstants.PRESET_DICT; + header += 31 - (header % 31); + + pending.writeShortMSB(header); + if((state & IS_SETDICT) != 0) + { + int chksum = engine.getAdler(); + engine.resetAdler(); + pending.writeShortMSB(chksum >> 16); + pending.writeShortMSB(chksum & 0xffff); + } + + state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING)); + } + + for(; ; ) + { + int count = pending.flush(output, offset, length); + offset += count; + totalOut += count; + length -= count; + if(length == 0 || state == FINISHED_STATE) + break; + + if(!engine.deflate((state & IS_FLUSHING) != 0, + (state & IS_FINISHING) != 0)) + { + if(state == BUSY_STATE) + /* We need more input now */ + return origLength - length; + else if(state == FLUSHING_STATE) + { + if(level != NO_COMPRESSION) + { + /* We have to supply some lookahead. 8 bit lookahead + * are needed by the zlib inflater, and we must fill + * the next byte, so that all bits are flushed. + */ + int neededbits = 8 + ((-pending.getBitCount()) & 7); + while(neededbits > 0) + { + /* write a static tree block consisting solely of + * an EOF: + */ + pending.writeBits(2, 10); + neededbits -= 10; + } + } + state = BUSY_STATE; + } + else if(state == FINISHING_STATE) + { + pending.alignToByte(); + /* We have completed the stream */ + if(!noHeader) + { + int adler = engine.getAdler(); + pending.writeShortMSB(adler >> 16); + pending.writeShortMSB(adler & 0xffff); + } + state = FINISHED_STATE; + } + } + } + + return origLength - length; + } + + /** + * Sets the dictionary which should be used in the deflate process. + * This call is equivalent to setDictionary(dict, 0, + * dict.length). + * @param dict the dictionary. + * @exception IllegalStateException if setInput () or deflate () + * were already called or another dictionary was already set. + */ + public void setDictionary(byte[] dict) + { + setDictionary(dict, 0, dict.length); + } + + /** + * Sets the dictionary which should be used in the deflate process. + * The dictionary should be a byte array containing strings that are + * likely to occur in the data which should be compressed. The + * dictionary is not stored in the compressed output, only a + * checksum. To decompress the output you need to supply the same + * dictionary again. + * @param dict the dictionary. + * @param offset an offset into the dictionary. + * @param length the length of the dictionary. + * @exception IllegalStateException if setInput () or deflate () were + * already called or another dictionary was already set. + */ + public void setDictionary(byte[] dict, int offset, int length) + { + if(state != INIT_STATE) + throw new IllegalStateException(); + + state = SETDICT_STATE; + engine.setDictionary(dict, offset, length); + } +} diff --git a/src/com/classpath/zip/DeflaterConstants.java b/src/com/classpath/zip/DeflaterConstants.java new file mode 100644 index 0000000..6743f67 --- /dev/null +++ b/src/com/classpath/zip/DeflaterConstants.java @@ -0,0 +1,79 @@ +/* java.util.zip.DeflaterConstants + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +class DeflaterConstants +{ + final static boolean DEBUGGING = false; + + final static int STORED_BLOCK = 0; + final static int STATIC_TREES = 1; + final static int DYN_TREES = 2; + final static int PRESET_DICT = 0x20; + + final static int DEFAULT_MEM_LEVEL = 8; + + final static int MAX_MATCH = 258; + final static int MIN_MATCH = 3; + + final static int MAX_WBITS = 15; + final static int WSIZE = 1 << MAX_WBITS; + final static int WMASK = WSIZE - 1; + + final static int HASH_BITS = DEFAULT_MEM_LEVEL + 7; + final static int HASH_SIZE = 1 << HASH_BITS; + final static int HASH_MASK = HASH_SIZE - 1; + final static int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH; + + final static int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1; + final static int MAX_DIST = WSIZE - MIN_LOOKAHEAD; + + final static int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8); + final static int MAX_BLOCK_SIZE = Math.min (65535, PENDING_BUF_SIZE-5); + + final static int DEFLATE_STORED = 0; + final static int DEFLATE_FAST = 1; + final static int DEFLATE_SLOW = 2; + + final static int GOOD_LENGTH[] = { 0,4, 4, 4, 4, 8, 8, 8, 32, 32 }; + final static int MAX_LAZY[] = { 0,4, 5, 6, 4,16, 16, 32, 128, 258 }; + final static int NICE_LENGTH[] = { 0,8,16,32,16,32,128,128, 258, 258 }; + final static int MAX_CHAIN[] = { 0,4, 8,32,16,32,128,256,1024,4096 }; + final static int COMPR_FUNC[] = { 0,1, 1, 1, 1, 2, 2, 2, 2, 2 }; +} diff --git a/src/com/classpath/zip/DeflaterEngine.java b/src/com/classpath/zip/DeflaterEngine.java new file mode 100644 index 0000000..f648bf1 --- /dev/null +++ b/src/com/classpath/zip/DeflaterEngine.java @@ -0,0 +1,740 @@ +/* java.util.zip.DeflaterEngine +Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +//package java.util.zip; +package com.classpath.zip; + +class DeflaterEngine +{ + private final static int TOO_FAR = 4096; + private int ins_h; + /** + * Hashtable, hashing three characters to an index for window, so + * that window[index]..window[index+2] have this hash code. + * Note that the array should really be unsigned short, so you need + * to and the values with 0xffff. + */ + private short[] head; + /** + * prev[index & WMASK] points to the previous index that has the + * same hash code as the string starting at index. This way + * entries with the same hash code are in a linked list. + * Note that the array should really be unsigned short, so you need + * to and the values with 0xffff. + */ + private short[] prev; + private int matchStart, matchLen; + private boolean prevAvailable; + private int blockStart; + /** + * strstart points to the current character in window. + */ + private int strstart; + /** + * lookahead is the number of characters starting at strstart in + * window that are valid. + * So window[strstart] until window[strstart+lookahead-1] are valid + * characters. + */ + private int lookahead; + /** + * This array contains the part of the uncompressed stream that + * is of relevance. The current character is indexed by strstart. + */ + private byte[] window; + private int strategy, max_chain, max_lazy, niceLength, goodLength; + /** The current compression function. */ + private int comprFunc; + /** The input data for compression. */ + private byte[] inputBuf; + /** The total bytes of input read. */ + private int totalIn; + /** The offset into inputBuf, where input data starts. */ + private int inputOff; + /** The end offset of the input data. */ + private int inputEnd; + private DeflaterPending pending; + private DeflaterHuffman huffman; + /** The adler checksum */ + private Adler32 adler; + + /* DEFLATE ALGORITHM: + * + * The uncompressed stream is inserted into the window array. When + * the window array is full the first half is thrown away and the + * second half is copied to the beginning. + * + * The head array is a hash table. Three characters build a hash value + * and they the value points to the corresponding index in window of + * the last string with this hash. The prev array implements a + * linked list of matches with the same hash: prev[index & WMASK] points + * to the previous index with the same hash. + * + * + */ + DeflaterEngine(DeflaterPending pending) + { + this.pending = pending; + huffman = new DeflaterHuffman(pending); + adler = new Adler32(); + + window = new byte[2 * DeflaterConstants.WSIZE]; + head = new short[DeflaterConstants.HASH_SIZE]; + prev = new short[DeflaterConstants.WSIZE]; + + /* We start at index 1, to avoid a implementation deficiency, that + * we cannot build a repeat pattern at index 0. + */ + blockStart = strstart = 1; + } + + public void reset() + { + huffman.reset(); + adler.reset(); + blockStart = strstart = 1; + lookahead = 0; + totalIn = 0; + prevAvailable = false; + matchLen = DeflaterConstants.MIN_MATCH - 1; + for(int i = 0; i < DeflaterConstants.HASH_SIZE; i++) + { + head[i] = 0; + } + for(int i = 0; i < DeflaterConstants.WSIZE; i++) + { + prev[i] = 0; + } + } + + public final void resetAdler() + { + adler.reset(); + } + + public final int getAdler() + { + int chksum = (int) adler.getValue(); + return chksum; + } + + public final int getTotalIn() + { + return totalIn; + } + + public final void setStrategy(int strat) + { + strategy = strat; + } + + public void setLevel(int lvl) + { + goodLength = DeflaterConstants.GOOD_LENGTH[lvl]; + max_lazy = DeflaterConstants.MAX_LAZY[lvl]; + niceLength = DeflaterConstants.NICE_LENGTH[lvl]; + max_chain = DeflaterConstants.MAX_CHAIN[lvl]; + + if(DeflaterConstants.COMPR_FUNC[lvl] != comprFunc) + { + if(DeflaterConstants.DEBUGGING) + { + System.err.println("Change from " + comprFunc + " to " + + DeflaterConstants.COMPR_FUNC[lvl]); + } + switch(comprFunc) + { + case DeflaterConstants.DEFLATE_STORED: + if(strstart > blockStart) + { + huffman.flushStoredBlock(window, blockStart, + strstart - blockStart, false); + blockStart = strstart; + } + updateHash(); + break; + case DeflaterConstants.DEFLATE_FAST: + if(strstart > blockStart) + { + huffman.flushBlock(window, blockStart, strstart - blockStart, + false); + blockStart = strstart; + } + break; + case DeflaterConstants.DEFLATE_SLOW: + if(prevAvailable) + { + huffman.tallyLit(window[strstart - 1] & 0xff); + } + if(strstart > blockStart) + { + huffman.flushBlock(window, blockStart, strstart - blockStart, + false); + blockStart = strstart; + } + prevAvailable = false; + matchLen = DeflaterConstants.MIN_MATCH - 1; + break; + } + comprFunc = DeflaterConstants.COMPR_FUNC[lvl]; + } + } + + private final void updateHash() + { + if(DeflaterConstants.DEBUGGING) + { + System.err.println("updateHash: " + strstart); + } + ins_h = (window[strstart] << DeflaterConstants.HASH_SHIFT) ^ window[strstart + 1]; + } + + /** + * Inserts the current string in the head hash and returns the previous + * value for this hash. + */ + private final int insertString() + { + short match; + int hash = ((ins_h << DeflaterConstants.HASH_SHIFT) ^ window[strstart + (DeflaterConstants.MIN_MATCH - 1)]) + & DeflaterConstants.HASH_MASK; + + /*if (DEBUGGING) + { + if (hash != (((window[strstart] << (2*HASH_SHIFT)) + ^ (window[strstart + 1] << HASH_SHIFT) + ^ (window[strstart + 2])) & HASH_MASK)) + throw new InternalError("hash inconsistent: "+hash+"/" + +window[strstart]+"," + +window[strstart+1]+"," + +window[strstart+2]+","+HASH_SHIFT); + }*/ + + prev[strstart & DeflaterConstants.WMASK] = match = head[hash]; + head[hash] = (short) strstart; + ins_h = hash; + return match & 0xffff; + } + + private void slideWindow() + { + System.arraycopy(window, DeflaterConstants.WSIZE, window, 0, DeflaterConstants.WSIZE); + matchStart -= DeflaterConstants.WSIZE; + strstart -= DeflaterConstants.WSIZE; + blockStart -= DeflaterConstants.WSIZE; + + /* Slide the hash table (could be avoided with 32 bit values + * at the expense of memory usage). + */ + for(int i = 0; i < DeflaterConstants.HASH_SIZE; i++) + { + int m = head[i] & 0xffff; + head[i] = m >= DeflaterConstants.WSIZE ? (short) (m - DeflaterConstants.WSIZE) : 0; + } + + /* Slide the prev table. + */ + for(int i = 0; i < DeflaterConstants.WSIZE; i++) + { + int m = prev[i] & 0xffff; + prev[i] = m >= DeflaterConstants.WSIZE ? (short) (m - DeflaterConstants.WSIZE) : 0; + } + } + + /** + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * OUT assertions: strstart + lookahead <= 2*WSIZE + * lookahead >= MIN_LOOKAHEAD or inputOff == inputEnd + */ + private void fillWindow() + { + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if(strstart >= DeflaterConstants.WSIZE + DeflaterConstants.MAX_DIST) + { + slideWindow(); + } + + /* If there is not enough lookahead, but still some input left, + * read in the input + */ + while(lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd) + { + int more = 2 * DeflaterConstants.WSIZE - lookahead - strstart; + + if(more > inputEnd - inputOff) + { + more = inputEnd - inputOff; + } + + System.arraycopy(inputBuf, inputOff, + window, strstart + lookahead, more); + adler.update(inputBuf, inputOff, more); + inputOff += more; + totalIn += more; + lookahead += more; + } + + if(lookahead >= DeflaterConstants.MIN_MATCH) + { + updateHash(); + } + } + + /** + * Find the best (longest) string in the window matching the + * string starting at strstart. + * + * Preconditions: + * strstart + MAX_MATCH <= window.length. + * + * + * @param curMatch + */ + private boolean findLongestMatch(int curMatch) + { + int chainLength = this.max_chain; + int niceLength = this.niceLength; + short[] prev = this.prev; + int scan = this.strstart; + int match; + int best_end = this.strstart + matchLen; + int best_len = Math.max(matchLen, DeflaterConstants.MIN_MATCH - 1); + + int limit = Math.max(strstart - DeflaterConstants.MAX_DIST, 0); + + int strend = scan + DeflaterConstants.MAX_MATCH - 1; + byte scan_end1 = window[best_end - 1]; + byte scan_end = window[best_end]; + + /* Do not waste too much time if we already have a good match: */ + if(best_len >= this.goodLength) + { + chainLength >>= 2; + } + + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if(niceLength > lookahead) + { + niceLength = lookahead; + } + + /*if (DeflaterConstants.DEBUGGING + && strstart > 2*WSIZE - MIN_LOOKAHEAD) + throw new InternalError("need lookahead");*/ + + do + { + /*if (DeflaterConstants.DEBUGGING && curMatch >= strstart) + throw new InternalError("future match");*/ + if(window[curMatch + best_len] != scan_end + || window[curMatch + best_len - 1] != scan_end1 + || window[curMatch] != window[scan] + || window[curMatch + 1] != window[scan + 1]) + { + continue; + } + + match = curMatch + 2; + scan += 2; + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + while(window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && scan < strend); + + if(scan > best_end) + { +// if (DeflaterConstants.DEBUGGING && ins_h == 0) +// System.err.println("Found match: "+curMatch+"-"+(scan-strstart)); + matchStart = curMatch; + best_end = scan; + best_len = scan - strstart; + if(best_len >= niceLength) + { + break; + } + + scan_end1 = window[best_end - 1]; + scan_end = window[best_end]; + } + scan = strstart; + } + while((curMatch = (prev[curMatch & DeflaterConstants.WMASK] & 0xffff)) > limit + && --chainLength != 0); + + matchLen = Math.min(best_len, lookahead); + return matchLen >= DeflaterConstants.MIN_MATCH; + } + + void setDictionary(byte[] buffer, int offset, int length) + { + if(DeflaterConstants.DEBUGGING && strstart != 1) + { + throw new IllegalStateException("strstart not 1"); + } + adler.update(buffer, offset, length); + if(length < DeflaterConstants.MIN_MATCH) + { + return; + } + if(length > DeflaterConstants.MAX_DIST) + { + offset += length - DeflaterConstants.MAX_DIST; + length = DeflaterConstants.MAX_DIST; + } + + System.arraycopy(buffer, offset, window, strstart, length); + + updateHash(); + length--; + while(--length > 0) + { + insertString(); + strstart++; + } + strstart += 2; + blockStart = strstart; + } + + private boolean deflateStored(boolean flush, boolean finish) + { + if(!flush && lookahead == 0) + { + return false; + } + + strstart += lookahead; + lookahead = 0; + + int storedLen = strstart - blockStart; + + if((storedLen >= DeflaterConstants.MAX_BLOCK_SIZE) + /* Block is full */ + || (blockStart < DeflaterConstants.WSIZE && storedLen >= DeflaterConstants.MAX_DIST) + /* Block may move out of window */ + || flush) + { + boolean lastBlock = finish; + if(storedLen > DeflaterConstants.MAX_BLOCK_SIZE) + { + storedLen = DeflaterConstants.MAX_BLOCK_SIZE; + lastBlock = false; + } + + if(DeflaterConstants.DEBUGGING) + { + System.err.println("storedBlock[" + storedLen + "," + lastBlock + "]"); + } + + huffman.flushStoredBlock(window, blockStart, storedLen, lastBlock); + blockStart += storedLen; + return !lastBlock; + } + return true; + } + + private boolean deflateFast(boolean flush, boolean finish) + { + if(lookahead < DeflaterConstants.MIN_LOOKAHEAD && !flush) + { + return false; + } + + while(lookahead >= DeflaterConstants.MIN_LOOKAHEAD || flush) + { + if(lookahead == 0) + { + /* We are flushing everything */ + huffman.flushBlock(window, blockStart, strstart - blockStart, + finish); + blockStart = strstart; + return false; + } + + if(strstart > 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD) + { + /* slide window, as findLongestMatch need this. + * This should only happen when flushing and the window + * is almost full. + */ + slideWindow(); + } + + int hashHead; + if(lookahead >= DeflaterConstants.MIN_MATCH + && (hashHead = insertString()) != 0 + && strategy != Deflater.HUFFMAN_ONLY + && strstart - hashHead <= DeflaterConstants.MAX_DIST + && findLongestMatch(hashHead)) + { + /* longestMatch sets matchStart and matchLen */ + /*if (DeflaterConstants.DEBUGGING) + { + for (int i = 0 ; i < matchLen; i++) + { + if (window[strstart+i] != window[matchStart + i]) + throw new InternalError(); + } + }*/ + huffman.tallyDist(strstart - matchStart, matchLen); + + lookahead -= matchLen; + if(matchLen <= max_lazy && lookahead >= DeflaterConstants.MIN_MATCH) + { + while(--matchLen > 0) + { + strstart++; + insertString(); + } + strstart++; + } + else + { + strstart += matchLen; + if(lookahead >= DeflaterConstants.MIN_MATCH - 1) + { + updateHash(); + } + } + matchLen = DeflaterConstants.MIN_MATCH - 1; + continue; + } + else + { + /* No match found */ + huffman.tallyLit(window[strstart] & 0xff); + strstart++; + lookahead--; + } + + if(huffman.isFull()) + { + boolean lastBlock = finish && lookahead == 0; + huffman.flushBlock(window, blockStart, strstart - blockStart, + lastBlock); + blockStart = strstart; + return !lastBlock; + } + } + return true; + } + + private boolean deflateSlow(boolean flush, boolean finish) + { + if(lookahead < DeflaterConstants.MIN_LOOKAHEAD && !flush) + { + return false; + } + + while(lookahead >= DeflaterConstants.MIN_LOOKAHEAD || flush) + { + if(lookahead == 0) + { + if(prevAvailable) + { + huffman.tallyLit(window[strstart - 1] & 0xff); + } + prevAvailable = false; + + /* We are flushing everything */ + /*if (DeflaterConstants.DEBUGGING && !flush) + throw new InternalError("Not flushing, but no lookahead");*/ + huffman.flushBlock(window, blockStart, strstart - blockStart, + finish); + blockStart = strstart; + return false; + } + + if(strstart >= 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD) + { + /* slide window, as findLongestMatch need this. + * This should only happen when flushing and the window + * is almost full. + */ + slideWindow(); + } + + int prevMatch = matchStart; + int prevLen = matchLen; + if(lookahead >= DeflaterConstants.MIN_MATCH) + { + int hashHead = insertString(); + if(strategy != Deflater.HUFFMAN_ONLY + && hashHead != 0 && strstart - hashHead <= DeflaterConstants.MAX_DIST + && findLongestMatch(hashHead)) + { + /* longestMatch sets matchStart and matchLen */ + + /* Discard match if too small and too far away */ + if(matchLen <= 5 + && (strategy == Deflater.FILTERED + || (matchLen == DeflaterConstants.MIN_MATCH + && strstart - matchStart > TOO_FAR))) + { + matchLen = DeflaterConstants.MIN_MATCH - 1; + } + } + } + + /* previous match was better */ + if(prevLen >= DeflaterConstants.MIN_MATCH && matchLen <= prevLen) + { + /*if (DeflaterConstants.DEBUGGING) + { + for (int i = 0 ; i < matchLen; i++) + { + if (window[strstart-1+i] != window[prevMatch + i]) + throw new InternalError(); + } + }*/ + huffman.tallyDist(strstart - 1 - prevMatch, prevLen); + prevLen -= 2; + do + { + strstart++; + lookahead--; + if(lookahead >= DeflaterConstants.MIN_MATCH) + { + insertString(); + } + } + while(--prevLen > 0); + strstart++; + lookahead--; + prevAvailable = false; + matchLen = DeflaterConstants.MIN_MATCH - 1; + } + else + { + if(prevAvailable) + { + huffman.tallyLit(window[strstart - 1] & 0xff); + } + prevAvailable = true; + strstart++; + lookahead--; + } + + if(huffman.isFull()) + { + int len = strstart - blockStart; + if(prevAvailable) + { + len--; + } + boolean lastBlock = (finish && lookahead == 0 && !prevAvailable); + huffman.flushBlock(window, blockStart, len, lastBlock); + blockStart += len; + return !lastBlock; + } + } + return true; + } + + public boolean deflate(boolean flush, boolean finish) + { + boolean progress; + do + { + fillWindow(); + boolean canFlush = flush && inputOff == inputEnd; + if(DeflaterConstants.DEBUGGING) + { + System.err.println("window: [" + blockStart + "," + strstart + "," + + lookahead + "], " + comprFunc + "," + canFlush); + } + switch(comprFunc) + { + case DeflaterConstants.DEFLATE_STORED: + progress = deflateStored(canFlush, finish); + break; + case DeflaterConstants.DEFLATE_FAST: + progress = deflateFast(canFlush, finish); + break; + case DeflaterConstants.DEFLATE_SLOW: + progress = deflateSlow(canFlush, finish); + break; + default: + return false; + } + } + while(pending.isFlushed() /* repeat while we have no pending output */ + && progress); /* and progress was made */ + + return progress; + } + + public void setInput(byte[] buf, int off, int len) + { + if(inputOff < inputEnd) + { + throw new IllegalStateException("Old input was not completely processed"); + } + + int end = off + len; + + /* We want to throw an ArrayIndexOutOfBoundsException early. The + * check is very tricky: it also handles integer wrap around. + */ + if(0 > off || off > end || end > buf.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + + inputBuf = buf; + inputOff = off; + inputEnd = end; + } + + public final boolean needsInput() + { + return inputEnd == inputOff; + } +} diff --git a/src/com/classpath/zip/DeflaterHuffman.java b/src/com/classpath/zip/DeflaterHuffman.java new file mode 100644 index 0000000..456f86c --- /dev/null +++ b/src/com/classpath/zip/DeflaterHuffman.java @@ -0,0 +1,797 @@ +/* java.util.zip.DeflaterHuffman + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +/** + * This is the DeflaterHuffman class. + * + * This class is not thread safe. This is inherent in the API, due + * to the split of deflate and setInput. + * + * @author Jochen Hoenicke + * @date Jan 6, 2000 + */ +class DeflaterHuffman +{ + private static final int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6); + private static final int LITERAL_NUM = 286; + private static final int DIST_NUM = 30; + private static final int BITLEN_NUM = 19; + private static final int REP_3_6 = 16; + private static final int REP_3_10 = 17; + private static final int REP_11_138 = 18; + private static final int EOF_SYMBOL = 256; + private static final int[] BL_ORDER = + { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + + private final static String bit4Reverse = + "\000\010\004\014\002\012\006\016\001\011\005\015\003\013\007\017"; + + class Tree + { + short[] freqs; + short[] codes; + byte[] length; + int[] bl_counts; + int minNumCodes, numCodes; + int maxLength; + + Tree (int elems, int minCodes, int maxLength) + { + this.minNumCodes = minCodes; + this.maxLength = maxLength; + freqs = new short[elems]; + bl_counts = new int[maxLength]; + } + + void reset () + { + for (int i = 0; i < freqs.length; i++) + freqs[i] = 0; + codes = null; + length = null; + } + + final void writeSymbol (int code) + { + if (DeflaterConstants.DEBUGGING) + { + freqs[code]--; +// System.err.print("writeSymbol("+freqs.length+","+code+"): "); + } + pending.writeBits (codes[code] & 0xffff, length[code]); + } + + final void checkEmpty () + { + boolean empty = true; + for (int i = 0; i < freqs.length; i++) + if (freqs[i] != 0) + { + System.err.println ("freqs["+i+"] == "+freqs[i]); + empty = false; + } + //if (!empty) + //throw new Exception ();//InternalError(); + System.err.println ("checkEmpty suceeded!"); + } + + void setStaticCodes (short[] stCodes, byte[] stLength) + { + codes = stCodes; + length = stLength; + } + + public void buildCodes () + { + int[] nextCode = new int[maxLength]; + int code = 0; + codes = new short[freqs.length]; + + if (DeflaterConstants.DEBUGGING) + System.err.println ("buildCodes: "+freqs.length); + for (int bits = 0; bits < maxLength; bits++) + { + nextCode[bits] = code; + code += bl_counts[bits] << (15 - bits); + if (DeflaterConstants.DEBUGGING) + System.err.println ("bits: "+(bits+1)+" count: "+bl_counts[bits] + +" nextCode: "+Integer.toHexString (code)); + } + if (DeflaterConstants.DEBUGGING && code != 65536) + throw new RuntimeException ("Inconsistent bl_counts!"); + + for (int i=0; i < numCodes; i++) + { + int bits = length[i]; + if (bits > 0) + { + if (DeflaterConstants.DEBUGGING) + System.err.println ("codes["+i+"] = rev(" + +Integer.toHexString (nextCode[bits-1])+")," + +bits); + codes[i] = bitReverse (nextCode[bits-1]); + nextCode[bits-1] += 1 << (16 - bits); + } + } + } + + private void buildLength (int childs[]) + { + this.length = new byte [freqs.length]; + int numNodes = childs.length / 2; + int numLeafs = (numNodes + 1) / 2; + int overflow = 0; + + for (int i = 0; i < maxLength; i++) + bl_counts[i] = 0; + + /* First calculate optimal bit lengths */ + int lengths[] = new int[numNodes]; + lengths[numNodes-1] = 0; + for (int i = numNodes - 1; i >= 0; i--) + { + if (childs[2*i+1] != -1) + { + int bitLength = lengths[i] + 1; + if (bitLength > maxLength) + { + bitLength = maxLength; + overflow++; + } + lengths[childs[2*i]] = lengths[childs[2*i+1]] = bitLength; + } + else + { + /* A leaf node */ + int bitLength = lengths[i]; + bl_counts[bitLength - 1]++; + this.length[childs[2*i]] = (byte) lengths[i]; + } + } + + if (DeflaterConstants.DEBUGGING) + { + System.err.println ("Tree "+freqs.length+" lengths:"); + for (int i=0; i < numLeafs; i++) + System.err.println ("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]] + + " len: "+length[childs[2*i]]); + } + + if (overflow == 0) + return; + + int incrBitLen = maxLength - 1; + do + { + /* Find the first bit length which could increase: */ + while (bl_counts[--incrBitLen] == 0) + ; + + /* Move this node one down and remove a corresponding + * amount of overflow nodes. + */ + do + { + bl_counts[incrBitLen]--; + bl_counts[++incrBitLen]++; + overflow -= 1 << (maxLength - 1 - incrBitLen); + } + while (overflow > 0 && incrBitLen < maxLength - 1); + } + while (overflow > 0); + + /* We may have overshot above. Move some nodes from maxLength to + * maxLength-1 in that case. + */ + bl_counts[maxLength-1] += overflow; + bl_counts[maxLength-2] -= overflow; + + /* Now recompute all bit lengths, scanning in increasing + * frequency. It is simpler to reconstruct all lengths instead of + * fixing only the wrong ones. This idea is taken from 'ar' + * written by Haruhiko Okumura. + * + * The nodes were inserted with decreasing frequency into the childs + * array. + */ + int nodePtr = 2 * numLeafs; + for (int bits = maxLength; bits != 0; bits--) + { + int n = bl_counts[bits-1]; + while (n > 0) + { + int childPtr = 2*childs[nodePtr++]; + if (childs[childPtr + 1] == -1) + { + /* We found another leaf */ + length[childs[childPtr]] = (byte) bits; + n--; + } + } + } + if (DeflaterConstants.DEBUGGING) + { + System.err.println ("*** After overflow elimination. ***"); + for (int i=0; i < numLeafs; i++) + System.err.println ("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]] + + " len: "+length[childs[2*i]]); + } + } + + void buildTree () + { + int numSymbols = freqs.length; + + /* heap is a priority queue, sorted by frequency, least frequent + * nodes first. The heap is a binary tree, with the property, that + * the parent node is smaller than both child nodes. This assures + * that the smallest node is the first parent. + * + * The binary tree is encoded in an array: 0 is root node and + * the nodes 2*n+1, 2*n+2 are the child nodes of node n. + */ + int[] heap = new int[numSymbols]; + int heapLen = 0; + int maxCode = 0; + for (int n = 0; n < numSymbols; n++) + { + int freq = freqs[n]; + if (freq != 0) + { + /* Insert n into heap */ + int pos = heapLen++; + int ppos; + while (pos > 0 && + freqs[heap[ppos = (pos - 1) / 2]] > freq) + { + heap[pos] = heap[ppos]; + pos = ppos; + } + heap[pos] = n; + maxCode = n; + } + } + + /* We could encode a single literal with 0 bits but then we + * don't see the literals. Therefore we force at least two + * literals to avoid this case. We don't care about order in + * this case, both literals get a 1 bit code. + */ + while (heapLen < 2) + { + int node = maxCode < 2 ? ++maxCode : 0; + heap[heapLen++] = node; + } + + numCodes = Math.max (maxCode + 1, minNumCodes); + + int numLeafs = heapLen; + int[] childs = new int[4*heapLen - 2]; + int[] values = new int[2*heapLen - 1]; + int numNodes = numLeafs; + for (int i = 0; i < heapLen; i++) + { + int node = heap[i]; + childs[2*i] = node; + childs[2*i+1] = -1; + values[i] = freqs[node] << 8; + heap[i] = i; + } + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + do + { + int first = heap[0]; + int last = heap[--heapLen]; + + /* Propagate the hole to the leafs of the heap */ + int ppos = 0; + int path = 1; + while (path < heapLen) + { + if (path + 1 < heapLen + && values[heap[path]] > values[heap[path+1]]) + path++; + + heap[ppos] = heap[path]; + ppos = path; + path = path * 2 + 1; + } + + /* Now propagate the last element down along path. Normally + * it shouldn't go too deep. + */ + int lastVal = values[last]; + while ((path = ppos) > 0 + && values[heap[ppos = (path - 1)/2]] > lastVal) + heap[path] = heap[ppos]; + heap[path] = last; + + + int second = heap[0]; + + /* Create a new node father of first and second */ + last = numNodes++; + childs[2*last] = first; + childs[2*last+1] = second; + int mindepth = Math.min (values[first] & 0xff, values[second] & 0xff); + values[last] = lastVal = values[first] + values[second] - mindepth + 1; + + /* Again, propagate the hole to the leafs */ + ppos = 0; + path = 1; + while (path < heapLen) + { + if (path + 1 < heapLen + && values[heap[path]] > values[heap[path+1]]) + path++; + + heap[ppos] = heap[path]; + ppos = path; + path = ppos * 2 + 1; + } + + /* Now propagate the new element down along path */ + while ((path = ppos) > 0 + && values[heap[ppos = (path - 1)/2]] > lastVal) + heap[path] = heap[ppos]; + heap[path] = last; + } + while (heapLen > 1); + + if (heap[0] != childs.length / 2 - 1) + throw new RuntimeException ("Weird!"); + + buildLength (childs); + } + + int getEncodedLength () + { + int len = 0; + for (int i = 0; i < freqs.length; i++) + len += freqs[i] * length[i]; + return len; + } + + void calcBLFreq (Tree blTree) + { + int max_count; /* max repeat count */ + int min_count; /* min repeat count */ + int count; /* repeat count of the current code */ + int curlen = -1; /* length of current code */ + + int i = 0; + while (i < numCodes) + { + count = 1; + int nextlen = length[i]; + if (nextlen == 0) + { + max_count = 138; + min_count = 3; + } + else + { + max_count = 6; + min_count = 3; + if (curlen != nextlen) + { + blTree.freqs[nextlen]++; + count = 0; + } + } + curlen = nextlen; + i++; + + while (i < numCodes && curlen == length[i]) + { + i++; + if (++count >= max_count) + break; + } + + if (count < min_count) + blTree.freqs[curlen] += count; + else if (curlen != 0) + blTree.freqs[REP_3_6]++; + else if (count <= 10) + blTree.freqs[REP_3_10]++; + else + blTree.freqs[REP_11_138]++; + } + } + + void writeTree (Tree blTree) + { + int max_count; /* max repeat count */ + int min_count; /* min repeat count */ + int count; /* repeat count of the current code */ + int curlen = -1; /* length of current code */ + + int i = 0; + while (i < numCodes) + { + count = 1; + int nextlen = length[i]; + if (nextlen == 0) + { + max_count = 138; + min_count = 3; + } + else + { + max_count = 6; + min_count = 3; + if (curlen != nextlen) + { + blTree.writeSymbol (nextlen); + count = 0; + } + } + curlen = nextlen; + i++; + + while (i < numCodes && curlen == length[i]) + { + i++; + if (++count >= max_count) + break; + } + + if (count < min_count) + { + while (count-- > 0) + blTree.writeSymbol (curlen); + } + else if (curlen != 0) + { + blTree.writeSymbol (REP_3_6); + pending.writeBits (count - 3, 2); + } + else if (count <= 10) + { + blTree.writeSymbol (REP_3_10); + pending.writeBits (count - 3, 3); + } + else + { + blTree.writeSymbol (REP_11_138); + pending.writeBits (count - 11, 7); + } + } + } + } + + + + DeflaterPending pending; + private Tree literalTree, distTree, blTree; + + private short d_buf[]; + private byte l_buf[]; + private int last_lit; + private int extra_bits; + + private static short staticLCodes[]; + private static byte staticLLength[]; + private static short staticDCodes[]; + private static byte staticDLength[]; + + /** + * Reverse the bits of a 16 bit value. + */ + static short bitReverse (int value) + { + return (short) (bit4Reverse.charAt (value & 0xf) << 12 + | bit4Reverse.charAt ((value >> 4) & 0xf) << 8 + | bit4Reverse.charAt ((value >> 8) & 0xf) << 4 + | bit4Reverse.charAt (value >> 12)); + } + + static + { + /* See RFC 1951 3.2.6 */ + /* Literal codes */ + staticLCodes = new short[LITERAL_NUM]; + staticLLength = new byte[LITERAL_NUM]; + int i = 0; + while (i < 144) + { + staticLCodes[i] = bitReverse ((0x030 + i) << 8); + staticLLength[i++] = 8; + } + while (i < 256) + { + staticLCodes[i] = bitReverse ((0x190 - 144 + i) << 7); + staticLLength[i++] = 9; + } + while (i < 280) + { + staticLCodes[i] = bitReverse ((0x000 - 256 + i) << 9); + staticLLength[i++] = 7; + } + while (i < LITERAL_NUM) + { + staticLCodes[i] = bitReverse ((0x0c0 - 280 + i) << 8); + staticLLength[i++] = 8; + } + + /* Distant codes */ + staticDCodes = new short[DIST_NUM]; + staticDLength = new byte[DIST_NUM]; + for (i = 0; i < DIST_NUM; i++) + { + staticDCodes[i] = bitReverse (i << 11); + staticDLength[i] = 5; + } + } + + public DeflaterHuffman (DeflaterPending pending) + { + this.pending = pending; + + literalTree = new Tree (LITERAL_NUM, 257, 15); + distTree = new Tree (DIST_NUM, 1, 15); + blTree = new Tree (BITLEN_NUM, 4, 7); + + d_buf = new short[BUFSIZE]; + l_buf = new byte [BUFSIZE]; + } + + public final void reset () + { + last_lit = 0; + extra_bits = 0; + literalTree.reset (); + distTree.reset (); + blTree.reset (); + } + + private final int l_code (int len) + { + if (len == 255) + return 285; + + int code = 257; + while (len >= 8) + { + code += 4; + len >>= 1; + } + return code + len; + } + + private final int d_code (int distance) + { + int code = 0; + while (distance >= 4) + { + code += 2; + distance >>= 1; + } + return code + distance; + } + + public void sendAllTrees (int blTreeCodes) + { + blTree.buildCodes (); + literalTree.buildCodes (); + distTree.buildCodes (); + pending.writeBits (literalTree.numCodes - 257, 5); + pending.writeBits (distTree.numCodes - 1, 5); + pending.writeBits (blTreeCodes - 4, 4); + for (int rank = 0; rank < blTreeCodes; rank++) + pending.writeBits (blTree.length[BL_ORDER[rank]], 3); + literalTree.writeTree (blTree); + distTree.writeTree (blTree); + if (DeflaterConstants.DEBUGGING) + blTree.checkEmpty (); + } + + public void compressBlock () + { + for (int i = 0; i < last_lit; i++) + { + int litlen = l_buf[i] & 0xff; + int dist = d_buf[i]; + if (dist-- != 0) + { + if (DeflaterConstants.DEBUGGING) + System.err.print ("["+(dist+1)+","+(litlen+3)+"]: "); + + int lc = l_code (litlen); + literalTree.writeSymbol (lc); + + int bits = (lc - 261) / 4; + if (bits > 0 && bits <= 5) + pending.writeBits (litlen & ((1 << bits) - 1), bits); + + int dc = d_code (dist); + distTree.writeSymbol (dc); + + bits = dc / 2 - 1; + if (bits > 0) + pending.writeBits (dist & ((1 << bits) - 1), bits); + } + else + { + if (DeflaterConstants.DEBUGGING) + { + if (litlen > 32 && litlen < 127) + System.err.print ("("+(char)litlen+"): "); + else + System.err.print ("{"+litlen+"}: "); + } + literalTree.writeSymbol (litlen); + } + } + if (DeflaterConstants.DEBUGGING) + System.err.print ("EOF: "); + literalTree.writeSymbol (EOF_SYMBOL); + if (DeflaterConstants.DEBUGGING) + { + literalTree.checkEmpty (); + distTree.checkEmpty (); + } + } + + public void flushStoredBlock (byte[] stored, + int stored_offset, int stored_len, + boolean lastBlock) + { + if (DeflaterConstants.DEBUGGING) + System.err.println ("Flushing stored block "+ stored_len); + pending.writeBits ((DeflaterConstants.STORED_BLOCK << 1) + + (lastBlock ? 1 : 0), 3); + pending.alignToByte (); + pending.writeShort (stored_len); + pending.writeShort (~stored_len); + pending.writeBlock (stored, stored_offset, stored_len); + reset (); + } + + public void flushBlock (byte[] stored, int stored_offset, int stored_len, + boolean lastBlock) + { + literalTree.freqs[EOF_SYMBOL]++; + + /* Build trees */ + literalTree.buildTree (); + distTree.buildTree (); + + /* Calculate bitlen frequency */ + literalTree.calcBLFreq (blTree); + distTree.calcBLFreq (blTree); + + /* Build bitlen tree */ + blTree.buildTree (); + + int blTreeCodes = 4; + for (int i = 18; i > blTreeCodes; i--) + { + if (blTree.length[BL_ORDER[i]] > 0) + blTreeCodes = i+1; + } + int opt_len = 14 + blTreeCodes * 3 + blTree.getEncodedLength () + + literalTree.getEncodedLength () + distTree.getEncodedLength () + + extra_bits; + + int static_len = extra_bits; + for (int i = 0; i < LITERAL_NUM; i++) + static_len += literalTree.freqs[i] * staticLLength[i]; + for (int i = 0; i < DIST_NUM; i++) + static_len += distTree.freqs[i] * staticDLength[i]; + if (opt_len >= static_len) + { + /* Force static trees */ + opt_len = static_len; + } + + if (stored_offset >= 0 && stored_len+4 < opt_len >> 3) + { + /* Store Block */ + if (DeflaterConstants.DEBUGGING) + System.err.println ("Storing, since " + stored_len + " < " + opt_len + + " <= " + static_len); + flushStoredBlock (stored, stored_offset, stored_len, lastBlock); + } + else if (opt_len == static_len) + { + /* Encode with static tree */ + pending.writeBits ((DeflaterConstants.STATIC_TREES << 1) + + (lastBlock ? 1 : 0), 3); + literalTree.setStaticCodes (staticLCodes, staticLLength); + distTree.setStaticCodes (staticDCodes, staticDLength); + compressBlock (); + reset (); + } + else + { + /* Encode with dynamic tree */ + pending.writeBits ((DeflaterConstants.DYN_TREES << 1) + + (lastBlock ? 1 : 0), 3); + sendAllTrees (blTreeCodes); + compressBlock (); + reset (); + } + } + + public final boolean isFull () + { + return last_lit == BUFSIZE; + } + + public final boolean tallyLit (int lit) + { + if (DeflaterConstants.DEBUGGING) + { + if (lit > 32 && lit < 127) + System.err.println ("("+(char)lit+")"); + else + System.err.println ("{"+lit+"}"); + } + d_buf[last_lit] = 0; + l_buf[last_lit++] = (byte) lit; + literalTree.freqs[lit]++; + return last_lit == BUFSIZE; + } + + public final boolean tallyDist (int dist, int len) + { + if (DeflaterConstants.DEBUGGING) + System.err.println ("["+dist+","+len+"]"); + + d_buf[last_lit] = (short) dist; + l_buf[last_lit++] = (byte) (len - 3); + + int lc = l_code (len-3); + literalTree.freqs[lc]++; + if (lc >= 265 && lc < 285) + extra_bits += (lc - 261) / 4; + + int dc = d_code (dist-1); + distTree.freqs[dc]++; + if (dc >= 4) + extra_bits += dc / 2 - 1; + return last_lit == BUFSIZE; + } +} diff --git a/src/com/classpath/zip/DeflaterOutputStream.java b/src/com/classpath/zip/DeflaterOutputStream.java new file mode 100644 index 0000000..310034c --- /dev/null +++ b/src/com/classpath/zip/DeflaterOutputStream.java @@ -0,0 +1,223 @@ +/* DeflaterOutputStream.java - Output filter for compressing. + Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package com.classpath.zip; + +import java.io.OutputStream; +import java.io.IOException; + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +/** + * This is a special FilterOutputStream deflating the bytes that are + * written through it. It uses the Deflater for deflating. + * + * A special thing to be noted is that flush() doesn't flush + * everything in Sun's JDK, but it does so in jazzlib. This is because + * Sun's Deflater doesn't have a way to flush() everything, without + * finishing the stream. + * + * @author Tom Tromey, Jochen Hoenicke + * @date Jan 11, 2001 + */ +public class DeflaterOutputStream extends OutputStream +{ + protected OutputStream out; + /** + * This buffer is used temporarily to retrieve the bytes from the + * deflater and write them to the underlying output stream. + */ + protected byte[] buf; + + /** + * The deflater which is used to deflate the stream. + */ + protected Deflater def; + + /** + * Deflates everything in the def's input buffers. This will call + * def.deflate() until all bytes from the input buffers + * are processed. + */ + protected void deflate() throws IOException + { + while(!def.needsInput()) + { + int len = def.deflate(buf, 0, buf.length); + + // System.err.println("DOS deflated " + len + " out of " + buf.length); + + if(len <= 0) + { + break; + } + + out.write(buf, 0, len); + } + + if(!def.needsInput()) + { + throw new IOException("Can't deflate all input?"); + } + } + + /** + * Creates a new DeflaterOutputStream with a default Deflater and + * default buffer size. + * @param out the output stream where deflated output should be written. + */ + public DeflaterOutputStream(OutputStream out) + { + this(out, new Deflater(), 512); + } + + /** + * Creates a new DeflaterOutputStream with the given Deflater and + * default buffer size. + * @param out the output stream where deflated output should be written. + * @param defl the underlying deflater. + */ + public DeflaterOutputStream(OutputStream out, Deflater defl) + { + this(out, defl, 512); + } + + /** + * Creates a new DeflaterOutputStream with the given Deflater and + * buffer size. + * @param out the output stream where deflated output should be written. + * @param defl the underlying deflater. + * @param bufsize the buffer size. + * @exception IllegalArgumentException if bufsize isn't positive. + */ + public DeflaterOutputStream(OutputStream out, Deflater defl, int bufsize) + { + //super (out); + this.out = out; + if(bufsize <= 0) + throw new IllegalArgumentException("bufsize <= 0"); + buf = new byte[bufsize]; + def = defl; + } + + public void setLevel(int level) + { + def.setLevel(level); + } + + /** + * Flushes the stream by calling flush() on the deflater and then + * on the underlying stream. This ensures that all bytes are + * flushed. This function doesn't work in Sun's JDK, but only in + * jazzlib. + */ + public void flush() throws IOException + { + def.flush(); + deflate(); + out.flush(); + } + + /** + * Finishes the stream by calling finish() on the deflater. This + * was the only way to ensure that all bytes are flushed in Sun's + * JDK. + */ + public void finish() throws IOException + { + def.finish(); + + while(!def.finished()) + { + int len = def.deflate(buf, 0, buf.length); + + if(len <= 0) + { + break; + } + + out.write(buf, 0, len); + } + + if(!def.finished()) + { + throw new IOException("Can't deflate all input?"); + } + + out.flush(); + } + + /** + * Calls finish () and closes the stream. + */ + public void close() throws IOException + { + finish(); + out.close(); + } + + public int getTotalOut() + { + return def.getTotalOut(); + } + + /** + * Writes a single byte to the compressed output stream. + * @param bval the byte value. + */ + public void write(int bval) throws IOException + { + byte[] b = new byte[1]; + b[0] = (byte)bval; + write(b, 0, 1); + } + + /** + * Writes a len bytes from an array to the compressed stream. + * @param buf the byte array. + * @param off the offset into the byte array where to start. + * @param len the number of bytes to write. + */ + public void write(byte[] buf, int off, int len) throws IOException + { + def.setInput(buf, off, len); + deflate(); + } +} diff --git a/src/com/classpath/zip/DeflaterPending.java b/src/com/classpath/zip/DeflaterPending.java new file mode 100644 index 0000000..5e19303 --- /dev/null +++ b/src/com/classpath/zip/DeflaterPending.java @@ -0,0 +1,55 @@ +/* java.util.zip.DeflaterPending + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +/** + * This class stores the pending output of the Deflater. + * + * @author Jochen Hoenicke + * @date Jan 5, 2000 + */ + +class DeflaterPending extends PendingBuffer +{ + public DeflaterPending () + { + super (DeflaterConstants.PENDING_BUF_SIZE); + } +} + diff --git a/src/com/classpath/zip/GZIPInputStream.java b/src/com/classpath/zip/GZIPInputStream.java new file mode 100644 index 0000000..730b941 --- /dev/null +++ b/src/com/classpath/zip/GZIPInputStream.java @@ -0,0 +1,356 @@ +/* GZIPInputStream.java - Input filter for reading gzip file + Copyright (C) 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +//package java.util.zip; +package com.classpath.zip; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +/** + * This filter stream is used to decompress a "GZIP" format stream. + * The "GZIP" format is described in RFC 1952. + * + * @author John Leuner + * @author Tom Tromey + * @since JDK 1.1 + */ +public class GZIPInputStream + extends InflaterInputStream +{ + /** + * The magic number found at the start of a GZIP stream. + */ + public static final int GZIP_MAGIC = 0x8b1f; + + /** + * The mask for bit 0 of the flag byte. + */ + static final int FTEXT = 0x1; + + /** + * The mask for bit 1 of the flag byte. + */ + static final int FHCRC = 0x2; + + /** + * The mask for bit 2 of the flag byte. + */ + static final int FEXTRA = 0x4; + + /** + * The mask for bit 3 of the flag byte. + */ + static final int FNAME = 0x8; + + /** + * The mask for bit 4 of the flag byte. + */ + static final int FCOMMENT = 0x10; + + /** + * The CRC-32 checksum value for uncompressed data. + */ + protected CRC32 crc; + + /** + * Indicates whether or not the end of the stream has been reached. + */ + protected boolean eos; + + /** + * Indicates whether or not the GZIP header has been read in. + */ + private boolean readGZIPHeader; + + /** + * Creates a GZIPInputStream with the default buffer size. + * + * @param in The stream to read compressed data from + * (in GZIP format). + * + * @throws IOException if an error occurs during an I/O operation. + */ + public GZIPInputStream(InputStream in) + throws IOException + { + this(in, 4096); + } + + /** + * Creates a GZIPInputStream with the specified buffer size. + * + * @param in The stream to read compressed data from + * (in GZIP format). + * @param size The size of the buffer to use. + * + * @throws IOException if an error occurs during an I/O operation. + * @throws IllegalArgumentException if size + * is less than or equal to 0. + */ + public GZIPInputStream(InputStream in, int size) + throws IOException + { + super(in, new Inflater(true), size); + crc = new CRC32(); + readHeader(); + } + + /** + * Closes the input stream. + * + * @throws IOException if an error occurs during an I/O operation. + */ + public void close() + throws IOException + { + // Nothing to do here. + super.close(); + } + + /** + * Reads in GZIP-compressed data and stores it in uncompressed form + * into an array of bytes. The method will block until either + * enough input data becomes available or the compressed stream + * reaches its end. + * + * @param buf the buffer into which the uncompressed data will + * be stored. + * @param offset the offset indicating where in buf + * the uncompressed data should be placed. + * @param len the number of uncompressed bytes to be read. + */ + public int read(byte[] buf, int offset, int len) throws IOException + { + // We first have to slurp in the GZIP header, then we feed all the + // rest of the data to the superclass. + // + // As we do that we continually update the CRC32. Once the data is + // finished, we check the CRC32. + // + // This means we don't need our own buffer, as everything is done + // in the superclass. + if(!readGZIPHeader) + readHeader(); + + if(eos) + return -1; + + // System.err.println("GZIPIS.read(byte[], off, len ... " + offset + " and len " + len); + + /* We don't have to read the header, + * so we just grab data from the superclass. + */ + int numRead = super.read(buf, offset, len); + if(numRead > 0) + crc.update(buf, offset, numRead); + + if(inf.finished()) + readFooter(); + return numRead; + } + + + /** + * Reads in the GZIP header. + */ + private void readHeader() throws IOException + { + /* 1. Check the two magic bytes */ + CRC32 headCRC = new CRC32(); + int magic = in.read(); + if(magic < 0) + { + eos = true; + return; + } + int magic2 = in.read(); + if((magic + (magic2 << 8)) != GZIP_MAGIC) + throw new IOException("Error in GZIP header, bad magic code"); + headCRC.update(magic); + headCRC.update(magic2); + + /* 2. Check the compression type (must be 8) */ + int CM = in.read(); + if(CM != Deflater.DEFLATED) + throw new IOException("Error in GZIP header, data not in deflate format"); + headCRC.update(CM); + + /* 3. Check the flags */ + int flags = in.read(); + if(flags < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(flags); + + /* This flag byte is divided into individual bits as follows: + + bit 0 FTEXT + bit 1 FHCRC + bit 2 FEXTRA + bit 3 FNAME + bit 4 FCOMMENT + bit 5 reserved + bit 6 reserved + bit 7 reserved + */ + + /* 3.1 Check the reserved bits are zero */ + if((flags & 0xd0) != 0) + throw new IOException("Reserved flag bits in GZIP header != 0"); + + /* 4.-6. Skip the modification time, extra flags, and OS type */ + for(int i = 0; i < 6; i++) + { + int readByte = in.read(); + if(readByte < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(readByte); + } + + /* 7. Read extra field */ + if((flags & FEXTRA) != 0) + { + /* Skip subfield id */ + for(int i = 0; i < 2; i++) + { + int readByte = in.read(); + if(readByte < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(readByte); + } + if(in.read() < 0 || in.read() < 0) + throw new EOFException("Early EOF in GZIP header"); + + int len1, len2, extraLen; + len1 = in.read(); + len2 = in.read(); + if((len1 < 0) || (len2 < 0)) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(len1); + headCRC.update(len2); + + extraLen = (len1 << 8) | len2; + for(int i = 0; i < extraLen; i++) + { + int readByte = in.read(); + if(readByte < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(readByte); + } + } + + /* 8. Read file name */ + if((flags & FNAME) != 0) + { + int readByte; + while((readByte = in.read()) > 0) + headCRC.update(readByte); + if(readByte < 0) + throw new EOFException("Early EOF in GZIP file name"); + headCRC.update(readByte); + } + + /* 9. Read comment */ + if((flags & FCOMMENT) != 0) + { + int readByte; + while((readByte = in.read()) > 0) + headCRC.update(readByte); + + if(readByte < 0) + throw new EOFException("Early EOF in GZIP comment"); + headCRC.update(readByte); + } + + /* 10. Read header CRC */ + if((flags & FHCRC) != 0) + { + int tempByte; + int crcval = in.read(); + if(crcval < 0) + throw new EOFException("Early EOF in GZIP header"); + + tempByte = in.read(); + if(tempByte < 0) + throw new EOFException("Early EOF in GZIP header"); + + crcval = (crcval << 8) | tempByte; + if(crcval != ((int)headCRC.getValue() & 0xffff)) + throw new IOException("Header CRC value mismatch"); + } + + readGZIPHeader = true; + //System.err.println("Read GZIP header"); + } + + private void readFooter() throws IOException + { + byte[] footer = new byte[8]; + int avail = inf.getRemaining(); + if(avail > 8) + avail = 8; + System.arraycopy(buf, len - inf.getRemaining(), footer, 0, avail); + int needed = 8 - avail; + while(needed > 0) + { + int count = in.read(footer, 8 - needed, needed); + if(count <= 0) + throw new EOFException("Early EOF in GZIP footer"); + needed -= count; //Jewel Jan 16 + } + + int crcval = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8) + | ((footer[2] & 0xff) << 16) | (footer[3] << 24); + if(crcval != (int)crc.getValue()) + throw new IOException("GZIP crc sum mismatch, theirs \"" + + Integer.toHexString(crcval) + + "\" and ours \"" + + Integer.toHexString((int)crc.getValue())); + + int total = (footer[4] & 0xff) | ((footer[5] & 0xff) << 8) + | ((footer[6] & 0xff) << 16) | (footer[7] << 24); + if(total != inf.getTotalOut()) + throw new IOException("Number of bytes mismatch"); + + /* FIXME" XXX Should we support multiple members. + * Difficult, since there may be some bytes still in buf + */ + eos = true; + } +} diff --git a/src/com/classpath/zip/GZIPOutputStream.java b/src/com/classpath/zip/GZIPOutputStream.java new file mode 100644 index 0000000..4db160a --- /dev/null +++ b/src/com/classpath/zip/GZIPOutputStream.java @@ -0,0 +1,152 @@ +/* GZIPOutputStream.java - Create a file in gzip format + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * This filter stream is used to compress a stream into a "GZIP" stream. + * The "GZIP" format is described in RFC 1952. + * + * @author John Leuner + * @author Tom Tromey + * @since JDK 1.1 + */ + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +public class GZIPOutputStream extends DeflaterOutputStream +{ + /** + * CRC-32 value for uncompressed data + */ + protected CRC32 crc; + + /** + * Creates a GZIPOutputStream with the default buffer size + * + * @param out The stream to read data (to be compressed) from + * + */ + public GZIPOutputStream(OutputStream out) throws IOException + { + this(out, 4096); + } + + /** + * Creates a GZIPOutputStream with the specified buffer size + * + * @param out The stream to read compressed data from + * @param size Size of the buffer to use + */ + public GZIPOutputStream(OutputStream out, int size) throws IOException + { + super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size); + crc = new CRC32(); + int mod_time = (int)(System.currentTimeMillis() / 1000L); + byte[] gzipHeader = + { + /* The two magic bytes */ + (byte) GZIPInputStream.GZIP_MAGIC, + (byte) (GZIPInputStream.GZIP_MAGIC >> 8), + + /* The compression type */ + (byte) Deflater.DEFLATED, + + /* The flags (not set) */ + 0, + + /* The modification time */ + (byte) mod_time, (byte) (mod_time >> 8), + (byte) (mod_time >> 16), (byte) (mod_time >> 24), + + /* The extra flags */ + 0, + + /* The OS type (unknown) */ + (byte) 255 + }; + + out.write(gzipHeader); + // System.err.println("wrote GZIP header (" + gzipHeader.length + " bytes )"); + } + + public synchronized void write(byte[] buf, int off, int len) + throws IOException + { + super.write(buf, off, len); + crc.update(buf, off, len); + } + + /** + * Writes remaining compressed output data to the output stream + * and closes it. + */ + public void close() throws IOException + { + finish(); + out.close(); + } + + public void finish() throws IOException + { + super.finish(); + + int totalin = def.getTotalIn(); + int crcval = (int)(crc.getValue() & 0xffffffff); + + // System.err.println("CRC val is " + Integer.toHexString( crcval ) + " and length " + Integer.toHexString(totalin)); + + byte[] gzipFooter = + { + (byte) crcval, (byte) (crcval >> 8), + (byte) (crcval >> 16), (byte) (crcval >> 24), + + (byte) totalin, (byte) (totalin >> 8), + (byte) (totalin >> 16), (byte) (totalin >> 24) + }; + + out.write(gzipFooter); + // System.err.println("wrote GZIP trailer (" + gzipFooter.length + " bytes )"); + } +} diff --git a/src/com/classpath/zip/Inflater.java b/src/com/classpath/zip/Inflater.java new file mode 100644 index 0000000..7431c09 --- /dev/null +++ b/src/com/classpath/zip/Inflater.java @@ -0,0 +1,743 @@ +/* Inflater.java - Decompress a data stream + Copyright (C) 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +/** + * Inflater is used to decompress data that has been compressed according + * to the "deflate" standard described in rfc1950. + * + * The usage is as following. First you have to set some input with + * setInput(), then inflate() it. If inflate doesn't + * inflate any bytes there may be three reasons: + *

    + *
  • needsInput() returns true because the input buffer is empty. + * You have to provide more input with setInput(). + * NOTE: needsInput() also returns true when, the stream is finished. + *
  • + *
  • needsDictionary() returns true, you have to provide a preset + * dictionary with setDictionary().
  • + *
  • finished() returns true, the inflater has finished.
  • + *
+ * Once the first output byte is produced, a dictionary will not be + * needed at a later stage. + * + * @author John Leuner, Jochen Hoenicke + * @author Tom Tromey + * @date May 17, 1999 + * @since JDK 1.1 + */ +public class Inflater +{ + /* Copy lengths for literal codes 257..285 */ + private static final int CPLENS[] = + { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 + }; + + /* Extra bits for literal codes 257..285 */ + private static final int CPLEXT[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 + }; + + /* Copy offsets for distance codes 0..29 */ + private static final int CPDIST[] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577 + }; + + /* Extra bits for distance codes */ + private static final int CPDEXT[] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13 + }; + + /* This are the state in which the inflater can be. */ + private static final int DECODE_HEADER = 0; + private static final int DECODE_DICT = 1; + private static final int DECODE_BLOCKS = 2; + private static final int DECODE_STORED_LEN1 = 3; + private static final int DECODE_STORED_LEN2 = 4; + private static final int DECODE_STORED = 5; + private static final int DECODE_DYN_HEADER = 6; + private static final int DECODE_HUFFMAN = 7; + private static final int DECODE_HUFFMAN_LENBITS = 8; + private static final int DECODE_HUFFMAN_DIST = 9; + private static final int DECODE_HUFFMAN_DISTBITS = 10; + private static final int DECODE_CHKSUM = 11; + private static final int FINISHED = 12; + + /** This variable contains the current state. */ + private int mode; + + /** + * The adler checksum of the dictionary or of the decompressed + * stream, as it is written in the header resp. footer of the + * compressed stream.
+ * + * Only valid if mode is DECODE_DICT or DECODE_CHKSUM. + */ + private int readAdler; + /** + * The number of bits needed to complete the current state. This + * is valid, if mode is DECODE_DICT, DECODE_CHKSUM, + * DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS. + */ + private int neededBits; + private int repLength, repDist; + private int uncomprLen; + /** + * True, if the last block flag was set in the last block of the + * inflated stream. This means that the stream ends after the + * current block. + */ + private boolean isLastBlock; + + /** + * The total number of inflated bytes. + */ + private long totalOut; + /** + * The total number of bytes set with setInput(). This is not the + * value returned by getTotalIn(), since this also includes the + * unprocessed input. + */ + private long totalIn; + /** + * This variable stores the nowrap flag that was given to the constructor. + * True means, that the inflated stream doesn't contain a header nor the + * checksum in the footer. + */ + private boolean nowrap; + + private StreamManipulator input; + private OutputWindow outputWindow; + private InflaterDynHeader dynHeader; + private InflaterHuffmanTree litlenTree, distTree; + private Adler32 adler; + + /** + * Creates a new inflater. + */ + public Inflater() + { + this(false); + } + + /** + * Creates a new inflater. + * @param nowrap true if no header and checksum field appears in the + * stream. This is used for GZIPed input. For compatibility with + * Sun JDK you should provide one byte of input more than needed in + * this case. + */ + public Inflater(boolean nowrap) + { + this.nowrap = nowrap; + this.adler = new Adler32(); + input = new StreamManipulator(); + outputWindow = new OutputWindow(); + mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER; + } + + // /** + // * Finalizes this object. + // */ + // protected void finalize () + // { + // /* Exists only for compatibility */ + // } + + /** + * Frees all objects allocated by the inflater. There's no reason + * to call this, since you can just rely on garbage collection (even + * for the Sun implementation). Exists only for compatibility + * with Sun's JDK, where the compressor allocates native memory. + * If you call any method (even reset) afterwards the behaviour is + * undefined. + */ + public void end() + { + outputWindow = null; + input = null; + dynHeader = null; + litlenTree = null; + distTree = null; + adler = null; + } + + /** + * Returns true, if the inflater has finished. This means, that no + * input is needed and no output can be produced. + */ + public boolean finished() + { + return mode == FINISHED && outputWindow.getAvailable() == 0; + } + + /** + * Gets the adler checksum. This is either the checksum of all + * uncompressed bytes returned by inflate(), or if needsDictionary() + * returns true (and thus no output was yet produced) this is the + * adler checksum of the expected dictionary. + * @returns the adler checksum. + */ + public int getAdler() + { + return needsDictionary() ? readAdler : (int)adler.getValue(); + } + + /** + * Gets the number of unprocessed input. Useful, if the end of the + * stream is reached and you want to further process the bytes after + * the deflate stream. + * @return the number of bytes of the input which were not processed. + */ + public int getRemaining() + { + return input.getAvailableBytes(); + } + + /** + * Gets the total number of processed compressed input bytes. + * @return the total number of bytes of processed input bytes. + */ + /* @Deprecated */ + public int getTotalIn() + { + return (int)(totalIn - getRemaining()); + } + + /** + * Gets the total number of processed compressed input bytes. + * @return the total number of bytes of processed input bytes. + * @since 1.5 + */ + public long getBytesRead() + { + return totalIn - getRemaining(); + } + + /** + * Gets the total number of output bytes returned by inflate(). + * @return the total number of output bytes. + */ + /* @Deprecated */ + public int getTotalOut() + { + return (int)totalOut; + } + + /** + * Gets the total number of output bytes returned by inflate(). + * @return the total number of output bytes. + * @since 1.5 + */ + public long getBytesWritten() + { + return totalOut; + } + + /** + * Inflates the compressed stream to the output buffer. If this + * returns 0, you should check, whether needsDictionary(), + * needsInput() or finished() returns true, to determine why no + * further output is produced. + * @param buf the output buffer. + * @return the number of bytes written to the buffer, 0 if no further + * output can be produced. + * @exception DataFormatException if deflated stream is invalid. + * @exception IllegalArgumentException if buf has length 0. + */ + public int inflate(byte[] buf) throws DataFormatException + { + return inflate(buf, 0, buf.length); + } + + /** + * Inflates the compressed stream to the output buffer. If this + * returns 0, you should check, whether needsDictionary(), + * needsInput() or finished() returns true, to determine why no + * further output is produced. + * @param buf the output buffer. + * @param off the offset into buffer where the output should start. + * @param len the maximum length of the output. + * @return the number of bytes written to the buffer, 0 if no further + * output can be produced. + * @exception DataFormatException if deflated stream is invalid. + * @exception IndexOutOfBoundsException if the off and/or len are wrong. + */ + public int inflate(byte[] buf, int off, int len) throws DataFormatException + { + /* Special case: len may be zero */ + if(len == 0) + { + return 0; + } + + /* Check for correct buff, off, len triple */ + if(0 > off || off > off + len || off + len > buf.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + + int count = 0; + int more; + do + { + if(mode != DECODE_CHKSUM) + { + /* Don't give away any output, if we are waiting for the + * checksum in the input stream. + * + * With this trick we have always: + * needsInput() and not finished() + * implies more output can be produced. + */ + more = outputWindow.copyOutput(buf, off, len); + adler.update(buf, off, more); + off += more; + count += more; + totalOut += more; + len -= more; + if(len == 0) + return count; + } + } + while(decode() || (outputWindow.getAvailable() > 0 + && mode != DECODE_CHKSUM)); + return count; + } + + /** + * Returns true, if a preset dictionary is needed to inflate the input. + */ + public boolean needsDictionary() + { + return mode == DECODE_DICT && neededBits == 0; + } + + /** + * Returns true, if the input buffer is empty. + * You should then call setInput().
+ * + * NOTE: This method also returns true when the stream is finished. + */ + public boolean needsInput() + { + return input.needsInput(); + } + + /** + * Resets the inflater so that a new stream can be decompressed. All + * pending input and output will be discarded. + */ + public void reset() + { + mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER; + totalIn = totalOut = 0; + input.reset(); + outputWindow.reset(); + dynHeader = null; + litlenTree = null; + distTree = null; + isLastBlock = false; + adler.reset(); + } + + /** + * Sets the preset dictionary. This should only be called, if + * needsDictionary() returns true and it should set the same + * dictionary, that was used for deflating. The getAdler() + * function returns the checksum of the dictionary needed. + * @param buffer the dictionary. + * @exception IllegalStateException if no dictionary is needed. + * @exception IllegalArgumentException if the dictionary checksum is + * wrong. + */ + public void setDictionary(byte[] buffer) + { + setDictionary(buffer, 0, buffer.length); + } + + /** + * Sets the preset dictionary. This should only be called, if + * needsDictionary() returns true and it should set the same + * dictionary, that was used for deflating. The getAdler() + * function returns the checksum of the dictionary needed. + * @param buffer the dictionary. + * @param off the offset into buffer where the dictionary starts. + * @param len the length of the dictionary. + * @exception IllegalStateException if no dictionary is needed. + * @exception IllegalArgumentException if the dictionary checksum is + * wrong. + * @exception IndexOutOfBoundsException if the off and/or len are wrong. + */ + public void setDictionary(byte[] buffer, int off, int len) + { + if(!needsDictionary()) + throw new IllegalStateException(); + + adler.update(buffer, off, len); + if((int)adler.getValue() != readAdler) + throw new IllegalArgumentException("Wrong adler checksum"); + adler.reset(); + outputWindow.copyDict(buffer, off, len); + mode = DECODE_BLOCKS; + } + + /** + * Sets the input. This should only be called, if needsInput() + * returns true. + * @param buf the input. + * @exception IllegalStateException if no input is needed. + */ + public void setInput(byte[] buf) + { + setInput(buf, 0, buf.length); + } + + /** + * Sets the input. This should only be called, if needsInput() + * returns true. + * @param buf the input. + * @param off the offset into buffer where the input starts. + * @param len the length of the input. + * @exception IllegalStateException if no input is needed. + * @exception IndexOutOfBoundsException if the off and/or len are wrong. + */ + public void setInput(byte[] buf, int off, int len) + { + input.setInput(buf, off, len); + totalIn += len; + } + + /** + * Decodes the deflate header. + * @return false if more input is needed. + * @exception DataFormatException if header is invalid. + */ + private boolean decodeHeader() throws DataFormatException + { + int header = input.peekBits(16); + if(header < 0) + return false; + input.dropBits(16); + + /* The header is written in "wrong" byte order */ + header = ((header << 8) | (header >> 8)) & 0xffff; + if(header % 31 != 0) + throw new DataFormatException("Header checksum illegal"); + + if((header & 0x0f00) != (Deflater.DEFLATED << 8)) + throw new DataFormatException("Compression Method unknown"); + + /* Maximum size of the backwards window in bits. + * We currently ignore this, but we could use it to make the + * inflater window more space efficient. On the other hand the + * full window (15 bits) is needed most times, anyway. + int max_wbits = ((header & 0x7000) >> 12) + 8; + */ + + if((header & 0x0020) == 0) // Dictionary flag? + { + mode = DECODE_BLOCKS; + } + else + { + mode = DECODE_DICT; + neededBits = 32; + } + return true; + } + + /** + * Decodes the dictionary checksum after the deflate header. + * @return false if more input is needed. + */ + private boolean decodeDict() + { + while(neededBits > 0) + { + int dictByte = input.peekBits(8); + if(dictByte < 0) + return false; + input.dropBits(8); + readAdler = (readAdler << 8) | dictByte; + neededBits -= 8; + } + return false; + } + + /** + * Decodes the huffman encoded symbols in the input stream. + * @return false if more input is needed, true if output window is + * full or the current block ends. + * @exception DataFormatException if deflated stream is invalid. + */ + private boolean decodeHuffman() throws DataFormatException + { + int free = outputWindow.getFreeSpace(); + while(free >= 258) + { + int symbol; + switch(mode) + { + case DECODE_HUFFMAN: + /* This is the inner loop so it is optimized a bit */ + while(((symbol = litlenTree.getSymbol(input)) & ~0xff) == 0) + { + outputWindow.write(symbol); + if(--free < 258) + return true; + } + if(symbol < 257) + { + if(symbol < 0) + return false; + else + { + /* symbol == 256: end of block */ + distTree = null; + litlenTree = null; + mode = DECODE_BLOCKS; + return true; + } + } + + try + { + repLength = CPLENS[symbol - 257]; + neededBits = CPLEXT[symbol - 257]; + } + catch(ArrayIndexOutOfBoundsException ex) + { + throw new DataFormatException("Illegal rep length code"); + } + /* fall through */ + case DECODE_HUFFMAN_LENBITS: + if(neededBits > 0) + { + mode = DECODE_HUFFMAN_LENBITS; + int i = input.peekBits(neededBits); + if(i < 0) + return false; + input.dropBits(neededBits); + repLength += i; + } + mode = DECODE_HUFFMAN_DIST; + /* fall through */ + case DECODE_HUFFMAN_DIST: + symbol = distTree.getSymbol(input); + if(symbol < 0) + return false; + try + { + repDist = CPDIST[symbol]; + neededBits = CPDEXT[symbol]; + } + catch(ArrayIndexOutOfBoundsException ex) + { + throw new DataFormatException("Illegal rep dist code"); + } + /* fall through */ + case DECODE_HUFFMAN_DISTBITS: + if(neededBits > 0) + { + mode = DECODE_HUFFMAN_DISTBITS; + int i = input.peekBits(neededBits); + if(i < 0) + return false; + input.dropBits(neededBits); + repDist += i; + } + outputWindow.repeat(repLength, repDist); + free -= repLength; + mode = DECODE_HUFFMAN; + break; + default: + throw new IllegalStateException(); + } + } + return true; + } + + /** + * Decodes the adler checksum after the deflate stream. + * @return false if more input is needed. + * @exception DataFormatException if checksum doesn't match. + */ + private boolean decodeChksum() throws DataFormatException + { + while(neededBits > 0) + { + int chkByte = input.peekBits(8); + if(chkByte < 0) + return false; + input.dropBits(8); + readAdler = (readAdler << 8) | chkByte; + neededBits -= 8; + } + if((int)adler.getValue() != readAdler) + throw new DataFormatException("Adler chksum doesn't match: " + + Integer.toHexString((int)adler.getValue()) + + " vs. " + Integer.toHexString(readAdler)); + mode = FINISHED; + return false; + } + + /** + * Decodes the deflated stream. + * @return false if more input is needed, or if finished. + * @exception DataFormatException if deflated stream is invalid. + */ + private boolean decode() throws DataFormatException + { + switch(mode) + { + case DECODE_HEADER: + return decodeHeader(); + case DECODE_DICT: + return decodeDict(); + case DECODE_CHKSUM: + return decodeChksum(); + + case DECODE_BLOCKS: + if(isLastBlock) + { + if(nowrap) + { + mode = FINISHED; + return false; + } + else + { + input.skipToByteBoundary(); + neededBits = 32; + mode = DECODE_CHKSUM; + return true; + } + } + + int type = input.peekBits(3); + if(type < 0) + return false; + input.dropBits(3); + + if((type & 1) != 0) + isLastBlock = true; + switch(type >> 1) + { + case DeflaterConstants.STORED_BLOCK: + input.skipToByteBoundary(); + mode = DECODE_STORED_LEN1; + break; + case DeflaterConstants.STATIC_TREES: + litlenTree = InflaterHuffmanTree.defLitLenTree; + distTree = InflaterHuffmanTree.defDistTree; + mode = DECODE_HUFFMAN; + break; + case DeflaterConstants.DYN_TREES: + dynHeader = new InflaterDynHeader(); + mode = DECODE_DYN_HEADER; + break; + default: + throw new DataFormatException("Unknown block type " + type); + } + return true; + + case DECODE_STORED_LEN1: + { + if((uncomprLen = input.peekBits(16)) < 0) + return false; + input.dropBits(16); + mode = DECODE_STORED_LEN2; + } + /* fall through */ + case DECODE_STORED_LEN2: + { + int nlen = input.peekBits(16); + if(nlen < 0) + return false; + input.dropBits(16); + if(nlen != (uncomprLen ^ 0xffff)) + throw new DataFormatException("broken uncompressed block"); + mode = DECODE_STORED; + } + /* fall through */ + case DECODE_STORED: + { + int more = outputWindow.copyStored(input, uncomprLen); + uncomprLen -= more; + if(uncomprLen == 0) + { + mode = DECODE_BLOCKS; + return true; + } + return !input.needsInput(); + } + + case DECODE_DYN_HEADER: + if(!dynHeader.decode(input)) + return false; + litlenTree = dynHeader.buildLitLenTree(); + distTree = dynHeader.buildDistTree(); + mode = DECODE_HUFFMAN; + /* fall through */ + case DECODE_HUFFMAN: + case DECODE_HUFFMAN_LENBITS: + case DECODE_HUFFMAN_DIST: + case DECODE_HUFFMAN_DISTBITS: + return decodeHuffman(); + case FINISHED: + return false; + default: + throw new IllegalStateException(); + } + } +} diff --git a/src/com/classpath/zip/InflaterDynHeader.java b/src/com/classpath/zip/InflaterDynHeader.java new file mode 100644 index 0000000..2c06151 --- /dev/null +++ b/src/com/classpath/zip/InflaterDynHeader.java @@ -0,0 +1,204 @@ +/* java.util.zip.InflaterDynHeader + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +class InflaterDynHeader +{ + private static final int LNUM = 0; + private static final int DNUM = 1; + private static final int BLNUM = 2; + private static final int BLLENS = 3; + private static final int LENS = 4; + private static final int REPS = 5; + + private static final int repMin[] = { 3, 3, 11 }; + private static final int repBits[] = { 2, 3, 7 }; + + + private byte[] blLens; + private byte[] litdistLens; + + private InflaterHuffmanTree blTree; + + private int mode; + private int lnum, dnum, blnum, num; + private int repSymbol; + private byte lastLen; + private int ptr; + + private static final int[] BL_ORDER = + { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + + public InflaterDynHeader() + { + } + + public boolean decode(StreamManipulator input) throws DataFormatException + { + decode_loop: + for (;;) + { + switch (mode) + { + case LNUM: + lnum = input.peekBits(5); + if (lnum < 0) + return false; + lnum += 257; + input.dropBits(5); +// System.err.println("LNUM: "+lnum); + mode = DNUM; + /* fall through */ + case DNUM: + dnum = input.peekBits(5); + if (dnum < 0) + return false; + dnum++; + input.dropBits(5); +// System.err.println("DNUM: "+dnum); + num = lnum+dnum; + litdistLens = new byte[num]; + mode = BLNUM; + /* fall through */ + case BLNUM: + blnum = input.peekBits(4); + if (blnum < 0) + return false; + blnum += 4; + input.dropBits(4); + blLens = new byte[19]; + ptr = 0; +// System.err.println("BLNUM: "+blnum); + mode = BLLENS; + /* fall through */ + case BLLENS: + while (ptr < blnum) + { + int len = input.peekBits(3); + if (len < 0) + return false; + input.dropBits(3); +// System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len); + blLens[BL_ORDER[ptr]] = (byte) len; + ptr++; + } + blTree = new InflaterHuffmanTree(blLens); + blLens = null; + ptr = 0; + mode = LENS; + /* fall through */ + case LENS: + { + int symbol; + while (((symbol = blTree.getSymbol(input)) & ~15) == 0) + { + /* Normal case: symbol in [0..15] */ + +// System.err.println("litdistLens["+ptr+"]: "+symbol); + litdistLens[ptr++] = lastLen = (byte) symbol; + + if (ptr == num) + { + /* Finished */ + return true; + } + } + + /* need more input ? */ + if (symbol < 0) + return false; + + /* otherwise repeat code */ + if (symbol >= 17) + { + /* repeat zero */ +// System.err.println("repeating zero"); + lastLen = 0; + } + else + { + if (ptr == 0) + throw new DataFormatException(); + } + repSymbol = symbol-16; + mode = REPS; + } + /* fall through */ + + case REPS: + { + int bits = repBits[repSymbol]; + int count = input.peekBits(bits); + if (count < 0) + return false; + input.dropBits(bits); + count += repMin[repSymbol]; +// System.err.println("litdistLens repeated: "+count); + + if (ptr + count > num) + throw new DataFormatException(); + while (count-- > 0) + litdistLens[ptr++] = lastLen; + + if (ptr == num) + { + /* Finished */ + return true; + } + } + mode = LENS; + continue decode_loop; + } + } + } + + public InflaterHuffmanTree buildLitLenTree() throws DataFormatException + { + byte[] litlenLens = new byte[lnum]; + System.arraycopy(litdistLens, 0, litlenLens, 0, lnum); + return new InflaterHuffmanTree(litlenLens); + } + + public InflaterHuffmanTree buildDistTree() throws DataFormatException + { + byte[] distLens = new byte[dnum]; + System.arraycopy(litdistLens, lnum, distLens, 0, dnum); + return new InflaterHuffmanTree(distLens); + } +} diff --git a/src/com/classpath/zip/InflaterHuffmanTree.java b/src/com/classpath/zip/InflaterHuffmanTree.java new file mode 100644 index 0000000..82b1e1b --- /dev/null +++ b/src/com/classpath/zip/InflaterHuffmanTree.java @@ -0,0 +1,218 @@ +/* InflaterHuffmanTree.java -- + Copyright (C) 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +class InflaterHuffmanTree +{ + private static final int MAX_BITLEN = 15; + + private short[] tree; + + static InflaterHuffmanTree defLitLenTree, defDistTree; + + static + { + try + { + byte[] codeLengths = new byte[288]; + int i = 0; + while (i < 144) + codeLengths[i++] = 8; + while (i < 256) + codeLengths[i++] = 9; + while (i < 280) + codeLengths[i++] = 7; + while (i < 288) + codeLengths[i++] = 8; + defLitLenTree = new InflaterHuffmanTree(codeLengths); + + codeLengths = new byte[32]; + i = 0; + while (i < 32) + codeLengths[i++] = 5; + defDistTree = new InflaterHuffmanTree(codeLengths); + } + catch (DataFormatException ex) + { +// throw new Exception +// ("InflaterHuffmanTree: static tree length illegal"); + } + } + + /** + * Constructs a Huffman tree from the array of code lengths. + * + * @param codeLengths the array of code lengths + */ + InflaterHuffmanTree(byte[] codeLengths) throws DataFormatException + { + buildTree(codeLengths); + } + + private void buildTree(byte[] codeLengths) throws DataFormatException + { + int[] blCount = new int[MAX_BITLEN+1]; + int[] nextCode = new int[MAX_BITLEN+1]; + for (int i = 0; i < codeLengths.length; i++) + { + int bits = codeLengths[i]; + if (bits > 0) + blCount[bits]++; + } + + int code = 0; + int treeSize = 512; + for (int bits = 1; bits <= MAX_BITLEN; bits++) + { + nextCode[bits] = code; + code += blCount[bits] << (16 - bits); + if (bits >= 10) + { + /* We need an extra table for bit lengths >= 10. */ + int start = nextCode[bits] & 0x1ff80; + int end = code & 0x1ff80; + treeSize += (end - start) >> (16 - bits); + } + } + if (code != 65536) + throw new DataFormatException("Code lengths don't add up properly."); + + /* Now create and fill the extra tables from longest to shortest + * bit len. This way the sub trees will be aligned. + */ + tree = new short[treeSize]; + int treePtr = 512; + for (int bits = MAX_BITLEN; bits >= 10; bits--) + { + int end = code & 0x1ff80; + code -= blCount[bits] << (16 - bits); + int start = code & 0x1ff80; + for (int i = start; i < end; i += 1 << 7) + { + tree[DeflaterHuffman.bitReverse(i)] + = (short) ((-treePtr << 4) | bits); + treePtr += 1 << (bits-9); + } + } + + for (int i = 0; i < codeLengths.length; i++) + { + int bits = codeLengths[i]; + if (bits == 0) + continue; + code = nextCode[bits]; + int revcode = DeflaterHuffman.bitReverse(code); + if (bits <= 9) + { + do + { + tree[revcode] = (short) ((i << 4) | bits); + revcode += 1 << bits; + } + while (revcode < 512); + } + else + { + int subTree = tree[revcode & 511]; + int treeLen = 1 << (subTree & 15); + subTree = -(subTree >> 4); + do + { + tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits); + revcode += 1 << bits; + } + while (revcode < treeLen); + } + nextCode[bits] = code + (1 << (16 - bits)); + } + } + + /** + * Reads the next symbol from input. The symbol is encoded using the + * huffman tree. + * @param input the input source. + * @return the next symbol, or -1 if not enough input is available. + */ + int getSymbol(StreamManipulator input) throws DataFormatException + { + int lookahead, symbol; + if ((lookahead = input.peekBits(9)) >= 0) + { + if ((symbol = tree[lookahead]) >= 0) + { + input.dropBits(symbol & 15); + return symbol >> 4; + } + int subtree = -(symbol >> 4); + int bitlen = symbol & 15; + if ((lookahead = input.peekBits(bitlen)) >= 0) + { + symbol = tree[subtree | (lookahead >> 9)]; + input.dropBits(symbol & 15); + return symbol >> 4; + } + else + { + int bits = input.getAvailableBits(); + lookahead = input.peekBits(bits); + symbol = tree[subtree | (lookahead >> 9)]; + if ((symbol & 15) <= bits) + { + input.dropBits(symbol & 15); + return symbol >> 4; + } + else + return -1; + } + } + else + { + int bits = input.getAvailableBits(); + lookahead = input.peekBits(bits); + symbol = tree[lookahead]; + if (symbol >= 0 && (symbol & 15) <= bits) + { + input.dropBits(symbol & 15); + return symbol >> 4; + } + else + return -1; + } + } +} diff --git a/src/com/classpath/zip/InflaterInputStream.java b/src/com/classpath/zip/InflaterInputStream.java new file mode 100644 index 0000000..1444489 --- /dev/null +++ b/src/com/classpath/zip/InflaterInputStream.java @@ -0,0 +1,308 @@ +/* InflaterInputStream.java - Input stream filter for decompressing + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package com.classpath.zip; + +import java.io.IOException; +import java.io.InputStream; + +/** + * This filter stream is used to decompress data compressed in the "deflate" + * format. The "deflate" format is described in RFC 1951. + * + * This stream may form the basis for other decompression filters, such + * as the GZIPInputStream. + * + * @author John Leuner + * @author Tom Tromey + * @since 1.1 + */ +public class InflaterInputStream extends InputStream +{ + /** + * Decompressor for this filter + */ + protected Inflater inf; + + /** + * Byte array used as a buffer + */ + protected byte[] buf; + + /** + * Size of buffer + */ + protected int len; + + // We just use this if we are decoding one byte at a time with the + // read() call. + private byte[] onebytebuffer = new byte[1]; + + protected InputStream in; + + /** + * Create an InflaterInputStream with the default decompresseor + * and a default buffer size. + * + * @param in the InputStream to read bytes from + */ + public InflaterInputStream(InputStream in) + { + this(in, new Inflater(), 4096); + } + + /** + * Create an InflaterInputStream with the specified decompresseor + * and a default buffer size. + * + * @param in the InputStream to read bytes from + * @param inf the decompressor used to decompress data read from in + */ + public InflaterInputStream(InputStream in, Inflater inf) + { + this(in, inf, 4096); + } + + /** + * Create an InflaterInputStream with the specified decompresseor + * and a specified buffer size. + * + * @param in the InputStream to read bytes from + * @param inf the decompressor used to decompress data read from in + * @param size size of the buffer to use + */ + public InflaterInputStream(InputStream in, Inflater inf, int size) + { + if(in == null) + { + throw new NullPointerException("in may not be null"); + } + + if(inf == null) + { + throw new NullPointerException("inf may not be null"); + } + + if(size < 0) + { + throw new IllegalArgumentException("size may not be negative"); + } + + this.in = in; + this.inf = inf; + this.buf = new byte[size]; + } + + /** + * Returns 0 once the end of the stream (EOF) has been reached. + * Otherwise returns 1. + */ + public int available() throws IOException + { + // According to the JDK 1.2 docs, this should only ever return 0 + // or 1 and should not be relied upon by Java programs. + + if(inf == null) + { + throw new IOException("stream closed"); + } + + return inf.finished() ? 0 : 1; + } + + /** + * Closes the input stream + */ + public synchronized void close() throws IOException + { + if(in != null) + { + in.close(); + } + + in = null; + } + + /** + * Fills the buffer with more data to decompress. + */ + protected void fill() throws IOException + { + if(in == null) + { + throw new ZipException("InflaterInputStream is closed"); + } + + len = in.read(buf, 0, buf.length); + + if(len < 0) + { + throw new ZipException("Deflated stream ends early."); + } + + inf.setInput(buf, 0, len); + } + + /** + * Reads one byte of decompressed data. + * + * The byte is in the lower 8 bits of the int. + */ + public int read() throws IOException + { + int nread = read(onebytebuffer, 0, 1); + + if(nread > 0) + { + return onebytebuffer[0] & 0xff; + } + + return -1; + } + + /** + * Decompresses data into the byte array + * + * @param b the array to read and decompress data into + * @param off the offset indicating where the data should be placed + * @param len the number of bytes to decompress + */ + public int read(byte[] b, int off, int len) throws IOException + { + if(inf == null) + { + throw new IOException("stream closed"); + } + + if(len == 0) + { + return 0; + } + + int count = 0; + + while(true) + { + try + { + count = inf.inflate(b, off, len); + } + catch(DataFormatException dfe) + { + throw new ZipException(dfe.getMessage()); + } + + if(count > 0) + { + return count; + } + + if(inf.needsDictionary() | inf.finished()) + { + return -1; + } + else if(inf.needsInput()) + { + fill(); + } + else + { + throw new ZipException("Don't know what to do"); + } + } + } + + /** + * Skip specified number of bytes of uncompressed data + * + * @param n number of bytes to skip + */ + public long skip(long n) throws IOException + { + if(inf == null) + { + throw new IOException("stream closed"); + } + + if(n < 0) + { + throw new IllegalArgumentException(); + } + + if(n == 0) + { + return 0; + } + + int buflen = (int)Math.min(n, 2048); + byte[] tmpbuf = new byte[buflen]; + + long skipped = 0L; + + while(n > 0L) + { + int numread = read(tmpbuf, 0, buflen); + + if(numread <= 0) + { + break; + } + + n -= numread; + skipped += numread; + buflen = (int)Math.min(n, 2048); + } + + return skipped; + } + + public boolean markSupported() + { + return false; + } + + public void mark(int readLimit) + { + } + + public void reset() throws IOException + { + throw new IOException("reset not supported"); + } +} diff --git a/src/com/classpath/zip/OutputWindow.java b/src/com/classpath/zip/OutputWindow.java new file mode 100644 index 0000000..4607dda --- /dev/null +++ b/src/com/classpath/zip/OutputWindow.java @@ -0,0 +1,180 @@ +/* OutputWindow.java -- + Copyright (C) 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +/** + * Contains the output from the Inflation process. + * + * We need to have a window so that we can refer backwards into the output stream + * to repeat stuff. + * + * @author John Leuner + * @since 1.1 + */ +class OutputWindow +{ + private static final int WINDOW_SIZE = 1 << 15; + private static final int WINDOW_MASK = WINDOW_SIZE - 1; + + private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes + private int window_end = 0; + private int window_filled = 0; + + public void write(int abyte) + { + if(window_filled++ == WINDOW_SIZE) + throw new IllegalStateException("Window full"); + window[window_end++] = (byte)abyte; + window_end &= WINDOW_MASK; + } + + private void slowRepeat(int rep_start, int len, int dist) + { + while(len-- > 0) + { + window[window_end++] = window[rep_start++]; + window_end &= WINDOW_MASK; + rep_start &= WINDOW_MASK; + } + } + + public void repeat(int len, int dist) + { + if((window_filled += len) > WINDOW_SIZE) + throw new IllegalStateException("Window full"); + + int rep_start = (window_end - dist) & WINDOW_MASK; + int border = WINDOW_SIZE - len; + if(rep_start <= border && window_end < border) + { + if(len <= dist) + { + System.arraycopy(window, rep_start, window, window_end, len); + window_end += len; + } + else + { + /* We have to copy manually, since the repeat pattern overlaps. + */ + while(len-- > 0) + window[window_end++] = window[rep_start++]; + } + } + else + slowRepeat(rep_start, len, dist); + } + + public int copyStored(StreamManipulator input, int len) + { + len = Math.min(Math.min(len, WINDOW_SIZE - window_filled), + input.getAvailableBytes()); + int copied; + + int tailLen = WINDOW_SIZE - window_end; + if(len > tailLen) + { + copied = input.copyBytes(window, window_end, tailLen); + if(copied == tailLen) + copied += input.copyBytes(window, 0, len - tailLen); + } + else + copied = input.copyBytes(window, window_end, len); + + window_end = (window_end + copied) & WINDOW_MASK; + window_filled += copied; + return copied; + } + + public void copyDict(byte[] dict, int offset, int len) + { + if(window_filled > 0) + throw new IllegalStateException(); + + if(len > WINDOW_SIZE) + { + offset += len - WINDOW_SIZE; + len = WINDOW_SIZE; + } + System.arraycopy(dict, offset, window, 0, len); + window_end = len & WINDOW_MASK; + } + + public int getFreeSpace() + { + return WINDOW_SIZE - window_filled; + } + + public int getAvailable() + { + return window_filled; + } + + public int copyOutput(byte[] output, int offset, int len) + { + int copy_end = window_end; + if(len > window_filled) + len = window_filled; + else + copy_end = (window_end - window_filled + len) & WINDOW_MASK; + + int copied = len; + int tailLen = len - copy_end; + + if(tailLen > 0) + { + System.arraycopy(window, WINDOW_SIZE - tailLen, + output, offset, tailLen); + offset += tailLen; + len = copy_end; + } + System.arraycopy(window, copy_end - len, output, offset, len); + window_filled -= copied; + if(window_filled < 0) + throw new IllegalStateException(); + return copied; + } + + public void reset() + { + window_filled = window_end = 0; + } +} + + + diff --git a/src/com/classpath/zip/PendingBuffer.java b/src/com/classpath/zip/PendingBuffer.java new file mode 100644 index 0000000..0e12eee --- /dev/null +++ b/src/com/classpath/zip/PendingBuffer.java @@ -0,0 +1,208 @@ +/* java.util.zip.PendingBuffer + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +/** + * This class is general purpose class for writing data to a buffer. + * + * It allows you to write bits as well as bytes + * + * Based on DeflaterPending.java + * + * @author Jochen Hoenicke + * @date Jan 5, 2000 + */ + +class PendingBuffer +{ + protected byte[] buf; + int start; + int end; + + int bits; + int bitCount; + + public PendingBuffer () + { + this (4096); + } + + public PendingBuffer (int bufsize) + { + buf = new byte[bufsize]; + } + + public final void reset () + { + start = end = bitCount = 0; + } + + public final void writeByte (int b) + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException (); + buf[end++] = (byte) b; + } + + public final void writeShort (int s) + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException (); + buf[end++] = (byte) s; + buf[end++] = (byte) (s >> 8); + } + + public final void writeInt (int s) + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException (); + buf[end++] = (byte) s; + buf[end++] = (byte) (s >> 8); + buf[end++] = (byte) (s >> 16); + buf[end++] = (byte) (s >> 24); + } + + public final void writeBlock (byte[] block, int offset, int len) + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException (); + System.arraycopy (block, offset, buf, end, len); + end += len; + } + + public final int getBitCount () + { + return bitCount; + } + + public final void alignToByte () + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException (); + if (bitCount > 0) + { + buf[end++] = (byte) bits; + if (bitCount > 8) + buf[end++] = (byte) (bits >>> 8); + } + bits = 0; + bitCount = 0; + } + + public final void writeBits (int b, int count) + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException (); + if (DeflaterConstants.DEBUGGING) + System.err.println ("writeBits("+Integer.toHexString (b)+","+count+")"); + bits |= b << bitCount; + bitCount += count; + if (bitCount >= 16) + { + buf[end++] = (byte) bits; + buf[end++] = (byte) (bits >>> 8); + bits >>>= 16; + bitCount -= 16; + } + } + + public final void writeShortMSB (int s) + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException (); + buf[end++] = (byte) (s >> 8); + buf[end++] = (byte) s; + } + + public final boolean isFlushed () + { + return end == 0; + } + + /** + * Flushes the pending buffer into the given output array. If the + * output array is to small, only a partial flush is done. + * + * @param output the output array; + * @param offset the offset into output array; + * @param length the maximum number of bytes to store; + * @exception IndexOutOfBoundsException if offset or length are + * invalid. + */ + public final int flush (byte[] output, int offset, int length) + { + if (bitCount >= 8) + { + buf[end++] = (byte) bits; + bits >>>= 8; + bitCount -= 8; + } + if (length > end - start) + { + length = end - start; + System.arraycopy (buf, start, output, offset, length); + start = 0; + end = 0; + } + else + { + System.arraycopy (buf, start, output, offset, length); + start += length; + } + return length; + } + + /** + * Flushes the pending buffer and returns that data in a new array + * + * @param output the output stream + */ + + public final byte[] toByteArray () + { + byte[] ret = new byte[ end - start ]; + System.arraycopy (buf, start, ret, 0, ret.length); + start = 0; + end = 0; + return ret; + } + + +} + diff --git a/src/com/classpath/zip/StreamManipulator.java b/src/com/classpath/zip/StreamManipulator.java new file mode 100644 index 0000000..48c92ce --- /dev/null +++ b/src/com/classpath/zip/StreamManipulator.java @@ -0,0 +1,217 @@ +/* java.util.zip.StreamManipulator + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +/** + * This class allows us to retrieve a specified amount of bits from + * the input buffer, as well as copy big byte blocks. + * + * It uses an int buffer to store up to 31 bits for direct + * manipulation. This guarantees that we can get at least 16 bits, + * but we only need at most 15, so this is all safe. + * + * There are some optimizations in this class, for example, you must + * never peek more then 8 bits more than needed, and you must first + * peek bits before you may drop them. This is not a general purpose + * class but optimized for the behaviour of the Inflater. + * + * @author John Leuner, Jochen Hoenicke + */ + +class StreamManipulator +{ + private byte[] window; + private int window_start = 0; + private int window_end = 0; + + private int buffer = 0; + private int bits_in_buffer = 0; + + /** + * Get the next n bits but don't increase input pointer. n must be + * less or equal 16 and if you if this call succeeds, you must drop + * at least n-8 bits in the next call. + * + * @return the value of the bits, or -1 if not enough bits available. */ + public final int peekBits(int n) + { + if (bits_in_buffer < n) + { + if (window_start == window_end) + return -1; + buffer |= (window[window_start++] & 0xff + | (window[window_start++] & 0xff) << 8) << bits_in_buffer; + bits_in_buffer += 16; + } + return buffer & ((1 << n) - 1); + } + + /* Drops the next n bits from the input. You should have called peekBits + * with a bigger or equal n before, to make sure that enough bits are in + * the bit buffer. + */ + public final void dropBits(int n) + { + buffer >>>= n; + bits_in_buffer -= n; + } + + /** + * Gets the next n bits and increases input pointer. This is equivalent + * to peekBits followed by dropBits, except for correct error handling. + * @return the value of the bits, or -1 if not enough bits available. + */ + public final int getBits(int n) + { + int bits = peekBits(n); + if (bits >= 0) + dropBits(n); + return bits; + } + /** + * Gets the number of bits available in the bit buffer. This must be + * only called when a previous peekBits() returned -1. + * @return the number of bits available. + */ + public final int getAvailableBits() + { + return bits_in_buffer; + } + + /** + * Gets the number of bytes available. + * @return the number of bytes available. + */ + public final int getAvailableBytes() + { + return window_end - window_start + (bits_in_buffer >> 3); + } + + /** + * Skips to the next byte boundary. + */ + public void skipToByteBoundary() + { + buffer >>= (bits_in_buffer & 7); + bits_in_buffer &= ~7; + } + + public final boolean needsInput() { + return window_start == window_end; + } + + + /* Copies length bytes from input buffer to output buffer starting + * at output[offset]. You have to make sure, that the buffer is + * byte aligned. If not enough bytes are available, copies fewer + * bytes. + * @param length the length to copy, 0 is allowed. + * @return the number of bytes copied, 0 if no byte is available. + */ + public int copyBytes(byte[] output, int offset, int length) + { + if (length < 0) + throw new IllegalArgumentException("length negative"); + if ((bits_in_buffer & 7) != 0) + /* bits_in_buffer may only be 0 or 8 */ + throw new IllegalStateException("Bit buffer is not aligned!"); + + int count = 0; + while (bits_in_buffer > 0 && length > 0) + { + output[offset++] = (byte) buffer; + buffer >>>= 8; + bits_in_buffer -= 8; + length--; + count++; + } + if (length == 0) + return count; + + int avail = window_end - window_start; + if (length > avail) + length = avail; + System.arraycopy(window, window_start, output, offset, length); + window_start += length; + + if (((window_start - window_end) & 1) != 0) + { + /* We always want an even number of bytes in input, see peekBits */ + buffer = (window[window_start++] & 0xff); + bits_in_buffer = 8; + } + return count + length; + } + + public StreamManipulator() + { + } + + public void reset() + { + window_start = window_end = buffer = bits_in_buffer = 0; + } + + public void setInput(byte[] buf, int off, int len) + { + if (window_start < window_end) + throw new IllegalStateException + ("Old input was not completely processed"); + + int end = off + len; + + /* We want to throw an ArrayIndexOutOfBoundsException early. The + * check is very tricky: it also handles integer wrap around. + */ + if (0 > off || off > end || end > buf.length) + throw new ArrayIndexOutOfBoundsException(); + + if ((len & 1) != 0) + { + /* We always want an even number of bytes in input, see peekBits */ + buffer |= (buf[off++] & 0xff) << bits_in_buffer; + bits_in_buffer += 8; + } + + window = buf; + window_start = off; + window_end = end; + } +} + diff --git a/src/com/classpath/zip/ZipConstants.java b/src/com/classpath/zip/ZipConstants.java new file mode 100644 index 0000000..9ce76da --- /dev/null +++ b/src/com/classpath/zip/ZipConstants.java @@ -0,0 +1,97 @@ +/* java.util.zip.ZipConstants + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package com.classpath.zip; + +class ZipConstants +{ + /* The local file header */ + final static int LOCHDR = 30; + final static int LOCSIG = 'P' | ('K' << 8) | (3 << 16) | (4 << 24); + + final static int LOCVER = 4; + final static int LOCFLG = 6; + final static int LOCHOW = 8; + final static int LOCTIM = 10; + final static int LOCCRC = 14; + final static int LOCSIZ = 18; + final static int LOCLEN = 22; + final static int LOCNAM = 26; + final static int LOCEXT = 28; + + /* The Data descriptor */ + final static int EXTSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24); + final static int EXTHDR = 16; + + final static int EXTCRC = 4; + final static int EXTSIZ = 8; + final static int EXTLEN = 12; + + /* The central directory file header */ + final static int CENSIG = 'P' | ('K' << 8) | (1 << 16) | (2 << 24); + final static int CENHDR = 46; + + final static int CENVEM = 4; + final static int CENVER = 6; + final static int CENFLG = 8; + final static int CENHOW = 10; + final static int CENTIM = 12; + final static int CENCRC = 16; + final static int CENSIZ = 20; + final static int CENLEN = 24; + final static int CENNAM = 28; + final static int CENEXT = 30; + final static int CENCOM = 32; + final static int CENDSK = 34; + final static int CENATT = 36; + final static int CENATX = 38; + final static int CENOFF = 42; + + /* The entries in the end of central directory */ + final static int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24); + final static int ENDHDR = 22; + + /* The following two fields are missing in SUN JDK */ + final static int ENDNRD = 4; + final static int ENDDCD = 6; + final static int ENDSUB = 8; + final static int ENDTOT = 10; + final static int ENDSIZ = 12; + final static int ENDOFF = 16; + final static int ENDCOM = 20; +} + diff --git a/src/com/classpath/zip/ZipEntry.java b/src/com/classpath/zip/ZipEntry.java new file mode 100644 index 0000000..595acee --- /dev/null +++ b/src/com/classpath/zip/ZipEntry.java @@ -0,0 +1,630 @@ +/* java.util.zip.ZipEntry + Copyright (C) 2001, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package com.classpath.zip; + +import com.one.ContainerEntry; +import com.vmx.AuxClass; +import com.vmx.StringEncoder; +import java.util.Calendar; +import java.util.Date; + +import java.io.*; + +/** + * This class represents a member of a zip archive. ZipFile and + * ZipInputStream will give you instances of this class as information + * about the members in an archive. On the other hand ZipOutputStream + * needs an instance of this class to create a new member. + * + * @author Jochen Hoenicke + */ +public class ZipEntry extends ContainerEntry +{ + private static int KNOWN_SIZE = 1; + private static int KNOWN_CSIZE = 2; + private static int KNOWN_CRC = 4; + private static int KNOWN_TIME = 8; + + private static Calendar cal = Calendar.getInstance(); + + private int crc; + private int dostime; + private short known = 0; + private short method = -1; + private byte[] extra = null; + private String comment = null; + + public int flags; /* used by ZipOutputStream */ + + /** + * Creates an empty zip entry. + */ + public ZipEntry() + { + } + + /** + * Creates a zip entry with the given name. + * @param name the name. May include directory components separated by '/'. + * + * @exception NullPointerException when name is null. + * @exception IllegalArgumentException when name is bigger then 65535 chars. + */ + public ZipEntry(String name) + { + setName(name); + } + + /** + * Creates a copy of the given zip entry. + * @param e the entry to copy. + */ + public ZipEntry(ZipEntry e) + { + name = e.name; + known = e.known; + size = e.size; + compressedSize = e.compressedSize; + crc = e.crc; + dostime = e.dostime; + method = e.method; + extra = e.extra; + comment = e.comment; + } + + public int getLocalSize() + { + if((known & KNOWN_CSIZE) == 0) + { + return -1; + } + + int localSize = ZipConstants.LOCHDR + compressedSize; + + if(name != null) + { + localSize += StringEncoder.getEncodedLength(name, StringEncoder.ENC_ARCHIVE); + } + + if(extra != null) + { + localSize += extra.length; + } + + if((flags & 8) != 0) + { + localSize += ZipConstants.EXTHDR; + } + + return localSize; + } + + /** + * Read this entry from central file header. + * Return true if successful, false if central header not found. + */ + public boolean readCentralHeader(InputStream is) throws IOException + { + if(AuxClass.readLeInt(is) != ZipConstants.CENSIG) + { + return false; + } + + is.skip(4); + + flags = AuxClass.readLeShort(is); + + setMethod(AuxClass.readLeShort(is)); + setDOSTime(AuxClass.readLeInt(is)); + setCRC(AuxClass.readLeInt(is)); + setCompressedSize(AuxClass.readLeInt(is)); + setSize(AuxClass.readLeInt(is)); + + int nameLen = AuxClass.readLeShort(is); + int extraLen = AuxClass.readLeShort(is); + int commentLen = AuxClass.readLeShort(is); + + is.skip(8); + + offset = AuxClass.readLeInt(is); + + if(nameLen > 0) + { + setName(StringEncoder.readString(is, nameLen, StringEncoder.ENC_ARCHIVE)); + } + + if(extraLen > 0) + { + byte[] b = new byte[extraLen]; + is.read(b, 0, extraLen); + + setExtra(b); + } + + if(commentLen > 0) + { + setComment(StringEncoder.readString(is, commentLen, StringEncoder.ENC_ARCHIVE)); + } + + return true; + } + + /** + * Write central file header for this entry, + * return number of bytes written. + */ + public int writeCentralHeader(OutputStream os) throws IOException + { + AuxClass.writeLeInt(os, ZipConstants.CENSIG); + + int method = getMethod(); + + AuxClass.writeLeShort(os, method == ZipFile.STORED ? ZipFile.ZIP_STORED_VERSION : ZipFile.ZIP_DEFLATED_VERSION); + AuxClass.writeLeShort(os, method == ZipFile.STORED ? ZipFile.ZIP_STORED_VERSION : ZipFile.ZIP_DEFLATED_VERSION); + AuxClass.writeLeShort(os, flags); + AuxClass.writeLeShort(os, method); + AuxClass.writeLeInt(os, getDOSTime()); + AuxClass.writeLeInt(os, getCRC()); + AuxClass.writeLeInt(os, getCompressedSize()); + AuxClass.writeLeInt(os, getSize()); + + byte[] name = StringEncoder.encodeString(getName(), StringEncoder.ENC_ARCHIVE); + + if(name.length > 0xFFFF) + { + throw new ZipException("Name too long."); + } + + byte[] extra = getExtra(); + + if(extra == null) + { + extra = new byte[0]; + } + + String strComment = getComment(); + + byte[] comment = strComment != null ? StringEncoder.encodeString(strComment, StringEncoder.ENC_ARCHIVE) : new byte[0]; + + if(comment.length > 0xFFFF) + { + throw new ZipException("Comment too long."); + } + + AuxClass.writeLeShort(os, name.length); + AuxClass.writeLeShort(os, extra.length); + AuxClass.writeLeShort(os, comment.length); + AuxClass.writeLeShort(os, 0); /* disk number */ + AuxClass.writeLeShort(os, 0); /* internal file attr */ + AuxClass.writeLeInt(os, 0); /* external file attr */ + AuxClass.writeLeInt(os, offset); + + os.write(name); + os.write(extra); + os.write(comment); + + return ZipConstants.CENHDR + name.length + extra.length + comment.length; + } + + /** + * Read this entry from local file header. + * Return true if successful, false if local header not found. + */ + public boolean readLocalHeader(InputStream is) throws IOException + { + if(AuxClass.readLeInt(is) != ZipConstants.LOCSIG) + { + return false; + } + + is.skip(2); + + flags = AuxClass.readLeShort(is); + + setMethod(AuxClass.readLeShort(is)); + setDOSTime(AuxClass.readLeInt(is)); + setCRC(AuxClass.readLeInt(is)); + setCompressedSize(AuxClass.readLeInt(is)); + setSize(AuxClass.readLeInt(is)); + + int nameLen = AuxClass.readLeShort(is); + int extraLen = AuxClass.readLeShort(is); + + if(nameLen > 0) + { + setName(StringEncoder.readString(is, nameLen, StringEncoder.ENC_ARCHIVE)); + } + + if(extraLen > 0) + { + byte[] b = new byte[extraLen]; + is.read(b, 0, extraLen); + + setExtra(b); + } + + return true; + } + + /** + * Write local file header for this entry, + * return number of bytes written. + */ + public int writeLocalHeader(OutputStream os) throws IOException + { + AuxClass.writeLeInt(os, ZipConstants.LOCSIG); + + int method = getMethod(); + + AuxClass.writeLeShort(os, method == ZipFile.STORED ? ZipFile.ZIP_STORED_VERSION : ZipFile.ZIP_DEFLATED_VERSION); + AuxClass.writeLeShort(os, flags); + AuxClass.writeLeShort(os, method); + AuxClass.writeLeInt(os, getDOSTime()); + + if((flags & 8) == 0) + { + AuxClass.writeLeInt(os, getCRC()); + AuxClass.writeLeInt(os, getCompressedSize()); + AuxClass.writeLeInt(os, getSize()); + } + else + { + AuxClass.writeLeInt(os, 0); + AuxClass.writeLeInt(os, 0); + AuxClass.writeLeInt(os, 0); + } + + byte[] name = StringEncoder.encodeString(getName(), StringEncoder.ENC_ARCHIVE); + + if(name.length > 0xFFFF) + { + throw new ZipException("Name too long."); + } + + byte[] extra = getExtra(); + + if(extra == null) + { + extra = new byte[0]; + } + + AuxClass.writeLeShort(os, name.length); + AuxClass.writeLeShort(os, extra.length); + + os.write(name); + os.write(extra); + + return ZipConstants.LOCHDR + name.length + extra.length; + } + + public void setDOSTime(int dostime) + { + this.dostime = dostime; + known |= KNOWN_TIME; + } + + public int getDOSTime() + { + if((known & KNOWN_TIME) == 0) + { + return 0; + } + else + { + return dostime; + } + } + + public void setName(String name) + { + if(name.length() > 65535) + { + throw new IllegalArgumentException("Name too long"); + } + + this.name = name; + } + + /** + * Returns the entry name. The path components in the entry are + * always separated by slashes ('/'). + */ + public String getName() + { + return name; + } + + /** + * Sets the time of last modification of the entry. + * @time the time of last modification of the entry. + */ + public void setLastModified(long time) + { + synchronized(cal) + { + cal.setTime(new Date(time * 1000L)); + + dostime = (cal.get(Calendar.YEAR) - 1980 & 0x7f) << 25 + | (cal.get(Calendar.MONTH) + 1) << 21 + | (cal.get(Calendar.DAY_OF_MONTH)) << 16 + | (cal.get(Calendar.HOUR_OF_DAY)) << 11 + | (cal.get(Calendar.MINUTE)) << 5 + | (cal.get(Calendar.SECOND)) >> 1; + } + + dostime = (int)(dostime / 1000L); + this.known |= KNOWN_TIME; + } + + /** + * Gets the time of last modification of the entry. + * @return the time of last modification of the entry, or -1 if unknown. + */ + public long getLastModified() + { + if((known & KNOWN_TIME) == 0) + { + return -1; + } + + int sec = 2 * (dostime & 0x1f); + int min = (dostime >> 5) & 0x3f; + int hrs = (dostime >> 11) & 0x1f; + int day = (dostime >> 16) & 0x1f; + int mon = ((dostime >> 21) & 0xf) - 1; + int year = ((dostime >> 25) & 0x7f) + 1980; /* since 1900 */ + + try + { + synchronized(cal) + { + cal.set(cal.YEAR, year); + cal.set(cal.MONTH, mon); + cal.set(cal.DAY_OF_MONTH, day); + cal.set(cal.HOUR_OF_DAY, hrs); + cal.set(cal.MINUTE, min); + cal.set(cal.SECOND, sec); + + return cal.getTime().getTime(); + } + } + catch(RuntimeException ex) + { + /* Ignore illegal time stamp */ + known &= ~KNOWN_TIME; + return -1; + } + } + + /** + * Sets the size of the uncompressed data. + * @exception IllegalArgumentException if size is not in 0..0xffffffffL + */ + public void setSize(int size) + { + this.size = size; + this.known |= KNOWN_SIZE; + } + + /** + * Gets the size of the uncompressed data. + * @return the size or -1 if unknown. + */ + public int getSize() + { + return (known & KNOWN_SIZE) != 0 ? size : -1; + } + + /** + * Sets the size of the compressed data. + * @exception IllegalArgumentException if size is not in 0..0xffffffffL + */ + public void setCompressedSize(int csize) + { + this.compressedSize = csize; + this.known |= KNOWN_CSIZE; + } + + /** + * Gets the size of the compressed data. + * @return the size or -1 if unknown. + */ + public int getCompressedSize() + { + return (known & KNOWN_CSIZE) != 0 ? compressedSize : -1; + } + + /** + * Sets the crc of the uncompressed data. + * @exception IllegalArgumentException if crc is not in 0..0xffffffffL + */ + public void setCRC(int crc) + { + this.crc = crc; + this.known |= KNOWN_CRC; + } + + /** + * Gets the crc of the uncompressed data. + * @return the crc or -1 if unknown. + */ + public int getCRC() + { + return (known & KNOWN_CRC) != 0 ? crc : -1; + } + + /** + * Sets the compression method. Only DEFLATED and STORED are + * supported. + * @exception IllegalArgumentException if method is not supported. + * @see ZipOutputStream#DEFLATED + * @see ZipOutputStream#STORED + */ + public void setMethod(int method) + { + if(method != ZipFile.STORED && method != ZipFile.DEFLATED) + { + throw new IllegalArgumentException("Method not STORED or DEFLATED"); + } + + this.method = (short)method; + } + + /** + * Gets the compression method. + * @return the compression method or -1 if unknown. + */ + public int getMethod() + { + return method; + } + + /** + * Sets the extra data. + * @exception IllegalArgumentException if extra is longer than 0xffff bytes. + */ + public void setExtra(byte[] extra) + { + if(extra == null) + { + this.extra = null; + return; + } + + if(extra.length > 0xffff) + { + throw new IllegalArgumentException("Extra too long"); + } + + this.extra = extra; + + try + { + int pos = 0; + + while(pos < extra.length) + { + int sig = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8; + int len = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8; + + if(sig == 0x5455) + { + /* extended time stamp */ + int flags = extra[pos]; + + if((flags & 1) != 0) + { + long time = ((extra[pos + 1] & 0xff) | + (extra[pos + 2] & 0xff) << 8 | + (extra[pos + 3] & 0xff) << 16 | + (extra[pos + 4] & 0xff) << 24); + + setLastModified(time); + } + } + + pos += len; + } + } + catch(ArrayIndexOutOfBoundsException ex) + { + /* be lenient */ + return; + } + } + + /** + * Gets the extra data. + * @return the extra data or null if not set. + */ + public byte[] getExtra() + { + return extra; + } + + /** + * Sets the entry comment. + * @exception IllegalArgumentException if comment is longer than 0xffff. + */ + public void setComment(String comment) + { + if(comment != null && comment.length() > 0xffff) + { + throw new IllegalArgumentException("Comment too long"); + } + + this.comment = comment; + } + + /** + * Gets the comment. + * @return the comment or null if not set. + */ + public String getComment() + { + return comment; + } + + /** + * Gets true, if the entry is a directory. This is solely + * determined by the name, a trailing slash '/' marks a directory. + */ + public boolean isDirectory() + { + int nlen = name.length(); + return nlen > 0 && name.charAt(nlen - 1) == '/'; + } + + /** + * Gets the string representation of this ZipEntry. This is just + * the name as returned by getName(). + */ + public String toString() + { + return name; + } + + /** + * Gets the hashCode of this ZipEntry. This is just the hashCode + * of the name. Note that the equals method isn't changed, though. + */ + public int hashCode() + { + return name.hashCode(); + } +} diff --git a/src/com/classpath/zip/ZipException.java b/src/com/classpath/zip/ZipException.java new file mode 100644 index 0000000..8409975 --- /dev/null +++ b/src/com/classpath/zip/ZipException.java @@ -0,0 +1,73 @@ +/* ZipException.java - exception representing a zip related error + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.util.zip; +package com.classpath.zip; + +import java.io.IOException; + +/** + * Thrown during the creation or input of a zip file. + * + * @author Jochen Hoenicke + * @author Per Bothner + * @status updated to 1.4 + */ +public class ZipException extends IOException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 8000196834066748623L; + + /** + * Create an exception without a message. + */ + public ZipException () + { + } + + /** + * Create an exception with a message. + * + * @param msg the message + */ + public ZipException (String msg) + { + super (msg); + } +} diff --git a/src/com/classpath/zip/ZipFile.java b/src/com/classpath/zip/ZipFile.java new file mode 100644 index 0000000..01bc2a0 --- /dev/null +++ b/src/com/classpath/zip/ZipFile.java @@ -0,0 +1,622 @@ +/* ZipFile.java -- + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package com.classpath.zip; + +import java.io.*; +import java.util.*; + + +import com.vmx.*; +import com.one.*; + +/** + * This class represents a Zip archive. You can ask for the contained + * entries, or get an input stream for a file entry. The entry is + * automatically decompressed. + * + * This class is thread safe: You can open input streams for arbitrary + * entries in different threads. + * + * @author Jochen Hoenicke + * @author Artur Biesiadowski + */ +public class ZipFile extends Container +{ + /** + * Our Zip version is hard coded to 1.0 resp. 2.0 + */ + public final static int ZIP_STORED_VERSION = 10; + public final static int ZIP_DEFLATED_VERSION = 20; + + /** + * Compression method. This method doesn't compress at all. + */ + public final static int STORED = 0; + + /** + * Compression method. This method uses the Deflater. + */ + public final static int DEFLATED = 8; + + private static int complevel = Deflater.BEST_COMPRESSION; + + public static int getCompressionLevel() + { + return complevel; + } + + public static void setCompressionLevel(int level) + { + if(level < Deflater.NO_COMPRESSION) + { + complevel = Deflater.NO_COMPRESSION; + } + else if(level > Deflater.BEST_COMPRESSION) + { + complevel = Deflater.BEST_COMPRESSION; + } + else + { + complevel = level; + } + } + + private CentralDirectoryEndRecord cder = new CentralDirectoryEndRecord(); + + /* + public void checkFormat() throws IOException + { + boolean valid = false; + + try + { + byte[] buf = new byte[4]; + rais.read(buf); + int sig = buf[0] & 0xFF | ((buf[1] & 0xFF) << 8) | ((buf[2] & 0xFF) << 16) | ((buf[3] & 0xFF) << 24); + valid = (sig == LOCSIG) || (sig == ENDSIG); + } + catch(IOException _) + { + } + + if(!valid) + { + try + { + rais.close(); + } + catch(IOException _) + { + } + + throw new ZipException("Not a valid zip file"); + } + } + */ + + protected void readEntries() throws IOException + { + try + { + readCentralDirectory(); + } + catch(IOException e1) + { + checkReadOnly(); + + finished = false; + + try + { + readLocalHeaders(); + } + catch(IOException e2) + { + throw new IOException(e1.toString() + ", " + e2.toString()); + } + } + } + + /** + * Read the central directory of a zip file and fill the entries + * array. This is called exactly once when first needed. It is called + * while holding the lock on rais. + * + * @exception IOException if a i/o error occured. + * @exception ZipException if the central directory is malformed + */ + protected void readCentralDirectory() throws IOException + { + /* + * Search for the End Of Central Directory. When a zip comment is + * present the directory may start earlier. + * Note that a comment has a maximum length of 64K, so that is the + * maximum we search backwards. + */ + + rais.setPosition(0); + BufDataInputStream inp = new BufDataInputStream(rais); + + int pos = rais.getCapacity() - ZipConstants.ENDHDR; + int top = Math.max(0, pos - 0xFFFF); + + inp.setPosition(pos); + + if(!cder.read(inp)) + { + byte[] sig = new byte[4]; + sig[0] = (byte)(ZipConstants.ENDSIG & 0xFF); + sig[1] = (byte)((ZipConstants.ENDSIG >> 8) & 0xFF); + sig[2] = (byte)((ZipConstants.ENDSIG >> 16) & 0xFF); + sig[3] = (byte)((ZipConstants.ENDSIG >> 24) & 0xFF); + + pos = inp.indexOf(sig, 0, 4, top, pos); + + if(pos >= 0) + { + inp.setPosition(pos); + cder.read(inp); + } + else + { + entries = new Hashtable(); + throw new ZipException("Central Directory not found, probably not a zip file"); + } + } + + entries = new Hashtable(cder.numEntries + cder.numEntries / 2 + 1); + ZipEntry entry; + + inp.setPosition(cder.centralOffset); + + for(int i = 0; i < cder.numEntries; i++) + { + entry = new ZipEntry(); + + if(!entry.readCentralHeader(inp)) + { + throw new ZipException("Wrong Central Directory signature"); + } + + entries.put(entry.getName(), entry); + addFile(entry.getName()); + } + } + + /** + * If for some reason Central Directory is either corrupted or not present at all, + * we can still try to recover files throug local headers. + */ + protected void readLocalHeaders() throws IOException + { + rais.setPosition(0); + BufDataInputStream inp = new BufDataInputStream(rais); + + byte[] sig = new byte[4]; + sig[0] = (byte)(ZipConstants.LOCSIG & 0xFF); + sig[1] = (byte)((ZipConstants.LOCSIG >> 8) & 0xFF); + sig[2] = (byte)((ZipConstants.LOCSIG >> 16) & 0xFF); + sig[3] = (byte)((ZipConstants.LOCSIG >> 24) & 0xFF); + + entries = new Hashtable(); + ZipEntry entry; + int pos; + + while(true) + { + pos = inp.indexOf(sig, 0, 4, -1, -1); + + if(pos >= 0) + { + inp.setPosition(pos); + + entry = new ZipEntry(); + entry.readLocalHeader(inp); + entry.offset = pos; + + entries.put(entry.getName(), entry); + addFile(entry.getName()); + } + else + { + sig[0] = (byte)(ZipConstants.ENDSIG & 0xFF); + sig[1] = (byte)((ZipConstants.ENDSIG >> 8) & 0xFF); + sig[2] = (byte)((ZipConstants.ENDSIG >> 16) & 0xFF); + sig[3] = (byte)((ZipConstants.ENDSIG >> 24) & 0xFF); + + pos = inp.indexOf(sig, 0, 4, -1, -1); + + if(pos >= 0) + { + cder.centralOffset = pos; + } + else + { + cder.centralOffset = (int)file.fileSize(); + } + + break; + } + } + } + + /** + * Add a new entry to the current zip archive. + * If entry with such name already exists, + * it is deleted and then new entry is added. + * If source stream is null, then an empty entry is written. + * The file data is entirely copied from specified input stream, + * compressed with DEFTATED method and specified compression level, + * and zip entry with specified name is written into the file, + * overwriting central directory (if present). + * Therefore zip file is no longer valid until finish() is called + * and correct central directory is restored at it's end. + */ + public boolean addEntry(RandomAccessInputStream source, String name, long time, boolean replace, ProgressCallback callback) throws IOException + { + if(replace) + { + deleteEntry(getEntry(name)); + } + else + { + checkReadOnly(); + checkEntries(); + + if(getEntry(name) != null) + { + return false; + } + } + + if(callback != null) + { + callback.setText(Locale.getString(this, Locale.PACKING_FILE, name)); + callback.setProgress(0); + callback.setMax(source.getCapacity()); + } + + ZipEntry entry = new ZipEntry(name); + + if(time < 0) + { + time = System.currentTimeMillis(); + } + + entry.setLastModified(time); + entry.setMethod(DEFLATED); + entry.flags = 8; + entry.offset = cder.centralOffset; + + OutputStream os = file.openOutputStream(cder.centralOffset); + finished = false; + + /* Write the local file header */ + cder.centralOffset += entry.writeLocalHeader(os); + + CRC32 crc = new CRC32(); + DeflaterOutputStream dos = new DeflaterOutputStream(os, new Deflater(complevel, true)); + int size = 0; + + if(source != null) + { + byte[] buf = new byte[AuxClass.ARCBUFSIZE]; + int len; + + if(callback != null) + { + while(source.available() > 0) + { + len = source.read(buf); + + dos.write(buf, 0, len); + crc.update(buf, 0, len); + + size += len; + callback.progress(len); + } + } + else + { + while(source.available() > 0) + { + len = source.read(buf); + + dos.write(buf, 0, len); + crc.update(buf, 0, len); + + size += len; + } + } + + source.close(); + } + + dos.finish(); + + int csize = dos.getTotalOut(); + cder.centralOffset += csize; + + entry.setSize(size); + entry.setCompressedSize(csize); + entry.setCRC((int)crc.getValue()); + + /* Now write the data descriptor entry if needed. */ + if((entry.flags & 8) != 0) + { + AuxClass.writeLeInt(os, ZipConstants.EXTSIG); + + AuxClass.writeLeInt(os, entry.getCRC()); + AuxClass.writeLeInt(os, entry.getCompressedSize()); + AuxClass.writeLeInt(os, entry.getSize()); + + cder.centralOffset += ZipConstants.EXTHDR; + } + + dos.close(); + + entries.put(name, entry); + rais.update(); + + addFile(name); + + return true; + } + + /** + * Delete the specified entry from the current zip archive. + * It also totally truncates central directory, + * so finish() must be called to restore this zip file valid. + */ + public boolean deleteEntry(ContainerEntry entry) throws IOException + { + if(entry == null) + { + return false; + } + + checkReadOnly(); + checkEntries(); + + if(entry.getName().endsWith("/")) + { + if(listFiles(entry.getName()).hasMoreElements()) + { + return false; + } + else + { + deleteFile(entry.getName()); + return true; + } + } + + if(!entries.containsKey(entry.getName())) + { + return false; + } + + if(!entry.pureVirtual) + { + ZipEntry zipentry = (ZipEntry)entry; + + finished = false; + + rais.close(); + + int delta = AuxClass.updateFileData(file, new byte[0], zipentry.offset, zipentry.offset + zipentry.getLocalSize()); + cder.centralOffset += delta; + file.truncate(cder.centralOffset); + + rais = new FileInputStream(file); + + updateOffset(zipentry.offset, delta); + } + + entries.remove(entry.getName()); + deleteFile(entry.getName()); + + return true; + } + + /** + * Rename specified entry. + */ + public boolean renameEntry(ContainerEntry entry, String newName) throws IOException + { + if(!entry.pureVirtual) + { + ZipEntry zipentry = (ZipEntry)entry; + + checkReadOnly(); + checkEntries(); + + byte[] b = StringEncoder.encodeString(newName, StringEncoder.ENC_ARCHIVE); + finished = false; + + rais.close(); + + int delta = AuxClass.updateFileData(file, b, zipentry.offset + ZipConstants.LOCHDR, zipentry.offset + ZipConstants.LOCHDR + StringEncoder.getEncodedLength(zipentry.getName(), StringEncoder.ENC_ARCHIVE)); + cder.centralOffset += delta; + file.truncate(cder.centralOffset); + + int len = b.length; + + b = new byte[2]; + b[0] = (byte)(len & 0xFF); + b[1] = (byte)((len & 0xFF) >> 8); + + AuxClass.updateFileData(file, b, zipentry.offset + ZipConstants.LOCNAM, zipentry.offset + ZipConstants.LOCNAM + 2); + + rais = new FileInputStream(file); + + updateOffset(zipentry.offset, delta); + } + + Directory.renameFile(files, null, entry.getName(), newName); + entries.remove(entry.getName()); + entry.setName(newName); + entries.put(entry.getName(), entry); + + return true; + } + + /** + * Write central directory at the end of file. + */ + public void finish() throws IOException + { + if(finished) + { + return; + } + + checkReadOnly(); + + ProgressCallback callback = ProgressBar.getProgressCallback(); + ProgressBar.show(); + + callback.setText(Locale.getString(this, Locale.WRITING_FILE, file.getName())); + callback.setProgress(0); + callback.setMax(size()); + callback.setPercentMode(false); + + Enumeration enm = entries(); + ZipEntry entry; + + cder.centralSize = 0; + cder.numEntries = 0; + + OutputStream os = file.openOutputStream(cder.centralOffset); + + while(enm.hasMoreElements()) + { + entry = (ZipEntry)enm.nextElement(); + + cder.centralSize += entry.writeCentralHeader(os); + cder.numEntries++; + + callback.progress(1); + } + + cder.write(os); + + os.flush(); + os.close(); + + finished = true; + + callback.setPercentMode(true); + ProgressBar.hide(); + } + + /** + * Creates an input stream reading the given zip entry as + * uncompressed data. Normally zip entry should be an entry + * returned by getEntry() or entries(). + * + * This implementation returns null if the requested entry does not + * exist. This decision is not obviously correct, however, it does + * appear to mirror Sun's implementation, and it is consistant with + * their javadoc. On the other hand, the old JCL book, 2nd Edition, + * claims that this should return a "non-null ZIP entry". We have + * chosen for now ignore the old book, as modern versions of Ant (an + * important application) depend on this behaviour. See discussion + * in this thread: + * http://gcc.gnu.org/ml/java-patches/2004-q2/msg00602.html + * + * @param entry the entry to create an InputStream for. + * @return the input stream, or null if the requested entry does not exist. + * + * @exception IllegalStateException when the ZipFile has already been closed + * @exception IOException if a i/o error occured. + * @exception ZipException if the Zip archive is malformed. + */ + public InputStream getInputStream(ContainerEntry entry) throws IOException + { + ZipEntry zipentry = (ZipEntry)entry; + ZipEntry readEntry = new ZipEntry(); + + rais.setPosition(zipentry.offset); + + if(!readEntry.readLocalHeader(rais)) + { + throw new ZipException("Wrong Local Header signature"); + } + + PartialInputStream inp = new PartialInputStream(rais, rais.getPosition(), zipentry.getCompressedSize()); + + switch(zipentry.getMethod()) + { + case STORED: + return inp; + + case DEFLATED: + inp.addDummyByte(); + final Inflater inf = new Inflater(true); + final int sz = zipentry.getSize(); + + return new InflaterInputStream(inp, inf) + { + public int available() throws IOException + { + if(sz == -1) + { + return super.available(); + } + + if(super.available() != 0) + { + return sz - inf.getTotalOut(); + } + + return 0; + } + }; + + default: + throw new ZipException("Unknown compression method " + zipentry.getMethod()); + } + } + +// private static void out(String s) +// { +// System.out.println("[ZipFile] " + s); +// } +} diff --git a/src/com/classpath/zip/ZipInputStream.java b/src/com/classpath/zip/ZipInputStream.java new file mode 100644 index 0000000..491d58d --- /dev/null +++ b/src/com/classpath/zip/ZipInputStream.java @@ -0,0 +1,382 @@ +/* ZipInputStream.java -- + Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +//package java.util.zip; +package com.classpath.zip; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; + +/** + * This is a FilterInputStream that reads the files in an zip archive + * one after another. It has a special method to get the zip entry of + * the next file. The zip entry contains information about the file name + * size, compressed size, CRC, etc. + * + * It includes support for STORED and DEFLATED entries. + * + * @author Jochen Hoenicke + */ +public class ZipInputStream extends InflaterInputStream +{ + private CRC32 crc = new CRC32(); + private ZipEntry entry = null; + + private int csize; + private int size; + private int method; + private int flags; + private int avail; + private boolean entryAtEOF; + + /** + * Creates a new Zip input stream, reading a zip archive. + */ + public ZipInputStream(InputStream in) + { + super(in, new Inflater(true)); + } + + private void fillBuf() throws IOException + { + avail = len = in.read(buf, 0, buf.length); + } + + private int readBuf(byte[] out, int offset, int length) throws IOException + { + if(avail <= 0) + { + fillBuf(); + if(avail <= 0) + return -1; + } + if(length > avail) + length = avail; + System.arraycopy(buf, len - avail, out, offset, length); + avail -= length; + return length; + } + + private void readFully(byte[] out) throws IOException + { + int off = 0; + int len = out.length; + while(len > 0) + { + int count = readBuf(out, off, len); + if(count == -1) + throw new EOFException(); + off += count; + len -= count; + } + } + + private int readLeByte() throws IOException + { + if(avail <= 0) + { + fillBuf(); + if(avail <= 0) + throw new ZipException("EOF in header"); + } + return buf[len - avail--] & 0xff; + } + + /** + * Read an unsigned short in little endian byte order. + */ + private int readLeShort() throws IOException + { + return readLeByte() | (readLeByte() << 8); + } + + /** + * Read an int in little endian byte order. + */ + private int readLeInt() throws IOException + { + return readLeShort() | (readLeShort() << 16); + } + + /** + * Open the next entry from the zip archive, and return its description. + * If the previous entry wasn't closed, this method will close it. + */ + public ZipEntry getNextEntry() throws IOException + { + if(crc == null) + throw new IOException("Stream closed."); + if(entry != null) + closeEntry(); + + int header = readLeInt(); + if(header == ZipConstants.CENSIG) + { + /* Central Header reached. */ + close(); + return null; + } + if(header != ZipConstants.LOCSIG) + throw new ZipException("Wrong Local header signature: " + + Integer.toHexString(header)); + /* skip version */ + readLeShort(); + flags = readLeShort(); + method = readLeShort(); + int dostime = readLeInt(); + int crc = readLeInt(); + csize = readLeInt(); + size = readLeInt(); + int nameLen = readLeShort(); + int extraLen = readLeShort(); + + if(method == ZipOutputStream.STORED && csize != size) + throw new ZipException("Stored, but compressed != uncompressed"); + + + byte[] buffer = new byte[nameLen]; + readFully(buffer); + String name; + try + { + name = new String(buffer, "UTF-8"); + } + catch(UnsupportedEncodingException uee) + { + throw new IOException("Assertion error: " + uee.getMessage()); + } + + entry = createZipEntry(name); + entryAtEOF = false; + entry.setMethod(method); + if((flags & 8) == 0) + { + entry.setCRC(crc); + entry.setSize(size); + entry.setCompressedSize(csize); + } + entry.setDOSTime(dostime); + if(extraLen > 0) + { + byte[] extra = new byte[extraLen]; + readFully(extra); + entry.setExtra(extra); + } + + if(method == ZipOutputStream.DEFLATED && avail > 0) + { + System.arraycopy(buf, len - avail, buf, 0, avail); + len = avail; + avail = 0; + inf.setInput(buf, 0, len); + } + return entry; + } + + private void readDataDescr() throws IOException + { + if(readLeInt() != ZipConstants.EXTSIG) + throw new ZipException("Data descriptor signature not found"); + entry.setCRC(readLeInt()); + csize = readLeInt(); + size = readLeInt(); + entry.setSize(size); + entry.setCompressedSize(csize); + } + + /** + * Closes the current zip entry and moves to the next one. + */ + public void closeEntry() throws IOException + { + if(crc == null) + throw new IOException("Stream closed."); + if(entry == null) + return; + + if(method == ZipOutputStream.DEFLATED) + { + if((flags & 8) != 0) + { + /* We don't know how much we must skip, read until end. */ + byte[] tmp = new byte[2048]; + while(read(tmp) > 0) + ; + + /* read will close this entry */ + return; + } + csize -= inf.getTotalIn(); + avail = inf.getRemaining(); + } + + if(avail > csize && csize >= 0) + avail -= csize; + else + { + csize -= avail; + avail = 0; + while(csize != 0) + { + long skipped = in.skip(csize & 0xffffffffL); + if(skipped <= 0) + throw new ZipException("zip archive ends early."); + csize -= skipped; + } + } + + size = 0; + crc.reset(); + if(method == ZipOutputStream.DEFLATED) + inf.reset(); + entry = null; + entryAtEOF = true; + } + + public int available() throws IOException + { + return entryAtEOF ? 0 : 1; + } + + /** + * Reads a byte from the current zip entry. + * @return the byte or -1 on EOF. + * @exception IOException if a i/o error occured. + * @exception ZipException if the deflated stream is corrupted. + */ + public int read() throws IOException + { + byte[] b = new byte[1]; + if(read(b, 0, 1) <= 0) + return -1; + return b[0] & 0xff; + } + + /** + * Reads a block of bytes from the current zip entry. + * @return the number of bytes read (may be smaller, even before + * EOF), or -1 on EOF. + * @exception IOException if a i/o error occured. + * @exception ZipException if the deflated stream is corrupted. + */ + public int read(byte[] b, int off, int len) throws IOException + { + if(len == 0) + return 0; + if(crc == null) + throw new IOException("Stream closed."); + if(entry == null) + return -1; + boolean finished = false; + switch(method) + { + case ZipOutputStream.DEFLATED: + len = super.read(b, off, len); + if(len < 0) + { + if(!inf.finished()) + throw new ZipException("Inflater not finished!?"); + avail = inf.getRemaining(); + if((flags & 8) != 0) + readDataDescr(); + + if(inf.getTotalIn() != csize + || inf.getTotalOut() != size) + throw new ZipException("size mismatch: " + csize + ";" + size + " <-> " + inf.getTotalIn() + ";" + inf.getTotalOut()); + inf.reset(); + finished = true; + } + break; + + case ZipOutputStream.STORED: + + if(len > csize && csize >= 0) + len = csize; + + len = readBuf(b, off, len); + if(len > 0) + { + csize -= len; + size -= len; + } + + if(csize == 0) + finished = true; + else if(len < 0) + throw new ZipException("EOF in stored block"); + break; + } + + if(len > 0) + crc.update(b, off, len); + + if(finished) + { + if((crc.getValue() & 0xffffffffL) != entry.getCRC()) + throw new ZipException("CRC mismatch"); + crc.reset(); + entry = null; + entryAtEOF = true; + } + return len; + } + + /** + * Closes the zip file. + * @exception IOException if a i/o error occured. + */ + public void close() throws IOException + { + super.close(); + crc = null; + entry = null; + entryAtEOF = true; + } + + /** + * Creates a new zip entry for the given name. This is equivalent + * to new ZipEntry(name). + * @param name the name of the zip entry. + */ + protected ZipEntry createZipEntry(String name) + { + return new ZipEntry(name); + } +} diff --git a/src/com/classpath/zip/ZipOutputStream.java b/src/com/classpath/zip/ZipOutputStream.java new file mode 100644 index 0000000..d267ef9 --- /dev/null +++ b/src/com/classpath/zip/ZipOutputStream.java @@ -0,0 +1,467 @@ +/* java.util.zip.ZipOutputStream + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package com.classpath.zip; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.Vector; + +/** + * This is a FilterOutputStream that writes the files into a zip + * archive one after another. It has a special method to start a new + * zip entry. The zip entries contains information about the file name + * size, compressed size, CRC, etc. + * + * It includes support for STORED and DEFLATED entries. + * + * This class is not thread safe. + * Referenced classes from java.util.zip: + * DeflaterOutputStream, Deflater, ZipConstants, ZipEntry, ZipException + * + * @author Jochen Hoenicke + */ +public class ZipOutputStream extends DeflaterOutputStream +{ + private Vector entries = new Vector(); + private CRC32 crc = new CRC32(); + private ZipEntry curEntry = null; + + private int curMethod; + private int size; + private int offset = 0; + + private byte[] zipComment = new byte[0]; + private int defaultMethod = DEFLATED; + + /** + * Our Zip version is hard coded to 1.0 resp. 2.0 + */ + private final static int ZIP_STORED_VERSION = 10; + private final static int ZIP_DEFLATED_VERSION = 20; + + /** + * Compression method. This method doesn't compress at all. + */ + public final static int STORED = 0; + /** + * Compression method. This method uses the Deflater. + */ + public final static int DEFLATED = 8; + + /** + * Creates a new Zip output stream, writing a zip archive. + * @param out the output stream to which the zip archive is written. + */ + public ZipOutputStream(OutputStream out) + { + super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true)); + } + + /** + * Set the zip file comment. + * @param comment the comment. + * @exception IllegalArgumentException if encoding of comment is + * longer than 0xffff bytes. + */ + public void setComment(String comment) + { + byte[] commentBytes; + commentBytes = comment.getBytes(); + if(commentBytes.length > 0xffff) + throw new IllegalArgumentException("Comment too long."); + zipComment = commentBytes; + } + + /** + * Sets default compression method. If the Zip entry specifies + * another method its method takes precedence. + * @param method the method. + * @exception IllegalArgumentException if method is not supported. + * @see #STORED + * @see #DEFLATED + */ + public void setMethod(int method) + { + if(method != STORED && method != DEFLATED) + { + throw new IllegalArgumentException("Method not supported."); + } + + defaultMethod = method; + } + + /** + * Sets default compression level. The new level will be activated + * immediately. + * @exception IllegalArgumentException if level is not supported. + * @see Deflater + */ + public void setLevel(int level) + { + def.setLevel(level); + } + + /** + * Write an unsigned short in little endian byte order. + */ + private final void writeLeShort(int value) throws IOException + { + out.write(value & 0xff); + out.write((value >> 8) & 0xff); + } + + /** + * Write an int in little endian byte order. + */ + private final void writeLeInt(int value) throws IOException + { + writeLeShort(value); + writeLeShort(value >> 16); + } + + /** + * Starts a new Zip entry. It automatically closes the previous + * entry if present. If the compression method is stored, the entry + * must have a valid size and crc, otherwise all elements (except + * name) are optional, but must be correct if present. If the time + * is not set in the entry, the current time is used. + * @param entry the entry. + * @exception IOException if an I/O error occured. + * @exception ZipException if stream was finished. + */ + public void putNextEntry(ZipEntry entry) throws IOException + { + if(entries == null) + { + throw new ZipException("ZipOutputStream was finished"); + } + + int method = entry.getMethod(); + int flags = 0; + + if(method == -1) + { + method = defaultMethod; + } + + if(method == STORED) + { + if(entry.getCompressedSize() >= 0) + { + if(entry.getSize() < 0) + { + entry.setSize(entry.getCompressedSize()); + } + else if(entry.getSize() != entry.getCompressedSize()) + { + throw new ZipException("Method STORED, but compressed size != size"); + } + } + else + { + entry.setCompressedSize(entry.getSize()); + } + + if(entry.getSize() < 0) + { + throw new ZipException("Method STORED, but size not set"); + } + + if(entry.getCRC() < 0) + { + throw new ZipException("Method STORED, but crc not set"); + } + } + else if(method == DEFLATED) + { + if(entry.getCompressedSize() < 0 || entry.getSize() < 0 || entry.getCRC() < 0) + { + flags |= 8; + } + } + + if(curEntry != null) + { + closeEntry(); + } + + if(entry.getLastModified() < 0) + { + entry.setLastModified(System.currentTimeMillis()); + } + + entry.flags = flags; + entry.offset = offset; + entry.setMethod(method); + curMethod = method; + + /* Write the local file header */ + writeLeInt(ZipConstants.LOCSIG); + writeLeShort(method == STORED ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION); + writeLeShort(flags); + writeLeShort(method); + writeLeInt(entry.getDOSTime()); + + if((flags & 8) == 0) + { + writeLeInt((int)entry.getCRC()); + writeLeInt((int)entry.getCompressedSize()); + writeLeInt((int)entry.getSize()); + } + else + { + writeLeInt(0); + writeLeInt(0); + writeLeInt(0); + } + + byte[] name = entry.getName().getBytes(); + + if(name.length > 0xffff) + { + throw new ZipException("Name too long."); + } + + byte[] extra = entry.getExtra(); + + if(extra == null) + { + extra = new byte[0]; + } + + writeLeShort(name.length); + writeLeShort(extra.length); + + out.write(name); + out.write(extra); + + offset += ZipConstants.LOCHDR + name.length + extra.length; + + /* Activate the entry. */ + + curEntry = entry; + + crc.reset(); + + if(method == DEFLATED) + { + def.reset(); + } + + size = 0; + } + + /** + * Closes the current entry. + * @exception IOException if an I/O error occured. + * @exception ZipException if no entry is active. + */ + public void closeEntry() throws IOException + { + if(curEntry == null) + { + throw new ZipException("No open entry"); + } + + /* First finish the deflater, if appropriate */ + if(curMethod == DEFLATED) + { + super.finish(); + } + + int csize = curMethod == DEFLATED ? def.getTotalOut() : size; + + if(curEntry.getSize() < 0) + { + curEntry.setSize(size); + } + else if(curEntry.getSize() != size) + { + throw new ZipException("size was " + size + ", but I expected " + curEntry.getSize()); + } + + if(curEntry.getCompressedSize() < 0) + { + curEntry.setCompressedSize(csize); + } + else if(curEntry.getCompressedSize() != csize) + { + throw new ZipException("compressed size was " + csize + ", but I expected " + curEntry.getSize()); + } + + if(curEntry.getCRC() < 0) + { + curEntry.setCRC((int)crc.getValue()); + } + else if(curEntry.getCRC() != crc.getValue()) + { + throw new ZipException("crc was " + Long.toString(crc.getValue(), 16) + ", but I expected " + Long.toString(curEntry.getCRC(), 16)); + } + + offset += csize; + + /* Now write the data descriptor entry if needed. */ + if(curMethod == DEFLATED && (curEntry.flags & 8) != 0) + { + writeLeInt(ZipConstants.EXTSIG); + writeLeInt((int)curEntry.getCRC()); + writeLeInt((int)curEntry.getCompressedSize()); + writeLeInt((int)curEntry.getSize()); + offset += ZipConstants.EXTHDR; + } + + entries.addElement(curEntry); + curEntry = null; + } + + /** + * Writes the given buffer to the current entry. + * @exception IOException if an I/O error occured. + * @exception ZipException if no entry is active. + */ + public void write(byte[] b, int off, int len) throws IOException + { + if(curEntry == null) + throw new ZipException("No open entry."); + + switch(curMethod) + { + case DEFLATED: + super.write(b, off, len); + break; + + case STORED: + out.write(b, off, len); + break; + } + + crc.update(b, off, len); + size += len; + } + + /** + * Finishes the stream. This will write the central directory at the + * end of the zip file and flush the stream. + * @exception IOException if an I/O error occured. + */ + public void finish() throws IOException + { + if(entries == null) + { + return; + } + + if(curEntry != null) + { + closeEntry(); + } + + int numEntries = 0; + int sizeEntries = 0; + + Enumeration enm = entries.elements(); + + while(enm.hasMoreElements()) + { + ZipEntry entry = (ZipEntry)enm.nextElement(); + + int method = entry.getMethod(); + + writeLeInt(ZipConstants.CENSIG); + + writeLeShort(method == STORED ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION); + writeLeShort(method == STORED ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION); + writeLeShort(entry.flags); + writeLeShort(method); + writeLeInt(entry.getDOSTime()); + writeLeInt((int)entry.getCRC()); + writeLeInt((int)entry.getCompressedSize()); + writeLeInt((int)entry.getSize()); + + byte[] name = entry.getName().getBytes(); + + if(name.length > 0xffff) + { + throw new ZipException("Name too long."); + } + + byte[] extra = entry.getExtra(); + + if(extra == null) + { + extra = new byte[0]; + } + + String strComment = entry.getComment(); + + byte[] comment = strComment != null ? strComment.getBytes() : new byte[0]; + + if(comment.length > 0xffff) + { + throw new ZipException("Comment too long."); + } + + writeLeShort(name.length); + writeLeShort(extra.length); + writeLeShort(comment.length); + writeLeShort(0); /* disk number */ + writeLeShort(0); /* internal file attr */ + writeLeInt(0); /* external file attr */ + writeLeInt(entry.offset); + + out.write(name); + out.write(extra); + out.write(comment); + numEntries++; + sizeEntries += ZipConstants.CENHDR + name.length + extra.length + comment.length; + } + + writeLeInt(ZipConstants.ENDSIG); + writeLeShort(0); /* disk number */ + writeLeShort(0); /* disk with start of central dir */ + writeLeShort(numEntries); + writeLeShort(numEntries); + writeLeInt(sizeEntries); + writeLeInt(offset); + writeLeShort(zipComment.length); + out.write(zipComment); + out.flush(); + entries = null; + } +} diff --git a/src/com/ibxm/Channel.java b/src/com/ibxm/Channel.java new file mode 100644 index 0000000..7823748 --- /dev/null +++ b/src/com/ibxm/Channel.java @@ -0,0 +1,947 @@ + +//package ibxm; +package com.ibxm; + +public class Channel { + public int pattern_loop_row; + + private Module module; + private Instrument instrument; + private Sample sample; + private int[] global_volume, current_note; + private boolean linear_periods, fast_volume_slides, key_on, silent; + private int sample_idx, sample_frac, step, left_gain, right_gain; + private int volume, panning, fine_tune, period, porta_period, key_add; + private int tremolo_speed, tremolo_depth, tremolo_tick, tremolo_wave, tremolo_add; + private int vibrato_speed, vibrato_depth, vibrato_tick, vibrato_wave, vibrato_add; + private int volume_slide_param, portamento_param, retrig_param; + private int volume_envelope_tick, panning_envelope_tick; + private int effect_tick, trigger_tick, fade_out_volume, random_seed; + + private int log_2_sampling_rate; + private static final int LOG_2_29024 = LogTable.log_2( 29024 ); + private static final int LOG_2_8287 = LogTable.log_2( 8287 ); + private static final int LOG_2_8363 = LogTable.log_2( 8363 ); + private static final int LOG_2_1712 = LogTable.log_2( 1712 ); + + private static final int[] sine_table = new int[] { + 0, 24 , 49, 74, 97, 120, 141, 161, 180, 197, 212, 224, 235, 244, 250, 253, + 255, 253, 250, 244, 235, 224, 212, 197, 180, 161, 141, 120, 97, 74, 49, 24 + }; + + public Channel( Module mod, int sampling_rate, int[] global_vol ) { + module = mod; + global_volume = global_vol; + linear_periods = module.linear_periods; + fast_volume_slides = module.fast_volume_slides; + current_note = new int[ 5 ]; + log_2_sampling_rate = LogTable.log_2( sampling_rate ); + } + + public void reset() { + tremolo_speed = 0; + tremolo_depth = 0; + tremolo_wave = 0; + vibrato_speed = 0; + vibrato_depth = 0; + vibrato_wave = 0; + volume_slide_param = 0; + portamento_param = 0; + retrig_param = 0; + random_seed = 0xABC123; + instrument = module.get_instrument( 0 ); + row( 48, 256, 0, 0, 0 ); + } + + public void resample( int[] mixing_buffer, int frame_offset, int frames, int quality ) { + if( !silent ) { + switch( quality ) { + default: + sample.resample_nearest( sample_idx, sample_frac, step, left_gain, right_gain, mixing_buffer, frame_offset, frames ); + break; + case 1: + sample.resample_linear( sample_idx, sample_frac, step, left_gain, right_gain, mixing_buffer, frame_offset, frames ); + break; + case 2: + sample.resample_sinc( sample_idx, sample_frac, step, left_gain, right_gain, mixing_buffer, frame_offset, frames ); + break; + } + } + } + + public void update_sample_idx( int samples ) { + sample_frac += step * samples; + sample_idx += sample_frac >> IBXM.FP_SHIFT; + sample_frac &= IBXM.FP_MASK; + } + + public void set_volume( int vol ) { + if( vol < 0 ) { + vol = 0; + } + if( vol > 64 ) { + vol = 64; + } + volume = vol; + } + + public void set_panning( int pan ) { + if( pan < 0 ) { + pan = 0; + } + if( pan > 255 ) { + pan = 255; + } + panning = pan; + } + + public void row( int key, int inst_idx, int volume_column, int effect, int effect_param ) { + effect = effect & 0xFF; + if( effect >= 0x30 ) { + /* Effects above 0x30 are internal.*/ + effect = 0; + } + if( effect == 0x00 && effect_param != 0 ) { + /* Arpeggio.*/ + effect = 0x40; + } + if( effect == 0x0E ) { + /* Renumber 0x0Ex effect command.*/ + effect = 0x30 + ( ( effect_param & 0xF0 ) >> 4 ); + effect_param = effect_param & 0x0F; + } + if( effect == 0x21 ) { + /* Renumber 0x21x effect command.*/ + effect = 0x40 + ( ( effect_param & 0xF0 ) >> 4 ); + effect_param = effect_param & 0x0F; + } + current_note[ 0 ] = key; + current_note[ 1 ] = inst_idx; + current_note[ 2 ] = volume_column; + current_note[ 3 ] = effect; + current_note[ 4 ] = effect_param; + effect_tick = 0; + trigger_tick += 1; + update_envelopes(); + key_add = 0; + vibrato_add = 0; + tremolo_add = 0; + if( ! ( effect == 0x3D && effect_param > 0 ) ) { + /* Not note delay.*/ + trigger( key, inst_idx, volume_column, effect ); + /* Handle volume column.*/ + switch( volume_column & 0xF0 ) { + case 0x00: + /* Do nothing.*/ + break; + case 0x60: + /* Volume slide down.*/ + break; + case 0x70: + /* Volume slide up.*/ + break; + case 0x80: + /* Fine volume slide down.*/ + set_volume( volume - ( volume_column & 0x0F ) ); + break; + case 0x90: + /* Fine volume slide up.*/ + set_volume( volume + ( volume_column & 0x0F ) ); + break; + case 0xA0: + /* Set vibrato speed.*/ + set_vibrato_speed( volume_column & 0x0F ); + break; + case 0xB0: + /* Vibrato.*/ + set_vibrato_depth( volume_column & 0x0F ); + vibrato(); + break; + case 0xC0: + /* Set panning.*/ + set_panning( ( volume_column & 0x0F ) << 4 ); + break; + case 0xD0: + /* Panning slide left.*/ + break; + case 0xE0: + /* Panning slide right.*/ + break; + case 0xF0: + /* Tone portamento.*/ + set_portamento_param( volume_column & 0x0F ); + break; + default: + /* Set volume.*/ + set_volume( volume_column - 0x10 ); + break; + } + } + if( instrument.vibrato_depth > 0 ) { + auto_vibrato(); + } + switch( effect ) { + case 0x01: + /* Portmento Up.*/ + set_portamento_param( effect_param ); + portamento_up(); + break; + case 0x02: + /* Portamento Down.*/ + set_portamento_param( effect_param ); + portamento_down(); + break; + case 0x03: + /* Tone Portamento.*/ + set_portamento_param( effect_param ); + break; + case 0x04: + /* Vibrato.*/ + set_vibrato_speed( ( effect_param & 0xF0 ) >> 4 ); + set_vibrato_depth( effect_param & 0x0F ); + vibrato(); + break; + case 0x05: + /* Tone Portamento + Volume Slide.*/ + set_volume_slide_param( effect_param ); + volume_slide(); + break; + case 0x06: + /* Vibrato + Volume Slide.*/ + set_volume_slide_param( effect_param ); + vibrato(); + volume_slide(); + break; + case 0x07: + /* Tremolo.*/ + set_tremolo_speed( ( effect_param & 0xF0 ) >> 4 ); + set_tremolo_depth( effect_param & 0x0F ); + tremolo(); + break; + case 0x08: + /* Set Panning.*/ + set_panning( effect_param ); + break; + case 0x09: + /* Set Sample Index.*/ + set_sample_index( effect_param << 8 ); + break; + case 0x0A: + /* Volume Slide.*/ + set_volume_slide_param( effect_param ); + volume_slide(); + break; + case 0x0B: + /* Pattern Jump.*/ + break; + case 0x0C: + /* Set volume.*/ + set_volume( effect_param ); + break; + case 0x0D: + /* Pattern Break.*/ + break; + case 0x0E: + /* Extended Commands (See 0x30-0x3F).*/ + break; + case 0x0F: + /* Set Speed/Tempo.*/ + break; + case 0x10: + /* Set Global Volume.*/ + set_global_volume( effect_param ); + break; + case 0x11: + /* global Volume Slide.*/ + set_volume_slide_param( effect_param ); + break; + case 0x14: + /* Key Off*/ + if( effect_param == 0 ) { + key_on = false; + } + break; + case 0x15: + /* Set Envelope Tick.*/ + set_envelope_tick( effect_param ); + break; + case 0x19: + /* Panning Slide.*/ + set_volume_slide_param( effect_param ); + break; + case 0x1B: + /* Retrig + Volume Slide.*/ + set_retrig_param( effect_param ); + retrig_volume_slide(); + break; + case 0x1D: + /* Tremor.*/ + set_retrig_param( effect_param ); + tremor(); + break; + case 0x24: + /* S3M Fine Vibrato.*/ + set_vibrato_speed( ( effect_param & 0xF0 ) >> 4 ); + set_vibrato_depth( effect_param & 0x0F ); + fine_vibrato(); + break; + case 0x25: + /* S3M Set Speed.*/ + break; + case 0x30: + /* Amiga Set Filter.*/ + break; + case 0x31: + /* Fine Portamento Up.*/ + set_portamento_param( 0xF0 | effect_param ); + portamento_up(); + break; + case 0x32: + /* Fine Portamento Down.*/ + set_portamento_param( 0xF0 | effect_param ); + portamento_down(); + break; + case 0x33: + /* Set Glissando Mode.*/ + break; + case 0x34: + /* Set Vibrato Waveform.*/ + set_vibrato_wave( effect_param ); + break; + case 0x35: + /* Set Fine Tune.*/ + break; + case 0x36: + /* Pattern Loop.*/ + break; + case 0x37: + /* Set Tremolo Waveform.*/ + set_tremolo_wave( effect_param ); + break; + case 0x38: + /* Set Panning(Obsolete).*/ + break; + case 0x39: + /* Retrig.*/ + set_retrig_param( effect_param ); + break; + case 0x3A: + /* Fine Volume Slide Up.*/ + set_volume_slide_param( ( effect_param << 4 ) | 0x0F ); + volume_slide(); + break; + case 0x3B: + /* Fine Volume Slide Down.*/ + set_volume_slide_param( 0xF0 | effect_param ); + volume_slide(); + break; + case 0x3C: + /* Note Cut.*/ + if( effect_param == 0 ) { + set_volume( 0 ); + } + break; + case 0x3D: + /* Note Delay.*/ + break; + case 0x3E: + /* Pattern Delay.*/ + break; + case 0x3F: + /* Invert Loop.*/ + break; + case 0x40: + /* Arpeggio.*/ + break; + case 0x41: + /* Extra Fine Porta Up.*/ + set_portamento_param( 0xE0 | effect_param ); + portamento_up(); + break; + case 0x42: + /* Extra Fine Porta Down.*/ + set_portamento_param( 0xE0 | effect_param ); + portamento_down(); + break; + } + calculate_amplitude(); + calculate_frequency(); + } + + public void tick() { + int volume_column, effect, effect_param; + volume_column = current_note[ 2 ]; + effect = current_note[ 3 ]; + effect_param = current_note[ 4 ]; + effect_tick += 1; + if( effect == 0x3D && effect_param == effect_tick ) { + /* Note delay.*/ + row( current_note[ 0 ], current_note[ 1 ], volume_column, 0, 0 ); + } else { + trigger_tick += 1; + vibrato_tick += 1; + tremolo_tick += 1; + update_envelopes(); + key_add = 0; + vibrato_add = 0; + tremolo_add = 0; + if( instrument.vibrato_depth > 0 ) { + auto_vibrato(); + } + switch( volume_column & 0xF0 ) { + case 0x60: + /* Volume Slide Down.*/ + set_volume( volume - ( volume_column & 0x0F ) ); + break; + case 0x70: + /* Volume Slide Up.*/ + set_volume( volume + ( volume_column & 0x0F ) ); + break; + case 0xB0: + /* Vibrato.*/ + vibrato(); + break; + case 0xD0: + /* Panning Slide Left.*/ + set_panning( panning - ( volume_column & 0x0F ) ); + break; + case 0xE0: + /* Panning Slide Right.*/ + set_panning( panning + ( volume_column & 0x0F ) ); + break; + case 0xF0: + /* Tone Portamento.*/ + tone_portamento(); + break; + } + switch( effect ) { + case 0x01: + /* Portamento Up.*/ + portamento_up(); + break; + case 0x02: + /* Portamento Down.*/ + portamento_down(); + break; + case 0x03: + /* Tone Portamento.*/ + tone_portamento(); + break; + case 0x04: + /* Vibrato.*/ + vibrato(); + break; + case 0x05: + /* Tone Portamento + Volume Slide.*/ + tone_portamento(); + volume_slide(); + break; + case 0x06: + /* Vibrato + Volume Slide */ + vibrato(); + volume_slide(); + break; + case 0x07: + /* Tremolo.*/ + tremolo(); + break; + case 0x0A: + /* Volume Slide.*/ + volume_slide(); + break; + case 0x11: + /* Global Volume Slide.*/ + global_volume_slide(); + break; + case 0x14: + /* Key off.*/ + if( effect_tick == effect_param ) { + key_on = false; + } + break; + case 0x19: + /* Panning Slide.*/ + panning_slide(); + break; + case 0x1B: + /* Retrig + Volume Slide.*/ + retrig_volume_slide(); + break; + case 0x1D: + /* Tremor.*/ + tremor(); + break; + case 0x24: + /* S3M Fine Vibrato.*/ + fine_vibrato(); + break; + case 0x39: + /* Retrig.*/ + retrig_volume_slide(); + break; + case 0x3C: + /* Note Cut.*/ + if( effect_tick == effect_param ) { + set_volume( 0 ); + } + break; + case 0x40: + /* Arpeggio.*/ + switch( effect_tick % 3 ) { + case 1: + key_add = ( effect_param & 0xF0 ) >> 4; + break; + case 2: + key_add = effect_param & 0x0F; + break; + } + break; + } + } + calculate_amplitude(); + calculate_frequency(); + } + + private void set_vibrato_speed( int speed ) { + if( speed > 0 ) { + vibrato_speed = speed; + } + } + + private void set_vibrato_depth( int depth ) { + if( depth > 0 ) { + vibrato_depth = depth; + } + } + + private void set_vibrato_wave( int wave ) { + if( wave < 0 || wave > 7 ) { + wave = 0; + } + vibrato_wave = wave; + } + + private void set_tremolo_speed( int speed ) { + if( speed > 0 ) { + tremolo_speed = speed; + } + } + + private void set_tremolo_depth( int depth ) { + if( depth > 0 ) { + tremolo_depth = depth; + } + } + + private void set_tremolo_wave( int wave ) { + if( wave < 0 || wave > 7 ) { + wave = 0; + } + tremolo_wave = wave; + } + + private void vibrato() { + int vibrato_phase; + vibrato_phase = vibrato_tick * vibrato_speed; + vibrato_add += waveform( vibrato_phase, vibrato_wave ) * vibrato_depth >> 5; + } + + private void fine_vibrato() { + int vibrato_phase; + vibrato_phase = vibrato_tick * vibrato_speed; + vibrato_add += waveform( vibrato_phase, vibrato_wave ) * vibrato_depth >> 7; + } + + private void tremolo() { + int tremolo_phase; + tremolo_phase = tremolo_tick * tremolo_speed; + tremolo_add += waveform( tremolo_phase, tremolo_wave ) * tremolo_depth >> 6; + } + + private void set_portamento_param( int param ) { + if( param != 0 ) { + portamento_param = param; + } + } + + private void tone_portamento() { + int new_period; + if( porta_period < period ) { + new_period = period - ( portamento_param << 2 ); + if( new_period < porta_period ) { + new_period = porta_period; + } + set_period( new_period ); + } + if( porta_period > period ) { + new_period = period + ( portamento_param << 2 ); + if( new_period > porta_period ) { + new_period = porta_period; + } + set_period( new_period ); + } + } + + private void portamento_up() { + if( ( portamento_param & 0xF0 ) == 0xE0 ) { + /* Extra-fine porta.*/ + if( effect_tick == 0 ) { + set_period( period - ( portamento_param & 0x0F ) ); + } + } else if( ( portamento_param & 0xF0 ) == 0xF0 ) { + /* Fine porta.*/ + if( effect_tick == 0 ) { + set_period( period - ( ( portamento_param & 0x0F ) << 2 ) ); + } + } else { + /* Normal porta.*/ + if( effect_tick > 0 ) { + set_period( period - ( portamento_param << 2 ) ); + } + } + } + + private void portamento_down() { + if( ( portamento_param & 0xF0 ) == 0xE0 ) { + /* Extra-fine porta.*/ + if( effect_tick == 0 ) { + set_period( period + ( portamento_param & 0x0F ) ); + } + } else if( ( portamento_param & 0xF0 ) == 0xF0 ) { + /* Fine porta.*/ + if( effect_tick == 0 ) { + set_period( period + ( ( portamento_param & 0x0F ) << 2 ) ); + } + } else { + /* Normal porta.*/ + if( effect_tick > 0 ) { + set_period( period + ( portamento_param << 2 ) ); + } + } + } + + private void set_period( int p ) { + if( p < 32 ) { + p = 32; + } + if( p > 32768 ) { + p = 32768; + } + period = p; + } + + private void set_global_volume( int vol ) { + if( vol < 0 ) { + vol = 0; + } + if( vol > 64 ) { + vol = 64; + } + global_volume[ 0 ] = vol; + } + + private void set_volume_slide_param( int param ) { + if( param != 0 ) { + volume_slide_param = param; + } + } + + private void global_volume_slide() { + int up, down; + up = ( volume_slide_param & 0xF0 ) >> 4; + down = volume_slide_param & 0x0F; + set_global_volume( global_volume[ 0 ] + up - down ); + } + + private void volume_slide() { + int up, down; + up = ( volume_slide_param & 0xF0 ) >> 4; + down = volume_slide_param & 0x0F; + if( down == 0x0F && up > 0 ) { + /* Fine slide up.*/ + if( effect_tick == 0 ) { + set_volume( volume + up ); + } + } else if( up == 0x0F && down > 0 ) { + /* Fine slide down.*/ + if( effect_tick == 0 ) { + set_volume( volume - down ); + } + } else { + /* Normal slide.*/ + if( effect_tick > 0 || fast_volume_slides ) { + set_volume( volume + up - down ); + } + } + } + + private void panning_slide() { + int left, right; + left = ( volume_slide_param & 0xF0 ) >> 4; + right = volume_slide_param & 0x0F; + set_panning( panning - left + right ); + } + + private void set_retrig_param( int param ) { + if( param != 0 ) { + retrig_param = param; + } + } + + private void tremor() { + int on_ticks, cycle_length, cycle_index; + on_ticks = ( ( retrig_param & 0xF0 ) >> 4 ) + 1; + cycle_length = on_ticks + ( retrig_param & 0x0F ) + 1; + cycle_index = trigger_tick % cycle_length; + if( cycle_index >= on_ticks ) { + tremolo_add = -64; + } + } + + private void retrig_volume_slide() { + int retrig_volume, retrig_tick; + retrig_volume = ( retrig_param & 0xF0 ) >> 4; + retrig_tick = retrig_param & 0x0F; + if( retrig_tick > 0 && ( trigger_tick % retrig_tick ) == 0 ) { + set_sample_index( 0 ); + switch( retrig_volume ) { + case 0x01: + set_volume( volume - 1 ); + break; + case 0x02: + set_volume( volume - 2 ); + break; + case 0x03: + set_volume( volume - 4 ); + break; + case 0x04: + set_volume( volume - 8 ); + break; + case 0x05: + set_volume( volume - 16 ); + break; + case 0x06: + set_volume( volume - volume / 3 ); + break; + case 0x07: + set_volume( volume / 2 ); + break; + case 0x09: + set_volume( volume + 1 ); + break; + case 0x0A: + set_volume( volume + 2 ); + break; + case 0x0B: + set_volume( volume + 4 ); + break; + case 0x0C: + set_volume( volume + 8 ); + break; + case 0x0D: + set_volume( volume + 16 ); + break; + case 0x0E: + set_volume( volume + volume / 2 ); + break; + case 0x0F: + set_volume( volume * 2 ); + break; + } + } + } + + private void set_sample_index( int index ) { + if( index < 0 ) { + index = 0; + } + sample_idx = index; + sample_frac = 0; + } + + private void set_envelope_tick( int tick ) { + volume_envelope_tick = tick; + panning_envelope_tick = tick; + } + + private void trigger( int key, int instrument_idx, int volume_column, int effect ) { + if( instrument_idx > 0 ) { + instrument = module.get_instrument( instrument_idx ); + sample = instrument.get_sample_from_key( key ); + set_volume( sample.volume ); + if( sample.set_panning ) { + set_panning( sample.panning ); + } + set_envelope_tick( 0 ); + fade_out_volume = 32768; + key_on = true; + } + if( key > 0 ) { + if( key < 97 ) { + porta_period = key_to_period( key ); + if( effect != 0x03 && effect != 0x05 ) { + if( ( volume_column & 0xF0 ) != 0xF0 ) { + /* Not portamento.*/ + trigger_tick = 0; + if( vibrato_wave < 4 ) { + vibrato_tick = 0; + } + if( tremolo_wave < 4 ) { + tremolo_tick = 0; + } + set_period( porta_period ); + set_sample_index( 0 ); + } + } + } else { + /* Key off.*/ + key_on = false; + } + } + } + + private void update_envelopes() { + Envelope envelope; + if( instrument.volume_envelope_active ) { + if( !key_on ) { + fade_out_volume -= instrument.volume_fade_out & 0xFFFF; + if( fade_out_volume < 0 ) { + fade_out_volume = 0; + } + } + envelope = instrument.get_volume_envelope(); + volume_envelope_tick = envelope.next_tick( volume_envelope_tick, key_on ); + } + if( instrument.panning_envelope_active ) { + envelope = instrument.get_panning_envelope(); + panning_envelope_tick = envelope.next_tick( panning_envelope_tick, key_on ); + } + } + + private void auto_vibrato() { + int sweep, depth, rate; + sweep = instrument.vibrato_sweep & 0xFF; + depth = instrument.vibrato_depth & 0x0F; + rate = instrument.vibrato_rate & 0x3F; + if( trigger_tick < sweep ) { + depth = depth * trigger_tick / sweep; + } + vibrato_add += waveform( trigger_tick * rate, 0 ) * depth >> 9; + } + + private int waveform( int phase, int wform ) { + int amplitude; + amplitude = 0; + switch( wform & 0x3 ) { + case 0: + /* Sine. */ + if( ( phase & 0x20 ) == 0 ) { + amplitude = sine_table[ phase & 0x1F ]; + } else { + amplitude = -sine_table[ phase & 0x1F ]; + } + break; + case 1: + /* Saw. */ + if( ( phase & 0x20 ) == 0 ) { + amplitude = ( phase & 0x1F ) << 3; + } else { + amplitude = ( ( phase & 0x1F ) << 3 ) - 255; + } + break; + case 2: + /* Square. */ + if( ( phase & 0x20 ) == 0 ) { + amplitude = 255; + } else { + amplitude = -255; + } + break; + case 3: + /* Random. */ + amplitude = ( random_seed >> 15 ) - 255; + random_seed = ( random_seed * 65 + 17 ) & 0xFFFFFF; + break; + } + return amplitude; + } + + private int key_to_period( int key ) { + int octave, log_2_period, period_out; + octave = ( key << IBXM.FP_SHIFT ) / 12 + sample.transpose; + if( linear_periods ) { + period_out = 7744 - ( octave * 768 >> IBXM.FP_SHIFT ); + } else { + log_2_period = LOG_2_29024 - octave; + period_out = LogTable.raise_2( log_2_period ); + period_out = period_out >> ( IBXM.FP_SHIFT - 1 ); + period_out = ( period_out >> 1 ) + ( period_out & 1 ); + } + return period_out; + } + + private void calculate_amplitude() { + int envelope_volume, tremolo_volume, amplitude; + int envelope_panning, mixer_panning, panning_range; + Envelope envelope; + envelope_volume = 0; + if( instrument.volume_envelope_active ) { + envelope = instrument.get_volume_envelope(); + envelope_volume = envelope.calculate_ampl( volume_envelope_tick ); + } else { + if( key_on ) { + envelope_volume = 64; + } + } + tremolo_volume = volume + tremolo_add; + if( tremolo_volume < 0 ) { + tremolo_volume = 0; + } + if( tremolo_volume > 64 ) { + tremolo_volume = 64; + } + amplitude = tremolo_volume << IBXM.FP_SHIFT - 6; + amplitude = amplitude * envelope_volume >> 6; + amplitude = amplitude * fade_out_volume >> 15; + amplitude = amplitude * global_volume[ 0 ] >> 6; + amplitude = amplitude * module.channel_gain >> IBXM.FP_SHIFT; + silent = sample.has_finished( sample_idx ); + if( amplitude <= 0 ) { + silent = true; + } else { + envelope_panning = 32; + if( instrument.panning_envelope_active ) { + envelope = instrument.get_panning_envelope(); + envelope_panning = envelope.calculate_ampl( panning_envelope_tick ); + } + mixer_panning = ( panning & 0xFF ) << IBXM.FP_SHIFT - 8; + panning_range = IBXM.FP_ONE - mixer_panning; + if( panning_range > mixer_panning ) { + panning_range = mixer_panning; + } + mixer_panning = mixer_panning + ( panning_range * ( envelope_panning - 32 ) >> 5 ); + left_gain = amplitude * ( IBXM.FP_ONE - mixer_panning ) >> IBXM.FP_SHIFT; + right_gain = amplitude * mixer_panning >> IBXM.FP_SHIFT; + } + } + + private void calculate_frequency() { + int vibrato_period, log_2_freq; + vibrato_period = period + vibrato_add; + if( vibrato_period < 32 ) { + vibrato_period = 32; + } + if( vibrato_period > 32768 ) { + vibrato_period = 32768; + } + if( linear_periods ) { + log_2_freq = LOG_2_8363 + ( 4608 - vibrato_period << IBXM.FP_SHIFT ) / 768; + } else { + log_2_freq = module.pal ? LOG_2_8287 : LOG_2_8363; + log_2_freq = log_2_freq + LOG_2_1712 - LogTable.log_2( vibrato_period ); + } + log_2_freq += ( key_add << IBXM.FP_SHIFT ) / 12; + step = LogTable.raise_2( log_2_freq - log_2_sampling_rate ); + } +} + diff --git a/src/com/ibxm/Envelope.java b/src/com/ibxm/Envelope.java new file mode 100644 index 0000000..8a0edf9 --- /dev/null +++ b/src/com/ibxm/Envelope.java @@ -0,0 +1,112 @@ + +//package ibxm; +package com.ibxm; + +public class Envelope { + public boolean sustain, looped; + private int sustain_tick, loop_start_tick, loop_end_tick; + private int[] ticks, ampls; + + public Envelope() { + set_num_points( 1 ); + } + + public void set_num_points( int num_points ) { + int point; + if( num_points <= 0 ) { + num_points = 1; + } + ticks = new int[ num_points ]; + ampls = new int[ num_points ]; + set_point( 0, 0, 0, false ); + } + + /* When you set a point, all subsequent points are reset. */ + public void set_point( int point, int tick, int ampl, boolean delta ) { + if( point >= 0 && point < ticks.length ) { + if( point == 0 ) { + tick = 0; + } + if( point > 0 ) { + if( delta ) tick += ticks[ point - 1 ]; + if( tick <= ticks[ point - 1 ] ) { + System.out.println( "Envelope: Point not valid (" + tick + " <= " + ticks[ point - 1 ] + ")"); + tick = ticks[ point - 1 ] + 1; + } + } + ticks[ point ] = tick; + ampls[ point ] = ampl; + point += 1; + while( point < ticks.length ) { + ticks[ point ] = ticks[ point - 1 ] + 1; + ampls[ point ] = 0; + point += 1; + } + } + } + + public void set_sustain_point( int point ) { + if( point < 0 ) { + point = 0; + } + if( point >= ticks.length ) { + point = ticks.length - 1; + } + sustain_tick = ticks[ point ]; + } + + public void set_loop_points( int start, int end ) { + if( start < 0 ) { + start = 0; + } + if( start >= ticks.length ) { + start = ticks.length - 1; + } + if( end < start || end >= ticks.length ) { + end = start; + } + loop_start_tick = ticks[ start ]; + loop_end_tick = ticks[ end ]; + } + + public int next_tick( int tick, boolean key_on ) { + tick = tick + 1; + if( looped && tick >= loop_end_tick ) { + tick = loop_start_tick; + } + if( sustain && key_on && tick >= sustain_tick ) { + tick = sustain_tick; + } + return tick; + } + + public int calculate_ampl( int tick ) { + int idx, point, delta_t, delta_a, ampl; + ampl = ampls[ ticks.length - 1 ]; + if( tick < ticks[ ticks.length - 1 ] ) { + point = 0; + for( idx = 1; idx < ticks.length; idx++ ) { + if( ticks[ idx ] <= tick ) { + point = idx; + } + } + delta_t = ticks[ point + 1 ] - ticks[ point ]; + delta_a = ampls[ point + 1 ] - ampls[ point ]; + ampl = ( delta_a << IBXM.FP_SHIFT ) / delta_t; + ampl = ampl * ( tick - ticks[ point ] ) >> IBXM.FP_SHIFT; + ampl = ampl + ampls[ point ]; + } + return ampl; + } + + public void dump() { + int idx, tick; + for( idx = 0; idx < ticks.length; idx++ ) { + System.out.println( ticks[ idx ] + ", " + ampls[ idx ] ); + } + for( tick = 0; tick < 222; tick++ ) { + System.out.print( calculate_ampl( tick ) + ", " ); + } + } +} + diff --git a/src/com/ibxm/FastTracker2.java b/src/com/ibxm/FastTracker2.java new file mode 100644 index 0000000..3884fe5 --- /dev/null +++ b/src/com/ibxm/FastTracker2.java @@ -0,0 +1,295 @@ + +//package ibxm; +package com.ibxm; + +import java.io.*; + +public class FastTracker2 +{ + public static boolean is_xm(byte[] header_60_bytes) + { + String xm_identifier; + xm_identifier = ascii_text(header_60_bytes, 0, 17); + return xm_identifier.equals("Extended Module: "); + } + + public static Module load_xm(byte[] header_60_bytes, DataInput data_input) throws IOException + { + int xm_version, song_header_length, sequence_length; + int num_channels, num_patterns, num_instruments, xm_flags, idx; + byte[] structure_header, song_header; + boolean delta_env; + String tracker_name; + Instrument instrument; + Module module; + if(!is_xm(header_60_bytes)) + { + throw new IllegalArgumentException("Not an XM file!"); + } + xm_version = unsigned_short_le(header_60_bytes, 58); + if(xm_version != 0x0104) + { + throw new IllegalArgumentException("Sorry, XM version " + xm_version + " is not supported!"); + } + module = new Module(); + module.song_title = ascii_text(header_60_bytes, 17, 20); + tracker_name = ascii_text(header_60_bytes, 38, 20); + delta_env = tracker_name.startsWith("DigiBooster Pro"); + structure_header = new byte[4]; + data_input.readFully(structure_header); + song_header_length = int_le(structure_header, 0); + song_header = new byte[song_header_length]; + data_input.readFully(song_header, 4, song_header_length - 4); + sequence_length = unsigned_short_le(song_header, 4); + module.restart_sequence_index = unsigned_short_le(song_header, 6); + num_channels = unsigned_short_le(song_header, 8); + num_patterns = unsigned_short_le(song_header, 10); + num_instruments = unsigned_short_le(song_header, 12); + xm_flags = unsigned_short_le(song_header, 14); + module.linear_periods = (xm_flags & 0x1) == 0x1; + module.global_volume = 64; + module.channel_gain = IBXM.FP_ONE * 3 / 8; + module.default_speed = unsigned_short_le(song_header, 16); + module.default_tempo = unsigned_short_le(song_header, 18); + module.set_num_channels(num_channels); + for(idx = 0; idx < num_channels; idx++) + { + module.set_initial_panning(idx, 128); + } + module.set_sequence_length(sequence_length); + for(idx = 0; idx < sequence_length; idx++) + { + module.set_sequence(idx, song_header[20 + idx] & 0xFF); + } + module.set_num_patterns(num_patterns); + for(idx = 0; idx < num_patterns; idx++) + { + module.set_pattern(idx, read_xm_pattern(data_input, num_channels)); + } + module.set_num_instruments(num_instruments); + for(idx = 1; idx <= num_instruments; idx++) + { + try + { + instrument = read_xm_instrument(data_input, delta_env); + module.set_instrument(idx, instrument); + } + catch(EOFException e) + { + System.out.println("Instrument " + idx + " is missing!"); + } + } + return module; + } + + private static Pattern read_xm_pattern(DataInput data_input, int num_channels) throws IOException + { + int pattern_header_length, packing_type, num_rows, pattern_data_length; + byte[] structure_header, pattern_header, pattern_data; + Pattern pattern; + structure_header = new byte[4]; + data_input.readFully(structure_header); + pattern_header_length = int_le(structure_header, 0); + pattern_header = new byte[pattern_header_length]; + data_input.readFully(pattern_header, 4, pattern_header_length - 4); + packing_type = pattern_header[4]; + if(packing_type != 0) + { + throw new IllegalArgumentException("Pattern packing type " + packing_type + " is not supported!"); + } + pattern = new Pattern(); + pattern.num_rows = unsigned_short_le(pattern_header, 5); + pattern_data_length = unsigned_short_le(pattern_header, 7); + pattern_data = new byte[pattern_data_length]; + data_input.readFully(pattern_data); + pattern.set_pattern_data(pattern_data); + return pattern; + } + + private static Instrument read_xm_instrument(DataInput data_input, boolean delta_env) throws IOException + { + int instrument_header_length, num_samples, idx; + int env_tick, env_ampl, env_num_points, flags; + byte[] structure_header, instrument_header, sample_headers; + Instrument instrument; + Envelope envelope; + structure_header = new byte[4]; + data_input.readFully(structure_header); + instrument_header_length = int_le(structure_header, 0); + instrument_header = new byte[instrument_header_length]; + data_input.readFully(instrument_header, 4, instrument_header_length - 4); + instrument = new Instrument(); + instrument.name = ascii_text(instrument_header, 4, 22); + num_samples = unsigned_short_le(instrument_header, 27); + if(num_samples > 0) + { + instrument.set_num_samples(num_samples); + for(idx = 0; idx < 96; idx++) + { + instrument.set_key_to_sample(idx + 1, instrument_header[33 + idx] & 0xFF); + } + envelope = new Envelope(); + env_num_points = instrument_header[225] & 0xFF; + envelope.set_num_points(env_num_points); + for(idx = 0; idx < env_num_points; idx++) + { + env_tick = unsigned_short_le(instrument_header, 129 + idx * 4); + env_ampl = unsigned_short_le(instrument_header, 131 + idx * 4); + envelope.set_point(idx, env_tick, env_ampl, delta_env); + } + envelope.set_sustain_point(instrument_header[227] & 0xFF); + envelope.set_loop_points(instrument_header[228] & 0xFF, instrument_header[229] & 0xFF); + flags = instrument_header[233] & 0xFF; + instrument.volume_envelope_active = (flags & 0x1) == 0x1; + envelope.sustain = (flags & 0x2) == 0x2; + envelope.looped = (flags & 0x4) == 0x4; + instrument.set_volume_envelope(envelope); + envelope = new Envelope(); + env_num_points = instrument_header[226] & 0xFF; + envelope.set_num_points(env_num_points); + for(idx = 0; idx < env_num_points; idx++) + { + env_tick = unsigned_short_le(instrument_header, 177 + idx * 4); + env_ampl = unsigned_short_le(instrument_header, 179 + idx * 4); + envelope.set_point(idx, env_tick, env_ampl, delta_env); + } + envelope.set_sustain_point(instrument_header[230] & 0xFF); + envelope.set_loop_points(instrument_header[231] & 0xFF, instrument_header[232] & 0xFF); + flags = instrument_header[234] & 0xFF; + instrument.panning_envelope_active = (flags & 0x1) == 0x1; + envelope.sustain = (flags & 0x2) == 0x2; + envelope.looped = (flags & 0x4) == 0x4; + instrument.set_panning_envelope(envelope); + instrument.vibrato_type = instrument_header[235] & 0xFF; + instrument.vibrato_sweep = instrument_header[236] & 0xFF; + instrument.vibrato_depth = instrument_header[237] & 0xFF; + instrument.vibrato_rate = instrument_header[238] & 0xFF; + instrument.volume_fade_out = unsigned_short_le(instrument_header, 239); + sample_headers = new byte[num_samples*40]; + data_input.readFully(sample_headers); + for(idx = 0; idx < num_samples; idx++) + { + instrument.set_sample(idx, read_xm_sample(sample_headers, idx, data_input)); + } + } + return instrument; + } + + private static Sample read_xm_sample(byte[] sample_headers, int sample_idx, DataInput data_input) throws IOException + { + int header_offset, sample_length, loop_start, loop_length; + int flags, in_idx, out_idx, sam, last_sam; + int fine_tune, relative_note; + boolean sixteen_bit, ping_pong; + byte[] raw_sample_data; + short[] decoded_sample_data; + Sample sample; + header_offset = sample_idx * 40; + sample = new Sample(); + sample_length = int_le(sample_headers, header_offset); + loop_start = int_le(sample_headers, header_offset + 4); + loop_length = int_le(sample_headers, header_offset + 8); + sample.volume = sample_headers[header_offset + 12] & 0xFF; + fine_tune = sample_headers[header_offset + 13]; + fine_tune = (fine_tune << IBXM.FP_SHIFT) / 1536; + sample.set_panning = true; + flags = sample_headers[header_offset + 14] & 0xFF; + if((flags & 0x03) == 0) + { + loop_length = 0; + } + ping_pong = (flags & 0x02) == 0x02; + sixteen_bit = (flags & 0x10) == 0x10; + sample.panning = sample_headers[header_offset + 15] & 0xFF; + relative_note = sample_headers[header_offset + 16]; + relative_note = (relative_note << IBXM.FP_SHIFT) / 12; + sample.transpose = relative_note + fine_tune; + sample.name = ascii_text(sample_headers, header_offset + 18, 22); + raw_sample_data = new byte[sample_length]; + try + { + data_input.readFully(raw_sample_data); + } + catch(EOFException e) + { + System.out.println("Sample has been truncated!"); + } + in_idx = 0; + out_idx = 0; + sam = 0; + last_sam = 0; + if(sixteen_bit) + { + decoded_sample_data = new short[sample_length>>1]; + while(in_idx < raw_sample_data.length) + { + sam = raw_sample_data[in_idx] & 0xFF; + sam = sam | ((raw_sample_data[in_idx + 1] & 0xFF) << 8); + last_sam = last_sam + sam; + decoded_sample_data[out_idx] = (short)last_sam; + in_idx += 2; + out_idx += 1; + } + sample.set_sample_data(decoded_sample_data, loop_start >> 1, loop_length >> 1, ping_pong); + } + else + { + decoded_sample_data = new short[sample_length]; + while(in_idx < raw_sample_data.length) + { + sam = raw_sample_data[in_idx] & 0xFF; + last_sam = last_sam + sam; + decoded_sample_data[out_idx] = (short)(last_sam << 8); + in_idx += 1; + out_idx += 1; + } + sample.set_sample_data(decoded_sample_data, loop_start, loop_length, ping_pong); + } + return sample; + } + + private static int unsigned_short_le(byte[] buffer, int offset) + { + int value; + value = buffer[offset] & 0xFF; + value = value | ((buffer[offset + 1] & 0xFF) << 8); + return value; + } + + private static int int_le(byte[] buffer, int offset) + { + int value; + value = buffer[offset] & 0xFF; + value = value | ((buffer[offset + 1] & 0xFF) << 8); + value = value | ((buffer[offset + 2] & 0xFF) << 16); + value = value | ((buffer[offset + 3] & 0x7F) << 24); + return value; + } + + private static String ascii_text(byte[] buffer, int offset, int length) + { + int idx, chr; + byte[] string_buffer; + String string; + string_buffer = new byte[length]; + for(idx = 0; idx < length; idx++) + { + chr = buffer[offset + idx]; + if(chr < 32) + { + chr = 32; + } + string_buffer[idx] = (byte)chr; + } + try + { + string = new String(string_buffer, 0, length, "ISO-8859-1"); + } + catch(UnsupportedEncodingException e) + { + string = ""; + } + return string; + } +} + diff --git a/src/com/ibxm/IBXM.java b/src/com/ibxm/IBXM.java new file mode 100644 index 0000000..1010e81 --- /dev/null +++ b/src/com/ibxm/IBXM.java @@ -0,0 +1,465 @@ +package com.ibxm; + +import java.io.*; + +public class IBXM +{ + public static final String VERSION = "ibxm alpha 51 (c)2008 mumart@gmail.com"; + + public static final int FP_SHIFT = 15; + public static final int FP_ONE = 1 << FP_SHIFT; + public static final int FP_MASK = FP_ONE - 1; + + private int sampling_rate, resampling_quality, volume_ramp_length; + private int tick_length_samples, current_tick_samples; + private int[] mixing_buffer, volume_ramp_buffer; + + private Module module; + private Channel[] channels; + private int[] global_volume, note; + private int current_sequence_index, next_sequence_index; + private int current_row, next_row; + private int tick_counter, ticks_per_row; + private int pattern_loop_count, pattern_loop_channel; + + public IBXM(InputStream input, int sample_rate, int quality) throws IOException + { + //System.out.println(VERSION); + + if(sample_rate < 8000) + { + sample_rate = 8000; + } + + sampling_rate = sample_rate; + volume_ramp_length = sampling_rate >> 10; + volume_ramp_buffer = new int[volume_ramp_length*2]; + mixing_buffer = new int[sampling_rate/6]; + global_volume = new int[1]; + note = new int[5]; + + set_module(load_module(input)); + set_resampling_quality(quality); + } + + public void set_module(Module m) + { + int channel_idx; + module = m; + channels = new Channel[module.get_num_channels()]; + for(channel_idx = 0; channel_idx < channels.length; channel_idx++) + { + channels[channel_idx] = new Channel(module, sampling_rate, global_volume); + } + set_sequence_index(0, 0); + } + + public void set_resampling_quality(int quality) + { + resampling_quality = quality; + } + + public int calculate_song_duration() + { + int song_duration; + set_sequence_index(0, 0); + next_tick(); + song_duration = tick_length_samples; + while(!next_tick()) + { + song_duration += tick_length_samples; + } + set_sequence_index(0, 0); + return song_duration; + } + + public void set_sequence_index(int sequence_index, int row) + { + int channel_idx; + global_volume[0] = 64; + for(channel_idx = 0; channel_idx < channels.length; channel_idx++) + { + channels[channel_idx].reset(); + channels[channel_idx].set_panning(module.get_initial_panning(channel_idx)); + } + set_global_volume(module.global_volume); + set_speed(6); + set_speed(module.default_speed); + set_tempo(125); + set_tempo(module.default_tempo); + pattern_loop_count = -1; + next_sequence_index = sequence_index; + next_row = row; + tick_counter = 0; + current_tick_samples = tick_length_samples; + clear_vol_ramp_buffer(); + } + + public void seek(int sample_position) + { + int idx; + set_sequence_index(0, 0); + next_tick(); + while(sample_position > tick_length_samples) + { + sample_position -= tick_length_samples; + next_tick(); + } + mix_tick(); + current_tick_samples = sample_position; + } + + public int get_audio(byte[] output_buffer, int offset, int frames) + { + int output_idx, mix_idx, mix_end, count, amplitude; + + output_idx = offset; + + while(frames > 0) + { + count = tick_length_samples - current_tick_samples; + + if(count > frames) + { + count = frames; + } + + mix_idx = current_tick_samples << 1; + mix_end = mix_idx + (count << 1) - 1; + + while(mix_idx <= mix_end) + { + amplitude = mixing_buffer[mix_idx]; + + if(amplitude > 32767) + { + amplitude = 32767; + } + + if(amplitude < -32768) + { + amplitude = -32768; + } + + output_buffer[output_idx] = (byte)(amplitude & 0xFF); + output_buffer[output_idx + 1] = (byte)(amplitude >> 8); + + output_idx += 2; + mix_idx += 1; + } + + current_tick_samples = mix_idx >> 1; + frames -= count; + + if(frames > 0) + { + next_tick(); + mix_tick(); + current_tick_samples = 0; + } + } + + return output_idx - offset; + } + + private void mix_tick() + { + int channel_idx, mix_idx, mix_len; + mix_idx = 0; + mix_len = tick_length_samples + volume_ramp_length << 1; + while(mix_idx < mix_len) + { + mixing_buffer[mix_idx] = 0; + mix_idx += 1; + } + for(channel_idx = 0; channel_idx < channels.length; channel_idx++) + { + mix_len = tick_length_samples + volume_ramp_length; + channels[channel_idx].resample(mixing_buffer, 0, mix_len, resampling_quality); + } + volume_ramp(); + } + + private boolean next_tick() + { + int channel_idx; + boolean song_end; + for(channel_idx = 0; channel_idx < channels.length; channel_idx++) + { + channels[channel_idx].update_sample_idx(tick_length_samples); + } + tick_counter -= 1; + if(tick_counter <= 0) + { + tick_counter = ticks_per_row; + song_end = next_row(); + } + else + { + for(channel_idx = 0; channel_idx < channels.length; channel_idx++) + { + channels[channel_idx].tick(); + } + song_end = false; + } + return song_end; + } + + private boolean next_row() + { + int channel_idx, effect, effect_param; + boolean song_end; + Pattern pattern; + song_end = false; + if(next_sequence_index < 0) + { + /* Bad next sequence index.*/ + next_sequence_index = 0; + next_row = 0; + } + if(next_sequence_index >= module.get_sequence_length()) + { + /* End of sequence.*/ + song_end = true; + next_sequence_index = module.restart_sequence_index; + if(next_sequence_index < 0) + { + next_sequence_index = 0; + } + if(next_sequence_index >= module.get_sequence_length()) + { + next_sequence_index = 0; + } + next_row = 0; + } + if(next_sequence_index < current_sequence_index) + { + /* Jump to previous pattern. */ + song_end = true; + } + if(next_sequence_index == current_sequence_index) + { + if(next_row <= current_row) + { + if(pattern_loop_count < 0) + { + /* Jump to previous row in the same pattern, but not a pattern loop. */ + song_end = true; + } + } + } + current_sequence_index = next_sequence_index; + pattern = module.get_pattern_from_sequence(current_sequence_index); + if(next_row < 0 || next_row >= pattern.num_rows) + { + /* Bad next row.*/ + next_row = 0; + } + current_row = next_row; + next_row = current_row + 1; + if(next_row >= pattern.num_rows) + { + next_sequence_index = current_sequence_index + 1; + next_row = 0; + } + for(channel_idx = 0; channel_idx < channels.length; channel_idx++) + { + pattern.get_note(note, current_row * channels.length + channel_idx); + effect = note[3]; + effect_param = note[4]; + channels[channel_idx].row(note[0], note[1], note[2], effect, effect_param); + switch(effect) + { + case 0x0B: + /* Pattern Jump.*/ + if(pattern_loop_count < 0) + { + next_sequence_index = effect_param; + next_row = 0; + } + break; + case 0x0D: + /* Pattern Break.*/ + if(pattern_loop_count < 0) + { + next_sequence_index = current_sequence_index + 1; + next_row = (effect_param >> 4) * 10 + (effect_param & 0x0F); + } + break; + case 0x0E: + /* Extended.*/ + switch(effect_param & 0xF0) + { + case 0x60: + /* Pattern loop.*/ + if((effect_param & 0x0F) == 0) + { + /* Set loop marker on this channel. */ + channels[channel_idx].pattern_loop_row = current_row; + } + if(channels[channel_idx].pattern_loop_row < current_row) + { + /* Marker and parameter are valid. Begin looping. */ + if(pattern_loop_count < 0) + { + /* Not already looping, begin. */ + pattern_loop_count = effect_param & 0x0F; + pattern_loop_channel = channel_idx; + } + if(pattern_loop_channel == channel_idx) + { + /* Loop in progress on this channel. Next iteration. */ + if(pattern_loop_count == 0) + { + /* Loop finished. */ + /* Invalidate current marker. */ + channels[channel_idx].pattern_loop_row = current_row + 1; + } + else + { + /* Count must be higher than zero. */ + /* Loop and cancel any breaks on this row. */ + next_row = channels[channel_idx].pattern_loop_row; + next_sequence_index = current_sequence_index; + } + pattern_loop_count -= 1; + } + } + break; + case 0xE0: + /* Pattern delay.*/ + tick_counter += ticks_per_row * (effect_param & 0x0F); + break; + } + break; + case 0x0F: + /* Set Speed/Tempo.*/ + if(effect_param < 32) + { + set_speed(effect_param); + tick_counter = ticks_per_row; + } + else + { + set_tempo(effect_param); + } + break; + case 0x25: + /* S3M Set Speed.*/ + set_speed(effect_param); + tick_counter = ticks_per_row; + break; + } + } + return song_end; + } + + private void set_global_volume(int volume) + { + if(volume < 0) + { + volume = 0; + } + if(volume > 64) + { + volume = 64; + } + global_volume[0] = volume; + } + + private void set_speed(int speed) + { + if(speed > 0 && speed < 256) + { + ticks_per_row = speed; + } + } + + private void set_tempo(int bpm) + { + if(bpm > 31 && bpm < 256) + { + tick_length_samples = (sampling_rate * 5) / (bpm * 2); + } + } + + private void volume_ramp() + { + int ramp_idx, next_idx, ramp_end; + int volume_ramp_delta, volume, sample; + sample = 0; + volume_ramp_delta = FP_ONE / volume_ramp_length; + volume = 0; + ramp_idx = 0; + next_idx = 2 * tick_length_samples; + ramp_end = volume_ramp_length * 2 - 1; + while(ramp_idx <= ramp_end) + { + sample = volume_ramp_buffer[ramp_idx] * (FP_ONE - volume) >> FP_SHIFT; + mixing_buffer[ramp_idx] = sample + (mixing_buffer[ramp_idx] * volume >> FP_SHIFT); + volume_ramp_buffer[ramp_idx] = mixing_buffer[next_idx + ramp_idx]; + sample = volume_ramp_buffer[ramp_idx + 1] * (FP_ONE - volume) >> FP_SHIFT; + mixing_buffer[ramp_idx + 1] = sample + (mixing_buffer[ramp_idx + 1] * volume >> FP_SHIFT); + volume_ramp_buffer[ramp_idx + 1] = mixing_buffer[next_idx + ramp_idx + 1]; + volume += volume_ramp_delta; + ramp_idx += 2; + } + } + + private void clear_vol_ramp_buffer() + { + int ramp_idx, ramp_end; + ramp_idx = 0; + ramp_end = volume_ramp_length * 2 - 1; + while(ramp_idx <= ramp_end) + { + volume_ramp_buffer[ramp_idx] = 0; + ramp_idx += 1; + } + } + + public String getSongTitle() + { + return module.song_title; + } + + /** + Decode the data in the specified InputStream into a Module instance. + @param input an InputStream containing the module file to be decoded. + @throws IllegalArgumentException if the data is not recognised as a module file. + */ + public static Module load_module(InputStream input) throws IllegalArgumentException, IOException + { + DataInputStream data_input_stream = new DataInputStream(input); + + /* Check if data is in XM format.*/ + byte[] xm_header = new byte[60]; + + data_input_stream.readFully(xm_header); + + if(FastTracker2.is_xm(xm_header)) + { + return FastTracker2.load_xm(xm_header, data_input_stream); + } + + /* Check if data is in ScreamTracker 3 format.*/ + byte[] s3m_header = new byte[96]; + + System.arraycopy(xm_header, 0, s3m_header, 0, 60); + data_input_stream.readFully(s3m_header, 60, 36); + + if(ScreamTracker3.is_s3m(s3m_header)) + { + return ScreamTracker3.load_s3m(s3m_header, data_input_stream); + } + + /* Check if data is in ProTracker format.*/ + byte[] mod_header = new byte[1084]; + + System.arraycopy(s3m_header, 0, mod_header, 0, 96); + data_input_stream.readFully(mod_header, 96, 988); + + return ProTracker.load_mod(mod_header, data_input_stream); + } +} + diff --git a/src/com/ibxm/Instrument.java b/src/com/ibxm/Instrument.java new file mode 100644 index 0000000..faeb218 --- /dev/null +++ b/src/com/ibxm/Instrument.java @@ -0,0 +1,91 @@ + +//package ibxm; +package com.ibxm; + +public class Instrument { + public String name; + public int vibrato_type, vibrato_sweep; + public int vibrato_depth, vibrato_rate; + public boolean volume_envelope_active, panning_envelope_active; + public int volume_fade_out; + + private Envelope volume_envelope, panning_envelope; + private int[] key_to_sample; + private Sample[] samples; + + public Instrument() { + name = ""; + set_volume_envelope( new Envelope() ); + set_panning_envelope( new Envelope() ); + key_to_sample = new int[ 96 ]; + set_num_samples( 1 ); + } + + public Envelope get_volume_envelope() { + return volume_envelope; + } + + public void set_volume_envelope( Envelope envelope ) { + if( envelope != null ) { + volume_envelope = envelope; + } + } + + public Envelope get_panning_envelope() { + return panning_envelope; + } + + public void set_panning_envelope( Envelope envelope ) { + if( envelope != null ) { + panning_envelope = envelope; + } + } + + public Sample get_sample_from_key( int key ) { + int sample_idx; + sample_idx = 0; + if( key > 0 && key <= key_to_sample.length ) { + sample_idx = key_to_sample[ key - 1 ]; + } + return get_sample( sample_idx ); + } + + public void set_key_to_sample( int key, int sample ) { + if( key > 0 && key <= key_to_sample.length ) { + key_to_sample[ key - 1 ] = sample; + } + } + + public int get_num_samples() { + return samples.length; + } + + public void set_num_samples( int num_samples ) { + if( num_samples < 1 ) { + num_samples = 1; + } + samples = new Sample[ num_samples ]; + set_sample( 0, null ); + } + + public Sample get_sample( int sample_index ) { + Sample sample; + sample = null; + if( sample_index >= 0 && sample_index < samples.length ) { + sample = samples[ sample_index ]; + } + if( sample == null ) { + sample = samples[ 0 ]; + } + return sample; + } + + public void set_sample( int sample_index, Sample sample ) { + if( sample_index >= 0 && sample_index < samples.length ) { + samples[ sample_index ] = sample; + } + if( samples[ 0 ] == null ) { + samples[ 0 ] = new Sample(); + } + } +} diff --git a/src/com/ibxm/LogTable.java b/src/com/ibxm/LogTable.java new file mode 100644 index 0000000..d77744c --- /dev/null +++ b/src/com/ibxm/LogTable.java @@ -0,0 +1,92 @@ + +//package ibxm; +package com.ibxm; + +/* + Base-2 Log and Exp functions, using linear-interpolated tables. +*/ +public class LogTable { + private static final int TABLE_SHIFT = 7; // 128 points (+1 for interp) + private static final int INTERP_SHIFT = IBXM.FP_SHIFT - TABLE_SHIFT; + private static final int INTERP_MASK = ( 1 << INTERP_SHIFT ) - 1; + + private static final int[] exp_2_table = { + 32768, 32945, 33124, 33304, 33485, 33667, 33850, 34033, + 34218, 34404, 34591, 34779, 34968, 35157, 35348, 35540, + 35733, 35927, 36122, 36319, 36516, 36714, 36913, 37114, + 37315, 37518, 37722, 37926, 38132, 38339, 38548, 38757, + 38967, 39179, 39392, 39606, 39821, 40037, 40254, 40473, + 40693, 40914, 41136, 41359, 41584, 41810, 42037, 42265, + 42494, 42725, 42957, 43190, 43425, 43661, 43898, 44136, + 44376, 44617, 44859, 45103, 45347, 45594, 45841, 46090, + 46340, 46592, 46845, 47099, 47355, 47612, 47871, 48131, + 48392, 48655, 48919, 49185, 49452, 49720, 49990, 50262, + 50535, 50809, 51085, 51362, 51641, 51922, 52204, 52487, + 52772, 53059, 53347, 53636, 53928, 54220, 54515, 54811, + 55108, 55408, 55709, 56011, 56315, 56621, 56928, 57238, + 57548, 57861, 58175, 58491, 58809, 59128, 59449, 59772, + 60096, 60423, 60751, 61081, 61412, 61746, 62081, 62418, + 62757, 63098, 63440, 63785, 64131, 64479, 64830, 65182, + 65536 + }; + + private static final int[] log_2_table = { + 0, 367, 732, 1095, 1454, 1811, 2165, 2517, + 2865, 3212, 3556, 3897, 4236, 4572, 4906, 5238, + 5568, 5895, 6220, 6542, 6863, 7181, 7497, 7812, + 8124, 8434, 8742, 9048, 9352, 9654, 9954, 10252, + 10548, 10843, 11136, 11427, 11716, 12003, 12289, 12573, + 12855, 13136, 13414, 13692, 13967, 14241, 14514, 14785, + 15054, 15322, 15588, 15853, 16117, 16378, 16639, 16898, + 17156, 17412, 17667, 17920, 18172, 18423, 18673, 18921, + 19168, 19413, 19657, 19900, 20142, 20383, 20622, 20860, + 21097, 21333, 21568, 21801, 22034, 22265, 22495, 22724, + 22952, 23178, 23404, 23628, 23852, 24074, 24296, 24516, + 24736, 24954, 25171, 25388, 25603, 25817, 26031, 26243, + 26455, 26665, 26875, 27084, 27292, 27499, 27705, 27910, + 28114, 28317, 28520, 28721, 28922, 29122, 29321, 29519, + 29716, 29913, 30109, 30304, 30498, 30691, 30884, 31076, + 31267, 31457, 31646, 31835, 32023, 32210, 32397, 32582, + 32768 + }; + + /* + Calculate log-base-2 of x (non-fixed-point). + A fixed point value is returned. + */ + public static int log_2( int x ) { + int shift; + /* Scale x to range 1.0 <= x < 2.0 */ + shift = IBXM.FP_SHIFT; + while( x < IBXM.FP_ONE ) { + x <<= 1; + shift--; + } + while( x >= ( IBXM.FP_ONE << 1 ) ) { + x >>= 1; + shift++; + } + return ( IBXM.FP_ONE * shift ) + eval_table( log_2_table, x - IBXM.FP_ONE ); + } + + /* + Raise 2 to the power x (fixed point). + A fixed point value is returned. + */ + public static int raise_2( int x ) { + int y; + y = eval_table( exp_2_table, x & IBXM.FP_MASK ) << IBXM.FP_SHIFT; + return y >> IBXM.FP_SHIFT - ( x >> IBXM.FP_SHIFT ); + } + + private static int eval_table( int[] table, int x ) { + int table_idx, table_frac, c, m, y; + table_idx = x >> INTERP_SHIFT; + table_frac = x & INTERP_MASK; + c = table[ table_idx ]; + m = table[ table_idx + 1 ] - c; + y = ( m * table_frac >> INTERP_SHIFT ) + c; + return y >> 15 - IBXM.FP_SHIFT; + } +} + diff --git a/src/com/ibxm/Module.java b/src/com/ibxm/Module.java new file mode 100644 index 0000000..e942b22 --- /dev/null +++ b/src/com/ibxm/Module.java @@ -0,0 +1,171 @@ + +//package ibxm; +package com.ibxm; + +public class Module +{ + public String song_title; + public boolean linear_periods, fast_volume_slides, pal; + public int global_volume, channel_gain; + public int default_speed, default_tempo; + public int restart_sequence_index; + + private int[] initial_panning, sequence; + private Pattern[] patterns; + private Instrument[] instruments; + + private Pattern default_pattern; + private Instrument default_instrument; + + public Module() + { + song_title = IBXM.VERSION; + set_num_channels(1); + set_sequence_length(1); + set_num_patterns(0); + set_num_instruments(0); + default_pattern = new Pattern(); + default_instrument = new Instrument(); + } + + public int get_num_channels() + { + return initial_panning.length; + } + + public void set_num_channels(int num_channels) + { + if(num_channels < 1) + { + num_channels = 1; + } + initial_panning = new int[num_channels]; + } + + public int get_initial_panning(int channel) + { + int panning; + panning = 128; + if(channel >= 0 && channel < initial_panning.length) + { + panning = initial_panning[channel]; + } + return panning; + } + + public void set_initial_panning(int channel, int panning) + { + if(channel >= 0 && channel < initial_panning.length) + { + initial_panning[channel] = panning; + } + } + + public int get_sequence_length() + { + return sequence.length; + } + + public void set_sequence_length(int sequence_length) + { + if(sequence_length < 0) + { + sequence_length = 0; + } + sequence = new int[sequence_length]; + } + + public void set_sequence(int sequence_index, int pattern_index) + { + if(sequence_index >= 0 && sequence_index < sequence.length) + { + sequence[sequence_index] = pattern_index; + } + } + + public int get_num_patterns() + { + return patterns.length; + } + + public void set_num_patterns(int num_patterns) + { + if(num_patterns < 0) + { + num_patterns = 0; + } + patterns = new Pattern[num_patterns]; + } + + public Pattern get_pattern_from_sequence(int sequence_index) + { + Pattern pattern; + pattern = default_pattern; + if(sequence_index >= 0 && sequence_index < sequence.length) + { + pattern = get_pattern(sequence[sequence_index]); + } + return pattern; + } + + public Pattern get_pattern(int pattern_index) + { + Pattern pattern; + pattern = null; + if(pattern_index >= 0 && pattern_index < patterns.length) + { + pattern = patterns[pattern_index]; + } + if(pattern == null) + { + pattern = default_pattern; + } + return pattern; + } + + public void set_pattern(int pattern_index, Pattern pattern) + { + if(pattern_index >= 0 && pattern_index < patterns.length) + { + patterns[pattern_index] = pattern; + } + } + + public int get_num_instruments() + { + return instruments.length; + } + + public void set_num_instruments(int num_instruments) + { + if(num_instruments < 0) + { + num_instruments = 0; + } + instruments = new Instrument[num_instruments]; + } + + public Instrument get_instrument(int instrument_index) + { + Instrument instrument; + instrument = null; + if(instrument_index > 0 && instrument_index <= instruments.length) + { + instrument = instruments[instrument_index - 1]; + } + if(instrument == null) + { + instrument = default_instrument; + } + return instrument; + } + + public void set_instrument(int instrument_index, Instrument instrument) + { + if(instrument_index > 0 && instrument_index <= instruments.length) + { + instruments[instrument_index - 1] = instrument; + } + } +} + diff --git a/src/com/ibxm/Pattern.java b/src/com/ibxm/Pattern.java new file mode 100644 index 0000000..ff87e0d --- /dev/null +++ b/src/com/ibxm/Pattern.java @@ -0,0 +1,62 @@ + +//package ibxm; +package com.ibxm; + +public class Pattern { + public int num_rows; + + private int data_offset, note_index; + private byte[] pattern_data; + + public Pattern() { + num_rows = 1; + set_pattern_data( new byte[ 0 ] ); + } + + public void set_pattern_data( byte[] data ) { + if( data != null ) { + pattern_data = data; + } + data_offset = 0; + note_index = 0; + } + + public void get_note( int[] note, int index ) { + if( index < note_index ) { + note_index = 0; + data_offset = 0; + } + while( note_index <= index ) { + data_offset = next_note( data_offset, note ); + note_index += 1; + } + } + + public int next_note( int data_offset, int[] note ) { + int bitmask, field; + if( data_offset < 0 ) { + data_offset = pattern_data.length; + } + bitmask = 0x80; + if( data_offset < pattern_data.length ) { + bitmask = pattern_data[ data_offset ] & 0xFF; + } + if( ( bitmask & 0x80 ) == 0x80 ) { + data_offset += 1; + } else { + bitmask = 0x1F; + } + for( field = 0; field < 5; field++ ) { + note[ field ] = 0; + if( ( bitmask & 0x01 ) == 0x01 ) { + if( data_offset < pattern_data.length ) { + note[ field ] = pattern_data[ data_offset ] & 0xFF; + data_offset += 1; + } + } + bitmask = bitmask >> 1; + } + return data_offset; + } +} + diff --git a/src/com/ibxm/ProTracker.java b/src/com/ibxm/ProTracker.java new file mode 100644 index 0000000..f931acf --- /dev/null +++ b/src/com/ibxm/ProTracker.java @@ -0,0 +1,235 @@ +//package ibxm; +package com.ibxm; + +import java.io.*; + +public class ProTracker { + public static boolean is_mod( byte[] header_1084_bytes ) { + boolean is_mod; + is_mod = false; + if( calculate_num_channels( header_1084_bytes ) > 0 ) { + is_mod = true; + } + return is_mod; + } + + public static Module load_mod( byte[] header_1084_bytes, DataInput data_input ) throws IOException { + int num_channels, channel_idx, panning; + int sequence_length, restart_idx, sequence_idx; + int num_patterns, pattern_idx, instrument_idx; + Module module; + num_channels = calculate_num_channels( header_1084_bytes ); + if( num_channels < 1 ) { + throw new IllegalArgumentException( "ProTracker: Unrecognised module format!" ); + } + module = new Module(); + module.song_title = ascii_text( header_1084_bytes, 0, 20 ); + module.pal = ( num_channels == 4 ); + module.global_volume = 64; + module.channel_gain = IBXM.FP_ONE * 3 / 8; + module.default_speed = 6; + module.default_tempo = 125; + module.set_num_channels( num_channels ); + for( channel_idx = 0; channel_idx < num_channels; channel_idx++ ) { + panning = 64; + if( ( channel_idx & 0x03 ) == 0x01 || ( channel_idx & 0x03 ) == 0x02 ) { + panning = 192; + } + module.set_initial_panning( channel_idx, panning ); + } + sequence_length = header_1084_bytes[ 950 ] & 0x7F; + restart_idx = header_1084_bytes[ 951 ] & 0x7F; + if( restart_idx >= sequence_length ) { + restart_idx = 0; + } + module.restart_sequence_index = restart_idx; + module.set_sequence_length( sequence_length ); + for( sequence_idx = 0; sequence_idx < sequence_length; sequence_idx++ ) { + module.set_sequence( sequence_idx, header_1084_bytes[ 952 + sequence_idx ] & 0x7F ); + } + num_patterns = calculate_num_patterns( header_1084_bytes ); + module.set_num_patterns( num_patterns ); + for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) { + module.set_pattern( pattern_idx, read_mod_pattern( data_input, num_channels ) ); + } + module.set_num_instruments( 31 ); + for( instrument_idx = 1; instrument_idx <= 31; instrument_idx++ ) { + module.set_instrument( instrument_idx, read_mod_instrument( header_1084_bytes, instrument_idx, data_input ) ); + } + return module; + } + + private static int calculate_num_patterns( byte[] module_header ) { + int num_patterns, order_entry, pattern_idx; + num_patterns = 0; + for( pattern_idx = 0; pattern_idx < 128; pattern_idx++ ) { + order_entry = module_header[ 952 + pattern_idx ] & 0x7F; + if( order_entry >= num_patterns ) { + num_patterns = order_entry + 1; + } + } + return num_patterns; + } + + private static int calculate_num_channels( byte[] module_header ) { + int num_channels; + switch( ( module_header[ 1082 ] << 8 ) | module_header[ 1083 ] ) { + case 0x4b2e: /* M.K. */ + case 0x4b21: /* M!K! */ + case 0x542e: /* N.T. */ + case 0x5434: /* FLT4 */ + num_channels = 4; + break; + case 0x484e: /* xCHN */ + num_channels = module_header[ 1080 ] - 48; + break; + case 0x4348: /* xxCH */ + num_channels = ( ( module_header[ 1080 ] - 48 ) * 10 ) + ( module_header[ 1081 ] - 48 ); + break; + default: + /* Not recognised. */ + num_channels = 0; + break; + } + return num_channels; + } + + private static Pattern read_mod_pattern( DataInput data_input, int num_channels ) throws IOException { + int input_idx, output_idx; + int period, instrument, effect, effect_param; + Pattern pattern; + byte[] input_pattern_data, output_pattern_data; + pattern = new Pattern(); + pattern.num_rows = 64; + input_pattern_data = new byte[ 64 * num_channels * 4 ]; + output_pattern_data = new byte[ 64 * num_channels * 5 ]; + data_input.readFully( input_pattern_data ); + input_idx = 0; + output_idx = 0; + while( input_idx < input_pattern_data.length ) { + period = ( input_pattern_data[ input_idx ] & 0x0F ) << 8; + period = period | ( input_pattern_data[ input_idx + 1 ] & 0xFF ); + output_pattern_data[ output_idx ] = to_key( period ); + instrument = input_pattern_data[ input_idx ] & 0x10; + instrument = instrument | ( ( input_pattern_data[ input_idx + 2 ] & 0xF0 ) >> 4 ); + output_pattern_data[ output_idx + 1 ] = ( byte ) instrument; + effect = input_pattern_data[ input_idx + 2 ] & 0x0F; + effect_param = input_pattern_data[ input_idx + 3 ] & 0xFF; + if( effect == 0x01 && effect_param == 0 ) { + /* Portamento up of zero has no effect. */ + effect = 0; + } + if( effect == 0x02 && effect_param == 0 ) { + /* Portamento down of zero has no effect. */ + effect = 0; + } + if( effect == 0x08 && num_channels == 4 ) { + /* Some Amiga mods use effect 0x08 for reasons other than panning.*/ + effect = 0; + effect_param = 0; + } + if( effect == 0x0A && effect_param == 0 ) { + /* Volume slide of zero has no effect.*/ + effect = 0; + } + if( effect == 0x05 && effect_param == 0 ) { + /* Porta + Volume slide of zero has no effect.*/ + effect = 0x03; + } + if( effect == 0x06 && effect_param == 0 ) { + /* Vibrato + Volume slide of zero has no effect.*/ + effect = 0x04; + } + output_pattern_data[ output_idx + 3 ] = ( byte ) effect; + output_pattern_data[ output_idx + 4 ] = ( byte ) effect_param; + input_idx += 4; + output_idx += 5; + } + pattern.set_pattern_data( output_pattern_data ); + return pattern; + } + + private static Instrument read_mod_instrument( byte[] mod_header, int idx, DataInput data_input ) throws IOException { + int header_offset, sample_data_length; + int loop_start, loop_length, sample_idx, fine_tune; + Instrument instrument; + Sample sample; + byte[] raw_sample_data; + short[] sample_data; + header_offset = ( idx - 1 ) * 30 + 20; + instrument = new Instrument(); + instrument.name = ascii_text( mod_header, header_offset, 22 ); + sample = new Sample(); + sample_data_length = unsigned_short_be( mod_header, header_offset + 22 ) << 1; + fine_tune = mod_header[ header_offset + 24 ] & 0x0F; + if( fine_tune > 7 ) { + fine_tune -= 16; + } + sample.transpose = ( fine_tune << IBXM.FP_SHIFT ) / 96; + sample.volume = mod_header[ header_offset + 25 ] & 0x7F; + loop_start = unsigned_short_be( mod_header, header_offset + 26 ) << 1; + loop_length = unsigned_short_be( mod_header, header_offset + 28 ) << 1; + if( loop_length < 4 ) { + loop_length = 0; + } + raw_sample_data = new byte[ sample_data_length ]; + sample_data = new short[ sample_data_length ]; + try { + data_input.readFully( raw_sample_data ); + } catch( EOFException e ) { + System.out.println( "ProTracker: Instrument " + idx + " has samples missing." ); + } + for( sample_idx = 0; sample_idx < raw_sample_data.length; sample_idx++ ) { + sample_data[ sample_idx ] = ( short ) ( raw_sample_data[ sample_idx ] << 8 ); + } + sample.set_sample_data( sample_data, loop_start, loop_length, false ); + instrument.set_num_samples( 1 ); + instrument.set_sample( 0, sample ); + return instrument; + } + + private static byte to_key( int period ) { + int oct, key; + if( period < 32 ) { + key = 0; + } else { + oct = LogTable.log_2( 7256 ) - LogTable.log_2( period ); + if( oct < 0 ) { + key = 0; + } else { + key = oct * 12; + key = key >> ( IBXM.FP_SHIFT - 1 ); + key = ( key >> 1 ) + ( key & 1 ); + } + } + return ( byte ) key; + } + + private static int unsigned_short_be( byte[] buf, int offset ) { + int value; + value = ( buf[ offset ] & 0xFF ) << 8; + value = value | ( buf[ offset + 1 ] & 0xFF ); + return value; + } + + private static String ascii_text( byte[] buffer, int offset, int length ) { + int idx, chr; + byte[] string_buffer; + String string; + string_buffer = new byte[ length ]; + for( idx = 0; idx < length; idx++ ) { + chr = buffer[ offset + idx ]; + if( chr < 32 ) { + chr = 32; + } + string_buffer[ idx ] = ( byte ) chr; + } + try { + string = new String( string_buffer, 0, length, "ISO-8859-1" ); + } catch( UnsupportedEncodingException e ) { + string = ""; + } + return string; + } +} + diff --git a/src/com/ibxm/Sample.java b/src/com/ibxm/Sample.java new file mode 100644 index 0000000..4bf7e14 --- /dev/null +++ b/src/com/ibxm/Sample.java @@ -0,0 +1,240 @@ + +//package ibxm; +package com.ibxm; + +public class Sample { + public String name; + public boolean set_panning; + public int volume, panning; + public int transpose; + + private int loop_start, loop_length; + private short[] sample_data; + + /* For the sinc interpolator.*/ + private static final int POINT_SHIFT = 4; + private static final int POINTS = 1 << POINT_SHIFT; + private static final int OVERLAP = POINTS >> 1; + private static final int INTERP_SHIFT = IBXM.FP_SHIFT - 4; + private static final int INTERP_BITMASK = ( 1 << INTERP_SHIFT ) - 1; + private static final short[] sinc_table = { + 0, -7, 27, -71, 142, -227, 299, 32439, 299, -227, 142, -71, 27, -7, 0, 0, + 0, 0, -5, 36, -142, 450, -1439, 32224, 2302, -974, 455, -190, 64, -15, 2, 0, + 0, 6, -33, 128, -391, 1042, -2894, 31584, 4540, -1765, 786, -318, 105, -25, 3, 0, + 0, 10, -55, 204, -597, 1533, -4056, 30535, 6977, -2573, 1121, -449, 148, -36, 5, 0, + -1, 13, -71, 261, -757, 1916, -4922, 29105, 9568, -3366, 1448, -578, 191, -47, 7, 0, + -1, 15, -81, 300, -870, 2185, -5498, 27328, 12263, -4109, 1749, -698, 232, -58, 9, 0, + -1, 15, -86, 322, -936, 2343, -5800, 25249, 15006, -4765, 2011, -802, 269, -68, 10, 0, + -1, 15, -87, 328, -957, 2394, -5849, 22920, 17738, -5298, 2215, -885, 299, -77, 12, 0, + 0, 14, -83, 319, -938, 2347, -5671, 20396, 20396, -5671, 2347, -938, 319, -83, 14, 0, + 0, 12, -77, 299, -885, 2215, -5298, 17738, 22920, -5849, 2394, -957, 328, -87, 15, -1, + 0, 10, -68, 269, -802, 2011, -4765, 15006, 25249, -5800, 2343, -936, 322, -86, 15, -1, + 0, 9, -58, 232, -698, 1749, -4109, 12263, 27328, -5498, 2185, -870, 300, -81, 15, -1, + 0, 7, -47, 191, -578, 1448, -3366, 9568, 29105, -4922, 1916, -757, 261, -71, 13, -1, + 0, 5, -36, 148, -449, 1121, -2573, 6977, 30535, -4056, 1533, -597, 204, -55, 10, 0, + 0, 3, -25, 105, -318, 786, -1765, 4540, 31584, -2894, 1042, -391, 128, -33, 6, 0, + 0, 2, -15, 64, -190, 455, -974, 2302, 32224, -1439, 450, -142, 36, -5, 0, 0, + 0, 0, -7, 27, -71, 142, -227, 299, 32439, 299, -227, 142, -71, 27, -7, 0 + }; + + public Sample() { + name = ""; + set_sample_data( new short[ 0 ], 0, 0, false ); + } + + public void set_sample_data( short[] data, int loop_start, int loop_length, boolean ping_pong ) { + int offset; + short sample; + if( loop_start < 0 ) { + loop_start = 0; + } + if( loop_start >= data.length ) { + loop_start = data.length - 1; + } + if( loop_start + loop_length > data.length ) { + loop_length = data.length - loop_start; + } + if( loop_length <= 1 ) { + sample_data = new short[ OVERLAP + data.length + OVERLAP * 3 ]; + System.arraycopy( data, 0, sample_data, OVERLAP, data.length ); + offset = 0; + while( offset < OVERLAP ) { + sample = sample_data[ OVERLAP + data.length - 1 ]; + sample = ( short ) ( sample * ( OVERLAP - offset ) / OVERLAP ); + sample_data[ OVERLAP + data.length + offset ] = sample; + offset += 1; + } + loop_start = OVERLAP + data.length + OVERLAP; + loop_length = 1; + } else { + if( ping_pong ) { + sample_data = new short[ OVERLAP + loop_start + loop_length * 2 + OVERLAP * 2 ]; + System.arraycopy( data, 0, sample_data, OVERLAP, loop_start + loop_length ); + offset = 0; + while( offset < loop_length ) { + sample = data[ loop_start + loop_length - offset - 1 ]; + sample_data[ OVERLAP + loop_start + loop_length + offset ] = sample; + offset += 1; + } + loop_start = loop_start + OVERLAP; + loop_length = loop_length * 2; + } else { + sample_data = new short[ OVERLAP + loop_start + loop_length + OVERLAP * 2 ]; + System.arraycopy( data, 0, sample_data, OVERLAP, loop_start + loop_length ); + loop_start = loop_start + OVERLAP; + } + offset = 0; + while( offset < OVERLAP * 2 ) { + sample = sample_data[ loop_start + offset ]; + sample_data[ loop_start + loop_length + offset ] = sample; + offset += 1; + } + } + this.loop_start = loop_start; + this.loop_length = loop_length; + } + + public void resample_nearest( + int sample_idx, int sample_frac, int step, int left_gain, int right_gain, + int[] mix_buffer, int frame_offset, int frames ) { + int loop_end, offset, end, max_sample_idx; + sample_idx += OVERLAP; + loop_end = loop_start + loop_length - 1; + offset = frame_offset << 1; + end = ( frame_offset + frames - 1 ) << 1; + while( frames > 0 ) { + if( sample_idx > loop_end ) { + if( loop_length <= 1 ) { + break; + } + sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length; + } + max_sample_idx = sample_idx + ( ( sample_frac + ( frames - 1 ) * step ) >> IBXM.FP_SHIFT ); + if( max_sample_idx > loop_end ) { + while( sample_idx <= loop_end ) { + mix_buffer[ offset++ ] += sample_data[ sample_idx ] * left_gain >> IBXM.FP_SHIFT; + mix_buffer[ offset++ ] += sample_data[ sample_idx ] * right_gain >> IBXM.FP_SHIFT; + sample_frac += step; + sample_idx += sample_frac >> IBXM.FP_SHIFT; + sample_frac &= IBXM.FP_MASK; + } + } else { + while( offset <= end ) { + mix_buffer[ offset++ ] += sample_data[ sample_idx ] * left_gain >> IBXM.FP_SHIFT; + mix_buffer[ offset++ ] += sample_data[ sample_idx ] * right_gain >> IBXM.FP_SHIFT; + sample_frac += step; + sample_idx += sample_frac >> IBXM.FP_SHIFT; + sample_frac &= IBXM.FP_MASK; + } + } + frames = ( end - offset + 2 ) >> 1; + } + } + + public void resample_linear( + int sample_idx, int sample_frac, int step, int left_gain, int right_gain, + int[] mix_buffer, int frame_offset, int frames ) { + int loop_end, offset, end, max_sample_idx, amplitude; + sample_idx += OVERLAP; + loop_end = loop_start + loop_length - 1; + offset = frame_offset << 1; + end = ( frame_offset + frames - 1 ) << 1; + while( frames > 0 ) { + if( sample_idx > loop_end ) { + if( loop_length <= 1 ) { + break; + } + sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length; + } + max_sample_idx = sample_idx + ( ( sample_frac + ( frames - 1 ) * step ) >> IBXM.FP_SHIFT ); + if( max_sample_idx > loop_end ) { + while( sample_idx <= loop_end ) { + amplitude = sample_data[ sample_idx ]; + amplitude += ( sample_data[ sample_idx + 1 ] - amplitude ) * sample_frac >> IBXM.FP_SHIFT; + mix_buffer[ offset++ ] += amplitude * left_gain >> IBXM.FP_SHIFT; + mix_buffer[ offset++ ] += amplitude * right_gain >> IBXM.FP_SHIFT; + sample_frac += step; + sample_idx += sample_frac >> IBXM.FP_SHIFT; + sample_frac &= IBXM.FP_MASK; + } + } else { + while( offset <= end ) { + amplitude = sample_data[ sample_idx ]; + amplitude += ( sample_data[ sample_idx + 1 ] - amplitude ) * sample_frac >> IBXM.FP_SHIFT; + mix_buffer[ offset++ ] += amplitude * left_gain >> IBXM.FP_SHIFT; + mix_buffer[ offset++ ] += amplitude * right_gain >> IBXM.FP_SHIFT; + sample_frac += step; + sample_idx += sample_frac >> IBXM.FP_SHIFT; + sample_frac &= IBXM.FP_MASK; + } + } + frames = ( end - offset + 2 ) >> 1; + } + } + + public void resample_sinc( + int sample_idx, int sample_frac, int step, int left_gain, int right_gain, + int[] mix_buffer, int frame_offset, int frames ) { + int offset, end, loop_end, table_idx, a1, a2, amplitude; + loop_end = loop_start + loop_length - 1; + offset = frame_offset << 1; + end = ( frame_offset + frames - 1 ) << 1; + while( offset <= end ) { + if( sample_idx > loop_end ) { + if( loop_length <= 1 ) { + break; + } + sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length; + } + table_idx = ( sample_frac >> INTERP_SHIFT ) << POINT_SHIFT; + a1 = sinc_table[ table_idx + 0 ] * sample_data[ sample_idx + 0 ] >> 15; + a1 += sinc_table[ table_idx + 1 ] * sample_data[ sample_idx + 1 ] >> 15; + a1 += sinc_table[ table_idx + 2 ] * sample_data[ sample_idx + 2 ] >> 15; + a1 += sinc_table[ table_idx + 3 ] * sample_data[ sample_idx + 3 ] >> 15; + a1 += sinc_table[ table_idx + 4 ] * sample_data[ sample_idx + 4 ] >> 15; + a1 += sinc_table[ table_idx + 5 ] * sample_data[ sample_idx + 5 ] >> 15; + a1 += sinc_table[ table_idx + 6 ] * sample_data[ sample_idx + 6 ] >> 15; + a1 += sinc_table[ table_idx + 7 ] * sample_data[ sample_idx + 7 ] >> 15; + a1 += sinc_table[ table_idx + 8 ] * sample_data[ sample_idx + 8 ] >> 15; + a1 += sinc_table[ table_idx + 9 ] * sample_data[ sample_idx + 9 ] >> 15; + a1 += sinc_table[ table_idx + 10 ] * sample_data[ sample_idx + 10 ] >> 15; + a1 += sinc_table[ table_idx + 11 ] * sample_data[ sample_idx + 11 ] >> 15; + a1 += sinc_table[ table_idx + 12 ] * sample_data[ sample_idx + 12 ] >> 15; + a1 += sinc_table[ table_idx + 13 ] * sample_data[ sample_idx + 13 ] >> 15; + a1 += sinc_table[ table_idx + 14 ] * sample_data[ sample_idx + 14 ] >> 15; + a1 += sinc_table[ table_idx + 15 ] * sample_data[ sample_idx + 15 ] >> 15; + a2 = sinc_table[ table_idx + 16 ] * sample_data[ sample_idx + 0 ] >> 15; + a2 += sinc_table[ table_idx + 17 ] * sample_data[ sample_idx + 1 ] >> 15; + a2 += sinc_table[ table_idx + 18 ] * sample_data[ sample_idx + 2 ] >> 15; + a2 += sinc_table[ table_idx + 19 ] * sample_data[ sample_idx + 3 ] >> 15; + a2 += sinc_table[ table_idx + 20 ] * sample_data[ sample_idx + 4 ] >> 15; + a2 += sinc_table[ table_idx + 21 ] * sample_data[ sample_idx + 5 ] >> 15; + a2 += sinc_table[ table_idx + 22 ] * sample_data[ sample_idx + 6 ] >> 15; + a2 += sinc_table[ table_idx + 23 ] * sample_data[ sample_idx + 7 ] >> 15; + a2 += sinc_table[ table_idx + 24 ] * sample_data[ sample_idx + 8 ] >> 15; + a2 += sinc_table[ table_idx + 25 ] * sample_data[ sample_idx + 9 ] >> 15; + a2 += sinc_table[ table_idx + 26 ] * sample_data[ sample_idx + 10 ] >> 15; + a2 += sinc_table[ table_idx + 27 ] * sample_data[ sample_idx + 11 ] >> 15; + a2 += sinc_table[ table_idx + 28 ] * sample_data[ sample_idx + 12 ] >> 15; + a2 += sinc_table[ table_idx + 29 ] * sample_data[ sample_idx + 13 ] >> 15; + a2 += sinc_table[ table_idx + 30 ] * sample_data[ sample_idx + 14 ] >> 15; + a2 += sinc_table[ table_idx + 31 ] * sample_data[ sample_idx + 15 ] >> 15; + amplitude = a1 + ( ( a2 - a1 ) * ( sample_frac & INTERP_BITMASK ) >> INTERP_SHIFT ); + mix_buffer[ offset ] += amplitude * left_gain >> IBXM.FP_SHIFT; + mix_buffer[ offset + 1 ] += amplitude * right_gain >> IBXM.FP_SHIFT; + offset += 2; + sample_frac += step; + sample_idx += sample_frac >> IBXM.FP_SHIFT; + sample_frac &= IBXM.FP_MASK; + } + } + + public boolean has_finished( int sample_idx ) { + boolean finished; + finished = false; + if( loop_length <= 1 && sample_idx > loop_start ) { + finished = true; + } + return finished; + } +} diff --git a/src/com/ibxm/ScreamTracker3.java b/src/com/ibxm/ScreamTracker3.java new file mode 100644 index 0000000..9b3a360 --- /dev/null +++ b/src/com/ibxm/ScreamTracker3.java @@ -0,0 +1,490 @@ + +//package ibxm; +package com.ibxm; + +import java.io.*; + +public class ScreamTracker3 { + private static final int[] effect_map = new int[] { + 0xFF, + 0x25, /* A: Set Speed.*/ + 0x0B, /* B: Pattern Jump.*/ + 0x0D, /* C: Pattern Break.*/ + 0x0A, /* D: Volume Slide.*/ + 0x02, /* E: Portamento Down.*/ + 0x01, /* F: Portamento Up.*/ + 0x03, /* G: Tone Portamento.*/ + 0x04, /* H: Vibrato.*/ + 0x1D, /* I: Tremor.*/ + 0x00, /* J: Arpeggio.*/ + 0x06, /* K: Vibrato + Volume Slide.*/ + 0x05, /* L: Tone Portamento + Volume Slide.*/ + 0xFF, /* M: */ + 0xFF, /* N: */ + 0x09, /* O: Sample Offset.*/ + 0xFF, /* P: */ + 0x1B, /* Q: Retrig + Volume Slide.*/ + 0x07, /* R: Tremolo.*/ + 0x0E, /* S: Extended Effects.*/ + 0x0F, /* T: Set Tempo.*/ + 0x24, /* U: Fine Vibrato.*/ + 0x10, /* V: Set Global Volume. */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF + }; + + private static final int[] effect_s_map = new int[] { + 0x00, /* 0: Set Filter.*/ + 0x03, /* 1: Glissando.*/ + 0x05, /* 2: Set Fine Tune.*/ + 0x04, /* 3: Set Vibrato Waveform.*/ + 0x07, /* 4: Set Tremolo Waveform.*/ + 0xFF, /* 5: */ + 0xFF, /* 6: */ + 0xFF, /* 7: */ + 0x08, /* 8: Set Panning.*/ + 0xFF, /* 9: */ + 0x09, /* A: Stereo Control.*/ + 0x06, /* B: Pattern Loop.*/ + 0x0C, /* C: Note Cut.*/ + 0x0D, /* D: Note Delay.*/ + 0x0E, /* E: Pattern Delay.*/ + 0x0F /* F: Invert Loop.*/ + }; + + public static boolean is_s3m( byte[] header_96_bytes ) { + String s3m_identifier; + s3m_identifier = ascii_text( header_96_bytes, 44, 4 ); + return s3m_identifier.equals( "SCRM" ); + } + + public static Module load_s3m( byte[] header_96_bytes, DataInput data_input ) throws IOException { + int num_pattern_orders, num_instruments, num_patterns, num_channels; + int flags, tracker_version, master_volume, panning, channel_config, sequence_length; + int instrument_idx, pattern_idx, channel_idx, order_idx, panning_offset; + boolean signed_samples, stereo_mode, default_panning; + int[] channel_map, sequence; + byte[] s3m_file; + Module module; + Instrument instrument; + s3m_file = read_s3m_file( header_96_bytes, data_input ); + module = new Module(); + module.song_title = ascii_text( s3m_file, 0, 28 ); + num_pattern_orders = get_num_pattern_orders( s3m_file ); + num_instruments = get_num_instruments( s3m_file ); + num_patterns = get_num_patterns( s3m_file ); + flags = unsigned_short_le( s3m_file, 38 ); + tracker_version = unsigned_short_le( s3m_file, 40 ); + if( ( flags & 0x40 ) == 0x40 || tracker_version == 0x1300 ) { + module.fast_volume_slides = true; + } + signed_samples = false; + if( unsigned_short_le( s3m_file, 42 ) == 0x01 ) { + signed_samples = true; + } + module.global_volume = s3m_file[ 48 ] & 0xFF; + module.default_speed = s3m_file[ 49 ] & 0xFF; + module.default_tempo = s3m_file[ 50 ] & 0xFF; + master_volume = s3m_file[ 51 ] & 0x7F; + module.channel_gain = ( master_volume << IBXM.FP_SHIFT ) >> 7; + stereo_mode = ( s3m_file[ 51 ] & 0x80 ) == 0x80; + default_panning = ( s3m_file[ 53 ] & 0xFF ) == 0xFC; + channel_map = new int[ 32 ]; + num_channels = 0; + for( channel_idx = 0; channel_idx < 32; channel_idx++ ) { + channel_config = s3m_file[ 64 + channel_idx ] & 0xFF; + channel_map[ channel_idx ] = -1; + if( channel_config < 16 ) { + channel_map[ channel_idx ] = num_channels; + num_channels += 1; + } + } + module.set_num_channels( num_channels ); + panning_offset = 96 + num_pattern_orders + num_instruments * 2 + num_patterns * 2; + for( channel_idx = 0; channel_idx < 32; channel_idx++ ) { + if( channel_map[ channel_idx ] < 0 ) continue; + panning = 7; + if( stereo_mode ) { + panning = 12; + if( ( s3m_file[ 64 + channel_idx ] & 0xFF ) < 8 ) { + panning = 3; + } + } + if( default_panning ) { + flags = s3m_file[ panning_offset + channel_idx ] & 0xFF; + if( ( flags & 0x20 ) == 0x20 ) { + panning = flags & 0xF; + } + } + module.set_initial_panning( channel_map[ channel_idx ], panning * 17 ); + } + sequence = read_s3m_sequence( s3m_file ); + module.set_sequence_length( sequence.length ); + for( order_idx = 0; order_idx < sequence.length; order_idx++ ) { + module.set_sequence( order_idx, sequence[ order_idx ] ); + } + module.set_num_instruments( num_instruments ); + for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) { + instrument = read_s3m_instrument( s3m_file, instrument_idx, signed_samples ); + module.set_instrument( instrument_idx + 1, instrument ); + } + module.set_num_patterns( num_patterns ); + for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) { + module.set_pattern( pattern_idx, read_s3m_pattern( s3m_file, pattern_idx, channel_map ) ); + } + return module; + } + + private static int[] read_s3m_sequence( byte[] s3m_file ) { + int num_pattern_orders, sequence_length; + int sequence_idx, order_idx, pattern_order; + int[] sequence; + num_pattern_orders = get_num_pattern_orders( s3m_file ); + sequence_length = 0; + for( order_idx = 0; order_idx < num_pattern_orders; order_idx++ ) { + pattern_order = s3m_file[ 96 + order_idx ] & 0xFF; + if( pattern_order == 255 ) { + break; + } else if( pattern_order < 254 ) { + sequence_length += 1; + } + } + sequence = new int[ sequence_length ]; + sequence_idx = 0; + for( order_idx = 0; order_idx < num_pattern_orders; order_idx++ ) { + pattern_order = s3m_file[ 96 + order_idx ] & 0xFF; + if( pattern_order == 255 ) { + break; + } else if( pattern_order < 254 ) { + sequence[ sequence_idx ] = pattern_order; + sequence_idx += 1; + } + } + return sequence; + } + + private static Instrument read_s3m_instrument( byte[] s3m_file, int instrument_idx, boolean signed_samples ) { + int instrument_offset; + int sample_data_offset, sample_data_length; + int loop_start, loop_length, c2_rate, sample_idx, amplitude; + boolean sixteen_bit; + Instrument instrument; + Sample sample; + short[] sample_data; + instrument_offset = get_instrument_offset( s3m_file, instrument_idx ); + instrument = new Instrument(); + instrument.name = ascii_text( s3m_file, instrument_offset + 48, 28 ); + sample = new Sample(); + if( s3m_file[ instrument_offset ] == 1 ) { + sample_data_length = get_sample_data_length( s3m_file, instrument_offset ); + loop_start = unsigned_short_le( s3m_file, instrument_offset + 20 ); + loop_length = unsigned_short_le( s3m_file, instrument_offset + 24 ) - loop_start; + sample.volume = s3m_file[ instrument_offset + 28 ] & 0xFF; + if( s3m_file[ instrument_offset + 30 ] != 0 ) { + throw new IllegalArgumentException( "ScreamTracker3: Packed samples not supported!" ); + } + if( ( s3m_file[ instrument_offset + 31 ] & 0x01 ) == 0 ) { + loop_length = 0; + } + if( ( s3m_file[ instrument_offset + 31 ] & 0x02 ) != 0 ) { + throw new IllegalArgumentException( "ScreamTracker3: Stereo samples not supported!" ); + } + sixteen_bit = ( s3m_file[ instrument_offset + 31 ] & 0x04 ) != 0; + c2_rate = unsigned_short_le( s3m_file, instrument_offset + 32 ); + sample.transpose = LogTable.log_2( c2_rate ) - LogTable.log_2( 8363 ); + sample_data_offset = get_sample_data_offset( s3m_file, instrument_offset ); + if( sixteen_bit ) { + if( signed_samples ) { + throw new IllegalArgumentException( "ScreamTracker3: Signed 16-bit samples not supported!" ); + } + sample_data_length >>= 1; + sample_data = new short[ sample_data_length ]; + for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) { + amplitude = s3m_file[ sample_data_offset + sample_idx * 2 ] & 0xFF; + amplitude |= ( s3m_file[ sample_data_offset + sample_idx * 2 + 1 ] & 0xFF ) << 8; + sample_data[ sample_idx ] = ( short ) ( amplitude - 32768 ); + } + } else { + sample_data = new short[ sample_data_length ]; + if( signed_samples ) { + for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) { + amplitude = s3m_file[ sample_data_offset + sample_idx ] << 8; + sample_data[ sample_idx ] = ( short ) amplitude; + } + } else { + for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) { + amplitude = ( s3m_file[ sample_data_offset + sample_idx ] & 0xFF ) << 8; + sample_data[ sample_idx ] = ( short ) ( amplitude - 32768 ); + } + } + } + sample.set_sample_data( sample_data, loop_start, loop_length, false ); + } + instrument.set_num_samples( 1 ); + instrument.set_sample( 0, sample ); + return instrument; + } + + private static Pattern read_s3m_pattern( byte[] s3m_file, int pattern_idx, int[] channel_map ) { + int pattern_offset; + int num_channels, num_notes; + int row_idx, channel_idx, note_idx; + int token, key, volume_column, effect, effect_param; + byte[] pattern_data; + Pattern pattern; + num_channels = 0; + for( channel_idx = 0; channel_idx < 32; channel_idx++ ) { + if( channel_map[ channel_idx ] >= num_channels ) { + num_channels = channel_idx + 1; + } + } + num_notes = num_channels * 64; + pattern_data = new byte[ num_notes * 5 ]; + row_idx = 0; + pattern_offset = get_pattern_offset( s3m_file, pattern_idx ) + 2; + while( row_idx < 64 ) { + token = s3m_file[ pattern_offset ] & 0xFF; + pattern_offset += 1; + if( token > 0 ) { + channel_idx = channel_map[ token & 0x1F ]; + note_idx = ( num_channels * row_idx + channel_idx ) * 5; + if( ( token & 0x20 ) == 0x20 ) { + /* Key + Instrument.*/ + if( channel_idx >= 0 ) { + key = s3m_file[ pattern_offset ] & 0xFF; + if( key == 255 ) { + key = 0; + } else if( key == 254 ) { + key = 97; + } else { + key = ( ( key & 0xF0 ) >> 4 ) * 12 + ( key & 0x0F ) + 1; + while( key > 96 ) { + key = key - 12; + } + } + pattern_data[ note_idx ] = ( byte ) key; + pattern_data[ note_idx + 1 ] = s3m_file[ pattern_offset + 1 ]; + } + pattern_offset += 2; + } + if( ( token & 0x40 ) == 0x40 ) { + /* Volume.*/ + if( channel_idx >= 0 ) { + volume_column = ( s3m_file[ pattern_offset ] & 0xFF ) + 0x10; + pattern_data[ note_idx + 2 ] = ( byte ) volume_column; + } + pattern_offset += 1; + } + if( ( token & 0x80 ) == 0x80 ) { + /* Effect + Param.*/ + if( channel_idx >= 0 ) { + effect = s3m_file[ pattern_offset ] & 0xFF; + effect_param = s3m_file[ pattern_offset + 1 ] & 0xFF; + effect = effect_map[ effect & 0x1F ]; + if( effect == 0xFF ) { + effect = 0; + effect_param = 0; + } + if( effect == 0x0E ) { + effect = effect_s_map[ ( effect_param & 0xF0 ) >> 4 ]; + effect_param = effect_param & 0x0F; + switch( effect ) { + case 0x08: + effect = 0x08; + effect_param = effect_param * 17; + break; + case 0x09: + effect = 0x08; + if( effect_param > 7 ) { + effect_param -= 8; + } else { + effect_param += 8; + } + effect_param = effect_param * 17; + break; + case 0xFF: + effect = 0; + effect_param = 0; + break; + default: + effect_param = ( ( effect & 0x0F ) << 4 ) | ( effect_param & 0x0F ); + effect = 0x0E; + break; + } + } + pattern_data[ note_idx + 3 ] = ( byte ) effect; + pattern_data[ note_idx + 4 ] = ( byte ) effect_param; + } + pattern_offset += 2; + } + } else { + row_idx += 1; + } + } + pattern = new Pattern(); + pattern.num_rows = 64; + pattern.set_pattern_data( pattern_data ); + return pattern; + } + + private static byte[] read_s3m_file( byte[] header_96_bytes, DataInput data_input ) throws IOException { + int s3m_file_length; + int num_pattern_orders, num_instruments, num_patterns; + int instrument_idx, pattern_idx; + int instrument_offset, sample_data_offset, pattern_offset; + byte[] s3m_file; + if( !is_s3m( header_96_bytes ) ) { + throw new IllegalArgumentException( "ScreamTracker3: Not an S3M file!" ); + } + s3m_file = header_96_bytes; + s3m_file_length = header_96_bytes.length; + num_pattern_orders = get_num_pattern_orders( s3m_file ); + num_instruments = get_num_instruments( s3m_file ); + num_patterns = get_num_patterns( s3m_file ); + s3m_file_length += num_pattern_orders; + s3m_file_length += num_instruments * 2; + s3m_file_length += num_patterns * 2; + /* Read enough of file to calculate the length.*/ + s3m_file = read_more( s3m_file, s3m_file_length, data_input ); + for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) { + instrument_offset = get_instrument_offset( s3m_file, instrument_idx ); + instrument_offset += 80; + if( instrument_offset > s3m_file_length ) { + s3m_file_length = instrument_offset; + } + } + for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) { + pattern_offset = get_pattern_offset( s3m_file, pattern_idx ); + pattern_offset += 2; + if( pattern_offset > s3m_file_length ) { + s3m_file_length = pattern_offset; + } + } + s3m_file = read_more( s3m_file, s3m_file_length, data_input ); + /* Read rest of file.*/ + for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) { + instrument_offset = get_instrument_offset( s3m_file, instrument_idx ); + sample_data_offset = get_sample_data_offset( s3m_file, instrument_offset ); + sample_data_offset += get_sample_data_length( s3m_file, instrument_offset ); + if( sample_data_offset > s3m_file_length ) { + s3m_file_length = sample_data_offset; + } + } + for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) { + pattern_offset = get_pattern_offset( s3m_file, pattern_idx ); + pattern_offset += get_pattern_length( s3m_file, pattern_offset ); + pattern_offset += 2; + if( pattern_offset > s3m_file_length ) { + s3m_file_length = pattern_offset; + } + } + s3m_file = read_more( s3m_file, s3m_file_length, data_input ); + return s3m_file; + } + + private static int get_num_pattern_orders( byte[] s3m_file ) { + int num_pattern_orders; + num_pattern_orders = unsigned_short_le( s3m_file, 32 ); + return num_pattern_orders; + } + + private static int get_num_instruments( byte[] s3m_file ) { + int num_instruments; + num_instruments = unsigned_short_le( s3m_file, 34 ); + return num_instruments; + } + + private static int get_num_patterns( byte[] s3m_file ) { + int num_patterns; + num_patterns = unsigned_short_le( s3m_file, 36 ); + return num_patterns; + } + + private static int get_instrument_offset( byte[] s3m_file, int instrument_idx ) { + int instrument_offset, pointer_offset; + pointer_offset = 96 + get_num_pattern_orders( s3m_file ); + instrument_offset = unsigned_short_le( s3m_file, pointer_offset + instrument_idx * 2 ) << 4; + return instrument_offset; + } + + private static int get_sample_data_offset( byte[] s3m_file, int instrument_offset ) { + int sample_data_offset; + sample_data_offset = 0; + if( s3m_file[ instrument_offset ] == 1 ) { + sample_data_offset = ( s3m_file[ instrument_offset + 13 ] & 0xFF ) << 20; + sample_data_offset |= unsigned_short_le( s3m_file, instrument_offset + 14 ) << 4; + } + return sample_data_offset; + } + + private static int get_sample_data_length( byte[] s3m_file, int instrument_offset ) { + int sample_data_length; + boolean sixteen_bit; + sample_data_length = 0; + if( s3m_file[ instrument_offset ] == 1 ) { + sample_data_length = unsigned_short_le( s3m_file, instrument_offset + 16 ); + sixteen_bit = ( s3m_file[ instrument_offset + 31 ] & 0x04 ) != 0; + if( sixteen_bit ) { + sample_data_length <<= 1; + } + } + return sample_data_length; + } + + private static int get_pattern_offset( byte[] s3m_file, int pattern_idx ) { + int pattern_offset, pointer_offset; + pointer_offset = 96 + get_num_pattern_orders( s3m_file ); + pointer_offset += get_num_instruments( s3m_file ) * 2; + pattern_offset = unsigned_short_le( s3m_file, pointer_offset + pattern_idx * 2 ) << 4; + return pattern_offset; + } + + private static int get_pattern_length( byte[] s3m_file, int pattern_offset ) { + int pattern_length; + pattern_length = unsigned_short_le( s3m_file, pattern_offset ); + return pattern_length; + } + + private static byte[] read_more( byte[] old_data, int new_length, DataInput data_input ) throws IOException { + byte[] new_data; + new_data = old_data; + if( new_length > old_data.length ) { + new_data = new byte[ new_length ]; + System.arraycopy( old_data, 0, new_data, 0, old_data.length ); + try { + data_input.readFully( new_data, old_data.length, new_data.length - old_data.length ); + } catch( EOFException e ) { + System.out.println( "ScreamTracker3: Module has been truncated!" ); + } + } + return new_data; + } + + private static int unsigned_short_le( byte[] buffer, int offset ) { + int value; + value = buffer[ offset ] & 0xFF; + value = value | ( ( buffer[ offset + 1 ] & 0xFF ) << 8 ); + return value; + } + + private static String ascii_text( byte[] buffer, int offset, int length ) { + int idx, chr; + byte[] string_buffer; + String string; + string_buffer = new byte[ length ]; + for( idx = 0; idx < length; idx++ ) { + chr = buffer[ offset + idx ]; + if( chr < 32 ) { + chr = 32; + } + string_buffer[ idx ] = ( byte ) chr; + } + try { + string = new String( string_buffer, 0, length, "ISO-8859-1" ); + } catch( UnsupportedEncodingException e ) { + string = ""; + } + return string; + } +} + diff --git a/src/com/ibxm/WavHeader.java b/src/com/ibxm/WavHeader.java new file mode 100644 index 0000000..e96af5c --- /dev/null +++ b/src/com/ibxm/WavHeader.java @@ -0,0 +1,102 @@ +package com.ibxm; + +/* + WAV Header format. All values little endian. + + CHAR[4] "RIFF" + UINT32 Size of following data. Sample data length+36. Must be even. + CHAR[4] "WAVE" + CHAR[4] "fmt " + UINT32 PCM Header chunk size = 16 + UINT16 0x0001 (PCM) + UINT16 NumChannels + UINT32 SampleRate + UINT32 BytesPerSec = samplerate*frame size + UINT16 frame Size (eg 4 bytes for stereo PCM16) + UINT16 BitsPerSample + CHAR[4] "data" + UINT32 Length of sample data. + + + Example from real, valid wave file. 16 bit mono 8khz. + + 524946466061000057415645666D74201000000001000100401F0000 + R I F F ^(dsiz) W A V E f m t ^(PCMHS)^(P)^(C)^(Rate) + 803E000002001000646174613C610000 + ^(Byt/s)^(F)^(b)d a t a ^(slen) + + Total 44 bytes. + + Audio data that follows is: + Unsigned if 8 bit. + Signed little-endian if 16 bit or above. + L-R interleaved if stereo. + */ + +/** + * A simple tool for computing and generating + * basic, single chunk RIFF-WAV headers. + * + * @author Martin Cameron + */ +public class WavHeader { + + /** Header size in bytes. */ + public static final int SIZE = 44; + + /** + *

Write a WAV header for the specified format.

+ *

For a valid header you also need to specify the number of samples + * that will immediately follow the header. This must result in an even number of bytes.

+ * + * @param outBuf the buffer to write header into, from index 0 + * @param channels the number of channels in audio stream. + * @param rate the sampling rate. + * @param bytes the number of bytes per sample (i.e. 2 for 16bit) + * @param numSamples the number of samples of audio data to follow. + * @return the number of bytes taken up by the header. + */ + public static int writeHeader(byte[] outBuf, int channels, int rate, int bytes, int numSamples) { + outBuf[0] = (byte) 0x52; //R + outBuf[1] = (byte) 0x49; //I + outBuf[2] = (byte) 0x46; //F + outBuf[3] = (byte) 0x46; //F + writeINT32LE(outBuf, 4, channels * bytes * numSamples + 36); + outBuf[8] = (byte) 0x57; //W + outBuf[9] = (byte) 0x41; //A + outBuf[10] = (byte) 0x56; //V + outBuf[11] = (byte) 0x45; //E + outBuf[12] = (byte) 0x66; //f + outBuf[13] = (byte) 0x6D; //m + outBuf[14] = (byte) 0x74; //t + outBuf[15] = (byte) 0x20; //Space + writeINT32LE(outBuf, 16, 16); + writeINT16LE(outBuf, 20, 1); + writeINT16LE(outBuf, 22, channels); + writeINT32LE(outBuf, 24, rate); + writeINT32LE(outBuf, 28, channels * bytes * rate); + writeINT16LE(outBuf, 32, channels * bytes); + writeINT16LE(outBuf, 34, bytes * 8); + outBuf[36] = (byte) 0x64; //d + outBuf[37] = (byte) 0x61; //a + outBuf[38] = (byte) 0x74; //t + outBuf[39] = (byte) 0x61; //a + writeINT32LE(outBuf, 40, channels * bytes * numSamples); + return SIZE; + } + + /** Write a little-endian short into the specified array. */ + public static void writeINT16LE(byte[] outBuf, int offset, int value) { + outBuf[offset] = (byte) (value & 0xFF); + outBuf[offset + 1] = (byte) (value >> 8); + } + + /** Write a little-endian int into the specified array. */ + public static void writeINT32LE(byte[] outBuf, int offset, int value) { + outBuf[offset] = (byte) (value & 0xFF); + outBuf[offset + 1] = (byte) ((value >> 8) & 0xFF); + outBuf[offset + 2] = (byte) ((value >> 16) & 0xFF); + outBuf[offset + 3] = (byte) (value >> 24); + } +} + diff --git a/src/com/innosystec/unrar/Archive.java b/src/com/innosystec/unrar/Archive.java new file mode 100644 index 0000000..a88e21d --- /dev/null +++ b/src/com/innosystec/unrar/Archive.java @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 22.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression + * algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar; + +import com.classpath.io.PipedInputStream; +import com.classpath.io.PipedOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import com.innosystec.unrar.exception.RarException; +import com.innosystec.unrar.exception.RarException.RarExceptionType; +import com.innosystec.unrar.rarfile.AVHeader; +import com.innosystec.unrar.rarfile.BaseBlock; +import com.innosystec.unrar.rarfile.BlockHeader; +import com.innosystec.unrar.rarfile.CommentHeader; +import com.innosystec.unrar.rarfile.EAHeader; +import com.innosystec.unrar.rarfile.EndArcHeader; +import com.innosystec.unrar.rarfile.FileHeader; +import com.innosystec.unrar.rarfile.MacInfoHeader; +import com.innosystec.unrar.rarfile.MainHeader; +import com.innosystec.unrar.rarfile.MarkHeader; +import com.innosystec.unrar.rarfile.ProtectHeader; +import com.innosystec.unrar.rarfile.SignHeader; +import com.innosystec.unrar.rarfile.SubBlockHeader; +import com.innosystec.unrar.rarfile.SubBlockHeaderType; +import com.innosystec.unrar.rarfile.UnixOwnersHeader; +import com.innosystec.unrar.rarfile.UnrarHeadertype; +import com.innosystec.unrar.unpack.ComprDataIO; +import com.innosystec.unrar.unpack.Unpack; +import com.one.Container; +import com.one.ContainerEntry; +import com.one.RandomAccessInputStream; +import com.one.file.FileConnection; +import com.vmx.AuxClass; +import com.vmx.ProgressCallback; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class Archive extends Container +{ + //private IReadOnlyAccess rais; + private final UnrarCallback unrarCallback; + private final ComprDataIO dataIO; + private final Vector headers = new Vector(); + private MarkHeader markHead = null; + private MainHeader newMhd = null; + private EndArcHeader endHeader = null; + private Unpack unpack; + /** Archive data CRC. */ + private long arcDataCRC = 0xffffffff; + private int currentHeaderIndex; + private boolean encrypted = false; + private int sfxSize = 0; + /** Size of packed data in current file. */ + private long totalPackedSize = 0L; + /** Number of bytes of compressed data read from current file. */ + private long totalPackedRead = 0L; + + public Archive() + { + unrarCallback = null; + dataIO = new ComprDataIO(this); + } + + public Archive(FileConnection file) throws RarException, IOException + { + this(file, null); + } + + /** + * create a new archive object using the given file + * @param file the file to extract + * @throws RarException + */ + public Archive(FileConnection file, UnrarCallback unrarCallback) throws RarException, IOException + { + setFile(file); + this.unrarCallback = unrarCallback; + dataIO = new ComprDataIO(this); + } + + public FileConnection getFile() + { + return file; + } + + void setFile(FileConnection file) throws IOException + { + this.file = file; + totalPackedSize = 0L; + totalPackedRead = 0L; + close(); + + try + { + readEntries(); + } + catch(Exception e) + { + System.out.println("exception in archive constructor maybe file is encrypted or currupt"); + e.printStackTrace(); + //ignore exceptions to allow exraction of working files in + //corrupt archive + } + + // Calculate size of packed data + + Enumeration blocks = headers.elements(); + BaseBlock block; + + while(blocks.hasMoreElements()) + { + block = (BaseBlock) blocks.nextElement(); + + if(block.getHeaderType() == UnrarHeadertype.FileHeader) + { + totalPackedSize += ((FileHeader) block).getFullPackSize(); + } + } + if(unrarCallback != null) + { + unrarCallback.volumeProgressChanged(totalPackedRead, + totalPackedSize); + } + } + + public void bytesReadRead(int count) + { + if(count > 0) + { + totalPackedRead += count; + if(unrarCallback != null) + { + unrarCallback.volumeProgressChanged(totalPackedRead, + totalPackedSize); + } + } + } + + public RandomAccessInputStream getRof() + { + return rais; + } + + /** + * @return returns all file headers of the archive + */ + public Vector getFileHeaders() + { + Vector list = new Vector(); + + Enumeration blocks = headers.elements(); + BaseBlock block; + + while(blocks.hasMoreElements()) + { + block = (BaseBlock) blocks.nextElement(); + + if(block.getHeaderType() == (UnrarHeadertype.FileHeader)) + { + list.addElement((FileHeader) block); + } + } + + return list; + } + + public FileHeader nextFileHeader() + { + int n = headers.size(); + + while(currentHeaderIndex < n) + { + BaseBlock block = (BaseBlock) headers.elementAt(currentHeaderIndex++); + + if(block.getHeaderType() == UnrarHeadertype.FileHeader) + { + return (FileHeader) block; + } + } + + return null; + } + + public UnrarCallback getUnrarCallback() + { + return unrarCallback; + } + + /** + * + * @return whether the archive is encrypted + */ + public boolean isEncrypted() + { + if(newMhd != null) + { + return newMhd.isEncrypted(); + } + else + { + throw new NullPointerException("mainheader is null"); + } + } + + public boolean isReadOnly() + { + return true; + } + + public boolean addEntry(RandomAccessInputStream source, String name, long time, boolean replace, ProgressCallback callback) throws IOException + { + //throw new IOException("Container is read only"); + checkReadOnly(); + return false; + } + + public boolean deleteEntry(ContainerEntry entry) throws IOException + { + //throw new IOException("Container is read only"); + checkReadOnly(); + return false; + } + + public boolean renameEntry(ContainerEntry entry, String newName) throws IOException + { + //throw new IOException("Container is read only"); + checkReadOnly(); + return false; + } + + public void finish() throws IOException + { + } + + public InputStream getInputStream(ContainerEntry entry) throws IOException + { + RarEntry rarentry = (RarEntry)entry; + + PipedOutputStream os = new PipedOutputStream(); + PipedInputStream is = new PipedInputStream(); + + is.connect(os); + + (new Thread(new ExtractThread(this, rarentry.getFileHeader(), os))).start(); + + return is; + } + + /** + * Read the headers of the archive + * @throws RarException + */ + protected void readEntries() throws IOException + { + entries = new Hashtable(); + + markHead = null; + newMhd = null; + endHeader = null; + headers.removeAllElements(); + currentHeaderIndex = 0; + int toRead = 0; + + long fileLength = rais.getCapacity(); + + while(true) + { + int size = 0; + int newpos = 0; + byte[] baseBlockBuffer = new byte[BaseBlock.BaseBlockSize]; + + int position = rais.getPosition(); + + // Weird, but is trying to read beyond the end of the file + if(position >= fileLength) + { + break; + } + +// System.out.println("\n--------reading header--------"); + size = rais.read(baseBlockBuffer, 0, BaseBlock.BaseBlockSize); + if(size == 0) + { + break; + } + BaseBlock block = new BaseBlock(baseBlockBuffer); + + block.setPositionInFile(position); + + + switch(block.getHeaderType()) + { + + case UnrarHeadertype.MarkHeader: + markHead = new MarkHeader(block); + if(!markHead.isSignature()) + { + throw new RarException( + RarException.RarExceptionType.badRarArchive); + } + headers.addElement(markHead); +// markHead.print(); + break; + + case UnrarHeadertype.MainHeader: + int mainHeaderSize = 0; + toRead = block.hasEncryptVersion() + ? MainHeader.mainHeaderSizeWithEnc + : MainHeader.mainHeaderSize; + byte[] mainbuff = new byte[toRead]; + mainHeaderSize = rais.read(mainbuff, 0, toRead); + MainHeader mainhead = new MainHeader(block, mainbuff); + headers.addElement(mainhead); + this.newMhd = mainhead; + if(newMhd.isEncrypted()) + { + throw new RarException( + RarException.RarExceptionType.rarEncryptedException); + } +// mainhead.print(); + break; + + case UnrarHeadertype.SignHeader: + int signHeaderSize = 0; + toRead = SignHeader.signHeaderSize; + byte[] signBuff = new byte[toRead]; + signHeaderSize = rais.read(signBuff, 0, toRead); + SignHeader signHead = new SignHeader(block, signBuff); + headers.addElement(signHead); +// System.out.println("HeaderType: SignHeader"); + + break; + + case UnrarHeadertype.AvHeader: + int avHeaderSize = 0; + toRead = AVHeader.avHeaderSize; + byte[] avBuff = new byte[toRead]; + avHeaderSize = rais.read(avBuff, 0, toRead); + AVHeader avHead = new AVHeader(block, avBuff); + headers.addElement(avHead); +// System.out.println("headertype: AVHeader"); + break; + + case UnrarHeadertype.CommHeader: + int commHeaderSize = 0; + toRead = CommentHeader.commentHeaderSize; + byte[] commBuff = new byte[toRead]; + commHeaderSize = rais.read(commBuff, 0, toRead); + CommentHeader commHead = new CommentHeader(block, commBuff); + headers.addElement(commHead); +// System.out.println("method: "+commHead.getUnpMethod()+"; 0x"+ +// Integer.toHexString(commHead.getUnpMethod())); + newpos = commHead.getPositionInFile() + commHead.getHeaderSize(); + rais.setPosition(newpos); + + break; + case UnrarHeadertype.EndArcHeader: + + toRead = 0; + if(block.hasArchiveDataCRC()) + { + toRead += EndArcHeader.endArcArchiveDataCrcSize; + } + if(block.hasVolumeNumber()) + { + toRead += EndArcHeader.endArcVolumeNumberSize; + } + EndArcHeader endArcHead; + if(toRead > 0) + { + int endArcHeaderSize = 0; + byte[] endArchBuff = new byte[toRead]; + endArcHeaderSize = rais.read(endArchBuff, 0, toRead); + endArcHead = new EndArcHeader(block, endArchBuff); +// System.out.println("HeaderType: endarch\ndatacrc:"+ +// endArcHead.getArchiveDataCRC()); + } + else + { +// System.out.println("HeaderType: endarch - no Data"); + endArcHead = new EndArcHeader(block, null); + } + headers.addElement(endArcHead); + this.endHeader = endArcHead; +// System.out.println("\n--------end header--------"); + return; + + default: + byte[] blockHeaderBuffer = + new byte[BlockHeader.blockHeaderSize]; + int bhsize = rais.read(blockHeaderBuffer, 0, BlockHeader.blockHeaderSize); + BlockHeader blockHead = new BlockHeader(block, + blockHeaderBuffer); + + switch(blockHead.getHeaderType()) + { + case UnrarHeadertype.NewSubHeader: + case UnrarHeadertype.FileHeader: + toRead = blockHead.getHeaderSize() + - BlockHeader.BaseBlockSize + - BlockHeader.blockHeaderSize; + byte[] fileHeaderBuffer = new byte[toRead]; + int fhsize = rais.read(fileHeaderBuffer, 0, toRead); + + FileHeader fh = new FileHeader(blockHead, fileHeaderBuffer); +// if (DEBUG) { +// fh.print(); +// } + headers.addElement(fh); + + RarEntry entry = new RarEntry(fh); + + entries.put(entry.getName(), entry); + addFile(entry.getName()); + + newpos = fh.getPositionInFile() + fh.getHeaderSize() + fh.getFullPackSize(); + rais.setPosition(newpos); + break; + + case UnrarHeadertype.ProtectHeader: + toRead = blockHead.getHeaderSize() + - BlockHeader.BaseBlockSize + - BlockHeader.blockHeaderSize; + byte[] protectHeaderBuffer = new byte[toRead]; + int phsize = rais.read(protectHeaderBuffer, 0, toRead); + ProtectHeader ph = new ProtectHeader(blockHead, + protectHeaderBuffer); + +// System.out.println("totalblocks"+ph.getTotalBlocks()); + newpos = ph.getPositionInFile() + + ph.getHeaderSize(); + rais.setPosition(newpos); + break; + + case UnrarHeadertype.SubHeader: + { + byte[] subHeadbuffer = new byte[SubBlockHeader.SubBlockHeaderSize]; + int subheadersize = rais.read(subHeadbuffer, 0, SubBlockHeader.SubBlockHeaderSize); + SubBlockHeader subHead = new SubBlockHeader(blockHead, subHeadbuffer); + subHead.print(); + switch(subHead.getSubType()) + { + case SubBlockHeaderType.MAC_HEAD: + { + byte[] macHeaderbuffer = new byte[MacInfoHeader.MacInfoHeaderSize]; + int macheadersize = rais.read(macHeaderbuffer, 0, MacInfoHeader.MacInfoHeaderSize); + MacInfoHeader macHeader = new MacInfoHeader(subHead, macHeaderbuffer); + macHeader.print(); + headers.addElement(macHeader); + + break; + } + //TODO implement other subheaders + case SubBlockHeaderType.BEEA_HEAD: + break; + case SubBlockHeaderType.EA_HEAD: + { + byte[] eaHeaderBuffer = new byte[EAHeader.EAHeaderSize]; + int eaheadersize = rais.read(eaHeaderBuffer, 0, EAHeader.EAHeaderSize); + EAHeader eaHeader = new EAHeader(subHead, eaHeaderBuffer); + eaHeader.print(); + headers.addElement(eaHeader); + + break; + } + case SubBlockHeaderType.NTACL_HEAD: + break; + case SubBlockHeaderType.STREAM_HEAD: + break; + case SubBlockHeaderType.UO_HEAD: + toRead = subHead.getHeaderSize(); + toRead -= BaseBlock.BaseBlockSize; + toRead -= BlockHeader.blockHeaderSize; + toRead -= SubBlockHeader.SubBlockHeaderSize; + byte[] uoHeaderBuffer = new byte[toRead]; + int uoHeaderSize = rais.read(uoHeaderBuffer, 0, toRead); + UnixOwnersHeader uoHeader = new UnixOwnersHeader(subHead, uoHeaderBuffer); + uoHeader.print(); + headers.addElement(uoHeader); + break; + default: + break; + } + + break; + } + default: + System.out.println("Unknown Header"); + throw new RarException( + RarExceptionType.notRarArchive); + + } + } +// System.out.println("\n--------end header--------"); + } + } + + /** + * Extract the file specified by the given header and write it + * to the supplied output stream + * + * @param header the header to be extracted + * @param os the outputstream + * @throws RarException + */ + public void extractFile(FileHeader hd, OutputStream os) throws RarException + { + if(!headers.contains(hd)) + { + throw new RarException(RarExceptionType.headerNotInArchive); + } + try + { + doExtractFile(hd, os); + } + catch(Exception e) + { + if(e instanceof RarException) + { + throw (RarException) e; + } + else + { + throw new RarException(e); + } + } + } + + private void doExtractFile(FileHeader hd, OutputStream os) throws RarException, IOException + { + dataIO.init(os); + dataIO.init(hd); + dataIO.setUnpFileCRC(this.isOldFormat() ? 0 : 0xffFFffFF); + if(unpack == null) + { + unpack = new Unpack(dataIO); + } + if(!hd.isSolid()) + { + unpack.init(null); + } + unpack.setDestSize(hd.getFullUnpackSize()); + try + { + unpack.doUnpack(hd.getUnpVersion(), hd.isSolid()); + // Verify file CRC + hd = dataIO.getSubHeader(); + long actualCRC = hd.isSplitAfter() ? ~dataIO.getPackedCRC() : ~dataIO.getUnpFileCRC(); + int expectedCRC = hd.getFileCRC(); + if(actualCRC != expectedCRC) + { + throw new RarException(RarExceptionType.crcError); + } +// if (!hd.isSplitAfter()) { +// // Verify file CRC +// if(~dataIO.getUnpFileCRC() != hd.getFileCRC()){ +// throw new RarException(RarExceptionType.crcError); +// } +// } + } + catch(Exception e) + { + unpack.cleanUp(); + if(e instanceof RarException) + { + //throw new RarException((RarException)e); + throw (RarException) e; + } + else + { + throw new RarException(e); + } + } + } + + /** + * @return returns the main header of this archive + */ + public MainHeader getMainHeader() + { + return newMhd; + } + + /** + * @return whether the archive is old format + */ + public boolean isOldFormat() + { + return markHead.isOldFormat(); + } + + /** Close the underlying compressed file. */ + public void close() throws IOException + { + if(rais != null) + { + rais.close(); + rais = null; + } + } +} diff --git a/src/com/innosystec/unrar/ExtractThread.java b/src/com/innosystec/unrar/ExtractThread.java new file mode 100644 index 0000000..8ceed94 --- /dev/null +++ b/src/com/innosystec/unrar/ExtractThread.java @@ -0,0 +1,44 @@ +package com.innosystec.unrar; + +import com.classpath.io.PipedOutputStream; +import com.innosystec.unrar.rarfile.FileHeader; +import java.io.IOException; + +public class ExtractThread implements Runnable +{ + protected Archive archive; + protected FileHeader fh; + protected PipedOutputStream os; + + public ExtractThread(Archive archive, FileHeader fh, PipedOutputStream os) + { + this.archive = archive; + this.fh = fh; + this.os = os; + } + + public void run() + { + try + { + archive.extractFile(fh, os); + } + catch(IOException ioe) + { + os.passException(ioe); + } + catch(Throwable t) + { + os.passException(new IOException(t.toString())); + } + + try + { + os.close(); + } + catch(IOException e) + { + e.printStackTrace(); + } + } +} diff --git a/src/com/innosystec/unrar/RarEntry.java b/src/com/innosystec/unrar/RarEntry.java new file mode 100644 index 0000000..55827af --- /dev/null +++ b/src/com/innosystec/unrar/RarEntry.java @@ -0,0 +1,29 @@ +package com.innosystec.unrar; + +import com.innosystec.unrar.rarfile.FileHeader; +import com.one.ContainerEntry; + +public class RarEntry extends ContainerEntry +{ + protected FileHeader fh; + + public RarEntry(FileHeader fh) + { + this.fh = fh; + + name = fh.getFileNameString().replace('\\', '/'); + + if(fh.isDirectory() && !name.endsWith("/")) + { + name += "/"; + } + + size = fh.getFullUnpackSize(); + compressedSize = fh.getFullPackSize(); + } + + public FileHeader getFileHeader() + { + return fh; + } +} diff --git a/src/com/innosystec/unrar/UnrarCallback.java b/src/com/innosystec/unrar/UnrarCallback.java new file mode 100644 index 0000000..a73fcbc --- /dev/null +++ b/src/com/innosystec/unrar/UnrarCallback.java @@ -0,0 +1,22 @@ +package com.innosystec.unrar; + +import com.one.file.FileConnection; + +/** + * + * @author alban + */ +public interface UnrarCallback { + + /** + * Return true if the next volume is ready to be processed, + * false otherwise. + */ + boolean isNextVolumeReady(FileConnection nextVolume); + + /** + * This method is invoked each time the progress of the current + * volume changes. + */ + void volumeProgressChanged(long current, long total); +} diff --git a/src/com/innosystec/unrar/Volume.java b/src/com/innosystec/unrar/Volume.java new file mode 100644 index 0000000..834a40b --- /dev/null +++ b/src/com/innosystec/unrar/Volume.java @@ -0,0 +1,128 @@ +package com.innosystec.unrar; + +import com.innosystec.unrar.rarfile.FileHeader; +import com.innosystec.unrar.unpack.*; +import com.one.file.Connector; +import com.one.file.FileConnection; +import java.io.IOException; + +/** + * + * @author alban + */ +public class Volume +{ + private Volume() + { + } + + public static boolean mergeArchive(Archive archive, ComprDataIO dataIO) + throws IOException + { + FileHeader hd = dataIO.getSubHeader(); + if(hd.getUnpVersion() >= 20 + && hd.getFileCRC() != 0xffffffff + && dataIO.getPackedCRC() != ~hd.getFileCRC()) + { + System.err.println("Data Bad CRC"); + } + + boolean oldNumbering = !archive.getMainHeader().isNewNumbering() || archive.isOldFormat(); + String nextName = nextVolumeName(archive.getFile().getPath(), oldNumbering); + FileConnection nextVolume = (FileConnection)Connector.open("file:///" + nextName); + UnrarCallback callback = archive.getUnrarCallback(); + if((callback != null) && !callback.isNextVolumeReady(nextVolume)) + { + return false; + } + if(!nextVolume.exists()) + { + return false; + } + archive.setFile(nextVolume); + hd = archive.nextFileHeader(); + if(hd == null) + { + return false; + } + dataIO.init(hd); + return true; + } + + public static String nextVolumeName(String arcName, boolean oldNumbering) + { + if(!oldNumbering) + { + // part1.rar, part2.rar, ... + int len = arcName.length(); + int indexR = len - 1; + while((indexR >= 0) && !isDigit(arcName.charAt(indexR))) + { + indexR--; + } + int index = indexR + 1; + int indexL = indexR - 1; + while((indexL >= 0) && isDigit(arcName.charAt(indexL))) + { + indexL--; + } + if(indexL < 0) + { + return null; + } + indexL++; + StringBuffer buffer = new StringBuffer(len); + buffer.append(arcName.substring(0, indexL)); + char[] digits = new char[indexR - indexL + 1]; + arcName.getChars(indexL, indexR + 1, digits, 0); + indexR = digits.length - 1; + while((indexR >= 0) && (++digits[indexR]) == '9' + 1) + { + digits[indexR] = '0'; + indexR--; + } + if(indexR < 0) + { + buffer.append('1'); + } + buffer.append(digits); + buffer.append(arcName.substring(index, len)); + return buffer.toString(); + } + else + { + // .rar, .r00, .r01, ... + int len = arcName.length(); + if((len <= 4) || (arcName.charAt(len - 4) != '.')) + { + return null; + } + StringBuffer buffer = new StringBuffer(); + int off = len - 3; + buffer.append(arcName.substring(0, off)); + if(!isDigit(arcName.charAt(off + 1)) + || !isDigit(arcName.charAt(off + 2))) + { + buffer.append("r00"); + } + else + { + char[] ext = new char[3]; + arcName.getChars(off, len, ext, 0); + int i = ext.length - 1; + while((++ext[i]) == '9' + 1) + { + ext[i] = '0'; + i--; + } + buffer.append(ext); + } + return buffer.toString(); + } + } + + private static boolean isDigit(char c) + { + return (c >= '0') && (c <= '9'); + } +} diff --git a/src/com/innosystec/unrar/crc/RarCRC.java b/src/com/innosystec/unrar/crc/RarCRC.java new file mode 100644 index 0000000..ab72ab7 --- /dev/null +++ b/src/com/innosystec/unrar/crc/RarCRC.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 29.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.crc; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RarCRC { + + private final static int crcTab[]; + static { + crcTab = new int[256]; + for (int i = 0; i < 256; i++) { + int c = i; + for (int j = 0; j < 8; j++){ + if ((c & 1) !=0) { + c >>>= 1; + c ^= 0xEDB88320; + } + else{ + c >>>= 1; + } + } + crcTab[i] = c; + } + } + + private RarCRC() { + } + + public static int checkCrc(int startCrc, byte[] data, int offset, + int count) { + int size = Math.min(data.length-offset,count); + // #if defined(LITTLE_ENDIAN) && defined(PRESENT_INT32) && + // defined(ALLOW_NOT_ALIGNED_INT) + /* + for (int i = 0; (0 < size) && i < data.length - 8 + && ((data[i + 8] & 7) != 0); i++) { + startCrc = crcTab[(short) (startCrc ^ data[i]) & 0x00FF] ^ (startCrc >>> 8); + size--; + } + + for (int i = 0; size >= 8; i += 8) { + startCrc ^= data[i + 0] << 24; + startCrc ^= data[i + 1] << 16; + startCrc ^= data[i + 2] << 8; + startCrc ^= data[i + 3]; + + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + + startCrc ^= data[i + 4] << 24; + startCrc ^= data[i + 5] << 16; + startCrc ^= data[i + 6] << 8; + startCrc ^= data[i + 7]; + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + size -= 8; + }*/ + + for (int i = 0; i < size; i++) + { +/* + // (byte)(StartCRC^Data[I]) + int pos = 0; // pos=0x00000000 + pos |= startCrc; // pos=ffffffff + + pos ^= data[i]; // data[0]=0x73=115dec --> pos=140 + System.out.println(Integer.toHexString(pos)); + + // Only last 8 bit because CRCtab has length 256 + pos = pos & 0x000000FF; + System.out.println("pos:"+pos); + //startCrc >>>= 8; + + + //StartCRC>>8 + int temp =0; + temp|=startCrc; + temp >>>= 8; + System.out.println("temp:"+Integer.toHexString(temp)); + + + startCrc = (crcTab[pos]^temp); + System.out.println("--"+Integer.toHexString(startCrc));*/ + + startCrc=(crcTab[((int)((int)startCrc ^ + (int)data[offset+i]))&0xff]^(startCrc>>>8)); + + //System.out.println(Integer.toHexString(startCrc)); + + // Original code: + //StartCRC=CRCTab[(byte)(StartCRC^Data[I])]^(StartCRC>>8); + } + return (startCrc); + } + + public static short checkOldCrc(short startCrc, byte[] data, int count) { + int n = Math.min(data.length, count); + for (int i = 0; i < n; i++) { + startCrc = (short) ((short) (startCrc + (short) (data[i]&0x00ff)) & -1); + startCrc = (short) (((startCrc << 1) | (startCrc >>> 15)) & -1); + } + return (startCrc); + } + +// public static void main(String[] args) +// { +// RarCRC rc = new RarCRC(); +// //byte[] data = { 0x72, 0x21, 0x1A, 0x07, 0x00}; +// +// byte[] data = {0x73 ,0x00 ,0x00 ,0x0D ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00}; +// +// int crc = 0x90CF; +// +// +// int result = rc.checkCrc(0xFFFFffff, data,0,data.length); +// System.out.println("3: "+Integer.toHexString(~result&0xffff)); +// +// } + +} diff --git a/src/com/innosystec/unrar/crypt/Rijndael.java b/src/com/innosystec/unrar/crypt/Rijndael.java new file mode 100644 index 0000000..34513e1 --- /dev/null +++ b/src/com/innosystec/unrar/crypt/Rijndael.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.crypt; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class Rijndael { + +} diff --git a/src/com/innosystec/unrar/exception/RarException.java b/src/com/innosystec/unrar/exception/RarException.java new file mode 100644 index 0000000..a19a112 --- /dev/null +++ b/src/com/innosystec/unrar/exception/RarException.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 30.07.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.exception; + +import java.io.IOException; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RarException extends IOException +{ + private String type; + + public RarException(Exception e) + { + super(e.toString()); + this.type = RarExceptionType.unkownError; + } + + public RarException(RarException e) + { + super(e.toString()); + this.type = e.getType(); + } + + public RarException(String type) + { + super(type); + this.type = type; + } + + public static class RarExceptionType + { + public static final String + + notImplementedYet = "notImplementedYet", + crcError = "crcError", + notRarArchive = "notRarArchive", + badRarArchive = "badRarArchive", + unkownError = "unkownError", + headerNotInArchive = "headerNotInArchive", + wrongHeaderType = "wrongHeaderType", + ioError = "ioError", + rarEncryptedException = "rarEncryptedException"; + } + + public String getType() + { + return type; + } + + public void setType(String type) + { + this.type = type; + } +} diff --git a/src/com/innosystec/unrar/io/IReadOnlyAccess.java b/src/com/innosystec/unrar/io/IReadOnlyAccess.java new file mode 100644 index 0000000..9cbc73d --- /dev/null +++ b/src/com/innosystec/unrar/io/IReadOnlyAccess.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 23.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.io; + +import java.io.IOException; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public interface IReadOnlyAccess { + + /** + * @return the current position in the file + */ + public long getPosition() throws IOException; + + /** + * @param pos the position in the file + * @return success ? true : false + */ + public void setPosition(long pos) throws IOException; + + /** Read a single byte of data. */ + public int read() throws IOException; + + /** + * Read up to count bytes to the specified buffer. + */ + public int read(byte[] buffer, int off, int count) throws IOException; + + /** + * Read exactly count bytes to the specified buffer. + * + * @param buffer where to store the read data + * @param count how many bytes to read + * @return bytes read || -1 if IO problem + */ + public int readFully(byte[] buffer, int count) throws IOException; + + /** Close this file. */ + public void close() throws IOException; +} diff --git a/src/com/innosystec/unrar/io/Raw.java b/src/com/innosystec/unrar/io/Raw.java new file mode 100644 index 0000000..7cc50ad --- /dev/null +++ b/src/com/innosystec/unrar/io/Raw.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 18.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.io; + +/** + * Read / write numbers to a byte[] regarding the endianness of the array + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class Raw +{ + /** + * Read a short value from the byte array at the given position + * (Big Endian) + * @param array the array to read from + * @param pos the position + * @return the value + */ + public static final short readShortBigEndian(byte[] array,int pos){ + short temp = 0; + temp |= array[pos]&0xff; + temp<<=8; + temp |= array[pos+1]&0xff; + return temp; + } + /** + * Read a int value from the byte array at the given position + * (Big Endian) + * @param array the array to read from + * @param pos the offset + * @return the value + */ + public static final int readIntBigEndian(byte[] array,int pos){ + int temp = 0; + temp |= array[pos]&0xff; + temp<<=8; + temp |= array[pos+1]&0xff; + temp<<=8; + temp |= array[pos+2]&0xff; + temp<<=8; + temp |= array[pos+3]&0xff; + return temp; + } + /** + * Read a long value from the byte array at the given position + * (Big Endian) + * @param array the array to read from + * @param pos the offset + * @return the value + */ + public static final long readLongBigEndian(byte[] array,int pos){ + int temp = 0; + temp |= array[pos]&0xff; + temp<<=8; + temp |= array[pos+1]&0xff; + temp<<=8; + temp |= array[pos+2]&0xff; + temp<<=8; + temp |= array[pos+3]&0xff; + temp<<=8; + temp |= array[pos+4]&0xff; + temp<<=8; + temp |= array[pos+5]&0xff; + temp<<=8; + temp |= array[pos+6]&0xff; + temp<<=8; + temp |= array[pos+7]&0xff; + return temp; + } + /** + * Read a short value from the byte array at the given position + * (little Endian) + * @param array the array to read from + * @param pos the offset + * @return the value + */ + public static final short readShortLittleEndian(byte[] array,int pos){ + short result = 0; + result += array[pos + 1]&0xff; + result <<= 8; + result += array[pos ]&0xff; + return result; + } + + /** + * Read an int value from the byte array at the given position + * (little Endian) + * @param array the array to read from + * @param pos the offset + * @return the value + */ + public static final int readIntLittleEndian(byte[] array,int pos){ + return ((array[pos + 3]&0xff) << 24) | + ((array[pos + 2]&0xff) << 16) | + ((array[pos + 1]&0xff) << 8) | + ((array[pos ]&0xff) ); + } + /** + * Read a long value from the byte array at the given position + * (little Endian) + * @param array the array to read from + * @param pos the offset + * @return the value + */ + public static final long readLongLittleEndian(byte[] array,int pos){ + int temp = 0; + temp |= array[pos+7]&0xff; + temp <<=8; + temp |= array[pos+6]&0xff; + temp <<=8; + temp |= array[pos+5]&0xff; + temp <<=8; + temp |= array[pos+4]&0xff; + temp <<=8; + temp |= array[pos+3]&0xff; + temp <<=8; + temp |= array[pos+2]&0xff; + temp <<=8; + temp |= array[pos+1]&0xff; + temp <<=8; + temp |= array[pos]; + return temp; + } + + + /** + * Write a short value into the byte array at the given position + * (Big endian) + * @param array the array + * @param pos the offset + * @param value the value to write + */ + public static final void writeShortBigEndian(byte[] array, int pos, + short value) + { + array[pos] = (byte) (value >>> 8); + array[pos + 1] = (byte) (value & 0xFF); + + } + + /** + * Write an int value into the byte array at the given position + * (Big endian) + * @param array the array + * @param pos the offset + * @param value the value to write + */ + public static final void writeIntBigEndian(byte[] array, int pos,int value) + { + array[pos ] = (byte)((value >>> 24) & 0xff); + array[pos+1] = (byte)((value >>> 16) & 0xff); + array[pos+2] = (byte)((value >>> 8) & 0xff); + array[pos+3] = (byte)((value ) & 0xff); + + } + + /** + * Write a long value into the byte array at the given position + * (Big endian) + * @param array the array + * @param pos the offset + * @param value the value to write + */ + public static final void writeLongBigEndian(byte[] array, int pos, long value) + { + array[pos] = (byte) (value >>>56); + array[pos+1] = (byte) (value >>>48); + array[pos+2] = (byte) (value >>>40); + array[pos+3] = (byte) (value >>>32); + array[pos+4] = (byte) (value >>>24); + array[pos+5] = (byte) (value >>>16); + array[pos+6] = (byte) (value >>>8); + array[pos+7] = (byte) (value &0xFF); + + } + + /** + * Write a short value into the byte array at the given position + * (little endian) + * @param array the array + * @param pos the offset + * @param value the value to write + */ + public static final void writeShortLittleEndian(byte[] array, int pos, + short value) + { + array[pos +1] = (byte) (value >>> 8); + array[pos ] = (byte) (value & 0xFF); + + } + + /** + * Increment a short value at the specified position by the + * specified amount (little endian). + */ + public static final void incShortLittleEndian(byte[] array, int pos, int dv) { + int c = ((array[pos]&0xff) + (dv&0xff)) >>> 8; + array[pos] += dv&0xff; + if ((c > 0) || ((dv&0xff00) != 0)) { + array[pos + 1] += ((dv >>> 8)&0xff) + c; + } + } + + /** + * Write an int value into the byte array at the given position + * (little endian) + * @param array the array + * @param pos the offset + * @param value the value to write + */ + public static final void writeIntLittleEndian(byte[] array, int pos,int value) + { + array[pos+3] = (byte) (value >>>24); + array[pos+2] = (byte) (value >>>16); + array[pos+1] = (byte) (value >>>8); + array[pos] = (byte) (value &0xFF); + + } + + /** + * Write a long value into the byte array at the given position + * (little endian) + * @param array the array + * @param pos the offset + * @param value the value to write + */ + public static final void writeLongLittleEndian(byte[] array, int pos, long value) + { + array[pos+7] = (byte) (value >>>56); + array[pos+6] = (byte) (value >>>48); + array[pos+5] = (byte) (value >>>40); + array[pos+4] = (byte) (value >>>32); + array[pos+3] = (byte) (value >>>24); + array[pos+2] = (byte) (value >>>16); + array[pos+1] = (byte) (value >>>8); + array[pos] = (byte) (value &0xFF); + + } +} diff --git a/src/com/innosystec/unrar/io/ReadOnlyAccessByteArray.java b/src/com/innosystec/unrar/io/ReadOnlyAccessByteArray.java new file mode 100644 index 0000000..36e1b82 --- /dev/null +++ b/src/com/innosystec/unrar/io/ReadOnlyAccessByteArray.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 30.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.io; + +import java.io.EOFException; +import java.io.IOException; + +/** + * A FileConnection like access to a byte array. + * (seek and read certain number of bytes) + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class ReadOnlyAccessByteArray implements IReadOnlyAccess{ + + private int positionInFile; + private byte[] file; + + /** + * Initialize with byte[ ] + * @param file the file given as byte array + */ + public ReadOnlyAccessByteArray(byte[] file){ + if(file == null){ + throw new NullPointerException("file must not be null!!"); + } + this.file = file; + this.positionInFile = 0; + } + + public long getPosition() throws IOException { + return positionInFile; + } + + public void setPosition(long pos) throws IOException { + if (pos < file.length && pos >= 0){ + this.positionInFile = (int)pos; + } + else{ + throw new EOFException(); + } + } + + /** Read a single byte of data. */ + public int read() throws IOException { + return file[positionInFile++]; + } + + /** + * Read up to count bytes to the specified buffer. + */ + public int read(byte[] buffer, int off, int count) throws IOException { + int read = Math.min(count, file.length-positionInFile); + System.arraycopy(file, positionInFile, buffer, off, read); + positionInFile += read; + return read; + } + + public int readFully(byte[] buffer, int count) throws IOException { + if(buffer == null ){ + throw new NullPointerException("buffer must not be null"); + } + if(count == 0){ + throw new IllegalArgumentException("cannot read 0 bytes ;-)"); + } + int read = Math.min(count, file.length-(int)positionInFile-1); + System.arraycopy(file, (int)positionInFile, buffer, 0, read ); + positionInFile+=read; + return read; + } + + public void close() throws IOException { + } +} diff --git a/src/com/innosystec/unrar/io/ReadOnlyAccessInputStream.java b/src/com/innosystec/unrar/io/ReadOnlyAccessInputStream.java new file mode 100644 index 0000000..77623e7 --- /dev/null +++ b/src/com/innosystec/unrar/io/ReadOnlyAccessInputStream.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 26.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression + * algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.io; + +import com.one.RandomAccessInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class ReadOnlyAccessInputStream extends InputStream +{ + private RandomAccessInputStream file; + private int curPos; + private final int startPos; + private final int endPos; + + public ReadOnlyAccessInputStream(RandomAccessInputStream file, int startPos, int endPos) throws IOException + { + super(); + this.file = file; + this.startPos = startPos; + curPos = startPos; + this.endPos = endPos; + file.setPosition(curPos); + } + + public int read() throws IOException + { + if(curPos == endPos) + { + return -1; + } + else + { + int b = file.read(); + curPos++; + return b; + } + } + + public int read(byte[] b, int off, int len) throws IOException + { + if(len == 0) + { + return 0; + } + if(curPos == endPos) + { + return -1; + } + int bytesRead = file.read(b, off, + (int) Math.min(len, endPos - curPos)); + curPos += bytesRead; + return bytesRead; + } + + public int read(byte[] b) throws IOException + { + return read(b, 0, b.length); + } +// +// public void close() throws IOException { +// file.close(); +// } +} diff --git a/src/com/innosystec/unrar/rarfile/AVHeader.java b/src/com/innosystec/unrar/rarfile/AVHeader.java new file mode 100644 index 0000000..f083f92 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/AVHeader.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +/** + * extended version info header + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class AVHeader extends BaseBlock { + + public static final int avHeaderSize = 7; + + private byte unpackVersion; + private byte method; + private byte avVersion; + private int avInfoCRC; + + public AVHeader(BaseBlock bb, byte[] avHeader){ + super(bb); + + int pos =0; + unpackVersion |= avHeader[pos]&0xff; + pos++; + method |= avHeader[pos]&0xff; + pos++; + avVersion |= avHeader[pos]&0xff; + pos++; + avInfoCRC = Raw.readIntLittleEndian(avHeader, pos); + } + + public int getAvInfoCRC() { + return avInfoCRC; + } + + public byte getAvVersion() { + return avVersion; + } + + public byte getMethod() { + return method; + } + + public byte getUnpackVersion() { + return unpackVersion; + } +} diff --git a/src/com/innosystec/unrar/rarfile/BaseBlock.java b/src/com/innosystec/unrar/rarfile/BaseBlock.java new file mode 100644 index 0000000..0b7cf36 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/BaseBlock.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 22.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +/** + * Base class of all rar headers + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class BaseBlock +{ + public static final short BaseBlockSize = 7; + //TODO move somewhere else + public static final short MHD_VOLUME = 0x0001; + public static final short MHD_COMMENT = 0x0002; + public static final short MHD_LOCK = 0x0004; + public static final short MHD_SOLID = 0x0008; + public static final short MHD_PACK_COMMENT = 0x0010; + public static final short MHD_NEWNUMBERING = 0x0010; + public static final short MHD_AV = 0x0020; + public static final short MHD_PROTECT = 0x0040; + public static final short MHD_PASSWORD = 0x0080; + public static final short MHD_FIRSTVOLUME = 0x0100; + public static final short MHD_ENCRYPTVER = 0x0200; + public static final short LHD_SPLIT_BEFORE = 0x0001; + public static final short LHD_SPLIT_AFTER = 0x0002; + public static final short LHD_PASSWORD = 0x0004; + public static final short LHD_COMMENT = 0x0008; + public static final short LHD_SOLID = 0x0010; + public static final short LHD_WINDOWMASK = 0x00e0; + public static final short LHD_WINDOW64 = 0x0000; + public static final short LHD_WINDOW128 = 0x0020; + public static final short LHD_WINDOW256 = 0x0040; + public static final short LHD_WINDOW512 = 0x0060; + public static final short LHD_WINDOW1024 = 0x0080; + public static final short LHD_WINDOW2048 = 0x00a0; + public static final short LHD_WINDOW4096 = 0x00c0; + public static final short LHD_DIRECTORY = 0x00e0; + public static final short LHD_LARGE = 0x0100; + public static final short LHD_UNICODE = 0x0200; + public static final short LHD_SALT = 0x0400; + public static final short LHD_VERSION = 0x0800; + public static final short LHD_EXTTIME = 0x1000; + public static final short LHD_EXTFLAGS = 0x2000; + public static final short SKIP_IF_UNKNOWN = 0x4000; + public static final short LONG_BLOCK = -0x8000; + public static final short EARC_NEXT_VOLUME = 0x0001; + public static final short EARC_DATACRC = 0x0002; + public static final short EARC_REVSPACE = 0x0004; + public static final short EARC_VOLNUMBER = 0x0008; + protected int positionInFile; + protected short headCRC = 0; + protected byte headerType = 0; + protected short flags = 0; + protected short headerSize = 0; + + /** + * + */ + public BaseBlock() + { + } + + public BaseBlock(BaseBlock bb) + { + this.flags = bb.getFlags(); + this.headCRC = bb.getHeadCRC(); + this.headerType = bb.getHeaderType(); + this.headerSize = bb.getHeaderSize(); + this.positionInFile = bb.getPositionInFile(); + } + + public BaseBlock(byte[] baseBlockHeader) + { + + int pos = 0; + this.headCRC = Raw.readShortLittleEndian(baseBlockHeader, pos); + pos += 2; + this.headerType |= baseBlockHeader[pos] & 0xff; + pos++; + this.flags = Raw.readShortLittleEndian(baseBlockHeader, pos); + pos += 2; + this.headerSize = Raw.readShortLittleEndian(baseBlockHeader, pos); + } + + public boolean hasArchiveDataCRC() + { + return (this.flags & EARC_DATACRC) != 0; + } + + public boolean hasVolumeNumber() + { + return (this.flags & EARC_VOLNUMBER) != 0; + } + + public boolean hasEncryptVersion() + { + return (flags & MHD_ENCRYPTVER) != 0; + } + + /** + * @return is it a sub block + */ + public boolean isSubBlock() + { + if(UnrarHeadertype.SubHeader == headerType) + { + return (true); + } + if(UnrarHeadertype.NewSubHeader == headerType && (flags & LHD_SOLID) != 0) + { + return (true); + } + return (false); + + } + + public int getPositionInFile() + { + return positionInFile; + } + + public short getFlags() + { + return flags; + } + + public short getHeadCRC() + { + return headCRC; + } + + public short getHeaderSize() + { + return headerSize; + } + + public byte getHeaderType() + { + return UnrarHeadertype.findType(headerType); + } + + public void setPositionInFile(int positionInFile) + { + this.positionInFile = positionInFile; + } + + public void print() + { + StringBuffer str = new StringBuffer(); + str.append("HeaderType: " + getHeaderType()); + str.append("\nHeadCRC: " + Integer.toHexString(getHeadCRC())); + str.append("\nFlags: " + Integer.toHexString(getFlags())); + str.append("\nHeaderSize: " + getHeaderSize()); + str.append("\nPosition in file: " + getPositionInFile()); + System.out.println(str.toString()); + } +} diff --git a/src/com/innosystec/unrar/rarfile/BlockHeader.java b/src/com/innosystec/unrar/rarfile/BlockHeader.java new file mode 100644 index 0000000..d1d7008 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/BlockHeader.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 22.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +/** + * Base class of headers that contain data + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class BlockHeader extends BaseBlock +{ + public static final short blockHeaderSize = 4; + private int dataSize; + private int packSize; + + public BlockHeader() + { + } + + public BlockHeader(BlockHeader bh) + { + super(bh); + this.packSize = bh.getDataSize(); + this.dataSize = packSize; + this.positionInFile = bh.getPositionInFile(); + } + + public BlockHeader(BaseBlock bb, byte[] blockHeader) + { + super(bb); + + this.packSize = Raw.readIntLittleEndian(blockHeader, 0); + this.dataSize = this.packSize; + } + + public int getDataSize() + { + return dataSize; + } + + public int getPackSize() + { + return packSize; + } + + public void print() + { + super.print(); + String s = "DataSize: " + getDataSize() + " packSize: " + getPackSize(); + System.out.println(s); + } +} diff --git a/src/com/innosystec/unrar/rarfile/CommentHeader.java b/src/com/innosystec/unrar/rarfile/CommentHeader.java new file mode 100644 index 0000000..6ce98b8 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/CommentHeader.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 23.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ + +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +/** + * Comment header + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class CommentHeader extends BaseBlock { + + public static final short commentHeaderSize = 6; + + private short unpSize; + private byte unpVersion; + private byte unpMethod; + private short commCRC; + + + public CommentHeader(BaseBlock bb, byte[] commentHeader){ + super(bb); + + int pos =0; + unpSize = Raw.readShortLittleEndian(commentHeader, pos); + pos += 2; + unpVersion |= commentHeader[pos]&0xff; + pos++; + + unpMethod |= commentHeader[pos]&0xff; + pos++; + commCRC =Raw.readShortLittleEndian(commentHeader, pos); + + } + + public short getCommCRC() { + return commCRC; + } + + public byte getUnpMethod() { + return unpMethod; + } + + public short getUnpSize() { + return unpSize; + } + + public byte getUnpVersion() { + return unpVersion; + } +} diff --git a/src/com/innosystec/unrar/rarfile/EAHeader.java b/src/com/innosystec/unrar/rarfile/EAHeader.java new file mode 100644 index 0000000..536b3e4 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/EAHeader.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 27.11.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +/** + * extended archive CRC header + * + */ +public class EAHeader +extends SubBlockHeader +{ + public static final short EAHeaderSize = 10; + + private int unpSize; + private byte unpVer; + private byte method; + private int EACRC; + + public EAHeader(SubBlockHeader sb, byte[] eahead) + { + super(sb); + int pos = 0; + unpSize = Raw.readIntLittleEndian(eahead, pos); + pos+=4; + unpVer |= eahead[pos]&0xff; + pos++; + method |= eahead[pos]&0xff; + pos++; + EACRC = Raw.readIntLittleEndian(eahead, pos); + } + + /** + * @return the eACRC + */ + public int getEACRC() { + return EACRC; + } + + /** + * @return the method + */ + public byte getMethod() { + return method; + } + + /** + * @return the unpSize + */ + public int getUnpSize() { + return unpSize; + } + + /** + * @return the unpVer + */ + public byte getUnpVer() { + return unpVer; + } + + public void print() + { + super.print(); + System.out.println("unpSize: "+unpSize); + System.out.println("unpVersion: " + unpVer); + System.out.println("method: "+method); + System.out.println("EACRC:" + EACRC); + } +} + diff --git a/src/com/innosystec/unrar/rarfile/EndArcHeader.java b/src/com/innosystec/unrar/rarfile/EndArcHeader.java new file mode 100644 index 0000000..5600cbb --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/EndArcHeader.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +/** + * + * the optional End header + * + */ +public class EndArcHeader extends BaseBlock{ + + private static final short EARC_NEXT_VOLUME = 0x0001; + private static final short EARC_DATACRC = 0x0002; + private static final short EARC_REVSPACE = 0x0004; + private static final short EARC_VOLNUMBER = 0x0008; + + private static final short endArcHeaderSize = 6; + public static final short endArcArchiveDataCrcSize = 4; + public static final short endArcVolumeNumberSize = 2; + + private int archiveDataCRC; + private short volumeNumber; + + + public EndArcHeader(BaseBlock bb, byte[] endArcHeader){ + super(bb); + + int pos = 0; + if(hasArchiveDataCRC()){ + archiveDataCRC =Raw.readIntLittleEndian(endArcHeader, pos); + pos+=4; + } + if(hasVolumeNumber()){ + volumeNumber = Raw.readShortLittleEndian(endArcHeader, pos); + } + } + + public int getArchiveDataCRC() { + return archiveDataCRC; + } + + public short getVolumeNumber() { + return volumeNumber; + } +} diff --git a/src/com/innosystec/unrar/rarfile/FileHeader.java b/src/com/innosystec/unrar/rarfile/FileHeader.java new file mode 100644 index 0000000..4149e61 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/FileHeader.java @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 22.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import java.util.Calendar; +import java.util.Date; + +import com.innosystec.unrar.io.Raw; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class FileHeader extends BlockHeader +{ + private static final byte SALT_SIZE = 8; + private static final byte NEWLHD_SIZE = 32; + private int unpSize; + private byte hostOS; + private int fileCRC; + private int fileTime; + private byte unpVersion; + private byte unpMethod; + private short nameSize; + private int highPackSize; + private int highUnpackSize; + private byte[] fileNameBytes; + private String fileName; + private String fileNameW; + private byte[] subData; + private byte[] salt = new byte[SALT_SIZE]; + private Date mTime; + private Date cTime; + private Date aTime; + private Date arcTime; + private int fullPackSize; + private int fullUnpackSize; + private int fileAttr; + private int subFlags; // same as fileAttr (in header) + private int recoverySectors = -1; + + public FileHeader(BlockHeader bh, byte[] fileHeader) + { + super(bh); + + int position = 0; + unpSize = Raw.readIntLittleEndian(fileHeader, position); + position += 4; + hostOS = HostSystem.findHostSystem(fileHeader[4]); + position++; + + fileCRC = Raw.readIntLittleEndian(fileHeader, position); + position += 4; + + fileTime = Raw.readIntLittleEndian(fileHeader, position); + position += 4; + + unpVersion |= fileHeader[13] & 0xff; + position++; + unpMethod |= fileHeader[14] & 0xff; + position++; + nameSize = Raw.readShortLittleEndian(fileHeader, position); + position += 2; + + fileAttr = Raw.readIntLittleEndian(fileHeader, position); + position += 4; + if(isLargeBlock()) + { + highPackSize = Raw.readIntLittleEndian(fileHeader, position); + position += 4; + + highUnpackSize = Raw.readIntLittleEndian(fileHeader, position); + position += 4; + } + else + { + highPackSize = 0; + highUnpackSize = 0; + if(unpSize == 0xffffffff) + { + + unpSize = 0xffffffff; + highUnpackSize = Integer.MAX_VALUE; + } + + } + fullPackSize |= highPackSize; + fullPackSize <<= 32; + fullPackSize |= getPackSize(); + + fullUnpackSize |= highUnpackSize; + fullUnpackSize <<= 32; + fullUnpackSize |= unpSize; + + nameSize = nameSize > 4 * 1024 ? 4 * 1024 : nameSize; + + fileNameBytes = new byte[nameSize]; + for(int i = 0; i < nameSize; i++) + { + fileNameBytes[i] = fileHeader[position]; + position++; + } + + if(isFileHeader()) + { + if(isUnicode()) + { + int length = 0; + fileName = ""; + fileNameW = ""; + while(length < fileNameBytes.length && fileNameBytes[length] != 0) + { + length++; + } + byte[] name = new byte[length]; + System.arraycopy(fileNameBytes, 0, name, 0, name.length); + fileName = new String(name); + if(length != nameSize) + { + length++; + fileNameW = FileNameDecoder.decode(fileNameBytes, length); + } + } + else + { + fileName = new String(fileNameBytes); + fileNameW = ""; + } + } + + if(UnrarHeadertype.NewSubHeader == (headerType)) + { + int datasize = headerSize - NEWLHD_SIZE - nameSize; + if(hasSalt()) + { + datasize -= SALT_SIZE; + } + if(datasize > 0) + { + subData = new byte[datasize]; + for(int i = 0; i < datasize; i++) + { + subData[i] = (fileHeader[position]); + position++; + } + } + + if(NewSubHeaderType.SUBHEAD_TYPE_RR.byteEquals(fileNameBytes)) + { + recoverySectors = subData[8] + (subData[9] << 8) + (subData[10] << 16) + (subData[11] << 24); + } + } + + + + if(hasSalt()) + { + for(int i = 0; i < SALT_SIZE; i++) + { + salt[i] = fileHeader[position]; + position++; + } + } + mTime = getDateDos(fileTime); + //TODO rartime -> extended + + + } + + public void print() + { + super.print(); + StringBuffer str = new StringBuffer(); + str.append("unpSize: " + getUnpSize()); + str.append("\nHostOS: " + HostSystem.names[hostOS]); + str.append("\nMDate: " + mTime); + str.append("\nFileName: " + getFileNameString()); + str.append("\nunpMethod: " + Integer.toHexString(getUnpMethod())); + str.append("\nunpVersion: " + Integer.toHexString(getUnpVersion())); + str.append("\nfullpackedsize: " + getFullPackSize()); + str.append("\nfullunpackedsize: " + getFullUnpackSize()); + str.append("\nisEncrypted: " + isEncrypted()); + str.append("\nisfileHeader: " + isFileHeader()); + str.append("\nisSolid: " + isSolid()); + str.append("\nisSplitafter: " + isSplitAfter()); + str.append("\nisSplitBefore:" + isSplitBefore()); + str.append("\nunpSize: " + getUnpSize()); + str.append("\ndataSize: " + getDataSize()); + str.append("\nisUnicode: " + isUnicode()); + str.append("\nhasVolumeNumber: " + hasVolumeNumber()); + str.append("\nhasArchiveDataCRC: " + hasArchiveDataCRC()); + str.append("\nhasSalt: " + hasSalt()); + str.append("\nhasEncryptVersions: " + hasEncryptVersion()); + str.append("\nisSubBlock: " + isSubBlock()); + System.out.println(str.toString()); + } + + private Date getDateDos(int time) + { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, (time >>> 25) + 1980); + cal.set(Calendar.MONTH, ((time >>> 21) & 0x0f) - 1); + cal.set(Calendar.DAY_OF_MONTH, (time >>> 16) & 0x1f); + cal.set(Calendar.HOUR_OF_DAY, (time >>> 11) & 0x1f); + cal.set(Calendar.MINUTE, (time >>> 5) & 0x3f); + cal.set(Calendar.SECOND, (time & 0x1f) * 2); + return cal.getTime(); + } + + public Date getArcTime() + { + return arcTime; + } + + public void setArcTime(Date arcTime) + { + this.arcTime = arcTime; + } + + public Date getATime() + { + return aTime; + } + + public void setATime(Date time) + { + aTime = time; + } + + public Date getCTime() + { + return cTime; + } + + public void setCTime(Date time) + { + cTime = time; + } + + public int getFileAttr() + { + return fileAttr; + } + + public void setFileAttr(int fileAttr) + { + this.fileAttr = fileAttr; + } + + public int getFileCRC() + { + return fileCRC; + } + + public byte[] getFileNameByteArray() + { + return fileNameBytes; + } + + public String getFileNameString() + { + return fileName; + } + + public void setFileName(String fileName) + { + this.fileName = fileName; + } + + public String getFileNameW() + { + return fileNameW; + } + + public void setFileNameW(String fileNameW) + { + this.fileNameW = fileNameW; + } + + public int getHighPackSize() + { + return highPackSize; + } + + public int getHighUnpackSize() + { + return highUnpackSize; + } + + public byte getHostOS() + { + return hostOS; + } + + public Date getMTime() + { + return mTime; + } + + public void setMTime(Date time) + { + mTime = time; + } + + public short getNameSize() + { + return nameSize; + } + + public int getRecoverySectors() + { + return recoverySectors; + } + + public byte[] getSalt() + { + return salt; + } + + public byte[] getSubData() + { + return subData; + } + + public int getSubFlags() + { + return subFlags; + } + + public byte getUnpMethod() + { + return unpMethod; + } + + public int getUnpSize() + { + return unpSize; + } + + public byte getUnpVersion() + { + return unpVersion; + } + + public int getFullPackSize() + { + return fullPackSize; + } + + public int getFullUnpackSize() + { + return fullUnpackSize; + } + + public String toString() + { + return super.toString(); + } + + /** + * the file will be continued in the next archive part + * @return + */ + public boolean isSplitAfter() + { + return (this.flags & BlockHeader.LHD_SPLIT_AFTER) != 0; + } + + /** + * the file is continued in this archive + * @return + */ + public boolean isSplitBefore() + { + return (this.flags & LHD_SPLIT_BEFORE) != 0; + } + + /** + * this file is compressed as solid (all files handeled as one) + * @return + */ + public boolean isSolid() + { + return (this.flags & LHD_SOLID) != 0; + } + + /** + * the file is encrypted + * @return + */ + public boolean isEncrypted() + { + return (this.flags & BlockHeader.LHD_PASSWORD) != 0; + } + + /** + * the filename is also present in unicode + * @return + */ + public boolean isUnicode() + { + return (flags & LHD_UNICODE) != 0; + } + + public boolean isFileHeader() + { + return UnrarHeadertype.FileHeader == (headerType); + } + + public boolean hasSalt() + { + return (flags & LHD_SALT) != 0; + } + + public boolean isLargeBlock() + { + return (flags & LHD_LARGE) != 0; + } + + /** + * whether this fileheader represents a directory + * @return + */ + public boolean isDirectory() + { + return (flags & LHD_WINDOWMASK) == LHD_DIRECTORY; + } +} diff --git a/src/com/innosystec/unrar/rarfile/FileNameDecoder.java b/src/com/innosystec/unrar/rarfile/FileNameDecoder.java new file mode 100644 index 0000000..e507d9c --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/FileNameDecoder.java @@ -0,0 +1,87 @@ +/* + * + * Original author: alpha_lam + * Creation date: ? + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +public class FileNameDecoder +{ + public static int getChar(byte[] name, int pos) + { + return name[pos] & 0xff; + } + + public static String decode(byte[] name, int encPos) + { + int decPos = 0; + int flags = 0; + int flagBits = 0; + + int low = 0; + int high = 0; + int highByte = getChar(name, encPos++); + StringBuffer buf = new StringBuffer(); + while(encPos < name.length) + { + if(flagBits == 0) + { + flags = getChar(name, encPos++); + flagBits = 8; + } + switch(flags >> 6) + { + case 0: + buf.append((char) (getChar(name, encPos++))); + ++decPos; + break; + case 1: + buf.append((char) (getChar(name, encPos++) + (highByte << 8))); + ++decPos; + break; + case 2: + low = getChar(name, encPos); + high = getChar(name, encPos + 1); + buf.append((char) ((high << 8) + low)); + ++decPos; + encPos += 2; + break; + case 3: + int length = getChar(name, encPos++); + if((length & 0x80) != 0) + { + int correction = getChar(name, encPos++); + for(length = (length & 0x7f) + 2; length > 0 && decPos < name.length; length--, decPos++) + { + low = (getChar(name, decPos) + correction) & 0xff; + buf.append((char) ((highByte << 8) + low)); + } + } + else + { + for(length += 2; length > 0 && decPos < name.length; length--, decPos++) + { + buf.append((char) (getChar(name, decPos))); + } + } + break; + } + flags = (flags << 2) & 0xff; + flagBits -= 2; + } + return buf.toString(); + } +} diff --git a/src/com/innosystec/unrar/rarfile/HostSystem.java b/src/com/innosystec/unrar/rarfile/HostSystem.java new file mode 100644 index 0000000..08ba82c --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/HostSystem.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 22.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class HostSystem +{ + public static final byte msdos = ((byte) 0), + os2 = ((byte) 1), + win32 = ((byte) 2), + unix = ((byte) 3), + macos = ((byte) 4), + beos = ((byte) 5); + + public static final String[] names = + { + "msdos", + "os2", + "win32", + "unix", + "macos", + "beos" + }; + + private byte hostByte; + + public static byte findHostSystem(byte hostByte) + { + return hostByte; + } + + private HostSystem(byte hostByte) + { + this.hostByte = hostByte; + } + + public boolean equals(byte hostByte) + { + return this.hostByte == hostByte; + } + + public byte getHostByte() + { + return hostByte; + } + //???? public static final byte max = 6; +} diff --git a/src/com/innosystec/unrar/rarfile/MacInfoHeader.java b/src/com/innosystec/unrar/rarfile/MacInfoHeader.java new file mode 100644 index 0000000..ea333f2 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/MacInfoHeader.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 26.11.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +/** + * Mac FileConnection attribute header + * + */ +public class MacInfoHeader +extends SubBlockHeader +{ + public static final short MacInfoHeaderSize = 8; + + private int fileType; + private int fileCreator; + + public MacInfoHeader(SubBlockHeader sb, byte[] macHeader) + { + super(sb); + int pos = 0; + fileType = Raw.readIntLittleEndian(macHeader, pos); + pos+=4; + fileCreator = Raw.readIntLittleEndian(macHeader, pos); + } + + /** + * @return the fileCreator + */ + public int getFileCreator() { + return fileCreator; + } + + /** + * @param fileCreator the fileCreator to set + */ + public void setFileCreator(int fileCreator) { + this.fileCreator = fileCreator; + } + + /** + * @return the fileType + */ + public int getFileType() { + return fileType; + } + + /** + * @param fileType the fileType to set + */ + public void setFileType(int fileType) { + this.fileType = fileType; + } + + public void print(){ + super.print(); + System.out.println("filetype: "+fileType); + System.out.println("creator :"+fileCreator); + } + +} diff --git a/src/com/innosystec/unrar/rarfile/MainHeader.java b/src/com/innosystec/unrar/rarfile/MainHeader.java new file mode 100644 index 0000000..e3bb8ae --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/MainHeader.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 22.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +/** + * The main header of an rar archive. holds information concerning the whole archive (solid, encrypted etc). + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class MainHeader extends BaseBlock +{ + public static final short mainHeaderSizeWithEnc = 7; + public static final short mainHeaderSize = 6; + private short highPosAv; + private int posAv; + private byte encryptVersion; + + public MainHeader(BaseBlock bb, byte[] mainHeader) + { + super(bb); + int pos = 0; + highPosAv = Raw.readShortLittleEndian(mainHeader, pos); + pos += 2; + posAv = Raw.readIntLittleEndian(mainHeader, pos); + pos += 4; + + if(hasEncryptVersion()) + { + encryptVersion |= mainHeader[pos] & 0xff; + } + } + + /** + * old cmt block is present + * @return true if has cmt block + */ + public boolean hasArchCmt() + { + return (this.flags & BaseBlock.MHD_COMMENT) != 0; + } + + /** + * the version the the encryption + * @return + */ + public byte getEncryptVersion() + { + return encryptVersion; + } + + public short getHighPosAv() + { + return highPosAv; + } + + public int getPosAv() + { + return posAv; + } + + /** + * returns whether the archive is encrypted + * @return + */ + public boolean isEncrypted() + { + return (this.flags & BaseBlock.MHD_PASSWORD) != 0; + } + + /** + * return whether the archive is a multivolume archive + * @return + */ + public boolean isMultiVolume() + { + return (this.flags & BaseBlock.MHD_VOLUME) != 0; + } + + /** + * if the archive is a multivolume archive this method returns whether this instance is the first part of the multivolume archive + * @return + */ + public boolean isFirstVolume() + { + return (this.flags & BaseBlock.MHD_FIRSTVOLUME) != 0; + } + + public void print() + { + super.print(); + StringBuffer str = new StringBuffer(); + str.append("posav: " + getPosAv()); + str.append("\nhighposav: " + getHighPosAv()); + str.append("\nhasencversion: " + hasEncryptVersion() + (hasEncryptVersion() ? String.valueOf(getEncryptVersion()) : "")); + str.append("\nhasarchcmt: " + hasArchCmt()); + str.append("\nisEncrypted: " + isEncrypted()); + str.append("\nisMultivolume: " + isMultiVolume()); + str.append("\nisFirstvolume: " + isFirstVolume()); + str.append("\nisSolid: " + isSolid()); + str.append("\nisLocked: " + isLocked()); + str.append("\nisProtected: " + isProtected()); + str.append("\nisAV: " + isAV()); + System.out.println(str.toString()); + } + + /** + * returns whether this archive is solid. in this case you can only extract all file at once + * @return + */ + public boolean isSolid() + { + return (this.flags & MHD_SOLID) != 0; + } + + public boolean isLocked() + { + return (this.flags & MHD_LOCK) != 0; + } + + public boolean isProtected() + { + return (this.flags & MHD_PROTECT) != 0; + } + + public boolean isAV() + { + return (this.flags & MHD_AV) != 0; + } + + /** + * the numbering format a multivolume archive + * @return + */ + public boolean isNewNumbering() + { + return (this.flags & MHD_NEWNUMBERING) != 0; + } +} diff --git a/src/com/innosystec/unrar/rarfile/MarkHeader.java b/src/com/innosystec/unrar/rarfile/MarkHeader.java new file mode 100644 index 0000000..2f76af5 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/MarkHeader.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +/** + * the header to recognize a file to be a rar archive + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class MarkHeader extends BaseBlock { + + private boolean oldFormat = false; + + public MarkHeader(BaseBlock bb){ + super(bb); + } + public boolean isValid(){ + if(!(getHeadCRC() == 0x6152)){ + return false; + } + if(!(getHeaderType() == UnrarHeadertype.MarkHeader)){ + return false; + } + if(!(getFlags() == 0x1a21)){ + return false; + } + if(!(getHeaderSize() == BaseBlockSize)){ + return false; + } + return true; + } + + public boolean isSignature() { + boolean valid=false; + byte[] d = new byte[BaseBlock.BaseBlockSize]; + Raw.writeShortLittleEndian(d, 0, headCRC); + d[2] = headerType; + Raw.writeShortLittleEndian(d, 3, flags); + Raw.writeShortLittleEndian(d, 5, headerSize); + + if (d[0] == 0x52) { + if (d[1]==0x45 && d[2]==0x7e && d[3]==0x5e) { + oldFormat=true; + valid=true; + } + else if (d[1]==0x61 && d[2]==0x72 && d[3]==0x21 && d[4]==0x1a && + d[5]==0x07 && d[6]==0x00) { + oldFormat=false; + valid=true; + } + } + return valid; + } + + public boolean isOldFormat() { + return oldFormat; + } + + public void print(){ + super.print(); + System.out.println("valid: "+isValid()); + } +} diff --git a/src/com/innosystec/unrar/rarfile/NewSubHeaderType.java b/src/com/innosystec/unrar/rarfile/NewSubHeaderType.java new file mode 100644 index 0000000..2ada235 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/NewSubHeaderType.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.classpath.util.Arrays; + +/** + * subheaders new version of the info headers + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class NewSubHeaderType { + + /** + * comment subheader + */ + public static final NewSubHeaderType SUBHEAD_TYPE_CMT = new NewSubHeaderType(new byte[]{'C','M','T'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_ACL = new NewSubHeaderType(new byte[]{'A','C','L'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_STREAM = new NewSubHeaderType(new byte[]{'S','T','M'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_UOWNER = new NewSubHeaderType(new byte[]{'U','O','W'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_AV = new NewSubHeaderType(new byte[]{'A','V'}); + /** + * recovery record subheader + */ + public static final NewSubHeaderType SUBHEAD_TYPE_RR = new NewSubHeaderType(new byte[]{'R','R'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_OS2EA = new NewSubHeaderType(new byte[]{'E','A','2'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_BEOSEA = new NewSubHeaderType(new byte[]{'E','A','B','E'}); + + private byte[] headerTypes; + + /** + * Private constructor + * @param headerTypes + */ + private NewSubHeaderType(byte[] headerTypes) + { + this.headerTypes = headerTypes; + } + + /** + * @param toCompare + * @return Returns true if the given byte array matches to the internal byte array of this header. + */ + public boolean byteEquals(byte[] toCompare) + { + return Arrays.equals(this.headerTypes, toCompare); + +// if(this.headerTypes == null || toCompare == null || +// this.headerTypes.length != toCompare.length) +// { +// return false; +// } +// +// for(int i = 0; i < this.headerTypes.length; i++) +// { +// if(this.headerTypes[i] != toCompare[i]) +// { +// return false; +// } +// } +// +// return true; + } + + public String toString() + { + return new String(this.headerTypes); + } +} diff --git a/src/com/innosystec/unrar/rarfile/ProtectHeader.java b/src/com/innosystec/unrar/rarfile/ProtectHeader.java new file mode 100644 index 0000000..f765522 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/ProtectHeader.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +/** + * recovery header + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class ProtectHeader extends BlockHeader { + + /** + * the header size + */ + public static final int protectHeaderSize = 8; + + private byte version; + private short recSectors; + private int totalBlocks; + private byte mark; + + + public ProtectHeader(BlockHeader bh, byte[] protectHeader){ + super(bh); + + int pos = 0; + version |= protectHeader[pos]&0xff; + + recSectors = Raw.readShortLittleEndian(protectHeader, pos); + pos += 2; + totalBlocks = Raw.readIntLittleEndian(protectHeader, pos); + pos += 4; + mark |= protectHeader[pos]&0xff; + } + + + public byte getMark() { + return mark; + } + + public short getRecSectors() { + return recSectors; + } + + public int getTotalBlocks() { + return totalBlocks; + } + + public byte getVersion() { + return version; + } +} diff --git a/src/com/innosystec/unrar/rarfile/SignHeader.java b/src/com/innosystec/unrar/rarfile/SignHeader.java new file mode 100644 index 0000000..13ad0c3 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/SignHeader.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +/** + * sign header + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class SignHeader extends BaseBlock { + + public static final short signHeaderSize = 8; + + private int creationTime=0; + private short arcNameSize=0; + private short userNameSize=0; + + + public SignHeader(BaseBlock bb, byte[] signHeader){ + super(bb); + + int pos = 0; + creationTime = Raw.readIntLittleEndian(signHeader, pos); + pos +=4; + arcNameSize = Raw.readShortLittleEndian(signHeader, pos); + pos+=2; + userNameSize = Raw.readShortLittleEndian(signHeader, pos); + } + + public short getArcNameSize() { + return arcNameSize; + } + + public int getCreationTime() { + return creationTime; + } + + public short getUserNameSize() { + return userNameSize; + } +} diff --git a/src/com/innosystec/unrar/rarfile/SubBlockHeader.java b/src/com/innosystec/unrar/rarfile/SubBlockHeader.java new file mode 100644 index 0000000..362c6cf --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/SubBlockHeader.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 21.11.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +public class SubBlockHeader +extends BlockHeader +{ + public static final short SubBlockHeaderSize = 3; + + private short subType; + private byte level; + + public SubBlockHeader(SubBlockHeader sb) + { + super(sb); + subType = sb.getSubType(); + level = sb.getLevel(); + } + + public SubBlockHeader(BlockHeader bh, byte[] subblock) + { + super(bh); + int position = 0; + subType = Raw.readShortLittleEndian(subblock, position); + position +=2; + level |= subblock[position]&0xff; + } + + /** + * @return + */ + public byte getLevel() { + return level; + } + + /** + * @return + */ + public short getSubType() { + return SubBlockHeaderType.findSubblockHeaderType(subType); + } + + public void print() + { + super.print(); + System.out.println("subtype: "+getSubType()); + System.out.println("level: "+level); + } +} diff --git a/src/com/innosystec/unrar/rarfile/SubBlockHeaderType.java b/src/com/innosystec/unrar/rarfile/SubBlockHeaderType.java new file mode 100644 index 0000000..0c49cef --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/SubBlockHeaderType.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 20.11.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +public class SubBlockHeaderType +{ + public static final short EA_HEAD = ((short) 0x100), + UO_HEAD = ((short) 0x101), + MAC_HEAD = ((short) 0x102), + BEEA_HEAD = ((short) 0x103), + NTACL_HEAD = ((short) 0x104), + STREAM_HEAD = ((short) 0x105); + private short subblocktype; + + private SubBlockHeaderType(short subblocktype) + { + this.subblocktype = subblocktype; + } + + /** + * Return true if the given value is equal to the enum's value + * @param subblocktype + * @return true if the given value is equal to the enum's value + */ + public boolean equals(short subblocktype) + { + return this.subblocktype == subblocktype; + } + + /** + * find the header type for the given short value + * @param SubType the short value + * @return the correspo nding enum or null + */ + public static short findSubblockHeaderType(short subType) + { + return subType; + } + + /** + * @return the short representation of this enum + */ + public short getSubblocktype() + { + return subblocktype; + } +} diff --git a/src/com/innosystec/unrar/rarfile/UnixOwnersHeader.java b/src/com/innosystec/unrar/rarfile/UnixOwnersHeader.java new file mode 100644 index 0000000..680df46 --- /dev/null +++ b/src/com/innosystec/unrar/rarfile/UnixOwnersHeader.java @@ -0,0 +1,91 @@ +package com.innosystec.unrar.rarfile; + +import com.innosystec.unrar.io.Raw; + +public class UnixOwnersHeader +extends SubBlockHeader +{ + private int ownerNameSize; + private int groupNameSize; + private String owner; + private String group; + + public UnixOwnersHeader(SubBlockHeader sb, byte[] uoHeader) { + super(sb); + int pos = 0; + ownerNameSize = Raw.readShortLittleEndian(uoHeader, pos)&0xFFFF; + pos+=2; + groupNameSize = Raw.readShortLittleEndian(uoHeader, pos)&0xFFFF; + pos+=2; + if(pos+ownerNameSize": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.rarfile; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class UnrarHeadertype +{ + public static final byte + /** + * + */ + MainHeader = ((byte) 0x73), + /** + * + */ + MarkHeader = ((byte) 0x72), + /** + * + */ + FileHeader = ((byte) 0x74), + /** + * + */ + CommHeader = ((byte) 0x75), + /** + * + */ + AvHeader = ((byte) 0x76), + /** + * + */ + SubHeader = ((byte) 0x77), + /** + * + */ + ProtectHeader = ((byte) 0x78), + /** + * + */ + SignHeader = ((byte) 0x79), + /** + * + */ + NewSubHeader = ((byte) 0x7a), + /** + * + */ + EndArcHeader = ((byte) 0x7b); + + /** + * Returns the enum according to the given byte or null + * @param headerType the headerbyte + * @return the enum or null + */ + public static byte findType(byte headerType) + { + return headerType; + } + + private byte headerByte; + + private UnrarHeadertype(byte headerByte) + { + this.headerByte = headerByte; + } + + /** + * Return true if the given byte is equal to the enum's byte + * @param header + * @return true if the given byte is equal to the enum's byte + */ + public boolean equals(byte header) + { + return headerByte == header; + } + + /** + * the header byte of this enum + * @return the header byte of this enum + */ + public byte getHeaderByte() + { + return headerByte; + } +} diff --git a/src/com/innosystec/unrar/unpack/ComprDataIO.java b/src/com/innosystec/unrar/unpack/ComprDataIO.java new file mode 100644 index 0000000..6355a99 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ComprDataIO.java @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack; + +import com.innosystec.unrar.Archive; +import com.innosystec.unrar.Volume; +import com.innosystec.unrar.crc.RarCRC; +import com.innosystec.unrar.exception.RarException; +import com.innosystec.unrar.io.ReadOnlyAccessInputStream; +import com.innosystec.unrar.rarfile.FileHeader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class ComprDataIO +{ + private final Archive archive; + private int unpPackedSize; + private boolean testMode; + private boolean skipUnpCRC; + private InputStream inputStream; + private OutputStream outputStream; + private FileHeader subHead; + // cryptData Crypt; + // cryptData Decrypt; + private boolean packVolume; + private boolean unpVolume; + private boolean nextVolumeMissing; + private int totalPackRead; + private int unpArcSize; + private int curPackRead, curPackWrite, curUnpRead, curUnpWrite; + private int processedArcSize, totalArcSize; + private long packFileCRC, unpFileCRC, packedCRC; + private int encryption; + private int decryption; + private int lastPercent; + private char currentCommand; + + public ComprDataIO(Archive arc) + { + this.archive = arc; + } + + public void init(OutputStream outputStream) + { + this.outputStream = outputStream; + unpPackedSize = 0; + testMode = false; + skipUnpCRC = false; + packVolume = false; + unpVolume = false; + nextVolumeMissing = false; + // command = null; + encryption = 0; + decryption = 0; + totalPackRead = 0; + curPackRead = curPackWrite = curUnpRead = curUnpWrite = 0; + packFileCRC = unpFileCRC = packedCRC = 0xffffffff; + lastPercent = -1; + subHead = null; + + currentCommand = 0; + processedArcSize = totalArcSize = 0; + } + + public void init(FileHeader hd) throws IOException + { + int startPos = hd.getPositionInFile() + hd.getHeaderSize(); + unpPackedSize = hd.getFullPackSize(); + inputStream = new ReadOnlyAccessInputStream(archive.getRof(), startPos, startPos + unpPackedSize); + subHead = hd; + curUnpRead = 0; + curPackWrite = 0; + packedCRC = 0xFFffFFff; + } + + public int unpRead(byte[] addr, int offset, int count) + throws IOException, RarException + { + int retCode = 0, totalRead = 0; + while(count > 0) + { + int readSize = (count > unpPackedSize) ? (int) unpPackedSize : count; + retCode = inputStream.read(addr, offset, readSize); + if(retCode < 0) + { + throw new EOFException(); + } + if(subHead.isSplitAfter()) + { + packedCRC = RarCRC.checkCrc( + (int) packedCRC, addr, offset, retCode); + } + + curUnpRead += retCode; + totalRead += retCode; + offset += retCode; + count -= retCode; + unpPackedSize -= retCode; + archive.bytesReadRead(retCode); + if(unpPackedSize == 0 && subHead.isSplitAfter()) + { + if(!Volume.mergeArchive(archive, this)) + { + nextVolumeMissing = true; + return -1; + } + } + else + { + break; + } + } + + if(retCode != -1) + { + retCode = totalRead; + } + return retCode; + + + } + + public void unpWrite(byte[] addr, int offset, int count) + throws IOException + { + if(!testMode) + { + // DestFile->Write(Addr,Count); + outputStream.write(addr, offset, count); + } + + curUnpWrite += count; + + if(!skipUnpCRC) + { + if(archive.isOldFormat()) + { + unpFileCRC = RarCRC.checkOldCrc( + (short) unpFileCRC, addr, count); + } + else + { + unpFileCRC = RarCRC.checkCrc( + (int) unpFileCRC, addr, offset, count); + } + } +// if (!skipArcCRC) { +// archive.updateDataCRC(Addr, offset, ReadSize); +// } + } + + public void setPackedSizeToRead(int size) + { + unpPackedSize = size; + } + + public void setTestMode(boolean mode) + { + testMode = mode; + } + + public void setSkipUnpCRC(boolean skip) + { + skipUnpCRC = skip; + } + + public void setSubHeader(FileHeader hd) + { + subHead = hd; + + } + + public int getCurPackRead() + { + return curPackRead; + } + + public void setCurPackRead(int curPackRead) + { + this.curPackRead = curPackRead; + } + + public int getCurPackWrite() + { + return curPackWrite; + } + + public void setCurPackWrite(int curPackWrite) + { + this.curPackWrite = curPackWrite; + } + + public int getCurUnpRead() + { + return curUnpRead; + } + + public void setCurUnpRead(int curUnpRead) + { + this.curUnpRead = curUnpRead; + } + + public int getCurUnpWrite() + { + return curUnpWrite; + } + + public void setCurUnpWrite(int curUnpWrite) + { + this.curUnpWrite = curUnpWrite; + } + + public int getDecryption() + { + return decryption; + } + + public void setDecryption(int decryption) + { + this.decryption = decryption; + } + + public int getEncryption() + { + return encryption; + } + + public void setEncryption(int encryption) + { + this.encryption = encryption; + } + + public boolean isNextVolumeMissing() + { + return nextVolumeMissing; + } + + public void setNextVolumeMissing(boolean nextVolumeMissing) + { + this.nextVolumeMissing = nextVolumeMissing; + } + + public long getPackedCRC() + { + return packedCRC; + } + + public void setPackedCRC(long packedCRC) + { + this.packedCRC = packedCRC; + } + + public long getPackFileCRC() + { + return packFileCRC; + } + + public void setPackFileCRC(long packFileCRC) + { + this.packFileCRC = packFileCRC; + } + + public boolean isPackVolume() + { + return packVolume; + } + + public void setPackVolume(boolean packVolume) + { + this.packVolume = packVolume; + } + + public int getProcessedArcSize() + { + return processedArcSize; + } + + public void setProcessedArcSize(int processedArcSize) + { + this.processedArcSize = processedArcSize; + } + + public int getTotalArcSize() + { + return totalArcSize; + } + + public void setTotalArcSize(int totalArcSize) + { + this.totalArcSize = totalArcSize; + } + + public int getTotalPackRead() + { + return totalPackRead; + } + + public void setTotalPackRead(int totalPackRead) + { + this.totalPackRead = totalPackRead; + } + + public int getUnpArcSize() + { + return unpArcSize; + } + + public void setUnpArcSize(int unpArcSize) + { + this.unpArcSize = unpArcSize; + } + + public long getUnpFileCRC() + { + return unpFileCRC; + } + + public void setUnpFileCRC(long unpFileCRC) + { + this.unpFileCRC = unpFileCRC; + } + + public boolean isUnpVolume() + { + return unpVolume; + } + + public void setUnpVolume(boolean unpVolume) + { + this.unpVolume = unpVolume; + } + + public FileHeader getSubHeader() + { + return subHead; + } +// public void setEncryption(int method, char[] Password, byte[] Salt, +// boolean encrypt, boolean handsOffHash) +// { +// +// } +// +// public void setAV15Encryption() +// { +// +// } +// +// public void setCmt13Encryption() +// { +// +// } +} diff --git a/src/com/innosystec/unrar/unpack/Unpack.java b/src/com/innosystec/unrar/unpack/Unpack.java new file mode 100644 index 0000000..abebdde --- /dev/null +++ b/src/com/innosystec/unrar/unpack/Unpack.java @@ -0,0 +1,1235 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack; + +import com.classpath.util.Arrays; +import com.classpath.util.ByteCache; +import java.io.IOException; +import java.util.Vector; + +import com.innosystec.unrar.exception.RarException; +import com.innosystec.unrar.unpack.decode.Compress; +import com.innosystec.unrar.unpack.ppm.BlockTypes; +import com.innosystec.unrar.unpack.ppm.ModelPPM; +import com.innosystec.unrar.unpack.ppm.SubAllocator; +import com.innosystec.unrar.unpack.vm.BitInput; +import com.innosystec.unrar.unpack.vm.RarVM; +import com.innosystec.unrar.unpack.vm.VMPreparedProgram; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public final class Unpack extends Unpack20 +{ + public static int BUFSIZE = 0x10000; + + private final ModelPPM ppm = new ModelPPM(); + private int ppmEscChar; + private RarVM rarVM = new RarVM(); + + /* Filters code, one entry per filter */ + private Vector filters = new Vector(); + + /* Filters stack, several entrances of same filter are possible */ + private Vector prgStack = new Vector(); + + /* + * lengths of preceding blocks, one length per filter. Used to reduce size + * required to write block length if lengths are repeating + */ + private Vector oldFilterLengths = new Vector(); + private int lastFilter; + private boolean tablesRead; + private byte[] unpOldTable = new byte[Compress.HUFF_TABLE_SIZE]; + private int unpBlockType; + private boolean externalWindow; + private long writtenFileSize; + private boolean fileExtracted; + private boolean ppmError; + private int prevLowDist; + private int lowDistRepCount; + public static int[] DBitLengthCounts = + { + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 14, 0, 12 + }; + + public Unpack(ComprDataIO DataIO) + { + unpIO = DataIO; + window = null; + externalWindow = false; + suspended = false; + unpAllBuf = false; + unpSomeRead = false; + } + + public void init(byte[] window) + { + if(window == null) + { + this.window = new byte[Compress.MAXWINSIZE]; + } + else + { + this.window = window; + externalWindow = true; + } + inAddr = 0; + unpInitData(false); + } + + public void doUnpack(int method, boolean solid) throws IOException, RarException + { + if(unpIO.getSubHeader().getUnpMethod() == 0x30) + { + unstoreFile(); + } + switch(method) + { + case 15: // rar 1.5 compression + unpack15(solid); + break; + case 20: // rar 2.x compression + case 26: // files larger than 2GB + unpack20(solid); + break; + case 29: // rar 3.x compression + case 36: // alternative hash + unpack29(solid); + break; + } + } + + private void unstoreFile() throws IOException, RarException + { + byte[] buffer = null; + + buffer = new byte[BUFSIZE]; + + while(true) + { + int code = unpIO.unpRead(buffer, 0, (int) Math.min(buffer.length, destUnpSize)); + if(code == 0 || code == -1) + { + break; + } + code = code < destUnpSize ? code : (int) destUnpSize; + unpIO.unpWrite(buffer, 0, code); + if(destUnpSize >= 0) + { + destUnpSize -= code; + } + } + + } + + private void unpack29(boolean solid) throws IOException, RarException + { + + int[] DDecode = new int[Compress.DC]; + byte[] DBits = new byte[Compress.DC]; + + int Bits; + + if(DDecode[1] == 0) + { + int Dist = 0, BitLength = 0, Slot = 0; + for(int I = 0; I < DBitLengthCounts.length; I++, BitLength++) + { + int count = DBitLengthCounts[I]; + for(int J = 0; J < count; J++, Slot++, Dist += (1 << BitLength)) + { + DDecode[Slot] = Dist; + DBits[Slot] = (byte) BitLength; + } + } + } + + fileExtracted = true; + + if(!suspended) + { + unpInitData(solid); + if(!unpReadBuf()) + { + return; + } + if((!solid || !tablesRead) && !readTables()) + { + return; + } + } + + if(ppmError) + { + return; + } + + while(true) + { + unpPtr &= Compress.MAXWINMASK; + + if(inAddr > readBorder) + { + if(!unpReadBuf()) + { + break; + } + } + //System.out.println(((wrPtr - unpPtr) & Compress.MAXWINMASK)+":"+wrPtr+":"+unpPtr); + if(((wrPtr - unpPtr) & Compress.MAXWINMASK) < 260 + && wrPtr != unpPtr) + { + + UnpWriteBuf(); + if(writtenFileSize > destUnpSize) + { + return; + } + if(suspended) + { + fileExtracted = false; + return; + } + } + if(unpBlockType == BlockTypes.BLOCK_PPM) + { + int Ch = ppm.decodeChar(); + if(Ch == -1) + { + ppmError = true; + break; + } + if(Ch == ppmEscChar) + { + int NextCh = ppm.decodeChar(); + if(NextCh == 0) + { + if(!readTables()) + { + break; + } + continue; + } + if(NextCh == 2 || NextCh == -1) + { + break; + } + if(NextCh == 3) + { + if(!readVMCodePPM()) + { + break; + } + continue; + } + if(NextCh == 4) + { + int Distance = 0, Length = 0; + boolean failed = false; + for(int I = 0; I < 4 && !failed; I++) + { + int ch = ppm.decodeChar(); + if(ch == -1) + { + failed = true; + } + else + { + if(I == 3) + { + // Bug fixed + Length = ch & 0xff; + } + else + { + // Bug fixed + Distance = (Distance << 8) + (ch & 0xff); + } + } + } + if(failed) + { + break; + } + copyString(Length + 32, Distance + 2); + continue; + } + if(NextCh == 5) + { + int Length = ppm.decodeChar(); + if(Length == -1) + { + break; + } + copyString(Length + 4, 1); + continue; + } + } + window[unpPtr++] = (byte) Ch; + continue; + } + + int Number = decodeNumber(LD); + if(Number < 256) + { + window[unpPtr++] = (byte) Number; + continue; + } + if(Number >= 271) + { + int Length = LDecode[Number -= 271] + 3; + if((Bits = LBits[Number]) > 0) + { + Length += getbits() >>> (16 - Bits); + addbits(Bits); + } + + int DistNumber = decodeNumber(DD); + int Distance = DDecode[DistNumber] + 1; + if((Bits = DBits[DistNumber]) > 0) + { + if(DistNumber > 9) + { + if(Bits > 4) + { + Distance += ((getbits() >>> (20 - Bits)) << 4); + addbits(Bits - 4); + } + if(lowDistRepCount > 0) + { + lowDistRepCount--; + Distance += prevLowDist; + } + else + { + int LowDist = decodeNumber(LDD); + if(LowDist == 16) + { + lowDistRepCount = Compress.LOW_DIST_REP_COUNT - 1; + Distance += prevLowDist; + } + else + { + Distance += LowDist; + prevLowDist = LowDist; + } + } + } + else + { + Distance += getbits() >>> (16 - Bits); + addbits(Bits); + } + } + + if(Distance >= 0x2000) + { + Length++; + if(Distance >= 0x40000L) + { + Length++; + } + } + + insertOldDist(Distance); + insertLastMatch(Length, Distance); + + copyString(Length, Distance); + continue; + } + if(Number == 256) + { + if(!readEndOfBlock()) + { + break; + } + continue; + } + if(Number == 257) + { + if(!readVMCode()) + { + break; + } + continue; + } + if(Number == 258) + { + if(lastLength != 0) + { + copyString(lastLength, lastDist); + } + continue; + } + if(Number < 263) + { + int DistNum = Number - 259; + int Distance = oldDist[DistNum]; + for(int I = DistNum; I > 0; I--) + { + oldDist[I] = oldDist[I - 1]; + } + oldDist[0] = Distance; + + int LengthNumber = decodeNumber(RD); + int Length = LDecode[LengthNumber] + 2; + if((Bits = LBits[LengthNumber]) > 0) + { + Length += getbits() >>> (16 - Bits); + addbits(Bits); + } + insertLastMatch(Length, Distance); + copyString(Length, Distance); + continue; + } + if(Number < 272) + { + int Distance = SDDecode[Number -= 263] + 1; + if((Bits = SDBits[Number]) > 0) + { + Distance += getbits() >>> (16 - Bits); + addbits(Bits); + } + insertOldDist(Distance); + insertLastMatch(2, Distance); + copyString(2, Distance); + continue; + } + } + UnpWriteBuf(); + + } + + private void UnpWriteBuf() throws IOException + { + int WrittenBorder = wrPtr; + int WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; + for(int I = 0; I < prgStack.size(); I++) + { + UnpackFilter flt = (UnpackFilter)prgStack.elementAt(I); + if(flt == null) + { + continue; + } + if(flt.isNextWindow()) + { + flt.setNextWindow(false);// ->NextWindow=false; + continue; + } + int BlockStart = flt.getBlockStart();// ->BlockStart; + int BlockLength = flt.getBlockLength();// ->BlockLength; + if(((BlockStart - WrittenBorder) & Compress.MAXWINMASK) < WriteSize) + { + if(WrittenBorder != BlockStart) + { + UnpWriteArea(WrittenBorder, BlockStart); + WrittenBorder = BlockStart; + WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; + } + if(BlockLength <= WriteSize) + { + int BlockEnd = (BlockStart + BlockLength) + & Compress.MAXWINMASK; + if(BlockStart < BlockEnd || BlockEnd == 0) + { + // VM.SetMemory(0,Window+BlockStart,BlockLength); + rarVM.setMemory(0, window, BlockStart, BlockLength); + } + else + { + int FirstPartLength = Compress.MAXWINSIZE - BlockStart; + // VM.SetMemory(0,Window+BlockStart,FirstPartLength); + rarVM.setMemory(0, window, BlockStart, FirstPartLength); + // VM.SetMemory(FirstPartLength,Window,BlockEnd); + rarVM.setMemory(FirstPartLength, window, 0, BlockEnd); + + } + + VMPreparedProgram ParentPrg = ((UnpackFilter)filters.elementAt(flt.getParentFilter())).getPrg(); + VMPreparedProgram Prg = flt.getPrg(); + + if(ParentPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) + { + // copy global data from previous script execution if + // any + // Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + // memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + Prg.getGlobalData().setSize( + ParentPrg.getGlobalData().size()); + for(int i = 0; i < ParentPrg.getGlobalData().size() + - RarVM.VM_FIXEDGLOBALSIZE; i++) + { + Prg.getGlobalData().setElementAt(ParentPrg.getGlobalData().elementAt(RarVM.VM_FIXEDGLOBALSIZE + i), RarVM.VM_FIXEDGLOBALSIZE + i); + } + } + + ExecuteCode(Prg); + + if(Prg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) + { + // save global data for next script execution + if(ParentPrg.getGlobalData().size() < Prg.getGlobalData().size()) + { + ParentPrg.getGlobalData().setSize( + Prg.getGlobalData().size());// ->GlobalData.Alloc(Prg->GlobalData.Size()); + } + // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for(int i = 0; i < Prg.getGlobalData().size() + - RarVM.VM_FIXEDGLOBALSIZE; i++) + { + ParentPrg.getGlobalData().setElementAt(Prg.getGlobalData().elementAt(RarVM.VM_FIXEDGLOBALSIZE + i), RarVM.VM_FIXEDGLOBALSIZE + i); + } + } + else + { + ParentPrg.getGlobalData().removeAllElements(); + } + + int FilteredDataOffset = Prg.getFilteredDataOffset(); + int FilteredDataSize = Prg.getFilteredDataSize(); + byte[] FilteredData = new byte[FilteredDataSize]; + + for(int i = 0; i < FilteredDataSize; i++) + { + FilteredData[i] = rarVM.getMem()[FilteredDataOffset + i];//Prg.getGlobalData().get(FilteredDataOffset + i); + } + + prgStack.setElementAt(null, I); + while(I + 1 < prgStack.size()) + { + UnpackFilter NextFilter = (UnpackFilter)prgStack.elementAt(I + 1); + if(NextFilter == null + || NextFilter.getBlockStart() != BlockStart + || NextFilter.getBlockLength() != FilteredDataSize + || NextFilter.isNextWindow()) + { + break; + } + // apply several filters to same data block + + rarVM.setMemory(0, FilteredData, 0, FilteredDataSize);// .SetMemory(0,FilteredData,FilteredDataSize); + + VMPreparedProgram pPrg = ((UnpackFilter)filters.elementAt(NextFilter.getParentFilter())).getPrg(); + VMPreparedProgram NextPrg = NextFilter.getPrg(); + + if(pPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) + { + // copy global data from previous script execution + // if any + // NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + NextPrg.getGlobalData().setSize( + pPrg.getGlobalData().size()); + // memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for(int i = 0; i < pPrg.getGlobalData().size() + - RarVM.VM_FIXEDGLOBALSIZE; i++) + { + NextPrg.getGlobalData().setElementAt(pPrg.getGlobalData().elementAt(RarVM.VM_FIXEDGLOBALSIZE + i), RarVM.VM_FIXEDGLOBALSIZE + i); + } + } + + ExecuteCode(NextPrg); + + if(NextPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) + { + // save global data for next script execution + if(pPrg.getGlobalData().size() < NextPrg.getGlobalData().size()) + { + pPrg.getGlobalData().setSize( + NextPrg.getGlobalData().size()); + } + // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for(int i = 0; i < NextPrg.getGlobalData().size() + - RarVM.VM_FIXEDGLOBALSIZE; i++) + { + pPrg.getGlobalData().setElementAt(NextPrg.getGlobalData().elementAt(RarVM.VM_FIXEDGLOBALSIZE + i), RarVM.VM_FIXEDGLOBALSIZE + i); + } + } + else + { + pPrg.getGlobalData().removeAllElements(); + } + FilteredDataOffset = NextPrg.getFilteredDataOffset(); + FilteredDataSize = NextPrg.getFilteredDataSize(); + + FilteredData = new byte[FilteredDataSize]; + for(int i = 0; i < FilteredDataSize; i++) + { + FilteredData[i] = ((Byte)NextPrg.getGlobalData().elementAt(FilteredDataOffset + i)).byteValue(); + } + + I++; + prgStack.setElementAt(null, I); + } + unpIO.unpWrite(FilteredData, 0, FilteredDataSize); + unpSomeRead = true; + writtenFileSize += FilteredDataSize; + WrittenBorder = BlockEnd; + WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; + } + else + { + for(int J = I; J < prgStack.size(); J++) + { + UnpackFilter filt = (UnpackFilter)prgStack.elementAt(J); + if(filt != null && filt.isNextWindow()) + { + filt.setNextWindow(false); + } + } + wrPtr = WrittenBorder; + return; + } + } + } + + UnpWriteArea(WrittenBorder, unpPtr); + wrPtr = unpPtr; + + } + + private void UnpWriteArea(int startPtr, int endPtr) throws IOException + { + if(endPtr != startPtr) + { + unpSomeRead = true; + } + if(endPtr < startPtr) + { + UnpWriteData(window, startPtr, -startPtr & Compress.MAXWINMASK); + UnpWriteData(window, 0, endPtr); + unpAllBuf = true; + } + else + { + UnpWriteData(window, startPtr, endPtr - startPtr); + } + } + + private void UnpWriteData(byte[] data, int offset, int size) + throws IOException + { + if(writtenFileSize >= destUnpSize) + { + return; + } + int writeSize = size; + long leftToWrite = destUnpSize - writtenFileSize; + if(writeSize > leftToWrite) + { + writeSize = (int) leftToWrite; + } + unpIO.unpWrite(data, offset, writeSize); + + writtenFileSize += size; + + } + + private void insertOldDist(int distance) + { + oldDist[3] = oldDist[2]; + oldDist[2] = oldDist[1]; + oldDist[1] = oldDist[0]; + oldDist[0] = distance; + } + + private void insertLastMatch(int length, int distance) + { + lastDist = distance; + lastLength = length; + } + + private void copyString(int length, int distance) + { +// System.out.println("copyString(" + length + ", " + distance + ")"); + + int destPtr = unpPtr - distance; + //System.out.println(unpPtr+":"+distance); + if(destPtr >= 0 && destPtr < Compress.MAXWINSIZE - 260 + && unpPtr < Compress.MAXWINSIZE - 260) + { + + + window[unpPtr++] = window[destPtr++]; + + while(--length > 0) + { + window[unpPtr++] = window[destPtr++]; + } + } + else + { + while(length-- != 0) + { + window[unpPtr] = window[destPtr++ & Compress.MAXWINMASK]; + unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; + } + } + } + + protected void unpInitData(boolean solid) + { + if(!solid) + { + tablesRead = false; + Arrays.fill(oldDist, 0); // memset(oldDist,0,sizeof(OldDist)); + + oldDistPtr = 0; + lastDist = 0; + lastLength = 0; + + Arrays.fill(unpOldTable, (byte) 0);// memset(UnpOldTable,0,sizeof(UnpOldTable)); + + unpPtr = 0; + wrPtr = 0; + ppmEscChar = 2; + + initFilters(); + } + InitBitInput(); + ppmError = false; + writtenFileSize = 0; + readTop = 0; + readBorder = 0; + unpInitData20(solid); + } + + private void initFilters() + { + oldFilterLengths.removeAllElements(); + lastFilter = 0; + + filters.removeAllElements(); + + prgStack.removeAllElements(); + } + + private boolean readEndOfBlock() throws IOException, RarException + { + int BitField = getbits(); + boolean NewTable, NewFile = false; + if((BitField & 0x8000) != 0) + { + NewTable = true; + addbits(1); + } + else + { + NewFile = true; + NewTable = (BitField & 0x4000) != 0 ? true : false; + addbits(2); + } + tablesRead = !NewTable; + return !(NewFile || NewTable && !readTables()); + } + + private boolean readTables() throws IOException, RarException + { + byte[] bitLength = new byte[Compress.BC]; + + byte[] table = new byte[Compress.HUFF_TABLE_SIZE]; + if(inAddr > readTop - 25) + { + if(!unpReadBuf()) + { + return (false); + } + } + faddbits((8 - inBit) & 7); + long bitField = fgetbits() & 0xffFFffFF; + if((bitField & 0x8000) != 0) + { + unpBlockType = BlockTypes.BLOCK_PPM; + return (ppm.decodeInit(this, ppmEscChar)); + } + unpBlockType = BlockTypes.BLOCK_LZ; + + prevLowDist = 0; + lowDistRepCount = 0; + + if((bitField & 0x4000) == 0) + { + Arrays.fill(unpOldTable, (byte) 0);// memset(UnpOldTable,0,sizeof(UnpOldTable)); + } + faddbits(2); + + for(int i = 0; i < Compress.BC; i++) + { + int length = (fgetbits() >>> 12) & 0xFF; + faddbits(4); + if(length == 15) + { + int zeroCount = (fgetbits() >>> 12) & 0xFF; + faddbits(4); + if(zeroCount == 0) + { + bitLength[i] = 15; + } + else + { + zeroCount += 2; + while(zeroCount-- > 0 && i < bitLength.length) + { + bitLength[i++] = 0; + } + i--; + } + } + else + { + bitLength[i] = (byte) length; + } + } + + makeDecodeTables(bitLength, 0, BD, Compress.BC); + + int TableSize = Compress.HUFF_TABLE_SIZE; + + for(int i = 0; i < TableSize;) + { + if(inAddr > readTop - 5) + { + if(!unpReadBuf()) + { + return (false); + } + } + int Number = decodeNumber(BD); + if(Number < 16) + { + table[i] = (byte) ((Number + unpOldTable[i]) & 0xf); + i++; + } + else if(Number < 18) + { + int N; + if(Number == 16) + { + N = (fgetbits() >>> 13) + 3; + faddbits(3); + } + else + { + N = (fgetbits() >>> 9) + 11; + faddbits(7); + } + while(N-- > 0 && i < TableSize) + { + table[i] = table[i - 1]; + i++; + } + } + else + { + int N; + if(Number == 18) + { + N = (fgetbits() >>> 13) + 3; + faddbits(3); + } + else + { + N = (fgetbits() >>> 9) + 11; + faddbits(7); + } + while(N-- > 0 && i < TableSize) + { + table[i++] = 0; + } + } + } + tablesRead = true; + if(inAddr > readTop) + { + return (false); + } + makeDecodeTables(table, 0, LD, Compress.NC); + makeDecodeTables(table, Compress.NC, DD, Compress.DC); + makeDecodeTables(table, Compress.NC + Compress.DC, LDD, Compress.LDC); + makeDecodeTables(table, Compress.NC + Compress.DC + Compress.LDC, RD, + Compress.RC); + + // memcpy(unpOldTable,table,sizeof(unpOldTable)); + for(int i = 0; i < unpOldTable.length; i++) + { + unpOldTable[i] = table[i]; + } + return (true); + + } + + private boolean readVMCode() throws IOException, RarException + { + int FirstByte = getbits() >> 8; + addbits(8); + int Length = (FirstByte & 7) + 1; + if(Length == 7) + { + Length = (getbits() >> 8) + 7; + addbits(8); + } + else if(Length == 8) + { + Length = getbits(); + addbits(16); + } + Vector vmCode = new Vector(); + for(int I = 0; I < Length; I++) + { + if(inAddr >= readTop - 1 && !unpReadBuf() && I < Length - 1) + { + return (false); + } + vmCode.addElement(ByteCache.valueOf((byte) (getbits() >> 8))); + addbits(8); + } + return (addVMCode(FirstByte, vmCode, Length)); + } + + private boolean readVMCodePPM() throws IOException, RarException + { + int FirstByte = ppm.decodeChar(); + if((int) FirstByte == -1) + { + return (false); + } + int Length = (FirstByte & 7) + 1; + if(Length == 7) + { + int B1 = ppm.decodeChar(); + if(B1 == -1) + { + return (false); + } + Length = B1 + 7; + } + else if(Length == 8) + { + int B1 = ppm.decodeChar(); + if(B1 == -1) + { + return (false); + } + int B2 = ppm.decodeChar(); + if(B2 == -1) + { + return (false); + } + Length = B1 * 256 + B2; + } + Vector vmCode = new Vector(); + for(int I = 0; I < Length; I++) + { + int Ch = ppm.decodeChar(); + if(Ch == -1) + { + return (false); + } + vmCode.addElement(ByteCache.valueOf((byte) Ch));// VMCode[I]=Ch; + } + return (addVMCode(FirstByte, vmCode, Length)); + } + + private boolean addVMCode(int firstByte, Vector vmCode, int length) + { + BitInput Inp = new BitInput(); + Inp.InitBitInput(); + // memcpy(Inp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize)); + for(int i = 0; i < Math.min(BitInput.MAX_SIZE, vmCode.size()); i++) + { + Inp.getInBuf()[i] = ((Byte)vmCode.elementAt(i)).byteValue(); + } + rarVM.init(); + + int FiltPos; + if((firstByte & 0x80) != 0) + { + FiltPos = RarVM.ReadData(Inp); + if(FiltPos == 0) + { + initFilters(); + } + else + { + FiltPos--; + } + } + else + { + FiltPos = lastFilter; // use the same filter as last time + } + if(FiltPos > filters.size() || FiltPos > oldFilterLengths.size()) + { + return (false); + } + lastFilter = FiltPos; + boolean NewFilter = (FiltPos == filters.size()); + + UnpackFilter StackFilter = new UnpackFilter(); // new filter for + // PrgStack + + UnpackFilter Filter; + if(NewFilter) // new filter code, never used before since VM reset + { + // too many different filters, corrupt archive + if(FiltPos > 1024) + { + return (false); + } + + // Filters[Filters.Size()-1]=Filter=new UnpackFilter; + Filter = new UnpackFilter(); + filters.addElement(Filter); + StackFilter.setParentFilter(filters.size() - 1); + oldFilterLengths.addElement(new Integer(0)); + Filter.setExecCount(0); + } + else // filter was used in the past + { + Filter = (UnpackFilter)filters.elementAt(FiltPos); + StackFilter.setParentFilter(FiltPos); + Filter.setExecCount(Filter.getExecCount() + 1);// ->ExecCount++; + } + + prgStack.addElement(StackFilter); + StackFilter.setExecCount(Filter.getExecCount());// ->ExecCount; + + int BlockStart = RarVM.ReadData(Inp); + if((firstByte & 0x40) != 0) + { + BlockStart += 258; + } + StackFilter.setBlockStart((BlockStart + unpPtr) & Compress.MAXWINMASK); + if((firstByte & 0x20) != 0) + { + StackFilter.setBlockLength(RarVM.ReadData(Inp)); + } + else + { + StackFilter.setBlockLength(FiltPos < oldFilterLengths.size() ? ((Integer)oldFilterLengths.elementAt(FiltPos)).intValue() : 0); + } + StackFilter.setNextWindow((wrPtr != unpPtr) + && ((wrPtr - unpPtr) & Compress.MAXWINMASK) <= BlockStart); + + // DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x + // BlockStart=%08x",UnpPtr,WrPtr,BlockStart); + + oldFilterLengths.setElementAt(new Integer(StackFilter.getBlockLength()), FiltPos); + + // memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR)); + Arrays.fill(StackFilter.getPrg().getInitR(), 0); + StackFilter.getPrg().getInitR()[3] = RarVM.VM_GLOBALMEMADDR;// StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR; + StackFilter.getPrg().getInitR()[4] = StackFilter.getBlockLength();// StackFilter->Prg.InitR[4]=StackFilter->BlockLength; + StackFilter.getPrg().getInitR()[5] = StackFilter.getExecCount();// StackFilter->Prg.InitR[5]=StackFilter->ExecCount; + + if((firstByte & 0x10) != 0) // set registers to optional parameters + // if any + { + int InitMask = Inp.fgetbits() >>> 9; + Inp.faddbits(7); + for(int I = 0; I < 7; I++) + { + if((InitMask & (1 << I)) != 0) + { + // StackFilter->Prg.InitR[I]=RarVM::ReadData(Inp); + StackFilter.getPrg().getInitR()[I] = RarVM.ReadData(Inp); + } + } + } + + if(NewFilter) + { + int VMCodeSize = RarVM.ReadData(Inp); + if(VMCodeSize >= 0x10000 || VMCodeSize == 0) + { + return (false); + } + byte[] VMCode = new byte[VMCodeSize]; + for(int I = 0; I < VMCodeSize; I++) + { + if(Inp.Overflow(3)) + { + return (false); + } + VMCode[I] = (byte) (Inp.fgetbits() >> 8); + Inp.faddbits(8); + } + // VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); + rarVM.prepare(VMCode, VMCodeSize, Filter.getPrg()); + } + StackFilter.getPrg().setAltCmd(Filter.getPrg().getCmd());// StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0]; + StackFilter.getPrg().setCmdCount(Filter.getPrg().getCmdCount());// StackFilter->Prg.CmdCount=Filter->Prg.CmdCount; + + int StaticDataSize = Filter.getPrg().getStaticData().size(); + if(StaticDataSize > 0 && StaticDataSize < RarVM.VM_GLOBALMEMSIZE) + { + // read statically defined data contained in DB commands + // StackFilter->Prg.StaticData.Add(StaticDataSize); + StackFilter.getPrg().setStaticData(Filter.getPrg().getStaticData()); + // memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize); + } + + if(StackFilter.getPrg().getGlobalData().size() < RarVM.VM_FIXEDGLOBALSIZE) + { + // StackFilter->Prg.GlobalData.Reset(); + // StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE); + StackFilter.getPrg().getGlobalData().removeAllElements(); + StackFilter.getPrg().getGlobalData().setSize(RarVM.VM_FIXEDGLOBALSIZE); + } + + // byte *GlobalData=&StackFilter->Prg.GlobalData[0]; + Vector globalData = StackFilter.getPrg().getGlobalData(); + for(int I = 0; I < 7; I++) + { + rarVM.setLowEndianValue(globalData, I * 4, StackFilter.getPrg().getInitR()[I]); + } + + // VM.SetLowEndianValue((uint + // *)&GlobalData[0x1c],StackFilter->BlockLength); + rarVM.setLowEndianValue(globalData, 0x1c, StackFilter.getBlockLength()); + // VM.SetLowEndianValue((uint *)&GlobalData[0x20],0); + rarVM.setLowEndianValue(globalData, 0x20, 0); + rarVM.setLowEndianValue(globalData, 0x24, 0); + rarVM.setLowEndianValue(globalData, 0x28, 0); + + // VM.SetLowEndianValue((uint + // *)&GlobalData[0x2c],StackFilter->ExecCount); + rarVM.setLowEndianValue(globalData, 0x2c, StackFilter.getExecCount()); + // memset(&GlobalData[0x30],0,16); + for(int i = 0; i < 16; i++) + { + globalData.setElementAt(ByteCache.valueOf((byte) (0)), 0x30 + i); + } + if((firstByte & 8) != 0) // put data block passed as parameter if any + { + if(Inp.Overflow(3)) + { + return (false); + } + int DataSize = RarVM.ReadData(Inp); + if(DataSize > RarVM.VM_GLOBALMEMSIZE - RarVM.VM_FIXEDGLOBALSIZE) + { + return (false); + } + int CurSize = StackFilter.getPrg().getGlobalData().size(); + if(CurSize < DataSize + RarVM.VM_FIXEDGLOBALSIZE) + { + // StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); + StackFilter.getPrg().getGlobalData().setSize( + DataSize + RarVM.VM_FIXEDGLOBALSIZE - CurSize); + } + int offset = RarVM.VM_FIXEDGLOBALSIZE; + globalData = StackFilter.getPrg().getGlobalData(); + for(int I = 0; I < DataSize; I++) + { + if(Inp.Overflow(3)) + { + return (false); + } + globalData.setElementAt(ByteCache.valueOf((byte) (Inp.fgetbits() >>> 8)), offset + I); + Inp.faddbits(8); + } + } + return (true); + } + + private void ExecuteCode(VMPreparedProgram Prg) + { + if(Prg.getGlobalData().size() > 0) + { + // Prg->InitR[6]=int64to32(WrittenFileSize); + Prg.getInitR()[6] = (int) (writtenFileSize); + // rarVM.SetLowEndianValue((uint + // *)&Prg->GlobalData[0x24],int64to32(WrittenFileSize)); + rarVM.setLowEndianValue(Prg.getGlobalData(), 0x24, + (int) writtenFileSize); + // rarVM.SetLowEndianValue((uint + // *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>32)); + rarVM.setLowEndianValue(Prg.getGlobalData(), 0x28, + (int) (writtenFileSize >>> 32)); + rarVM.execute(Prg); + } + } + +// Duplicate method +// private boolean ReadEndOfBlock() throws IOException, RarException +// { +// int BitField = getbits(); +// boolean NewTable, NewFile = false; +// if ((BitField & 0x8000) != 0) { +// NewTable = true; +// addbits(1); +// } else { +// NewFile = true; +// NewTable = (BitField & 0x4000) != 0; +// addbits(2); +// } +// tablesRead = !NewTable; +// return !(NewFile || NewTable && !readTables()); +// } + public boolean isFileExtracted() + { + return fileExtracted; + } + + public void setDestSize(long destSize) + { + this.destUnpSize = destSize; + this.fileExtracted = false; + } + + public void setSuspended(boolean suspended) + { + this.suspended = suspended; + } + + public int getChar() throws IOException, RarException + { + if(inAddr > BitInput.MAX_SIZE - 30) + { + unpReadBuf(); + } + return (inBuf[inAddr++] & 0xff); + } + + public int getPpmEscChar() + { + return ppmEscChar; + } + + public void setPpmEscChar(int ppmEscChar) + { + this.ppmEscChar = ppmEscChar; + } + + public void cleanUp() + { + if(ppm != null) + { + SubAllocator allocator = ppm.getSubAlloc(); + if(allocator != null) + { + allocator.stopSubAllocator(); + } + } + } +} diff --git a/src/com/innosystec/unrar/unpack/Unpack15.java b/src/com/innosystec/unrar/unpack/Unpack15.java new file mode 100644 index 0000000..8476edb --- /dev/null +++ b/src/com/innosystec/unrar/unpack/Unpack15.java @@ -0,0 +1,745 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 21.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack; + +import com.classpath.util.Arrays; +import java.io.IOException; + +import com.innosystec.unrar.exception.RarException; +import com.innosystec.unrar.unpack.decode.Compress; +import com.innosystec.unrar.unpack.vm.BitInput; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public abstract class Unpack15 extends BitInput +{ + protected int readBorder; + protected boolean suspended; + protected boolean unpAllBuf; + protected ComprDataIO unpIO; + protected boolean unpSomeRead; + protected int readTop; + protected long destUnpSize; + protected byte[] window; + protected int[] oldDist = new int[4]; + protected int unpPtr, wrPtr; + protected int oldDistPtr; + protected int[] ChSet = new int[256], ChSetA = new int[256], + ChSetB = new int[256], ChSetC = new int[256]; + protected int[] Place = new int[256], PlaceA = new int[256], + PlaceB = new int[256], PlaceC = new int[256]; + protected int[] NToPl = new int[256], NToPlB = new int[256], + NToPlC = new int[256]; + protected int FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3; + protected int Buf60, NumHuf, StMode, LCount, FlagsCnt; + protected int Nhfb, Nlzb, MaxDist3; + protected int lastDist, lastLength; + private static final int STARTL1 = 2; + private static int DecL1[] = + { + 0x8000, 0xa000, 0xc000, 0xd000, 0xe000, + 0xea00, 0xee00, 0xf000, 0xf200, 0xf200, 0xffff + }; + private static int PosL1[] = + { + 0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32 + }; + private static final int STARTL2 = 3; + private static int DecL2[] = + { + 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, + 0xee00, 0xf000, 0xf200, 0xf240, 0xffff + }; + private static int PosL2[] = + { + 0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36 + }; + private static final int STARTHF0 = 4; + private static int DecHf0[] = + { + 0x8000, 0xc000, 0xe000, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xffff + }; + private static int PosHf0[] = + { + 0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, + 33 + }; + private static final int STARTHF1 = 5; + private static int DecHf1[] = + { + 0x2000, 0xc000, 0xe000, 0xf000, 0xf200, + 0xf200, 0xf7e0, 0xffff + }; + private static int PosHf1[] = + { + 0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, + 127 + }; + private static final int STARTHF2 = 5; + private static int DecHf2[] = + { + 0x1000, 0x2400, 0x8000, 0xc000, 0xfa00, + 0xffff, 0xffff, 0xffff + }; + private static int PosHf2[] = + { + 0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0 + }; + private static final int STARTHF3 = 6; + private static int DecHf3[] = + { + 0x800, 0x2400, 0xee00, 0xfe80, 0xffff, + 0xffff, 0xffff + }; + private static int PosHf3[] = + { + 0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0 + }; + private static final int STARTHF4 = 8; + private static int DecHf4[] = + { + 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff + }; + private static int PosHf4[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0 + }; + static int ShortLen1[] = + { + 1, 3, 4, 4, 5, 6, 7, 8, 8, 4, 4, 5, 6, 6, 4, 0 + }; + static int ShortXor1[] = + { + 0, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, + 0xff, 0xc0, 0x80, 0x90, 0x98, 0x9c, 0xb0 + }; + static int ShortLen2[] = + { + 2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 4, 5, 6, 6, 4, 0 + }; + static int ShortXor2[] = + { + 0, 0x40, 0x60, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, + 0xfc, 0xc0, 0x80, 0x90, 0x98, 0x9c, 0xb0 + }; + + protected abstract void unpInitData(boolean solid); + + protected void unpack15(boolean solid) throws IOException, RarException + { + if(suspended) + { + unpPtr = wrPtr; + } + else + { + unpInitData(solid); + oldUnpInitData(solid); + unpReadBuf(); + if(!solid) + { + initHuff(); + unpPtr = 0; + } + else + { + unpPtr = wrPtr; + } + --destUnpSize; + } + if(destUnpSize >= 0) + { + getFlagsBuf(); + FlagsCnt = 8; + } + + while(destUnpSize >= 0) + { + unpPtr &= Compress.MAXWINMASK; + + if(inAddr > readTop - 30 && !unpReadBuf()) + { + break; + } + if(((wrPtr - unpPtr) & Compress.MAXWINMASK) < 270 + && wrPtr != unpPtr) + { + oldUnpWriteBuf(); + if(suspended) + { + return; + } + } + if(StMode != 0) + { + huffDecode(); + continue; + } + + if(--FlagsCnt < 0) + { + getFlagsBuf(); + FlagsCnt = 7; + } + + if((FlagBuf & 0x80) != 0) + { + FlagBuf <<= 1; + if(Nlzb > Nhfb) + { + longLZ(); + } + else + { + huffDecode(); + } + } + else + { + FlagBuf <<= 1; + if(--FlagsCnt < 0) + { + getFlagsBuf(); + FlagsCnt = 7; + } + if((FlagBuf & 0x80) != 0) + { + FlagBuf <<= 1; + if(Nlzb > Nhfb) + { + huffDecode(); + } + else + { + longLZ(); + } + } + else + { + FlagBuf <<= 1; + shortLZ(); + } + } + } + oldUnpWriteBuf(); + } + + protected boolean unpReadBuf() throws IOException, RarException + { + int dataSize = readTop - inAddr; + if(dataSize < 0) + { + return (false); + } + if(inAddr > BitInput.MAX_SIZE / 2) + { + if(dataSize > 0) + { + //memmove(InBuf,InBuf+InAddr,DataSize); +// for (int i = 0; i < dataSize; i++) { +// inBuf[i] = inBuf[inAddr + i]; +// } + System.arraycopy(inBuf, inAddr, inBuf, 0, dataSize); + } + inAddr = 0; + readTop = dataSize; + } + else + { + dataSize = readTop; + } + //int readCode=UnpIO->UnpRead(InBuf+DataSize,(BitInput::MAX_SIZE-DataSize)&~0xf); + int readCode = unpIO.unpRead(inBuf, dataSize, (BitInput.MAX_SIZE - dataSize) & ~0xf); + if(readCode > 0) + { + readTop += readCode; + } + readBorder = readTop - 30; + return (readCode != -1); + } + + private int getShortLen1(int pos) + { + return pos == 1 ? Buf60 + 3 : ShortLen1[pos]; + } + + private int getShortLen2(int pos) + { + return pos == 3 ? Buf60 + 3 : ShortLen2[pos]; + } + + protected void shortLZ() + { + int Length, SaveLength; + int LastDistance; + int Distance; + int DistancePlace; + NumHuf = 0; + + int BitField = fgetbits(); + if(LCount == 2) + { + faddbits(1); + if(BitField >= 0x8000) + { + oldCopyString(lastDist, lastLength); + return; + } + BitField <<= 1; + LCount = 0; + } + BitField >>>= 8; + if(AvrLn1 < 37) + { + for(Length = 0;; Length++) + { + if(((BitField ^ ShortXor1[Length]) & (~(0xff >>> getShortLen1(Length)))) == 0) + { + break; + } + } + faddbits(getShortLen1(Length)); + } + else + { + for(Length = 0;; Length++) + { + if(((BitField ^ ShortXor2[Length]) & (~(0xff >> getShortLen2(Length)))) == 0) + { + break; + } + } + faddbits(getShortLen2(Length)); + } + + if(Length >= 9) + { + if(Length == 9) + { + LCount++; + oldCopyString(lastDist, lastLength); + return; + } + if(Length == 14) + { + LCount = 0; + Length = decodeNum(fgetbits(), STARTL2, DecL2, PosL2) + 5; + Distance = (fgetbits() >> 1) | 0x8000; + faddbits(15); + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + return; + } + + LCount = 0; + SaveLength = Length; + Distance = oldDist[(oldDistPtr - (Length - 9)) & 3]; + Length = decodeNum(fgetbits(), STARTL1, DecL1, PosL1) + 2; + if(Length == 0x101 && SaveLength == 10) + { + Buf60 ^= 1; + return; + } + if(Distance > 256) + { + Length++; + } + if(Distance >= MaxDist3) + { + Length++; + } + + oldDist[oldDistPtr++] = Distance; + oldDistPtr = oldDistPtr & 3; + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + return; + } + + LCount = 0; + AvrLn1 += Length; + AvrLn1 -= AvrLn1 >> 4; + + DistancePlace = decodeNum(fgetbits(), STARTHF2, DecHf2, PosHf2) & 0xff; + Distance = ChSetA[DistancePlace]; + if(--DistancePlace != -1) + { + PlaceA[Distance]--; + LastDistance = ChSetA[DistancePlace]; + PlaceA[LastDistance]++; + ChSetA[DistancePlace + 1] = LastDistance; + ChSetA[DistancePlace] = Distance; + } + Length += 2; + oldDist[oldDistPtr++] = ++Distance; + oldDistPtr = oldDistPtr & 3; + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + } + + protected void longLZ() + { + int Length; + int Distance; + int DistancePlace, NewDistancePlace; + int OldAvr2, OldAvr3; + + NumHuf = 0; + Nlzb += 16; + if(Nlzb > 0xff) + { + Nlzb = 0x90; + Nhfb >>>= 1; + } + OldAvr2 = AvrLn2; + + int BitField = fgetbits(); + if(AvrLn2 >= 122) + { + Length = decodeNum(BitField, STARTL2, DecL2, PosL2); + } + else + { + if(AvrLn2 >= 64) + { + Length = decodeNum(BitField, STARTL1, DecL1, PosL1); + } + else + { + if(BitField < 0x100) + { + Length = BitField; + faddbits(16); + } + else + { + for(Length = 0; ((BitField << Length) & 0x8000) == 0; Length++) + { + ; + } + faddbits(Length + 1); + } + } + } + AvrLn2 += Length; + AvrLn2 -= AvrLn2 >>> 5; + + BitField = fgetbits(); + if(AvrPlcB > 0x28ff) + { + DistancePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); + } + else + { + if(AvrPlcB > 0x6ff) + { + DistancePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); + } + else + { + DistancePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); + } + } + AvrPlcB += DistancePlace; + AvrPlcB -= AvrPlcB >> 8; + while(true) + { + Distance = ChSetB[DistancePlace & 0xff]; + NewDistancePlace = NToPlB[Distance++ & 0xff]++; + if((Distance & 0xff) == 0) + { + corrHuff(ChSetB, NToPlB); + } + else + { + break; + } + } + + ChSetB[DistancePlace] = ChSetB[NewDistancePlace]; + ChSetB[NewDistancePlace] = Distance; + + Distance = ((Distance & 0xff00) | (fgetbits() >>> 8)) >>> 1; + faddbits(7); + + OldAvr3 = AvrLn3; + if(Length != 1 && Length != 4) + { + if(Length == 0 && Distance <= MaxDist3) + { + AvrLn3++; + AvrLn3 -= AvrLn3 >> 8; + } + else + { + if(AvrLn3 > 0) + { + AvrLn3--; + } + } + } + Length += 3; + if(Distance >= MaxDist3) + { + Length++; + } + if(Distance <= 256) + { + Length += 8; + } + if(OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40) + { + MaxDist3 = 0x7f00; + } + else + { + MaxDist3 = 0x2001; + } + oldDist[oldDistPtr++] = Distance; + oldDistPtr = oldDistPtr & 3; + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + } + + protected void huffDecode() + { + int CurByte, NewBytePlace; + int Length; + int Distance; + int BytePlace; + + int BitField = fgetbits(); + + if(AvrPlc > 0x75ff) + { + BytePlace = decodeNum(BitField, STARTHF4, DecHf4, PosHf4); + } + else + { + if(AvrPlc > 0x5dff) + { + BytePlace = decodeNum(BitField, STARTHF3, DecHf3, PosHf3); + } + else + { + if(AvrPlc > 0x35ff) + { + BytePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); + } + else + { + if(AvrPlc > 0x0dff) + { + BytePlace = decodeNum(BitField, STARTHF1, DecHf1, + PosHf1); + } + else + { + BytePlace = decodeNum(BitField, STARTHF0, DecHf0, + PosHf0); + } + } + } + } + BytePlace &= 0xff; + if(StMode != 0) + { + if(BytePlace == 0 && BitField > 0xfff) + { + BytePlace = 0x100; + } + if(--BytePlace == -1) + { + BitField = fgetbits(); + faddbits(1); + if((BitField & 0x8000) != 0) + { + NumHuf = StMode = 0; + return; + } + else + { + Length = (BitField & 0x4000) != 0 ? 4 : 3; + faddbits(1); + Distance = decodeNum(fgetbits(), STARTHF2, DecHf2, PosHf2); + Distance = (Distance << 5) | (fgetbits() >>> 11); + faddbits(5); + oldCopyString(Distance, Length); + return; + } + } + } + else + { + if(NumHuf++ >= 16 && FlagsCnt == 0) + { + StMode = 1; + } + } + AvrPlc += BytePlace; + AvrPlc -= AvrPlc >>> 8; + Nhfb += 16; + if(Nhfb > 0xff) + { + Nhfb = 0x90; + Nlzb >>>= 1; + } + + window[unpPtr++] = (byte) (ChSet[BytePlace] >>> 8); + --destUnpSize; + + while(true) + { + CurByte = ChSet[BytePlace]; + NewBytePlace = NToPl[CurByte++ & 0xff]++; + if((CurByte & 0xff) > 0xa1) + { + corrHuff(ChSet, NToPl); + } + else + { + break; + } + } + + ChSet[BytePlace] = ChSet[NewBytePlace]; + ChSet[NewBytePlace] = CurByte; + } + + protected void getFlagsBuf() + { + int Flags, NewFlagsPlace; + int FlagsPlace = decodeNum(fgetbits(), STARTHF2, DecHf2, PosHf2); + + while(true) + { + Flags = ChSetC[FlagsPlace]; + FlagBuf = Flags >>> 8; + NewFlagsPlace = NToPlC[Flags++ & 0xff]++; + if((Flags & 0xff) != 0) + { + break; + } + corrHuff(ChSetC, NToPlC); + } + + ChSetC[FlagsPlace] = ChSetC[NewFlagsPlace]; + ChSetC[NewFlagsPlace] = Flags; + } + + protected void oldUnpInitData(boolean Solid) + { + if(!Solid) + { + AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; + AvrPlc = 0x3500; + MaxDist3 = 0x2001; + Nhfb = Nlzb = 0x80; + } + FlagsCnt = 0; + FlagBuf = 0; + StMode = 0; + LCount = 0; + readTop = 0; + } + + protected void initHuff() + { + for(int I = 0; I < 256; I++) + { + Place[I] = PlaceA[I] = PlaceB[I] = I; + PlaceC[I] = (~I + 1) & 0xff; + ChSet[I] = ChSetB[I] = I << 8; + ChSetA[I] = I; + ChSetC[I] = ((~I + 1) & 0xff) << 8; + } + + Arrays.fill(NToPl, 0);// memset(NToPl,0,sizeof(NToPl)); + Arrays.fill(NToPlB, 0); // memset(NToPlB,0,sizeof(NToPlB)); + Arrays.fill(NToPlC, 0); // memset(NToPlC,0,sizeof(NToPlC)); + corrHuff(ChSetB, NToPlB); + } + + protected void corrHuff(int[] CharSet, int[] NumToPlace) + { + int I, J, pos = 0; + for(I = 7; I >= 0; I--) + { + for(J = 0; J < 32; J++, pos++) + { + CharSet[pos] = ((CharSet[pos] & ~0xff) | I);// *CharSet=(*CharSet + // & ~0xff) | I; + } + } + Arrays.fill(NumToPlace, 0);// memset(NumToPlace,0,sizeof(NToPl)); + for(I = 6; I >= 0; I--) + { + NumToPlace[I] = (7 - I) * 32; + } + } + + protected void oldCopyString(int Distance, int Length) + { + destUnpSize -= Length; + while((Length--) != 0) + { + window[unpPtr] = window[(unpPtr - Distance) & Compress.MAXWINMASK]; + unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; + } + } + + protected int decodeNum(int Num, int StartPos, int[] DecTab, int[] PosTab) + { + int I; + for(Num &= 0xfff0, I = 0; DecTab[I] <= Num; I++) + { + StartPos++; + } + faddbits(StartPos); + return (((Num - (I != 0 ? DecTab[I - 1] : 0)) >>> (16 - StartPos)) + PosTab[StartPos]); + } + + protected void oldUnpWriteBuf() throws IOException + { + if(unpPtr != wrPtr) + { + unpSomeRead = true; + } + if(unpPtr < wrPtr) + { + unpIO.unpWrite(window, wrPtr, -wrPtr & Compress.MAXWINMASK); + unpIO.unpWrite(window, 0, unpPtr); + unpAllBuf = true; + } + else + { + unpIO.unpWrite(window, wrPtr, unpPtr - wrPtr); + } + wrPtr = unpPtr; + } +} diff --git a/src/com/innosystec/unrar/unpack/Unpack20.java b/src/com/innosystec/unrar/unpack/Unpack20.java new file mode 100644 index 0000000..0bff9b6 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/Unpack20.java @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 21.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack; + +import com.classpath.util.Arrays; +import java.io.IOException; + +import com.innosystec.unrar.exception.RarException; +import com.innosystec.unrar.unpack.decode.AudioVariables; +import com.innosystec.unrar.unpack.decode.BitDecode; +import com.innosystec.unrar.unpack.decode.Compress; +import com.innosystec.unrar.unpack.decode.Decode; +import com.innosystec.unrar.unpack.decode.DistDecode; +import com.innosystec.unrar.unpack.decode.LitDecode; +import com.innosystec.unrar.unpack.decode.LowDistDecode; +import com.innosystec.unrar.unpack.decode.RepDecode; + +import com.innosystec.unrar.unpack.decode.MultDecode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public abstract class Unpack20 extends Unpack15 +{ + + protected MultDecode[] MD = new MultDecode[4]; + + protected byte[] UnpOldTable20 = new byte[Compress.MC20 * 4]; + + protected int UnpAudioBlock, UnpChannels, UnpCurChannel, UnpChannelDelta; + + protected AudioVariables[] AudV = new AudioVariables[4]; + + protected LitDecode LD = new LitDecode(); + + protected DistDecode DD = new DistDecode(); + + protected LowDistDecode LDD = new LowDistDecode(); + + protected RepDecode RD = new RepDecode(); + + protected BitDecode BD = new BitDecode(); + + public static final int[] LDecode = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, + 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, + 224 }; + + public static final byte[] LBits = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, + 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; + + public static final int[] DDecode = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, + 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, + 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, 65536, 98304, + 131072, 196608, 262144, 327680, 393216, 458752, 524288, 589824, + 655360, 720896, 786432, 851968, 917504, 983040 }; + + public static final int[] DBits = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, + 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, + 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; + + public static final int[] SDDecode = { 0, 4, 8, 16, 32, 64, 128, 192 }; + + public static final int[] SDBits = { 2, 2, 3, 4, 5, 6, 6, 6 }; + + protected void unpack20(boolean solid) throws IOException, RarException + { + + int Bits; + + if (suspended) { + unpPtr = wrPtr; + } else { + unpInitData(solid); + if (!unpReadBuf()) { + return; + } + if (!solid) { + if (!ReadTables20()) { + return; + } + } + --destUnpSize; + } + + while (destUnpSize >= 0) { + unpPtr &= Compress.MAXWINMASK; + + if (inAddr > readTop - 30) + if (!unpReadBuf()) + break; + if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 270 + && wrPtr != unpPtr) { + oldUnpWriteBuf(); + if (suspended) + return; + } + if (UnpAudioBlock != 0) { + int AudioNumber = decodeNumber(MD[UnpCurChannel]); + + if (AudioNumber == 256) { + if (!ReadTables20()) + break; + continue; + } + window[unpPtr++] = DecodeAudio(AudioNumber); + if (++UnpCurChannel == UnpChannels) + UnpCurChannel = 0; + --destUnpSize; + continue; + } + + int Number = decodeNumber(LD); + if (Number < 256) { + window[unpPtr++] = (byte) Number; + --destUnpSize; + continue; + } + if (Number > 269) { + int Length = LDecode[Number -= 270] + 3; + if ((Bits = LBits[Number]) > 0) { + Length += getbits() >>> (16 - Bits); + addbits(Bits); + } + + int DistNumber = decodeNumber(DD); + int Distance = DDecode[DistNumber] + 1; + if ((Bits = DBits[DistNumber]) > 0) { + Distance += getbits() >>> (16 - Bits); + addbits(Bits); + } + + if (Distance >= 0x2000) { + Length++; + if (Distance >= 0x40000L) + Length++; + } + + CopyString20(Length, Distance); + continue; + } + if (Number == 269) { + if (!ReadTables20()) + break; + continue; + } + if (Number == 256) { + CopyString20(lastLength, lastDist); + continue; + } + if (Number < 261) { + int Distance = oldDist[(oldDistPtr - (Number - 256)) & 3]; + int LengthNumber = decodeNumber(RD); + int Length = LDecode[LengthNumber] + 2; + if ((Bits = LBits[LengthNumber]) > 0) { + Length += getbits() >>> (16 - Bits); + addbits(Bits); + } + if (Distance >= 0x101) { + Length++; + if (Distance >= 0x2000) { + Length++; + if (Distance >= 0x40000) + Length++; + } + } + CopyString20(Length, Distance); + continue; + } + if (Number < 270) { + int Distance = SDDecode[Number -= 261] + 1; + if ((Bits = SDBits[Number]) > 0) { + Distance += getbits() >>> (16 - Bits); + addbits(Bits); + } + CopyString20(2, Distance); + continue; + } + } + ReadLastTables(); + oldUnpWriteBuf(); + + } + + protected void CopyString20(int Length, int Distance) + { + lastDist = oldDist[oldDistPtr++ & 3] = Distance; + lastLength = Length; + destUnpSize -= Length; + + int DestPtr = unpPtr - Distance; + if (DestPtr < Compress.MAXWINSIZE - 300 + && unpPtr < Compress.MAXWINSIZE - 300) { + window[unpPtr++] = window[DestPtr++]; + window[unpPtr++] = window[DestPtr++]; + while (Length > 2) { + Length--; + window[unpPtr++] = window[DestPtr++]; + } + } else { + while ((Length--) != 0) { + window[unpPtr] = window[DestPtr++ & Compress.MAXWINMASK]; + unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; + } + } + } + + protected void makeDecodeTables(byte[] lenTab, int offset, Decode dec, + int size) + { + int[] lenCount = new int[16]; + int[] tmpPos = new int[16]; + int i; + long M, N; + + Arrays.fill(lenCount, 0);// memset(LenCount,0,sizeof(LenCount)); + + Arrays.fill(dec.getDecodeNum(), 0);// memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum)); + + for (i = 0; i < size; i++) { + lenCount[(int) (lenTab[offset + i] & 0xF)]++; + } + lenCount[0] = 0; + for (tmpPos[0] = 0, dec.getDecodePos()[0] = 0, dec.getDecodeLen()[0] = 0, N = 0, i = 1; i < 16; i++) { + N = 2 * (N + lenCount[i]); + M = N << (15 - i); + if (M > 0xFFFF) { + M = 0xFFFF; + } + dec.getDecodeLen()[i] = (int) M; + tmpPos[i] = dec.getDecodePos()[i] = dec.getDecodePos()[i - 1] + + lenCount[i - 1]; + } + + for (i = 0; i < size; i++) { + if (lenTab[offset + i] != 0) { + dec.getDecodeNum()[tmpPos[lenTab[offset + i] & 0xF]++] = i; + } + } + dec.setMaxNum(size); + } + + protected int decodeNumber(Decode dec) + { + int bits; + long bitField = getbits() & 0xfffe; +// if (bitField < dec.getDecodeLen()[8]) { +// if (bitField < dec.getDecodeLen()[4]) { +// if (bitField < dec.getDecodeLen()[2]) { +// if (bitField < dec.getDecodeLen()[1]) { +// bits = 1; +// } else { +// bits = 2; +// } +// } else { +// if (bitField < dec.getDecodeLen()[3]) { +// bits = 3; +// } else { +// bits = 4; +// } +// } +// } else { +// if (bitField < dec.getDecodeLen()[6]) { +// if (bitField < dec.getDecodeLen()[5]) +// bits = 5; +// else +// bits = 6; +// } else { +// if (bitField < dec.getDecodeLen()[7]) { +// bits = 7; +// } else { +// bits = 8; +// } +// } +// } +// } else { +// if (bitField < dec.getDecodeLen()[12]) { +// if (bitField < dec.getDecodeLen()[10]) +// if (bitField < dec.getDecodeLen()[9]) +// bits = 9; +// else +// bits = 10; +// else if (bitField < dec.getDecodeLen()[11]) +// bits = 11; +// else +// bits = 12; +// } else { +// if (bitField < dec.getDecodeLen()[14]) { +// if (bitField < dec.getDecodeLen()[13]) { +// bits = 13; +// } else { +// bits = 14; +// } +// } else { +// bits = 15; +// } +// } +// } +// addbits(bits); +// int N = dec.getDecodePos()[bits] +// + (((int) bitField - dec.getDecodeLen()[bits - 1]) >>> (16 - bits)); +// if (N >= dec.getMaxNum()) { +// N = 0; +// } +// return (dec.getDecodeNum()[N]); + int[] decodeLen = dec.getDecodeLen(); + if (bitField < decodeLen[8]) { + if (bitField < decodeLen[4]) { + if (bitField < decodeLen[2]) { + if (bitField < decodeLen[1]) { + bits = 1; + } else { + bits = 2; + } + } else { + if (bitField < decodeLen[3]) { + bits = 3; + } else { + bits = 4; + } + } + } else { + if (bitField < decodeLen[6]) { + if (bitField < decodeLen[5]) + bits = 5; + else + bits = 6; + } else { + if (bitField < decodeLen[7]) { + bits = 7; + } else { + bits = 8; + } + } + } + } else { + if (bitField < decodeLen[12]) { + if (bitField < decodeLen[10]) + if (bitField < decodeLen[9]) + bits = 9; + else + bits = 10; + else if (bitField < decodeLen[11]) + bits = 11; + else + bits = 12; + } else { + if (bitField < decodeLen[14]) { + if (bitField < decodeLen[13]) { + bits = 13; + } else { + bits = 14; + } + } else { + bits = 15; + } + } + } + addbits(bits); + int N = dec.getDecodePos()[bits] + + (((int) bitField - decodeLen[bits - 1]) >>> (16 - bits)); + if (N >= dec.getMaxNum()) { + N = 0; + } + return (dec.getDecodeNum()[N]); + } + + protected boolean ReadTables20() throws IOException, RarException + { + byte[] BitLength = new byte[Compress.BC20]; + byte[] Table = new byte[Compress.MC20 * 4]; + int TableSize, N, I; + if (inAddr > readTop - 25) { + if (!unpReadBuf()) { + return (false); + } + } + int BitField = getbits(); + UnpAudioBlock = (BitField & 0x8000); + + if (0 == (BitField & 0x4000)) { + // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + Arrays.fill(UnpOldTable20, (byte) 0); + } + addbits(2); + + if (UnpAudioBlock != 0) { + UnpChannels = ((BitField >>> 12) & 3) + 1; + if (UnpCurChannel >= UnpChannels) { + UnpCurChannel = 0; + } + addbits(2); + TableSize = Compress.MC20 * UnpChannels; + } else { + TableSize = Compress.NC20 + Compress.DC20 + Compress.RC20; + } + for (I = 0; I < Compress.BC20; I++) { + BitLength[I] = (byte) (getbits() >>> 12); + addbits(4); + } + makeDecodeTables(BitLength, 0, BD, Compress.BC20); + I = 0; + while (I < TableSize) { + if (inAddr > readTop - 5) { + if (!unpReadBuf()) { + return (false); + } + } + int Number = decodeNumber(BD); + if (Number < 16) { + Table[I] = (byte) ((Number + UnpOldTable20[I]) & 0xf); + I++; + } else if (Number == 16) { + N = (getbits() >>> 14) + 3; + addbits(2); + while (N-- > 0 && I < TableSize) { + Table[I] = Table[I - 1]; + I++; + } + } else { + if (Number == 17) { + N = (getbits() >>> 13) + 3; + addbits(3); + } else { + N = (getbits() >>> 9) + 11; + addbits(7); + } + while (N-- > 0 && I < TableSize) + Table[I++] = 0; + } + } + if (inAddr > readTop) { + return (true); + } + if (UnpAudioBlock != 0) + for (I = 0; I < UnpChannels; I++) + makeDecodeTables(Table, I * Compress.MC20, MD[I], Compress.MC20); + else { + makeDecodeTables(Table, 0, LD, Compress.NC20); + makeDecodeTables(Table, Compress.NC20, DD, Compress.DC20); + makeDecodeTables(Table, Compress.NC20 + Compress.DC20, RD, + Compress.RC20); + } + // memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); + for (int i = 0; i < UnpOldTable20.length; i++) { + UnpOldTable20[i] = Table[i]; + } + return (true); + } + + protected void unpInitData20(boolean Solid) + { + if (!Solid) { + UnpChannelDelta = UnpCurChannel = 0; + UnpChannels = 1; + // memset(AudV,0,sizeof(AudV)); + Arrays.fill(AudV, new AudioVariables()); + // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + Arrays.fill(UnpOldTable20, (byte) 0); + } + } + + protected void ReadLastTables() throws IOException, RarException + { + if (readTop >= inAddr + 5) { + if (UnpAudioBlock != 0) { + if (decodeNumber(MD[UnpCurChannel]) == 256) { + ReadTables20(); + } + } else { + if (decodeNumber(LD) == 269) { + ReadTables20(); + } + } + } + } + + protected byte DecodeAudio(int Delta) + { + AudioVariables v = AudV[UnpCurChannel]; + v.setByteCount(v.getByteCount() + 1); + v.setD4(v.getD3()); + v.setD3(v.getD2());// ->D3=V->D2; + v.setD2(v.getLastDelta() - v.getD1());// ->D2=V->LastDelta-V->D1; + v.setD1(v.getLastDelta());// V->D1=V->LastDelta; + // int PCh=8*V->LastChar+V->K1*V->D1 +V->K2*V->D2 +V->K3*V->D3 + // +V->K4*V->D4+ V->K5*UnpChannelDelta; + int PCh = 8 * v.getLastChar() + v.getK1() * v.getD1(); + PCh += v.getK2() * v.getD2() + v.getK3() * v.getD3(); + PCh += v.getK4() * v.getD4() + v.getK5() * UnpChannelDelta; + PCh = (PCh >>> 3) & 0xFF; + + int Ch = PCh - Delta; + + int D = ((byte) Delta) << 3; + + v.getDif()[0] += Math.abs(D);// V->Dif[0]+=abs(D); + v.getDif()[1] += Math.abs(D - v.getD1());// V->Dif[1]+=abs(D-V->D1); + v.getDif()[2] += Math.abs(D + v.getD1());// V->Dif[2]+=abs(D+V->D1); + v.getDif()[3] += Math.abs(D - v.getD2());// V->Dif[3]+=abs(D-V->D2); + v.getDif()[4] += Math.abs(D + v.getD2());// V->Dif[4]+=abs(D+V->D2); + v.getDif()[5] += Math.abs(D - v.getD3());// V->Dif[5]+=abs(D-V->D3); + v.getDif()[6] += Math.abs(D + v.getD3());// V->Dif[6]+=abs(D+V->D3); + v.getDif()[7] += Math.abs(D - v.getD4());// V->Dif[7]+=abs(D-V->D4); + v.getDif()[8] += Math.abs(D + v.getD4());// V->Dif[8]+=abs(D+V->D4); + v.getDif()[9] += Math.abs(D - UnpChannelDelta);// V->Dif[9]+=abs(D-UnpChannelDelta); + v.getDif()[10] += Math.abs(D + UnpChannelDelta);// V->Dif[10]+=abs(D+UnpChannelDelta); + + v.setLastDelta((byte) (Ch - v.getLastChar())); + UnpChannelDelta = v.getLastDelta(); + v.setLastChar(Ch);// V->LastChar=Ch; + + if ((v.getByteCount() & 0x1F) == 0) { + int MinDif = v.getDif()[0], NumMinDif = 0; + v.getDif()[0] = 0;// ->Dif[0]=0; + for (int I = 1; I < v.getDif().length; I++) { + if (v.getDif()[I] < MinDif) { + MinDif = v.getDif()[I]; + NumMinDif = I; + } + v.getDif()[I] = 0; + } + switch (NumMinDif) { + case 1: + if (v.getK1() >= -16) { + v.setK1(v.getK1() - 1);// V->K1--; + } + break; + case 2: + if (v.getK1() < 16) { + v.setK1(v.getK1() + 1);// V->K1++; + } + break; + case 3: + if (v.getK2() >= -16) { + v.setK2(v.getK2() - 1);// V->K2--; + } + break; + case 4: + if (v.getK2() < 16) { + v.setK2(v.getK2() + 1);// V->K2++; + } + break; + case 5: + if (v.getK3() >= -16) { + v.setK3(v.getK3() - 1); + } + break; + case 6: + if (v.getK3() < 16) { + v.setK3(v.getK3() + 1); + } + break; + case 7: + if (v.getK4() >= -16) { + v.setK4(v.getK4() - 1); + } + break; + case 8: + if (v.getK4() < 16) { + v.setK4(v.getK4() + 1); + } + break; + case 9: + if (v.getK5() >= -16) { + v.setK5(v.getK5() - 1); + } + break; + case 10: + if (v.getK5() < 16) { + v.setK5(v.getK5() + 1); + } + break; + } + } + return ((byte) Ch); + } + +} diff --git a/src/com/innosystec/unrar/unpack/UnpackFilter.java b/src/com/innosystec/unrar/unpack/UnpackFilter.java new file mode 100644 index 0000000..732b2f4 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/UnpackFilter.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack; + +import com.innosystec.unrar.unpack.vm.VMPreparedProgram; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class UnpackFilter { + + private int BlockStart; + + private int BlockLength; + + private int ExecCount; + + private boolean NextWindow; + + // position of parent filter in Filters array used as prototype for filter + // in PrgStack array. Not defined for filters in Filters array. + private int ParentFilter; + + private VMPreparedProgram Prg = new VMPreparedProgram(); + + public int getBlockLength() { + return BlockLength; + } + + public void setBlockLength(int blockLength) { + BlockLength = blockLength; + } + + public int getBlockStart() { + return BlockStart; + } + + public void setBlockStart(int blockStart) { + BlockStart = blockStart; + } + + public int getExecCount() { + return ExecCount; + } + + public void setExecCount(int execCount) { + ExecCount = execCount; + } + + public boolean isNextWindow() { + return NextWindow; + } + + public void setNextWindow(boolean nextWindow) { + NextWindow = nextWindow; + } + + public int getParentFilter() { + return ParentFilter; + } + + public void setParentFilter(int parentFilter) { + ParentFilter = parentFilter; + } + + public VMPreparedProgram getPrg() { + return Prg; + } + + public void setPrg(VMPreparedProgram prg) { + Prg = prg; + } + + + +} diff --git a/src/com/innosystec/unrar/unpack/decode/AudioVariables.java b/src/com/innosystec/unrar/unpack/decode/AudioVariables.java new file mode 100644 index 0000000..b8371bf --- /dev/null +++ b/src/com/innosystec/unrar/unpack/decode/AudioVariables.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class AudioVariables { + int k1, k2, k3, k4, k5; + + int d1, d2, d3, d4; + + int lastDelta; + + int dif[] = new int[11]; + + int byteCount; + + int lastChar; + + public int getByteCount() { + return byteCount; + } + + public void setByteCount(int byteCount) { + this.byteCount = byteCount; + } + + public int getD1() { + return d1; + } + + public void setD1(int d1) { + this.d1 = d1; + } + + public int getD2() { + return d2; + } + + public void setD2(int d2) { + this.d2 = d2; + } + + public int getD3() { + return d3; + } + + public void setD3(int d3) { + this.d3 = d3; + } + + public int getD4() { + return d4; + } + + public void setD4(int d4) { + this.d4 = d4; + } + + public int[] getDif() { + return dif; + } + + public void setDif(int[] dif) { + this.dif = dif; + } + + public int getK1() { + return k1; + } + + public void setK1(int k1) { + this.k1 = k1; + } + + public int getK2() { + return k2; + } + + public void setK2(int k2) { + this.k2 = k2; + } + + public int getK3() { + return k3; + } + + public void setK3(int k3) { + this.k3 = k3; + } + + public int getK4() { + return k4; + } + + public void setK4(int k4) { + this.k4 = k4; + } + + public int getK5() { + return k5; + } + + public void setK5(int k5) { + this.k5 = k5; + } + + public int getLastChar() { + return lastChar; + } + + public void setLastChar(int lastChar) { + this.lastChar = lastChar; + } + + public int getLastDelta() { + return lastDelta; + } + + public void setLastDelta(int lastDelta) { + this.lastDelta = lastDelta; + } + + +} diff --git a/src/com/innosystec/unrar/unpack/decode/BitDecode.java b/src/com/innosystec/unrar/unpack/decode/BitDecode.java new file mode 100644 index 0000000..78048cd --- /dev/null +++ b/src/com/innosystec/unrar/unpack/decode/BitDecode.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class BitDecode extends Decode +{ + /** + * + */ + public BitDecode() + { + decodeNum = new int[Compress.BC]; + } +} diff --git a/src/com/innosystec/unrar/unpack/decode/CodeType.java b/src/com/innosystec/unrar/unpack/decode/CodeType.java new file mode 100644 index 0000000..bda916c --- /dev/null +++ b/src/com/innosystec/unrar/unpack/decode/CodeType.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.decode; + +/** + * DOCUMENT ME + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class CodeType +{ + public static final int CODE_HUFFMAN = 0, + CODE_LZ = 1, + CODE_LZ2 = 2, + CODE_REPEATLZ = 3, + CODE_CACHELZ = 4, + CODE_STARTFILE = 5, + CODE_ENDFILE = 6, + CODE_VM = 7, + CODE_VMDATA = 8; +} diff --git a/src/com/innosystec/unrar/unpack/decode/Compress.java b/src/com/innosystec/unrar/unpack/decode/Compress.java new file mode 100644 index 0000000..47c1a1c --- /dev/null +++ b/src/com/innosystec/unrar/unpack/decode/Compress.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class Compress +{ + public static int CODEBUFSIZE = 0x4000; + public static int MAXWINSIZE = 0x100000; + public static int MAXWINMASK = (MAXWINSIZE-1); + + public static final int LOW_DIST_REP_COUNT = 16; + + public static final int NC = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public static final int DC = 60; + public static final int LDC = 17; + public static final int RC = 28; + public static final int HUFF_TABLE_SIZE = (NC+DC+RC+LDC); + public static final int BC = 20; + + public static final int NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public static final int DC20 = 48; + public static final int RC20 = 28; + public static final int BC20 = 19; + public static final int MC20 = 257; +} diff --git a/src/com/innosystec/unrar/unpack/decode/Decode.java b/src/com/innosystec/unrar/unpack/decode/Decode.java new file mode 100644 index 0000000..83285ea --- /dev/null +++ b/src/com/innosystec/unrar/unpack/decode/Decode.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.decode; + +/** + * Used to store information for lz decoding + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class Decode +{ + private int maxNum; + + private final int[] decodeLen = new int[16]; + + private final int[] decodePos = new int[16]; + + protected int[] decodeNum = new int[2]; + + /** + * returns the decode Length array + * @return decodeLength + */ + public int[] getDecodeLen() + { + return decodeLen; + } + + /** + * returns the decode num array + * @return decodeNum + */ + public int[] getDecodeNum() + { + return decodeNum; + } + + /** + * returns the decodePos array + * @return decodePos + */ + public int[] getDecodePos() + { + return decodePos; + } + + /** + * returns the max num + * @return maxNum + */ + public int getMaxNum() + { + return maxNum; + } + + /** + * sets the max num + * @param maxNum to be set to maxNum + */ + public void setMaxNum(int maxNum) + { + this.maxNum = maxNum; + } + +} diff --git a/src/com/innosystec/unrar/unpack/decode/DistDecode.java b/src/com/innosystec/unrar/unpack/decode/DistDecode.java new file mode 100644 index 0000000..12fe79a --- /dev/null +++ b/src/com/innosystec/unrar/unpack/decode/DistDecode.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class DistDecode extends Decode +{ + + /** + * + */ + public DistDecode() + { + decodeNum = new int[Compress.DC]; + } + +} diff --git a/src/com/innosystec/unrar/unpack/decode/FilterType.java b/src/com/innosystec/unrar/unpack/decode/FilterType.java new file mode 100644 index 0000000..2b93d35 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/decode/FilterType.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class FilterType +{ + public static final int FILTER_NONE = 0, + FILTER_PPM /*dummy*/ = 1, + FILTER_E8 = 2, + FILTER_E8E9 = 3, + FILTER_UPCASETOLOW = 4, + FILTER_AUDIO = 5, + FILTER_RGB = 6, + FILTER_DELTA = 7, + FILTER_ITANIUM = 8, + FILTER_E8E9V2 = 9; +} diff --git a/src/com/innosystec/unrar/unpack/decode/LitDecode.java b/src/com/innosystec/unrar/unpack/decode/LitDecode.java new file mode 100644 index 0000000..8b38e8b --- /dev/null +++ b/src/com/innosystec/unrar/unpack/decode/LitDecode.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class LitDecode extends Decode +{ + /** + * + */ + public LitDecode() + { + decodeNum = new int[Compress.NC]; + } + +} diff --git a/src/com/innosystec/unrar/unpack/decode/LowDistDecode.java b/src/com/innosystec/unrar/unpack/decode/LowDistDecode.java new file mode 100644 index 0000000..087b8d9 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/decode/LowDistDecode.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class LowDistDecode extends Decode +{ + + /** + * + */ + public LowDistDecode() + { + decodeNum = new int[Compress.LDC]; + } + +} diff --git a/src/com/innosystec/unrar/unpack/decode/MultDecode.java b/src/com/innosystec/unrar/unpack/decode/MultDecode.java new file mode 100644 index 0000000..7c6c8c4 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/decode/MultDecode.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class MultDecode extends Decode +{ + + /** + * + */ + public MultDecode() + { + decodeNum = new int[Compress.MC20]; + } + +} diff --git a/src/com/innosystec/unrar/unpack/decode/RepDecode.java b/src/com/innosystec/unrar/unpack/decode/RepDecode.java new file mode 100644 index 0000000..aab771e --- /dev/null +++ b/src/com/innosystec/unrar/unpack/decode/RepDecode.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RepDecode extends Decode +{ + /** + * + */ + public RepDecode() + { + decodeNum = new int[Compress.RC]; + } + +} diff --git a/src/com/innosystec/unrar/unpack/ppm/BlockTypes.java b/src/com/innosystec/unrar/unpack/ppm/BlockTypes.java new file mode 100644 index 0000000..bb4679d --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/BlockTypes.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class BlockTypes +{ + public static final int BLOCK_LZ = (0), BLOCK_PPM = (1); + + private int blockType; + + private BlockTypes(int blockType) + { + this.blockType = blockType; + } + + public int getBlockType() + { + return blockType; + } + + public boolean equals(int blockType) + { + return this.blockType == blockType; + } + + public static int findBlockType(int blockType) + { + return blockType; + } +} diff --git a/src/com/innosystec/unrar/unpack/ppm/FreqData.java b/src/com/innosystec/unrar/unpack/ppm/FreqData.java new file mode 100644 index 0000000..a3f4770 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/FreqData.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + +import com.innosystec.unrar.io.Raw; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class FreqData extends Pointer{ + + public static final int size = 6; + +// struct FreqData +// { +// ushort SummFreq; +// STATE _PACK_ATTR * Stats; +// }; + + public FreqData(byte[]mem){ + super(mem); + } + + public FreqData init(byte[] mem) { + this.mem = mem; + pos = 0; + return this; + } + + public int getSummFreq() { + return Raw.readShortLittleEndian(mem, pos)&0xffff; + } + + public void setSummFreq(int summFreq) { + Raw.writeShortLittleEndian(mem, pos, (short)summFreq); + } + + public void incSummFreq(int dSummFreq) { + Raw.incShortLittleEndian(mem, pos, dSummFreq); + } + + public int getStats() { + return Raw.readIntLittleEndian(mem, pos+2); + } + + public void setStats(State state) { + setStats(state.getAddress()); + } + + public void setStats(int state) { + Raw.writeIntLittleEndian(mem, pos+2, state); + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("FreqData["); + buffer.append("\n pos="); + buffer.append(pos); + buffer.append("\n size="); + buffer.append(size); + buffer.append("\n summFreq="); + buffer.append(getSummFreq()); + buffer.append("\n stats="); + buffer.append(getStats()); + buffer.append("\n]"); + return buffer.toString(); + } + +} diff --git a/src/com/innosystec/unrar/unpack/ppm/ModelPPM.java b/src/com/innosystec/unrar/unpack/ppm/ModelPPM.java new file mode 100644 index 0000000..5109231 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/ModelPPM.java @@ -0,0 +1,771 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + +import com.classpath.util.Arrays; +import java.io.IOException; + +import com.innosystec.unrar.exception.RarException; +import com.innosystec.unrar.unpack.Unpack; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class ModelPPM +{ + public static final int MAX_O = 64; /* maximum allowed model order */ + + public static final int INT_BITS = 7; + public static final int PERIOD_BITS = 7; + public static final int TOT_BITS = INT_BITS + PERIOD_BITS; + public static final int INTERVAL = 1 << INT_BITS; + public static final int BIN_SCALE = 1 << TOT_BITS; + public static final int MAX_FREQ = 124; + private SEE2Context[][] SEE2Cont = new SEE2Context[25][16]; + private SEE2Context dummySEE2Cont; + private PPMContext minContext, medContext, maxContext; + private State foundState; // found next state transition + private int numMasked, initEsc, orderFall, maxOrder, runLength, initRL; + private int[] charMask = new int[256]; + private int[] NS2Indx = new int[256]; + private int[] NS2BSIndx = new int[256]; + private int[] HB2Flag = new int[256]; + // byte EscCount, PrevSuccess, HiBitsFlag; + private int escCount, prevSuccess, hiBitsFlag; + private int[][] binSumm = new int[128][64]; // binary SEE-contexts + private RangeCoder coder = new RangeCoder(); + private SubAllocator subAlloc = new SubAllocator(); + private static int InitBinEsc[] = + { + 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, + 0x64A1, 0x5ABC, 0x6632, 0x6051 + }; + // Temp fields + private final State tempState1 = new State(null); + private final State tempState2 = new State(null); + private final State tempState3 = new State(null); + private final State tempState4 = new State(null); + private final StateRef tempStateRef1 = new StateRef(); + private final StateRef tempStateRef2 = new StateRef(); + private final PPMContext tempPPMContext1 = new PPMContext(null); + private final PPMContext tempPPMContext2 = new PPMContext(null); + private final PPMContext tempPPMContext3 = new PPMContext(null); + private final PPMContext tempPPMContext4 = new PPMContext(null); + private final int[] ps = new int[MAX_O]; + + public ModelPPM() + { + minContext = null; + maxContext = null; + medContext = null; + } + + public SubAllocator getSubAlloc() + { + return subAlloc; + } + + private void restartModelRare() + { + Arrays.fill(charMask, 0); + subAlloc.initSubAllocator(); + initRL = -(maxOrder < 12 ? maxOrder : 12) - 1; + int addr = subAlloc.allocContext(); + minContext.setAddress(addr); + maxContext.setAddress(addr); + minContext.setSuffix(0); + orderFall = maxOrder; + minContext.setNumStats(256); + minContext.getFreqData().setSummFreq(minContext.getNumStats() + 1); + + addr = subAlloc.allocUnits(256 / 2); + foundState.setAddress(addr); + minContext.getFreqData().setStats(addr); + + State state = new State(subAlloc.getHeap()); + addr = minContext.getFreqData().getStats(); + runLength = initRL; + prevSuccess = 0; + for(int i = 0; i < 256; i++) + { + state.setAddress(addr + i * State.size); + state.setSymbol(i); + state.setFreq(1); + state.setSuccessor(0); + } + + for(int i = 0; i < 128; i++) + { + for(int k = 0; k < 8; k++) + { + for(int m = 0; m < 64; m += 8) + { + binSumm[i][k + m] = BIN_SCALE - InitBinEsc[k] / (i + 2); + } + } + } + for(int i = 0; i < 25; i++) + { + for(int k = 0; k < 16; k++) + { + SEE2Cont[i][k].init(5 * i + 10); + } + } + } + + private void startModelRare(int MaxOrder) + { + int i, k, m, Step; + escCount = 1; + this.maxOrder = MaxOrder; + restartModelRare(); + // Bug Fixed + NS2BSIndx[0] = 0; + NS2BSIndx[1] = 2; + for(int j = 0; j < 9; j++) + { + NS2BSIndx[2 + j] = 4; + } + for(int j = 0; j < 256 - 11; j++) + { + NS2BSIndx[11 + j] = 6; + } + for(i = 0; i < 3; i++) + { + NS2Indx[i] = i; + } + for(m = i, k = 1, Step = 1; i < 256; i++) + { + NS2Indx[i] = m; + if((--k) == 0) + { + k = ++Step; + m++; + } + } + for(int j = 0; j < 0x40; j++) + { + HB2Flag[j] = 0; + } + for(int j = 0; j < 0x100 - 0x40; j++) + { + HB2Flag[0x40 + j] = 0x08; + } + dummySEE2Cont.setShift(PERIOD_BITS); + + } + + private void clearMask() + { + escCount = 1; + Arrays.fill(charMask, 0); + } + + public boolean decodeInit(Unpack unpackRead, int escChar/* ref */) + throws IOException, RarException + { + + int MaxOrder = unpackRead.getChar() & 0xff; + boolean reset = ((MaxOrder & 0x20) != 0); + + int MaxMB = 0; + if(reset) + { + MaxMB = unpackRead.getChar(); + } + else + { + if(subAlloc.GetAllocatedMemory() == 0) + { + return (false); + } + } + if((MaxOrder & 0x40) != 0) + { + escChar = unpackRead.getChar(); + unpackRead.setPpmEscChar(escChar); + } + coder.initDecoder(unpackRead); + if(reset) + { + MaxOrder = (MaxOrder & 0x1f) + 1; + if(MaxOrder > 16) + { + MaxOrder = 16 + (MaxOrder - 16) * 3; + } + if(MaxOrder == 1) + { + subAlloc.stopSubAllocator(); + return (false); + } + subAlloc.startSubAllocator(MaxMB + 1); + minContext = new PPMContext(getHeap()); + medContext = new PPMContext(getHeap()); + maxContext = new PPMContext(getHeap()); + foundState = new State(getHeap()); + dummySEE2Cont = new SEE2Context(); + for(int i = 0; i < 25; i++) + { + for(int j = 0; j < 16; j++) + { + SEE2Cont[i][j] = new SEE2Context(); + } + } + startModelRare(MaxOrder); + } + return (minContext.getAddress() != 0); + } + + public int decodeChar() throws IOException, RarException + { + // Debug + //subAlloc.dumpHeap(); + + if(minContext.getAddress() <= subAlloc.getPText() + || minContext.getAddress() > subAlloc.getHeapEnd()) + { + return (-1); + } + + if(minContext.getNumStats() != 1) + { + if(minContext.getFreqData().getStats() <= subAlloc.getPText() + || minContext.getFreqData().getStats() > subAlloc.getHeapEnd()) + { + return (-1); + } + if(!minContext.decodeSymbol1(this)) + { + return (-1); + } + } + else + { + minContext.decodeBinSymbol(this); + } + coder.decode(); + while(foundState.getAddress() == 0) + { + coder.ariDecNormalize(); + do + { + orderFall++; + minContext.setAddress(minContext.getSuffix());// =MinContext->Suffix; + if(minContext.getAddress() <= subAlloc.getPText() + || minContext.getAddress() > subAlloc.getHeapEnd()) + { + return (-1); + } + } + while(minContext.getNumStats() == numMasked); + if(!minContext.decodeSymbol2(this)) + { + return (-1); + } + coder.decode(); + } + int Symbol = foundState.getSymbol(); + if((orderFall == 0) && foundState.getSuccessor() > subAlloc.getPText()) + { + // MinContext=MaxContext=FoundState->Successor; + int addr = foundState.getSuccessor(); + minContext.setAddress(addr); + maxContext.setAddress(addr); + } + else + { + updateModel(); + //this.foundState.setAddress(foundState.getAddress());//TODO just 4 debugging + if(escCount == 0) + { + clearMask(); + } + } + coder.ariDecNormalize();// ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); + return (Symbol); + } + + public SEE2Context[][] getSEE2Cont() + { + return SEE2Cont; + } + + public SEE2Context getDummySEE2Cont() + { + return dummySEE2Cont; + } + + public int getInitRL() + { + return initRL; + } + + public void setEscCount(int escCount) + { + this.escCount = escCount & 0xff; + } + + public int getEscCount() + { + return escCount; + } + + public void incEscCount(int dEscCount) + { + setEscCount(getEscCount() + dEscCount); + } + + public int[] getCharMask() + { + return charMask; + } + + public int getNumMasked() + { + return numMasked; + } + + public void setNumMasked(int numMasked) + { + this.numMasked = numMasked; + } + + public void setPrevSuccess(int prevSuccess) + { + this.prevSuccess = prevSuccess & 0xff; + } + + public int getInitEsc() + { + return initEsc; + } + + public void setInitEsc(int initEsc) + { + this.initEsc = initEsc; + } + + public void setRunLength(int runLength) + { + this.runLength = runLength; + } + + public int getRunLength() + { + return runLength; + } + + public void incRunLength(int dRunLength) + { + setRunLength(getRunLength() + dRunLength); + } + + public int getPrevSuccess() + { + return prevSuccess; + } + + public int getHiBitsFlag() + { + return hiBitsFlag; + } + + public void setHiBitsFlag(int hiBitsFlag) + { + this.hiBitsFlag = hiBitsFlag & 0xff; + } + + public int[][] getBinSumm() + { + return binSumm; + } + + public RangeCoder getCoder() + { + return coder; + } + + public int[] getHB2Flag() + { + return HB2Flag; + } + + public int[] getNS2BSIndx() + { + return NS2BSIndx; + } + + public int[] getNS2Indx() + { + return NS2Indx; + } + + public State getFoundState() + { + return foundState; + } + + public byte[] getHeap() + { + return subAlloc.getHeap(); + } + + public int getOrderFall() + { + return orderFall; + } + + private int /* ppmcontext ptr */ createSuccessors(boolean Skip, + State p1 /* state ptr */) + { + //State upState = tempState1.init(null); + StateRef upState = tempStateRef2; + State tempState = tempState1.init(getHeap()); + + // PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor; + PPMContext pc = tempPPMContext1.init(getHeap()); + pc.setAddress(minContext.getAddress()); + PPMContext upBranch = tempPPMContext2.init(getHeap()); + upBranch.setAddress(foundState.getSuccessor()); + + // STATE * p, * ps[MAX_O], ** pps=ps; + State p = tempState2.init(getHeap()); + int pps = 0; + + boolean noLoop = false; + + if(!Skip) + { + ps[pps++] = foundState.getAddress();// *pps++ = FoundState; + if(pc.getSuffix() == 0) + { + noLoop = true; + } + } + if(!noLoop) + { + boolean loopEntry = false; + if(p1.getAddress() != 0) + { + p.setAddress(p1.getAddress()); + pc.setAddress(pc.getSuffix());// =pc->Suffix; + loopEntry = true; + } + do + { + if(!loopEntry) + { + pc.setAddress(pc.getSuffix());// pc=pc->Suffix; + if(pc.getNumStats() != 1) + { + p.setAddress(pc.getFreqData().getStats());// p=pc->U.Stats + if(p.getSymbol() != foundState.getSymbol()) + { + do + { + p.incAddress(); + } + while(p.getSymbol() != foundState.getSymbol()); + } + } + else + { + p.setAddress(pc.getOneState().getAddress());// p=&(pc->OneState); + } + }// LOOP_ENTRY: + loopEntry = false; + if(p.getSuccessor() != upBranch.getAddress()) + { + pc.setAddress(p.getSuccessor());// =p->Successor; + break; + } + ps[pps++] = p.getAddress(); + } + while(pc.getSuffix() != 0); + + } // NO_LOOP: + if(pps == 0) + { + return pc.getAddress(); + } + upState.setSymbol(getHeap()[upBranch.getAddress()]);// UpState.Symbol=*(byte*) + // UpBranch; + // UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1); + upState.setSuccessor(upBranch.getAddress() + 1); //TODO check if +1 necessary + if(pc.getNumStats() != 1) + { + if(pc.getAddress() <= subAlloc.getPText()) + { + return (0); + } + p.setAddress(pc.getFreqData().getStats()); + if(p.getSymbol() != upState.getSymbol()) + { + do + { + p.incAddress(); + } + while(p.getSymbol() != upState.getSymbol()); + } + int cf = p.getFreq() - 1; + int s0 = pc.getFreqData().getSummFreq() - pc.getNumStats() - cf; + // UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0))); + upState.setFreq(1 + ((2 * cf <= s0) ? (5 * cf > s0 ? 1 : 0) + : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); + } + else + { + upState.setFreq(pc.getOneState().getFreq());// UpState.Freq=pc->OneState.Freq; + } + do + { + // pc = pc->createChild(this,*--pps,UpState); + tempState.setAddress(ps[--pps]); + pc.setAddress(pc.createChild(this, tempState, upState)); + if(pc.getAddress() == 0) + { + return 0; + } + } + while(pps != 0); + return pc.getAddress(); + } + + private void updateModelRestart() + { + restartModelRare(); + escCount = 0; + } + + private void updateModel() + { + //System.out.println("ModelPPM.updateModel()"); + // STATE fs = *FoundState, *p = NULL; + StateRef fs = tempStateRef1; + fs.setValues(foundState); + State p = tempState3.init(getHeap()); + State tempState = tempState4.init(getHeap()); + + PPMContext pc = tempPPMContext3.init(getHeap()); + PPMContext successor = tempPPMContext4.init(getHeap()); + + int ns1, ns, cf, sf, s0; + pc.setAddress(minContext.getSuffix()); + if(fs.getFreq() < MAX_FREQ / 4 && pc.getAddress() != 0) + { + if(pc.getNumStats() != 1) + { + p.setAddress(pc.getFreqData().getStats()); + if(p.getSymbol() != fs.getSymbol()) + { + do + { + p.incAddress(); + } + while(p.getSymbol() != fs.getSymbol()); + tempState.setAddress(p.getAddress() - State.size); + if(p.getFreq() >= tempState.getFreq()) + { + State.ppmdSwap(p, tempState); + p.decAddress(); + } + } + if(p.getFreq() < MAX_FREQ - 9) + { + p.incFreq(2); + pc.getFreqData().incSummFreq(2); + } + } + else + { + p.setAddress(pc.getOneState().getAddress()); + if(p.getFreq() < 32) + { + p.incFreq(1); + } + } + } + if(orderFall == 0) + { + foundState.setSuccessor(createSuccessors(true, p)); + minContext.setAddress(foundState.getSuccessor()); + maxContext.setAddress(foundState.getSuccessor()); + if(minContext.getAddress() == 0) + { + updateModelRestart(); + return; + } + return; + } + subAlloc.getHeap()[subAlloc.getPText()] = (byte) fs.getSymbol(); + subAlloc.incPText(); + successor.setAddress(subAlloc.getPText()); + if(subAlloc.getPText() >= subAlloc.getFakeUnitsStart()) + { + updateModelRestart(); + return; + } +// // Debug +// subAlloc.dumpHeap(); + if(fs.getSuccessor() != 0) + { + if(fs.getSuccessor() <= subAlloc.getPText()) + { + fs.setSuccessor(createSuccessors(false, p)); + if(fs.getSuccessor() == 0) + { + updateModelRestart(); + return; + } + } + if(--orderFall == 0) + { + successor.setAddress(fs.getSuccessor()); + if(maxContext.getAddress() != minContext.getAddress()) + { + subAlloc.decPText(1); + } + } + } + else + { + foundState.setSuccessor(successor.getAddress()); + fs.setSuccessor(minContext); + } +// // Debug +// subAlloc.dumpHeap(); + ns = minContext.getNumStats(); + s0 = minContext.getFreqData().getSummFreq() - (ns) - (fs.getFreq() - 1); + for(pc.setAddress(maxContext.getAddress()); + pc.getAddress() != minContext.getAddress(); + pc.setAddress(pc.getSuffix())) + { + if((ns1 = pc.getNumStats()) != 1) + { + if((ns1 & 1) == 0) + { + //System.out.println(ns1); + pc.getFreqData().setStats( + subAlloc.expandUnits(pc.getFreqData().getStats(), + ns1 >>> 1)); + if(pc.getFreqData().getStats() == 0) + { + updateModelRestart(); + return; + } + } + // bug fixed +// int sum = ((2 * ns1 < ns) ? 1 : 0) + +// 2 * ((4 * ((ns1 <= ns) ? 1 : 0)) & ((pc.getFreqData() +// .getSummFreq() <= 8 * ns1) ? 1 : 0)); + int sum = ((2 * ns1 < ns) ? 1 : 0) + 2 * (((4 * ns1 <= ns) ? 1 : 0) + & ((pc.getFreqData().getSummFreq() <= 8 * ns1) ? 1 : 0)); + pc.getFreqData().incSummFreq(sum); + } + else + { + p.setAddress(subAlloc.allocUnits(1)); + if(p.getAddress() == 0) + { + updateModelRestart(); + return; + } + p.setValues(pc.getOneState()); + pc.getFreqData().setStats(p); + if(p.getFreq() < MAX_FREQ / 4 - 1) + { + p.incFreq(p.getFreq()); + } + else + { + p.setFreq(MAX_FREQ - 4); + } + pc.getFreqData().setSummFreq( + (p.getFreq() + initEsc + (ns > 3 ? 1 : 0))); + } + cf = 2 * fs.getFreq() * (pc.getFreqData().getSummFreq() + 6); + sf = s0 + pc.getFreqData().getSummFreq(); + if(cf < 6 * sf) + { + cf = 1 + (cf > sf ? 1 : 0) + (cf >= 4 * sf ? 1 : 0); + pc.getFreqData().incSummFreq(3); + } + else + { + cf = 4 + (cf >= 9 * sf ? 1 : 0) + (cf >= 12 * sf ? 1 : 0) + + (cf >= 15 * sf ? 1 : 0); + pc.getFreqData().incSummFreq(cf); + } + p.setAddress(pc.getFreqData().getStats() + ns1 * State.size); + p.setSuccessor(successor); + p.setSymbol(fs.getSymbol()); + p.setFreq(cf); + pc.setNumStats(++ns1); + } + + int address = fs.getSuccessor(); + maxContext.setAddress(address); + minContext.setAddress(address); + //TODO-----debug +// int pos = minContext.getFreqData().getStats(); +// State a = new State(getHeap()); +// a.setAddress(pos); +// pos+=State.size; +// a.setAddress(pos); +//--dbg end + return; + } + + // Debug + public String toString() + { + StringBuffer buffer = new StringBuffer(); + buffer.append("ModelPPM["); + buffer.append("\n numMasked="); + buffer.append(numMasked); + buffer.append("\n initEsc="); + buffer.append(initEsc); + buffer.append("\n orderFall="); + buffer.append(orderFall); + buffer.append("\n maxOrder="); + buffer.append(maxOrder); + buffer.append("\n runLength="); + buffer.append(runLength); + buffer.append("\n initRL="); + buffer.append(initRL); + buffer.append("\n escCount="); + buffer.append(escCount); + buffer.append("\n prevSuccess="); + buffer.append(prevSuccess); + buffer.append("\n foundState="); + buffer.append(foundState); + buffer.append("\n coder="); + buffer.append(coder); + buffer.append("\n subAlloc="); + buffer.append(subAlloc); + buffer.append("\n]"); + return buffer.toString(); + } + // Debug +// public void dumpHeap() { +// subAlloc.dumpHeap(); +// } +} diff --git a/src/com/innosystec/unrar/unpack/ppm/PPMContext.java b/src/com/innosystec/unrar/unpack/ppm/PPMContext.java new file mode 100644 index 0000000..a72f899 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/PPMContext.java @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + +import com.innosystec.unrar.io.Raw; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class PPMContext extends Pointer +{ + + private static final int unionSize = Math.max(FreqData.size, State.size); + + public static final int size = 2 + unionSize + 4; // 12 + + // ushort NumStats; + private int numStats; // determines if feqData or onstate is used + + // (1==onestate) + + private final FreqData freqData; // -\ + + // |-> union + private final State oneState; // -/ + + private int suffix; // pointer ppmcontext + + public final static int[] ExpEscape = + { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; + + // Temp fields + private final State tempState1 = new State(null); + private final State tempState2 = new State(null); + private final State tempState3 = new State(null); + private final State tempState4 = new State(null); + private final State tempState5 = new State(null); + private PPMContext tempPPMContext = null; + private final int[] ps = new int[256]; + + public PPMContext(byte[] mem) + { + super(mem); + oneState = new State(mem); + freqData = new FreqData(mem); + } + + public PPMContext init(byte[] mem) { + this.mem = mem; + pos = 0; + oneState.init(mem); + freqData.init(mem); + return this; + } + + public FreqData getFreqData() + { + return freqData; + } + + public void setFreqData(FreqData freqData) + { + this.freqData.setSummFreq(freqData.getSummFreq()); + this.freqData.setStats(freqData.getStats()); + } + + public final int getNumStats() + { + if (mem!=null){ + numStats = Raw.readShortLittleEndian(mem, pos)&0xffff; + } + return numStats; + } + + public final void setNumStats(int numStats) + { + this.numStats = numStats&0xffff; + if (mem != null) { + Raw.writeShortLittleEndian(mem, pos, (short)numStats); + } + } + + public State getOneState() + { + return oneState; + } + + public void setOneState(StateRef oneState) + { + this.oneState.setValues(oneState); + } + + public int getSuffix() + { + if(mem!=null){ + suffix = Raw.readIntLittleEndian(mem, pos+8); + } + return suffix; + } + + public void setSuffix(PPMContext suffix) + { + setSuffix(suffix.getAddress()); + } + + public void setSuffix(int suffix) + { + this.suffix = suffix; + if (mem != null) { + Raw.writeIntLittleEndian(mem, pos + 8, suffix); + } + } + + public void setAddress(int pos) + { + super.setAddress(pos); + oneState.setAddress(pos+2); + freqData.setAddress(pos+2); + } + + private PPMContext getTempPPMContext(byte[] mem) { + if (tempPPMContext == null) { + tempPPMContext = new PPMContext(null); + } + return tempPPMContext.init(mem); + } + + public int createChild(ModelPPM model, State pStats/* ptr */, + StateRef firstState /* ref */) + { + PPMContext pc = getTempPPMContext(model.getSubAlloc().getHeap()); + pc.setAddress(model.getSubAlloc().allocContext()); + if (pc != null) { + pc.setNumStats(1); + pc.setOneState(firstState); + pc.setSuffix(this); + pStats.setSuccessor(pc); + } + return pc.getAddress(); + } + + public void rescale(ModelPPM model) + { + int OldNS = getNumStats(), i = getNumStats() - 1, Adder, EscFreq; + // STATE* p1, * p; + State p1 = new State(model.getHeap()); + State p = new State(model.getHeap()); + State temp = new State(model.getHeap()); + + for (p.setAddress(model.getFoundState().getAddress()); + p.getAddress() != freqData.getStats(); + p.decAddress()) { + temp.setAddress(p.getAddress() - State.size); + State.ppmdSwap(p, temp); + } + temp.setAddress(freqData.getStats()); + temp.incFreq(4); + freqData.incSummFreq(4); + EscFreq = freqData.getSummFreq() - p.getFreq(); + Adder = (model.getOrderFall() != 0) ? 1 : 0; + p.setFreq((p.getFreq() + Adder) >>> 1); + freqData.setSummFreq(p.getFreq()); + do { + p.incAddress(); + EscFreq -= p.getFreq(); + p.setFreq((p.getFreq() + Adder) >>> 1); + freqData.incSummFreq(p.getFreq()); + temp.setAddress(p.getAddress() - State.size); + if (p.getFreq() > temp.getFreq()) { + p1.setAddress(p.getAddress()); + StateRef tmp = new StateRef(); + tmp.setValues(p1); + State temp2 = new State(model.getHeap()); + State temp3 = new State(model.getHeap()); + do { + // p1[0]=p1[-1]; + temp2.setAddress(p1.getAddress() - State.size); + p1.setValues(temp2); + p1.decAddress(); + temp3.setAddress(p1.getAddress() - State.size); + } while (p1.getAddress() != freqData.getStats() && tmp.getFreq() > temp3.getFreq()); + p1.setValues(tmp); + } + } while (--i != 0); + if (p.getFreq() == 0) { + do { + i++; + p.decAddress(); + } while (p.getFreq() == 0); + EscFreq += i; + setNumStats(getNumStats() - i); + if (getNumStats() == 1) { + StateRef tmp = new StateRef(); + temp.setAddress(freqData.getStats()); + tmp.setValues(temp); + // STATE tmp=*U.Stats; + do { + // tmp.Freq-=(tmp.Freq >> 1) + tmp.decFreq(tmp.getFreq() >>> 1); + EscFreq >>>= 1; + } while (EscFreq > 1); + model.getSubAlloc().freeUnits(freqData.getStats(),(OldNS + 1) >>> 1); + oneState.setValues(tmp); + model.getFoundState().setAddress(oneState.getAddress()); + return; + } + } + EscFreq -= EscFreq >>> 1; + freqData.incSummFreq(EscFreq); + int n0 = (OldNS + 1) >>> 1, n1 = (getNumStats() + 1) >>> 1; + if (n0 != n1) { + freqData.setStats(model.getSubAlloc().shrinkUnits(freqData.getStats(), n0, n1)); + } + model.getFoundState().setAddress(freqData.getStats()); + } + + private int getArrayIndex(ModelPPM Model, State rs) + { + PPMContext tempSuffix = getTempPPMContext(Model.getSubAlloc().getHeap()); + tempSuffix.setAddress(getSuffix()); + int ret = 0; + ret += Model.getPrevSuccess(); + ret += Model.getNS2BSIndx()[tempSuffix.getNumStats() - 1]; + ret += Model.getHiBitsFlag() + 2* Model.getHB2Flag()[rs.getSymbol()]; + ret += ((Model.getRunLength() >>> 26) & 0x20); + return ret; + } + + public int getMean(int summ, int shift, int round) + { + return ( (summ + (1 << (shift - round) ) ) >>> (shift) ); + } + + public void decodeBinSymbol(ModelPPM model) + { + State rs = tempState1.init(model.getHeap()); + rs.setAddress(oneState.getAddress());// State& + model.setHiBitsFlag(model.getHB2Flag()[model.getFoundState().getSymbol()]); + int off1 = rs.getFreq() - 1; + int off2 = getArrayIndex(model, rs); + int bs = model.getBinSumm()[off1][off2]; + if (model.getCoder().getCurrentShiftCount(ModelPPM.TOT_BITS) < bs) { + model.getFoundState().setAddress(rs.getAddress()); + rs.incFreq((rs.getFreq() < 128) ? 1 : 0); + model.getCoder().getSubRange().setLowCount(0); + model.getCoder().getSubRange().setHighCount(bs); + bs = ((bs + ModelPPM.INTERVAL - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xffff); + model.getBinSumm()[off1][off2] = bs; + model.setPrevSuccess(1); + model.incRunLength(1); + } else { + model.getCoder().getSubRange().setLowCount(bs); + bs = (bs - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xFFFF; + model.getBinSumm()[off1][off2] = bs; + model.getCoder().getSubRange().setHighCount(ModelPPM.BIN_SCALE); + model.setInitEsc(ExpEscape[bs >>> 10]); + model.setNumMasked(1); + model.getCharMask()[rs.getSymbol()] = model.getEscCount(); + model.setPrevSuccess(0); + model.getFoundState().setAddress(0); + } + //int a = 0;//TODO just 4 debugging + } + +// public static void ppmdSwap(ModelPPM model, StatePtr state1, StatePtr state2) +// { +// byte[] bytes = model.getSubAlloc().getHeap(); +// int p1 = state1.getAddress(); +// int p2 = state2.getAddress(); +// +// for (int i = 0; i < StatePtr.size; i++) { +// byte temp = bytes[p1+i]; +// bytes[p1+i] = bytes[p2+i]; +// bytes[p2+i] = temp; +// } +// state1.setAddress(p1); +// state2.setAddress(p2); +// } + + public void update1(ModelPPM model, int p/* ptr */) + { + model.getFoundState().setAddress(p); + model.getFoundState().incFreq(4); + freqData.incSummFreq(4); + State p0 = tempState3.init(model.getHeap()); + State p1 = tempState4.init(model.getHeap()); + p0.setAddress(p); + p1.setAddress(p - State.size); + if (p0.getFreq() > p1.getFreq()) { + State.ppmdSwap(p0, p1); + model.getFoundState().setAddress(p1.getAddress()); + if (p1.getFreq() > ModelPPM.MAX_FREQ) + rescale(model); + } + } + + public boolean decodeSymbol2(ModelPPM model) + { + long count; + int hiCnt, i = getNumStats() - model.getNumMasked(); + SEE2Context psee2c = makeEscFreq2(model, i); + RangeCoder coder = model.getCoder(); + // STATE* ps[256], ** pps=ps, * p=U.Stats-1; + State p = tempState1.init(model.getHeap()); + State temp = tempState2.init(model.getHeap()); + p.setAddress(freqData.getStats() - State.size); + int pps = 0; + hiCnt = 0; + + do { + do { + p.incAddress();// p++; + } while (model.getCharMask()[p.getSymbol()] == model.getEscCount()); + hiCnt += p.getFreq(); + ps[pps++] = p.getAddress(); + } while (--i != 0); + coder.getSubRange().incScale(hiCnt); + count = coder.getCurrentCount(); + if (count >= coder.getSubRange().getScale()) { + return false; + } + pps = 0; + p.setAddress(ps[pps]); + if (count < hiCnt) { + hiCnt = 0; + while ((hiCnt += p.getFreq()) <= count) { + p.setAddress(ps[++pps]);// p=*++pps; + } + coder.getSubRange().setHighCount(hiCnt); + coder.getSubRange().setLowCount(hiCnt - p.getFreq()); + psee2c.update(); + update2(model, p.getAddress()); + } else { + coder.getSubRange().setLowCount(hiCnt); + coder.getSubRange().setHighCount(coder.getSubRange().getScale()); + i = getNumStats() - model.getNumMasked();// ->NumMasked; + pps--; + do { + temp.setAddress(ps[++pps]);// (*++pps) + model.getCharMask()[temp.getSymbol()] = model.getEscCount(); + } while (--i != 0); + psee2c.incSumm((int)coder.getSubRange().getScale()); + model.setNumMasked(getNumStats()); + } + return (true); + } + + public void update2(ModelPPM model, int p/* state ptr */) + { + State temp = tempState5.init(model.getHeap()); + temp.setAddress(p); + model.getFoundState().setAddress(p); + model.getFoundState().incFreq(4); + freqData.incSummFreq(4); + if (temp.getFreq() > ModelPPM.MAX_FREQ) { + rescale(model); + } + model.incEscCount(1); + model.setRunLength(model.getInitRL()); + } + + private SEE2Context makeEscFreq2(ModelPPM model, int Diff) + { + SEE2Context psee2c; + int numStats = getNumStats(); + if (numStats != 256) { + PPMContext suff = getTempPPMContext(model.getHeap()); + suff.setAddress(getSuffix()); + int idx1 = model.getNS2Indx()[Diff - 1]; + int idx2 = 0; + idx2 += (Diff < suff.getNumStats() - numStats) ? 1 : 0; + idx2 += 2 * ((freqData.getSummFreq() < 11 * numStats) ? 1 : 0); + idx2 += 4 * ((model.getNumMasked() > Diff) ? 1 : 0); + idx2 += model.getHiBitsFlag(); + psee2c = model.getSEE2Cont()[idx1][idx2]; + model.getCoder().getSubRange().setScale(psee2c.getMean()); + } else { + psee2c = model.getDummySEE2Cont(); + model.getCoder().getSubRange().setScale(1); + } + return psee2c; + } + + public boolean decodeSymbol1(ModelPPM model) + { + + RangeCoder coder = model.getCoder(); + coder.getSubRange().setScale(freqData.getSummFreq()); + State p = new State(model.getHeap()); + p.setAddress(freqData.getStats()); + int i, HiCnt; + long count = coder.getCurrentCount(); + if (count >= coder.getSubRange().getScale()) { + return false; + } + if (count < (HiCnt = p.getFreq())) { + coder.getSubRange().setHighCount(HiCnt); + model.setPrevSuccess((2 * HiCnt > coder.getSubRange().getScale()) ? 1 : 0); + model.incRunLength(model.getPrevSuccess()); + HiCnt += 4; + model.getFoundState().setAddress(p.getAddress()); + model.getFoundState().setFreq(HiCnt); + freqData.incSummFreq(4); + if (HiCnt > ModelPPM.MAX_FREQ) { + rescale(model); + } + coder.getSubRange().setLowCount(0); + return true; + } else { + if (model.getFoundState().getAddress() == 0) { + return (false); + } + } + model.setPrevSuccess(0); + int numStats = getNumStats(); + i = numStats - 1; + while ((HiCnt += p.incAddress().getFreq()) <= count) + { + if (--i == 0) { + model.setHiBitsFlag(model.getHB2Flag()[model.getFoundState().getSymbol()]); + coder.getSubRange().setLowCount(HiCnt); + model.getCharMask()[p.getSymbol()] = model.getEscCount(); + model.setNumMasked(numStats); + i = numStats - 1; + model.getFoundState().setAddress(0); + do { + model.getCharMask()[p.decAddress().getSymbol()] = model.getEscCount(); + } while (--i != 0); + coder.getSubRange().setHighCount(coder.getSubRange().getScale()); + return (true); + } + } + coder.getSubRange().setLowCount(HiCnt-p.getFreq()); + coder.getSubRange().setHighCount(HiCnt); + update1(model, p.getAddress()); + return (true); + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("PPMContext["); + buffer.append("\n pos="); + buffer.append(pos); + buffer.append("\n size="); + buffer.append(size); + buffer.append("\n numStats="); + buffer.append(getNumStats()); + buffer.append("\n Suffix="); + buffer.append(getSuffix()); + buffer.append("\n freqData="); + buffer.append(freqData); + buffer.append("\n oneState="); + buffer.append(oneState); + buffer.append("\n]"); + return buffer.toString(); + } + +} diff --git a/src/com/innosystec/unrar/unpack/ppm/Pointer.java b/src/com/innosystec/unrar/unpack/ppm/Pointer.java new file mode 100644 index 0000000..4f16c36 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/Pointer.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 14.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + +/** + * Simulates Pointers on a single mem block as a byte[] + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public abstract class Pointer +{ + protected byte[] mem; + protected int pos; + + /** + * Initialize the object with the array (may be null) + * @param mem the byte array + */ + public Pointer(byte[] mem) + { + this.mem = mem; + } + + /** + * returns the position of this object in the byte[] + * @return the address of this object + */ + public int getAddress() + { + return pos; + } + + /** + * needs to set the fields of this object to the values in the byte[] + * at the given position. + * be aware of the byte order + * @param pos the position this object should point to + * @return true if the address could be set + */ + public void setAddress(int pos) + { + this.pos = pos; + } +} diff --git a/src/com/innosystec/unrar/unpack/ppm/RangeCoder.java b/src/com/innosystec/unrar/unpack/ppm/RangeCoder.java new file mode 100644 index 0000000..274bf2d --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/RangeCoder.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + +import java.io.IOException; + +import com.innosystec.unrar.exception.RarException; +import com.innosystec.unrar.unpack.Unpack; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RangeCoder +{ + public static final int TOP = 1 << 24; + + public static final int BOT = 1 << 15; + + private static final long uintMask = 0xFFFFffffL; + + // uint low, code, range; + private long low, code, range; + + private final SubRange subRange = new SubRange(); + + private Unpack unpackRead; + + public SubRange getSubRange() + { + return subRange; + } + + public void initDecoder(Unpack unpackRead) throws IOException, RarException + { + this.unpackRead = unpackRead; + + low = code = 0L; + range = 0xFFFFffffL; + for (int i = 0; i < 4; i++) { + code = ((code << 8) | getChar())&uintMask; + } + } + + public int getCurrentCount() + { + range = (range / subRange.getScale())&uintMask; + return (int)((code - low) / (range)); + } + + public long getCurrentShiftCount(int SHIFT) + { + range = range >>>SHIFT; + return ((code - low) / (range))&uintMask; + } + + public void decode() + { + low = (low + (range * subRange.getLowCount()))&uintMask; + range = (range * (subRange.getHighCount() - subRange.getLowCount()))&uintMask; + } + + private int getChar() throws IOException, RarException + { + return (unpackRead.getChar()); + } + + public void ariDecNormalize() throws IOException, RarException + { +// while ((low ^ (low + range)) < TOP || range < BOT && ((range = -low & (BOT - 1)) != 0 ? true : true)) +// { +// code = ((code << 8) | unpackRead.getChar()&0xff)&uintMask; +// range = (range << 8)&uintMask; +// low = (low << 8)&uintMask; +// } + + // Rewrote for clarity + boolean c2 = false; + while ((low ^ (low + range)) < TOP || (c2 = range < BOT)) { + if (c2) { + range = (-low & (BOT - 1))&uintMask; + c2 = false; + } + code = ((code << 8) | getChar())&uintMask; + range = (range << 8)&uintMask; + low = (low << 8)&uintMask; + } + } + + // Debug + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("RangeCoder["); + buffer.append("\n low="); + buffer.append(low); + buffer.append("\n code="); + buffer.append(code); + buffer.append("\n range="); + buffer.append(range); + buffer.append("\n subrange="); + buffer.append(subRange); + buffer.append("]"); + return buffer.toString(); + } + + public static class SubRange + { + // uint LowCount, HighCount, scale; + private long lowCount, highCount, scale; + + public long getHighCount() + { + return highCount; + } + + public void setHighCount(long highCount) + { + this.highCount = highCount&uintMask; + } + + public long getLowCount() + { + return lowCount&uintMask; + } + + public void setLowCount(long lowCount) + { + this.lowCount = lowCount&uintMask; + } + + public long getScale() + { + return scale; + } + + public void setScale(long scale) + { + this.scale = scale&uintMask; + } + + public void incScale(int dScale) { + setScale(getScale() + dScale); + } + + // Debug + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("SubRange["); + buffer.append("\n lowCount="); + buffer.append(lowCount); + buffer.append("\n highCount="); + buffer.append(highCount); + buffer.append("\n scale="); + buffer.append(scale); + buffer.append("]"); + return buffer.toString(); + } + } +} diff --git a/src/com/innosystec/unrar/unpack/ppm/RarMemBlock.java b/src/com/innosystec/unrar/unpack/ppm/RarMemBlock.java new file mode 100644 index 0000000..30d294f --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/RarMemBlock.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 05.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + +import com.innosystec.unrar.io.Raw; + + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RarMemBlock extends Pointer +{ + + public static final int size = 12; + + private int stamp, NU; + + private int next, prev; // Pointer RarMemBlock + + public RarMemBlock(byte[] mem) + { + super(mem); + } + + public void insertAt(RarMemBlock p) + { + RarMemBlock temp = new RarMemBlock(mem); + setPrev(p.getAddress()); + temp.setAddress(getPrev()); + setNext(temp.getNext());// prev.getNext(); + temp.setNext(this);// prev.setNext(this); + temp.setAddress(getNext()); + temp.setPrev(this);// next.setPrev(this); + } + + public void remove() + { + RarMemBlock temp = new RarMemBlock(mem); + temp.setAddress(getPrev()); + temp.setNext(getNext());// prev.setNext(next); + temp.setAddress(getNext()); + temp.setPrev(getPrev());// next.setPrev(prev); +// next = -1; +// prev = -1; + } + + public int getNext() + { + if(mem!=null){ + next = Raw.readIntLittleEndian(mem, pos+4); + } + return next; + } + + public void setNext(RarMemBlock next) + { + setNext(next.getAddress()); + } + + public void setNext(int next) + { + this.next = next; + if (mem != null) { + Raw.writeIntLittleEndian(mem, pos + 4, next); + } + } + + public int getNU() + { + if(mem!=null){ + NU = Raw.readShortLittleEndian(mem, pos+2)&0xffff; + } + return NU; + } + + public void setNU(int nu) + { + NU = nu&0xffff; + if (mem != null) { + Raw.writeShortLittleEndian(mem, pos + 2, (short)nu); + } + } + + public int getPrev() + { + if(mem!=null){ + prev = Raw.readIntLittleEndian(mem, pos+8); + } + return prev; + } + + public void setPrev(RarMemBlock prev) + { + setPrev(prev.getAddress()); + } + + public void setPrev(int prev) + { + this.prev = prev; + if (mem != null) { + Raw.writeIntLittleEndian(mem, pos + 8, prev); + } + } + + public int getStamp() + { + if(mem!=null){ + stamp = Raw.readShortLittleEndian(mem, pos)&0xffff; + } + return stamp; + } + + public void setStamp(int stamp) + { + this.stamp = stamp; + if (mem != null) { + Raw.writeShortLittleEndian(mem, pos, (short)stamp); + } + } +} diff --git a/src/com/innosystec/unrar/unpack/ppm/RarNode.java b/src/com/innosystec/unrar/unpack/ppm/RarNode.java new file mode 100644 index 0000000..73b4917 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/RarNode.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 05.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + +import com.innosystec.unrar.io.Raw; + + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RarNode extends Pointer{ + private int next; //rarnode pointer + + public static final int size = 4; + + public RarNode(byte[] mem){ + super(mem); + } + + public int getNext() { + if(mem!=null){ + next = Raw.readIntLittleEndian(mem, pos); + } + return next; + } + + public void setNext(RarNode next) { + setNext(next.getAddress()); + } + + public void setNext(int next) { + this.next = next; + if(mem!=null){ + Raw.writeIntLittleEndian(mem, pos, next); + } + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("State["); + buffer.append("\n pos="); + buffer.append(pos); + buffer.append("\n size="); + buffer.append(size); + buffer.append("\n next="); + buffer.append(getNext()); + buffer.append("\n]"); + return buffer.toString(); + } +} diff --git a/src/com/innosystec/unrar/unpack/ppm/SEE2Context.java b/src/com/innosystec/unrar/unpack/ppm/SEE2Context.java new file mode 100644 index 0000000..529488e --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/SEE2Context.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class SEE2Context +{ + public static final int size = 4; + // ushort Summ; + private int summ; + // byte Shift; + private int shift; + // byte Count; + private int count; + + public void init(int initVal) + { + shift = (ModelPPM.PERIOD_BITS - 4) & 0xff; + summ = (initVal << shift) & 0xffff; + count = 4; + } + + public int getMean() + { + int retVal = summ >>> shift; + summ -= retVal; + return retVal + ((retVal == 0) ? 1 : 0); + } + + public void update() + { + if(shift < ModelPPM.PERIOD_BITS && --count == 0) + { + summ += summ; + count = (3 << shift++); + } + summ &= 0xffff; + count &= 0xff; + shift &= 0xff; + } + + public int getCount() + { + return count; + } + + public void setCount(int count) + { + this.count = count & 0xff; + } + + public int getShift() + { + return shift; + } + + public void setShift(int shift) + { + this.shift = shift & 0xff; + } + + public int getSumm() + { + return summ; + } + + public void setSumm(int summ) + { + this.summ = summ & 0xffff; + } + + public void incSumm(int dSumm) + { + setSumm(getSumm() + dSumm); + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + buffer.append("SEE2Context["); + buffer.append("\n size="); + buffer.append(size); + buffer.append("\n summ="); + buffer.append(summ); + buffer.append("\n shift="); + buffer.append(shift); + buffer.append("\n count="); + buffer.append(count); + buffer.append("\n]"); + return buffer.toString(); + } +} diff --git a/src/com/innosystec/unrar/unpack/ppm/State.java b/src/com/innosystec/unrar/unpack/ppm/State.java new file mode 100644 index 0000000..69dfae8 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/State.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + +import com.innosystec.unrar.io.Raw; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class State extends Pointer { + + public static final int size = 6; + + public State(byte[] mem) { + super(mem); + } + + public State init(byte[] mem) { + this.mem = mem; + pos = 0; + return this; + } + + public int getSymbol() { + return mem[pos]&0xff; + } + + public void setSymbol(int symbol) { + mem[pos] = (byte)symbol; + } + + public int getFreq() { + return mem[pos+1]&0xff; + } + + public void setFreq(int freq) { + mem[pos + 1] = (byte)freq; + } + + public void incFreq(int dFreq) { + mem[pos + 1] += dFreq; + } + + public int getSuccessor() { + return Raw.readIntLittleEndian(mem, pos+2); + } + + public void setSuccessor(PPMContext successor) { + setSuccessor(successor.getAddress()); + } + + public void setSuccessor(int successor) { + Raw.writeIntLittleEndian(mem, pos + 2, successor); + } + + public void setValues(StateRef state){ + setSymbol(state.getSymbol()); + setFreq(state.getFreq()); + setSuccessor(state.getSuccessor()); + } + + public void setValues(State ptr){ + System.arraycopy(ptr.mem, ptr.pos, mem, pos, size); + } + + public State decAddress(){ + setAddress(pos-size); + return this; + } + + public State incAddress(){ + setAddress(pos+size); + return this; + } + + public static void ppmdSwap(State ptr1, State ptr2) { + byte[] mem1=ptr1.mem, mem2=ptr2.mem; + for (int i=0, pos1=ptr1.pos, pos2=ptr2.pos; i < size; i++, pos1++, pos2++) { + byte temp = mem1[pos1]; + mem1[pos1] = mem2[pos2]; + mem2[pos2] = temp; + } + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("State["); + buffer.append("\n pos="); + buffer.append(pos); + buffer.append("\n size="); + buffer.append(size); + buffer.append("\n symbol="); + buffer.append(getSymbol()); + buffer.append("\n freq="); + buffer.append(getFreq()); + buffer.append("\n successor="); + buffer.append(getSuccessor()); + buffer.append("\n]"); + return buffer.toString(); + } +} diff --git a/src/com/innosystec/unrar/unpack/ppm/StateRef.java b/src/com/innosystec/unrar/unpack/ppm/StateRef.java new file mode 100644 index 0000000..2387e90 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/StateRef.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class StateRef { + + private int symbol; + + private int freq; + + private int successor; // pointer ppmcontext + + public StateRef() { + } + + public int getSymbol() { + return symbol; + } + + public void setSymbol(int symbol) { + this.symbol = symbol&0xff; + } + + public int getFreq() { + return freq; + } + + public void setFreq(int freq) { + this.freq = freq&0xff; + } + + public void incFreq(int dFreq) { + freq = (freq + dFreq)&0xff; + } + + public void decFreq(int dFreq) { + freq = (freq - dFreq)&0xff; + } + + public void setValues(State statePtr){ + setFreq(statePtr.getFreq()); + setSuccessor(statePtr.getSuccessor()); + setSymbol(statePtr.getSymbol()); + } + + public int getSuccessor() { + return successor; + } + + public void setSuccessor(PPMContext successor) { + setSuccessor(successor.getAddress()); + } + + public void setSuccessor(int successor) { + this.successor = successor; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("State["); + buffer.append("\n symbol="); + buffer.append(getSymbol()); + buffer.append("\n freq="); + buffer.append(getFreq()); + buffer.append("\n successor="); + buffer.append(getSuccessor()); + buffer.append("\n]"); + return buffer.toString(); + } +} diff --git a/src/com/innosystec/unrar/unpack/ppm/SubAllocator.java b/src/com/innosystec/unrar/unpack/ppm/SubAllocator.java new file mode 100644 index 0000000..5ff0dfc --- /dev/null +++ b/src/com/innosystec/unrar/unpack/ppm/SubAllocator.java @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.ppm; + +import com.classpath.util.Arrays; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class SubAllocator +{ + public static final int + N1 = 4, + N2 = 4, + N3 = 4, + N4 = (128 + 3 - 1 * N1 - 2 * N2 - 3 * N3) / 4; + + public static final int N_INDEXES = N1 + N2 + N3 + N4; + public static final int UNIT_SIZE = Math.max(PPMContext.size, RarMemBlock.size); + public static final int FIXED_UNIT_SIZE = 12; + private int subAllocatorSize; + // byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount; + private int[] indx2Units = new int[N_INDEXES]; + private int[] units2Indx = new int[128]; + private int glueCount; + // byte *HeapStart,*LoUnit, *HiUnit; + private int heapStart, loUnit, hiUnit; + private final RarNode[] freeList = new RarNode[N_INDEXES]; + // byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart; + private int pText, unitsStart, heapEnd, fakeUnitsStart; + private byte[] heap; + private int freeListPos; + private int tempMemBlockPos; + // Temp fields + private RarNode tempRarNode = null; + private RarMemBlock tempRarMemBlock1 = null; + private RarMemBlock tempRarMemBlock2 = null; + private RarMemBlock tempRarMemBlock3 = null; + + public SubAllocator() + { + clean(); + } + + public void clean() + { + subAllocatorSize = 0; + } + + private void insertNode(int p/* rarnode ptr */, int indx) + { + RarNode temp = tempRarNode; + temp.setAddress(p); + temp.setNext(freeList[indx].getNext()); + freeList[indx].setNext(temp); + } + + public void incPText() + { + pText++; + } + + private int removeNode(int indx) + { + int retVal = freeList[indx].getNext(); + RarNode temp = tempRarNode; + temp.setAddress(retVal); + freeList[indx].setNext(temp.getNext()); + return retVal; + } + + private int U2B(int NU) + { + return /* 8*NU+4*NU */ UNIT_SIZE * NU; + } + + /* memblockptr */ + private int MBPtr(int BasePtr, int Items) + { + return (BasePtr + U2B(Items)); + } + + private void splitBlock(int pv/* ptr */, int oldIndx, int newIndx) + { + int i, uDiff = indx2Units[oldIndx] - indx2Units[newIndx]; + int p = pv + U2B(indx2Units[newIndx]); + if(indx2Units[i = units2Indx[uDiff - 1]] != uDiff) + { + insertNode(p, --i); + p += U2B(i = indx2Units[i]); + uDiff -= i; + } + insertNode(p, units2Indx[uDiff - 1]); + } + + public void stopSubAllocator() + { + if(subAllocatorSize != 0) + { + subAllocatorSize = 0; + heap = null; + heapStart = 1; + // rarfree(HeapStart); + // Free temp fields + tempRarNode = null; + tempRarMemBlock1 = null; + tempRarMemBlock2 = null; + tempRarMemBlock3 = null; + } + } + + public int GetAllocatedMemory() + { + return subAllocatorSize; + } + + ; + + public boolean startSubAllocator(int SASize) + { + int t = SASize << 20; + if(subAllocatorSize == t) + { + return true; + } + stopSubAllocator(); + int allocSize = t / FIXED_UNIT_SIZE * UNIT_SIZE + UNIT_SIZE; + + // adding space for freelist (needed for poiters) + //1+ for null pointer + int realAllocSize = 1 + allocSize + 4 * N_INDEXES; + // adding space for an additional memblock + tempMemBlockPos = realAllocSize; + realAllocSize += RarMemBlock.size; + + heap = new byte[realAllocSize]; + heapStart = 1; + heapEnd = heapStart + allocSize - UNIT_SIZE; + subAllocatorSize = t; + // Bug fixed + freeListPos = heapStart + allocSize; + + // Init freeList + for(int i = 0, pos = freeListPos; i < freeList.length; i++, pos += RarNode.size) + { + freeList[i] = new RarNode(heap); + freeList[i].setAddress(pos); + } + + // Init temp fields + tempRarNode = new RarNode(heap); + tempRarMemBlock1 = new RarMemBlock(heap); + tempRarMemBlock2 = new RarMemBlock(heap); + tempRarMemBlock3 = new RarMemBlock(heap); + + return true; + } + + private void glueFreeBlocks() + { + RarMemBlock s0 = tempRarMemBlock1; + s0.setAddress(tempMemBlockPos); + RarMemBlock p = tempRarMemBlock2; + RarMemBlock p1 = tempRarMemBlock3; + int i, k, sz; + if(loUnit != hiUnit) + { + heap[loUnit] = 0; + } + for(i = 0, s0.setPrev(s0), s0.setNext(s0); i < N_INDEXES; i++) + { + while(freeList[i].getNext() != 0) + { + p.setAddress(removeNode(i));// =(RAR_MEM_BLK*)RemoveNode(i); + p.insertAt(s0);// p->insertAt(&s0); + p.setStamp(0xFFFF);// p->Stamp=0xFFFF; + p.setNU(indx2Units[i]);// p->NU=Indx2Units[i]; + } + } + for(p.setAddress(s0.getNext()); p.getAddress() != s0.getAddress(); + p.setAddress(p.getNext())) + { + // while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU + // < 0x10000) + // Bug fixed + p1.setAddress(MBPtr(p.getAddress(), p.getNU())); + while(p1.getStamp() == 0xFFFF && p.getNU() + p1.getNU() < 0x10000) + { + p1.remove(); + p.setNU(p.getNU() + p1.getNU());// ->NU += p1->NU; + p1.setAddress(MBPtr(p.getAddress(), p.getNU())); + } + } + // while ((p=s0.next) != &s0) + // Bug fixed + p.setAddress(s0.getNext()); + while(p.getAddress() != s0.getAddress()) + { + for(p.remove(), sz = p.getNU(); sz > 128; + sz -= 128, p.setAddress(MBPtr(p.getAddress(), 128))) + { + insertNode(p.getAddress(), N_INDEXES - 1); + } + if(indx2Units[i = units2Indx[sz - 1]] != sz) + { + k = sz - indx2Units[--i]; + insertNode(MBPtr(p.getAddress(), sz - k), k - 1); + } + insertNode(p.getAddress(), i); + p.setAddress(s0.getNext()); + } + } + + private int allocUnitsRare(int indx) + { + if(glueCount == 0) + { + glueCount = 255; + glueFreeBlocks(); + if(freeList[indx].getNext() != 0) + { + return removeNode(indx); + } + } + int i = indx; + do + { + if(++i == N_INDEXES) + { + glueCount--; + i = U2B(indx2Units[indx]); + int j = FIXED_UNIT_SIZE * indx2Units[indx]; + if(fakeUnitsStart - pText > j) + { + fakeUnitsStart -= j; + unitsStart -= i; + return unitsStart; + } + return (0); + } + } + while(freeList[i].getNext() == 0); + int retVal = removeNode(i); + splitBlock(retVal, i, indx); + return retVal; + } + + public int allocUnits(int NU) + { + int indx = units2Indx[NU - 1]; + if(freeList[indx].getNext() != 0) + { + return removeNode(indx); + } + int retVal = loUnit; + loUnit += U2B(indx2Units[indx]); + if(loUnit <= hiUnit) + { + return retVal; + } + loUnit -= U2B(indx2Units[indx]); + return allocUnitsRare(indx); + } + + public int allocContext() + { + if(hiUnit != loUnit) + { + return (hiUnit -= UNIT_SIZE); + } + if(freeList[0].getNext() != 0) + { + return removeNode(0); + } + return allocUnitsRare(0); + } + + public int expandUnits(int oldPtr, int OldNU) + { + int i0 = units2Indx[OldNU - 1]; + int i1 = units2Indx[OldNU - 1 + 1]; + if(i0 == i1) + { + return oldPtr; + } + int ptr = allocUnits(OldNU + 1); + if(ptr != 0) + { + // memcpy(ptr,OldPtr,U2B(OldNU)); + System.arraycopy(heap, oldPtr, heap, ptr, U2B(OldNU)); + insertNode(oldPtr, i0); + } + return ptr; + } + + public int shrinkUnits(int oldPtr, int oldNU, int newNU) + { + //System.out.println("SubAllocator.shrinkUnits(" + OldPtr + ", " + OldNU + ", " + NewNU + ")"); + int i0 = units2Indx[oldNU - 1]; + int i1 = units2Indx[newNU - 1]; + if(i0 == i1) + { + return oldPtr; + } + if(freeList[i1].getNext() != 0) + { + int ptr = removeNode(i1); + // memcpy(ptr,OldPtr,U2B(NewNU)); +// for (int i = 0; i < U2B(NewNU); i++) { +// heap[ptr + i] = heap[OldPtr + i]; +// } + System.arraycopy(heap, oldPtr, heap, ptr, U2B(newNU)); + insertNode(oldPtr, i0); + return ptr; + } + else + { + splitBlock(oldPtr, i0, i1); + return oldPtr; + } + } + + public void freeUnits(int ptr, int OldNU) + { + insertNode(ptr, units2Indx[OldNU - 1]); + } + + public int getFakeUnitsStart() + { + return fakeUnitsStart; + } + + public void setFakeUnitsStart(int fakeUnitsStart) + { + this.fakeUnitsStart = fakeUnitsStart; + } + + public int getHeapEnd() + { + return heapEnd; + } + + public int getPText() + { + return pText; + } + + public void setPText(int text) + { + pText = text; + } + + public void decPText(int dPText) + { + setPText(getPText() - dPText); + } + + public int getUnitsStart() + { + return unitsStart; + } + + public void setUnitsStart(int unitsStart) + { + this.unitsStart = unitsStart; + } + + public void initSubAllocator() + { + int i, k; + Arrays.fill(heap, freeListPos, freeListPos + sizeOfFreeList(), (byte) 0); + + pText = heapStart; + + int size2 = FIXED_UNIT_SIZE + * (subAllocatorSize / 8 / FIXED_UNIT_SIZE * 7); + int realSize2 = size2 / FIXED_UNIT_SIZE * UNIT_SIZE; + int size1 = subAllocatorSize - size2; + int realSize1 = size1 / FIXED_UNIT_SIZE * UNIT_SIZE + size1 + % FIXED_UNIT_SIZE; + hiUnit = heapStart + subAllocatorSize; + loUnit = unitsStart = heapStart + realSize1; + fakeUnitsStart = heapStart + size1; + hiUnit = loUnit + realSize2; + + for(i = 0, k = 1; i < N1; i++, k += 1) + { + indx2Units[i] = k & 0xff; + } + for(k++; i < N1 + N2; i++, k += 2) + { + indx2Units[i] = k & 0xff; + } + for(k++; i < N1 + N2 + N3; i++, k += 3) + { + indx2Units[i] = k & 0xff; + } + for(k++; i < (N1 + N2 + N3 + N4); i++, k += 4) + { + indx2Units[i] = k & 0xff; + } + + for(glueCount = 0, k = 0, i = 0; k < 128; k++) + { + i += ((indx2Units[i] < (k + 1)) ? 1 : 0); + units2Indx[k] = i & 0xff; + } + + } + + private int sizeOfFreeList() + { + return freeList.length * RarNode.size; + } + + public byte[] getHeap() + { + return heap; + } + + // Debug +// public void dumpHeap() { +// FileConnection file = new FileConnection("P:\\test\\heapdumpj"); +// OutputStream out = null; +// try { +// out = new FileOutputStream(file); +// out.write(heap, heapStart, heapEnd - heapStart); +// out.flush(); +// System.out.println("Heap dumped to " + file.getAbsolutePath()); +// } +// catch (IOException e) { +// e.printStackTrace(); +// } +// finally { +// FileUtil.close(out); +// } +// } + // Debug + public String toString() + { + StringBuffer buffer = new StringBuffer(); + buffer.append("SubAllocator["); + buffer.append("\n subAllocatorSize="); + buffer.append(subAllocatorSize); + buffer.append("\n glueCount="); + buffer.append(glueCount); + buffer.append("\n heapStart="); + buffer.append(heapStart); + buffer.append("\n loUnit="); + buffer.append(loUnit); + buffer.append("\n hiUnit="); + buffer.append(hiUnit); + buffer.append("\n pText="); + buffer.append(pText); + buffer.append("\n unitsStart="); + buffer.append(unitsStart); + buffer.append("\n]"); + return buffer.toString(); + } +} diff --git a/src/com/innosystec/unrar/unpack/vm/BitInput.java b/src/com/innosystec/unrar/unpack/vm/BitInput.java new file mode 100644 index 0000000..ab87442 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/vm/BitInput.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class BitInput +{ + /** + * the max size of the input + */ + public static int MAX_SIZE = 0x8000; + protected int inAddr; + protected int inBit; + protected byte[] inBuf; + + /** + * + */ + public void InitBitInput() + { + inAddr = 0; + inBit = 0; + } + + /** + * @param Bits + */ + public void addbits(int Bits) + { + Bits += inBit; + inAddr += Bits >> 3; + inBit = Bits & 7; + } + + /** + * @return the bits (unsigned short) + */ + public int getbits() + { +// int BitField=0; +// BitField|=(int)(inBuf[inAddr] << 16)&0xFF0000; +// BitField|=(int)(inBuf[inAddr+1] << 8)&0xff00; +// BitField|=(int)(inBuf[inAddr+2])&0xFF; +// BitField >>>= (8-inBit); +// return (BitField & 0xffff); + return (((((inBuf[inAddr] & 0xff) << 16) + + ((inBuf[inAddr + 1] & 0xff) << 8) + + ((inBuf[inAddr + 2] & 0xff))) >>> (8 - inBit)) & 0xffff); + } + + /** + * + */ + public BitInput() + { + inBuf = new byte[MAX_SIZE]; + } + + /** + * @param Bits add the bits + */ + public void faddbits(int Bits) + { + addbits(Bits); + } + + /** + * @return get the bits + */ + public int fgetbits() + { + return (getbits()); + } + + /** + * Indicates an Overfow + * @param IncPtr how many bytes to inc + * @return true if an Oververflow would occur + */ + public boolean Overflow(int IncPtr) + { + return (inAddr + IncPtr >= MAX_SIZE); + } + + public byte[] getInBuf() + { + return inBuf; + } +} diff --git a/src/com/innosystec/unrar/unpack/vm/RarVM.java b/src/com/innosystec/unrar/unpack/vm/RarVM.java new file mode 100644 index 0000000..7f8b32b --- /dev/null +++ b/src/com/innosystec/unrar/unpack/vm/RarVM.java @@ -0,0 +1,1405 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.vm; + +import com.classpath.util.ByteCache; +import java.util.Vector; + +import com.innosystec.unrar.crc.RarCRC; +import com.innosystec.unrar.io.Raw; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RarVM extends BitInput +{ + public static int VM_MEMSIZE = 0x40000; + public static int VM_MEMMASK = (VM_MEMSIZE - 1); + public static int VM_GLOBALMEMADDR = 0x3C000; + public static int VM_GLOBALMEMSIZE = 0x2000; + public static int VM_FIXEDGLOBALSIZE = 64; + private static final int regCount = 8; + private static final long UINT_MASK = 0xffffFFFF;//((long)2*(long)Integer.MAX_VALUE); + private byte[] mem; + private int[] R = new int[regCount]; + private int flags; + private int maxOpCount = 25000000; + private int codeSize; + private int IP; + + public RarVM() + { + mem = null; + } + + public void init() + { + if(mem == null) + { + mem = new byte[VM_MEMSIZE + 4]; + } + } + + private boolean isVMMem(byte[] mem) + { + return this.mem == mem; + } + + private int getValue(boolean byteMode, byte[] mem, int offset) + { + if(byteMode) + { + if(isVMMem(mem)) + { + return (mem[offset]); + } + else + { + return (mem[offset] & 0xff); + } + } + else + { + if(isVMMem(mem)) + { + //little + return Raw.readIntLittleEndian(mem, offset); + } + else + //big endian + { + return Raw.readIntBigEndian(mem, offset); + } + } + } + + private void setValue(boolean byteMode, byte[] mem, int offset, int value) + { + if(byteMode) + { + if(isVMMem(mem)) + { + mem[offset] = (byte) value; + } + else + { + mem[offset] = (byte) ((mem[offset] & 0x00) | (byte) (value & 0xff)); + } + } + else + { + if(isVMMem(mem)) + { + Raw.writeIntLittleEndian(mem, offset, value); +// mem[offset + 0] = (byte) value; +// mem[offset + 1] = (byte) (value >>> 8); +// mem[offset + 2] = (byte) (value >>> 16); +// mem[offset + 3] = (byte) (value >>> 24); + } + else + { + Raw.writeIntBigEndian(mem, offset, value); +// mem[offset + 3] = (byte) value; +// mem[offset + 2] = (byte) (value >>> 8); +// mem[offset + 1] = (byte) (value >>> 16); +// mem[offset + 0] = (byte) (value >>> 24); + } + + } + // #define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint + // *)Addr,Value) + } + + public void setLowEndianValue(byte[] mem, int offset, int value) + { + Raw.writeIntLittleEndian(mem, offset, value); +// mem[offset + 0] = (byte) (value&0xff); +// mem[offset + 1] = (byte) ((value >>> 8)&0xff); +// mem[offset + 2] = (byte) ((value >>> 16)&0xff); +// mem[offset + 3] = (byte) ((value >>> 24)&0xff); + } + + public void setLowEndianValue(Vector mem, int offset, int value) + { + mem.setElementAt(ByteCache.valueOf((byte) (value & 0xff)), offset + 0); + mem.setElementAt(ByteCache.valueOf((byte) ((value >>> 8) & 0xff)), offset + 1); + mem.setElementAt(ByteCache.valueOf((byte) ((value >>> 16) & 0xff)), offset + 2); + mem.setElementAt(ByteCache.valueOf((byte) ((value >>> 24) & 0xff)), offset + 3); + } + + private int getOperand(VMPreparedOperand cmdOp) + { + int ret = 0; + if(cmdOp.getType() == VMOpType.VM_OPREGMEM) + { + int pos = (cmdOp.getOffset() + cmdOp.getBase()) & VM_MEMMASK; + ret = Raw.readIntLittleEndian(mem, pos); + } + else + { + int pos = cmdOp.getOffset(); + ret = Raw.readIntLittleEndian(mem, pos); + } + return ret; + } + + public void execute(VMPreparedProgram prg) + { + for(int i = 0; i < prg.getInitR().length; i++) // memcpy(R,Prg->InitR,sizeof(Prg->InitR)); + { + R[i] = prg.getInitR()[i]; + } + + long globalSize = Math.min(prg.getGlobalData().size(), VM_GLOBALMEMSIZE) & 0xffFFffFF; + if(globalSize != 0) + { + for(int i = 0; i < globalSize; i++) // memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); + { + mem[VM_GLOBALMEMADDR + i] = ((Byte)prg.getGlobalData().elementAt(i)).byteValue(); + } + + } + long staticSize = Math.min(prg.getStaticData().size(), VM_GLOBALMEMSIZE + - globalSize) & 0xffFFffFF; + if(staticSize != 0) + { + for(int i = 0; i < staticSize; i++) // memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); + { + mem[VM_GLOBALMEMADDR + (int) globalSize + i] = ((Byte)prg.getStaticData().elementAt(i)).byteValue(); + } + + } + R[7] = VM_MEMSIZE; + flags = 0; + + Vector preparedCode = prg.getAltCmd().size() != 0 ? prg.getAltCmd() : prg.getCmd(); + + if(!ExecuteCode(preparedCode, prg.getCmdCount())) + { + ((VMPreparedCommand)preparedCode.elementAt(0)).setOpCode(VMCommands.VM_RET); + } + int newBlockPos = getValue(false, mem, VM_GLOBALMEMADDR + 0x20) & VM_MEMMASK; + int newBlockSize = getValue(false, mem, VM_GLOBALMEMADDR + 0x1c) & VM_MEMMASK; + if((newBlockPos + newBlockSize) >= VM_MEMSIZE) + { + newBlockPos = 0; + newBlockSize = 0; + } + + prg.setFilteredDataOffset(newBlockPos); + prg.setFilteredDataSize(newBlockSize); + + prg.getGlobalData().removeAllElements(); + + int dataSize = Math.min(getValue(false, mem, VM_GLOBALMEMADDR + 0x30), + VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE); + if(dataSize != 0) + { + prg.getGlobalData().setSize(dataSize + VM_FIXEDGLOBALSIZE); + // ->GlobalData.Add(dataSize+VM_FIXEDGLOBALSIZE); + + for(int i = 0; i < dataSize + VM_FIXEDGLOBALSIZE; i++) // memcpy(&Prg->GlobalData[0],&Mem[VM_GLOBALMEMADDR],DataSize+VM_FIXEDGLOBALSIZE); + { + prg.getGlobalData().setElementAt(ByteCache.valueOf(mem[VM_GLOBALMEMADDR + i]), i); + } + } + } + + public byte[] getMem() + { + return mem; + } + + private boolean setIP(int ip) + { + if((ip) >= codeSize) + { + return (true); + } + + if(--maxOpCount <= 0) + { + return (false); + } + + IP = ip; + return true; + } + + private boolean ExecuteCode(Vector preparedCode, + int cmdCount) + { + + maxOpCount = 25000000; + this.codeSize = cmdCount; + this.IP = 0; + + while(true) + { + VMPreparedCommand cmd = (VMPreparedCommand)preparedCode.elementAt(IP); + int op1 = getOperand(cmd.getOp1()); + int op2 = getOperand(cmd.getOp2()); + switch(cmd.getOpCode()) + { + case VMCommands.VM_MOV: + setValue(cmd.isByteMode(), mem, op1, getValue(cmd.isByteMode(), + mem, op2)); // SET_VALUE(Cmd->ByteMode,Op1,GET_VALUE(Cmd->ByteMode,Op2)); + break; + case VMCommands.VM_MOVB: + setValue(true, mem, op1, getValue(true, mem, op2)); + break; + case VMCommands.VM_MOVD: + setValue(false, mem, op1, getValue(false, mem, op2)); + break; + + case VMCommands.VM_CMP: + { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int result = value1 - getValue(cmd.isByteMode(), mem, op2); + + if(result == 0) + { + flags = VMFlags.VM_FZ; + } + else + { + flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS); + } + } + break; + + case VMCommands.VM_CMPB: + { + int value1 = getValue(true, mem, op1); + int result = value1 - getValue(true, mem, op2); + if(result == 0) + { + flags = VMFlags.VM_FZ; + } + else + { + flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS); + } + } + break; + case VMCommands.VM_CMPD: + { + int value1 = getValue(false, mem, op1); + int result = value1 - getValue(false, mem, op2); + if(result == 0) + { + flags = VMFlags.VM_FZ; + } + else + { + flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS); + } + } + break; + + case VMCommands.VM_ADD: + { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int result = (int) ((((long) value1 + (long) getValue(cmd.isByteMode(), mem, op2))) & 0xffffffff); + if(cmd.isByteMode()) + { + result &= 0xff; + flags = (result < value1) ? 1 + : 0 | (result == 0 ? VMFlags.VM_FZ + : ((result & 0x80) != 0) ? VMFlags.VM_FS : 0); + // Flags=(Result value1) ? 1 : 0 | (result & VMFlags.VM_FS); + setValue(cmd.isByteMode(), mem, op1, result);// (Cmd->ByteMode,Op1,Result); + } + break; + + case VMCommands.VM_SUBB: + setValue(true, mem, op1, + (int) ((long) getValue(true, mem, op1) & 0xFFffFFff + - (long) getValue(true, mem, op2) & 0xFFffFFff)); + break; + case VMCommands.VM_SUBD: + setValue( + false, + mem, + op1, + (int) ((long) getValue(false, mem, op1) & 0xFFffFFff + - (long) getValue(false, mem, op2) & 0xFFffFFff)); + break; + + case VMCommands.VM_JZ: + if((flags & VMFlags.VM_FZ) != 0) + { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VMCommands.VM_JNZ: + if((flags & VMFlags.VM_FZ) == 0) + { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VMCommands.VM_INC: + { + int result = (int) ((long) getValue(cmd.isByteMode(), mem, op1) & 0xFFffFFff + 1); + if(cmd.isByteMode()) + { + result &= 0xff; + } + + setValue(cmd.isByteMode(), mem, op1, result); + flags = result == 0 ? VMFlags.VM_FZ : result + & VMFlags.VM_FS; + } + break; + + case VMCommands.VM_INCB: + setValue( + true, + mem, + op1, + (int) ((long) getValue(true, mem, op1) & 0xFFffFFff + 1)); + break; + case VMCommands.VM_INCD: + setValue(false, mem, op1, (int) ((long) getValue(false, mem, + op1) & 0xFFffFFff + 1)); + break; + + case VMCommands.VM_DEC: + { + int result = (int) ((long) getValue(cmd.isByteMode(), mem, op1) & 0xFFffFFff - 1); + setValue(cmd.isByteMode(), mem, op1, result); + flags = result == 0 ? VMFlags.VM_FZ : result + & VMFlags.VM_FS; + } + break; + + case VMCommands.VM_DECB: + setValue( + true, + mem, + op1, + (int) ((long) getValue(true, mem, op1) & 0xFFffFFff - 1)); + break; + case VMCommands.VM_DECD: + setValue(false, mem, op1, (int) ((long) getValue(false, mem, + op1) & 0xFFffFFff - 1)); + break; + + case VMCommands.VM_JMP: + setIP(getValue(false, mem, op1)); + continue; + case VMCommands.VM_XOR: + { + int result = getValue(cmd.isByteMode(), mem, op1) + ^ getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ : result + & VMFlags.VM_FS; + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VMCommands.VM_AND: + { + int result = getValue(cmd.isByteMode(), mem, op1) + & getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ : result + & VMFlags.VM_FS; + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VMCommands.VM_OR: + { + int result = getValue(cmd.isByteMode(), mem, op1) + | getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ : result + & VMFlags.VM_FS; + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VMCommands.VM_TEST: + { + int result = getValue(cmd.isByteMode(), mem, op1) + & getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ : result + & VMFlags.VM_FS; + } + break; + case VMCommands.VM_JS: + if((flags & VMFlags.VM_FS) != 0) + { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VMCommands.VM_JNS: + if((flags & VMFlags.VM_FS) == 0) + { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VMCommands.VM_JB: + if((flags & VMFlags.VM_FC) != 0) + { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VMCommands.VM_JBE: + if((flags & (VMFlags.VM_FC | VMFlags.VM_FZ)) != 0) + { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VMCommands.VM_JA: + if((flags & (VMFlags.VM_FC | VMFlags.VM_FZ)) == 0) + { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VMCommands.VM_JAE: + if((flags & VMFlags.VM_FC) == 0) + { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VMCommands.VM_PUSH: + R[7] -= 4; + setValue(false, mem, R[7] & VM_MEMMASK, getValue(false, mem, + op1)); + break; + case VMCommands.VM_POP: + setValue(false, mem, op1, getValue(false, mem, R[7] + & VM_MEMMASK)); + R[7] += 4; + break; + case VMCommands.VM_CALL: + R[7] -= 4; + setValue(false, mem, R[7] & VM_MEMMASK, IP + 1); + setIP(getValue(false, mem, op1)); + continue; + case VMCommands.VM_NOT: + setValue(cmd.isByteMode(), mem, op1, ~getValue( + cmd.isByteMode(), mem, op1)); + break; + case VMCommands.VM_SHL: + { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int value2 = getValue(cmd.isByteMode(), mem, op2); + int result = value1 << value2; + flags = (result == 0 ? VMFlags.VM_FZ + : (result & VMFlags.VM_FS)) + | (((value1 << (value2 - 1)) & 0x80000000) != 0 ? VMFlags.VM_FC + : 0); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VMCommands.VM_SHR: + { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int value2 = getValue(cmd.isByteMode(), mem, op2); + int result = value1 >>> value2; + flags = (result == 0 ? VMFlags.VM_FZ + : (result & VMFlags.VM_FS)) + | ((value1 >>> (value2 - 1)) & VMFlags.VM_FC); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VMCommands.VM_SAR: + { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int value2 = getValue(cmd.isByteMode(), mem, op2); + int result = ((int) value1) >> value2; + flags = (result == 0 ? VMFlags.VM_FZ + : (result & VMFlags.VM_FS)) + | ((value1 >> (value2 - 1)) & VMFlags.VM_FC); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VMCommands.VM_NEG: + { + int result = -getValue(cmd.isByteMode(), mem, op1); + flags = result == 0 ? VMFlags.VM_FZ : VMFlags.VM_FC + | (result & VMFlags.VM_FS); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + + case VMCommands.VM_NEGB: + setValue(true, mem, op1, -getValue(true, mem, op1)); + break; + case VMCommands.VM_NEGD: + setValue(false, mem, op1, -getValue(false, mem, op1)); + break; + case VMCommands.VM_PUSHA: + { + for(int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) + { + setValue(false, mem, SP & VM_MEMMASK, R[i]); + } + R[7] -= regCount * 4; + } + break; + case VMCommands.VM_POPA: + { + for(int i = 0, SP = R[7]; i < regCount; i++, SP += 4) + { + R[7 - i] = getValue(false, mem, SP & VM_MEMMASK); + } + } + break; + case VMCommands.VM_PUSHF: + R[7] -= 4; + setValue(false, mem, R[7] & VM_MEMMASK, flags); + break; + case VMCommands.VM_POPF: + flags = getValue(false, mem, R[7] & VM_MEMMASK); + R[7] += 4; + break; + case VMCommands.VM_MOVZX: + setValue(false, mem, op1, getValue(true, mem, op2)); + break; + case VMCommands.VM_MOVSX: + setValue(false, mem, op1, (byte) getValue(true, mem, op2)); + break; + case VMCommands.VM_XCHG: + { + int value1 = getValue(cmd.isByteMode(), mem, op1); + setValue(cmd.isByteMode(), mem, op1, getValue(cmd.isByteMode(), + mem, op2)); + setValue(cmd.isByteMode(), mem, op2, value1); + } + break; + case VMCommands.VM_MUL: + { + int result = (int) (((long) getValue(cmd.isByteMode(), mem, op1) + & 0xFFffFFff + * (long) getValue(cmd.isByteMode(), mem, op2) & 0xFFffFFff) & 0xFFffFFff); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VMCommands.VM_DIV: + { + int divider = getValue(cmd.isByteMode(), mem, op2); + if(divider != 0) + { + int result = getValue(cmd.isByteMode(), mem, op1) / divider; + setValue(cmd.isByteMode(), mem, op1, result); + } + } + break; + case VMCommands.VM_ADC: + { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int FC = (flags & VMFlags.VM_FC); + int result = (int) ((long) value1 & 0xFFffFFff + + (long) getValue(cmd.isByteMode(), mem, op2) + & 0xFFffFFff + (long) FC & 0xFFffFFff); + if(cmd.isByteMode()) + { + result &= 0xff; + } + + flags = (result < value1 || result == value1 && FC != 0) ? 1 + : 0 | (result == 0 ? VMFlags.VM_FZ + : (result & VMFlags.VM_FS)); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VMCommands.VM_SBB: + { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int FC = (flags & VMFlags.VM_FC); + int result = (int) ((long) value1 & 0xFFffFFff + - (long) getValue(cmd.isByteMode(), mem, op2) + & 0xFFffFFff - (long) FC & 0xFFffFFff); + if(cmd.isByteMode()) + { + result &= 0xff; + } + flags = (result > value1 || result == value1 && FC != 0) ? 1 + : 0 | (result == 0 ? VMFlags.VM_FZ + : (result & VMFlags.VM_FS)); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + + case VMCommands.VM_RET: + if(R[7] >= VM_MEMSIZE) + { + return (true); + } + setIP(getValue(false, mem, R[7] & VM_MEMMASK)); + R[7] += 4; + continue; + + case VMCommands.VM_STANDARD: + ExecuteStandardFilter(VMStandardFilters.findFilter(cmd.getOp1().getData())); + break; + case VMCommands.VM_PRINT: + break; + } + IP++; + --maxOpCount; + } + } + + public void prepare(byte[] code, int codeSize, VMPreparedProgram prg) + { + InitBitInput(); + int cpLength = Math.min(MAX_SIZE, codeSize); + for(int i = 0; i < cpLength; i++) // memcpy(inBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); + { + inBuf[i] |= code[i]; + } + + byte xorSum = 0; + for(int i = 1; i < codeSize; i++) + { + xorSum ^= code[i]; + } + + faddbits(8); + + prg.setCmdCount(0); + if(xorSum == code[0]) + { + int filterType = IsStandardFilter(code, codeSize); + if(filterType != VMStandardFilters.VMSF_NONE) + { + + VMPreparedCommand curCmd = new VMPreparedCommand(); + curCmd.setOpCode(VMCommands.VM_STANDARD); + curCmd.getOp1().setData(filterType); + curCmd.getOp1().setType(VMOpType.VM_OPNONE); + curCmd.getOp2().setType(VMOpType.VM_OPNONE); + codeSize = 0; + prg.getCmd().addElement(curCmd); + prg.setCmdCount(prg.getCmdCount() + 1); + // TODO + // curCmd->Op1.Data=FilterType; + // >>>>>> CurCmd->Op1.Addr=&CurCmd->Op1.Data; <<<<<<<<<< not set + // do i need to ? + // >>>>>> CurCmd->Op2.Addr=&CurCmd->Op2.Data; <<<<<<<<<< " + // CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; + // CodeSize=0; + } + int dataFlag = fgetbits(); + faddbits(1); + + // Read static data contained in DB operators. This data cannot be + // changed, + // it is a part of VM code, not a filter parameter. + + if((dataFlag & 0x8000) != 0) + { + long dataSize = (long) ((long) ReadData(this) & 0xffFFffFF + 1); + for(int i = 0; inAddr < codeSize && i < dataSize; i++) + { + prg.getStaticData().addElement(ByteCache.valueOf((byte) (fgetbits() >> 8))); + faddbits(8); + } + } + + while(inAddr < codeSize) + { + VMPreparedCommand curCmd = new VMPreparedCommand(); + int data = fgetbits(); + if((data & 0x8000) == 0) + { + curCmd.setOpCode(VMCommands.findVMCommand((data >> 12))); + faddbits(4); + } + else + { + curCmd.setOpCode(VMCommands.findVMCommand((data >> 10) - 24)); + faddbits(6); + } + if((VMCmdFlags.VM_CmdFlags[curCmd.getOpCode()] & VMCmdFlags.VMCF_BYTEMODE) != 0) + { + curCmd.setByteMode((fgetbits() >> 15) == 1 ? true : false); + faddbits(1); + } + else + { + curCmd.setByteMode(false); + } + curCmd.getOp1().setType(VMOpType.VM_OPNONE); + curCmd.getOp2().setType(VMOpType.VM_OPNONE); + + int opNum = (VMCmdFlags.VM_CmdFlags[curCmd.getOpCode()] & VMCmdFlags.VMCF_OPMASK); + // TODO >>> CurCmd->Op1.Addr=CurCmd->Op2.Addr=NULL; << 0) + { + decodeArg(curCmd.getOp1(), curCmd.isByteMode()); + if(opNum == 2) + { + decodeArg(curCmd.getOp2(), curCmd.isByteMode()); + } + else + { + if(curCmd.getOp1().getType() == VMOpType.VM_OPINT + && (VMCmdFlags.VM_CmdFlags[curCmd.getOpCode()] & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC)) != 0) + { + int distance = curCmd.getOp1().getData(); + if(distance >= 256) + { + distance -= 256; + } + else + { + if(distance >= 136) + { + distance -= 264; + } + else + { + if(distance >= 16) + { + distance -= 8; + } + else + { + if(distance >= 8) + { + distance -= 16; + } + } + } + distance += prg.getCmdCount(); + } + curCmd.getOp1().setData(distance); + } + } + } + prg.setCmdCount(prg.getCmdCount() + 1); + prg.getCmd().addElement(curCmd); + } + } + VMPreparedCommand curCmd = new VMPreparedCommand(); + curCmd.setOpCode(VMCommands.VM_RET); + // TODO CurCmd->Op1.Addr=&CurCmd->Op1.Data; + // CurCmd->Op2.Addr=&CurCmd->Op2.Data; + curCmd.getOp1().setType(VMOpType.VM_OPNONE); + curCmd.getOp2().setType(VMOpType.VM_OPNONE); + + // for (int i=0;iCmd[I]; + // if (Cmd->Op1.Addr==NULL) + // Cmd->Op1.Addr=&Cmd->Op1.Data; + // if (Cmd->Op2.Addr==NULL) + // Cmd->Op2.Addr=&Cmd->Op2.Data; + // } + + prg.getCmd().addElement(curCmd); + prg.setCmdCount(prg.getCmdCount() + 1); + // #ifdef VM_OPTIMIZE + if(codeSize != 0) + { + optimize(prg); + } + } + + private void decodeArg(VMPreparedOperand op, boolean byteMode) + { + int data = fgetbits(); + if((data & 0x8000) != 0) + { + op.setType(VMOpType.VM_OPREG); + op.setData((data >> 12) & 7); + op.setOffset(op.getData()); + faddbits(4); + } + else + { + if((data & 0xc000) == 0) + { + op.setType(VMOpType.VM_OPINT); + if(byteMode) + { + op.setData((data >> 6) & 0xff); + faddbits(10); + } + else + { + faddbits(2); + op.setData(ReadData(this)); + } + } + else + { + op.setType(VMOpType.VM_OPREGMEM); + if((data & 0x2000) == 0) + { + op.setData((data >> 10) & 7); + op.setOffset(op.getData()); + op.setBase(0); + faddbits(6); + } + else + { + if((data & 0x1000) == 0) + { + op.setData((data >> 9) & 7); + op.setOffset(op.getData()); + faddbits(7); + } + else + { + op.setData(0); + faddbits(4); + } + op.setBase(ReadData(this)); + } + } + } + + } + + private void optimize(VMPreparedProgram prg) + { + Vector commands = prg.getCmd(); + VMPreparedCommand cmd; + + for(int index = 0; index < commands.size(); index++) + { + cmd = (VMPreparedCommand)commands.elementAt(index); + + switch(cmd.getOpCode()) + { + case VMCommands.VM_MOV: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_MOVB : VMCommands.VM_MOVD); + continue; + case VMCommands.VM_CMP: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_CMPB : VMCommands.VM_CMPD); + continue; + } + if((VMCmdFlags.VM_CmdFlags[cmd.getOpCode()] & VMCmdFlags.VMCF_CHFLAGS) == 0) + { + continue; + } + boolean flagsRequired = false; + + for(int i = commands.indexOf(cmd) + 1; i < commands.size(); i++) + { + int flags = VMCmdFlags.VM_CmdFlags[((VMPreparedCommand)commands.elementAt(i)).getOpCode()]; + if((flags & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC | VMCmdFlags.VMCF_USEFLAGS)) != 0) + { + flagsRequired = true; + break; + } + if((flags & VMCmdFlags.VMCF_CHFLAGS) != 0) + { + break; + } + } + if(flagsRequired) + { + continue; + } + switch(cmd.getOpCode()) + { + case VMCommands.VM_ADD: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_ADDB + : VMCommands.VM_ADDD); + continue; + case VMCommands.VM_SUB: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_SUBB + : VMCommands.VM_SUBD); + continue; + case VMCommands.VM_INC: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_INCB + : VMCommands.VM_INCD); + continue; + case VMCommands.VM_DEC: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_DECB + : VMCommands.VM_DECD); + continue; + case VMCommands.VM_NEG: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_NEGB + : VMCommands.VM_NEGD); + continue; + } + } + + } + + public static int ReadData(BitInput rarVM) + { + int data = rarVM.fgetbits(); + switch(data & 0xc000) + { + case 0: + rarVM.faddbits(6); + return ((data >> 10) & 0xf); + case 0x4000: + if((data & 0x3c00) == 0) + { + data = 0xffffff00 | ((data >> 2) & 0xff); + rarVM.faddbits(14); + } + else + { + data = (data >> 6) & 0xff; + rarVM.faddbits(10); + } + return (data); + case 0x8000: + rarVM.faddbits(2); + data = rarVM.fgetbits(); + rarVM.faddbits(16); + return (data); + default: + rarVM.faddbits(2); + data = (rarVM.fgetbits() << 16); + rarVM.faddbits(16); + data |= rarVM.fgetbits(); + rarVM.faddbits(16); + return (data); + } + } + + private int IsStandardFilter(byte[] code, int codeSize) + { + VMStandardFilterSignature stdList[] = + { + new VMStandardFilterSignature(53, 0xad576887, VMStandardFilters.VMSF_E8), + new VMStandardFilterSignature(57, 0x3cd7e57e, VMStandardFilters.VMSF_E8E9), + new VMStandardFilterSignature(120, 0x3769893f, VMStandardFilters.VMSF_ITANIUM), + new VMStandardFilterSignature(29, 0x0e06077d, VMStandardFilters.VMSF_DELTA), + new VMStandardFilterSignature(149, 0x1c2c5dc8, VMStandardFilters.VMSF_RGB), + new VMStandardFilterSignature(216, 0xbc85e701, VMStandardFilters.VMSF_AUDIO), + new VMStandardFilterSignature(40, 0x46b9c560, VMStandardFilters.VMSF_UPCASE) + }; + int CodeCRC = RarCRC.checkCrc(0xffffffff, code, 0, code.length) ^ 0xffffffff; + for(int i = 0; i < stdList.length; i++) + { + if(stdList[i].getCRC() == CodeCRC && stdList[i].getLength() == code.length) + { + return (stdList[i].getType()); + } + + } + return (VMStandardFilters.VMSF_NONE); + } + + private void ExecuteStandardFilter(int filterType) + { + switch(filterType) + { + case VMStandardFilters.VMSF_E8: + case VMStandardFilters.VMSF_E8E9: + { + int dataSize = R[4]; + long fileOffset = R[6] & 0xFFffFFff; + + if(dataSize >= VM_GLOBALMEMADDR) + { + break; + } + int fileSize = 0x1000000; + byte cmpByte2 = (byte) ((filterType == VMStandardFilters.VMSF_E8E9) ? 0xe9 : 0xe8); + for(int curPos = 0; curPos < dataSize - 4;) + { + byte curByte = mem[curPos++]; + if(curByte == 0xe8 || curByte == cmpByte2) + { +// #ifdef PRESENT_INT32 +// sint32 Offset=CurPos+FileOffset; +// sint32 Addr=GET_VALUE(false,Data); +// if (Addr<0) +// { +// if (Addr+Offset>=0) +// SET_VALUE(false,Data,Addr+FileSize); +// } +// else +// if (Addr= VM_GLOBALMEMADDR) + { + break; + } + int curPos = 0; + final byte Masks[] = + { + 4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0 + }; + fileOffset >>>= 4; + + while(curPos < dataSize - 21) + { + int Byte = (mem[curPos] & 0x1f) - 0x10; + if(Byte >= 0) + { + + byte cmdMask = Masks[Byte]; + if(cmdMask != 0) + { + for(int i = 0; i <= 2; i++) + { + if((cmdMask & (1 << i)) != 0) + { + int startPos = i * 41 + 5; + int opType = filterItanium_GetBits(curPos, startPos + 37, 4); + if(opType == 5) + { + int offset = filterItanium_GetBits(curPos, startPos + 13, 20); + filterItanium_SetBits(curPos, (int) (offset - fileOffset) & 0xfffff, startPos + 13, 20); + } + } + } + } + } + curPos += 16; + fileOffset++; + } + } + break; + case VMStandardFilters.VMSF_DELTA: + { + int dataSize = R[4] & 0xFFffFFff; + int channels = R[0] & 0xFFffFFff; + int srcPos = 0; + int border = (dataSize * 2) & 0xFFffFFff; + setValue(false, mem, VM_GLOBALMEMADDR + 0x20, (int) dataSize); + if(dataSize >= VM_GLOBALMEMADDR / 2) + { + break; + } +// bytes from same channels are grouped to continual data blocks, +// so we need to place them back to their interleaving positions + + for(int curChannel = 0; curChannel < channels; curChannel++) + { + byte PrevByte = 0; + for(int destPos = dataSize + curChannel; destPos < border; destPos += channels) + { + mem[destPos] = (PrevByte -= mem[srcPos++]); + } + + } + } + break; + case VMStandardFilters.VMSF_RGB: + { + // byte *SrcData=Mem,*DestData=SrcData+DataSize; + int dataSize = R[4], width = R[0] - 3, posR = R[1]; + int channels = 3; + int srcPos = 0; + int destDataPos = dataSize; + setValue(false, mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if(dataSize >= VM_GLOBALMEMADDR / 2 || posR < 0) + { + break; + } + for(int curChannel = 0; curChannel < channels; curChannel++) + { + long prevByte = 0; + + for(int i = curChannel; i < dataSize; i += channels) + { + long predicted; + int upperPos = i - width; + if(upperPos >= 3) + { + int upperDataPos = destDataPos + upperPos; + int upperByte = mem[(int) upperDataPos] & 0xff; + int upperLeftByte = mem[upperDataPos - 3] & 0xff; + predicted = prevByte + upperByte - upperLeftByte; + int pa = Math.abs((int) (predicted - prevByte)); + int pb = Math.abs((int) (predicted - upperByte)); + int pc = Math.abs((int) (predicted - upperLeftByte)); + if(pa <= pb && pa <= pc) + { + predicted = prevByte; + } + else + { + if(pb <= pc) + { + predicted = upperByte; + } + else + { + predicted = upperLeftByte; + } + } + } + else + { + predicted = prevByte; + } + + prevByte = (predicted - mem[srcPos++] & 0xff) & 0xff; + mem[destDataPos + i] = (byte) (prevByte & 0xff); + + } + } + for(int i = posR, border = dataSize - 2; i < border; i += 3) + { + byte G = mem[destDataPos + i + 1]; + mem[destDataPos + i] += G; + mem[destDataPos + i + 2] += G; + } + } + break; + case VMStandardFilters.VMSF_AUDIO: + { + int dataSize = R[4], channels = R[0]; + int srcPos = 0; + int destDataPos = dataSize; + //byte *SrcData=Mem,*DestData=SrcData+DataSize; + setValue(false, mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if(dataSize >= VM_GLOBALMEMADDR / 2) + { + break; + } + for(int curChannel = 0; curChannel < channels; curChannel++) + { + long prevByte = 0; + long prevDelta = 0; + long Dif[] = new long[7]; + int D1 = 0, D2 = 0, D3; + int K1 = 0, K2 = 0, K3 = 0; + + for(int i = curChannel, byteCount = 0; i < dataSize; i += channels, byteCount++) + { + D3 = D2; + D2 = (int) prevDelta - D1; + D1 = (int) prevDelta; + + long predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3; + predicted = (predicted >>> 3) & 0xff; + + long curByte = mem[srcPos++] & 0xff; + + predicted = (predicted - curByte) & UINT_MASK; + mem[destDataPos + i] = (byte) predicted; + prevDelta = (byte) (predicted - prevByte); + prevByte = predicted; + + int D = ((byte) curByte) << 3; + + Dif[0] += Math.abs(D); + Dif[1] += Math.abs(D - D1); + Dif[2] += Math.abs(D + D1); + Dif[3] += Math.abs(D - D2); + Dif[4] += Math.abs(D + D2); + Dif[5] += Math.abs(D - D3); + Dif[6] += Math.abs(D + D3); + + if((byteCount & 0x1f) == 0) + { + long minDif = Dif[0], numMinDif = 0; + Dif[0] = 0; + for(int j = 1; j < Dif.length; j++) + { + if(Dif[j] < minDif) + { + minDif = Dif[j]; + numMinDif = j; + } + Dif[j] = 0; + } + switch((int) numMinDif) + { + case 1: + if(K1 >= -16) + { + K1--; + } + break; + case 2: + if(K1 < 16) + { + K1++; + } + break; + case 3: + if(K2 >= -16) + { + K2--; + } + break; + case 4: + if(K2 < 16) + { + K2++; + } + break; + case 5: + if(K3 >= -16) + { + K3--; + } + break; + case 6: + if(K3 < 16) + { + K3++; + } + break; + } + } + } + } + } + break; + case VMStandardFilters.VMSF_UPCASE: + { + int dataSize = R[4], srcPos = 0, destPos = dataSize; + if(dataSize >= VM_GLOBALMEMADDR / 2) + { + break; + } + while(srcPos < dataSize) + { + byte curByte = mem[srcPos++]; + if(curByte == 2 && (curByte = mem[srcPos++]) != 2) + { + curByte -= 32; + } + mem[destPos++] = curByte; + } + setValue(false, mem, VM_GLOBALMEMADDR + 0x1c, destPos - dataSize); + setValue(false, mem, VM_GLOBALMEMADDR + 0x20, dataSize); + } + break; + } + + } + + private void filterItanium_SetBits(int curPos, int bitField, int bitPos, int bitCount) + { + int inAddr = bitPos / 8; + int inBit = bitPos & 7; + int andMask = 0xffffffff >>> (32 - bitCount); + andMask = ~(andMask << inBit); + + bitField <<= inBit; + + for(int i = 0; i < 4; i++) + { + mem[curPos + inAddr + i] &= andMask; + mem[curPos + inAddr + i] |= bitField; + andMask = (andMask >>> 8) | 0xff000000; + bitField >>>= 8; + } + + } + + private int filterItanium_GetBits(int curPos, int bitPos, int bitCount) + { + int inAddr = bitPos / 8; + int inBit = bitPos & 7; + int bitField = (int) (mem[curPos + inAddr++] & 0xff); + bitField |= (int) ((mem[curPos + inAddr++] & 0xff) << 8); + bitField |= (int) ((mem[curPos + inAddr++] & 0xff) << 16); + bitField |= (int) ((mem[curPos + inAddr] & 0xff) << 24); + bitField >>>= inBit; + return (bitField & (0xffffffff >>> (32 - bitCount))); + } + + public void setMemory(int pos, byte[] data, int offset, int dataSize) + { + if(pos < VM_MEMSIZE) + { //&& data!=Mem+Pos) + //memmove(Mem+Pos,Data,Min(DataSize,VM_MEMSIZE-Pos)); + for(int i = 0; i < Math.min(data.length - offset, dataSize); i++) + { + if((VM_MEMSIZE - pos) < i) + { + break; + } + mem[pos + i] = data[offset + i]; + } + } + } +} + +// diff --git a/src/com/innosystec/unrar/unpack/vm/VMCmdFlags.java b/src/com/innosystec/unrar/unpack/vm/VMCmdFlags.java new file mode 100644 index 0000000..2c45b2c --- /dev/null +++ b/src/com/innosystec/unrar/unpack/vm/VMCmdFlags.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMCmdFlags { + public static final byte VMCF_OP0 = 0; + public static final byte VMCF_OP1 = 1; + public static final byte VMCF_OP2 = 2; + public static final byte VMCF_OPMASK = 3; + public static final byte VMCF_BYTEMODE = 4; + public static final byte VMCF_JUMP = 8; + public static final byte VMCF_PROC = 16; + public static final byte VMCF_USEFLAGS = 32; + public static final byte VMCF_CHFLAGS = 64; + + public static byte VM_CmdFlags[]= + { + /* VM_MOV */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_CMP */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_ADD */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_SUB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_JZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JNZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_INC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_DEC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_JMP */ VMCF_OP1 | VMCF_JUMP , + /* VM_XOR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_AND */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_OR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_TEST */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_JS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JNS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JB */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JBE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JA */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JAE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_PUSH */ VMCF_OP1 , + /* VM_POP */ VMCF_OP1 , + /* VM_CALL */ VMCF_OP1 | VMCF_PROC , + /* VM_RET */ VMCF_OP0 | VMCF_PROC , + /* VM_NOT */ VMCF_OP1 | VMCF_BYTEMODE , + /* VM_SHL */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_SHR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_SAR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_NEG */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_PUSHA */ VMCF_OP0 , + /* VM_POPA */ VMCF_OP0 , + /* VM_PUSHF */ VMCF_OP0 | VMCF_USEFLAGS , + /* VM_POPF */ VMCF_OP0 | VMCF_CHFLAGS , + /* VM_MOVZX */ VMCF_OP2 , + /* VM_MOVSX */ VMCF_OP2 , + /* VM_XCHG */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_MUL */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_DIV */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_ADC */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS , + /* VM_SBB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS , + /* VM_PRINT */ VMCF_OP0 + }; + +} diff --git a/src/com/innosystec/unrar/unpack/vm/VMCommands.java b/src/com/innosystec/unrar/unpack/vm/VMCommands.java new file mode 100644 index 0000000..e943a09 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/vm/VMCommands.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMCommands +{ + public static final int + VM_MOV = (0), + VM_CMP = (1), + VM_ADD = (2), + VM_SUB = (3), + VM_JZ = (4), + VM_JNZ = (5), + VM_INC = (6), + VM_DEC = (7), + VM_JMP = (8), + VM_XOR = (9), + VM_AND = (10), + VM_OR = (11), + VM_TEST = (12), + VM_JS = (13), + VM_JNS = (14), + VM_JB = (15), + VM_JBE = (16), + VM_JA = (17), + VM_JAE = (18), + VM_PUSH = (19), + VM_POP = (20), + VM_CALL = (21), + VM_RET = (22), + VM_NOT = (23), + VM_SHL = (24), + VM_SHR = (25), + VM_SAR = (26), + VM_NEG = (27), + VM_PUSHA = (28), + VM_POPA = (29), + VM_PUSHF = (30), + VM_POPF = (31), + VM_MOVZX = (32), + VM_MOVSX = (33), + VM_XCHG = (34), + VM_MUL = (35), + VM_DIV = (36), + VM_ADC = (37), + VM_SBB = (38), + VM_PRINT = (39), + + // #ifdef VM_OPTIMIZE + VM_MOVB = (40), + VM_MOVD = (41), + VM_CMPB = (42), + VM_CMPD = (43), + VM_ADDB = (44), + VM_ADDD = (45), + VM_SUBB = (46), + VM_SUBD = (47), + VM_INCB = (48), + VM_INCD = (49), + VM_DECB = (50), + VM_DECD = (51), + VM_NEGB = (52), + VM_NEGD = (53), + // #endif*/ + + VM_STANDARD = (54); + + private int vmCommand; + + private VMCommands(int vmCommand) + { + this.vmCommand = vmCommand; + } + + public int getVMCommand() + { + return vmCommand; + } + + public boolean equals(int vmCommand) + { + return this.vmCommand == vmCommand; + } + + public static int findVMCommand(int vmCommand) + { + return vmCommand; + } +} diff --git a/src/com/innosystec/unrar/unpack/vm/VMFlags.java b/src/com/innosystec/unrar/unpack/vm/VMFlags.java new file mode 100644 index 0000000..c7b084a --- /dev/null +++ b/src/com/innosystec/unrar/unpack/vm/VMFlags.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMFlags +{ + public static final int + /** + * + */ + VM_FC = (1), + /** + * + */ + VM_FZ = (2), + /** + * + */ + VM_FS = (0x80000000); + + private int flag; + + private VMFlags(int flag) + { + this.flag = flag; + } + + /** + * Returns the VMFlags Type of the given int or null + * @param flag as int + * @return VMFlag of the int value + */ + public static int findFlag(int flag) + { + return flag; + } + + /** + * Returns true if the flag provided as int is equal to the enum + * @param flag + * @return returns true if the flag is equal to the enum + */ + public boolean equals(int flag) + { + return this.flag == flag; + } + + /** + * @return the flag as int + */ + public int getFlag() + { + return flag; + } +} diff --git a/src/com/innosystec/unrar/unpack/vm/VMOpType.java b/src/com/innosystec/unrar/unpack/vm/VMOpType.java new file mode 100644 index 0000000..c68e301 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/vm/VMOpType.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMOpType +{ + public static final int + VM_OPREG = (0), + VM_OPINT = (1), + VM_OPREGMEM = (2), + VM_OPNONE = (3); + + private int opType; + + private VMOpType(int opType) + { + this.opType = opType; + } + + public int getOpType() + { + return opType; + } + + public boolean equals(int opType) + { + return this.opType == opType; + } + + public static int findOpType(int opType) + { + return opType; + } +} diff --git a/src/com/innosystec/unrar/unpack/vm/VMPreparedCommand.java b/src/com/innosystec/unrar/unpack/vm/VMPreparedCommand.java new file mode 100644 index 0000000..86a9978 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/vm/VMPreparedCommand.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMPreparedCommand +{ + private int OpCode; + private boolean ByteMode; + private VMPreparedOperand Op1 = new VMPreparedOperand(); + private VMPreparedOperand Op2 = new VMPreparedOperand(); + + public boolean isByteMode() + { + return ByteMode; + } + + public void setByteMode(boolean byteMode) + { + ByteMode = byteMode; + } + + public VMPreparedOperand getOp1() + { + return Op1; + } + + public void setOp1(VMPreparedOperand op1) + { + Op1 = op1; + } + + public VMPreparedOperand getOp2() + { + return Op2; + } + + public void setOp2(VMPreparedOperand op2) + { + Op2 = op2; + } + + public int getOpCode() + { + return OpCode; + } + + public void setOpCode(int opCode) + { + OpCode = opCode; + } +} diff --git a/src/com/innosystec/unrar/unpack/vm/VMPreparedOperand.java b/src/com/innosystec/unrar/unpack/vm/VMPreparedOperand.java new file mode 100644 index 0000000..4d15417 --- /dev/null +++ b/src/com/innosystec/unrar/unpack/vm/VMPreparedOperand.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMPreparedOperand +{ + private int Type; + private int Data; + private int Base; + private int offset; + + public int getBase() + { + return Base; + } + + public void setBase(int base) + { + Base = base; + } + + public int getData() + { + return Data; + } + + public void setData(int data) + { + Data = data; + } + + public int getType() + { + return Type; + } + + public void setType(int type) + { + Type = type; + } + + public int getOffset() + { + return offset; + } + + public void setOffset(int offset) + { + this.offset = offset; + } +} diff --git a/src/com/innosystec/unrar/unpack/vm/VMPreparedProgram.java b/src/com/innosystec/unrar/unpack/vm/VMPreparedProgram.java new file mode 100644 index 0000000..d83f59d --- /dev/null +++ b/src/com/innosystec/unrar/unpack/vm/VMPreparedProgram.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.vm; + +import java.util.Vector; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMPreparedProgram +{ + private Vector Cmd = new Vector(); + private Vector AltCmd =new Vector(); + private int CmdCount; + + + + private Vector GlobalData = new Vector(); + private Vector StaticData = new Vector(); // static data contained in DB operators + private int InitR[] = new int[7]; + + private int FilteredDataOffset; + private int FilteredDataSize; + + public VMPreparedProgram() + { + AltCmd=null; + } + + + + public Vector getAltCmd() { + return AltCmd; + } + + + + public void setAltCmd(Vector altCmd) { + AltCmd = altCmd; + } + + + + public Vector getCmd() { + return Cmd; + } + + public void setCmd(Vector cmd) { + Cmd = cmd; + } + + public int getCmdCount() { + return CmdCount; + } + + public void setCmdCount(int cmdCount) { + CmdCount = cmdCount; + } + + + + public int getFilteredDataOffset() { + return FilteredDataOffset; + } + + + + public void setFilteredDataOffset(int filteredDataOffset) { + FilteredDataOffset = filteredDataOffset; + } + + + + public int getFilteredDataSize() { + return FilteredDataSize; + } + + public void setFilteredDataSize(int filteredDataSize) { + FilteredDataSize = filteredDataSize; + } + + public Vector getGlobalData() { + return GlobalData; + } + + public void setGlobalData(Vector globalData) { + GlobalData = globalData; + } + + public int[] getInitR() { + return InitR; + } + + public void setInitR(int[] initR) { + InitR = initR; + } + + public Vector getStaticData() { + return StaticData; + } + + public void setStaticData(Vector staticData) { + StaticData = staticData; + } + + +} diff --git a/src/com/innosystec/unrar/unpack/vm/VMStandardFilterSignature.java b/src/com/innosystec/unrar/unpack/vm/VMStandardFilterSignature.java new file mode 100644 index 0000000..5e8842d --- /dev/null +++ b/src/com/innosystec/unrar/unpack/vm/VMStandardFilterSignature.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMStandardFilterSignature +{ + private int length; + private int CRC; + private int type; + + public VMStandardFilterSignature(int length, int crc, int type) + { + super(); + this.length = length; + CRC = crc; + this.type = type; + } + + public int getCRC() + { + return CRC; + } + + public void setCRC(int crc) + { + CRC = crc; + } + + public int getLength() + { + return length; + } + + public void setLength(int length) + { + this.length = length; + } + + public int getType() + { + return type; + } + + public void setType(int type) + { + this.type = type; + } +} diff --git a/src/com/innosystec/unrar/unpack/vm/VMStandardFilters.java b/src/com/innosystec/unrar/unpack/vm/VMStandardFilters.java new file mode 100644 index 0000000..7f5cffb --- /dev/null +++ b/src/com/innosystec/unrar/unpack/vm/VMStandardFilters.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMStandardFilters +{ + public static final int + VMSF_NONE = ((int) 0), + VMSF_E8 = ((int) 1), + VMSF_E8E9 = ((int) 2), + VMSF_ITANIUM = ((int) 3), + VMSF_RGB = ((int) 4), + VMSF_AUDIO = ((int) 5), + VMSF_DELTA = ((int) 6), + VMSF_UPCASE = ((int) 7); + + private int filter; + + private VMStandardFilters(int filter) + { + this.filter = filter; + } + + public int getFilter() + { + return filter; + } + + public boolean equals(int filter) + { + return this.filter == filter; + } + + public static int findFilter(int filter) + { + return filter; + } +} diff --git a/src/com/innosystec/unrar/unsigned/UnsignedByte.java b/src/com/innosystec/unrar/unsigned/UnsignedByte.java new file mode 100644 index 0000000..6667e31 --- /dev/null +++ b/src/com/innosystec/unrar/unsigned/UnsignedByte.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unsigned; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class UnsignedByte +{ + public static byte longToByte(long unsignedByte1) + { + return (byte) (unsignedByte1 & 0xff); + } + + public static byte intToByte(int unsignedByte1) + { + return (byte) (unsignedByte1 & 0xff); + } + + public static byte shortToByte(short unsignedByte1) + { + return (byte) (unsignedByte1 & 0xff); + } + + public static short add(byte unsignedByte1, byte unsignedByte2) + { + return (short) (unsignedByte1 + unsignedByte2); + } + + public static short sub(byte unsignedByte1, byte unsignedByte2) + { + + return (short) (unsignedByte1 - unsignedByte2); + } + + public static void main(String[] args) + { + //tests unsigned (signed) + //add + System.out.println(add((byte) 0xfe, (byte) 0x01)); //255 (-1) + System.out.println(add((byte) 0xff, (byte) 0x01)); //0 (0) + System.out.println(add((byte) 0x7f, (byte) 0x01)); //128 (-128) + System.out.println(add((byte) 0xff, (byte) 0xff)); //254 (-2) + + //sub + System.out.println(sub((byte) 0xfe, (byte) 0x01)); //253 (-3) + System.out.println(sub((byte) 0x00, (byte) 0x01)); //255 (-1) + System.out.println(sub((byte) 0x80, (byte) 0x01)); //127 (127) + //mul + System.out.println((byte) -1 * (byte) -1); + } +} diff --git a/src/com/innosystec/unrar/unsigned/UnsignedInteger.java b/src/com/innosystec/unrar/unsigned/UnsignedInteger.java new file mode 100644 index 0000000..460d682 --- /dev/null +++ b/src/com/innosystec/unrar/unsigned/UnsignedInteger.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unsigned; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class UnsignedInteger { + +} diff --git a/src/com/innosystec/unrar/unsigned/UnsignedLong.java b/src/com/innosystec/unrar/unsigned/UnsignedLong.java new file mode 100644 index 0000000..240c993 --- /dev/null +++ b/src/com/innosystec/unrar/unsigned/UnsignedLong.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unsigned; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class UnsignedLong { + +} diff --git a/src/com/innosystec/unrar/unsigned/UnsignedShort.java b/src/com/innosystec/unrar/unsigned/UnsignedShort.java new file mode 100644 index 0000000..02c331c --- /dev/null +++ b/src/com/innosystec/unrar/unsigned/UnsignedShort.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.innosystec.unrar.unsigned; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class UnsignedShort { + +} diff --git a/src/com/one/Accelerometer.java b/src/com/one/Accelerometer.java new file mode 100644 index 0000000..ff79e76 --- /dev/null +++ b/src/com/one/Accelerometer.java @@ -0,0 +1,7 @@ +package com.one; + +public interface Accelerometer +{ + public int getValue(int channel); + public int getDelta(int channel, int threshold); +} diff --git a/src/com/one/Application.java b/src/com/one/Application.java new file mode 100644 index 0000000..00629ba --- /dev/null +++ b/src/com/one/Application.java @@ -0,0 +1,8 @@ +package com.one; + +import java.io.IOException; + +public interface Application +{ + public void openFile(String filename, PlayList filelist) throws IOException; +} diff --git a/src/com/one/AsyncRenderer.java b/src/com/one/AsyncRenderer.java new file mode 100644 index 0000000..3cb3efb --- /dev/null +++ b/src/com/one/AsyncRenderer.java @@ -0,0 +1,118 @@ +package com.one; + +import com.vmx.AuxClass; +import java.util.Vector; + +public class AsyncRenderer extends Renderer implements Runnable +{ + public static final int KEY_PRESSED = 0; + public static final int KEY_RELEASED = 1; + public static final int KEY_REPEATED = 2; + + public static class KeyEvent + { + public int type; + public int key; + + public KeyEvent(int type, int key) + { + this.type = type; + this.key = key; + } + } + + protected final Vector queue = new Vector(); + protected boolean isrunning; + protected KeyEvent currevent; + + public AsyncRenderer() + { + (new Thread(this, "AsyncRenderer/EventDispatch")).start(); + } + + public void keyPressed(int keyCode) + { + enqueueEvent(new KeyEvent(KEY_PRESSED, keyCode)); + } + + public void keyReleased(int keyCode) + { + enqueueEvent(new KeyEvent(KEY_RELEASED, keyCode)); + } + + public void keyRepeated(int keyCode) + { + enqueueEvent(new KeyEvent(KEY_REPEATED, keyCode)); + } + + public void enqueueEvent(KeyEvent event) + { + synchronized(queue) + { + if(isrunning) + { + if(event.type != KEY_REPEATED && (event.type == currevent.type ? event.key != currevent.key : true)) + { + if(queue.isEmpty()) + { + queue.addElement(event); + } + else + { + KeyEvent lastevent = (KeyEvent)queue.elementAt(queue.size() - 1); + + if(event.type != lastevent.type || event.key != lastevent.key) + { + queue.addElement(event); + } + } + } + } + else + { + queue.addElement(event); + queue.notifyAll(); + } + } + } + + public void run() + { + while(true) + { + try + { + synchronized(queue) + { + if(queue.isEmpty()) + { + isrunning = false; + queue.wait(); + } + + isrunning = true; + + currevent = (KeyEvent)queue.elementAt(0); + queue.removeElementAt(0); + } + + if(currevent.type == KEY_PRESSED) + { + super.keyPressed(currevent.key); + } + else if(currevent.type == KEY_RELEASED) + { + super.keyReleased(currevent.key); + } + else + { + super.keyRepeated(currevent.key); + } + } + catch(InterruptedException ie) + { + System.out.println("Event dispatch thread interrupted"); + } + } + } +} \ No newline at end of file diff --git a/src/com/one/AutoAdvanceScreen.java b/src/com/one/AutoAdvanceScreen.java new file mode 100644 index 0000000..d59d0e0 --- /dev/null +++ b/src/com/one/AutoAdvanceScreen.java @@ -0,0 +1,10 @@ +package com.one; + +import javax.microedition.lcdui.CommandListener; + +public interface AutoAdvanceScreen extends Runnable +{ + public boolean finiteTimeout(); + public void setCommandListener(CommandListener cl); + public void run(); +} diff --git a/src/com/one/BufferedInputStream.java b/src/com/one/BufferedInputStream.java new file mode 100644 index 0000000..62513c2 --- /dev/null +++ b/src/com/one/BufferedInputStream.java @@ -0,0 +1,220 @@ +package com.one; + +import com.vmx.AuxClass; +import java.io.*; + + +/** + * Входной поток Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð¹ буферизацией. + * Призван работать там, где требуетÑÑ Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶ÐºÐ° mark / reset, но ее почему - то нет. + */ +public class BufferedInputStream extends RandomAccessInputStream +{ + protected InputStream is = null; + protected byte[] buf = null; + protected int currpos; // Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ð¿ÐµÑ€Ð²Ð¾Ð³Ð¾ неÑчитанного байта + protected int readpos; // Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ð¿ÐµÑ€Ð²Ð¾Ð³Ð¾ неинициализированного байта + protected int markedpos; // Ð¼Ð°Ñ€ÐºÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ + + public BufferedInputStream(InputStream is) throws IOException + { + this(is, true); + } + + public BufferedInputStream(InputStream is, boolean prebuffer) throws IOException + { + if(prebuffer) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] b = new byte[AuxClass.ARCBUFSIZE]; + int len; + + try + { + while(true) + { + len = is.read(b); + + if(len > 0) + { + baos.write(b, 0, len); + } + else + { + break; + } + } + + is.close(); + is = null; + + b = null; + + System.gc(); + + buf = baos.toByteArray(); + readpos = buf.length; + + baos.close(); + } + catch(OutOfMemoryError oome) + { + baos.close(); + throw new IOException("Consider this as \"OutOfMemoryError\""); + } + } + else + { + this.is = is; + + System.gc(); + + buf = new byte[is.available()]; + readpos = 0; + } + + currpos = 0; + markedpos = 0; + } + + public BufferedInputStream(byte[] data) + { + this.is = null; + + buf = data; + + currpos = 0; + readpos = data.length; + markedpos = 0; + } + + public int available() + { + return buf.length - currpos; + } + + public void close() throws IOException + { + if(is != null) + { + is.close(); + is = null; + } + + buf = null; + + System.gc(); + } + + public void mark(int readLimit) + { + markedpos = currpos; + } + + public int read() throws IOException + { + if(currpos >= buf.length) // конец потока + { + return -1; + } + + bufferize(currpos); + + return ((int)buf[currpos++]) & 0xFF; + } + + public int read(byte[] b) throws IOException + { + return read(b, 0, b.length); + } + + public int read(byte[] b, int off, int len) throws IOException + { + int available = available(); + + if(available <= 0) + { + return -1; + } + + if(len > available) + { + len = available; + } + + bufferize(currpos + len - 1); + + System.arraycopy(buf, currpos, b, off, len); + + currpos += len; + + return len; + } + + public void reset() + { + currpos = markedpos; + } + + public long skip(long n) + { + if(n > available()) + { + n = available(); + } + + currpos += n; + + return n; + } + + public void setPosition(int pos) + { + if(pos == currpos) + { + return; + } + + if(pos < 0) + { + currpos = 0; + } + else if(pos > getCapacity()) + { + currpos = getCapacity(); + } + else + { + currpos = pos; + } + } + + public int getPosition() + { + return currpos; + } + + public int getCapacity() + { + return buf.length; + } + + public void update() + { + } + + /** + * Заполнить буфер, чтобы из него можно было получить байт ÐРПОЗИЦИИ target + * ОбÑзанноÑÑ‚ÑŒ вызывающего Ñледить чтобы выполнÑлоÑÑŒ target < buf.length + */ + protected void bufferize(int target) throws IOException + { + if(is != null) + { + while(readpos <= target) + { + buf[readpos++] = (byte)is.read(); + } + } + } +} diff --git a/src/com/one/Container.java b/src/com/one/Container.java new file mode 100644 index 0000000..c93ff59 --- /dev/null +++ b/src/com/one/Container.java @@ -0,0 +1,373 @@ +package com.one; + +import com.classpath.io.PipedInputStream; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.AuxClass; +import com.vmx.Locale; +import com.vmx.ProgressCallback; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.Hashtable; + +public abstract class Container +{ + protected FileConnection file; + protected RandomAccessInputStream rais; + protected boolean closed; + protected boolean finished; + + protected Hashtable entries; + protected Hashtable files; + + public void init(FileConnection base, boolean create) throws IOException + { + file = base; + + if(file.isDirectory()) + { + file.close(); + throw new IOException("Not a file: " + file.getPath() + file.getName()); + } + else if(!file.exists()) + { + if(create) + { + file.create(); + } + else + { + file.close(); + throw new IOException("File does not exist: " + file.getPath() + file.getName()); + } + } + + rais = new FileInputStream(file); + + if(rais.getCapacity() == 0) + { + entries = new Hashtable(); + finished = false; + } + else + { + checkFormat(); + finished = true; + } + + files = new Hashtable(); + } + + public void init(RandomAccessInputStream rais) throws IOException + { + this.rais = rais; + + checkFormat(); + + finished = true; + files = new Hashtable(); + } + + protected void checkFormat() throws IOException + { + } + + public FileConnection getFileConnection(String file, int mode) throws IOException + { + checkClosed(); + checkEntries(); + return new ContainerFileConnection(this.file, this, file, mode); + } + + protected void checkClosed() + { + if(closed) + { + throw new IllegalStateException("Container is closed"); + } + } + + public boolean isReadOnly() + { + checkClosed(); + return file != null ? !file.canWrite() : true; + } + + protected void checkReadOnly() throws IOException + { + if(isReadOnly()) + { + throw new IOException("Container is read only"); + } + } + + protected void checkEntries() throws IOException + { + if(entries == null) + { + readEntries(); + } + } + + protected abstract void readEntries() throws IOException; + + public abstract boolean addEntry(RandomAccessInputStream source, String name, long time, boolean replace, ProgressCallback callback) throws IOException; + public abstract boolean deleteEntry(ContainerEntry entry) throws IOException; + + public void renameDirectory(String oldName, String newName) throws IOException + { + checkReadOnly(); + checkEntries(); + + Enumeration e = entries.elements(); + ContainerEntry entry; + String entryName, baseName; + int index; + + index = oldName.substring(0, oldName.length() - 1).lastIndexOf('/'); + baseName = oldName.substring(0, index + 1); + index = oldName.length(); + + while(e.hasMoreElements()) + { + entry = (ContainerEntry)e.nextElement(); + entryName = entry.getName(); + + if(entryName.startsWith(oldName)) + { + renameEntry(entry, baseName + newName + entryName.substring(index)); + } + } + } + + public abstract boolean renameEntry(ContainerEntry entry, String newName) throws IOException; + + public void updateOffset(int base, int delta) throws IOException + { + if(finished) + { + return; + } + + checkReadOnly(); + checkEntries(); + + Enumeration e = entries(); + ContainerEntry entry; + + while(e.hasMoreElements()) + { + entry = (ContainerEntry)e.nextElement(); + + if(entry.offset > base) + { + entry.offset += delta; + } + } + } + + public abstract void finish() throws IOException; + + public void close() throws IOException + { + Enumeration e = entries.elements(); + + while(e.hasMoreElements()) + { + realizeEntry((ContainerEntry)e.nextElement()); + } + + if(!finished) + { + finish(); + } + + ProgressBar.hide(); + + closed = true; + entries = null; + files = null; + + if(rais != null) + { + rais.close(); + rais = null; + } + + if(file != null) + { + file.close(); + file = null; + } + } + + public Enumeration entries() throws IOException + { + checkClosed(); + checkEntries(); + + return entries.elements(); + } + + public ContainerEntry getEntry(String name) throws IOException + { + if(name.endsWith("/")) + { + if(listFiles(name) != null) + { + return new ContainerEntry(name); + } + else + { + return null; + } + } + else + { + checkClosed(); + checkEntries(); + + return (ContainerEntry)entries.get(name); + } + } + + public abstract InputStream getInputStream(ContainerEntry entry) throws IOException; + + public int size() throws IOException + { + checkClosed(); + checkEntries(); + + return entries.size(); + } + + public boolean entryExists(String name) throws IOException + { + checkClosed(); + checkEntries(); + + return entries.containsKey(name); + } + + public long directorySize(String path, boolean includeSubDirs) + { + long size = 0; + + Enumeration e = listFiles(path); + String s; + + while(e.hasMoreElements()) + { + s = (String)e.nextElement(); + + if(s.endsWith("/")) + { + if(includeSubDirs) + { + size += directorySize(path + s, true); + } + } + else + { + size += ((ContainerEntry)entries.get(path + s)).getSize(); + } + } + + return size; + } + + public void virtualizeEntry(ContainerEntry entry) throws IOException + { + checkEntries(); + + if(!entries.containsKey(entry.getName())) + { + checkReadOnly(); + entries.put(entry.getName(), entry); + } + + if(entry.vfc == null) + { + entry.vfc = (FileConnection)Connector.open("file:///" + Connector.createTempFile(file.getPath(), false)); + entry.vfc.create(); + + if(!entry.pureVirtual) + { + ProgressCallback callback = ProgressBar.getProgressCallback(); + ProgressBar.show(); + + callback.setText(Locale.getString(this, Locale.UNPACKING_FILE, entry.getName())); + + byte[] buf = new byte[AuxClass.COPYBUFSIZE]; + int len, total; + + InputStream is = getInputStream(entry); + OutputStream os = entry.vfc.openOutputStream(); + + total = 0; + callback.setMax(is.available()); + + while((len = is.read(buf)) > 0) + { + os.write(buf, 0, len); + total += len; + + if(callback.getMax() < total) + { + callback.setPercentMode(false); + callback.setMax(total); + } + + callback.setProgress(total); + } + + os.close(); + is.close(); + + ProgressBar.hide(); + } + } + } + + public void realizeEntry(ContainerEntry entry) throws IOException + { + if(entry.vfc != null) + { + checkReadOnly(); + checkEntries(); + + ProgressCallback callback = ProgressBar.getProgressCallback(); + ProgressBar.show(); + + deleteEntry(entry); + addEntry(new FileInputStream(entry.vfc), entry.getName(), -1, false, callback); + + Connector.releaseTempFile(entry.vfc.getPath() + entry.vfc.getName()); + + entry.vfc.delete(); + entry.vfc.close(); + } + } + + public void addFile(String file) + { + Directory.addFile(files, file); + } + + public void deleteFile(String file) + { + Directory.deleteFile(files, file); + } + + public Enumeration listFiles(String path) + { + return Directory.listFiles(files, path); + } + + public boolean fileExists(String file) + { + return Directory.fileExists(files, file); + } +} \ No newline at end of file diff --git a/src/com/one/ContainerEntry.java b/src/com/one/ContainerEntry.java new file mode 100644 index 0000000..8f38a68 --- /dev/null +++ b/src/com/one/ContainerEntry.java @@ -0,0 +1,65 @@ +package com.one; + +import com.one.file.FileConnection; + +public class ContainerEntry +{ + protected String name = ""; + protected int size = -1; + protected int compressedSize = -1; + protected long lastModified = -1; + + public FileConnection vfc; + public boolean pureVirtual; + + public int offset; + + public ContainerEntry() + { + } + + public ContainerEntry(String name) + { + setName(name); + } + + public void setName(String name) + { + this.name = name; + } + + public String getName() + { + return name; + } + + public void setSize(int size) + { + this.size = size; + } + + public int getSize() + { + return size; + } + + public void setCompressedSize(int size) + { + this.compressedSize = size; + } + + public int getCompressedSize() + { + return compressedSize; + } + + public void setLastModified(long time) + { + lastModified = time; + } + + public long getLastModified() + { + return lastModified; + } +} diff --git a/src/com/one/ContainerFileConnection.java b/src/com/one/ContainerFileConnection.java new file mode 100644 index 0000000..819316a --- /dev/null +++ b/src/com/one/ContainerFileConnection.java @@ -0,0 +1,320 @@ +package com.one; + +import com.one.file.Connector; +import com.one.file.FileConnection; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.Vector; + +public class ContainerFileConnection implements FileConnection +{ + protected FileConnection base; + protected Container container; + protected ContainerEntry entry; + protected int mode; + + protected String contname; // Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° от диÑка до имени контейнера включительно + protected String filepath; // путь к файлу внутри контейнера + protected String filename; // Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° + + protected boolean isdirectory; + + public ContainerFileConnection(FileConnection base, Container container, String file, int mode) throws IOException + { + this.base = base; + this.container = container; + this.mode = mode; + + contname = base.getPath() + base.getName() + "/"; + int index = file.lastIndexOf('/') + 1; + filepath = file.substring(0, index); + filename = file.substring(index); + + entry = container.getEntry(file); + + if(entry == null) + { + entry = new ContainerEntry(filepath + filename); + entry.pureVirtual = true; + } + + isdirectory = filename.endsWith("/") || filename.length() == 0; + } + + public void close() + { + } + + public long availableSize() + { + return base.availableSize(); + } + + public boolean canRead() + { + return true; + } + + public boolean canWrite() + { + return !container.isReadOnly(); + } + + public void create() throws IOException + { + if(exists() || isdirectory) + { + throw new IOException("Entry already exists or is a directory"); + } + + container.virtualizeEntry(entry); + container.addFile(entry.getName()); + } + + public void delete() throws IOException + { + if(!exists()) + { + throw new IOException("Entry does not exist"); + } + + if(isdirectory && container.listFiles(filepath).hasMoreElements()) + { + throw new IOException("Directory is not empty"); + } + + if(!container.deleteEntry(entry)) + { + throw new IOException("Entry not deleted or not found"); + } + } + + public long directorySize(boolean includeSubDirs) throws IOException + { + if(!isdirectory) + { + throw new IOException("Entry is a file"); + } + + return container.directorySize(filepath, includeSubDirs); + } + + public boolean exists() + { + return entry.getName().length() > 0 ? container.fileExists(entry.getName()) : true; + } + + public long fileSize() throws IOException + { + if(isdirectory) + { + throw new IOException("Entry is a directory"); + } + + if(entry.vfc != null) + { + return entry.vfc.fileSize(); + } + else + { + return entry.getSize(); + } + } + + public long compressedSize() throws IOException + { + if(isdirectory) + { + throw new IOException("Entry is a directory"); + } + + return entry.getCompressedSize(); + } + + public String getName() + { + return filename; + } + + public String getPath() + { + return contname + filepath; + } + + public String getURL() + { + return "file:///" + contname + filepath + filename; + } + + public boolean isDirectory() + { + return isdirectory; + } + + public boolean isHidden() + { + return false; + } + + public boolean isOpen() + { + return entry != null; + } + + public long lastModified() + { + long time = entry.getLastModified(); + return time >= 0 ? time : base.lastModified(); + } + + public Enumeration list() throws IOException + { + if(!exists() || !isdirectory) + { + throw new IOException("Entry does not exist or is a file"); + } + + return container.listFiles(filepath); + } + + public Enumeration list(String filter, boolean includeHidden) throws IOException + { + Enumeration srcfiles = list(); + Vector dstfiles = new Vector(); + StringPattern pattern = new StringPattern(filter, true); + String fname; + + while(srcfiles.hasMoreElements()) + { + fname = (String)srcfiles.nextElement(); + + if(pattern.matchesWith(fname)) + { + dstfiles.addElement(fname); + } + } + + return dstfiles.elements(); + } + + public void mkdir() throws IOException + { + if(exists() || !isdirectory) + { + throw new IOException("Entry already exists or is a file"); + } + + container.addFile(entry.getName()); + } + + public DataInputStream openDataInputStream() throws IOException + { + return new DataInputStream(openInputStream()); + } + + public DataOutputStream openDataOutputStream() throws IOException + { + return new DataOutputStream(openOutputStream()); + } + + public InputStream openInputStream() throws IOException + { + if(!exists() || isdirectory) + { + throw new IOException("Entry does not exist or is a directory"); + } + + if(mode != Connector.READ) + { + container.virtualizeEntry(entry); + } + + if(entry.vfc != null) + { + return entry.vfc.openInputStream(); + } + else + { + return container.getInputStream(entry); + } + } + + public OutputStream openOutputStream() throws IOException + { + if(!exists() || isdirectory) + { + throw new IOException("Entry does not exist or is a directory"); + } + + container.virtualizeEntry(entry); + + return entry.vfc.openOutputStream(); + } + + public OutputStream openOutputStream(long byteOffset) throws IOException + { + if(!exists() || isdirectory) + { + throw new IOException("Entry does not exist or is a directory"); + } + + container.virtualizeEntry(entry); + + return entry.vfc.openOutputStream(byteOffset); + } + + public void rename(String newName) throws IOException + { + if(isdirectory) + { + container.renameDirectory(entry.getName(), filepath + newName); + } + else + { + container.renameEntry(entry, filepath + newName); + } + } + + public void setFileConnection(String fileName) throws IOException + { + throw new IOException("Operation not supported"); + } + + public void setHidden(boolean hidden) + { + } + + public void setReadable(boolean readable) + { + } + + public void setWritable(boolean writable) + { + } + + public long totalSize() + { + return base.totalSize(); + } + + public void truncate(long byteOffset) throws IOException + { + if(!exists() || isdirectory) + { + throw new IOException("Entry does not exist or is a directory"); + } + + container.virtualizeEntry(entry); + + entry.vfc.truncate(byteOffset); + } + + public long usedSize() + { + return base.totalSize(); + } +} diff --git a/src/com/one/CubicSpline.java b/src/com/one/CubicSpline.java new file mode 100644 index 0000000..93fa412 --- /dev/null +++ b/src/com/one/CubicSpline.java @@ -0,0 +1,814 @@ +/************************************************************************* +Copyright (c) 2007, Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses + +>>> END OF LICENSE >>> +*************************************************************************/ + +package com.one; + +public class CubicSpline +{ + /************************************************************************* + РеÑÑмплирование бикубичеÑким Ñплайном. + + Процедура получает Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ на Ñетке OldWidth*OldHeight и + путем интерполÑции бикубичеÑким Ñплайном вычиÑлÑет Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ в + узлах Декартовой Ñетки размером NewWidth*NewHeight. ÐÐ¾Ð²Ð°Ñ Ñетка может быть + как более, так и менее плотнаÑ, чем ÑтараÑ. + + Входные параметры: + A - маÑÑив значений функции на Ñтарой Ñетке. + ÐÑƒÐ¼ÐµÑ€Ð°Ñ†Ð¸Ñ Ñлементов [0..OldHeight-1, + 0..OldWidth-1] + OldHeight - Ñтарый размер Ñетки, OldHeight>1 + OldWidth - Ñтарый размер Ñетки, OldWidth>1 + NewHeight - новый размер Ñетки, NewHeight>1 + NewWidth - новый размер Ñетки, NewWidth>1 + + Выходные параметры: + B - маÑÑив значений функции на новой Ñетке. + ÐÑƒÐ¼ÐµÑ€Ð°Ñ†Ð¸Ñ Ñлементов [0..NewHeight-1, + 0..NewWidth-1] + + -- ALGLIB routine -- + 15 May, 2007 + Copyright by Bochkanov Sergey + *************************************************************************/ + public static float[][] bicubicResampleCartesian(float[][] a, int oldheight, int oldwidth, int newheight, int newwidth) + { + float[][] buf; + float[][] b; + + float[] x; + float[] y; + float[] c; + + int i = 0; + int j = 0; + int mw = 0; + int mh = 0; + + // + // Prepare + // + + mw = Math.max(oldwidth, newwidth); + mh = Math.max(oldheight, newheight); + + buf = new float[oldheight][newwidth]; + b = new float[newheight][newwidth]; + + x = new float[Math.max(mw, mh)]; + y = new float[Math.max(mw, mh)]; + + // + // Horizontal interpolation + // + + for(i = 0; i < oldheight; i++) + { + + // + // Fill X, Y + // + + for(j = 0; j < oldwidth; j++) + { + x[j] = (float)j / (float)(oldwidth - 1); + y[j] = a[i][j]; + } + + // + // Interpolate and place result into temporary matrix + // + + c = CubicSpline.buildCubicSpline(x, y, oldwidth, 0, 0.0f, 0, 0.0f); + + for(j = 0; j < newwidth; j++) + { + buf[i][j] = CubicSpline.splineInterpolation(c, (float)j / (float)(newwidth - 1)); + } + } + + // + // Vertical interpolation + // + + for(j = 0; j < newwidth; j++) + { + + // + // Fill X, Y + // + + for(i = 0; i < oldheight; i++) + { + x[i] = (float)i / (float)(oldheight - 1); + y[i] = buf[i][j]; + } + + // + // Interpolate and place result into B + // + + c = CubicSpline.buildCubicSpline(x, y, oldheight, 0, 0.0f, 0, 0.0f); + + for(i = 0; i < newheight; i++) + { + b[i][j] = CubicSpline.splineInterpolation(c, (float)i / (float)(newheight - 1)); + } + } + + return b; + } + + /************************************************************************* + ПоÑтроение таблицы коÑффициентов кубичеÑкого Ñплайна + + Входные параметры: + X - абÑциÑÑÑ‹, маÑÑив Ñ Ð½ÑƒÐ¼ÐµÑ€Ð°Ñ†Ð¸ÐµÐ¹ Ñлементов [0..N-1] + Y - Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸, + маÑÑив Ñ Ð½ÑƒÐ¼ÐµÑ€Ð°Ñ†Ð¸ÐµÐ¹ Ñлементов [0..N-1] + N - чиÑло точек, N>=2 + BoundLType - тип граничного уÑÐ»Ð¾Ð²Ð¸Ñ (Ð»ÐµÐ²Ð°Ñ Ð³Ñ€Ð°Ð½Ð¸Ñ†Ð°) + BoundL - значение первой (или второй, в завиÑимоÑти от + BoundType) производной Ñплайна на левой границе + BoundRType - тип граничного уÑÐ»Ð¾Ð²Ð¸Ñ (Ð¿Ñ€Ð°Ð²Ð°Ñ Ð³Ñ€Ð°Ð½Ð¸Ñ†Ð°) + BoundR - значение первой (или второй, в завиÑимоÑти от + BoundType) производной Ñплайна на правой границе + + Выходные параметры: + C - таблица коÑффициентов Ñплайна Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² + подпрограмме SplineInterpolation + + Параметры BoundLType/BoundRType задают тип граничного уÑÐ»Ð¾Ð²Ð¸Ñ Ð¸ принимают + Ñледующие значениÑ: + * 0, что ÑоответÑтвует граничному уÑловию типа "Ñплайн, завершающийÑÑ + параболой" (при Ñтом Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ BoundL/BoundR игнорируютÑÑ). + * 1, что ÑоответÑтвует граничному уÑловию Ð´Ð»Ñ Ð¿ÐµÑ€Ð²Ð¾Ð¹ производной + * 2, что ÑоответÑтвует граничному уÑловию Ð´Ð»Ñ Ð²Ñ‚Ð¾Ñ€Ð¾Ð¹ производной + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey + *************************************************************************/ + public static float[] buildCubicSpline(float[] x, float[] y, int n, int boundltype, float boundl, int boundrtype, float boundr) + { + if(n < 2 || boundltype < 0 || boundltype > 2 || boundrtype < 0 || boundrtype > 2) + { + throw new IllegalArgumentException(); + } + + float[] d; + int i = 0; + int tblsize = 0; + float delta = 0; + float delta2 = 0; + float delta3 = 0; + + x = cloneArray(x); + y = cloneArray(y); + + float[] a1 = new float[n]; + float[] a2 = new float[n]; + float[] a3 = new float[n]; + float[] b = new float[n]; + + // + // Special case: + // * N=2 + // * parabolic terminated boundary condition on both ends + // + + if(n == 2 & boundltype == 0 & boundrtype == 0) + { + + // + // Change task type + // + + boundltype = 2; + boundl = 0; + boundrtype = 2; + boundr = 0; + } + + // + // Sort points + // + + heapSortPoints(x, y, n); + + // + // Left boundary conditions + // + + if(boundltype == 0) + { + a1[0] = 0; + a2[0] = 1; + a3[0] = 1; + b[0] = 2 * (y[1] - y[0]) / (x[1] - x[0]); + } + + if(boundltype == 1) + { + a1[0] = 0; + a2[0] = 1; + a3[0] = 0; + b[0] = boundl; + } + + if(boundltype == 2) + { + a1[0] = 0; + a2[0] = 2; + a3[0] = 1; + b[0] = 3 * (y[1] - y[0]) / (x[1] - x[0]) - 0.5f * boundl * (x[1] - x[0]); + } + + // + // Central conditions + // + + for(i = 1; i <= n - 2; i++) + { + a1[i] = x[i + 1] - x[i]; + a2[i] = 2 * (x[i + 1] - x[i - 1]); + a3[i] = x[i] - x[i - 1]; + b[i] = 3 * (y[i] - y[i - 1]) / (x[i] - x[i - 1]) * (x[i + 1] - x[i]) + 3 * (y[i + 1] - y[i]) / (x[i + 1] - x[i]) * (x[i] - x[i - 1]); + } + + // + // Right boundary conditions + // + + if(boundrtype == 0) + { + a1[n - 1] = 1; + a2[n - 1] = 1; + a3[n - 1] = 0; + b[n - 1] = 2 * (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2]); + } + + if(boundrtype == 1) + { + a1[n - 1] = 0; + a2[n - 1] = 1; + a3[n - 1] = 0; + b[n - 1] = boundr; + } + + if(boundrtype == 2) + { + a1[n - 1] = 1; + a2[n - 1] = 2; + a3[n - 1] = 0; + b[n - 1] = 3 * (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2]) + 0.5f * boundr * (x[n - 1] - x[n - 2]); + } + + // + // Solve + // + + d = solveTridiagonal(a1, a2, a3, b, n); + + // + // Now problem is reduced to the cubic Hermite spline + // + + return buildHermiteSpline(x, y, d, n); + } + + /************************************************************************* + ПоÑтроение таблицы коÑффициентов Ñплайна Эрмита + + Входные параметры: + X - абÑциÑÑÑ‹, маÑÑив Ñ Ð½ÑƒÐ¼ÐµÑ€Ð°Ñ†Ð¸ÐµÐ¹ Ñлементов [0..N-1] + Y - Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸, + маÑÑив Ñ Ð½ÑƒÐ¼ÐµÑ€Ð°Ñ†Ð¸ÐµÐ¹ Ñлементов [0..N-1] + D - Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð½Ð¾Ð¹, + маÑÑив Ñ Ð½ÑƒÐ¼ÐµÑ€Ð°Ñ†Ð¸ÐµÐ¹ Ñлементов [0..N-1] + N - чиÑло точек, N>=2 + + Выходные параметры: + C - таблица коÑффициентов Ñплайна Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² + подпрограмме SplineInterpolation + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey + *************************************************************************/ + public static float[] buildHermiteSpline(float[] x, float[] y, float[] d, int n) + { + if(n < 2) + { + throw new IllegalArgumentException(); + } + + int i = 0; + int tblsize = 0; + float delta = 0; + float delta2 = 0; + float delta3 = 0; + + x = cloneArray(x); + y = cloneArray(y); + d = cloneArray(d); + + // + // Sort points + // + + heapSortDPoints(x, y, d, n); + + // + // Fill C: + // C[0] - length(C) + // C[1] - type(C): + // 3 - general cubic spline + // C[2] - N + // C[3]...C[3+N-1] - x[i], i = 0...N-1 + // C[3+N]...C[3+N+(N-1)*4-1] - coefficients table + // + + tblsize = 3 + n + (n - 1) * 4; + + float[] c = new float[tblsize]; + + c[0] = tblsize; + c[1] = 3; + c[2] = n; + + for(i = 0; i < n; i++) + { + c[3 + i] = x[i]; + } + + for(i = 0; i < n - 1; i++) + { + delta = x[i + 1] - x[i]; + delta2 = delta * delta; + delta3 = delta * delta2; + + c[3 + n + 4 * i + 0] = y[i]; + c[3 + n + 4 * i + 1] = d[i]; + c[3 + n + 4 * i + 2] = (3 * (y[i + 1] - y[i]) - 2 * d[i] * delta - d[i + 1] * delta) / delta2; + c[3 + n + 4 * i + 3] = (2 * (y[i] - y[i + 1]) + d[i] * delta + d[i + 1] * delta) / delta3; + } + + return c; + } + + /************************************************************************* + ВычиÑление интерполирующего Ñплайна + + Входные параметры: + C - маÑÑив коÑффициентов, вычиÑленный подпрограммой Ð´Ð»Ñ + поÑÑ‚Ñ€Ð¾ÐµÐ½Ð¸Ñ Ñплайна. + X - точка, в которой вычиÑлÑетÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ðµ Ñплайна + + Результат: + значение Ñплайна в точке X + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey + *************************************************************************/ + public static float splineInterpolation(float[] c, float x) + { + if((int)c[1] != 3) + { + throw new IllegalArgumentException(); + } + + int n = 0; + int l = 0; + int r = 0; + int m = 0; + + n = (int)c[2]; + + // + // Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) + // + + l = 3; + r = 3 + n - 2 + 1; + + while(l != r - 1) + { + m = (l + r) / 2; + + if(c[m] >= x) + { + r = m; + } + else + { + l = m; + } + } + + // + // Interpolation + // + + x = x - c[l]; + m = 3 + n + 4 * (l - 3); + + return c[m] + x * (c[m + 1] + x * (c[m + 2] + x * c[m + 3])); + } + + /************************************************************************* + Internal subroutine. Heap sort. + *************************************************************************/ + protected static void heapSortPoints(float[] x, float[] y, int n) + { + int i = 0; + int j = 0; + int k = 0; + int t = 0; + + float tmp = 0; + + boolean isascending = true; + boolean isdescending = true; + + // + // Test for already sorted set + // + + for(i = 1; i < n; i++) + { + isascending &= x[i] > x[i - 1]; + isdescending &= x[i] < x[i - 1]; + } + + if(isascending) + { + return; + } + + if(isdescending) + { + for(i = 0; i < n; i++) + { + j = n - 1 - i; + + if(j <= i) + { + break; + } + + tmp = x[i]; + x[i] = x[j]; + x[j] = tmp; + + tmp = y[i]; + y[i] = y[j]; + y[j] = tmp; + } + + return; + } + + // + // Special case: N=1 + // + + if(n == 1) + { + return; + } + + // + // General case + // + + i = 2; + + do + { + t = i; + + while(t != 1) + { + k = t / 2; + + if(x[k - 1] >= x[t - 1]) + { + t = 1; + } + else + { + tmp = x[k - 1]; + x[k - 1] = x[t - 1]; + x[t - 1] = tmp; + + tmp = y[k - 1]; + y[k - 1] = y[t - 1]; + y[t - 1] = tmp; + + t = k; + } + } + } + while(i++ <= n); + + i = n - 1; + + do + { + tmp = x[i]; + x[i] = x[0]; + x[0] = tmp; + + tmp = y[i]; + y[i] = y[0]; + y[0] = tmp; + + t = 1; + + while(t != 0) + { + k = 2 * t; + + if(k > i) + { + t = 0; + } + else + { + if(k < i) + { + if(x[k] > x[k - 1]) + { + k = k + 1; + } + } + + if(x[t - 1] >= x[k - 1]) + { + t = 0; + } + else + { + tmp = x[k - 1]; + x[k - 1] = x[t - 1]; + x[t - 1] = tmp; + + tmp = y[k - 1]; + y[k - 1] = y[t - 1]; + y[t - 1] = tmp; + + t = k; + } + } + } + } + while(i-- >= 1); + } + + + /************************************************************************* + Internal subroutine. Heap sort. + *************************************************************************/ + protected static void heapSortDPoints(float[] x, float[] y, float[] d, int n) + { + int i = 0; + int j = 0; + int k = 0; + int t = 0; + + float tmp = 0; + + boolean isascending = true; + boolean isdescending = true; + + // + // Test for already sorted set + // + + for(i = 1; i < n; i++) + { + isascending &= x[i] > x[i - 1]; + isdescending &= x[i] < x[i - 1]; + } + + if(isascending) + { + return; + } + + if(isdescending) + { + for(i = 0; i < n; i++) + { + j = n - 1 - i; + + if(j <= i) + { + break; + } + + tmp = x[i]; + x[i] = x[j]; + x[j] = tmp; + + tmp = y[i]; + y[i] = y[j]; + y[j] = tmp; + + tmp = d[i]; + d[i] = d[j]; + d[j] = tmp; + } + + return; + } + + // + // Special case: N=1 + // + + if(n == 1) + { + return; + } + + // + // General case + // + + i = 2; + + do + { + t = i; + + while(t != 1) + { + k = t / 2; + + if(x[k - 1] >= x[t - 1]) + { + t = 1; + } + else + { + tmp = x[k - 1]; + x[k - 1] = x[t - 1]; + x[t - 1] = tmp; + + tmp = y[k - 1]; + y[k - 1] = y[t - 1]; + y[t - 1] = tmp; + + tmp = d[k - 1]; + d[k - 1] = d[t - 1]; + d[t - 1] = tmp; + + t = k; + } + } + } + while(i++ <= n); + + i = n - 1; + + do + { + tmp = x[i]; + x[i] = x[0]; + x[0] = tmp; + + tmp = y[i]; + y[i] = y[0]; + y[0] = tmp; + + tmp = d[i]; + d[i] = d[0]; + d[0] = tmp; + + t = 1; + + while(t != 0) + { + k = 2 * t; + + if(k > i) + { + t = 0; + } + else + { + if(k < i) + { + if(x[k] > x[k - 1]) + { + k = k + 1; + } + } + + if(x[t - 1] >= x[k - 1]) + { + t = 0; + } + else + { + tmp = x[k - 1]; + x[k - 1] = x[t - 1]; + x[t - 1] = tmp; + + tmp = y[k - 1]; + y[k - 1] = y[t - 1]; + y[t - 1] = tmp; + + tmp = d[k - 1]; + d[k - 1] = d[t - 1]; + d[t - 1] = tmp; + + t = k; + } + } + } + } + while(i-- >= 1); + } + + /************************************************************************* + Internal subroutine. Tridiagonal solver. + *************************************************************************/ + protected static float[] solveTridiagonal(float[] a, float[] b, float[] c, float[] d, int n) + { + int k = 0; + float t = 0; + + a = cloneArray(a); + b = cloneArray(b); + c = cloneArray(c); + d = cloneArray(d); + + float[] x = new float[n]; + + a[0] = 0; + c[n - 1] = 0; + + for(k = 1; k <= n - 1; k++) + { + t = a[k] / b[k - 1]; + + b[k] = b[k] - t * c[k - 1]; + d[k] = d[k] - t * d[k - 1]; + } + + x[n - 1] = d[n - 1] / b[n - 1]; + + for(k = n - 2; k >= 0; k--) + { + x[k] = (d[k] - c[k] * x[k + 1]) / b[k]; + } + + return x; + } + + /************************************************************************* + Internal subroutine. Three-point differentiation + *************************************************************************/ + protected static float diffThreePoint(float t, float x0, float f0, float x1, float f1, float x2, float f2) + { + float a = 0; + float b = 0; + + t = t - x0; + x1 = x1 - x0; + x2 = x2 - x0; + a = (f2 - f0 - x2 / x1 * (f1 - f0)) / (x2 * x2 - x1 * x2); + b = (f1 - f0 - a * x1 * x1) / x1; + + return 2 * a * t + b; + } + + /************************************************************************* + Internal subroutine. Array cloning + *************************************************************************/ + protected static float[] cloneArray(float[] array) + { + float[] clone = new float[array.length]; + System.arraycopy(array, 0, clone, 0, array.length); + + return clone; + } +} diff --git a/src/com/one/Directory.java b/src/com/one/Directory.java new file mode 100644 index 0000000..57f4674 --- /dev/null +++ b/src/com/one/Directory.java @@ -0,0 +1,190 @@ +package com.one; + +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * Библиотека Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ‡ÐµÑких ÑпиÑков файлов. + * + * Папка в ÑпиÑке предÑтавлÑет Ñобой Hashtable, + * в которой ключами ÑвлÑÑŽÑ‚ÑÑ Ð¸Ð¼ÐµÐ½Ð° файлов в Ñтой папке (без путей), + * а Ñлементами могут ÑвлÑÑ‚ÑŒÑÑ: + * Ð´Ð»Ñ Ð´Ð¾Ñ‡ÐµÑ€Ð½Ð¸Ñ… папок - Ð´Ñ€ÑƒÐ³Ð°Ñ Hashtable, + * Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… файлов - new Object(). + */ +public class Directory +{ + public static void addFile(Hashtable directory, String file) + { + int index = file.indexOf('/') + 1; + + if(index > 0) + { + String filepath = file.substring(0, index); + String filename = file.substring(index); + + Hashtable subdirectory = (Hashtable)directory.get(filepath); + + if(subdirectory == null) + { + subdirectory = new Hashtable(); + directory.put(filepath, subdirectory); + } + + if(filename.length() > 0) + { + addFile(subdirectory, filename); + } + } + else + { + directory.put(file, new Object()); + } + } + + public static void deleteFile(Hashtable directory, String file) + { + int index = file.indexOf('/') + 1; + + if(index > 0) + { + String filepath = file.substring(0, index); + String filename = file.substring(index); + + if(filename.length() > 0) + { + Hashtable subdirectory = (Hashtable)directory.get(filepath); + + if(subdirectory == null) + { + return; + } + + deleteFile(subdirectory, filename); + } + else + { + directory.remove(filepath); + } + } + else + { + directory.remove(file); + } + } + + public static void renameFile(Hashtable files, String path, String oldname, String newname) + { + if(path == null) + { + char[] ocs = oldname.toCharArray(); + char[] ncs = newname.toCharArray(); + + int len = Math.min(ocs.length, ncs.length); + + for(int i = 0; i < len; i++) + { + if(ncs[i] != ocs[i]) + { + path = oldname.substring(0, i); + + oldname = oldname.substring(i); + newname = newname.substring(i); + + break; + } + } + + if(path == null) + { + return; + } + } + + Hashtable directory = files; + int index; + + while(path.length() > 0) + { + index = path.indexOf('/') + 1; + directory = (Hashtable)directory.get(path.substring(0, index)); + + if(directory == null) + { + return; + } + + path = path.substring(index); + } + + directory.put(newname, directory.remove(oldname)); + } + + public static Enumeration listFiles(Hashtable files, String path) + { + if(path == null || path.length() == 0) + { + return files.keys(); + } + else + { + if(!path.endsWith("/")) + { + path = path + "/"; + } + + Hashtable directory = files; + int index; + + while(true) + { + index = path.indexOf('/') + 1; + directory = (Hashtable)directory.get(path.substring(0, index)); + + if(directory == null) + { + return null; + } + + path = path.substring(index); + + if(path.length() == 0) + { + return directory.keys(); + } + } + } + } + + public static boolean fileExists(Hashtable files, String file) + { + Hashtable directory = files; + int index; + + while(true) + { + index = file.indexOf('/') + 1; + + if(index > 0) + { + directory = (Hashtable)directory.get(file.substring(0, index)); + + if(directory == null) + { + return false; + } + + file = file.substring(index); + + if(file.length() == 0) + { + return true; + } + } + else + { + return directory.containsKey(file); + } + } + } +} diff --git a/src/com/one/DisplayManager.java b/src/com/one/DisplayManager.java new file mode 100644 index 0000000..f604c5d --- /dev/null +++ b/src/com/one/DisplayManager.java @@ -0,0 +1,156 @@ +package com.one; + +import javax.microedition.lcdui.*; + +public class DisplayManager implements CommandListener +{ + protected Display dsp; + protected Renderer rn; + protected boolean renderMode; + protected Object next; + + public DisplayManager(Display d) + { + dsp = d; + rn = new Renderer(); // new AsyncRenderer(); + renderMode = false; + } + + public void commandAction(Command c, Displayable d) + { + if(next != null) + { + setCurrent(next); + next = null; + } + } + + public Renderer getRenderer() + { + return rn; + } + + public void setCurrent(Object obj) + { + if(obj instanceof ErrScreen.ObjectWrap) + { + obj = ((ErrScreen.ObjectWrap)obj).object; + } + else if(getCurrent() instanceof ErrScreen) + { + ErrScreen.getInstance().setNextDisplayable(obj); + return; + } + + if(obj instanceof PaintableObject) + { + rn.setCurrent((PaintableObject)obj); + + if(!renderMode) + { + dsp.setCurrent(rn); + renderMode = true; + } + } + else + { + dsp.setCurrent((Displayable)obj); + renderMode = false; + } + } + + public void setCurrent(AutoAdvanceScreen aas, Object obj) + { + setCurrent(aas); + + if(aas.finiteTimeout()) + { + next = obj; + + aas.setCommandListener(this); + (new Thread(aas, "DisplayManager/AutoAdvance")).start(); + } + } + + public void setCurrent(Alert al, Object obj) + { + if(obj instanceof PaintableObject) + { + rn.setCurrent((PaintableObject)obj); + dsp.setCurrent(al, rn); + } + else + { + dsp.setCurrent(al, (Displayable)obj); + } + + renderMode = false; + } + + public Object getCurrent() + { + if(renderMode) + { + return rn.getCurrent(); + } + else + { + return dsp.getCurrent(); + } + } + + public void callSerially(Runnable r) + { + dsp.callSerially(r); + } + + public boolean flashBacklight(int duration) + { + return dsp.flashBacklight(duration); + } + + public int getBestImageHeight(int imageType) + { + return dsp.getBestImageHeight(imageType); + } + + public int getBestImageWidth(int imageType) + { + return dsp.getBestImageWidth(imageType); + } + + public int getBorderStyle(boolean highlighted) + { + return dsp.getBorderStyle(highlighted); + } + + public int getColor(int colorSpecifier) + { + return dsp.getColor(colorSpecifier); + } + + public boolean isColor() + { + return dsp.isColor(); + } + + public int numAlphaLevels() + { + return dsp.numAlphaLevels(); + } + + public int numColors() + { + return dsp.numColors(); + } + + public void setCurrentItem(Item item) + { + dsp.setCurrentItem(item); + } + + public boolean vibrate(int duration) + { + return dsp.vibrate(duration); + } +} diff --git a/src/com/one/ErrScreen.java b/src/com/one/ErrScreen.java new file mode 100644 index 0000000..264bd04 --- /dev/null +++ b/src/com/one/ErrScreen.java @@ -0,0 +1,232 @@ +package com.one; + +import com.vmx.*; +import javax.microedition.lcdui.*; +import javax.microedition.midlet.MIDletStateChangeException; + +public class ErrScreen extends Canvas implements CommandListener +{ + public static class ObjectWrap + { + public Object object; + } + + protected static RootLoader loader; + protected static DisplayManager manager; + protected static ErrScreen instance; + + protected ObjectWrap parent; + + protected Font font; + protected FontWidthCache fwc; + protected int fnth; + + protected int width, height; + protected int ty; + + protected String message; + protected String[] msglines; + + public static void setRootLoader(RootLoader rl) + { + loader = rl; + } + + public static void setDisplayManager(DisplayManager dsp) + { + manager = dsp; + } + + static + { + instance = new ErrScreen(); + } + + public static ErrScreen getInstance() + { + return instance; + } + + public static void showErrMsg(int errcode, Throwable t) + { + instance.append("ERROR", errcode, t); + } + + public static void showStopMsg(int errcode, Throwable t) + { + instance.append("STOP", errcode, t); + } + + protected ErrScreen() + { + setFullScreenMode(true); + + width = getWidth(); + height = getHeight(); + ty = 0; + + font = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_SMALL); + fwc = FontWidthCache.getCache(font); + fnth = font.getHeight(); + + setMessage(""); + + parent = new ObjectWrap(); + + addCommand(new Command("Return", Command.BACK, 1)); + addCommand(new Command("Exit", Command.EXIT, 2)); + + setCommandListener(this); + } + + public void append(String msgtype, int errcode, Throwable t) + { + StringBuffer msg = new StringBuffer(); + + //msg.append(Integer.toHexString(errcode).toUpperCase()); + msg.append(Integer.toString(errcode)); + + while(msg.length() < 8) + { + msg.insert(0, '0'); + } + + //msg.insert(0, ": 0x"); + msg.insert(0, ": "); + + msg.insert(0, msgtype); + msg.insert(0, "*** "); + msg.append(" ("); + msg.append(t); + msg.append(")"); + + System.out.println(msg.toString()); + + if(t != null) + { + t.printStackTrace(); + } + + setMessage(message + msg.toString() + "\n\n"); + + if(fnth * msglines.length > height) + { + ty = height - fnth * msglines.length; + } + + if(manager != null) + { + ProgressBar.hide(); + + if(manager.getCurrent() != this) + { + parent.object = manager.getCurrent(); + } + + manager.setCurrent(this); + } + } + + public void setMessage(String text) + { + message = text; + msglines = fwc.splitString(text, width); + + repaint(); + } + + public void setNextDisplayable(Object obj) + { + if(obj != instance) + { + parent.object = obj; + } + } + + public void keyRepeated(int keyCode) + { + keyPressed(keyCode); + } + + public void keyPressed(int keyCode) + { + if(keyCode == KEY_NUM0) + { + ty = 0; + } + else + { + keyCode = getGameAction(keyCode); + + if(keyCode == UP) + { + ty += fnth; + } + else if(keyCode == DOWN) + { + ty -= fnth; + } + else if(keyCode == LEFT) + { + ty += height; + } + else if(keyCode == RIGHT) + { + ty -= height; + } + else + { + return; + } + } + + repaint(); + } + + public void paint(Graphics g) + { + g.setColor(0x000080); + g.fillRect(0, 0, width, height); + + g.setColor(0xFFFFFF); + g.setFont(font); + + for(int i = 0; i < msglines.length; i++) + { + g.drawString(msglines[i], 0, ty + i * fnth, Graphics.LEFT | Graphics.TOP); + } + } + + public void commandAction(Command c, Displayable dp) + { + if(c.getCommandType() == Command.BACK) + { + if(manager != null && parent.object != null) + { + setMessage(""); + ty = 0; + + manager.setCurrent(parent); + } + else if(loader != null) + { + destroyApp(); + } + } + else if(loader != null) + { + destroyApp(); + } + } + + protected static void destroyApp() + { + try + { + loader.destroyApp(false); + } + catch(MIDletStateChangeException _) + { + } + } +} diff --git a/src/com/one/ExtRandom.java b/src/com/one/ExtRandom.java new file mode 100644 index 0000000..c58b8e6 --- /dev/null +++ b/src/com/one/ExtRandom.java @@ -0,0 +1,73 @@ +package com.one; + +import java.util.Random; + +/** + * Генератор пÑевдоÑлучайных чиÑел. + * ИÑпользуетÑÑ Ð°Ð»Ð³Ð¾Ñ€Ð¸Ñ‚Ð¼ Джорджа МарÑаглии "Xorshift 128". + */ +public class ExtRandom extends Random +{ + protected static int[] bitmask = new int[33]; + + static + { + bitmask[32] = 0xFFFFFFFF; + + for(int i = 31; i >= 0; i--) + { + bitmask[i] = bitmask[i + 1] >>> 1; + } + } + + protected int t, x, y, z, w; + protected int mx, my, mz, mw; + + public ExtRandom() + { + super(); + } + + public ExtRandom(long seed) + { + super(seed); + } + + protected int next(int bits) + { + t = (x ^ (x << 11)); + x = y; + y = z; + z = w; + w = (w ^ (w >>> 19)) ^ (t ^ (t >>> 8)); + + return w & bitmask[bits]; + } + + public void setSeed(long seed) + { + x = (int)seed; + + y = 362436069; + z = 521288629; + w = 88675123; + + mark(); + } + + public void mark() + { + mx = x; + my = y; + mz = z; + mw = w; + } + + public void reset() + { + x = mx; + y = my; + z = mz; + w = mw; + } +} diff --git a/src/com/one/ExtThread.java b/src/com/one/ExtThread.java new file mode 100644 index 0000000..65e3619 --- /dev/null +++ b/src/com/one/ExtThread.java @@ -0,0 +1,34 @@ +package com.one; + +public abstract class ExtThread implements Runnable +{ + protected boolean running; + protected Thread t; + + public void start() + { + running = true; + t = new Thread(this, "ExtThread/Task"); + t.start(); + } + + public void stop() + { + running = false; + } + + public boolean isAlive() + { + return running; + } + + public void join() throws InterruptedException + { + if(running && t != null) + { + t.join(); + } + } + + public abstract void run(); +} diff --git a/src/com/one/FileInputStream.java b/src/com/one/FileInputStream.java new file mode 100644 index 0000000..28cd55f --- /dev/null +++ b/src/com/one/FileInputStream.java @@ -0,0 +1,236 @@ +package com.one; + +import java.io.*; +import com.one.file.*; + +/** + * Файловый входной поток. + * Призван работать там, где требуетÑÑ Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶ÐºÐ° mark / reset, но ее почему - то нет. + */ + +/* + * ЗÐМЕЧÐÐИЕ + * + * Ð’ некоторых меÑтах напиÑано что-то вроде + * + * is.skip(n); + * currpos += n; + * + * хотÑ, возможно, было бы правильнее напиÑать + * + * n = is.skip(n); + * currpos += n; + * + * Однако выÑÑнилоÑÑŒ, что skip() не вÑегда возвращает + * именно количеÑтво пропущенных байт. + * Видимо, поведение Ñтого метода, а возможно, и других, + * завиÑит от платформы (например, на телефонах SonyEricsson + * Ñтот метод возвращает текущую позицию в потоке). + * Ð”Ð»Ñ Ð¸ÑÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð´Ð¾Ð±Ð½Ñ‹Ñ… ошибок в данном клаÑÑе + * значениÑ, возвращаемые Ñтими методами, не иÑпользуютÑÑ. + * ВмеÑто Ñтого оÑущеÑтвлÑетÑÑ ÑÐ²Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° + * количеÑтва доÑтупных Ð´Ð»Ñ ÑÑ‡Ð¸Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð±Ð°Ð¹Ñ‚. + */ +public class FileInputStream extends RandomAccessInputStream +{ + protected FileConnection fc; + protected InputStream is; + protected int currpos; // Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ð¿ÐµÑ€Ð²Ð¾Ð³Ð¾ неÑчитанного байта + protected int markedpos; // Ð¼Ð°Ñ€ÐºÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ + protected boolean marksupp; // поддержка mark / reset базовым потоком + + public FileInputStream(FileConnection fc) throws IOException + { + setFileConnection(fc); + + currpos = 0; + markedpos = 0; + } + + public void setFileConnection(FileConnection fc) throws IOException + { + close(); + + this.fc = fc; + + is = fc.openInputStream(); + + if(marksupp = is.markSupported()) + { + is.mark(available() + 0x100); + } + } + + public FileConnection getBaseConnection() + { + return fc; + } + + public void checkClosed() throws IOException + { + if(fc == null) + { + throw new IOException("Stream is closed"); + } + } + + public int available() throws IOException + { + checkClosed(); + return (int)(fc.fileSize() - currpos); // is.available(); + } + + public void close() throws IOException + { + if(is != null) + { + is.close(); + is = null; + } + + fc = null; + } + + public void mark(int readLimit) + { + markedpos = currpos; + } + + public int read() throws IOException + { + checkClosed(); + + if(available() <= 0) // конец потока + { + return -1; + } + + currpos++; + + return is.read(); + } + + public int read(byte[] b) throws IOException + { + return read(b, 0, b.length); + } + + public int read(byte[] b, int off, int len) throws IOException + { + checkClosed(); + + int available = available(); + + if(available <= 0) + { + return -1; + } + + if(len > available) + { + len = available; + } + + is.read(b, off, len); + + currpos += len; + + return len; + } + + public void reset() throws IOException + { + checkClosed(); + setPosition(markedpos); + } + + public long skip(long n) throws IOException + { + checkClosed(); + + if(n > available()) + { + n = available(); + } + + is.skip(n); + + currpos += n; + + return n; + } + + public void setPosition(int pos) throws IOException + { + checkClosed(); + + if(pos == currpos) + { + return; + } + + if(pos < 0) + { + pos = 0; + } + else if(pos > getCapacity()) + { + pos = getCapacity(); + } + + if(pos < currpos) + { + if(marksupp) + { + is.reset(); + } + else + { + is.close(); + is = fc.openInputStream(); + } + + is.skip(pos); + } + else + { + is.skip(pos - currpos); + } + + currpos = pos; + } + + public int getPosition() + { + return currpos; + } + + public int getCapacity() throws IOException + { + checkClosed(); + return (int)fc.fileSize(); // is.available() + currpos; + } + + public void update() throws IOException + { + checkClosed(); + + int pos = currpos; + currpos = 0; + + is.close(); + is = fc.openInputStream(); + + if(marksupp = is.markSupported()) + { + is.mark(available() + 0x100); + } + + setPosition(pos); + } + +// private static void out(String s) +// { +// System.out.println("[FileInputStream] " + s); +// } +} diff --git a/src/com/one/FileSource.java b/src/com/one/FileSource.java new file mode 100644 index 0000000..2e34b4d --- /dev/null +++ b/src/com/one/FileSource.java @@ -0,0 +1,11 @@ +package com.one; + +import java.io.IOException; + +public interface FileSource +{ + public static final int TYPE_NORMAL_FILE = 0; + public static final int TYPE_CONTAINER = 1; + + public void createFile(String filename) throws IOException; +} \ No newline at end of file diff --git a/src/com/one/ImageProcessor.java b/src/com/one/ImageProcessor.java new file mode 100644 index 0000000..5f2005b --- /dev/null +++ b/src/com/one/ImageProcessor.java @@ -0,0 +1,333 @@ +package com.one; + +import javax.microedition.lcdui.*; +import com.one.vector.AuxMath; +import com.vmx.ProgressCallback; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Hashtable; +import javax.microedition.lcdui.game.Sprite; + +/** + * КлаÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ изображений + */ +public class ImageProcessor +{ + protected static Hashtable srcimages = new Hashtable(); + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¼Ð°ÑÑˆÑ‚Ð°Ð±Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ð¹ + */ + public static Image scaleImage(Image source, int destw, int desth, boolean interpolate, boolean alpha) + { + if(source == null) + { + return null; + } + + try + { + int srcw = source.getWidth(); + int srch = source.getHeight(); + + if(destw < 0) + { + if(desth < 0) + { + return source; + } + else + { + destw = srcw * desth / srch; + } + } + else if(desth < 0) + { + desth = srch * destw / srcw; + } + + int[] src = null; + int[] dst = null; + int fragcount = 1; + int srcfw, srcfh; + int dstfw, dstfh; + + do + { + srcfw = srcw / fragcount; + srcfh = srch / fragcount; + dstfw = destw / fragcount; + dstfh = desth / fragcount; + + try + { + src = new int[srcfw * srcfh]; + dst = new int[dstfw * dstfh]; + } + catch(OutOfMemoryError oome) + { + src = null; + dst = null; + fragcount++; + } + } + while(src == null || dst == null); + + if(fragcount == 1) + { + source.getRGB(src, 0, srcw, 0, 0, srcw, srch); + + if(interpolate) // && (destw > srcw || desth > srch)) + { + AuxMath.bicubicScaleRGB(src, dst, srcw, srch, destw, desth, alpha); + } + else + { + AuxMath.scaleRGB(src, dst, srcw, srch, destw, desth, alpha); + } + + return Image.createRGBImage(dst, destw, desth, alpha); + } + else + { + Image scaled = Image.createImage(destw, desth); + Graphics g = scaled.getGraphics(); + + int fx, fy; + + for(fx = 0; fx < fragcount; fx++) + { + for(fy = 0; fy < fragcount; fy++) + { + source.getRGB(src, 0, srcfw, fx * srcfw, fy * srcfh, srcfw, srcfh); + + if(interpolate && (dstfw > srcfw || dstfh > srcfh)) + { + AuxMath.bicubicScaleRGB(src, dst, srcfw, srcfh, dstfw, dstfh, false); + } + else + { + AuxMath.scaleRGB(src, dst, srcfw, srcfh, dstfw, dstfh, false); + } + + g.drawRGB(dst, 0, dstfw, fx * dstfw, fy * dstfh, dstfw, dstfh, false); + } + } + + return scaled; + } + } + catch(Throwable t) + { + return source; + } + } + + /** + * ЯркоÑÑ‚ÑŒ иÑходного Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ð¼ÐµÐ½ÑетÑÑ + * как альфа-канал конечного изображениÑ. + * + * Пример: + * первую картинку заливаем градиентом, + * вторую заливаем черным и пишем белый текÑÑ‚. + * Потом юзаем Ñту функцию, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ + * картинку Ñ Ð³Ñ€Ð°Ð´Ð¸ÐµÐ½Ñ‚Ð¾Ð¼ как конечную и + * картинку Ñ Ñ‚ÐµÐºÑтом как иÑходную, и Ð²ÑƒÐ°Ð»Ñ - + * получаем картинку Ñ Ð³Ñ€Ð°Ð´Ð¸ÐµÐ½Ñ‚Ð½Ñ‹Ð¼ текÑтом. + * + * @param source иÑходное изображение + * @param dest конечное изображение + */ + public static void lightAlphaMask(int[] source, int[] dest) + { + for(int i = 0; i < source.length; i++) + { + dest[i] = (dest[i] & 0xFFFFFF) | (((((source[i] >> 16) & 0xFF) + ((source[i] >> 8) & 0xFF) + (source[i] & 0xFF)) / 3) << 24); + } + } + + /** + * ДоÑтать картинку, заданную базовой папкой и + * Ñпецификатором вида "file.ext @ x, y, w, h". + * Однако, Ñпецификатор, ÑоÑтоÑщий только из имени картинки, тоже работает. + * + * ИÑходные изображениÑ, чтобы каждый раз не Ñоздавать заново, + * кешируютÑÑ Ð² Hashtable и доÑтаютÑÑ Ð¿Ð¾Ñ‚Ð¾Ð¼ оттуда. + * ПоÑтому поÑле загрузки вÑех необходимых картинок рекомендуетÑÑ + * Ð´Ð»Ñ Ð¾ÑÐ²Ð¾Ð±Ð¾Ð¶Ð´ÐµÐ½Ð¸Ñ Ð¿Ð°Ð¼Ñти вызвать releaseCachedImages(). + * + * @param base Ð±Ð°Ð·Ð¾Ð²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°, в которой иÑкать картинки + * @param specifier Ñпецификатор картинки (Ñм. выше) + * @return получившаÑÑÑ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + * @throws IOException еÑли не удалоÑÑŒ доÑтать иÑходную картинку + */ + public static Image getImage(String base, String specifier) throws IOException + { + int index = specifier.indexOf('@'); + + if(index >= 0) + { + String filename = base + specifier.substring(0, index).trim(); + Image source = (Image)srcimages.get(filename); + + if(source == null) + { + source = Image.createImage(filename); + srcimages.put(filename, source); + } + + String[] position = TextProcessor.vectorToStringArray(StringPattern.tokenizeString(specifier.substring(index + 1), ',')); + + if(position.length >= 5) + { + return Image.createImage(source, Integer.parseInt(position[0].trim()), Integer.parseInt(position[1].trim()), + Integer.parseInt(position[2].trim()), Integer.parseInt(position[3].trim()), + Integer.parseInt(position[4].trim())); + } + else + { + return Image.createImage(source, Integer.parseInt(position[0].trim()), Integer.parseInt(position[1].trim()), + Integer.parseInt(position[2].trim()), Integer.parseInt(position[3].trim()), + Sprite.TRANS_NONE); + } + } + else + { + String filename = base + specifier.trim(); + Image source = (Image)srcimages.get(filename); + + if(source == null) + { + source = Image.createImage(filename); + srcimages.put(filename, source); + } + + return source; + } + } + + /** + * Добавить картинку в Hashtable Ð´Ð»Ñ getImage(). + * + * @param name Ð¸Ð¼Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ¸, например "/img/icons.png" + * @param image ÑобÑтвенно картинка + */ + public static void addImageToCache(String name, Image image) + { + srcimages.put(name, image); + } + + /** + * ОчиÑтить Hashtable Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ°Ð¼Ð¸ Ð´Ð»Ñ getImage(). + */ + public static void releaseCachedImages() + { + srcimages.clear(); + } + + /** + * ЗапиÑать Image в DataOutputStream. + * + * ÐеÑÐ¶Ð°Ñ‚Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° хранитÑÑ Ð² потоке в Ñледующем виде: + * int width, int height, int[width * height] pixels + * + * Ð¡Ð¶Ð°Ñ‚Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° хранитÑÑ Ð² потоке в Ñледующем виде: + * int length, byte[length] data + * + * @param dos поток, куда пиÑать картинку + * @param image запиÑÑ‹Ð²Ð°ÐµÐ¼Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + * @throws IOException + */ + public static void writeImage(DataOutputStream dos, Image image, boolean encode, ProgressCallback callback) throws IOException + { + if(image != null) + { + dos.writeBoolean(encode); + + if(encode) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(baos); + + PNGFile.writePNG(image, out, callback); + + byte[] data = baos.toByteArray(); + out.close(); + + dos.writeInt(data.length); + dos.write(data); + } + else + { + int[] rgb = new int[image.getWidth() * image.getHeight()]; + image.getRGB(rgb, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight()); + + dos.writeInt(image.getWidth()); + dos.writeInt(image.getHeight()); + + for(int i = 0; i < rgb.length; i++) + { + dos.writeInt(rgb[i]); + } + } + } + else + { + dos.writeBoolean(false); + + dos.writeInt(-1); + dos.writeInt(-1); + } + } + + /** + * Считать Image из DataInputStream. + * + * ÐеÑÐ¶Ð°Ñ‚Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° хранитÑÑ Ð² потоке в Ñледующем виде: + * int width, int height, int[width * height] pixels + * + * Ð¡Ð¶Ð°Ñ‚Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° хранитÑÑ Ð² потоке в Ñледующем виде: + * int length, byte[length] data + * + * @param dis поток, из которого читать картинку + * @return ÑÑ‡Ð¸Ñ‚Ð°Ð½Ð½Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + * @throws IOException + */ + public static Image readImage(DataInputStream dis) throws IOException + { + boolean encoded = dis.readBoolean(); + + if(encoded) + { + int length = dis.readInt(); + byte[] data = new byte[length]; + + dis.readFully(data); + + return Image.createImage(data, 0, length); + } + else + { + int width = dis.readInt(); + int height = dis.readInt(); + + if(width >= 0 && height >= 0) + { + int[] rgb = new int[width * height]; + + for(int i = 0; i < rgb.length; i++) + { + rgb[i] = dis.readInt(); + } + + return Image.createRGBImage(rgb, width, height, true); + } + else + { + return null; + } + } + } +} diff --git a/src/com/one/IniFile.java b/src/com/one/IniFile.java new file mode 100644 index 0000000..1ebf3e2 --- /dev/null +++ b/src/com/one/IniFile.java @@ -0,0 +1,460 @@ +package com.one; + +import java.util.*; +import java.io.*; +import com.vmx.*; + +/** + * ПарÑер INI файлов. + * Секции подерживаютÑÑ. + */ +public class IniFile +{ + /* + * ЗдеÑÑŒ ÑобÑтвенно данные + */ + protected Hashtable sections; + protected boolean ignorecase; + + /* + * Имена Ñекций и ключей в ÑекциÑÑ… дополнительно помещаютÑÑ ÐµÑ‰Ðµ и в вектора, + * поÑкольку из Hashtable.keys() они возвращаютÑÑ Ð²Ð½Ðµ иÑходного порÑдка. + */ + protected Vector sectlist; + protected Hashtable keylists; + + /** + * Открытие реÑурÑа как INI файла + */ + public IniFile(String resname, boolean ignorecase) throws IOException + { + read(InputStreamDecoder.getResourceDecoder(resname), ignorecase); + } + + /** + * Открытие ÑущеÑтвующего INI файла + */ + public IniFile(InputStreamDecoder isd, boolean ignorecase) throws IOException + { + read(isd, ignorecase); + } + + /** + * Создание нового INI файла + */ + public IniFile(boolean ignorecase) + { + sections = new Hashtable(); + this.ignorecase = ignorecase; + + sectlist = new Vector(); + keylists = new Hashtable(); + } + + /** + * Чтение INI файла + */ + public void read(InputStreamDecoder isd, boolean ignorecase) throws IOException + { + sections = new Hashtable(); + this.ignorecase = ignorecase; + + sectlist = new Vector(); + keylists = new Hashtable(); + + String cursection = ""; + Hashtable records = null; + Vector keylist = null; + + String s, key; + int index; + + while((s = readIniLine(isd)) != null) + { + index = s.indexOf('='); + + if(index >= 0) + { + if(records == null) + { + records = (Hashtable)sections.get(cursection); + + if(records == null) + { + records = new Hashtable(); + sections.put(cursection, records); + + keylist = new Vector(); + keylists.put(cursection, keylist); + + sectlist.addElement(cursection); + } + else + { + keylist = (Vector)keylists.get(cursection); + } + } + + key = ignorecase ? s.substring(0, index).trim().toLowerCase() : s.substring(0, index).trim(); + + records.put(key, s.substring(index + 1).trim()); + keylist.addElement(key); + } + else + { + index = s.indexOf('['); + + if(index >= 0) + { + s = s.substring(index + 1); + index = s.indexOf(']'); + + if(index >= 0) + { + cursection = ignorecase ? s.substring(0, index).toLowerCase() : s.substring(0, index); + records = null; + } + else + { + if(records == null) + { + records = (Hashtable)sections.get(cursection); + + if(records == null) + { + records = new Hashtable(); + sections.put(cursection, records); + + keylist = new Vector(); + keylists.put(cursection, keylist); + + sectlist.addElement(cursection); + } + else + { + keylist = (Vector)keylists.get(cursection); + } + } + + records.put(s, s); + keylist.addElement(s); + } + } + else + { + if(records == null) + { + records = (Hashtable)sections.get(cursection); + + if(records == null) + { + records = new Hashtable(); + sections.put(cursection, records); + + keylist = new Vector(); + keylists.put(cursection, keylist); + + sectlist.addElement(cursection); + } + else + { + keylist = (Vector)keylists.get(cursection); + } + } + + records.put(s, s); + keylist.addElement(s); + } + } + } + } + + /** + * ЗапиÑÑŒ INI файла + */ + public void write(OutputStreamEncoder ose) throws IOException + { + String cursection = ""; + Hashtable records = (Hashtable)sections.get(cursection); + Vector keylist; + + Enumeration keys; + String key; + String value; + + ose.writeBOM(); + + if(records != null) + { + keylist = (Vector)keylists.get(cursection); + keys = keylist.elements(); // records.keys(); + + if(keys.hasMoreElements()) + { + while(keys.hasMoreElements()) + { + key = (String)keys.nextElement(); + value = (String)records.get(key); + + if(value.equals(key)) + { + ose.writeString(value + "\r\n"); + } + else + { + ose.writeString(key + "\t=\t" + value + "\r\n"); + } + } + + ose.writeString("\r\n"); + } + } + + Enumeration secnames = sectlist.elements(); // sections.keys(); + + while(secnames.hasMoreElements()) + { + cursection = (String)secnames.nextElement(); + + if(cursection.length() == 0) + { + continue; + } + + records = (Hashtable)sections.get(cursection); + keylist = (Vector)keylists.get(cursection); + keys = keylist.elements(); // records.keys(); + + if(keys.hasMoreElements()) + { + ose.writeString("[" + cursection + "]\r\n\r\n"); + + while(keys.hasMoreElements()) + { + key = (String)keys.nextElement(); + value = (String)records.get(key); + + if(value.equals(key)) + { + ose.writeString(value + "\r\n"); + } + else + { + ose.writeString(key + "\t=\t" + value + "\r\n"); + } + } + + ose.writeString("\r\n"); + } + } + } + + public void addRecord(String section, String key, String value) + { + System.out.println(section + ", " + key + " = '" + value + "'"); + + if(value == null) + { + value = ""; + } + + if(key == null || key.length() == 0) + { + key = value; + } + + if(section == null) + { + section = ""; + } + + if(ignorecase) + { + section = section.toLowerCase(); + key = key.toLowerCase(); + } + + Hashtable records = (Hashtable)sections.get(section); + Vector keylist; + + if(records == null) + { + records = new Hashtable(); + sections.put(section, records); + + keylist = new Vector(); + keylists.put(section, keylist); + + sectlist.addElement(section); + } + else + { + keylist = (Vector)keylists.get(section); + } + + records.put(key, value); + keylist.addElement(key); + } + + public String getRecord(String section, String key) + { + if(key == null || key.length() == 0) + { + return null; + } + + if(section == null) + { + section = ""; + } + + if(ignorecase) + { + section = section.toLowerCase(); + key = key.toLowerCase(); + } + + Hashtable records = (Hashtable)sections.get(section); + + if(records == null) + { + return null; + } + + return (String)records.get(key); + } + + public void removeRecord(String section, String key) + { + if(section == null) + { + section = ""; + } + + if(ignorecase) + { + section = section.toLowerCase(); + key = key.toLowerCase(); + } + + Hashtable records = (Hashtable)sections.get(section); + + if(records != null) + { + records.remove(key); + ((Vector)keylists.get(section)).removeElement(key); + } + } + + public void removeSection(String section) + { + if(section == null) + { + section = ""; + } + + if(ignorecase) + { + section = section.toLowerCase(); + } + + sections.remove(section); + sectlist.removeElement(section); + } + + public Enumeration listSections() + { + return sectlist.elements(); // sections.keys(); + } + + public Enumeration listKeys(String section) + { + if(section == null) + { + section = ""; + } + + if(ignorecase) + { + section = section.toLowerCase(); + } + +// Hashtable records = (Hashtable)sections.get(section); +// +// if(records == null) +// { +// return null; +// } +// +// return records.keys(); + + Vector keylist = (Vector)keylists.get(section); + + if(keylist == null) + { + return null; + } + + return keylist.elements(); + } + + /** + * Считать из потока INI-Ñтроку. + */ + public static String readIniLine(InputStreamDecoder isd) throws IOException + { + if(isd == null || isd.available() <= 0) + { + // еÑли файл кончилÑÑ, возвращаем null + return null; + } + + String s; + char c; + int index; + + // внешний цикл - читаем Ñтроки, + // пока не вÑтретитÑÑ Ð½Ðµ пуÑÑ‚Ð°Ñ + while(isd.available() > 0) + { + s = ""; + + // внутренний цикл - чтение Ñтроки + while(isd.available() > 0) + { + c = isd.readChar(); + + if(c == '\n') + { + break; + } + else if(c == '\t') + { + c = ' '; + } + + if(c != '\r') + { + s += c; + } + } + + index = s.indexOf(';'); + + if(index >= 0) + { + // убираем комментарии + s = s.substring(0, index); + } + + s = s.trim(); + + if(s.length() > 0) + { + return s; + } + } + + return null; + } +} diff --git a/src/com/one/IniRecord.java b/src/com/one/IniRecord.java new file mode 100644 index 0000000..c01db9c --- /dev/null +++ b/src/com/one/IniRecord.java @@ -0,0 +1,49 @@ +package com.one; + +import com.vmx.*; + +/** + * ЗапиÑÑŒ INI. + * ОÑтавлена, по большому Ñчету, только Ð´Ð»Ñ ÑовмеÑтимоÑти + * (в тот день программиÑту было лень пиÑать обновленный код). + */ +public class IniRecord +{ + public String key; + public String value; + + public IniRecord(String key, String value) + { + this.key = key; + this.value = value; + } + + public static IniRecord getNextRecord(InputStreamDecoder isd) + { + try + { + String line = IniFile.readIniLine(isd); + + if(line == null) + { + return null; + } + + int index = line.indexOf('='); + + if(index >= 0) + { + return new IniRecord(line.substring(0, index).trim(), line.substring(index + 1).trim()); + } + else + { + return new IniRecord(line, line); + } + } + catch(Exception e) + { + ErrScreen.showErrMsg(99, e); + return null; + } + } +} diff --git a/src/com/one/IntStack.java b/src/com/one/IntStack.java new file mode 100644 index 0000000..ed3784d --- /dev/null +++ b/src/com/one/IntStack.java @@ -0,0 +1,69 @@ +package com.one; + +import java.util.EmptyStackException; + +public class IntStack +{ + public static final int DELTA = 4096; + + protected int[] data; + protected int index; + + public IntStack() + { + clear(); + } + + public void push(int value) + { + if(index >= data.length - 1) + { + try + { + int[] temp = new int[data.length + DELTA]; + System.arraycopy(data, 0, temp, 0, data.length); + data = temp; + } + catch(OutOfMemoryError oome) + { + throw new StackOverflowException(); + } + } + + data[++index] = value; + } + + public int pop() + { + if(index < 0) + { + throw new EmptyStackException(); + } + + if(index + (DELTA << 1) <= data.length - 1) + { + try + { + int[] temp = new int[data.length - DELTA]; + System.arraycopy(data, 0, temp, 0, temp.length); + data = temp; + } + catch(OutOfMemoryError oome) + { + } + } + + return data[index--]; + } + + public void clear() + { + data = new int[0]; + index = -1; + } + + public boolean empty() + { + return index < 0; + } +} diff --git a/src/com/one/LightControl.java b/src/com/one/LightControl.java new file mode 100644 index 0000000..a666ac5 --- /dev/null +++ b/src/com/one/LightControl.java @@ -0,0 +1,55 @@ +package com.one; + +//#if NokiaUI == "true" + +import java.util.Timer; +import java.util.TimerTask; +import com.nokia.mid.ui.DeviceControl; +import com.vmx.AuxClass; + +public class LightControl +{ + public static final int LEVEL = 100; + public static final int INTERVAL = 1000; + + protected static Timer timer; + + public static void startLightControl(boolean enabled) + { + if(!AuxClass.classExists("com.nokia.mid.ui.DeviceControl")) + { + return; + } + + if(timer != null) + { + timer.cancel(); + timer = null; + } + + if(enabled) + { + TimerTask task = new TimerTask() + { + public void run() + { + DeviceControl.setLights(0, LEVEL); + } + }; + + timer = new Timer(); + timer.scheduleAtFixedRate(task, INTERVAL, INTERVAL); + } + } +} + +//#else +//# +//# public class LightControl +//# { +//# public static void startLightControl(boolean enabled) +//# { +//# } +//# } +//# +//#endif \ No newline at end of file diff --git a/src/com/one/MD5.java b/src/com/one/MD5.java new file mode 100644 index 0000000..d97f9d5 --- /dev/null +++ b/src/com/one/MD5.java @@ -0,0 +1,380 @@ +package com.one; + +public class MD5 +{ + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + private long count; + private byte[] buffer; + + /** 128-bit interim result. */ + private int h0, h1, h2, h3; + + public MD5() + { + buffer = new byte[BLOCK_SIZE]; + resetContext(); + } + + public void update(byte b) + { + // compute number of bytes still unhashed; ie. present in buffer + + int i = (int)(count % BLOCK_SIZE); + count++; + buffer[i] = b; + + if(i == (BLOCK_SIZE - 1)) + { + transform(buffer, 0); + } + } + + public void update(byte[] b) + { + update(b, 0, b.length); + } + + public void update(byte[] b, int offset, int len) + { + int n = (int)(count % BLOCK_SIZE); + count += len; + int partLen = BLOCK_SIZE - n; + int i = 0; + + if(len >= partLen) + { + System.arraycopy(b, offset, buffer, n, partLen); + transform(buffer, 0); + + for(i = partLen; i + BLOCK_SIZE - 1 < len; i += BLOCK_SIZE) + { + transform(b, offset + i); + } + + n = 0; + } + + if(i < len) + { + System.arraycopy(b, offset + i, buffer, n, len - i); + } + } + + /** + * Constructs the result from the contents of the current context. + * + * @return the output of the completed hash operation. + */ + public int[] digest() + { + byte[] tail = padBuffer(); // pad remaining bytes in buffer + update(tail, 0, tail.length); // last transform of a message + + // make a result out of context + int[] result = new int[4]; + result[0] = (h0 & 0xFF) << 24 | + ((h0 >> 8) & 0xFF) << 16 | + ((h0 >> 16) & 0xFF) << 8 | + ((h0 >> 24) & 0xFF); + result[1] = (h1 & 0xFF) << 24 | + ((h1 >> 8) & 0xFF) << 16 | + ((h1 >> 16) & 0xFF) << 8 | + ((h1 >> 24) & 0xFF); + result[2] = (h2 & 0xFF) << 24 | + ((h2 >> 8) & 0xFF) << 16 | + ((h2 >> 16) & 0xFF) << 8 | + ((h2 >> 24) & 0xFF); + result[3] = (h3 & 0xFF) << 24 | + ((h3 >> 8) & 0xFF) << 16 | + ((h3 >> 16) & 0xFF) << 8 | + ((h3 >> 24) & 0xFF); + + reset(); // reset this instance for future re-use + + return result; + } + + public void reset() + { + count = 0L; + + for(int i = 0; i < BLOCK_SIZE; buffer[i++] = 0); + + resetContext(); + } + + /** + * Returns the byte array to use as padding before completing a hash + * operation. + * + * @return the bytes to pad the remaining bytes in the buffer before + * completing a hash operation. + */ + private byte[] padBuffer() + { + int n = (int)(count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] result = new byte[padding+8]; + + // padding is always binary 1 followed by binary 0s + result[0] = (byte)0x80; + + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + + result[padding++] = (byte)bits; + result[padding++] = (byte)(bits >>> 8); + result[padding++] = (byte)(bits >>> 16); + result[padding++] = (byte)(bits >>> 24); + result[padding++] = (byte)(bits >>> 32); + result[padding++] = (byte)(bits >>> 40); + result[padding++] = (byte)(bits >>> 48); + result[padding] = (byte)(bits >>> 56); + + return result; + } + + private void resetContext() + { + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + } + + /** + * The block digest transformation per se. + * + * @param in the blockSize long block, as an array of bytes to digest. + * @param offset the index where the data to digest is located within the + * input buffer. + */ + private void transform(byte[] in, int i) + { + int X0 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X1 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X2 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X3 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X4 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X5 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X6 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X7 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X8 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X9 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X10 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X11 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X12 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X13 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X14 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X15 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i] << 24; + + int A = h0; + int B = h1; + int C = h2; + int D = h3; + + // hex constants are from md5.c in FSF Gnu Privacy Guard 0.9.2 + + // round 1 + A += ((B & C) | (~B & D)) + X0 + 0xD76AA478; + A = B + (A << 7 | A >>> -7); + D += ((A & B) | (~A & C)) + X1 + 0xE8C7B756; + D = A + (D << 12 | D >>> -12); + C += ((D & A) | (~D & B)) + X2 + 0x242070DB; + C = D + (C << 17 | C >>> -17); + B += ((C & D) | (~C & A)) + X3 + 0xC1BDCEEE; + B = C + (B << 22 | B >>> -22); + + A += ((B & C) | (~B & D)) + X4 + 0xF57C0FAF; + A = B + (A << 7 | A >>> -7); + D += ((A & B) | (~A & C)) + X5 + 0x4787C62A; + D = A + (D << 12 | D >>> -12); + C += ((D & A) | (~D & B)) + X6 + 0xA8304613; + C = D + (C << 17 | C >>> -17); + B += ((C & D) | (~C & A)) + X7 + 0xFD469501; + B = C + (B << 22 | B >>> -22); + + A += ((B & C) | (~B & D)) + X8 + 0x698098D8; + A = B + (A << 7 | A >>> -7); + D += ((A & B) | (~A & C)) + X9 + 0x8B44F7AF; + D = A + (D << 12 | D >>> -12); + C += ((D & A) | (~D & B)) + X10 + 0xFFFF5BB1; + C = D + (C << 17 | C >>> -17); + B += ((C & D) | (~C & A)) + X11 + 0x895CD7BE; + B = C + (B << 22 | B >>> -22); + + A += ((B & C) | (~B & D)) + X12 + 0x6B901122; + A = B + (A << 7 | A >>> -7); + D += ((A & B) | (~A & C)) + X13 + 0xFD987193; + D = A + (D << 12 | D >>> -12); + C += ((D & A) | (~D & B)) + X14 + 0xA679438E; + C = D + (C << 17 | C >>> -17); + B += ((C & D) | (~C & A)) + X15 + 0x49B40821; + B = C + (B << 22 | B >>> -22); + + // round 2 + A += ((B & D) | (C & ~D)) + X1 + 0xF61E2562; + A = B + (A << 5 | A >>> -5); + D += ((A & C) | (B & ~C)) + X6 + 0xC040B340; + D = A + (D << 9 | D >>> -9); + C += ((D & B) | (A & ~B)) + X11 + 0x265E5A51; + C = D + (C << 14 | C >>> -14); + B += ((C & A) | (D & ~A)) + X0 + 0xE9B6C7AA; + B = C + (B << 20 | B >>> -20); + + A += ((B & D) | (C & ~D)) + X5 + 0xD62F105D; + A = B + (A << 5 | A >>> -5); + D += ((A & C) | (B & ~C)) + X10 + 0x02441453; + D = A + (D << 9 | D >>> -9); + C += ((D & B) | (A & ~B)) + X15 + 0xD8A1E681; + C = D + (C << 14 | C >>> -14); + B += ((C & A) | (D & ~A)) + X4 + 0xE7D3FBC8; + B = C + (B << 20 | B >>> -20); + + A += ((B & D) | (C & ~D)) + X9 + 0x21E1CDE6; + A = B + (A << 5 | A >>> -5); + D += ((A & C) | (B & ~C)) + X14 + 0xC33707D6; + D = A + (D << 9 | D >>> -9); + C += ((D & B) | (A & ~B)) + X3 + 0xF4D50D87; + C = D + (C << 14 | C >>> -14); + B += ((C & A) | (D & ~A)) + X8 + 0x455A14ED; + B = C + (B << 20 | B >>> -20); + + A += ((B & D) | (C & ~D)) + X13 + 0xA9E3E905; + A = B + (A << 5 | A >>> -5); + D += ((A & C) | (B & ~C)) + X2 + 0xFCEFA3F8; + D = A + (D << 9 | D >>> -9); + C += ((D & B) | (A & ~B)) + X7 + 0x676F02D9; + C = D + (C << 14 | C >>> -14); + B += ((C & A) | (D & ~A)) + X12 + 0x8D2A4C8A; + B = C + (B << 20 | B >>> -20); + + // round 3 + A += (B ^ C ^ D) + X5 + 0xFFFA3942; + A = B + (A << 4 | A >>> -4); + D += (A ^ B ^ C) + X8 + 0x8771F681; + D = A + (D << 11 | D >>> -11); + C += (D ^ A ^ B) + X11 + 0x6D9D6122; + C = D + (C << 16 | C >>> -16); + B += (C ^ D ^ A) + X14 + 0xFDE5380C; + B = C + (B << 23 | B >>> -23); + + A += (B ^ C ^ D) + X1 + 0xA4BEEA44; + A = B + (A << 4 | A >>> -4); + D += (A ^ B ^ C) + X4 + 0x4BDECFA9; + D = A + (D << 11 | D >>> -11); + C += (D ^ A ^ B) + X7 + 0xF6BB4B60; + C = D + (C << 16 | C >>> -16); + B += (C ^ D ^ A) + X10 + 0xBEBFBC70; + B = C + (B << 23 | B >>> -23); + + A += (B ^ C ^ D) + X13 + 0x289B7EC6; + A = B + (A << 4 | A >>> -4); + D += (A ^ B ^ C) + X0 + 0xEAA127FA; + D = A + (D << 11 | D >>> -11); + C += (D ^ A ^ B) + X3 + 0xD4EF3085; + C = D + (C << 16 | C >>> -16); + B += (C ^ D ^ A) + X6 + 0x04881D05; + B = C + (B << 23 | B >>> -23); + + A += (B ^ C ^ D) + X9 + 0xD9D4D039; + A = B + (A << 4 | A >>> -4); + D += (A ^ B ^ C) + X12 + 0xE6DB99E5; + D = A + (D << 11 | D >>> -11); + C += (D ^ A ^ B) + X15 + 0x1FA27CF8; + C = D + (C << 16 | C >>> -16); + B += (C ^ D ^ A) + X2 + 0xC4AC5665; + B = C + (B << 23 | B >>> -23); + + // round 4 + A += (C ^ (B | ~D)) + X0 + 0xF4292244; + A = B + (A << 6 | A >>> -6); + D += (B ^ (A | ~C)) + X7 + 0x432AFF97; + D = A + (D << 10 | D >>> -10); + C += (A ^ (D | ~B)) + X14 + 0xAB9423A7; + C = D + (C << 15 | C >>> -15); + B += (D ^ (C | ~A)) + X5 + 0xFC93A039; + B = C + (B << 21 | B >>> -21); + + A += (C ^ (B | ~D)) + X12 + 0x655B59C3; + A = B + (A << 6 | A >>> -6); + D += (B ^ (A | ~C)) + X3 + 0x8F0CCC92; + D = A + (D << 10 | D >>> -10); + C += (A ^ (D | ~B)) + X10 + 0xFFEFF47D; + C = D + (C << 15 | C >>> -15); + B += (D ^ (C | ~A)) + X1 + 0x85845dd1; + B = C + (B << 21 | B >>> -21); + + A += (C ^ (B | ~D)) + X8 + 0x6FA87E4F; + A = B + (A << 6 | A >>> -6); + D += (B ^ (A | ~C)) + X15 + 0xFE2CE6E0; + D = A + (D << 10 | D >>> -10); + C += (A ^ (D | ~B)) + X6 + 0xA3014314; + C = D + (C << 15 | C >>> -15); + B += (D ^ (C | ~A)) + X13 + 0x4E0811A1; + B = C + (B << 21 | B >>> -21); + + A += (C ^ (B | ~D)) + X4 + 0xF7537E82; + A = B + (A << 6 | A >>> -6); + D += (B ^ (A | ~C)) + X11 + 0xBD3AF235; + D = A + (D << 10 | D >>> -10); + C += (A ^ (D | ~B)) + X2 + 0x2AD7D2BB; + C = D + (C << 15 | C >>> -15); + B += (D ^ (C | ~A)) + X9 + 0xEB86D391; + B = C + (B << 21 | B >>> -21); + + h0 += A; + h1 += B; + h2 += C; + h3 += D; + } +} diff --git a/src/com/one/ModulePlayer.java b/src/com/one/ModulePlayer.java new file mode 100644 index 0000000..3073301 --- /dev/null +++ b/src/com/one/ModulePlayer.java @@ -0,0 +1,582 @@ +package com.one; + +import javax.microedition.media.*; +import javax.microedition.media.control.*; +import java.io.*; +import java.util.*; +import com.ibxm.*; + +public class ModulePlayer implements Runnable, Player, PlayerListener +{ + protected static final String CONTENT = "audio/x-wav"; + protected static final Random rnd = new Random(); + + public static final int[] SAMPLE_RATES = new int[] { 8000, 11025, 16000, 22050, 32000, 44100 }; + + protected IBXM ibxm; + protected int samplerate; + protected int bufseconds; + protected int bufsamples; + protected int bufdispersion; + protected int totalsamples; + protected int samplesleft; + + protected Player currentPlayer; + protected Player playerA, playerB; + protected byte[] bufferA, bufferB; + protected Thread t; + protected long prevtime, totaltime; + protected Vector listeners; + protected int state; + protected int loopcount; + protected VolumeControl volumecontrol; + protected int volumelevel; + protected boolean volumemute; + + public ModulePlayer(InputStream input, int samplerateindex, int quality, int bufseconds) throws IOException + { + this.samplerate = SAMPLE_RATES[samplerateindex]; + this.bufseconds = bufseconds; + + ibxm = new IBXM(input, samplerate, quality); + + totalsamples = ibxm.calculate_song_duration(); + totaltime = (long)totalsamples * 1000000L / (long)samplerate; + + listeners = new Vector(); + + state = UNREALIZED; + + volumelevel = 100; + volumemute = false; + } + + public void addPlayerListener(PlayerListener listener) + { + if(listener != null && !listeners.contains(listener)) + { + listeners.addElement(listener); + } + } + + public void close() + { + deallocate(); + + state = Player.CLOSED; + postEvent(PlayerListener.CLOSED, null); + + bufferA = null; + bufferB = null; + + ibxm = null; + + System.gc(); + } + + public void deallocate() + { + if(state == Player.CLOSED) + { + throw new IllegalStateException("Player is closed"); + } + + try + { + stop(); + } + catch(MediaException me) + { + } + + if(state == PREFETCHED) + { + if(t != null && t.isAlive()) + { + try + { + t.join(); + } + catch(InterruptedException ie) + { + } + } + + currentPlayer = null; + updateVolumeControl(); + + if(playerA != null) + { + playerA.close(); + playerA = null; + } + + if(playerB != null) + { + playerB.close(); + playerB = null; + } + + state = REALIZED; + } + } + + public String getContentType() + { + return CONTENT; + } + + public long getDuration() + { + if(state == Player.CLOSED) + { + throw new IllegalStateException("Player is closed"); + } + + return totaltime; + } + + public long getMediaTime() + { + if(state == Player.CLOSED) + { + throw new IllegalStateException("Player is closed"); + } + + if(currentPlayer != null) + { + return prevtime + currentPlayer.getMediaTime(); + } + else + { + return prevtime; + } + } + + public int getState() + { + return state; + } + + public TimeBase getTimeBase() + { + return Manager.getSystemTimeBase(); + } + + public void prefetch() throws MediaException + { + realize(); + + if(state == REALIZED) + { + startThread(); + + if(t.isAlive()) + { + try + { + t.join(); + } + catch(InterruptedException ie) + { + } + } + + currentPlayer = playerA; + updateVolumeControl(); + + startThread(); + + if(t.isAlive()) + { + try + { + t.join(); + } + catch(InterruptedException ie) + { + } + } + + state = PREFETCHED; + } + } + + public void realize() throws MediaException + { + if(state == Player.CLOSED) + { + throw new IllegalStateException("Player is closed"); + } + + if(state == UNREALIZED) + { + ibxm.seek(0); + samplesleft = totalsamples; + prevtime = 0; + + int bufsize; + + while(true) + { + try + { + if(bufseconds <= 0) + { + bufseconds = (int)(totaltime / 2000000L) + 1; + } + + bufsamples = bufseconds * samplerate; + bufdispersion = bufsamples / 5; + bufsize = (bufsamples + bufdispersion) * 2 * 2 + WavHeader.SIZE; + + bufferA = new byte[bufsize]; + bufferB = new byte[bufsize]; + + break; + } + catch(Throwable e) + { + bufferA = null; + bufferB = null; + System.gc(); + + if(--bufseconds <= 0) + { + throw new MediaException("Consider this as \"OutOfMemoryError\""); + } + } + } + + state = REALIZED; + } + } + + public void removePlayerListener(PlayerListener listener) + { + if(listener != null) + { + listeners.removeElement(listener); + } + } + + public void setLoopCount(int count) + { + loopcount = count; + } + + public long setMediaTime(long now) throws MediaException + { + if(state == Player.CLOSED) + { + throw new IllegalStateException("Player is closed"); + } + + if(now < 0) + { + now = 0; + } + else if(now > totaltime) + { + now = totaltime; + } + + if(currentPlayer != null && now >= prevtime && now <= prevtime + currentPlayer.getDuration()) + { + currentPlayer.setMediaTime(now - prevtime); + return getMediaTime(); + } + + deallocate(); + + int framepos = (int)((long)samplerate * now / 1000000L); + + ibxm.seek(framepos); + samplesleft = totalsamples - framepos; + prevtime = now; + + return getMediaTime(); + } + + public void setTimeBase(TimeBase master) + { + } + + public void start() throws MediaException + { + prefetch(); + + if(state == PREFETCHED) + { + if(currentPlayer != null) + { + currentPlayer.start(); + + state = Player.STARTED; + postEvent(PlayerListener.STARTED, null); + } + } + } + + public void stop() throws MediaException + { + if(state == Player.CLOSED) + { + throw new IllegalStateException("Player is closed"); + } + + if(state == Player.STARTED) + { + if(currentPlayer != null) + { + currentPlayer.stop(); + } + + state = PREFETCHED; + postEvent(STOPPED, null); + } + } + + public String getSongTitle() + { + return ibxm.getSongTitle(); + } + + protected void updateVolumeControl() + { + if(currentPlayer != null) + { + volumecontrol = (VolumeControl)currentPlayer.getControl("VolumeControl"); + + volumecontrol.setLevel(volumelevel); + volumecontrol.setMute(volumemute); + } + else + { + volumecontrol = null; + } + } + + public void setVolumeLevel(int level) + { + volumelevel = level; + + if(volumecontrol != null) + { + volumecontrol.setLevel(volumelevel); + } + } + + public void setVolumeMute(boolean mute) + { + volumemute = mute; + + if(volumecontrol != null) + { + volumecontrol.setMute(volumemute); + } + } + + public void playerUpdate(Player player, String event, Object data) + { + if(event.equals(PlayerListener.STARTED)) + { + if(state != Player.STARTED) + { + try + { + player.stop(); + } + catch(MediaException me) + { + } + } + } + else if(event.equals(END_OF_MEDIA)) + { + try + { + if(t.isAlive()) + { + try + { + t.join(); + } + catch(InterruptedException ie) + { + } + } + + if(player == playerA) + { + prevtime += player.getDuration(); + + currentPlayer = playerB; + updateVolumeControl(); + + if(playerB != null) + { + if(state == Player.STARTED) + { + playerB.start(); + } + } + else + { + postEvent(END_OF_MEDIA, null); + + if(state != Player.CLOSED) + { + if(loopcount < 0) + { + setMediaTime(0); + } + else if(loopcount > 0) + { + setMediaTime(0); + loopcount--; + } + } + } + + playerA.close(); + playerA = null; + } + else if(player == playerB) + { + prevtime += player.getDuration(); + + currentPlayer = playerA; + updateVolumeControl(); + + if(playerA != null) + { + if(state == Player.STARTED) + { + playerA.start(); + } + } + else + { + postEvent(END_OF_MEDIA, null); + + if(state != Player.CLOSED) + { + if(loopcount < 0) + { + setMediaTime(0); + } + else if(loopcount > 0) + { + setMediaTime(0); + loopcount--; + } + } + } + + playerB.close(); + playerB = null; + } + else + { + deallocate(); + return; + } + + startThread(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(97, e); + deallocate(); + } + } + } + + protected void startThread() + { + t = new Thread(this, "ModulePlayer/Bufferization"); + t.setPriority(Thread.MIN_PRIORITY); + t.start(); + } + + public void run() + { + try + { + if(samplesleft <= 0) + { + return; + } + + Thread.yield(); + + int numsamples; + + if(samplesleft > bufsamples) + { + if(bufdispersion > 0) + { + numsamples = bufsamples + rnd.nextInt() % bufdispersion; + } + else + { + numsamples = bufsamples; + } + } + else + { + numsamples = samplesleft; + } + + samplesleft -= numsamples; + + if(playerA == null) + { + WavHeader.writeHeader(bufferA, 2, samplerate, 2, numsamples); + ibxm.get_audio(bufferA, WavHeader.SIZE, numsamples); + + playerA = Manager.createPlayer(new ByteArrayInputStream(bufferA), CONTENT); + playerA.realize(); + playerA.prefetch(); + playerA.addPlayerListener(this); + } + else if(playerB == null) + { + WavHeader.writeHeader(bufferB, 2, samplerate, 2, numsamples); + ibxm.get_audio(bufferB, WavHeader.SIZE, numsamples); + + playerB = Manager.createPlayer(new ByteArrayInputStream(bufferB), CONTENT); + playerB.realize(); + playerB.prefetch(); + playerB.addPlayerListener(this); + } + else + { + deallocate(); + } + } + catch(Exception e) + { + ErrScreen.showErrMsg(98, e); + } + } + + protected void postEvent(String event, Object data) + { + for(int i = 0; i < listeners.size(); i++) + { + ((PlayerListener)listeners.elementAt(i)).playerUpdate(this, event, data); + } + } + + public Control getControl(String controlType) + { + return null; + } + + public Control[] getControls() + { + return null; + } +} diff --git a/src/com/one/ModuleRegistry.java b/src/com/one/ModuleRegistry.java new file mode 100644 index 0000000..d45ca21 --- /dev/null +++ b/src/com/one/ModuleRegistry.java @@ -0,0 +1,968 @@ +package com.one; + +import com.vmx.AuxClass; +import com.vmx.InputStreamDecoder; +import com.vmx.Locale; +import com.vmx.ProgressCallback; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; +import javax.microedition.lcdui.Font; +import javax.microedition.lcdui.Image; +import javax.microedition.rms.InvalidRecordIDException; +import javax.microedition.rms.RecordStore; +import javax.microedition.rms.RecordStoreException; +import javax.microedition.rms.RecordStoreNotOpenException; + +public class ModuleRegistry +{ + public static final int ACTION_UNKNOWN = 0; + public static final int ACTION_EXPLORE = 1; + public static final int ACTION_OPEN = 2; + + protected static Hashtable modules = new Hashtable(); // файловые модули по раÑширениÑм + protected static Hashtable actions = new Hashtable(); // дейÑÑ‚Ð²Ð¸Ñ Ð¿Ð¾ раÑширениÑм и модулÑм + //protected static Hashtable instances = new Hashtable(); // загруженные объекты по раÑширениÑм + protected static Hashtable icons = new Hashtable(); // значки по раширениÑм и модулÑм + protected static Hashtable locnames = new Hashtable(); // локализованные имена по модулÑм + protected static Hashtable similars = new Hashtable(); // ÑпиÑки похожих модулей по группам + protected static Vector operations = new Vector(); // операции + protected static Vector filesources = new Vector(); // иÑточники файлов + protected static Vector contsources = new Vector(); // иÑточники контейнеров + protected static Hashtable extensions = new Hashtable(); // раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² по модулÑм + protected static Vector optstores = new Vector(); // хранилища наÑтроек + protected static Hashtable errcodes = new Hashtable(); // базы кодов ошибок + + protected static Vector modlist = new Vector(); // упорÑдоченный ÑпиÑок Ð´Ð»Ñ modules + protected static Vector simlist = new Vector(); // упорÑдоченный ÑпиÑок Ð´Ð»Ñ similars + + protected static Hashtable rmsmap; // номера запиÑей по модулÑм + + /** + * ОчиÑтить вÑе ÑпиÑки модулей (например, перед повторной загрузкой). + */ + public static void reset() + { + modules.clear(); + actions.clear(); + icons.clear(); + locnames.clear(); + similars.clear(); + operations.removeAllElements(); + filesources.removeAllElements(); + contsources.removeAllElements(); + extensions.clear(); + optstores.removeAllElements(); + errcodes.clear(); + modlist.removeAllElements(); + simlist.removeAllElements(); + + rmsmap = null; + } + + /** + * Чтение абÑтрактного ÑпиÑка модулей (файл modules.ini). + */ + public static void readModuleList(ProgressCallback callback, boolean noEffects) throws IOException + { + IniFile ini = new IniFile("/config/modules.ini", false); + + Enumeration sections = ini.listSections(); + String section; + Integer action; + Vector target; + + Enumeration keys; + String key, value; + int index; + String locname; + Image icon; + String iconspec; + Integer errcode; + + int ih = Font.getDefaultFont().getHeight(); + + loadScaledIcons(); + boolean updatecache = false; + + while(sections.hasMoreElements()) + { + section = (String)sections.nextElement(); + + if(section.equalsIgnoreCase("Container")) + { + action = new Integer(ACTION_EXPLORE); + target = null; + } + else if(section.equalsIgnoreCase("Application")) + { + action = new Integer(ACTION_OPEN); + target = null; + } + else if(section.equalsIgnoreCase("Operation")) + { + action = null; + target = operations; + } + else if(section.equalsIgnoreCase("FileSource")) + { + action = null; + target = filesources; + } + else if(section.equalsIgnoreCase("ContainerSource")) + { + action = null; + target = contsources; + } + else + { + continue; + } + + keys = ini.listKeys(section); + + while(keys.hasMoreElements()) + { + key = (String)keys.nextElement(); + + if(!AuxClass.classExists(key)) + { + continue; + } + + value = ini.getRecord(section, key); + + index = value.indexOf(','); + + if(index >= 0) + { + locname = value.substring(0, index).trim(); + iconspec = value.substring(index + 1); + } + else + { + locname = value; + iconspec = null; + } + + errcode = null; + + if(locname.startsWith("#")) + { + try + { + errcode = new Integer(Integer.parseInt(key.substring(1).trim()) + Locale.getOffset(key)); + } + catch(NumberFormatException nfe) + { + } + } + + if(errcode == null) + { + errcode = new Integer(locname.hashCode() % 1000); + } + + errcodes.put(key, errcode); + + locname = TextProcessor.getString(key, locname); + + if(action != null) + { + actions.put(key.toLowerCase(), action); + modlist.addElement(key); + } + + if(target != null) + { + target.addElement(key); + } + + locnames.put(key, locname); + + key = key.toLowerCase(); + + if(!icons.containsKey(key) && iconspec != null) + { + icon = ImageProcessor.scaleImage(ImageProcessor.getImage("/img/", iconspec), -1, ih, !noEffects, true); + + if(icon != null) + { + icons.put(key, icon); + updatecache = true; + + callback.setProgress(0); + callback.setMax(icons.size()); + } + } + } + } + + if(updatecache) + { + saveScaledIcons(callback); + } + } + + /** + * Чтение аÑÑоциаций раÑширений файлов Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñми (файл types.ini). + */ + public static void readTypeList() throws IOException + { + if(readCustomTypeList()) + { + return; + } + + IniFile ini = new IniFile("/config/types.ini", false); + + Enumeration sections = ini.listSections(); + String section; + + Enumeration keys; + String key, value; + + Integer action; + Image icon; + Vector tokens; + String ext; + + while(sections.hasMoreElements()) + { + section = (String)sections.nextElement(); + keys = ini.listKeys(section); + + if(section.equalsIgnoreCase("Open")) + { + while(keys.hasMoreElements()) + { + key = (String)keys.nextElement(); + value = ini.getRecord(section, key); + + if(!AuxClass.classExists(value)) + { + continue; + } + + action = (Integer)actions.get(value.toLowerCase()); + icon = (Image)icons.get(value.toLowerCase()); + + tokens = StringPattern.tokenizeString(key, ' '); + + for(int i = 0; i < tokens.size(); i++) + { + ext = ((String)tokens.elementAt(i)).toLowerCase(); + + modules.put(ext, value); + + if(action != null) + { + actions.put(ext, action); + } + + if(icon != null) + { + icons.put(ext, icon); + } + } + } + } + else if(section.equalsIgnoreCase("Create") || + section.equalsIgnoreCase("Special")) + { + while(keys.hasMoreElements()) + { + key = (String)keys.nextElement(); + value = ini.getRecord(section, key); + + extensions.put(key, value); + } + } + } + + saveCustomTypeList(); + } + + /** + * Чтение ÑпиÑка групп Ñхожих модулей (файл groups.ini). + */ + public static void readGroupList() throws IOException + { + InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/config/groups.ini"); + IniRecord record = null; + + Vector tokens; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + tokens = StringPattern.tokenizeString(record.value, ','); + + for(int i = 0; i < tokens.size(); i++) + { + tokens.setElementAt(((String)tokens.elementAt(i)).trim(), i); + } + +// if(record.key.startsWith("#")) +// { +// record.key = Locale.getString(this, Integer.parseInt(record.key.substring(1).trim())); +// } + + simlist.addElement(record.key); + similars.put(record.key, tokens); + } + + ini.close(); + } + + /** + * Чтение ÑпиÑка хранилищ наÑтроек (файл options.ini). + */ + public static void readOptionStoreList() throws IOException + { + InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/config/options.ini"); + IniRecord record = null; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + if(!AuxClass.classExists(record.key)) + { + continue; + } + + optstores.addElement(record.key); + locnames.put(record.key, TextProcessor.getString(record.key, record.value)); + } + + ini.close(); + } + + /** + * ВоÑÑтановить наÑтройки Ð´Ð»Ñ Ð²Ñех зарегиÑтрированных хранилищ. + */ + public static void restoreModuleOptions() + { + Enumeration e = optstores.elements(); + String s; + + while(e.hasMoreElements()) + { + ((OptionStorage)ModuleRegistry.getModuleInstance((String)e.nextElement())).restoreOptions(); + } + } + + /** + * Сохранить наÑтройки Ð´Ð»Ñ Ð²Ñех зарегиÑтрированных хранилищ. + */ + public static void saveModuleOptions() + { + Enumeration e = optstores.elements(); + String s; + + while(e.hasMoreElements()) + { + ((OptionStorage)ModuleRegistry.getModuleInstance((String)e.nextElement())).saveOptions(); + } + } + + /** + * ДоÑтать ÑкземплÑÑ€ данного модулÑ. + * + * @param module Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа Ð¼Ð¾Ð´ÑƒÐ»Ñ + * @return ÑкземплÑÑ€ модулÑ, или null + */ + public static Object getModuleInstance(String module) + { + Object instance = null; // instances.get(module); + + if(instance == null) + { + try + { + instance = Class.forName(module).newInstance(); + //instances.put(module, instance); + } + catch(Throwable t) + { + throw new RuntimeException("Unable to instantiate module '" + module + "': " + t.toString()); + } + } + + return instance; + } + + /** + * Получить Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа модулÑ, ÑвÑзанного Ñ Ð´Ð°Ð½Ð½Ñ‹Ð¼ раÑширением. + * + * @param key раÑширение файла (без точки) + * @return Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа модулÑ, или null + */ + public static String getModule(String ext) + { + return (String)modules.get(ext.toLowerCase()); + } + + /** + * Получить Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа модулÑ, который в ÑпиÑке модулей идет под данным индекÑом. + * + * @param index Ð¸Ð½Ð´ÐµÐºÑ Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð² ÑпиÑке + * @return Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа Ð¼Ð¾Ð´ÑƒÐ»Ñ + */ + public static String getModule(int index) + { + return (String)modlist.elementAt(index); + } + + /** + * Получить локализованное Ð¸Ð¼Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ Ñ Ð´Ð°Ð½Ð½Ñ‹Ð¼ именем клаÑÑа. + * + * @param module Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа Ð¼Ð¾Ð´ÑƒÐ»Ñ + * @return локализованное Ð¸Ð¼Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ + */ + public static String getModuleName(String module) + { + return (String)locnames.get(module); + } + + /** + * Получить дейÑтвие Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ ключа. + * Ключом может быть как раÑширение файла, + * так и Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа модулÑ. + * + * @param key ключ + * @return номер дейÑÑ‚Ð²Ð¸Ñ + */ + public static int getAction(String key) + { + Integer action = (Integer)actions.get(key.toLowerCase()); + + if(action == null) + { + return ACTION_UNKNOWN; + } + + return action.intValue(); + } + + /** + * Получить значек Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ ключа. + * Ключом может быть как раÑширение файла, + * так и Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа модулÑ. + * + * @param key ключ + * @return значек, или null + */ + public static Image getIcon(String key) + { + return (Image)icons.get(key.toLowerCase()); + } + + /** + * Получить раÑширение файла Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ модулÑ. + * + * @param module Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа Ð¼Ð¾Ð´ÑƒÐ»Ñ + * @return раÑширение файла, или null + */ + public static String getExtension(String module) + { + return (String)extensions.get(module); + } + + /** + * Получить базовый номер Ð´Ð»Ñ Ð¾ÑˆÐ¸Ð±Ð¾Ðº в данном модуле. + * + * Пример иÑпользованиÑ: + * ErrScreen.showErrMsg(getErrCode() * 100 + LocalErrCode, exception); + * где LocalErrCode - меÑтный код ошибки, в данном Ñлучае + * под меÑтные коды отводитÑÑ 100 номеров (* 100). + * + * @param module Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа Ð¼Ð¾Ð´ÑƒÐ»Ñ + * @return базовый код ошибки + */ + public static int getErrCode(String module) + { + Integer errcode = (Integer)errcodes.get(modules); + + if(errcode != null) + { + return errcode.intValue(); + } + + return 0; + } + + /** + * Получить ÑпиÑок модулей. + * @return Enumeration + */ + public static Enumeration listModules() + { + return modlist.elements(); + } + + /** + * Получить ÑпиÑок файловых иÑточников. + * @return Enumeration + */ + public static Enumeration listFileSources() + { + return filesources.elements(); + } + + /** + * Получить ÑпиÑок иÑточников контейнеров. + * @return Enumeration + */ + public static Enumeration listContainerSources() + { + return contsources.elements(); + } + + /** + * Получить ÑпиÑок хранилищ наÑтроек. + * @return Enumeration + */ + public static Enumeration listOptionStores() + { + return optstores.elements(); + } + + /** + * Получить ÑпиÑок имен групп ÑхожеÑти. + * @return Enumeration + */ + public static Enumeration listSimalarityGroups() + { + return simlist.elements(); + } + + /** + * Получить ÑпиÑок модулей в группе ÑхожеÑти. + * + * @param group группа ÑхожеÑти + * @return Enumeration + */ + public static Enumeration listSimilars(String group) + { + Vector tokens = (Vector)similars.get(group); + + if(tokens == null) + { + return null; + } + + return tokens.elements(); + } + + /** + * СвÑзать раÑширение файла Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ñ‹Ð¼ модулем. + * + * @param key раÑширение файла (без точки) + * @param module Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа Ð¼Ð¾Ð´ÑƒÐ»Ñ + */ + public static String associate(String ext, String module, boolean save) + { + ext = ext.toLowerCase(); + + String prev; + + if(module != null) + { + prev = (String)modules.put(ext, module); + + actions.put(ext, actions.get(module.toLowerCase())); + + if(save) + { + icons.put(ext, icons.get(module.toLowerCase())); + } + } + else + { + prev = (String)modules.remove(ext); + + actions.remove(ext); + icons.remove(ext); + } + + //instances.remove(ext); + + if(save) + { + saveCustomTypeList(); + } + + return prev; + } + + public static void loadIcons(InputStreamDecoder ini, ProgressCallback callback, boolean noEffects) throws IOException + { + reset(); + + IniRecord record = null; + int ih = Font.getDefaultFont().getHeight(); + int counter = 1; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + try + { + icons.put(record.key.toLowerCase(), ImageProcessor.scaleImage(ImageProcessor.getImage("/img/", record.value), -1, ih, !noEffects, true)); + + callback.setProgress(0); + callback.setMax(counter++); + callback.setPercentMode(false); + } + catch(Exception e) + { + } + } + + saveScaledIcons(callback); + + callback.setPercentMode(true); + + readModuleList(callback, noEffects); + readTypeList(); + readGroupList(); + } + + protected static void loadScaledIcons() + { + try + { + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(5), true); + + if(rs.getNumRecords() == 0) + { + rs.closeRecordStore(); + return; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(rs.getRecord(1))); + + int count = dis.readInt(); + + for(int i = 0; i < count; i++) + { + icons.put(dis.readUTF(), ImageProcessor.readImage(dis)); + } + + dis.close(); + + rs.closeRecordStore(); + } + catch(Throwable t) + { + ErrScreen.showErrMsg(129, t); + } + } + + protected static void saveScaledIcons(ProgressCallback callback) + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(icons.size()); + + Enumeration keys = icons.keys(); + String key; + + while(keys.hasMoreElements()) + { + key = (String)keys.nextElement(); + + dos.writeUTF(key); + ImageProcessor.writeImage(dos, (Image)icons.get(key), true, null); + + callback.progress(1); + } + + byte[] data = baos.toByteArray(); + dos.close(); + + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(5), true); + + if(rs.getNumRecords() == 0) + { + rs.addRecord(data, 0, data.length); + } + else + { + rs.setRecord(1, data, 0, data.length); + } + + rs.closeRecordStore(); + } + catch(Throwable t) + { + ErrScreen.showErrMsg(130, t); + } + } + + public static void loadRMSMap() + { + try + { + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(6), true); + + if(rs.getNumRecords() == 0) + { + rs.addRecord(null, 0, 0); + rs.closeRecordStore(); + + rmsmap = new Hashtable(); + + return; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(rs.getRecord(1))); + + int count = dis.readInt(); + rmsmap = new Hashtable(count + count / 2); + + for(int i = 0; i < count; i++) + { + rmsmap.put(dis.readUTF(), new Integer(dis.readInt())); + } + + dis.close(); + + rs.closeRecordStore(); + } + catch(Throwable t) + { + ErrScreen.showErrMsg(131, t); + } + } + + protected static void saveRMSMap(RecordStore rs) throws IOException, RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException + { + if(rmsmap == null) + { + return; + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(rmsmap.size()); + + Enumeration keys = rmsmap.keys(); + String key; + + while(keys.hasMoreElements()) + { + key = (String)keys.nextElement(); + + dos.writeUTF(key); + dos.writeInt(((Integer)rmsmap.get(key)).intValue()); + } + + byte[] data = baos.toByteArray(); + dos.close(); + + rs.setRecord(1, data, 0, data.length); + } + + public static byte[] getModuleData(String module) + { + if(rmsmap == null) + { + loadRMSMap(); + } + + try + { + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(6), true); + + if(rs.getNumRecords() == 0) + { + rs.addRecord(null, 0, 0); + } + + Integer id = (Integer)rmsmap.get(module); + + if(id == null) + { + id = new Integer(rs.addRecord(null, 0, 0)); + rmsmap.put(module, id); + + saveRMSMap(rs); + } + + byte[] data = rs.getRecord(id.intValue()); + + rs.closeRecordStore(); + + return data; + } + catch(Throwable t) + { + ErrScreen.showErrMsg(132, t); + return null; + } + } + + public static void setModuleData(String module, byte[] data) + { + if(rmsmap == null) + { + loadRMSMap(); + } + + try + { + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(6), true); + + if(rs.getNumRecords() == 0) + { + rs.addRecord(null, 0, 0); + } + + Integer id = (Integer)rmsmap.get(module); + + if(id == null) + { + id = new Integer(rs.addRecord(null, 0, 0)); + rmsmap.put(module, id); + + saveRMSMap(rs); + } + + rs.setRecord(id.intValue(), data, 0, data.length); + + rs.closeRecordStore(); + } + catch(Throwable t) + { + ErrScreen.showErrMsg(133, t); + } + } + + protected static boolean readCustomTypeList() + { + try + { + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(7), true); + + if(rs.getNumRecords() == 0) + { + rs.closeRecordStore(); + return false; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(rs.getRecord(1))); + + int count = dis.readInt(); + String ext, module; + + Integer action; + Image icon; + + for(int i = 0; i < count; i++) + { + ext = dis.readUTF(); + module = dis.readUTF(); + + modules.put(ext, module); + + module = module.toLowerCase(); + + action = (Integer)actions.get(module); + icon = (Image)icons.get(module); + + if(action != null) + { + actions.put(ext, action); + } + + if(icon != null) + { + icons.put(ext, icon); + } + } + + count = dis.readInt(); + + for(int i = 0; i < count; i++) + { + module = dis.readUTF(); + ext = dis.readUTF(); + + extensions.put(module, ext); + } + + dis.close(); + + rs.closeRecordStore(); + + return true; + } + catch(Throwable t) + { + ErrScreen.showErrMsg(134, t); + return false; + } + } + + protected static void saveCustomTypeList() + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(modules.size()); + + Enumeration keys = modules.keys(); + String key; + + while(keys.hasMoreElements()) + { + key = (String)keys.nextElement(); + + dos.writeUTF(key); + dos.writeUTF((String)modules.get(key)); + } + + dos.writeInt(extensions.size()); + + keys = extensions.keys(); + + while(keys.hasMoreElements()) + { + key = (String)keys.nextElement(); + + dos.writeUTF(key); + dos.writeUTF((String)extensions.get(key)); + } + + byte[] data = baos.toByteArray(); + dos.close(); + + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(7), true); + + if(rs.getNumRecords() == 0) + { + rs.addRecord(data, 0, data.length); + } + else + { + rs.setRecord(1, data, 0, data.length); + } + + rs.closeRecordStore(); + } + catch(Throwable t) + { + ErrScreen.showErrMsg(135, t); + } + } +} diff --git a/src/com/one/OptionStorage.java b/src/com/one/OptionStorage.java new file mode 100644 index 0000000..74e47ad --- /dev/null +++ b/src/com/one/OptionStorage.java @@ -0,0 +1,9 @@ +package com.one; + +public interface OptionStorage +{ + public void saveOptions(); + public void restoreOptions(); + + public void showEditor(Object parent); +} diff --git a/src/com/one/PNGFile.java b/src/com/one/PNGFile.java new file mode 100644 index 0000000..117009d --- /dev/null +++ b/src/com/one/PNGFile.java @@ -0,0 +1,136 @@ +package com.one; + +import javax.microedition.lcdui.Image; +import java.io.*; +import com.vmx.ProgressCallback; +import com.classpath.zip.*; + +public class PNGFile +{ + public static final long PNG_SIGNATURE = 0x89504E470D0A1A0AL; + + public static final int CHUNK_IHDR = 0x49484452; + public static final int CHUNK_IDAT = 0x49444154; + public static final int CHUNK_IEND = 0x49454E44; + + protected static CRC32 crc = new CRC32(); + + public static void writePNG(Image image, DataOutputStream out, ProgressCallback callback) throws IOException + { + int width = image.getWidth(); + int height = image.getHeight(); + + if(callback != null) + { + callback.setProgress(0); + callback.setMax(height); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + out.writeLong(PNG_SIGNATURE); + + dos.writeInt(CHUNK_IHDR); + dos.writeInt(width); + dos.writeInt(height); + dos.writeByte(8); + dos.writeByte(6); + dos.writeByte(0); + dos.writeByte(0); + dos.writeByte(0); + + writeChunk(out, baos.toByteArray()); + baos.reset(); + + dos.writeInt(CHUNK_IDAT); + DeflaterOutputStream def = new DeflaterOutputStream(baos, new Deflater(Deflater.BEST_COMPRESSION, false)); + + int scanlength = width * 4 + 1; + int[] curline = new int[scanlength]; + int[] prevline = new int[scanlength]; + byte[] scanline = new byte[scanlength]; + int[] pixel = new int[1]; + int index; + + for(int y = 0; y < height; y++) + { + index = 0; + + for(int x = 0; x < width; x++) + { + image.getRGB(pixel, 0, 1, x, y, 1, 1); + + curline[++index] = (pixel[0] >> 16) & 0xFF; + curline[++index] = (pixel[0] >> 8) & 0xFF; + curline[++index] = pixel[0] & 0xFF; + curline[++index] = (pixel[0] >> 24) & 0xFF; + } + + scanline[0] = 4; + + scanline[1] = (byte)(curline[1] - PaethPredictor(0, prevline[1], 0)); + scanline[2] = (byte)(curline[2] - PaethPredictor(0, prevline[2], 0)); + scanline[3] = (byte)(curline[3] - PaethPredictor(0, prevline[3], 0)); + scanline[4] = (byte)(curline[4] - PaethPredictor(0, prevline[4], 0)); + + for(index = 5; index < scanlength; index++) + { + scanline[index] = (byte)(curline[index] - PaethPredictor(curline[index - 4], prevline[index], prevline[index - 4])); + } + + def.write(scanline); + + System.arraycopy(curline, 0, prevline, 0, scanlength); + + if(callback != null) + { + callback.progress(1); + } + } + + def.finish(); + + writeChunk(out, baos.toByteArray()); + baos.reset(); + + dos.writeInt(CHUNK_IEND); + + writeChunk(out, baos.toByteArray()); + baos.close(); + } + + public static int PaethPredictor(int a, int b, int c) + { + int p = a + b - c; + + int pa = Math.abs(p - a); + int pb = Math.abs(p - b); + int pc = Math.abs(p - c); + + if(pa <= pb && pa <= pc) + { + return a; + } + else if(pb <= pc) + { + return b; + } + else + { + return c; + } + } + + public static void writeChunk(DataOutputStream dos, byte[] data) throws IOException + { + dos.writeInt(data.length - 4); + + dos.write(data); + + crc.reset(); + crc.update(data); + + dos.writeInt((int)crc.getValue()); + } +} \ No newline at end of file diff --git a/src/com/one/PaintableObject.java b/src/com/one/PaintableObject.java new file mode 100644 index 0000000..84f568e --- /dev/null +++ b/src/com/one/PaintableObject.java @@ -0,0 +1,144 @@ +package com.one; + +import javax.microedition.lcdui.*; + +public abstract class PaintableObject +{ + public static final int KEY_NUM0 = 48; + public static final int KEY_NUM1 = 49; + public static final int KEY_NUM2 = 50; + public static final int KEY_NUM3 = 51; + public static final int KEY_NUM4 = 52; + public static final int KEY_NUM5 = 53; + public static final int KEY_NUM6 = 54; + public static final int KEY_NUM7 = 55; + public static final int KEY_NUM8 = 56; + public static final int KEY_NUM9 = 57; + public static final int KEY_STAR = 42; + public static final int KEY_POUND = 35; + + public static final int UP = 1; + public static final int LEFT = 2; + public static final int RIGHT = 5; + public static final int DOWN = 6; + public static final int FIRE = 8; + public static final int GAME_A = 9; + public static final int GAME_B = 10; + public static final int GAME_C = 11; + public static final int GAME_D = 12; + + private static Renderer renderer; + + public static void setRenderer(Renderer rn) + { + renderer = rn; + } + + public static Renderer getRenderer() + { + return renderer; + } + + public void repaint() + { + renderer.repaint(this); + } + + public void repaint(int x, int y, int width, int height) + { + renderer.repaint(this, x, y, width, height); + } + + public void serviceRepaints() + { + renderer.serviceRepaints(this); + } + + public void setFullScreenMode(boolean mode) + { + renderer.setFullScreenMode(this, mode); + } + + public int getWidth() + { + return renderer.getWidth(); + } + + public int getHeight() + { + return renderer.getHeight(); + } + + public int getGameAction(int keyCode) + { + return renderer.getGameAction(keyCode); + } + + public int getKeyCode(int gameAction) + { + return renderer.getKeyCode(gameAction); + } + + public String getKeyName(int keyCode) + { + return renderer.getKeyName(keyCode); + } + + public boolean hasPointerEvents() + { + return renderer.hasPointerEvents(); + } + + public boolean hasPointerMotionEvents() + { + return renderer.hasPointerMotionEvents(); + } + + public boolean hasRepeatEvents() + { + return renderer.hasRepeatEvents(); + } + + public boolean isDoubleBuffered() + { + return renderer.isDoubleBuffered(); + } + + public void showNotify() + { + } + + public void hideNotify() + { + } + + public void keyPressed(int keyCode) + { + } + + public void keyReleased(int keyCode) + { + } + + public void keyRepeated(int keyCode) + { + } + + public abstract void paint(Graphics g); + + public void pointerDragged(int x, int y) + { + } + + public void pointerPressed(int x, int y) + { + } + + public void pointerReleased(int x, int y) + { + } + + public void sizeChanged(int w, int h) + { + } +} diff --git a/src/com/one/PakFile.java b/src/com/one/PakFile.java new file mode 100644 index 0000000..9529185 --- /dev/null +++ b/src/com/one/PakFile.java @@ -0,0 +1,233 @@ +package com.one; + +import java.io.*; +import java.util.Hashtable; +import com.vmx.*; + +/** + * КлаÑÑ Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ Ñ PAK файлами. + */ +public class PakFile +{ + protected RandomAccessInputStream bis; + protected ByteArrayOutputStream baos_header, baos_files; + protected DataOutputStream dos_header; + + protected short currindex = 0; + protected int curroffset = 0; + protected byte[] buf = null; + + protected short header; // размер заголовка (Ñмещение первого файла) + protected short count; // чиÑло файлов + protected String[] names; // Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° + protected int[] offset; // Ñмещение файла отноÑительно конца заголовка + protected short[] size; // размер файла + protected Hashtable entries; // таблица ÑоответÑÑ‚Ð²Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑов именам + + /** + * Открытие PAK файла из потока в режиме Ñ‡Ñ‚ÐµÐ½Ð¸Ñ + */ + public PakFile(RandomAccessInputStream is) throws IOException + { + closeOutput(); + + //bis = new BufferedInputStream(is); + bis = is; + BufDataInputStream dis = new BufDataInputStream(bis); + + header = dis.readShort(); + count = dis.readShort(); + + names = new String[count]; + offset = new int[count]; + size = new short[count]; + + entries = new Hashtable(count + count / 2); + + for(int i = 0; i < count; i++) + { + names[i] = dis.readUTF(); + offset[i] = dis.readInt(); // + header; + size[i] = dis.readShort(); + + entries.put(names[i], new Integer(i)); + } + } + + /** + * Создание PAK файла в режиме запиÑи. + * + * @param newcount чиÑло Ñлементов + */ + public PakFile(int newcount) throws IOException + { + closeInput(); + + baos_header = new ByteArrayOutputStream(); + dos_header = new DataOutputStream(baos_header); + baos_files = new ByteArrayOutputStream(); + buf = new byte[AuxClass.COPYBUFSIZE]; + currindex = 0; + curroffset = 0; + + header = 0; + count = (short)newcount; + + dos_header.writeShort(header); + dos_header.writeShort(count); + + names = new String[count]; + offset = new int[count]; + size = new short[count]; + + entries = null; + } + + protected void closeInput() throws IOException + { + if(bis != null) + { + bis.close(); + bis = null; + } + + names = null; + offset = null; + size = null; + entries = null; + } + + protected void closeOutput() throws IOException + { + if(dos_header != null) + { + dos_header.close(); + dos_header = null; + baos_header = null; + } + + if(baos_files != null) + { + baos_files.close(); + baos_files = null; + } + + buf = null; + System.gc(); + } + + public void close() throws IOException + { + closeInput(); + closeOutput(); + } + + public String[] listElements() + { + if(names != null) + { + String[] s = new String[names.length]; + System.arraycopy(names, 0, s, 0, names.length); + + return s; + } + else + { + return null; + } + } + + public InputStream getElementAsStream(String name) throws IOException, IllegalStateException + { + if(bis == null) + { + throw new IllegalStateException("Pak file was not open for reading"); + } + + Integer index = (Integer)entries.get(name); + + if(index == null) + { + throw new IOException("File \"" + name + "\" not found"); + } + + return new PartialInputStream(bis, offset[index.intValue()] + header, size[index.intValue()]); + } + + public short getElementSize(String name) throws IOException, IllegalStateException + { + if(bis == null) + { + throw new IllegalStateException("Pak file was not open for reading"); + } + + Integer index = (Integer)entries.get(name); + + if(index == null) + { + throw new IOException("File \"" + name + "\" not found"); + } + + return size[index.intValue()]; + } + + public void addElement(String name, InputStream is, ProgressCallback callback) throws IOException, IllegalStateException + { + if(baos_header == null || baos_files == null) + { + throw new IllegalStateException("Pak file was not open for writing"); + } + else if(currindex >= count) + { + throw new IllegalStateException("All available elements have been set"); + } + + dos_header.writeUTF(name); + dos_header.writeInt(curroffset); + dos_header.writeShort(is.available()); + + curroffset += is.available(); + currindex++; + + if(callback != null) + { + int buflen; + + while(is.available() > 0) + { + baos_files.write(buf, 0, buflen = is.read(buf)); + callback.progress(buflen); + } + } + else + { + while(is.available() > 0) + { + baos_files.write(buf, 0, is.read(buf)); + } + } + } + + public void write(OutputStream os) throws IOException, IllegalStateException + { + if(baos_header == null || baos_files == null) + { + throw new IllegalStateException("Pak file was not open for writing"); + } + + buf = baos_header.toByteArray(); + + header = (short)buf.length; + buf[0] = (byte)((header >> 8) & 0xFF); + buf[1] = (byte)(header & 0xFF); + + os.write(buf); + os.write(baos_files.toByteArray()); + os.flush(); + } + +// private static void out(String s) +// { +// System.out.println("[PakFile] " + s); +// } +} diff --git a/src/com/one/PartialInputStream.java b/src/com/one/PartialInputStream.java new file mode 100644 index 0000000..56f8014 --- /dev/null +++ b/src/com/one/PartialInputStream.java @@ -0,0 +1,166 @@ +package com.one; + +import java.io.*; + +public class PartialInputStream extends RandomAccessInputStream +{ + protected RandomAccessInputStream is; + protected int currpos, markedpos; + protected int start, end; + + // We may need to supply an extra dummy byte to our reader. + // See Inflater. We use a count here to simplify the logic + // elsewhere in this class. Note that we ignore the dummy + // byte in methods where we know it is not needed. + protected int dummyByteCount; + + public PartialInputStream(RandomAccessInputStream rais, int off, int len) throws IOException + { + is = rais; + + if(off >= 0) + { + start = off; + } + else + { + start = 0; + } + + if(len >= 0) + { + end = start + len; + } + else + { + end = rais.getCapacity(); + } + + currpos = start; + markedpos = currpos; + dummyByteCount = 0; + } + + public void addDummyByte() + { + dummyByteCount = 1; + } + + public int available() + { + return end - currpos; + } + + public void close() + { + } + + public void mark(int readLimit) + { + markedpos = currpos; + } + + public int read() throws IOException + { + if(currpos >= end) + { + if(dummyByteCount > 0) + { + dummyByteCount--; + return 0; + } + else + { + return -1; + } + } + + is.setPosition(currpos++); + + return is.read(); + } + + public int read(byte[] b) throws IOException + { + return read(b, 0, b.length); + } + + public int read(byte[] b, int off, int len) throws IOException + { + int available = available() + dummyByteCount; + + if(available <= 0) + { + return -1; + } + + if(len > available) + { + len = available; + } + + is.setPosition(currpos); + int n = is.read(b, off, len); + + if(n < len && dummyByteCount > 0) + { + dummyByteCount--; + b[off + n] = 0; + } + + currpos += n; + + return n; + } + + public void reset() + { + currpos = markedpos; + } + + public long skip(long n) + { + if(n > available()) + { + n = available(); + } + + currpos += n; + + return n; + } + + public void setPosition(int pos) throws IOException + { + if(pos == currpos) + { + return; + } + + if(pos < start) + { + pos = start; + } + else if(pos > end) + { + pos = end; + } + + currpos = pos; + } + + public int getPosition() + { + return currpos - start; + } + + public int getCapacity() + { + return end - start; + } + + public void update() throws IOException + { + is.update(); + } +} diff --git a/src/com/one/PlainPackage.java b/src/com/one/PlainPackage.java new file mode 100644 index 0000000..e869305 --- /dev/null +++ b/src/com/one/PlainPackage.java @@ -0,0 +1,256 @@ +package com.one; + +import com.vmx.*; +import java.io.*; +import java.util.*; + +public class PlainPackage extends Container +{ + protected void readEntries() throws IOException + { + entries = new Hashtable(); + + BufDataInputStream dis = new BufDataInputStream(rais); + ContainerEntry entry; + + try + { + while(true) + { + entry = new ContainerEntry(); + entry.name = dis.readUTF(); + entry.size = dis.readInt(); + entry.offset = dis.getPosition(); + + if(entry.name.length() > 0 && entry.size >= 0) + { + entries.put(entry.name, entry); + dis.skip(entry.size); + } + else + { + break; + } + + addFile(entry.name); + } + } + catch(EOFException eofe) + { + finished = false; + } + } + + public InputStream getInputStream(ContainerEntry entry) throws IOException + { + if(entry == null) + { + return null; + } + + checkClosed(); + + return new PartialInputStream(rais, entry.offset, entry.size); + } + + public boolean addEntry(RandomAccessInputStream source, String name, long time, boolean replace, ProgressCallback callback) throws IOException + { + if(replace) + { + deleteEntry(getEntry(name)); + } + else + { + checkReadOnly(); + checkEntries(); + + if(entries.containsKey(name)) + { + return false; + } + } + + if(callback != null) + { + callback.setText(Locale.getString(this, Locale.PACKING_FILE, name)); + callback.setProgress(0); + callback.setMax(source.getCapacity()); + } + + ContainerEntry entry = new ContainerEntry(); + entry.name = name; + entry.size = source != null ? source.getCapacity() : 0; + entry.offset = finished ? (int)file.fileSize() - 6 : (int)file.fileSize(); + + DataOutputStream os = new DataOutputStream(file.openOutputStream(entry.offset)); + finished = false; + + os.writeUTF(entry.name); + os.writeInt(entry.size); + + if(source != null) + { + byte[] buf = new byte[AuxClass.COPYBUFSIZE]; + int len; + + if(callback != null) + { + while(source.available() > 0) + { + len = source.read(buf); + os.write(buf, 0, len); + + entry.size += len; + callback.progress(len); + } + } + else + { + while(source.available() > 0) + { + len = source.read(buf); + os.write(buf, 0, len); + + entry.size += len; + } + } + + source.close(); + } + + os.close(); + + entries.put(name, entry); + rais.update(); + + addFile(name); + + return true; + } + + public boolean deleteEntry(ContainerEntry entry) throws IOException + { + if(entry == null) + { + return false; + } + + checkReadOnly(); + checkEntries(); + + if(entry.name.endsWith("/")) + { + if(listFiles(entry.name).hasMoreElements()) + { + return false; + } + else + { + deleteFile(entry.name); + return true; + } + } + + if(!entries.containsKey(entry.name)) + { + return false; + } + + if(!entry.pureVirtual) + { + if(finished) + { + file.truncate(file.fileSize() - 6); + } + + finished = false; + + rais.close(); + + int hdrsize = 2 + StringEncoder.getEncodedLength(entry.getName(), StringEncoder.ENC_UTF8) + 4; + + int delta = AuxClass.updateFileData(file, new byte[0], entry.offset - hdrsize, entry.offset + entry.size); + + rais = new FileInputStream(file); + + updateOffset(entry.offset, delta); + } + + entries.remove(entry.name); + deleteFile(entry.name); + + return true; + } + + public boolean renameEntry(ContainerEntry entry, String newName) throws IOException + { + if(!entry.pureVirtual) + { + checkReadOnly(); + checkEntries(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeUTF(entry.name); + int namelen = baos.size(); + + baos.reset(); + dos.writeUTF(newName); + byte[] b = baos.toByteArray(); + + dos.close(); + + if(finished) + { + file.truncate(file.fileSize() - 6); + } + + finished = false; + rais.close(); + + int delta = AuxClass.updateFileData(file, b, entry.offset, entry.offset + namelen); + + rais = new FileInputStream(file); + + updateOffset(entry.offset, delta); + } + + Directory.renameFile(files, null, entry.name, newName); + entries.remove(entry.name); + entry.name = newName; + entries.put(newName, entry); + + return true; + } + + public void finish() throws IOException + { + if(finished) + { + return; + } + + checkReadOnly(); + + ProgressCallback callback = ProgressBar.getProgressCallback(); + ProgressBar.show(); + + callback.setText(Locale.getString(this, Locale.WRITING_FILE)); + callback.setProgress(0); + callback.setMax(1); + + DataOutputStream dos = new DataOutputStream(file.openOutputStream(file.fileSize())); + + dos.writeUTF(""); + dos.writeInt(-1); + + callback.progress(1); + + dos.close(); + + finished = true; + + ProgressBar.hide(); + } +} diff --git a/src/com/one/PlayList.java b/src/com/one/PlayList.java new file mode 100644 index 0000000..fbd2217 --- /dev/null +++ b/src/com/one/PlayList.java @@ -0,0 +1,253 @@ +package com.one; + +import com.vmx.AuxClass; +import java.util.Enumeration; +import java.util.Vector; + +public class PlayList +{ + protected String[] playlist; + protected int selectedIndexNormal, selectedIndexRandom; + protected int[] randomRemapIndices; + + protected class ArraySearchThread extends ExtThread + { + public String element; + + public void run() + { + for(int i = 0; (i < playlist.length) && running; i++) + { + if(playlist[i].equals(element)) + { + selectedIndexNormal = i; + break; + } + } + + running = false; + rst.start(); + } + }; + + protected class RemapSearchThread extends ExtThread + { + public void run() + { + for(int i = 0; (i < playlist.length) && running; i++) + { + if(randomRemapIndices[i] == selectedIndexNormal) + { + selectedIndexRandom = i; + break; + } + } + + running = false; + } + }; + + protected ArraySearchThread ast = new ArraySearchThread(); + protected RemapSearchThread rst = new RemapSearchThread(); + + public PlayList(Enumeration newlist) + { + Vector v = new Vector(); + + while(newlist.hasMoreElements()) + { + v.addElement(newlist.nextElement()); + } + + playlist = new String[v.size()]; + v.copyInto(playlist); + + randomRemapIndices = AuxClass.randomSequence(0, playlist.length - 1, -1); + + selectedIndexNormal = 0; + rst.start(); + } + + public PlayList(String[] newlist) + { + playlist = newlist; + randomRemapIndices = AuxClass.randomSequence(0, playlist.length - 1, -1); + + selectedIndexNormal = 0; + rst.start(); + } + + public PlayList(String file) + { + playlist = new String[1]; + playlist[0] = file; + selectedIndexNormal = 0; + + randomRemapIndices = new int[1]; + randomRemapIndices[0] = 0; + selectedIndexRandom = 0; + } + + public void selectElement(String element) + { + if(getCurrentElement().equals(element)) + { + return; + } + + ast.element = element; + ast.start(); + } + + public void waitForElementFound() + { + if(ast.isAlive()) + { + try + { + ast.join(); + } + catch(InterruptedException ie) + { + } + } + + if(rst.isAlive()) + { + try + { + rst.join(); + } + catch(InterruptedException ie) + { + } + } + } + + public void cancelSearch() + { + ast.stop(); + rst.stop(); + } + + public void nextElement(boolean shuffle) + { + if(ast.isAlive()) + { + try + { + ast.join(); + } + catch(InterruptedException ie) + { + } + } + + if(shuffle) + { + if(rst.isAlive()) + { + try + { + rst.join(); + } + catch(InterruptedException ie) + { + } + } + + if(++selectedIndexRandom >= playlist.length) + { + selectedIndexRandom = 0; + } + + selectedIndexNormal = randomRemapIndices[selectedIndexRandom]; + } + else + { + if(++selectedIndexNormal >= playlist.length) + { + selectedIndexNormal = 0; + } + + rst.start(); + } + } + + public void prevElement(boolean shuffle) + { + if(ast.isAlive()) + { + try + { + ast.join(); + } + catch(InterruptedException ie) + { + } + } + + if(shuffle) + { + if(rst.isAlive()) + { + try + { + rst.join(); + } + catch(InterruptedException ie) + { + } + } + + if(--selectedIndexRandom < 0) + { + selectedIndexRandom = playlist.length - 1; + } + + selectedIndexNormal = randomRemapIndices[selectedIndexRandom]; + } + else + { + if(--selectedIndexNormal < 0) + { + selectedIndexNormal = playlist.length - 1; + } + + rst.start(); + } + } + + public String getElement(int index) + { + if(index >= 0 && index < playlist.length) + { + return playlist[index]; + } + else + { + return null; + } + } + + public String getCurrentElement() + { + return playlist[getCurrentIndex()]; + } + + public int getCurrentIndex() + { + if(ast.isAlive()) + { + try + { + ast.join(); + } + catch(InterruptedException ie) + { + } + } + + return selectedIndexNormal; + } +} diff --git a/src/com/one/ProgressBar.java b/src/com/one/ProgressBar.java new file mode 100644 index 0000000..69a965b --- /dev/null +++ b/src/com/one/ProgressBar.java @@ -0,0 +1,165 @@ +package com.one; + +import com.vmx.ProgressCallback; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; +import javax.microedition.lcdui.Gauge; +import javax.microedition.lcdui.Item; +import javax.microedition.lcdui.StringItem; + +public class ProgressBar +{ + protected static DisplayManager manager; + + protected static Object displayable; + protected static Object parent; + + protected static class DefaultProgressDisplayable extends Form implements ProgressCallback + { + protected Gauge g; + protected StringItem si; + protected boolean percentmode; + protected boolean cancelflag; + + public DefaultProgressDisplayable() + { + super("Please, wait..."); + + percentmode = true; + + g = new Gauge("0%", false, 1, 0); + g.setLayout(Item.LAYOUT_EXPAND); + + si = new StringItem(null, ""); + si.setLayout(Item.LAYOUT_EXPAND); + + append(g); + append(si); + } + + protected void updateLabel() + { + if(percentmode) + { + g.setLabel(Integer.toString(g.getValue() * 100 / g.getMaxValue()) + "%"); + } + else + { + g.setLabel(Integer.toString(g.getValue()) + " / " + Integer.toString(g.getMaxValue())); + } + } + + public void setMax(int max) + { + g.setMaxValue(max); + updateLabel(); + } + + public void setProgress(int progress) + { + g.setValue(progress); + updateLabel(); + } + + public void rise(int plus) + { + g.setMaxValue(g.getMaxValue() + plus); + updateLabel(); + } + + public void progress(int plus) + { + g.setValue(g.getValue() + plus); + updateLabel(); + } + + public void setText(String text) + { + si.setText(text); + } + + public int getMax() + { + return g.getMaxValue(); + } + + public int getProgress() + { + return g.getValue(); + } + + public String getText() + { + return si.getText(); + } + + public void setPercentMode(boolean mode) + { + percentmode = mode; + } + + public void setCancelFlag(boolean flag) + { + cancelflag = flag; + } + + public boolean getCancelFlag() + { + return cancelflag; + } + } + + public static void setDisplayManager(DisplayManager dsp) + { + manager = dsp; + } + + static + { + setDisplayable(null); + } + + public static void setDisplayable(Object object) + { + if(object != null) + { + if(!(object instanceof Displayable || object instanceof PaintableObject)) + { + throw new IllegalArgumentException("No displayable"); + } + + if(!(object instanceof ProgressCallback)) + { + throw new IllegalArgumentException("No progress callback"); + } + + displayable = object; + } + else + { + displayable = new DefaultProgressDisplayable(); + } + } + + public static ProgressCallback getProgressCallback() + { + return (ProgressCallback)displayable; + } + + public static void show() + { + if(manager != null && manager.getCurrent() != displayable) + { + parent = manager.getCurrent(); + manager.setCurrent(displayable); + } + } + + public static void hide() + { + if(manager != null && manager.getCurrent() == displayable) + { + manager.setCurrent(parent); + } + } +} diff --git a/src/com/one/RTEF.java b/src/com/one/RTEF.java new file mode 100644 index 0000000..a319397 --- /dev/null +++ b/src/com/one/RTEF.java @@ -0,0 +1,109 @@ +package com.one; + +import java.io.*; +import com.vmx.*; + +/** + * Шифратор. + * Ð”Ð»Ñ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸ÑпользуетÑÑ Ð¼ÐµÑ‚Ð¾Ð´ Ð³Ð°Ð¼Ð¼Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ Ð¿ÑевдоÑлучайным ключом. + */ +public class RTEF +{ + protected ExtRandom rnd; + + /** + * Ð¥ÐµÑˆÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñтроки. + * Хеш вычиÑлÑетÑÑ Ð¿Ð¾ алгоритму SHA-1, Ñтрока раÑÑматриваетÑÑ + * как поÑледовательноÑÑ‚ÑŒ Ñимволов в Юникоде. + */ + public static int[] hashString(String s) + { + SHA1 md = new SHA1(); + int len = s.length(); + char c; + + for(int i = 0; i < len; i++) + { + c = s.charAt(i); + + md.update((byte)(c >> 8)); + md.update((byte)c); + } + + return md.digest(); + } + + /** + * Создание шифратора Ñ Ð¿Ð°Ñ€Ð¾Ð»ÐµÐ¼ в виде Ñтроки + */ + public RTEF(String password) + { + int[] hash = hashString(password); + + rnd = new ExtRandom(hash[0] ^ hash[1] ^ hash[2]); + + int offset = (hash[3] ^ hash[4]) & 0xFFFF; + + for(int i = 0; i < offset; i++) + { + rnd.nextInt(); + } + + rnd.mark(); + } + + /** + * Создание шифратора Ñ Ð¿Ð°Ñ€Ð¾Ð»ÐµÐ¼ в виде параметров ГСЧ + */ + public RTEF(long key, int offset) + { + rnd = new ExtRandom(key); + + for(int i = 0; i < offset; i++) + { + rnd.nextInt(); + } + + rnd.mark(); + } + + /** + * Шифрование потока. + * Ð”Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ операции ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸ÑпользуетÑÑ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ð°Ñ Ð³Ð°Ð¼Ð¼Ð°. + */ + public void crypt(InputStream is, OutputStream os, ProgressCallback callback) throws IOException + { + rnd.reset(); + + int k = rnd.nextInt(); + int shift = 0; + + byte[] buf = new byte[AuxClass.COPYBUFSIZE]; + int buflen, i; + + while(is.available() > 0) + { + buflen = is.read(buf); + + for(i = 0; i < buflen; i++) + { + buf[i] ^= (byte)((k >> shift) & 0xFF); + + shift += 8; + + if(shift >= 32) + { + k = rnd.nextInt(); + shift = 0; + } + } + + os.write(buf, 0, buflen); + + if(callback != null) + { + callback.progress(buflen); + } + } + } +} diff --git a/src/com/one/RandomAccessInputStream.java b/src/com/one/RandomAccessInputStream.java new file mode 100644 index 0000000..a76dc1a --- /dev/null +++ b/src/com/one/RandomAccessInputStream.java @@ -0,0 +1,123 @@ +package com.one; + +import java.io.*; + +/** + * Входной поток Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð»ÑŒÐ½Ñ‹Ð¼ доÑтупом. + */ +public abstract class RandomAccessInputStream extends InputStream +{ + /** + * Переход на произвольную позицию + */ + public abstract void setPosition(int pos) throws IOException; + + /** + * Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ð² потоке + */ + public abstract int getPosition() throws IOException; + + /** + * ÐžÐ±Ñ‰Ð°Ñ ÐµÐ¼ÐºÐ¾ÑÑ‚ÑŒ потока + */ + public abstract int getCapacity() throws IOException; + + /** + * Обновление потока + */ + public abstract void update() throws IOException; + + /** + * Mark / Reset поддерживаетÑÑ Ð¿Ð¾ определению + */ + public final boolean markSupported() + { + return true; + } + + /** + * ПоиÑк данных в потоке. + * ЕÑли startIndex >= 0, то поиÑк ведетÑÑ Ñо startIndex, иначе Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ позиции. + * ЕÑли endIndex >= 0, то поиÑк идет макÑимум до endIndex, иначе до конца потока. + * ПоÑле поиÑка поток возвращаетÑÑ Ð½Ð° прежнюю позицию. + */ + public int indexOf(byte[] data, int off, int len, int startIndex, int endIndex) throws IOException + { + int prevpos = getPosition(); + + if(startIndex >= 0) + { + setPosition(startIndex); + } + + int end = off + len; + int index = -1; + int i = off; + + byte b; + + while(available() > 0) + { + b = (byte)read(); + + if(b == data[i]) + { + if(index < 0) + { + index = getPosition() - 1; + } + + if(++i >= end) + { + break; + } + } + else if(b == data[off]) + { + index = getPosition() - 1; + i = off; + } + else + { + index = -1; + i = off; + } + + if(endIndex >= 0 && getPosition() >= endIndex) + { + break; + } + } + + setPosition(prevpos); + + return index; + } + + /** + * Получить чаÑÑ‚ÑŒ некоторого потока + * как отдельный поток. + */ +// public static InputStream getPartialInputStream(RandomAccessInputStream is, int off, int len) throws IOException +// { +// byte[] b; +// +// try +// { +// b = new byte[len]; +// +// int pos = is.tell(); +// +// is.seek(off); +// len = is.read(b, 0, len); +// is.seek(pos); +// } +// catch(OutOfMemoryError oome) +// { +// b = new byte[0]; +// len = 0; +// } +// +// return new ByteArrayInputStream(b, 0, len); +// } +} diff --git a/src/com/one/Renderer.java b/src/com/one/Renderer.java new file mode 100644 index 0000000..fcc75f7 --- /dev/null +++ b/src/com/one/Renderer.java @@ -0,0 +1,148 @@ +package com.one; + +import javax.microedition.lcdui.*; + +public class Renderer extends Canvas +{ + protected PaintableObject current; + protected boolean shown, fsmode; + + protected static Display vibraDisplay; + protected static int vibraDuration; + + public Renderer() + { + setFullScreenMode(fsmode = true); + shown = false; + + current = new PaintableObject() + { + public void paint(Graphics g) + { + } + }; + } + + public void setCurrent(PaintableObject po) + { + if(shown) + { + current.hideNotify(); + po.showNotify(); + } + + current = po; + + repaint(); + serviceRepaints(); + } + + public PaintableObject getCurrent() + { + return current; + } + + public void repaint(PaintableObject po) + { + if(current == po) + { + repaint(); + } + } + + public void repaint(PaintableObject po, int x, int y, int width, int height) + { + if(current == po) + { + repaint(x, y, width, height); + } + } + + public void serviceRepaints(PaintableObject po) + { + if(current == po) + { + serviceRepaints(); + } + } + + public void setFullScreenMode(PaintableObject po, boolean mode) + { + setFullScreenMode(fsmode = mode); + } + + public void paint(Graphics g) + { + current.paint(g); + } + + public void showNotify() + { + setFullScreenMode(fsmode); + + current.showNotify(); + shown = true; + } + + public void hideNotify() + { + current.hideNotify(); + shown = false; + } + + public boolean isShown() + { + return shown; + } + + public void keyPressed(int keyCode) + { + vibrate(); + current.keyPressed(keyCode); + } + + public void keyRepeated(int keyCode) + { + vibrate(); + current.keyRepeated(keyCode); + } + + public void keyReleased(int keyCode) + { + current.keyReleased(keyCode); + } + + public void pointerPressed(int x, int y) + { + vibrate(); + current.pointerPressed(x, y); + } + + public void pointerDragged(int x, int y) + { + current.pointerDragged(x, y); + } + + public void pointerReleased(int x, int y) + { + current.pointerReleased(x, y); + } + + public static void setVibraDisplay(Display d) + { + vibraDisplay = d; + } + + public static void setVibraDuration(int value) + { + vibraDuration = value; + } + + public static void vibrate() + { + if(vibraDisplay != null && vibraDuration > 0) + { + vibraDisplay.vibrate(vibraDuration); + } + } +} diff --git a/src/com/one/ReplaceableInputStream.java b/src/com/one/ReplaceableInputStream.java new file mode 100644 index 0000000..cbecc62 --- /dev/null +++ b/src/com/one/ReplaceableInputStream.java @@ -0,0 +1,339 @@ +package com.one; + +import java.io.*; +import java.util.Vector; + +/** + * Поток Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñтью замены произвольного учаÑтка. + */ +public class ReplaceableInputStream extends RandomAccessInputStream +{ + protected RandomAccessInputStream is; + protected int currpos, markedpos; + + protected int repstart; // начало заменÑемого фрагмента + protected int repend; // конец заменÑемого фрагмента + protected int replen; // длина заменÑющего фрагмента + protected int delta; // изменение размера потока + protected int repbufend; // позициÑ, на которой заканчиваетÑÑ Ð·Ð°Ð¼ÐµÐ½Ð° + + protected byte[] repbuf; + + public ReplaceableInputStream(RandomAccessInputStream is) + { + this.is = is; + + markedpos = currpos = 0; + + removeReplace(); + } + + /** + * Сложить в вектор цепочку из потоков замены. + * ПредполагаетÑÑ, что в цепочке еÑÑ‚ÑŒ один базовый поток + * и пучок вложенных RIS'ов. + * + * @param v вектор, в котором будет Ñобрана цепочка + */ + public void traverseReplaceChain(Vector v) + { + if(is instanceof ReplaceableInputStream) + { + ((ReplaceableInputStream)is).traverseReplaceChain(v); + } + + v.addElement(this); + } + + /** + * Получить базовый Ð´Ð»Ñ Ð²Ñей цепочки RIS'ов поток. + * @return поток, на котором оÑнован первый RIS в цепочке + */ + public InputStream getBaseStream() + { + if(is instanceof ReplaceableInputStream) + { + return ((ReplaceableInputStream)is).getBaseStream(); + } + + return is; + } + + /** + * УÑтановка замены. + * Данные в потоке Ñо Start Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¿Ð¾ End не Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ + * заменÑетÑÑ Ð½Ð° данные из маÑÑива B. + * Размер замещающего маÑÑива может не Ñовпадать + * Ñ Ñ€Ð°Ð·Ð¼ÐµÑ€Ð¾Ð¼ замещаемого учаÑтка, в Ñтом Ñлучае + * ÑоответÑтвенно изменÑетÑÑ Ñ€Ð°Ð·Ð¼ÐµÑ€ вÑего потока. + * + * @param b замещающий маÑÑив + * @param start начало замещаемого учаÑтка + * @param end конец замещаемого учаÑтка + */ + public void setReplace(byte[] b, int start, int end) + { + repbuf = b; + + repstart = start; + repend = end; + replen = repbuf.length; + + repbufend = repstart + replen; + delta = replen - repend + repstart; + } + + /** + * Отмена замены. + */ + public void removeReplace() + { + repbuf = null; + System.gc(); + + repstart = repend = replen = repbufend = -1; + delta = 0; + } + + /** + * Сколько операций запиÑи потребуетÑÑ Ð¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÑти, + * чтобы Ñохранить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² файл. + * УчитываетÑÑ ÐºÐ°Ðº размер Ñамой замены, так и операции + * по перемещению хвоÑта файла поÑле замены. + */ + public int getWriteCount() throws IOException + { + int res; + + if(is instanceof ReplaceableInputStream) + { + res = ((ReplaceableInputStream)is).getWriteCount(); + } + else + { + res = 0; + } + + if(delta > 0) + { + res += delta + (is.getCapacity() - repend) + replen; + } + else if(delta < 0) + { + res += (is.getCapacity() - repend) + replen; + } + else + { + res += replen; + } + + return res; + } + + public byte[] getReplace() + { + return repbuf; + } + + public int getReplaceStart() + { + return repstart; + } + + public int getReplaceEnd() + { + return repend; + } + + public boolean isReplaceSet() + { + return replen >= 0; + } + + public int available() throws IOException + { + return getCapacity() - currpos; + } + + /** + * ОÑвобожение реÑурÑов, иÑпользуемых Ñтим потоком. + * Базовый поток не закрываетÑÑ Ð´Ð»Ñ Ð´Ð°Ð»ÑŒÐ½ÐµÐ¹ÑˆÐµÐ³Ð¾ иÑпользованиÑ. + */ + public void close() + { + removeReplace(); + } + + public void mark(int readLimit) + { + markedpos = currpos; + } + + public int read() throws IOException + { + if(replen < 0 || currpos < repstart) + { + is.setPosition(currpos); + currpos++; + + return is.read(); + } + else if(currpos < repbufend) + { + return ((int)repbuf[currpos++ - repstart]) & 0xFF; + } + else + { + is.setPosition(currpos - delta); + currpos++; + + return is.read(); + } + } + + public int read(byte[] b) throws IOException + { + return read(b, 0, b.length); + } + + public int read(byte[] b, int off, int len) throws IOException + { + int read = 0; + + if(replen < 0) + { + is.setPosition(currpos); + + read = is.read(b, off, len); + + currpos += read; + + return read; + } + + int available = available(); + + if(available <= 0) + { + return -1; + } + + if(len > available) + { + len = available; + } + + int temp; + + while(len > 0) + { + if(currpos < repstart) + { + is.setPosition(currpos); + + temp = repstart - currpos; + + if(temp > len) + { + temp = len; + } + + temp = is.read(b, off, temp); + + currpos += temp; + read += temp; + off += temp; + len -= temp; + } + else if(currpos < repbufend) + { + temp = repbufend - currpos; + + if(temp > len) + { + temp = len; + } + + System.arraycopy(repbuf, currpos - repstart, b, off, temp); + + currpos += temp; + read += temp; + off += temp; + len -= temp; + } + else + { + is.setPosition(currpos - delta); + + temp = is.read(b, off, len); + + currpos += temp; + read += temp; + off += temp; + len -= temp; + } + } + + return read; + } + + public void reset() + { + currpos = markedpos; + } + + public long skip(long n) throws IOException + { + if(n > available()) + { + n = available(); + } + + currpos += n; + + return n; + } + + public void setPosition(int pos) throws IOException + { + if(pos == currpos) + { + return; + } + + if(pos < 0) + { + pos = 0; + } + else if(pos > getCapacity()) + { + pos = getCapacity(); + } + + currpos = pos; + } + + public int getPosition() + { + return currpos; + } + + /** + * Получение емкоÑти потока. + * Возвращаемое значение может изменÑÑ‚ÑŒÑÑ Ð¿Ñ€Ð¸ уÑтановке замены. + */ + public int getCapacity() throws IOException + { + return is.getCapacity() + delta; + } + + public void update() throws IOException + { + is.update(); + } + +// private static void out(String s) +// { +// System.out.println("[ReplaceableInputStream] " + s); +// } +} diff --git a/src/com/one/RootLoader.java b/src/com/one/RootLoader.java new file mode 100644 index 0000000..f69e852 --- /dev/null +++ b/src/com/one/RootLoader.java @@ -0,0 +1,25 @@ +package com.one; + +import com.one.file.ConnectionProvider; +import javax.microedition.io.ConnectionNotFoundException; +import javax.microedition.lcdui.Display; +import javax.microedition.midlet.MIDletStateChangeException; + +public interface RootLoader +{ + public void startApp() throws MIDletStateChangeException; + public void pauseApp(); + public void destroyApp(boolean unconditional) throws MIDletStateChangeException; + public void restartApp(); + + public void notifyPaused(); + public void notifyDestroyed(); + + public boolean platformRequest(String url) throws ConnectionNotFoundException; + + public Display getDisplay(); + public String getAppProperty(String key); + public Accelerometer getAccelerometer(); + public ConnectionProvider getConnectionProvider(); + public boolean useNoEffects(); +} diff --git a/src/com/one/SHA1.java b/src/com/one/SHA1.java new file mode 100644 index 0000000..9331570 --- /dev/null +++ b/src/com/one/SHA1.java @@ -0,0 +1,206 @@ +package com.one; + +public class SHA1 +{ + private static final int BLOCK_SIZE = 64; + + private long count; + private byte[] buffer; + private int[] w = new int[80]; + + /** 160-bit interim result. */ + private int h0, h1, h2, h3, h4; + + public SHA1() + { + buffer = new byte[BLOCK_SIZE]; + resetContext(); + } + + public void update(byte b) + { + // compute number of bytes still unhashed; ie. present in buffer + + int i = (int)(count % BLOCK_SIZE); + count++; + buffer[i] = b; + + if(i == (BLOCK_SIZE - 1)) + { + transform(buffer, 0); + } + } + + public void update(byte[] b) + { + update(b, 0, b.length); + } + + public void update(byte[] b, int offset, int len) + { + int n = (int)(count % BLOCK_SIZE); + count += len; + int partLen = BLOCK_SIZE - n; + int i = 0; + + if(len >= partLen) + { + System.arraycopy(b, offset, buffer, n, partLen); + transform(buffer, 0); + + for(i = partLen; i + BLOCK_SIZE - 1 < len; i += BLOCK_SIZE) + { + transform(b, offset + i); + } + + n = 0; + } + + if(i < len) + { + System.arraycopy(b, offset + i, buffer, n, len - i); + } + } + + /** + * Constructs the result from the contents of the current context. + * + * @return the output of the completed hash operation. + */ + public int[] digest() + { + byte[] tail = padBuffer(); // pad remaining bytes in buffer + update(tail, 0, tail.length); // last transform of a message + + int[] result = new int[] {h0, h1, h2, h3, h4}; // make a result out of context + + reset(); // reset this instance for future re-use + + return result; + } + + public void reset() + { + count = 0L; + + for(int i = 0; i < BLOCK_SIZE; buffer[i++] = 0); + + resetContext(); + } + + + /** + * Returns the byte array to use as padding before completing a hash + * operation. + * + * @return the bytes to pad the remaining bytes in the buffer before + * completing a hash operation. + */ + private byte[] padBuffer() + { + int n = (int)(count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] result = new byte[padding+8]; + + // padding is always binary 1 followed by binary 0s + result[0] = (byte)0x80; + + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + + result[padding++] = (byte)(bits >>> 56); + result[padding++] = (byte)(bits >>> 48); + result[padding++] = (byte)(bits >>> 40); + result[padding++] = (byte)(bits >>> 32); + result[padding++] = (byte)(bits >>> 24); + result[padding++] = (byte)(bits >>> 16); + result[padding++] = (byte)(bits >>> 8); + result[padding] = (byte)bits; + + return result; + } + + /** Resets the instance for future re-use. */ + private void resetContext() + { + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + h4 = 0xC3D2E1F0; + } + + /** + * The block digest transformation per se. + * + * @param in the blockSize long block, as an array of bytes to digest. + * @param offset the index where the data to digest is located within the + * input buffer. + */ + private void transform(byte[] in, int offset) + { + int A = h0; + int B = h1; + int C = h2; + int D = h3; + int E = h4; + int r, T; + + for(r = 0; r < 16; r++) + { + w[r] = in[offset++] << 24 | (in[offset++] & 0xFF) << 16 | (in[offset++] & 0xFF) << 8 | (in[offset++] & 0xFF); + } + + for(r = 16; r < 80; r++) + { + T = w[r - 3] ^ w[r - 8] ^ w[r - 14] ^ w[r - 16]; + w[r] = T << 1 | T >>> 31; + } + + for(r = 0; r < 20; r++) // rounds 0-19 + { + T = (A << 5 | A >>> 27) + ((B & C) | (~B & D)) + E + w[r] + 0x5A827999; + E = D; + D = C; + C = B << 30 | B >>> 2; + B = A; + A = T; + } + + for(r = 20; r < 40; r++) // rounds 20-39 + { + T = (A << 5 | A >>> 27) + (B ^ C ^ D) + E + w[r] + 0x6ED9EBA1; + E = D; + D = C; + C = B << 30 | B >>> 2; + B = A; + A = T; + } + + for(r = 40; r < 60; r++) // rounds 40-59 + { + T = (A << 5 | A >>> 27) + (B & C | B & D | C & D) + E + w[r] + 0x8F1BBCDC; + E = D; + D = C; + C = B << 30 | B >>> 2; + B = A; + A = T; + } + + for(r = 60; r < 80; r++) // rounds 60-79 + { + T = (A << 5 | A >>> 27) + (B ^ C ^ D) + E + w[r] + 0xCA62C1D6; + E = D; + D = C; + C = B << 30 | B >>> 2; + B = A; + A = T; + } + + h0 += A; + h1 += B; + h2 += C; + h3 += D; + h4 += E; + } +} diff --git a/src/com/one/SlidingNumber.java b/src/com/one/SlidingNumber.java new file mode 100644 index 0000000..0919497 --- /dev/null +++ b/src/com/one/SlidingNumber.java @@ -0,0 +1,79 @@ +package com.one; + +import java.util.Random; + +public class SlidingNumber +{ + protected static final int FP_SHIFT = 16; + protected static Random rnd = new Random(); + + protected int current, target, delta; + protected int minvalue, maxvalue; + protected int mindelta, maxdelta; + + public SlidingNumber(int minvalue, int maxvalue, int minsteps, int maxsteps) + { + this.minvalue = minvalue; + this.maxvalue = maxvalue; + + mindelta = ((maxvalue - minvalue) << FP_SHIFT) / maxsteps; + maxdelta = ((maxvalue - minvalue) << FP_SHIFT) / minsteps; + + current = (minvalue + (rnd.nextInt() & 0x7FFFFFFF) % (maxvalue - minvalue + 1)) << FP_SHIFT; + updateCourse(); + } + + public SlidingNumber(int minvalue, int maxvalue, int value, int minsteps, int maxsteps) + { + this.minvalue = minvalue; + this.maxvalue = maxvalue; + + mindelta = ((maxvalue - minvalue) << FP_SHIFT) / maxsteps; + maxdelta = ((maxvalue - minvalue) << FP_SHIFT) / minsteps; + + setValue(value); + } + + public void setValue(int value) + { + if(value < minvalue) + { + value = minvalue; + } + else if(value > maxvalue) + { + value = maxvalue; + } + + current = value << FP_SHIFT; + updateCourse(); + } + + public int nextValue() + { + current += delta; + + if(delta > 0) + { + if(current >= target) + { + updateCourse(); + } + } + else if(delta < 0) + { + if(current <= target) + { + updateCourse(); + } + } + + return current >>> FP_SHIFT; + } + + protected void updateCourse() + { + target = (minvalue + (rnd.nextInt() & 0x7FFFFFFF) % (maxvalue - minvalue + 1)) << FP_SHIFT; + delta = (target < current ? -1 : 1) * (mindelta + (rnd.nextInt() & 0x7FFFFFFF) % (maxdelta - mindelta + 1)); + } +} diff --git a/src/com/one/StackOverflowException.java b/src/com/one/StackOverflowException.java new file mode 100644 index 0000000..c18f787 --- /dev/null +++ b/src/com/one/StackOverflowException.java @@ -0,0 +1,13 @@ +package com.one; + +public class StackOverflowException extends RuntimeException +{ + public StackOverflowException() + { + } + + public StackOverflowException(String msg) + { + super(msg); + } +} diff --git a/src/com/one/StringPattern.java b/src/com/one/StringPattern.java new file mode 100644 index 0000000..410af8b --- /dev/null +++ b/src/com/one/StringPattern.java @@ -0,0 +1,183 @@ +package com.one; + +import java.util.Vector; +import java.util.Enumeration; + +/** + * КлаÑÑ Ð´Ð»Ñ ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ñтрок на ÑоответÑтвие шаблону. + * + * Ð’ шаблонах возможно иÑпользование ÑпецÑимволов: + * '*' - заменÑет ноль или более любых Ñимволов, + * ';' - Ñлужит Ð´Ð»Ñ Ñ€Ð°Ð·Ð´ÐµÐ»ÐµÐ½Ð¸Ñ Ð½ÐµÑкольких шаблонов. + * + * @author SilentKnight + */ +public class StringPattern +{ + public static final char WILDCARD = '*'; + public static final char SEPARATOR = ';'; + + protected String[] prefix; + protected String[] suffix; + protected Vector[] middle; + protected boolean ignorecase; + protected int count; + + /** + * Создать Ñтроковый шаблон. + * + * @param pattern ÑобÑтвенно Ñпецификатор шаблона + * @param ignorecase true, еÑли не нужно учитывать региÑÑ‚Ñ€ при Ñравнении + */ + public StringPattern(String pattern, boolean ignorecase) + { + this.ignorecase = ignorecase; + + if(ignorecase) + { + pattern = pattern.toLowerCase(); + } + + Vector patterns = tokenizeString(pattern, SEPARATOR); + count = patterns.size(); + + prefix = new String[count]; + suffix = new String[count]; + middle = new Vector[count]; + + for(int i = 0; i < count; i++) + { + pattern = (String)patterns.elementAt(i); + + int index = pattern.indexOf(WILDCARD); + + if(index < 0) + { + prefix[i] = pattern; + pattern = ""; + } + else + { + prefix[i] = pattern.substring(0, index); + pattern = pattern.substring(index + 1); + } + + index = pattern.lastIndexOf(WILDCARD); + + if(index < 0) + { + suffix[i] = pattern; + pattern = ""; + } + else + { + suffix[i] = pattern.substring(index + 1, pattern.length()); + pattern = pattern.substring(0, index); + } + + middle[i] = tokenizeString(pattern, WILDCARD); + } + } + + /** + * Проверить Ñтроку на ÑоотвеÑтвие шаблону. + * + * ЕÑли шаблон ÑоÑтоит из неÑкольких чаÑтей (разделенных ';'), то Ñтрока + * проходит проверку, еÑли она ÑоответÑтвует Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ одной чаÑти. + * + * @param str проверÑÐµÐ¼Ð°Ñ Ñтрока + * @return true, еÑти Ñтрока ÑоответÑтвует шаблону или его чаÑти + */ + public boolean matchesWith(String str) + { + if(ignorecase) + { + str = str.toLowerCase(); + } + + for(int i = 0; i < count; i++) + { + boolean flag = str.startsWith(prefix[i]); + + if(flag) + { + str = str.substring(prefix[i].length()); + + if(str.length() > 0) + { + flag = str.endsWith(suffix[i]); + + if(flag) + { + str = str.substring(0, str.length() - suffix[i].length()); + + Enumeration mid = middle[i].elements(); + String cmp; + int index; + + while(str.length() > 0 && mid.hasMoreElements()) + { + cmp = (String)mid.nextElement(); + index = str.indexOf(cmp); + + if(index >= 0) + { + str = str.substring(index + cmp.length()); + } + else + { + flag = false; + break; + } + } + } + } + } + + if(flag) + { + return true; + } + } + + return false; + } + + /** + * Разбить Ñтроку на подÑтроки. + * + * ÐеÑколько поÑледовательных разделителей ÑчитаютÑÑ Ð·Ð° один. + * Ð’ результат Ñ€Ð°Ð·Ð±Ð¸ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð´ÐµÐ»Ð¸Ñ‚ÐµÐ»Ð¸ не включаюÑÑ. + * + * @param str разделÑÐµÐ¼Ð°Ñ Ñтрока + * @param sep Ñимвол-разделитель + * @return вектор Ñ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ð°Ð¼Ð¸ Ñ€Ð°Ð·Ð±Ð¸ÐµÐ½Ð¸Ñ + */ + public static Vector tokenizeString(String str, char sep) + { + Vector res = new Vector(); + int index; + + while(str.length() > 0) + { + index = str.indexOf(sep); + + if(index > 0) + { + res.addElement(str.substring(0, index)); + str = str.substring(index + 1); + } + else if(index == 0) + { + str = str.substring(1); + } + else + { + res.addElement(str); + break; + } + } + + return res; + } +} diff --git a/src/com/one/TestCanvas.java b/src/com/one/TestCanvas.java new file mode 100644 index 0000000..aedeebf --- /dev/null +++ b/src/com/one/TestCanvas.java @@ -0,0 +1,83 @@ +package com.one; + +import javax.microedition.lcdui.*; + +/** + * Служебный клаÑÑ. + */ +public class TestCanvas extends PaintableObject implements Runnable +{ + protected String key, fps; + protected Font font; + protected int x, y; + protected boolean flag; + protected long time, prevtime, delta; + protected int framecount; + + public TestCanvas() + { + setFullScreenMode(true); + + font = Font.getDefaultFont(); + + key = "0"; + fps = "0 FPS"; + + x = getWidth() / 2; + y = (getHeight() - font.getHeight()) / 2; + } + + public void keyPressed(int keyCode) + { + key = Integer.toString(keyCode); // + " (" + getKeyName(keyCode) + ")"; + + repaint(); + serviceRepaints(); + } + + public void showNotify() + { + flag = true; + (new Thread(this, "TestCanvas/Repaint")).start(); + } + + public void hideNotify() + { + flag = false; + } + + public void paint(Graphics g) + { + g.setColor(0x008080); + g.fillRect(0, 0, getWidth(), getHeight()); + + g.setColor(0xE0E0E0); + g.setFont(font); + + g.drawString(key, 0, 0, Graphics.LEFT | Graphics.TOP); + g.drawString(fps, getWidth(), 0, Graphics.RIGHT | Graphics.TOP); + g.drawString(Long.toString(time, 10).toUpperCase(), x, y, Graphics.HCENTER | Graphics.TOP); + + time = System.currentTimeMillis(); + delta = time - prevtime; + framecount++; + + if(delta >= 1000) + { + fps = Long.toString(framecount * 1000 / delta, 10).toUpperCase() + " FPS"; + prevtime = time; + framecount = 0; + } + } + + public void run() + { + while(flag) + { + repaint(); + serviceRepaints(); + + Thread.yield(); + } + } +} diff --git a/src/com/one/TextProcessor.java b/src/com/one/TextProcessor.java new file mode 100644 index 0000000..7a04b8b --- /dev/null +++ b/src/com/one/TextProcessor.java @@ -0,0 +1,340 @@ +package com.one; + +import com.vmx.Locale; +import com.vmx.StringEncoder; +import java.util.Enumeration; +import java.util.Vector; + +/** + * КлаÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ текÑта + */ +public class TextProcessor +{ + /** + * Замена в Ñтроке хитрых Ñимволов Ñкранированными. + * + * Символы вроде CR, LF и TAB заменÑÑŽÑ‚ÑÑ Ð±ÑƒÐºÐ²ÐµÐ½Ð½Ñ‹Ð¼Ð¸ ÑочетаниÑми, + * вÑе оÑтальные Ñимволы до пробела - октальными. + * Также заменÑÑŽÑ‚ÑÑ Ð¾ÐºÑ‚Ð°Ð»ÑŒÐ½Ñ‹Ð¼Ð¸ или юникодовыми ÑочетаниÑми + * вÑе Ñимволы, которые не входÑÑ‚ в указанную кодировку. + */ + public static String escapeString(String text, int enc) + { + StringBuffer res = new StringBuffer(text.length()); + char[] src = text.toCharArray(); + int index; + char c; + + if(enc >= 0) + { + for(int i = 0; i < src.length; i++) + { + c = src[i]; + index = "\b\f\n\r\t\\".indexOf(c); + + if(index >= 0) + { + res.append('\\'); + res.append("bfnrt\\".charAt(index)); + } + else if(c < 8) + { + res.append('\\'); + res.append('0'); + res.append('0'); + res.append(Integer.toOctalString(c)); + } + else if(c < 32) + { + res.append('\\'); + res.append('0'); + res.append(Integer.toOctalString(c)); + } + else if(c >= 128 && StringEncoder.decodeChar(StringEncoder.encodeChar(c, enc), enc) != c) + { + if(c < 256) + { + res.append('\\'); + res.append(Integer.toOctalString(c)); + } + else if(c < 4096) + { + res.append('\\'); + res.append('u'); + res.append('0'); + res.append(Integer.toHexString(c).toUpperCase()); + } + else + { + res.append('\\'); + res.append('u'); + res.append(Integer.toHexString(c).toUpperCase()); + } + } + else + { + res.append(c); + } + } + } + else + { + for(int i = 0; i < src.length; i++) + { + c = src[i]; + index = "\b\f\n\r\t\\".indexOf(c); + + if(index >= 0) + { + res.append('\\'); + res.append("bfnrt\\".charAt(index)); + } + else if(c < 8) + { + res.append('\\'); + res.append('0'); + res.append('0'); + res.append(Integer.toOctalString(c)); + } + else if(c < 32) + { + res.append('\\'); + res.append('0'); + res.append(Integer.toOctalString(c)); + } + else + { + res.append(c); + } + } + } + + return res.toString(); + } + + /** + * Замена в Ñтроке Ñкранированных Ñимволов их значениÑми. + * + * РаÑпознаютÑÑ ÐºÐ°Ðº буквенные ÑÐ¾Ñ‡ÐµÑ‚Ð°Ð½Ð¸Ñ Ð²Ñ€Ð¾Ð´Ðµ CR, LF и TAB, + * так и октальные и юникодовые. + */ + public static String unescapeString(String text) + { + StringBuffer res = new StringBuffer(text.length()); + int index, subindex, rc; + char c; + + while(text.length() > 0) + { + index = text.indexOf('\\'); + + if(index >= 0) + { + res.append(text.substring(0, index)); + + c = Character.toLowerCase(text.charAt(++index)); + subindex = "bfnrt\\".indexOf(c); + + if(subindex >= 0) + { + res.append("\b\f\n\r\t\\".charAt(subindex)); + text = text.substring(index + 1); + } + else if(c == 'u') + { + index++; + rc = 0; + + for(int i = 0; i < 4 && index < text.length(); i++) + { + subindex = "0123456789ABCDEF".indexOf(Character.toUpperCase(text.charAt(index++))); + + if(subindex >= 0) + { + rc = (rc << 4) | subindex; + } + else + { + break; + } + } + + res.append((char)rc); + text = text.substring(index); + } + else + { + rc = 0; + + for(int i = 0; i < 3 && index < text.length(); i++) + { + subindex = "01234567".indexOf(text.charAt(index++)); + + if(subindex >= 0) + { + rc = (rc << 3) | subindex; + } + else + { + break; + } + } + + res.append((char)rc); + text = text.substring(index); + } + } + else + { + res.append(text); + break; + } + } + + return res.toString(); + } + + /** + * Чередует Ñимволы из первой Ñтроки Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð¹ Ñтрокой. + */ + public static String interlaceString(String text, String filler) + { + StringBuffer res = new StringBuffer(text.length() + filler.length() * (text.length() - 1)); + char[] cs = text.toCharArray(); + + res.append(cs[0]); + + for(int i = 1; i < cs.length; i++) + { + res.append(filler); + res.append(cs[i]); + } + + return res.toString(); + } + + /** + * Преобразовать маÑÑив байт в Ñтроку Ñимволов, + * ÑоответÑтвующих Ñтим байтам. + */ + public static String byteArrayToString(byte[] b) + { + char[] cs = new char[b.length]; + + for(int i = 0; i < b.length; i++) + { + cs[i] = (char)((int)b[i] & 0xFF); + } + + return new String(cs); + } + + /** + * Убрать из Ñтроки вÑе упавлÑющие Ñимволы. + */ + public static String removeControlChars(String text) + { + StringBuffer res = new StringBuffer(text.length()); + + char[] cs = text.toCharArray(); + + for(int i = 0; i < cs.length; i++) + { + if(cs[i] >= ' ') + { + res.append(cs[i]); + } + } + + return res.toString(); + } + + /** + * Преобразовать вектор в маÑÑив Ñтрочек. + * + * @param vector вектор Ñо Ñтрочками + * @return маÑÑив Ñтрочек + */ + public static String[] vectorToStringArray(Vector vector) + { + String[] res = new String[vector.size()]; + vector.copyInto(res); + + return res; + } + + /** + * Преобразовать перечиÑление в маÑÑив Ñрочек. + * + * @param enumeration перечиÑлени Ñтрочек + * @return маÑÑив Ñтрочек + */ + public static String[] enumerationToStringArray(Enumeration enumeration) + { + Vector vector = new Vector(); + + while(enumeration.hasMoreElements()) + { + vector.addElement(enumeration.nextElement()); + } + + String[] res = new String[vector.size()]; + vector.copyInto(res); + + return res; + } + + /** + * Замемена текÑта в Ñтроке. + * + * @param text иÑÑ…Ð¾Ð´Ð½Ð°Ñ Ñтрока + * @param replaceWhat что заменÑÑ‚ÑŒ + * @param replaceWith чем заменÑÑ‚ÑŒ + * @return Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ð°Ñ Ñтрока + */ + public static String replaceText(String text, String replaceWhat, String replaceWith) + { + if(replaceWhat.equals(replaceWith)) + { + return text; + } + + int replen = replaceWhat.length(); + int index; + + while(true) + { + index = text.indexOf(replaceWhat); + + if(index >= 0) + { + text = text.substring(0, index) + replaceWith + text.substring(index + replen); + } + else + { + break; + } + } + + return text; + } + + public static String getString(Object object, String text) + { + if(text.startsWith("#")) + { + try + { + return Locale.getString(object, Integer.parseInt(text.substring(1).trim())); + } + catch(NumberFormatException nfe) + { + return text; + } + } + else + { + return text; + } + } +} diff --git a/src/com/one/VolumeUnit.java b/src/com/one/VolumeUnit.java new file mode 100644 index 0000000..f2f4d42 --- /dev/null +++ b/src/com/one/VolumeUnit.java @@ -0,0 +1,107 @@ +package com.one; + +import java.util.Random; + +/** + * Значение Vu - индикатора. + */ +public class VolumeUnit +{ + protected static final int FP_SHIFT = 16; + protected static Random rnd = new Random(); + + protected int minvalue, maxvalue; + protected int current, target, updatetarget; + protected int filldelta, reldelta; + protected boolean dirflag; + protected int fillfactor, relfactor; + + public VolumeUnit(int minvalue, int maxvalue, int fillsteps, int relsteps, int fillfactor, int relfactor) + { + this.minvalue = minvalue << FP_SHIFT; + this.maxvalue = maxvalue << FP_SHIFT; + + this.fillfactor = fillfactor; + this.relfactor = relfactor; + + filldelta = ((maxvalue - minvalue) << FP_SHIFT) / fillsteps; + reldelta = ((maxvalue - minvalue) << FP_SHIFT) / relsteps; + + setTarget(0); + } + + public void setTarget(int value) + { + target = value << FP_SHIFT; + + if(target < minvalue) + { + target = minvalue; + } + else if(target > maxvalue) + { + target = maxvalue; + } + + updatetarget = target; + dirflag = target >= current; + } + + public void setValue(int value) + { + current = value << FP_SHIFT; + + if(current < minvalue) + { + current = minvalue; + } + else if(current > maxvalue) + { + current = maxvalue; + } + + setTarget(value); + } + + public int nextValue(boolean update) + { + if(update) + { + if(dirflag ? current >= updatetarget : current <= updatetarget) + { + target = minvalue + (rnd.nextInt() & 0x7FFFFFFF) % (maxvalue - minvalue + 1); + dirflag = target >= current; + + if(dirflag) + { + updatetarget = current + (rnd.nextInt() & 0x7FFFFFFF) % ((target - current) / fillfactor + 1); + } + else + { + updatetarget = current - (rnd.nextInt() & 0x7FFFFFFF) % ((current - target) / relfactor + 1); + } + } + } + + if(current < target) + { + current += filldelta; + + if(current > target) + { + current = target; + } + } + else if(current > target) + { + current -= reldelta; + + if(current < target) + { + current = target; + } + } + + return current >>> FP_SHIFT; + } +} diff --git a/src/com/one/file/AFCInputStream.java b/src/com/one/file/AFCInputStream.java new file mode 100644 index 0000000..4420d47 --- /dev/null +++ b/src/com/one/file/AFCInputStream.java @@ -0,0 +1,66 @@ +package com.one.file; + +import java.io.IOException; +import java.io.InputStream; + +/** + * InputStream, оÑнованный на FileConnection. + * При закрытии автоматичеÑки закрывает базовый файл. + */ +public class AFCInputStream extends InputStream +{ + protected FileConnection fc; + protected InputStream is; + + public AFCInputStream(FileConnection fc) throws IOException + { + this.fc = fc; + is = fc.openInputStream(); + } + + public int available() throws IOException + { + return is.available(); + } + + public void close() throws IOException + { + is.close(); + fc.close(); + } + + public void mark(int readLimit) + { + is.mark(readLimit); + } + + public boolean markSuported() + { + return is.markSupported(); + } + + public int read() throws IOException + { + return is.read(); + } + + public int read(byte[] b) throws IOException + { + return is.read(b); + } + + public int read(byte[] b, int off, int len) throws IOException + { + return is.read(b, off, len); + } + + public void reset() throws IOException + { + is.reset(); + } + + public long skip(long n) throws IOException + { + return is.skip(n); + } +} diff --git a/src/com/one/file/AFCOutputStream.java b/src/com/one/file/AFCOutputStream.java new file mode 100644 index 0000000..c9a6a3f --- /dev/null +++ b/src/com/one/file/AFCOutputStream.java @@ -0,0 +1,46 @@ +package com.one.file; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * OutputStream, оÑнованный на FileConnection. + * При закрытии автоматичеÑки закрывает базовый файл. + */ +public class AFCOutputStream extends OutputStream +{ + protected FileConnection fc; + protected OutputStream os; + + public AFCOutputStream(FileConnection fc) throws IOException + { + this.fc = fc; + os = fc.openOutputStream(); + } + + public void close() throws IOException + { + os.close(); + fc.close(); + } + + public void flush() throws IOException + { + os.flush(); + } + + public void write(byte[] b) throws IOException + { + os.write(b); + } + + public void write(byte[] b, int off, int len) throws IOException + { + os.write(b, off, len); + } + + public void write(int b) throws IOException + { + os.write(b); + } +} diff --git a/src/com/one/file/ConnectionProvider.java b/src/com/one/file/ConnectionProvider.java new file mode 100644 index 0000000..c8d727c --- /dev/null +++ b/src/com/one/file/ConnectionProvider.java @@ -0,0 +1,10 @@ +package com.one.file; + +import java.util.Enumeration; +import javax.microedition.io.Connection; + +public interface ConnectionProvider +{ + public Enumeration listRoots(); + public FileConnection convertFileConnection(Connection conn); +} \ No newline at end of file diff --git a/src/com/one/file/Connector.java b/src/com/one/file/Connector.java new file mode 100644 index 0000000..a36105d --- /dev/null +++ b/src/com/one/file/Connector.java @@ -0,0 +1,171 @@ +package com.one.file; + +import java.io.*; +import java.util.Enumeration; +import java.util.Hashtable; +import javax.microedition.io.Connection; + +public class Connector +{ + public static final int READ = javax.microedition.io.Connector.READ; + public static final int WRITE = javax.microedition.io.Connector.WRITE; + public static final int READ_WRITE = javax.microedition.io.Connector.READ_WRITE; + + private static ConnectionProvider provider; + private static Hashtable tempfiles = new Hashtable(); + + public static void setConnectionProvider(ConnectionProvider cp) + { + provider = cp; + } + + public static Connection open(String name) throws IOException + { + if(name.startsWith("file://")) + { + return TransparentConnector.open(name, READ_WRITE); + } + else + { + return javax.microedition.io.Connector.open(name); + } + } + + public static Connection open(String name, int mode) throws IOException + { + if(name.startsWith("file://")) + { + return TransparentConnector.open(name, mode); + } + else + { + return javax.microedition.io.Connector.open(name, mode); + } + } + + public static Connection open(String name, int mode, boolean timeouts) throws IOException + { + if(name.startsWith("file://")) + { + return TransparentConnector.open(name, mode); + } + else + { + return javax.microedition.io.Connector.open(name, mode, timeouts); + } + } + + public static InputStream openInputStream(String name) throws IOException + { + if(name.startsWith("file://")) + { + return new AFCInputStream((FileConnection)TransparentConnector.open(name, READ)); + } + else + { + return javax.microedition.io.Connector.openInputStream(name); + } + } + + public static OutputStream openOutputStream(String name) throws IOException + { + if(name.startsWith("file://")) + { + return new AFCOutputStream((FileConnection)TransparentConnector.open(name, WRITE)); + } + else + { + return javax.microedition.io.Connector.openOutputStream(name); + } + } + + public static DataInputStream openDataInputStream(String name) throws IOException + { + return new DataInputStream(openInputStream(name)); + } + + public static DataOutputStream openDataOutputStream(String name) throws IOException + { + return new DataOutputStream(openOutputStream(name)); + } + + public static Enumeration listRoots() + { + return provider.listRoots(); + } + + /** + * Открыть FileConnection напрÑмую из ФС. + * + * Методы open(), в отличие от Ñтого, иÑпользуют TransparentConnector + * Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¾Ð·Ñ€Ð°Ñ‡Ð½Ñ‹Ñ… Ñоединений Ñ Ð°Ñ€Ñ…Ð¸Ð²Ð°Ð¼Ð¸, + * а Ñам TransparentConnector вынужден иÑпользовать Ñтот метод + * Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ð±Ð°Ð·Ð¾Ð²Ñ‹Ñ… файлов. + * + * @param name Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° / папки Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ + * @return FileConnection Ð´Ð»Ñ Ñтого файла / папки + * @throws IOException + */ + public static FileConnection openDirectConnection(String name, int mode) throws IOException + { + if(!name.startsWith("file:///")) + { + name = "file:///" + name; + } + + return provider.convertFileConnection(javax.microedition.io.Connector.open(name, mode)); + } + + /** + * Открыть временный файл. + * + * Временный файл имеет вÑегда уникальное имÑ, и ÑоздаетÑÑ + * в ближайшей папке, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ñ€Ð°Ñположена в реальной ФС + * (чтобы не пиÑать в контейнеры вроде архивов, + * которые Ñами Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи требуют временный файл). + * + * @param base путь или полное Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°, Ñ€Ñдом Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼ будет Ñоздан временный файл + * @param exact true, еÑли вÑе таки надо Ñоздать файл ИМЕÐÐО в указанной папке + * @return Ð¸Ð¼Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð½Ð¾Ð³Ð¾ файла + */ + public static String createTempFile(String base, boolean exact) + { + if(!base.startsWith("/")) + { + base = "/" + base; + } + + if(exact) + { + base = base.substring(0, base.lastIndexOf('/') + 1); + } + else + { + int index = base.indexOf("."); + + if(index >= 0) + { + base = base.substring(0, base.lastIndexOf('/', index) + 1); + } + else + { + base = base.substring(0, base.lastIndexOf('/') + 1); + } + } + + String filename = (base + "~" + Long.toString(System.currentTimeMillis(), 16).toUpperCase() + ".tmp").substring(1); + tempfiles.put(filename, new Object()); + + return filename; + } + + public static void releaseTempFile(String filename) + { + tempfiles.remove(filename); + } + + public static boolean isTempFileUsed(String filename) + { + return tempfiles.get(filename) != null; + } +} diff --git a/src/com/one/file/FileConnection.java b/src/com/one/file/FileConnection.java new file mode 100644 index 0000000..6198404 --- /dev/null +++ b/src/com/one/file/FileConnection.java @@ -0,0 +1,41 @@ +package com.one.file; + +import java.io.*; +import java.util.Enumeration; +import javax.microedition.io.Connection; + +public interface FileConnection extends Connection +{ + public abstract void close() throws IOException; + public abstract boolean isOpen(); + public abstract InputStream openInputStream() throws IOException; + public abstract DataInputStream openDataInputStream() throws IOException; + public abstract OutputStream openOutputStream() throws IOException; + public abstract DataOutputStream openDataOutputStream() throws IOException; + public abstract OutputStream openOutputStream(long byteOffset) throws IOException; + public abstract long totalSize(); + public abstract long availableSize(); + public abstract long usedSize(); + public abstract long directorySize(boolean includeSubDirs) throws IOException; + public abstract long fileSize() throws IOException; + public abstract boolean canRead(); + public abstract boolean canWrite(); + public abstract boolean isHidden(); + public abstract void setReadable(boolean readable) throws IOException; + public abstract void setWritable(boolean writable) throws IOException; + public abstract void setHidden(boolean hidden) throws IOException; + public abstract Enumeration list() throws IOException; + public abstract Enumeration list(String filter, boolean includeHidden) throws IOException; + public abstract void create() throws IOException; + public abstract void mkdir() throws IOException; + public abstract boolean exists(); + public abstract boolean isDirectory(); + public abstract void delete() throws IOException; + public abstract void rename(String newName) throws IOException; + public abstract void truncate(long byteOffset) throws IOException; + public abstract void setFileConnection(String fileName) throws IOException; + public abstract String getName(); + public abstract String getPath(); + public abstract String getURL(); + public abstract long lastModified(); +} \ No newline at end of file diff --git a/src/com/one/file/GenericConnectionProvider.java b/src/com/one/file/GenericConnectionProvider.java new file mode 100644 index 0000000..7beddaa --- /dev/null +++ b/src/com/one/file/GenericConnectionProvider.java @@ -0,0 +1,17 @@ +package com.one.file; + +import java.util.Enumeration; +import javax.microedition.io.Connection; + +public class GenericConnectionProvider implements ConnectionProvider +{ + public Enumeration listRoots() + { + return GenericFileConnection.listRoots(); + } + + public FileConnection convertFileConnection(Connection conn) + { + return new GenericFileConnection(conn); + } +} diff --git a/src/com/one/file/GenericFileConnection.java b/src/com/one/file/GenericFileConnection.java new file mode 100644 index 0000000..55941b0 --- /dev/null +++ b/src/com/one/file/GenericFileConnection.java @@ -0,0 +1,184 @@ +package com.one.file; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import javax.microedition.io.Connection; + +public class GenericFileConnection implements com.one.file.FileConnection +{ + protected javax.microedition.io.file.FileConnection conn; + + public static Enumeration listRoots() + { + return javax.microedition.io.file.FileSystemRegistry.listRoots(); + } + + public GenericFileConnection(Connection conn) + { + this.conn = (javax.microedition.io.file.FileConnection)conn; + } + + public void close() throws IOException + { + conn.close(); + } + + public boolean isOpen() + { + return conn.isOpen(); + } + + public InputStream openInputStream() throws IOException + { + return conn.openInputStream(); + } + + public DataInputStream openDataInputStream() throws IOException + { + return conn.openDataInputStream(); + } + + public OutputStream openOutputStream() throws IOException + { + return conn.openOutputStream(); + } + + public DataOutputStream openDataOutputStream() throws IOException + { + return conn.openDataOutputStream(); + } + + public OutputStream openOutputStream(long byteOffset) throws IOException + { + return conn.openOutputStream(byteOffset); + } + + public long totalSize() + { + return conn.totalSize(); + } + + public long availableSize() + { + return conn.availableSize(); + } + + public long usedSize() + { + return conn.usedSize(); + } + + public long directorySize(boolean includeSubDirs) throws IOException + { + return conn.directorySize(includeSubDirs); + } + + public long fileSize() throws IOException + { + return conn.fileSize(); + } + + public boolean canRead() + { + return conn.canRead(); + } + + public boolean canWrite() + { + return conn.canWrite(); + } + + public boolean isHidden() + { + return conn.isHidden(); + } + + public void setReadable(boolean readable) throws IOException + { + conn.setReadable(readable); + } + + public void setWritable(boolean writable) throws IOException + { + conn.setWritable(writable); + } + + public void setHidden(boolean hidden) throws IOException + { + conn.setHidden(hidden); + } + + public Enumeration list() throws IOException + { + return conn.list(); + } + + public Enumeration list(String filter, boolean includeHidden) throws IOException + { + return conn.list(filter, includeHidden); + } + + public void create() throws IOException + { + conn.create(); + } + + public void mkdir() throws IOException + { + conn.mkdir(); + } + + public boolean exists() + { + return conn.exists(); + } + + public boolean isDirectory() + { + return conn.isDirectory(); + } + + public void delete() throws IOException + { + conn.delete(); + } + + public void rename(String newName) throws IOException + { + conn.rename(newName); + } + + public void truncate(long byteOffset) throws IOException + { + conn.truncate(byteOffset); + } + + public void setFileConnection(String fileName) throws IOException + { + conn.setFileConnection(fileName); + } + + public String getName() + { + return conn.getName(); + } + + public String getPath() + { + return conn.getPath(); + } + + public String getURL() + { + return conn.getURL(); + } + + public long lastModified() + { + return conn.lastModified(); + } +} \ No newline at end of file diff --git a/src/com/one/file/TransparentConnector.java b/src/com/one/file/TransparentConnector.java new file mode 100644 index 0000000..a86b62d --- /dev/null +++ b/src/com/one/file/TransparentConnector.java @@ -0,0 +1,372 @@ +package com.one.file; + +import com.one.Container; +import com.one.ModuleRegistry; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; +import javax.microedition.io.Connection; + +/** + * КлаÑÑ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð·Ñ€Ð°Ñ‡Ð½Ð¾Ð³Ð¾ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ¹Ð½ÐµÑ€Ð¾Ð² (архивов) как обычных папок. + * Содержит пул контейнеров Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ñ‹Ñ… открытий одного и того же контейнера. + * Учитывает завиÑимоÑти вложенных контейнеров от базовых при их закрытии. + * ОтÑлеживает чаÑтоту иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ¹Ð½ÐµÑ€Ð¾Ð². + */ +public class TransparentConnector +{ + protected static final String FILE_PREFIX = "file:///"; + protected static final int PREFIX_LEN = FILE_PREFIX.length(); + + protected static Hashtable contpool = new Hashtable(); + protected static Hashtable actpool = new Hashtable(); + + public static Connection open(String name, int mode) throws IOException + { + if(name.startsWith(FILE_PREFIX)) + { + name = name.substring(PREFIX_LEN); + + if(name.endsWith("/")) + { + /* + * Это - папка. + */ + + int fromindex = name.length() - 1; + + while(true) + { + int pindex = name.lastIndexOf('.', fromindex); + + if(pindex >= 0) + { + /* + * Это папка, но тем не менее в имени еÑÑ‚ÑŒ точка. + * Это может означать только одно - перед нами контейнер. -- ÐЕ ФÐКТ! + * Теперь надо найти первый Ñлеш, который идет за Ñтой точкой, + * и взÑÑ‚ÑŒ Ñтроку от начала до Ñтого Ñлеша - будет Ð¸Ð¼Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ¹Ð½ÐµÑ€Ð°. + * Потом надо будет доÑтать контейнер из пула, + * а еÑли там нет, то открыть. + */ + + int sindex = name.indexOf('/', pindex); + + String contname = name.substring(0, sindex + 1); + Container container = (Container)contpool.get(contname); + + if(container == null) + { + String ext = name.substring(pindex + 1, sindex); + + if(ModuleRegistry.getAction(ext) == ModuleRegistry.ACTION_EXPLORE) + { + FileConnection fc = (FileConnection)open(FILE_PREFIX + name.substring(0, sindex), Connector.READ_WRITE); + + container = (Container)ModuleRegistry.getModuleInstance(ModuleRegistry.getModule(ext)); + container.init(fc, false); + + contpool.put(contname, container); + } + else + { + /* + * Излучаем в проÑтранÑтво пучок короткоÑложных ÑкÑпреÑÑивных выражений, + * поÑкольку нам попалаÑÑŒ Ð¾Ð±Ñ‹Ñ‡Ð½Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°, в имени которой за каким-то чертом еÑÑ‚ÑŒ точка. + */ + + fromindex = name.lastIndexOf('/', pindex - 1) - 1; + continue; + } + } + + Integer usecount = (Integer)actpool.get(contname); + + if(usecount == null) + { + actpool.put(contname, new Integer(1)); + } + else + { + actpool.put(contname, new Integer(usecount.intValue() + 1)); + } + + return container.getFileConnection(name.substring(sindex + 1), mode); + } + else + { + return Connector.openDirectConnection(name, mode); + } + } + } + else + { + /* + * Это - файл + */ + + int sindex = name.lastIndexOf('/'); + String path = name.substring(0, sindex); + + int fromindex = path.length() - 1; + + while(true) + { + int pindex = path.lastIndexOf('.', fromindex); + + if(pindex >= 0) + { + /* + * Был файл, Ð¸Ð¼Ñ Ð¾Ñ‚Ð±Ñ€Ð¾Ñили, но точка вÑе равно еще где-то еÑÑ‚ÑŒ. + * Значит, перед нами опÑÑ‚ÑŒ контейнер. + */ + + sindex = name.indexOf('/', pindex); + + String contname = name.substring(0, sindex + 1); + Container container = (Container)contpool.get(contname); + + if(container == null) + { + String ext = name.substring(pindex + 1, sindex); + + if(ModuleRegistry.getAction(ext) == ModuleRegistry.ACTION_EXPLORE) + { + FileConnection fc = (FileConnection)open(FILE_PREFIX + name.substring(0, sindex), Connector.READ_WRITE); + + container = (Container)ModuleRegistry.getModuleInstance(ModuleRegistry.getModule(ext)); + container.init(fc, false); + + contpool.put(contname, container); + } + else + { + /* + * Излучаем в проÑтранÑтво пучок короткоÑложных ÑкÑпреÑÑивных выражений, + * поÑкольку нам попалаÑÑŒ Ð¾Ð±Ñ‹Ñ‡Ð½Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°, в имени которой за каким-то чертом еÑÑ‚ÑŒ точка. + */ + + fromindex = path.lastIndexOf('/', pindex - 1) - 1; + continue; + } + } + + Integer usecount = (Integer)actpool.get(contname); + + if(usecount == null) + { + actpool.put(contname, new Integer(1)); + } + else + { + actpool.put(contname, new Integer(usecount.intValue() + 1)); + } + + return container.getFileConnection(name.substring(sindex + 1), mode); + } + else + { + return Connector.openDirectConnection(name, mode); + } + } + } + } + else + { + throw new IllegalArgumentException("File URL expected"); + } + } + + /** + * Сколько раз иÑпользовалÑÑ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¹ контейнер. + */ + public static int getUseCount(String contname) + { + int res; + + Integer usecount = (Integer)actpool.get(contname); + + if(usecount != null) + { + res = usecount.intValue(); + + Enumeration dependents = listDependents(contname); + + while(dependents.hasMoreElements()) + { + res += getUseCount((String)dependents.nextElement()); + } + + return res; + } + else + { + return 0; + } + } + + /** + * Проверить, имеютÑÑ Ð»Ð¸ открытые контейнеры. + */ + public static boolean hasOpenContainers() + { + return contpool.size() > 0; + } + + /** + * Проверить, еÑÑ‚ÑŒ ли Ñреди открытых данный контейнер. + */ + public static boolean hasOpenContainer(String contname) + { + return contpool.get(contname) != null; + } + + /** + * Ðайти контейнер, который иÑпользовалÑÑ Ð½Ð°Ð¸Ð¼ÐµÐ½ÑŒÑˆÐµÐµ чиÑло раз. + */ + public static String findLeastUsedContainer() + { + String contname = null; + + Enumeration contnames = contpool.keys(); + String s; + + int mincount = Integer.MAX_VALUE; + int usecount; + + while(contnames.hasMoreElements()) + { + s = (String)contnames.nextElement(); + usecount = getUseCount(s); + + if(usecount < mincount) + { + mincount = usecount; + contname = s; + } + } + + return contname; + } + + /** + * Вернуть ÑпиÑок вÑех открытых контейнеров. + */ + public static Enumeration listContainers() + { + return contpool.keys(); + } + + /** + * Вернуть ÑпиÑок контейнеров, которые открыты на базе указанного. + */ + public static Enumeration listDependents(String base) + { + Vector res = new Vector(); + + Enumeration contnames = contpool.keys(); + String contname; + + while(contnames.hasMoreElements()) + { + contname = (String)contnames.nextElement(); + + if(contname.startsWith(base) && !contname.equals(base)) + { + res.addElement(contname); + } + } + + return res.elements(); + } + + /** + * Вернуть чиÑло контейнеров, которые открыты на базе указанного. + */ + public static int getDependentCount(String base) + { + int res = 0; + + Enumeration contnames = contpool.keys(); + String contname; + + while(contnames.hasMoreElements()) + { + contname = (String)contnames.nextElement(); + + if(contname.startsWith(base) && !contname.equals(base)) + { + res++; + } + } + + return res; + } + + /** + * Закрыть указанный контейнер и удалить его из пула. + * + * Перед закрытием контейнера закрываютÑÑ Ð²Ñе открытые на его базе контейнеры. + * ЕÑли контейнер уже закрыт (его нет в пуле), ничего не проиÑходит. + */ + public static void closeContainer(String contname) throws IOException + { + Enumeration dependents = listDependents(contname); + + while(dependents.hasMoreElements()) + { + closeContainer((String)dependents.nextElement()); + } + + Container container = (Container)contpool.get(contname); + + if(container != null) + { + container.close(); + + contpool.remove(contname); + actpool.remove(contname); + } + } + + /** + * Закрыть вÑе контейнеры, которые еÑÑ‚ÑŒ в пуле. + * Сначала закрываютÑÑ Ð·Ð°Ð²Ð¸Ñимые, затем базовые (Ñм. closeContainer()). + */ + public static void closeContainers() throws IOException + { + StringBuffer errors = new StringBuffer(); + + Enumeration contnames = contpool.keys(); + String contname; + + while(contnames.hasMoreElements()) + { + contname = (String)contnames.nextElement(); + + try + { + closeContainer(contname); + } + catch(Exception e) + { + e.printStackTrace(); + + if(errors.length() > 0) + { + errors.append("; "); + } + + errors.append(contname); + errors.append(": "); + errors.append(e.toString()); + } + } + + if(errors.length() > 0) + { + throw new IOException(errors.toString()); + } + } +} diff --git a/src/com/one/gif/ColorQuantizer.java b/src/com/one/gif/ColorQuantizer.java new file mode 100644 index 0000000..64a7184 --- /dev/null +++ b/src/com/one/gif/ColorQuantizer.java @@ -0,0 +1,568 @@ +package com.one.gif; + +import javax.microedition.lcdui.Image; + +/** + * An efficient color quantization algorithm, adapted from the C++ + * implementation quantize.c in ImageMagick. The pixels for + * an image are placed into an oct tree. The oct tree is reduced in + * size, and the pixels from the original image are reassigned to the + * nodes in the reduced tree.

+ * + * @version 0.90 19 Sep 2000 + * @author Adam Doppelt + */ +public class ColorQuantizer +{ + final static int MAX_RGB = 255; + final static int MAX_NODES = 266817; + final static int MAX_TREE_DEPTH = 8; + + // these are precomputed in advance + static int SQUARES[]; + static int SHIFT[]; + + static + { + SQUARES = new int[MAX_RGB + MAX_RGB + 1]; + + for(int i = -MAX_RGB; i <= MAX_RGB; i++) + { + SQUARES[i + MAX_RGB] = i * i; + } + + SHIFT = new int[MAX_TREE_DEPTH + 1]; + + for(int i = 0; i < MAX_TREE_DEPTH + 1; ++i) + { + SHIFT[i] = 1 << (15 - i); + } + } + + Cube cube; + boolean QUICK; + + /** + * Reduce the image to the given number of colors. + */ + public ColorQuantizer(Image image, int max_colors, boolean accurate) + { + QUICK = !accurate; + cube = new Cube(image, max_colors); + + cube.classification(); + cube.reduction(); + cube.assignment(); + } + + public int[] getPalette() + { + return cube.colormap; + } + + public int getColorIndex(int color) + { + return cube.colorIndex(color, QUICK); + } + + static class Cube + { + Image image; + int max_colors; + int colormap[]; + + Node root; + int depth; + + // counter for the number of colors in the cube. this gets + // recalculated often. + int colors; + + // counter for the number of nodes in the tree + int nodes; + + Cube(Image image, int max_colors) + { + this.image = image; + this.max_colors = max_colors; + + int i = max_colors; + + // tree_depth = log max_colors + // 4 + + for(depth = 1; i != 0; depth++) + { + i /= 4; + } + + if(depth > 1) + { + --depth; + } + + if(depth > MAX_TREE_DEPTH) + { + depth = MAX_TREE_DEPTH; + } + else if(depth < 2) + { + depth = 2; + } + + root = new Node(this); + } + + /* + * Procedure Classification begins by initializing a color + * description tree of sufficient depth to represent each + * possible input color in a leaf. However, it is impractical + * to generate a fully-formed color description tree in the + * classification phase for realistic values of cmax. If + * colors components in the input image are quantized to k-bit + * precision, so that cmax= 2k-1, the tree would need k levels + * below the root node to allow representing each possible + * input color in a leaf. This becomes prohibitive because the + * tree's total number of nodes is 1 + sum(i=1,k,8k). + * + * A complete tree would require 19,173,961 nodes for k = 8, + * cmax = 255. Therefore, to avoid building a fully populated + * tree, QUANTIZE: (1) Initializes data structures for nodes + * only as they are needed; (2) Chooses a maximum depth for + * the tree as a function of the desired number of colors in + * the output image (currently log2(colormap size)). + * + * For each pixel in the input image, classification scans + * downward from the root of the color description tree. At + * each level of the tree it identifies the single node which + * represents a cube in RGB space containing It updates the + * following data for each such node: + * + * number_pixels : Number of pixels whose color is contained + * in the RGB cube which this node represents; + * + * unique : Number of pixels whose color is not represented + * in a node at lower depth in the tree; initially, n2 = 0 + * for all nodes except leaves of the tree. + * + * total_red/green/blue : Sums of the red, green, and blue + * component values for all pixels not classified at a lower + * depth. The combination of these sums and n2 will + * ultimately characterize the mean color of a set of pixels + * represented by this node. + */ + void classification() + { + int width = image.getWidth(); + int height = image.getHeight(); + + int[] pixel = new int[1]; + + // convert to indexed color + for(int x = width; x-- > 0; ) + { + for(int y = height; y-- > 0; ) + { + image.getRGB(pixel, 0, 1, x, y, 1, 1); + + int red = (pixel[0] >> 16) & 0xFF; + int green = (pixel[0] >> 8) & 0xFF; + int blue = (pixel[0] >> 0) & 0xFF; + + // a hard limit on the number of nodes in the tree + if(nodes > MAX_NODES) + { + root.pruneLevel(); + --depth; + } + + // walk the tree to depth, increasing the + // number_pixels count for each node + Node node = root; + + for(int level = 1; level <= depth; ++level) + { + int id = (((red > node.mid_red ? 1 : 0) << 0) | + ((green > node.mid_green ? 1 : 0) << 1) | + ((blue > node.mid_blue ? 1 : 0) << 2)); + + if(node.child[id] == null) + { + new Node(node, id, level); + } + + node = node.child[id]; + node.number_pixels += SHIFT[level]; + } + + ++node.unique; + node.total_red += red; + node.total_green += green; + node.total_blue += blue; + } + } + } + + /* + * reduction repeatedly prunes the tree until the number of + * nodes with unique > 0 is less than or equal to the maximum + * number of colors allowed in the output image. + * + * When a node to be pruned has offspring, the pruning + * procedure invokes itself recursively in order to prune the + * tree from the leaves upward. The statistics of the node + * being pruned are always added to the corresponding data in + * that node's parent. This retains the pruned node's color + * characteristics for later averaging. + */ + void reduction() + { + int threshold = 1; + + while(colors > max_colors) + { + colors = 0; + threshold = root.reduce(threshold, Integer.MAX_VALUE); + } + } + + /** + * The result of a closest color search. + */ + static class Search + { + int distance; + int color_number; + } + + /* + * Procedure assignment generates the output image from the + * pruned tree. The output image consists of two parts: (1) A + * color map, which is an array of color descriptions (RGB + * triples) for each color present in the output image; (2) A + * pixel array, which represents each pixel as an index into + * the color map array. + * + * First, the assignment phase makes one pass over the pruned + * color description tree to establish the image's color map. + * For each node with n2 > 0, it divides Sr, Sg, and Sb by n2. + * This produces the mean color of all pixels that classify no + * lower than this node. Each of these colors becomes an entry + * in the color map. + */ + void assignment() + { + colormap = new int[colors]; + + colors = 0; + root.colormap(); + } + + /** + * Reclassify pixel in the pruned tree to identify + * the deepest node containing the pixel's color. + * @return Index in color map for given pixel. + */ + int colorIndex(int pixel, boolean quick) + { + // convert to indexed color + int red = (pixel >> 16) & 0xFF; + int green = (pixel >> 8) & 0xFF; + int blue = (pixel >> 0) & 0xFF; + + // walk the tree to find the cube containing that color + Node node = root; + + for(; ; ) + { + int id = (((red > node.mid_red ? 1 : 0) << 0) | + ((green > node.mid_green ? 1 : 0) << 1) | + ((blue > node.mid_blue ? 1 : 0) << 2)); + + if(node.child[id] == null) + { + break; + } + + node = node.child[id]; + } + + if(quick) + { + // if QUICK is set, just use that + // node. Strictly speaking, this isn't + // necessarily best match. + return node.color_number; + } + else + { + // Find the closest color. + Search search = new Search(); + search.distance = Integer.MAX_VALUE; + node.parent.closestColor(red, green, blue, search); + return search.color_number; + } + } + + /** + * A single Node in the tree. + */ + static class Node + { + Cube cube; + + // parent node + Node parent; + + // child nodes + Node child[]; + int nchild; + + // our index within our parent + int id; + + // our level within the tree + int level; + + // our color midpoint + int mid_red; + int mid_green; + int mid_blue; + + // the pixel count for this node and all children + int number_pixels; + + // the pixel count for this node + int unique; + + // the sum of all pixels contained in this node + int total_red; + int total_green; + int total_blue; + + // used to build the colormap + int color_number; + + Node(Cube cube) + { + this.cube = cube; + this.parent = this; + this.child = new Node[8]; + this.id = 0; + this.level = 0; + + this.number_pixels = Integer.MAX_VALUE; + + this.mid_red = (MAX_RGB + 1) >> 1; + this.mid_green = (MAX_RGB + 1) >> 1; + this.mid_blue = (MAX_RGB + 1) >> 1; + } + + Node(Node parent, int id, int level) + { + this.cube = parent.cube; + this.parent = parent; + this.child = new Node[8]; + this.id = id; + this.level = level; + + // add to the cube + ++cube.nodes; + + if(level == cube.depth) + { + ++cube.colors; + } + + // add to the parent + ++parent.nchild; + parent.child[id] = this; + + // figure out our midpoint + int bi = (1 << (MAX_TREE_DEPTH - level)) >> 1; + mid_red = parent.mid_red + ((id & 1) > 0 ? bi : -bi); + mid_green = parent.mid_green + ((id & 2) > 0 ? bi : -bi); + mid_blue = parent.mid_blue + ((id & 4) > 0 ? bi : -bi); + } + + /** + * Remove this child node, and make sure our parent + * absorbs our pixel statistics. + */ + void pruneChild() + { + --parent.nchild; + parent.unique += unique; + parent.total_red += total_red; + parent.total_green += total_green; + parent.total_blue += total_blue; + parent.child[id] = null; + --cube.nodes; + cube = null; + parent = null; + } + + /** + * Prune the lowest layer of the tree. + */ + void pruneLevel() + { + if(nchild != 0) + { + for(int id = 0; id < 8; id++) + { + if(child[id] != null) + { + child[id].pruneLevel(); + } + } + } + + if(level == cube.depth) + { + pruneChild(); + } + } + + /** + * Remove any nodes that have fewer than threshold + * pixels. Also, as long as we're walking the tree: + * + * - figure out the color with the fewest pixels + * - recalculate the total number of colors in the tree + */ + int reduce(int threshold, int next_threshold) + { + if(nchild != 0) + { + for(int id = 0; id < 8; id++) + { + if(child[id] != null) + { + next_threshold = child[id].reduce(threshold, next_threshold); + } + } + } + + if(number_pixels <= threshold) + { + pruneChild(); + } + else + { + if(unique != 0) + { + cube.colors++; + } + + if(number_pixels < next_threshold) + { + next_threshold = number_pixels; + } + } + + return next_threshold; + } + + /* + * colormap traverses the color cube tree and notes each + * colormap entry. A colormap entry is any node in the + * color cube tree where the number of unique colors is + * not zero. + */ + void colormap() + { + if(nchild != 0) + { + for(int id = 0; id < 8; id++) + { + if(child[id] != null) + { + child[id].colormap(); + } + } + } + + if(unique != 0) + { + int r = ((total_red + (unique >> 1)) / unique); + int g = ((total_green + (unique >> 1)) / unique); + int b = ((total_blue + (unique >> 1)) / unique); + + cube.colormap[cube.colors] = (((0xFF) << 24) | + ((r & 0xFF) << 16) | + ((g & 0xFF) << 8) | + ((b & 0xFF) << 0)); + + color_number = cube.colors++; + } + } + + /* ClosestColor traverses the color cube tree at a + * particular node and determines which colormap entry + * best represents the input color. + */ + void closestColor(int red, int green, int blue, Search search) + { + if(nchild != 0) + { + for(int id = 0; id < 8; id++) + { + if(child[id] != null) + { + child[id].closestColor(red, green, blue, search); + } + } + } + + if(unique != 0) + { + int color = cube.colormap[color_number]; + int distance = distance(color, red, green, blue); + + if(distance < search.distance) + { + search.distance = distance; + search.color_number = color_number; + } + } + } + + /** + * Figure out the distance between this node and som color. + */ + final static int distance(int color, int r, int g, int b) + { + return (SQUARES[((color >> 16) & 0xFF) - r + MAX_RGB] + + SQUARES[((color >> 8) & 0xFF) - g + MAX_RGB] + + SQUARES[((color >> 0) & 0xFF) - b + MAX_RGB]); + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + + if(parent == this) + { + buf.append("root"); + } + else + { + buf.append("node"); + } + + buf.append(' '); + buf.append(level); + buf.append(" ["); + buf.append(mid_red); + buf.append(','); + buf.append(mid_green); + buf.append(','); + buf.append(mid_blue); + buf.append(']'); + + return new String(buf); + } + } + } +} diff --git a/src/com/one/gif/GIFFile.java b/src/com/one/gif/GIFFile.java new file mode 100644 index 0000000..15ff1d8 --- /dev/null +++ b/src/com/one/gif/GIFFile.java @@ -0,0 +1,429 @@ +package com.one.gif; + +import javax.microedition.lcdui.*; +import java.io.*; +import com.vmx.ProgressCallback; + +public class GIFFile +{ + protected OutputStream out; + protected int[] gct; + + public GIFFile(OutputStream out, int[] palette, int backcolor, int width, int height, int loopcount) throws IOException + { + this.out = out; + this.gct = palette; + + out.write(0x47); + out.write(0x49); + out.write(0x46); + out.write(0x38); + out.write(0x39); + out.write(0x61); + + writeWord(out, width); + writeWord(out, height); + + if(palette != null) + { + out.write(0xF7); + out.write(nearestColor(backcolor, palette)); + out.write(0); + + for(int index = 0; index < 256; index++) + { + out.write(palette[index] >> 16); + out.write(palette[index] >> 8); + out.write(palette[index]); + } + } + else + { + out.write(0x70); + out.write(0); + out.write(0); + } + + out.write(0x21); + out.write(0xFF); + out.write(0x0B); + out.write(0x4E); + out.write(0x45); + out.write(0x54); + out.write(0x53); + out.write(0x43); + out.write(0x41); + out.write(0x50); + out.write(0x45); + out.write(0x32); + out.write(0x2E); + out.write(0x30); + out.write(0x03); + out.write(0x01); + writeWord(out, loopcount); + out.write(0); + } + + public void writeImage(Image image, int delay, boolean quantize, boolean dither, ProgressCallback callback) throws IOException + { + int width = image.getWidth(); + int height = image.getHeight(); + + if(callback != null) + { + callback.setProgress(0); + callback.setMax(dither ? height * 2 : height); + } + + out.write(0x21); + out.write(0xF9); + out.write(4); + out.write(0); + writeWord(out, delay); + out.write(0); + out.write(0); + + out.write(0x2C); + writeWord(out, 0); + writeWord(out, 0); + writeWord(out, width); + writeWord(out, height); + + ColorQuantizer quantizer = null; + int[] palette; + + if(quantize || gct == null) + { + out.write(0x87); + + quantizer = new ColorQuantizer(image, 256, true); + palette = quantizer.getPalette(); + + int index = 0; + + for(; index < palette.length; index++) + { + out.write(palette[index] >> 16); + out.write(palette[index] >> 8); + out.write(palette[index]); + } + + for(; index < 256; index++) + { + out.write(0); + out.write(0); + out.write(0); + } + } + else + { + out.write(0x07); + palette = gct; + } + + int[] pixel = new int[2]; + int x, y; + + if(dither) + { + Graphics g = null; + + if(image.isMutable()) + { + g = image.getGraphics(); + } + else + { + try + { + Image img = Image.createImage(width, height); + g = img.getGraphics(); + g.drawImage(image, 0, 0, Graphics.LEFT | Graphics.TOP); + image = img; + } + catch(OutOfMemoryError oome) + { + } + } + + if(g != null) + { + int dr, dg, db; + int cr, cg, cb; + + for(y = 0; y < height; y++) + { + for(x = 0; x < width; x++) + { + image.getRGB(pixel, 0, 1, x, y, 1, 1); + pixel[1] = palette[quantize ? quantizer.getColorIndex(pixel[0]) : nearestColor(pixel[0], palette)]; + + g.setColor(pixel[1]); + g.drawLine(x, y, x, y); + + dr = ((pixel[0] >> 16) & 0xFF) - ((pixel[1] >> 16) & 0xFF); + dg = ((pixel[0] >> 8) & 0xFF) - ((pixel[1] >> 8) & 0xFF); + db = (pixel[0] & 0xFF) - (pixel[1] & 0xFF); + + try + { + image.getRGB(pixel, 0, 1, x + 1, y, 1, 1); + + cr = ((pixel[0] >> 16) & 0xFF) + ((dr * 7) >> 4); + cg = ((pixel[0] >> 8) & 0xFF) + ((dg * 7) >> 4); + cb = (pixel[0] & 0xFF) + ((db * 7) >> 4); + + if(cr < 0) + { + cr = 0; + } + else if(cr > 255) + { + cr = 255; + } + + if(cg < 0) + { + cg = 0; + } + else if(cg > 255) + { + cg = 255; + } + + if(cb < 0) + { + cb = 0; + } + else if(cb > 255) + { + cb = 255; + } + + g.setColor(cr, cg, cb); + g.drawLine(x + 1, y, x + 1, y); + } + catch(Exception e) + { + } + + try + { + image.getRGB(pixel, 0, 1, x - 1, y + 1, 1, 1); + + cr = ((pixel[0] >> 16) & 0xFF) + ((dr * 3) >> 4); + cg = ((pixel[0] >> 8) & 0xFF) + ((dg * 3) >> 4); + cb = (pixel[0] & 0xFF) + ((db * 3) >> 4); + + if(cr < 0) + { + cr = 0; + } + else if(cr > 255) + { + cr = 255; + } + + if(cg < 0) + { + cg = 0; + } + else if(cg > 255) + { + cg = 255; + } + + if(cb < 0) + { + cb = 0; + } + else if(cb > 255) + { + cb = 255; + } + + g.setColor(cr, cg, cb); + g.drawLine(x - 1, y + 1, x - 1, y + 1); + } + catch(Exception e) + { + } + + try + { + image.getRGB(pixel, 0, 1, x, y + 1, 1, 1); + + cr = ((pixel[0] >> 16) & 0xFF) + ((dr * 5) >> 4); + cg = ((pixel[0] >> 8) & 0xFF) + ((dg * 5) >> 4); + cb = (pixel[0] & 0xFF) + ((db * 5) >> 4); + + if(cr < 0) + { + cr = 0; + } + else if(cr > 255) + { + cr = 255; + } + + if(cg < 0) + { + cg = 0; + } + else if(cg > 255) + { + cg = 255; + } + + if(cb < 0) + { + cb = 0; + } + else if(cb > 255) + { + cb = 255; + } + + g.setColor(cr, cg, cb); + g.drawLine(x, y + 1, x, y + 1); + } + catch(Exception e) + { + } + + try + { + image.getRGB(pixel, 0, 1, x + 1, y + 1, 1, 1); + + cr = ((pixel[0] >> 16) & 0xFF) + (dr >> 4); + cg = ((pixel[0] >> 8) & 0xFF) + (dg >> 4); + cb = (pixel[0] & 0xFF) + (db >> 4); + + if(cr < 0) + { + cr = 0; + } + else if(cr > 255) + { + cr = 255; + } + + if(cg < 0) + { + cg = 0; + } + else if(cg > 255) + { + cg = 255; + } + + if(cb < 0) + { + cb = 0; + } + else if(cb > 255) + { + cb = 255; + } + + g.setColor(cr, cg, cb); + g.drawLine(x + 1, y + 1, x + 1, y + 1); + } + catch(Exception e) + { + } + } + + if(callback != null) + { + callback.progress(1); + } + } + } + else if(callback != null) + { + callback.progress(height); + } + } + + out.write(8); + LZWCompressor lzw = new LZWCompressor(out, 8); + + for(y = 0; y < height; y++) + { + for(x = 0; x < width; x++) + { + image.getRGB(pixel, 0, 1, x, y, 1, 1); + lzw.write((byte)(quantize ? quantizer.getColorIndex(pixel[0]) : nearestColor(pixel[0], palette))); + } + + if(callback != null) + { + callback.progress(1); + } + } + + lzw.finish(); + + out.write(0); + } + + public void finish() throws IOException + { + out.write(0x3B); + } + + protected static void writeWord(OutputStream os, int v) throws IOException + { + os.write(v); + os.write(v >> 8); + } + + public static int[] SQUARES = new int[256]; + + static + { + for(int i = 0; i < 256; i++) + { + SQUARES[i] = i * i; + } + } + + public static int colorDistance(int color1, int color2) + { + /* + int dr = ((color1 >> 16) & 0xFF) - ((color2 >> 16) & 0xFF); + int dg = ((color1 >> 8) & 0xFF) - ((color2 >> 8) & 0xFF); + int db = (color1 & 0xFF) - (color2 & 0xFF); + + return dr * dr + dg * dg + db * db; + */ + + return SQUARES[Math.abs(((color1 >> 16) & 0xFF) - ((color2 >> 16) & 0xFF))] + + SQUARES[Math.abs(((color1 >> 8) & 0xFF) - ((color2 >> 8) & 0xFF))] + + SQUARES[Math.abs((color1 & 0xFF) - (color2 & 0xFF))]; + } + + public static int nearestColor(int color, int[] palette) + { + int mindistance = colorDistance(0, -1) + 1; + int distance, index = -1; + + for(int i = 0; i < palette.length; i++) + { + distance = colorDistance(palette[i], color); + + if(distance == 0) + { + return i; + } + else if(distance < mindistance) + { + index = i; + mindistance = distance; + } + } + + return index; + } +} \ No newline at end of file diff --git a/src/com/one/gif/LZWCompressor.java b/src/com/one/gif/LZWCompressor.java new file mode 100644 index 0000000..e9ca7cf --- /dev/null +++ b/src/com/one/gif/LZWCompressor.java @@ -0,0 +1,248 @@ +package com.one.gif; + +import java.io.*; + +/** + * Class for LZW compression of GIF data. + * Extracted from GIFEncoder. + * + * GIFEncoder is based upon gifsave.c, which was written and released + * by:

+ *

+ * Sverre H. Huseby
+ * Bjoelsengt. 17
+ * N-0468 Oslo
+ * Norway

+ * + * Phone: +47 2 230539
+ * sverrehu@ifi.uio.no

+ *

+ * @version 0.90 21 Apr 1996 + * @author Adam Doppelt + */ + +public class LZWCompressor +{ + protected static class BitFile + { + protected OutputStream output_; + protected byte buffer_[]; + protected int index_, bitsLeft_; + + public BitFile(OutputStream output) + { + output_ = output; + buffer_ = new byte[256]; + index_ = 0; + bitsLeft_ = 8; + } + + public void Flush() throws IOException + { + int numBytes = index_ + (bitsLeft_ == 8 ? 0 : 1); + + if(numBytes > 0) + { + output_.write(numBytes); + output_.write(buffer_, 0, numBytes); + buffer_[0] = 0; + index_ = 0; + bitsLeft_ = 8; + } + } + + public void WriteBits(int bits, int numbits) throws IOException + { + int bitsWritten = 0; + int numBytes = 255; + + do + { + if((index_ == 254 && bitsLeft_ == 0) || index_ > 254) + { + output_.write(numBytes); + output_.write(buffer_, 0, numBytes); + + buffer_[0] = 0; + index_ = 0; + bitsLeft_ = 8; + } + + if(numbits <= bitsLeft_) + { + buffer_[index_] |= (bits & ((1 << numbits) - 1)) << (8 - bitsLeft_); + bitsWritten += numbits; + bitsLeft_ -= numbits; + numbits = 0; + } + else + { + buffer_[index_] |= (bits & ((1 << bitsLeft_) - 1)) << (8 - bitsLeft_); + bitsWritten += bitsLeft_; + bits >>= bitsLeft_; + numbits -= bitsLeft_; + buffer_[++index_] = 0; + bitsLeft_ = 8; + } + } + while(numbits != 0); + } + } + + protected static class LZWStringTable + { + protected final static int RES_CODES = 2; + protected final static short HASH_FREE = (short)0xFFFF; + protected final static short NEXT_FIRST = (short)0xFFFF; + protected final static int MAXBITS = 12; + protected final static int MAXSTR = (1 << MAXBITS); + protected final static short HASHSIZE = 9973; + protected final static short HASHSTEP = 2039; + + protected byte strChr_[]; + protected short strNxt_[]; + protected short strHsh_[]; + protected short numStrings_; + + public LZWStringTable() + { + strChr_ = new byte[MAXSTR]; + strNxt_ = new short[MAXSTR]; + strHsh_ = new short[HASHSIZE]; + } + + public int AddCharString(short index, byte b) + { + int hshidx; + + if(numStrings_ >= MAXSTR) + { + return 0xFFFF; + } + + hshidx = Hash(index, b); + + while(strHsh_[hshidx] != HASH_FREE) + { + hshidx = (hshidx + HASHSTEP) % HASHSIZE; + } + + strHsh_[hshidx] = numStrings_; + strChr_[numStrings_] = b; + strNxt_[numStrings_] = (index != HASH_FREE) ? index : NEXT_FIRST; + + return numStrings_++; + } + + public short FindCharString(short index, byte b) + { + int hshidx, nxtidx; + + if(index == HASH_FREE) + { + return b; + } + + hshidx = Hash(index, b); + + while((nxtidx = strHsh_[hshidx]) != HASH_FREE) + { + if(strNxt_[nxtidx] == index && strChr_[nxtidx] == b) + { + return (short)nxtidx; + } + + hshidx = (hshidx + HASHSTEP) % HASHSIZE; + } + + return (short)0xFFFF; + } + + public void ClearTable(int codesize) + { + numStrings_ = 0; + + for(int q = 0; q < HASHSIZE; q++) + { + strHsh_[q] = HASH_FREE; + } + + int w = (1 << codesize) + RES_CODES; + + for(int q = 0; q < w; q++) + { + AddCharString((short)0xFFFF, (byte)q); + } + } + + static public int Hash(short index, byte lastbyte) + { + return ((int)((short)(lastbyte << 8) ^ index) & 0xFFFF) % HASHSIZE; + } + } + + protected OutputStream output; + protected int codesize; + protected int clearcode, endofinfo; + protected int numbits, limit; + protected BitFile bitFile; + protected LZWStringTable strings; + protected short prefix, index; + + public LZWCompressor(OutputStream output, int codesize) throws IOException + { + this.output = output; + this.codesize = codesize; + + bitFile = new BitFile(output); + strings = new LZWStringTable(); + + clearcode = 1 << codesize; + endofinfo = clearcode + 1; + + numbits = codesize + 1; + limit = (1 << numbits) - 1; + + strings.ClearTable(codesize); + bitFile.WriteBits(clearcode, numbits); + + prefix = (short)0xFFFF; + } + + public void write(byte c) throws IOException + { + if((index = strings.FindCharString(prefix, c)) != -1) + { + prefix = index; + } + else + { + bitFile.WriteBits(prefix, numbits); + + if(strings.AddCharString(prefix, c) > limit) + { + if(++numbits > 12) + { + bitFile.WriteBits(clearcode, numbits - 1); + strings.ClearTable(codesize); + numbits = codesize + 1; + } + + limit = (1 << numbits) - 1; + } + + prefix = (short)((short)c & 0xFF); + } + } + + public void finish() throws IOException + { + if(prefix != -1) + { + bitFile.WriteBits(prefix, numbits); + } + + bitFile.WriteBits(endofinfo, numbits); + bitFile.Flush(); + } +} \ No newline at end of file diff --git a/src/com/one/vector/AnimationTask.java b/src/com/one/vector/AnimationTask.java new file mode 100644 index 0000000..beed840 --- /dev/null +++ b/src/com/one/vector/AnimationTask.java @@ -0,0 +1,27 @@ +package com.one.vector; + +import java.util.TimerTask; +import com.one.PaintableObject; + +public class AnimationTask extends TimerTask +{ + protected VectorImage image; + protected PaintableObject canvas; + + public AnimationTask(VectorImage image, PaintableObject canvas) + { + this.image = image; + this.canvas = canvas; + } + + public void run() + { + synchronized(image) + { + image.nextFrame(); + } + + canvas.repaint(); + canvas.serviceRepaints(); + } +} diff --git a/src/com/one/vector/Arc.java b/src/com/one/vector/Arc.java new file mode 100644 index 0000000..c49e26e --- /dev/null +++ b/src/com/one/vector/Arc.java @@ -0,0 +1,220 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.util.Vector; +import java.util.Enumeration; +import java.io.*; + +public class Arc extends VectorElement +{ + protected float[] data = new float[4]; + protected int[] sdata = new int[4]; + protected int start, length; + + public Arc() + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + start = 0; + length = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + + start = dis.readShort(); + length = dis.readShort(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + + dos.writeShort(start); + dos.writeShort(length); + + writeTransformList(dos); + } + + public void rescale() + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + sdata[2] = getScaled(data[2], 2); + sdata[3] = getScaled(data[3], 3); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + g.setColor(color); + } + + if(fill) + { + g.fillArc(sdata[0], sdata[1], sdata[2], sdata[3], start, length); + } + else + { + g.setStrokeStyle(stroke); + g.drawArc(sdata[0], sdata[1], sdata[2], sdata[3], start, length); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case START: + start = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + break; + + case LENGTH: + length = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + break; + } + } + } + + if(flag && changed) + { + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(data[0]); + + case Y: + return new Float(data[1]); + + case WIDTH: + return new Float(data[2]); + + case HEIGHT: + return new Float(data[3]); + + case START: + return new Integer(start); + + case LENGTH: + return new Integer(length); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + data[0] = ((Float)value).floatValue(); + break; + + case Y: + data[1] = ((Float)value).floatValue(); + break; + + case WIDTH: + data[2] = ((Float)value).floatValue(); + break; + + case HEIGHT: + data[3] = ((Float)value).floatValue(); + break; + + case START: + start = ((Integer)value).intValue(); + break; + + case LENGTH: + length = ((Integer)value).intValue(); + break; + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/ArcArray.java b/src/com/one/vector/ArcArray.java new file mode 100644 index 0000000..9ae1a5f --- /dev/null +++ b/src/com/one/vector/ArcArray.java @@ -0,0 +1,413 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class ArcArray extends VectorElement +{ + protected float[][] data = new float[4][]; + protected int[][] sdata; + protected int[] colors; + protected int[] starts; + protected int[] lengths; + protected int count; + protected ArrayData clr, x, y, width, height, start, length; + + public ArcArray() + { + clr = new ArrayData(); + x = new ArrayData(); + y = new ArrayData(); + width = new ArrayData(); + height = new ArrayData(); + start = new ArrayData(); + length = new ArrayData(); + + count = 2; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + parseFlag(dis.readUnsignedByte()); + + count = dis.readUnsignedShort(); + + clr = new ArrayData(dis); + x = new ArrayData(dis); + y = new ArrayData(dis); + width = new ArrayData(dis); + height = new ArrayData(dis); + start = new ArrayData(dis); + length = new ArrayData(dis); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeByte(getFlag()); + + dos.writeShort(count); + + clr.write(dos); + x.write(dos); + y.write(dos); + width.write(dos); + height.write(dos); + start.write(dos); + length.write(dos); + + writeTransformList(dos); + } + + public void create() + { + colors = AuxMath.linearArrayRGB(clr, count); + + data[0] = AuxMath.specificArrayFloat(x, count); + data[1] = AuxMath.specificArrayFloat(y, count); + data[2] = AuxMath.specificArrayFloat(width, count); + data[3] = AuxMath.specificArrayFloat(height, count); + + starts = AuxMath.specificArrayInt(start, count); + lengths = AuxMath.specificArrayInt(length, count); + + sdata = new int[4][count]; + } + + public void rescale() + { + for(int i = 0; i < count; i++) + { + sdata[0][i] = getScaled(data[0][i], 0); + sdata[1][i] = getScaled(data[1][i], 1); + sdata[2][i] = getScaled(data[2][i], 2); + sdata[3][i] = getScaled(data[3][i], 3); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + g.setStrokeStyle(stroke); + + if(group.image.usecolor) + { + if(fill) + { + for(int i = 0; i < count; i++) + { + g.setColor(colors[i]); + g.fillArc(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], starts[i], lengths[i]); + } + } + else + { + for(int i = 0; i < count; i++) + { + g.setColor(colors[i]); + g.drawArc(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], starts[i], lengths[i]); + } + } + } + else + { + if(fill) + { + for(int i = 0; i < count; i++) + { + g.fillArc(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], starts[i], lengths[i]); + } + } + else + { + for(int i = 0; i < count; i++) + { + g.drawArc(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], starts[i], lengths[i]); + } + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + ArrayData v; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else + { + subparam = transform.getSubParam(); + + if(subparam == 0) + { + if(param == INT_A) + { + clr.inta = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + else if(param == INT_B) + { + clr.intb = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + + continue; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else if(subparam == 5) + { + v = start; + } + else if(subparam == 6) + { + v = length; + } + else + { + continue; + } + + switch(param) + { + case VAL_A: + v.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case VAL_B: + v.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_A: + v.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_B: + v.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_C: + v.divc = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_D: + v.divd = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_A: + v.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_B: + v.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == COUNT) + { + return new Integer(count); + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else if(subparam == 5) + { + v = start; + } + else if(subparam == 6) + { + v = length; + } + else + { + return null; + } + + switch(param) + { + case VAL_A: + return new Float(v.vala); + + case VAL_B: + return new Float(v.valb); + + case DIV_A: + return new Float(v.diva); + + case DIV_B: + return new Float(v.divb); + + case DIV_C: + return new Float(v.divc); + + case DIV_D: + return new Float(v.divd); + + case INT_A: + return new Integer(v.inta); + + case INT_B: + return new Integer(v.intb); + + case FUNCTION: + return new Integer(v.type); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == COUNT) + { + count = ((Integer)value).intValue(); + return; + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else if(subparam == 5) + { + v = start; + } + else if(subparam == 6) + { + v = length; + } + else + { + return; + } + + switch(param) + { + case VAL_A: + v.vala = ((Float)value).floatValue(); + break; + + case VAL_B: + v.valb = ((Float)value).floatValue(); + break; + + case DIV_A: + v.diva = ((Float)value).floatValue(); + break; + + case DIV_B: + v.divb = ((Float)value).floatValue(); + break; + + case DIV_C: + v.divc = ((Float)value).floatValue(); + break; + + case DIV_D: + v.divd = ((Float)value).floatValue(); + break; + + case INT_A: + v.inta = ((Integer)value).intValue(); + break; + + case INT_B: + v.intb = ((Integer)value).intValue(); + break; + + case FUNCTION: + v.type = ((Integer)value).intValue(); + break; + } + } +} diff --git a/src/com/one/vector/AreaFill.java b/src/com/one/vector/AreaFill.java new file mode 100644 index 0000000..d944879 --- /dev/null +++ b/src/com/one/vector/AreaFill.java @@ -0,0 +1,171 @@ +package com.one.vector; + +import java.util.EmptyStackException; +import java.io.*; +import com.one.*; + +public class AreaFill extends Effect +{ + protected int color; + protected float x, y; + + protected IntStack xps, yps; + + public AreaFill() + { + xps = new IntStack(); + yps = new IntStack(); + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + hidden = dis.readBoolean(); + + color = dis.readInt(); + + x = dis.readFloat(); + y = dis.readFloat(); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeBoolean(hidden); + + dos.writeInt(color); + + dos.writeFloat(x); + dos.writeFloat(y); + } + + public void apply(int rgb[], int[] temp, int width, int height) + { + if(hidden) + { + return; + } + + int cx = (int)((float)width * x); + int cy = (int)((float)height * y); + + if(cx < 0 || cx >= width || cy < 0 || cy >= height) + { + return; + } + + xps.clear(); + yps.clear(); + + xps.push(cx); + yps.push(cy); + + int interior; + int index; + + index = cx + cy * width; + interior = rgb[index]; + rgb[index] = color; + + try + { + while(true) + { + try + { + cx = xps.pop(); + cy = yps.pop(); + + if(cx - 1 >= 0) + { + index = (cx - 1) + cy * width; + + if(rgb[index] == interior) + { + xps.push(cx - 1); + yps.push(cy); + + rgb[index] = color; + } + } + + if(cx + 1 < width) + { + index = (cx + 1) + cy * width; + + if(rgb[index] == interior) + { + xps.push(cx + 1); + yps.push(cy); + + rgb[index] = color; + } + } + + if(cy - 1 >= 0) + { + index = cx + (cy - 1) * width; + + if(rgb[index] == interior) + { + xps.push(cx); + yps.push(cy - 1); + + rgb[index] = color; + } + } + + if(cy + 1 < height) + { + index = cx + (cy + 1) * width; + + if(rgb[index] == interior) + { + xps.push(cx); + yps.push(cy + 1); + + rgb[index] = color; + } + } + } + catch(StackOverflowException soe) + { + xps.clear(); + yps.clear(); + + xps.push(cx); + yps.push(cy); + } + } + } + catch(EmptyStackException ese) + { + } + } + + public void setColor(int color) + { + this.color = color; + } + + public void setPosition(float x, float y) + { + this.x = x; + this.y = y; + } + + public int getColor() + { + return color; + } + + public float getX() + { + return x; + } + + public float getY() + { + return y; + } +} diff --git a/src/com/one/vector/ArrayData.java b/src/com/one/vector/ArrayData.java new file mode 100644 index 0000000..80ff433 --- /dev/null +++ b/src/com/one/vector/ArrayData.java @@ -0,0 +1,137 @@ +package com.one.vector; + +import java.io.*; + +public class ArrayData +{ + public static final int LINEAR = 0; + public static final int INTEGER = 1; + public static final int HARMONIC = 2; + public static final int CUBIC = 3; + + public float vala, valb; + public float diva, divb, divc, divd; + public int inta, intb; + public int type; + + public ArrayData() + { + } + + public ArrayData(float vala, float valb) + { + this.vala = vala; + this.valb = valb; + + this.type = LINEAR; + } + + public ArrayData(int inta, int intb) + { + this.inta = inta; + this.intb = intb; + + this.type = INTEGER; + } + + public ArrayData(float vala, float valb, float diva, float divb, int inta, int intb) + { + this.vala = vala; + this.valb = valb; + this.diva = diva; + this.divb = divb; + this.inta = inta; + this.intb = intb; + + this.type = HARMONIC; + } + + public ArrayData(float vala, float valb, float diva, float divb, float divc, float divd) + { + this.vala = vala; + this.valb = valb; + this.diva = diva; + this.divb = divb; + this.divc = divc; + this.divd = divd; + + this.type = CUBIC; + } + + public ArrayData(DataInputStream dis) throws IOException + { + read(dis); + } + + public void read(DataInputStream dis) throws IOException + { + type = dis.readUnsignedByte(); + + switch(type) + { + case LINEAR: + vala = dis.readFloat(); + valb = dis.readFloat(); + break; + + case INTEGER: + inta = dis.readInt(); + intb = dis.readInt(); + break; + + case HARMONIC: + vala = dis.readFloat(); + valb = dis.readFloat(); + diva = dis.readFloat(); + divb = dis.readFloat(); + inta = dis.readInt(); + intb = dis.readInt(); + break; + + case CUBIC: + vala = dis.readFloat(); + valb = dis.readFloat(); + diva = dis.readFloat(); + divb = dis.readFloat(); + divc = dis.readFloat(); + divd = dis.readFloat(); + break; + } + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeByte(type); + + switch(type) + { + case LINEAR: + dos.writeFloat(vala); + dos.writeFloat(valb); + break; + + case INTEGER: + dos.writeInt(inta); + dos.writeInt(intb); + break; + + case HARMONIC: + dos.writeFloat(vala); + dos.writeFloat(valb); + dos.writeFloat(diva); + dos.writeFloat(divb); + dos.writeInt(inta); + dos.writeInt(intb); + break; + + case CUBIC: + dos.writeFloat(vala); + dos.writeFloat(valb); + dos.writeFloat(diva); + dos.writeFloat(divb); + dos.writeFloat(divc); + dos.writeFloat(divd); + break; + } + } +} diff --git a/src/com/one/vector/AuxMath.java b/src/com/one/vector/AuxMath.java new file mode 100644 index 0000000..6421dee --- /dev/null +++ b/src/com/one/vector/AuxMath.java @@ -0,0 +1,1133 @@ +package com.one.vector; + +import com.one.CubicSpline; + +public class AuxMath +{ + protected static final int FP_SHIFT = 16; + protected static final int FP_MASK = (1 << FP_SHIFT) - 1; + + public static final float PI = 3.1415927f; + + protected static final float PI_L = 1.2246469E-16f; + protected static final float ATAN_0_5H = 0.4636476f; + protected static final float ATAN_0_5L = 2.2698777E-17f; + protected static final float ATAN_1_5H = 0.98279375f; + protected static final float ATAN_1_5L = 1.3903311E-17f; + protected static final float AT0 = 0.33333334f; + protected static final float AT1 = -0.2f; + protected static final float AT2 = 0.14285715f; + protected static final float AT3 = -0.111111104f; + protected static final float AT4 = 0.09090887f; + protected static final float AT5 = -0.07691876f; + protected static final float AT6 = 0.06661073f; + protected static final float AT7 = -0.058335703f; + protected static final float AT8 = 0.04976878f; + protected static final float AT9 = -0.03653157f; + protected static final float AT10 = 0.01628582f; + protected static final float TWO_29 = 5.3687091E8f; + protected static final float TWO_60 = 1.1529215E18f; + protected static final float TWO_66 = 7.3786976E19f; + + protected static float[] sintab; + + static + { + sintab = new float[360]; + + for(int i = 0; i < 360; i++) + { + sintab[i] = (float)Math.sin(Math.toRadians((double)i)); + } + } + + public static float sin(int a) + { + while(a < 0) + { + a += 360; + } + + return sintab[a % 360]; + } + + public static float cos(int a) + { + while(a < 0) + { + a += 360; + } + + return sintab[(a + 90) % 360]; + } + + public static float sin(float x, float y) + { + return y / (float)Math.sqrt(x * x + y * y); + } + + public static float cos(float x, float y) + { + return x / (float)Math.sqrt(x * x + y * y); + } + + public static float[] rotate(float x, float y, float x0, float y0, int a) + { + float[] r = new float[2]; + + r[0] = x0 + (x - x0) * cos(a) + (y - y0) * sin(a); + r[1] = y0 - (x - x0) * sin(a) + (y - y0) * cos(a); + + return r; + } + + public static float power(float x, int n) + { + float r = 1.0f; + + for(int i = 0; i < n; i++) + { + r *= x; + } + + return r; + } + + public static int gcd(int m, int n) + { + if(m == 0 || m == n) + { + return n; + } + else if(n == 0) + { + return m; + } + else if(m == 1 || n == 1) + { + return 1; + } + else if((m & 1) == 0) + { + if((n & 1) == 0) + { + return gcd(m >>> 1, n >>> 1) << 1; + } + else + { + return gcd(m >>> 1, n); + } + } + else + { + if((n & 1) == 0) + { + return gcd(m, n >>> 1); + } + else + { + return gcd(n, Math.abs(m - n)); + } + } + } + + public static int averageColor(int[] points) + { + int a = 0, r = 0, g = 0, b = 0; + + for(int i = 0; i < points.length; i++) + { + a += (points[i] >> 24) & 0xFF; + r += (points[i] >> 16) & 0xFF; + g += (points[i] >> 8) & 0xFF; + b += points[i] & 0xFF; + } + + a /= points.length; + r /= points.length; + g /= points.length; + b /= points.length; + + return (a << 24) | (r << 16) | (g << 8) | b; + } + + public static int averageColorNoAlpha(int[] points) + { + int r = 0, g = 0, b = 0; + + for(int i = 0; i < points.length; i++) + { + r += (points[i] >> 16) & 0xFF; + g += (points[i] >> 8) & 0xFF; + b += points[i] & 0xFF; + } + + r /= points.length; + g /= points.length; + b /= points.length; + + return (r << 16) | (g << 8) | b; + } + + /* + public static Image scaleImage(Image image, int destwidth, int destheight) + { + Image scaled = Image.createImage(destwidth, destheight); + Graphics g = scaled.getGraphics(); + + int relwidth = (width << FP_SHIFT) / destwidth; + int relheight = (height << FP_SHIFT) / destheight; + + int scanwidth = relwidth >>> FP_SHIFT; + int scanheight = relheight >>> FP_SHIFT; + + if(scanwidth < 1) + { + scanwidth = 1; + } + + if(scanheight < 1) + { + scanheight = 1; + } + + int[] points = new int[scanwidth * scanheight]; + + int pointwidth = destwidth / width; + int pointheight = destheight / height; + + if(pointwidth < 1) + { + pointwidth = 1; + } + + if(pointheight < 1) + { + pointheight = 1; + } + + for(int x = 0; x < sdata[2]; x += pointwidth) + { + for(int y = 0; y < sdata[3]; y += pointheight) + { + image.getRGB(points, 0, scanwidth, (x * relwidth) >>> FP_SHIFT, (y * relheight) >>> FP_SHIFT, scanwidth, scanheight); + + g.setColor(averageColorNoAlpha(points)); + g.fillRect(x, y, pointwidth, pointheight); + } + } + + return scaled; + } + */ + + public static void scaleRGB(int[] srcPixels, int[] destPixels, int srcw, int srch, int destw, int desth, boolean alpha) + { + int wscan, hscan, scancount; + int x, y, sx, sy, cx, cy; + int a, r, g, b; + int idx; + int rx, ry; + + rx = (srcw << FP_SHIFT) / destw; + ry = (srch << FP_SHIFT) / desth; + + wscan = rx >>> FP_SHIFT; + hscan = ry >>> FP_SHIFT; + + if(wscan == 0) + { + wscan = 1; + } + + if(hscan == 0) + { + hscan = 1; + } + + scancount = wscan * hscan; + + try + { + if(alpha) + { + for(x = 0; x < destw; x++) + { + for(y = 0; y < desth; y++) + { + sx = (x * rx) >>> FP_SHIFT ; + sy = (y * ry) >>> FP_SHIFT; + + a = r = g = b = 0; + + for(cx = 0; cx < wscan; cx++) + { + for(cy = 0; cy < hscan; cy++) + { + idx = sx + cx + (sy + cy) * srcw; + + a += (srcPixels[idx] >> 24) & 0xFF; + r += (srcPixels[idx] >> 16) & 0xFF; + g += (srcPixels[idx] >> 8) & 0xFF; + b += (srcPixels[idx]) & 0xFF; + } + } + + a /= scancount; + r /= scancount; + g /= scancount; + b /= scancount; + + destPixels[x + y * destw] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + } + else + { + for(x = 0; x < destw; x++) + { + for(y = 0; y < desth; y++) + { + sx = (x * rx) >>> FP_SHIFT ; + sy = (y * ry) >>> FP_SHIFT; + + r = g = b = 0; + + for(cx = 0; cx < wscan; cx++) + { + for(cy = 0; cy < hscan; cy++) + { + idx = sx + cx + (sy + cy) * srcw; + + r += (srcPixels[idx] >> 16) & 0xFF; + g += (srcPixels[idx] >> 8) & 0xFF; + b += (srcPixels[idx]) & 0xFF; + } + } + + r /= scancount; + g /= scancount; + b /= scancount; + + destPixels[x + y * destw] = (r << 16) | (g << 8) | b; + } + } + } + } + catch(ArrayIndexOutOfBoundsException e) + { + } + } + + public static void bilinearScaleRGB(int[] srcPixels, int[] destPixels, int srcw, int srch, int destw, int desth, boolean alpha) + { + int x, y, rx, ry, ix, iy, fx, fy; + int idx1, idx2, idx3, idx4; + int a, r, g, b; + + try + { + if(alpha) + { + for(x = 0; x < destw; x++) + { + for(y = 0; y < desth; y++) + { + rx = (x << FP_SHIFT) / destw * srcw; + ry = (y << FP_SHIFT) / desth * srch; + + ix = rx >>> FP_SHIFT; + iy = ry >>> FP_SHIFT; + + fx = rx & FP_MASK; + fy = ry & FP_MASK; + + idx1 = idx2 = idx3 = idx4 = ix + iy * srcw; + + if(ix < srcw - 1) + { + idx2++; + idx4++; + } + + if(iy < srch - 1) + { + idx3 += srcw; + idx4 += srcw; + } + + a = (((((srcPixels[idx1] >> 24) & 0xFF) * (FP_MASK - fx) + ((srcPixels[idx2] >> 24) & 0xFF) * fx) >>> FP_SHIFT) * (FP_MASK - fy) + ((((srcPixels[idx3] >> 24) & 0xFF) * (FP_MASK - fx) + ((srcPixels[idx4] >> 24) & 0xFF) * fx) >>> FP_SHIFT) * fy) >>> FP_SHIFT; + r = (((((srcPixels[idx1] >> 16) & 0xFF) * (FP_MASK - fx) + ((srcPixels[idx2] >> 16) & 0xFF) * fx) >>> FP_SHIFT) * (FP_MASK - fy) + ((((srcPixels[idx3] >> 16) & 0xFF) * (FP_MASK - fx) + ((srcPixels[idx4] >> 16) & 0xFF) * fx) >>> FP_SHIFT) * fy) >>> FP_SHIFT; + g = (((((srcPixels[idx1] >> 8) & 0xFF) * (FP_MASK - fx) + ((srcPixels[idx2] >> 8) & 0xFF) * fx) >>> FP_SHIFT) * (FP_MASK - fy) + ((((srcPixels[idx3] >> 8) & 0xFF) * (FP_MASK - fx) + ((srcPixels[idx4] >> 8) & 0xFF) * fx) >>> FP_SHIFT) * fy) >>> FP_SHIFT; + b = ((((srcPixels[idx1] & 0xFF) * (FP_MASK - fx) + (srcPixels[idx2] & 0xFF) * fx) >>> FP_SHIFT) * (FP_MASK - fy) + (((srcPixels[idx3] & 0xFF) * (FP_MASK - fx) + (srcPixels[idx4] & 0xFF) * fx) >>> FP_SHIFT) * fy) >>> FP_SHIFT; + + destPixels[x + y * destw] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + } + else + { + for(x = 0; x < destw; x++) + { + for(y = 0; y < desth; y++) + { + rx = (x << FP_SHIFT) / destw * srcw; + ry = (y << FP_SHIFT) / desth * srch; + + ix = rx >>> FP_SHIFT; + iy = ry >>> FP_SHIFT; + + fx = rx & FP_MASK; + fy = ry & FP_MASK; + + idx1 = idx2 = idx3 = idx4 = ix + iy * srcw; + + if(ix < srcw - 1) + { + idx2++; + idx4++; + } + + if(iy < srch - 1) + { + idx3 += srcw; + idx4 += srcw; + } + + r = (((((srcPixels[idx1] >> 16) & 0xFF) * (FP_MASK - fx) + ((srcPixels[idx2] >> 16) & 0xFF) * fx) >>> FP_SHIFT) * (FP_MASK - fy) + ((((srcPixels[idx3] >> 16) & 0xFF) * (FP_MASK - fx) + ((srcPixels[idx4] >> 16) & 0xFF) * fx) >>> FP_SHIFT) * fy) >>> FP_SHIFT; + g = (((((srcPixels[idx1] >> 8) & 0xFF) * (FP_MASK - fx) + ((srcPixels[idx2] >> 8) & 0xFF) * fx) >>> FP_SHIFT) * (FP_MASK - fy) + ((((srcPixels[idx3] >> 8) & 0xFF) * (FP_MASK - fx) + ((srcPixels[idx4] >> 8) & 0xFF) * fx) >>> FP_SHIFT) * fy) >>> FP_SHIFT; + b = ((((srcPixels[idx1] & 0xFF) * (FP_MASK - fx) + (srcPixels[idx2] & 0xFF) * fx) >>> FP_SHIFT) * (FP_MASK - fy) + (((srcPixels[idx3] & 0xFF) * (FP_MASK - fx) + (srcPixels[idx4] & 0xFF) * fx) >>> FP_SHIFT) * fy) >>> FP_SHIFT; + + destPixels[x + y * destw] = (r << 16) | (g << 8) | b; + } + } + } + } + catch(ArrayIndexOutOfBoundsException e) + { + } + } + + public static void bicubicScaleRGB(int[] srcPixels, int[] destPixels, int srcw, int srch, int destw, int desth, boolean alpha) + { + try + { + float[][] srca = alpha ? new float[srch][srcw] : null; + + float[][] srcr = new float[srch][srcw]; + float[][] srcg = new float[srch][srcw]; + float[][] srcb = new float[srch][srcw]; + + int x, y, index; + int a, r, g, b; + + if(alpha) + { + for(y = 0; y < srch; y++) + { + for(x = 0; x < srcw; x++) + { + index = x + y * srcw; + + srca[y][x] = (float)((srcPixels[index] >> 24) & 0xFF); + srcr[y][x] = (float)((srcPixels[index] >> 16) & 0xFF); + srcg[y][x] = (float)((srcPixels[index] >> 8) & 0xFF); + srcb[y][x] = (float)(srcPixels[index] & 0xFF); + } + } + } + else + { + for(y = 0; y < srch; y++) + { + for(x = 0; x < srcw; x++) + { + index = x + y * srcw; + + srcr[y][x] = (float)((srcPixels[index] >> 16) & 0xFF); + srcg[y][x] = (float)((srcPixels[index] >> 8) & 0xFF); + srcb[y][x] = (float)(srcPixels[index] & 0xFF); + } + } + } + + float[][] desta = alpha ? CubicSpline.bicubicResampleCartesian(srca, srch, srcw, desth, destw) : null; + + float[][] destr = CubicSpline.bicubicResampleCartesian(srcr, srch, srcw, desth, destw); + float[][] destg = CubicSpline.bicubicResampleCartesian(srcg, srch, srcw, desth, destw); + float[][] destb = CubicSpline.bicubicResampleCartesian(srcb, srch, srcw, desth, destw); + + if(alpha) + { + for(y = 0; y < desth; y++) + { + for(x = 0; x < destw; x++) + { + a = (int)desta[y][x]; + r = (int)destr[y][x]; + g = (int)destg[y][x]; + b = (int)destb[y][x]; + + if(a < 0) + { + a = 0; + } + else if(a > 255) + { + a = 255; + } + + if(r < 0) + { + r = 0; + } + else if(r > 255) + { + r = 255; + } + + if(g < 0) + { + g = 0; + } + else if(g > 255) + { + g = 255; + } + + if(b < 0) + { + b = 0; + } + else if(b > 255) + { + b = 255; + } + + destPixels[x + y * destw] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + } + else + { + for(y = 0; y < desth; y++) + { + for(x = 0; x < destw; x++) + { + r = (int)destr[y][x]; + g = (int)destg[y][x]; + b = (int)destb[y][x]; + + if(r < 0) + { + r = 0; + } + else if(r > 255) + { + r = 255; + } + + if(g < 0) + { + g = 0; + } + else if(g > 255) + { + g = 255; + } + + if(b < 0) + { + b = 0; + } + else if(b > 255) + { + b = 255; + } + + destPixels[x + y * destw] = (r << 16) | (g << 8) | b; + } + } + } + } + catch(OutOfMemoryError oome) + { + bilinearScaleRGB(srcPixels, destPixels, srcw, srch, destw, desth, alpha); + } + catch(ArrayIndexOutOfBoundsException e) + { + } + } + + public static int[] linearArrayRGB(ArrayData v, int count) + { + if(count < 2) + { + return new int[0]; + } + + int[] colors = new int[count--]; + + int cr, cg, cb; + + int sr = (v.inta >> 16) & 0xFF; + int sg = (v.inta >> 8) & 0xFF; + int sb = v.inta & 0xFF; + + int er = (v.intb >> 16) & 0xFF; + int eg = (v.intb >> 8) & 0xFF; + int eb = v.intb & 0xFF; + + int i, j; + + for(i = 0; i <= count; i++) + { + j = count - i; + + cr = (sr * j + er * i) / count; + cg = (sg * j + eg * i) / count; + cb = (sb * j + eb * i) / count; + + colors[i] = (cr << 16) | (cg << 8) | cb; + } + + return colors; + } + + public static int[] harmonicArrayRGB(ArrayData v, int count) + { + int[] colors = new int[count--]; + + int cr, cg, cb; + + int sr = (v.inta >> 16) & 0xFF; + int sg = (v.inta >> 8) & 0xFF; + int sb = v.inta & 0xFF; + + int er = (v.intb >> 16) & 0xFF; + int eg = (v.intb >> 8) & 0xFF; + int eb = v.intb & 0xFF; + + float delta = 1.0f / (float)count; + int a, b; + + for(int i = 0; i <= count; i++) + { + b = (int)(delta * i * 90); + a = 90 - b; + + cr = (int)(sr * sin(a) * sin(a) + er * sin(b) * sin(b)); + cg = (int)(sg * sin(a) * sin(a) + eg * sin(b) * sin(b)); + cb = (int)(sb * sin(a) * sin(a) + eb * sin(b) * sin(b)); + + colors[i] = (cr << 16) | (cg << 8) | cb; + } + + return colors; + } + + public static float[] specificArrayFloat(ArrayData v, int count) + { + float[] r = new float[count--]; + + float delta = 1.0f / (float)count; + float s, t; + + if(v.type == ArrayData.HARMONIC) + { + for(int i = 0; i <= count; i++) + { + t = delta * i; + s = 1.0f - t; + + r[i] = (v.vala * s + v.valb * t) + (v.diva * s + v.divb * t) * sin(v.inta + (int)(v.intb * t)); + } + } + else if(v.type == ArrayData.CUBIC) + { + for(int i = 0; i <= count; i++) + { + t = delta * i; + s = v.vala * (1.0f - t) + v.valb * t; + + r[i] = ((v.diva * s + v.divb) * s + v.divc) * s + v.divd; + } + } + else + { + for(int i = 0; i <= count; i++) + { + t = delta * i; + s = 1.0f - t; + + r[i] = v.vala * s + v.valb * t; + } + } + + return r; + } + + public static int[] specificArrayInt(ArrayData v, int count) + { + int[] r = new int[count--]; + + float delta = 1.0f / (float)count; + float s, t; + + if(v.type == ArrayData.HARMONIC) + { + for(int i = 0; i <= count; i++) + { + t = delta * i; + s = 1.0f - t; + + r[i] = (int)((v.vala * s + v.valb * t) + (v.diva * s + v.divb * t) * sin(v.inta + (int)(v.intb * t))); + } + } + else if(v.type == ArrayData.CUBIC) + { + for(int i = 0; i <= count; i++) + { + t = delta * i; + s = v.vala * (1.0f - t) + v.valb * t; + + r[i] = (int)(((v.diva * s + v.divb) * s + v.divc) * s + v.divd); + } + } + else + { + for(int i = 0; i <= count; i++) + { + t = delta * i; + s = 1.0f - t; + + r[i] = (int)(v.inta * s + v.intb * t); + } + } + + return r; + } + + public static float[] plotThickLine(float x1, float y1, float x2, float y2, float thickness, boolean processend) + { + float[] r = new float[processend ? 14 : 8]; // tl, bl, tr, br, e1, e2 + + thickness /= 2; + + float dx, dy; + + if(x1 != x2 || y1 != y2) + { + dx = thickness * sin(x2 - x1, y2 - y1); + dy = thickness * cos(x2 - x1, y2 - y1); + } + else + { + dx = dy = 0; + } + + r[0] = x1 - dx; + r[1] = y1 + dy; + + r[2] = x1 + dx; + r[3] = y1 - dy; + + r[4] = x2 - dx; + r[5] = y2 + dy; + + r[6] = x2 + dx; + r[7] = y2 - dy; + + if(processend) + { + r[8] = x1; + r[9] = y1; + r[10] = x2; + r[11] = y2; + r[12] = thickness; + r[13] = thickness; + } + + return r; + } + + public static float[] plotRotRect(float x, float y, float width, float height, int angle) + { + float[] r = new float[8]; // x1, y1, x2, y2, x3, y3, x4, y4 + + width /= 2; + height /= 2; + + float wc = width * cos(angle); + float ws = width * sin(angle); + float hc = height * cos(angle); + float hs = height * sin(angle); + + r[0] = x - wc - hs; + r[1] = y + ws - hc; + + r[2] = x - wc + hs; + r[3] = y + ws + hc; + + r[4] = x + wc - hs; + r[5] = y - ws - hc; + + r[6] = x + wc + hs; + r[7] = y - ws + hc; + + return r; + } + + public static int linearFunctionRGB(ArrayData v, float t) + { + float s = 1.0f - t; + + return ((int)(((v.inta >> 16) & 0xFF) * s + ((v.intb >> 16) & 0xFF) * t) << 16) | + ((int)(((v.inta >> 8) & 0xFF) * s + ((v.intb >> 8) & 0xFF) * t) << 8) | + (int)((v.inta & 0xFF) * s + (v.intb & 0xFF) * t); + } + + public static float specificFunctionFloat(ArrayData v, float t) + { + if(v.type == ArrayData.HARMONIC) + { + return (v.vala * (1.0f - t) + v.valb * t) + (v.diva * (1.0f - t) + v.divb * t) * sin(v.inta + (int)(v.intb * t)); + } + else if(v.type == ArrayData.CUBIC) + { + t = v.vala * (1.0f - t) + v.valb * t; + return ((v.diva * t + v.divb) * t + v.divc) * t + v.divd; + } + else + { + return v.vala * (1.0f - t) + v.valb * t; + } + } + + public static int specificFunctionInt(ArrayData v, float t) + { + if(v.type == ArrayData.HARMONIC) + { + return (int)((v.vala * (1.0f - t) + v.valb * t) + (v.diva * (1.0f - t) + v.divb * t) * sin(v.inta + (int)(v.intb * t))); + } + else if(v.type == ArrayData.CUBIC) + { + t = v.vala * (1.0f - t) + v.valb * t; + return (int)(((v.diva * t + v.divb) * t + v.divc) * t + v.divd); + } + else + { + return (int)(v.inta * (1.0f - t) + v.intb * t); + } + } + + public static float cubicMagnitude(ArrayData v) + { + float y1 = ((v.diva * v.vala + v.divb) * v.vala + v.divc) * v.vala; + float y2 = ((v.diva * v.valb + v.divb) * v.valb + v.divc) * v.valb; + + if(v.diva != 0) + { + float d = 4 * v.divb * v.divb - 12 * v.diva * v.divc; + + if(d < 0) + { + return Math.abs(y2 - y1); + } + else + { + d = (float)Math.sqrt(d); + + float e1 = -(v.divb + d) / 3 / v.diva; + float e2 = -(v.divb - d) / 3 / v.diva; + + float y3 = ((v.diva * e1 + v.divb) * e1 + v.divc) * e1; + float y4 = ((v.diva * e2 + v.divb) * e2 + v.divc) * e2; + + return Math.max(y1, Math.max(y2, Math.max(y3, y4))) - Math.min(y1, Math.min(y2, Math.min(y3, y4))); + } + } + else if(v.divb != 0) + { + float e1 = -v.divc / 2 / v.divb; + + float y3 = ((v.diva * e1 + v.divb) * e1 + v.divc) * e1; + + return Math.max(y1, Math.max(y2, y3)) - Math.min(y1, Math.min(y2, y3)); + } + else if(v.divc != 0) + { + return Math.abs(y2 - y1); + } + else + { + return 0.0f; + } + } + + public static ArrayData fitCubicInRange(ArrayData v, float y1, float y2) + { + float k = (y2 - y1) / cubicMagnitude(v); + float c = y1 - ((v.diva * v.vala + v.divb) * v.vala + v.divc) * v.vala; + + return new ArrayData(v.vala, v.valb, v.diva * k, v.divb * k, v.divc * k, c); + } + + public static float[][] plotBezierCurve(float[][] points, int count) + { + if(points.length < 2 || count <= 0) + { + return new float[0][2]; + } + + int i, n; + + float[] coefs = new float[points.length]; + coefs[0] = 1.0f; + + for(n = 1; n < coefs.length; n++) + { + for(i = n; i > 0; i--) + { + coefs[i] = coefs[i] + coefs[i - 1]; + } + } + + float delta = 1.0f / (float)count; + float param; + float value; + + int maxpower = points.length - 1; + + float[][] data = new float[count--][2]; + + data[0][0] = points[0][0]; + data[0][1] = points[0][1]; + data[data.length - 1][0] = points[points.length - 1][0]; + data[data.length - 1][1] = points[points.length - 1][1]; + + for(i = 1; i < count; i++) + { + data[i][0] = 0.0f; + data[i][1] = 0.0f; + + param = delta * i; + + for(n = 0; n <= maxpower; n++) + { + value = coefs[n] * power(param, n) * power(1.0f - param, maxpower - n); + + data[i][0] += points[n][0] * value; + data[i][1] += points[n][1] * value; + } + } + + return data; + } + + public static float[][] plotPolygon(float x, float y, float width, float height, int count, int rot, int angle) + { + if(count <= 0) + { + return new float[0][2]; + } + + float[][] data = new float[count][2]; + + int sec = 360 / count; + int cur = rot; + + width /= 2; + height /= 2; + + for(int i = 0; i < count; i++) + { + data[i] = rotate(x + width * cos(cur), y - height * sin(cur), x, y, angle); + cur += sec; + } + + return data; + } + + public static int hypot(int x, int y) + { + return (int)Math.sqrt(x * x + y * y); + } + + public static int normAngle(int angle) + { + while(angle < 0) + { + angle += 360; + } + + angle %= 360; + + if(angle == 0) + { + angle = 360; + } + + return angle; + } + + public static int toDegrees(float rads) + { + return (int)((rads * 180) / PI); + } + + public static float atan(float x) + { + float lo; + float hi; + + boolean negative = x < 0; + + if(negative) + { + x = -x; + } + + if(x >= TWO_66) + { + return negative ? -PI / 2 : PI / 2; + } + + if(!(x >= 0.4375)) // |x|<7/16, or NaN. + { + if(!(x >= 1 / TWO_29)) // Small, or NaN. + { + return negative ? -x : x; + } + + lo = hi = 0; + } + else if(x < 1.1875) + { + if(x < 0.6875) // 7/16<=|x|<11/16. + { + x = (2 * x - 1) / (2 + x); + + hi = ATAN_0_5H; + lo = ATAN_0_5L; + } + else // 11/16<=|x|<19/16. + { + x = (x - 1) / (x + 1); + + hi = PI / 4; + lo = PI_L / 4; + } + } + else if(x < 2.4375) // 19/16<=|x|<39/16. + { + x = (x - 1.5f) / (1 + 1.5f * x); + + hi = ATAN_1_5H; + lo = ATAN_1_5L; + } + else // 39/16<=|x|<2**66. + { + x = -1 / x; + + hi = PI / 2; + lo = PI_L / 2; + } + + // Break sum from i=0 to 10 ATi*z**(i+1) into odd and even poly. + + float z = x * x; + float w = z * z; + float s1 = z * (AT0 + w * (AT2 + w * (AT4 + w * (AT6 + w * (AT8 + w * AT10))))); + float s2 = w * (AT1 + w * (AT3 + w * (AT5 + w * (AT7 + w * AT9)))); + + if(hi == 0) + { + return negative ? x * (s1 + s2) - x : x - x * (s1 + s2); + } + + z = hi - ((x * (s1 + s2) - lo) - x); + + return negative ? -z : z; + } + + public static float atan2(float y, float x) + { + if(x != x || y != y) + { + return Float.NaN; + } + + if(x == 1) + { + return atan(y); + } + + if(x == Float.POSITIVE_INFINITY) + { + if(y == Float.POSITIVE_INFINITY) + { + return PI / 4; + } + + if(y == Float.NEGATIVE_INFINITY) + { + return -PI / 4; + } + + return 0 * y; + } + + if(x == Float.NEGATIVE_INFINITY) + { + if(y == Float.POSITIVE_INFINITY) + { + return 3 * PI / 4; + } + + if(y == Float.NEGATIVE_INFINITY) + { + return -3 * PI / 4; + } + + return (1 / (0 * y) == Float.POSITIVE_INFINITY) ? PI : -PI; + } + + if(y == 0) + { + if(1 / (0 * x) == Float.POSITIVE_INFINITY) + { + return y; + } + + return (1 / y == Float.POSITIVE_INFINITY) ? PI : -PI; + } + + if(y == Float.POSITIVE_INFINITY || y == Float.NEGATIVE_INFINITY || x == 0) + { + return y < 0 ? -PI / 2 : PI / 2; + } + + float z = Math.abs(y / x); // Safe to do y/x. + + if(z > TWO_60) + { + z = PI / 2 + 0.5f * PI_L; + } + else if(x < 0 && z < 1 / TWO_60) + { + z = 0; + } + else + { + z = atan(z); + } + + if(x > 0) + { + return y > 0 ? z : -z; + } + + return y > 0 ? PI - (z - PI_L) : z - PI_L - PI; + } +} diff --git a/src/com/one/vector/BezierCurve.java b/src/com/one/vector/BezierCurve.java new file mode 100644 index 0000000..bacea08 --- /dev/null +++ b/src/com/one/vector/BezierCurve.java @@ -0,0 +1,240 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class BezierCurve extends VectorElement +{ + protected float[][] data; + protected int[][] sdata; + protected float[][] points; + protected int count; + + public BezierCurve() + { + points = new float[3][2]; + points[0][0] = 0; + points[0][1] = 0; + points[1][0] = 0; + points[1][1] = 0; + points[2][0] = 0; + points[2][1] = 0; + + count = 3; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + count = dis.readUnsignedShort() + 1; + + points = new float[dis.readUnsignedShort()][2]; + + for(int i = 0; i < points.length; i++) + { + points[i][0] = dis.readFloat(); + points[i][1] = dis.readFloat(); + } + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeShort(count - 1); + + dos.writeShort(points.length); + + for(int i = 0; i < points.length; i++) + { + dos.writeFloat(points[i][0]); + dos.writeFloat(points[i][1]); + } + + writeTransformList(dos); + } + + public void create() + { + data = AuxMath.plotBezierCurve(points, count); + sdata = new int[data.length][2]; + } + + public void rescale() + { + for(int i = 0; i < data.length; i++) + { + sdata[i][0] = getScaled(data[i][0], 0); + sdata[i][1] = getScaled(data[i][1], 1); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + g.setColor(color); + } + + g.setStrokeStyle(stroke); + + for(int i = 1; i < data.length; i++) + { + g.drawLine(sdata[i][0], sdata[i][1], sdata[i - 1][0], sdata[i - 1][1]); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else if(param == COLOR) + { + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + else + { + subparam = transform.getSubParam() - 1; + + if(subparam >= 0 && subparam < points.length) + { + switch(param) + { + case X: + points[subparam][0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + points[subparam][1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == COUNT) + { + return new Integer(points.length); + } + else if(param == QUALITY) + { + return new Integer(count - 1); + } + else if(param == X) + { + subparam--; + + if(subparam >= 0 && subparam < points.length) + { + return new Float(points[subparam][0]); + } + } + else if(param == Y) + { + subparam--; + + if(subparam >= 0 && subparam < points.length) + { + return new Float(points[subparam][1]); + } + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == COUNT) + { + float[][] p = new float[((Integer)value).intValue()][2]; + int minlength = Math.min(points.length, p.length); + + for(int i = 0; i < minlength; i++) + { + p[i][0] = points[i][0]; + p[i][1] = points[i][1]; + } + + points = p; + } + else if(param == QUALITY) + { + count = ((Integer)value).intValue() + 1; + } + else if(param == X) + { + subparam--; + + if(subparam >= 0 && subparam < points.length) + { + points[subparam][0] = ((Float)value).floatValue(); + } + } + else if(param == Y) + { + subparam--; + + if(subparam >= 0 && subparam < points.length) + { + points[subparam][1] = ((Float)value).floatValue(); + } + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/Bitmap.java b/src/com/one/vector/Bitmap.java new file mode 100644 index 0000000..4463976 --- /dev/null +++ b/src/com/one/vector/Bitmap.java @@ -0,0 +1,452 @@ +package com.one.vector; + +import com.one.file.Connector; +import javax.microedition.lcdui.*; +import java.io.*; + +public class Bitmap extends VectorElement +{ + public static final int MODE_NORMAL = 0; + public static final int MODE_REPEAT_X = 1; + public static final int MODE_REPEAT_Y = 2; + public static final int MODE_REPEAT_BOTH = 3; + public static final int MODE_SCALE = 4; + + public static final int DEFTEX_WIDTH = 16; + public static final int DEFTEX_HEIGHT = 16; + + public static final int FP_SHIFT = 16; + + protected Image image, scaled; + protected String filename; + protected float[] data = new float[4]; + protected int[] sdata = new int[4]; + protected int width, height; + protected int mode; + protected int repx, repy; + protected boolean usescaled; + + protected int[] clip = new int[4]; + + public Bitmap() + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + + mode = dis.readUnsignedByte(); + + System.gc(); + + try + { + if(dis.readBoolean()) + { + int blen = dis.readInt(); + byte[] b = new byte[blen]; + + dis.readFully(b); + image = Image.createImage(b, 0, blen); + + width = image.getWidth(); + height = image.getHeight(); + } + else + { + width = dis.readInt(); + height = dis.readInt(); + + int[] rgbdata = new int[width * height]; + + for(int i = 0; i < rgbdata.length; i++) + { + rgbdata[i] = dis.readInt(); + } + + image = Image.createRGBImage(rgbdata, width, height, true); + } + } + catch(OutOfMemoryError oome) + { + width = DEFTEX_WIDTH; + height = DEFTEX_HEIGHT; + + int[] rgbdata = new int[width * height]; + + for(int i = 0; i < rgbdata.length; i++) + { + rgbdata[i] = color; + } + + image = Image.createRGBImage(rgbdata, width, height, true); + } + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + + dos.writeByte(mode); + + try + { + InputStream is = Connector.openInputStream("file:///" + filename); + + byte[] b = new byte[4096]; + + dos.writeBoolean(true); + dos.writeInt(is.available()); + + while(is.available() > 0) + { + dos.write(b, 0, is.read(b)); + } + + is.close(); + } + catch(Exception e) + { + System.gc(); + + try + { + int[] rgbdata = new int[width * height]; + image.getRGB(rgbdata, 0, width, 0, 0, width, height); + + dos.writeBoolean(false); + dos.writeInt(width); + dos.writeInt(height); + + for(int i = 0; i < rgbdata.length; i++) + { + dos.writeInt(rgbdata[i]); + } + } + catch(OutOfMemoryError oome) + { + dos.writeBoolean(false); + dos.writeInt(DEFTEX_WIDTH); + dos.writeInt(DEFTEX_HEIGHT); + + for(int i = 0, len = DEFTEX_WIDTH * DEFTEX_HEIGHT; i < len; i++) + { + dos.writeInt(color); + } + } + } + + writeTransformList(dos); + } + + public void create() + { + if(image == null) + { + try + { + InputStream is = Connector.openInputStream("file:///" + filename); + image = Image.createImage(is); + is.close(); + + width = image.getWidth(); + height = image.getHeight(); + } + catch(Exception e) + { + width = DEFTEX_WIDTH; + height = DEFTEX_HEIGHT; + + int[] rgbdata = new int[width * height]; + + for(int i = 0; i < rgbdata.length; i++) + { + rgbdata[i] = color; + } + + image = Image.createRGBImage(rgbdata, width, height, true); + } + } + } + + public void rescale() + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + sdata[2] = getScaled(data[2], 2); + sdata[3] = getScaled(data[3], 3); + + if(mode == MODE_REPEAT_X) + { + repx = (sdata[2] + width - 1) / width; + repy = 1; + + usescaled = false; + scaled = null; + } + else if(mode == MODE_REPEAT_Y) + { + repx = 1; + repy = (sdata[3] + height - 1) / height; + + usescaled = false; + scaled = null; + } + else if(mode == MODE_REPEAT_BOTH) + { + repx = (sdata[2] + width - 1) / width; + repy = (sdata[3] + height - 1) / height; + + usescaled = false; + scaled = null; + } + else if(mode == MODE_SCALE) + { + if(image != null && (sdata[2] != width || sdata[3] != height)) + { + if(scaled == null || scaled.getWidth() != sdata[2] || scaled.getHeight() != sdata[3]) + { + scaled = Image.createImage(sdata[2], sdata[3]); + Graphics g = scaled.getGraphics(); + + int[] src = null; + int[] dst = null; + int fragcount = 1; + int srcfw, srcfh; + int dstfw, dstfh; + + do + { + srcfw = width / fragcount; + srcfh = height / fragcount; + dstfw = sdata[2] / fragcount; + dstfh = sdata[3] / fragcount; + + try + { + src = new int[srcfw * srcfh]; + dst = new int[dstfw * dstfh]; + } + catch(OutOfMemoryError oome) + { + src = null; + dst = null; + fragcount++; + } + } + while(src == null || dst == null); + + int fx, fy; + + for(fx = 0; fx < fragcount; fx++) + { + for(fy = 0; fy < fragcount; fy++) + { + image.getRGB(src, 0, srcfw, fx * srcfw, fy * srcfh, srcfw, srcfh); + + if(dstfw > srcfw || dstfh > srcfh) + { + AuxMath.bicubicScaleRGB(src, dst, srcfw, srcfh, dstfw, dstfh, false); + } + else + { + AuxMath.scaleRGB(src, dst, srcfw, srcfh, dstfw, dstfh, false); + } + + g.drawRGB(dst, 0, dstfw, fx * dstfw, fy * dstfh, dstfw, dstfh, false); + } + } + } + + usescaled = true; + } + else + { + repx = 1; + repy = 1; + + usescaled = false; + } + } + else + { + repx = 1; + repy = 1; + + usescaled = false; + scaled = null; + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + if(usescaled && scaled != null) + { + g.drawImage(scaled, sdata[0], sdata[1], Graphics.LEFT | Graphics.TOP); + } + else if(image != null) + { + clip[0] = g.getClipX(); + clip[1] = g.getClipY(); + clip[2] = g.getClipWidth(); + clip[3] = g.getClipHeight(); + + g.clipRect(sdata[0], sdata[1], sdata[2], sdata[3]); + + for(int i = 0; i < repx; i++) + { + for(int j = 0; j < repy; j++) + { + g.drawImage(image, sdata[0] + i * width, sdata[1] + j * height, Graphics.LEFT | Graphics.TOP); + } + } + + g.setClip(clip[0], clip[1], clip[2], clip[3]); + } + else + { + g.setColor(color); + g.fillRect(sdata[0], sdata[1], sdata[2], sdata[3]); + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(data[0]); + + case Y: + return new Float(data[1]); + + case WIDTH: + return new Float(data[2]); + + case HEIGHT: + return new Float(data[3]); + + case MODE: + return new Integer(mode); + + case FILE: + return filename; + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + data[0] = ((Float)value).floatValue(); + break; + + case Y: + data[1] = ((Float)value).floatValue(); + break; + + case WIDTH: + data[2] = ((Float)value).floatValue(); + break; + + case HEIGHT: + data[3] = ((Float)value).floatValue(); + break; + + case MODE: + mode = ((Integer)value).intValue(); + break; + + case FILE: + filename = (String)value; + image = null; + scaled = null; + break; + } + } +} diff --git a/src/com/one/vector/BitwiseFunction.java b/src/com/one/vector/BitwiseFunction.java new file mode 100644 index 0000000..32c4aa7 --- /dev/null +++ b/src/com/one/vector/BitwiseFunction.java @@ -0,0 +1,92 @@ +package com.one.vector; + +import java.io.*; + +public class BitwiseFunction extends Effect +{ + public static final int OR = 0; + public static final int XOR = 1; + public static final int AND = 2; + + public static final String[] FUNCTIONS = + { + "OR", "XOR", "AND" + }; + + protected int type; + protected int value; + + public BitwiseFunction() + { + type = OR; + value = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + hidden = dis.readBoolean(); + + type = dis.readUnsignedByte(); + value = dis.readInt(); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeBoolean(hidden); + + dos.writeByte(type); + dos.writeInt(value); + } + + public void apply(int[] rgb, int[] temp, int width, int height) + { + if(hidden) + { + return; + } + + if(type == OR) + { + for(int i = 0; i < rgb.length; i++) + { + rgb[i] |= value; + } + } + else if(type == XOR) + { + for(int i = 0; i < rgb.length; i++) + { + rgb[i] ^= value; + } + } + else if(type == AND) + { + for(int i = 0; i < rgb.length; i++) + { + rgb[i] &= value; + } + } + } + + public void setType(int type) + { + this.type = type; + } + + public void setValue(int value) + { + this.value = value; + } + + public int getType() + { + return type; + } + + public int getValue() + { + return value; + } +} diff --git a/src/com/one/vector/ChannelMatrix.java b/src/com/one/vector/ChannelMatrix.java new file mode 100644 index 0000000..3836c31 --- /dev/null +++ b/src/com/one/vector/ChannelMatrix.java @@ -0,0 +1,187 @@ +package com.one.vector; + +import java.io.*; + +public class ChannelMatrix extends Effect +{ + protected int[][] factors = new int[4][4]; + protected int[] divisors = new int[4]; + protected int[] offsets = new int[4]; + + protected int[] values = new int[4]; + + public ChannelMatrix() + { + factors[0][0] = 1; + factors[1][1] = 1; + factors[2][2] = 1; + factors[3][3] = 1; + + divisors[0] = 1; + divisors[1] = 1; + divisors[2] = 1; + divisors[3] = 1; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + hidden = dis.readBoolean(); + + factors[0][0] = dis.readInt(); + factors[0][1] = dis.readInt(); + factors[0][2] = dis.readInt(); + factors[0][3] = dis.readInt(); + factors[1][0] = dis.readInt(); + factors[1][1] = dis.readInt(); + factors[1][2] = dis.readInt(); + factors[1][3] = dis.readInt(); + factors[2][0] = dis.readInt(); + factors[2][1] = dis.readInt(); + factors[2][2] = dis.readInt(); + factors[2][3] = dis.readInt(); + factors[3][0] = dis.readInt(); + factors[3][1] = dis.readInt(); + factors[3][2] = dis.readInt(); + factors[3][3] = dis.readInt(); + + divisors[0] = dis.readInt(); + divisors[1] = dis.readInt(); + divisors[2] = dis.readInt(); + divisors[3] = dis.readInt(); + + offsets[0] = dis.readInt(); + offsets[1] = dis.readInt(); + offsets[2] = dis.readInt(); + offsets[3] = dis.readInt(); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeBoolean(hidden); + + dos.writeInt(factors[0][0]); + dos.writeInt(factors[0][1]); + dos.writeInt(factors[0][2]); + dos.writeInt(factors[0][3]); + dos.writeInt(factors[1][0]); + dos.writeInt(factors[1][1]); + dos.writeInt(factors[1][2]); + dos.writeInt(factors[1][3]); + dos.writeInt(factors[2][0]); + dos.writeInt(factors[2][1]); + dos.writeInt(factors[2][2]); + dos.writeInt(factors[2][3]); + dos.writeInt(factors[3][0]); + dos.writeInt(factors[3][1]); + dos.writeInt(factors[3][2]); + dos.writeInt(factors[3][3]); + + dos.writeInt(divisors[0]); + dos.writeInt(divisors[1]); + dos.writeInt(divisors[2]); + dos.writeInt(divisors[3]); + + dos.writeInt(offsets[0]); + dos.writeInt(offsets[1]); + dos.writeInt(offsets[2]); + dos.writeInt(offsets[3]); + } + + public void apply(int[] rgb, int[] temp, int width, int height) + { + if(hidden) + { + return; + } + + int a, r, g, b; + + for(int i = 0; i < rgb.length; i++) + { + a = (rgb[i] >> 24) & 0xFF; + r = (rgb[i] >> 16) & 0xFF; + g = (rgb[i] >> 8) & 0xFF; + b = rgb[i] & 0xFF; + + values[0] = (a * factors[0][0] + r * factors[1][0] + g * factors[2][0] + b * factors[3][0]) / divisors[0] + offsets[0]; + values[1] = (a * factors[0][1] + r * factors[1][1] + g * factors[2][1] + b * factors[3][1]) / divisors[1] + offsets[1]; + values[2] = (a * factors[0][2] + r * factors[1][2] + g * factors[2][2] + b * factors[3][2]) / divisors[2] + offsets[2]; + values[3] = (a * factors[0][3] + r * factors[1][3] + g * factors[2][3] + b * factors[3][3]) / divisors[3] + offsets[3]; + + a = values[0]; + r = values[1]; + g = values[2]; + b = values[3]; + + if(a < 0) + { + a = 0; + } + else if(a > 255) + { + a = 255; + } + + if(r < 0) + { + r = 0; + } + else if(r > 255) + { + r = 255; + } + + if(g < 0) + { + g = 0; + } + else if(g > 255) + { + g = 255; + } + + if(b < 0) + { + b = 0; + } + else if(b > 255) + { + b = 255; + } + + rgb[i] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + + public void setFactor(int srcchannel, int dstchannel, int value) + { + factors[srcchannel][dstchannel] = value; + } + + public void setDivisor(int dstchannel, int value) + { + divisors[dstchannel] = value; + } + + public void setOffset(int dstchannel, int value) + { + offsets[dstchannel] = value; + } + + public int getFactor(int srcchannel, int dstchannel) + { + return factors[srcchannel][dstchannel]; + } + + public int getDivisor(int dstchannel) + { + return divisors[dstchannel]; + } + + public int getOffset(int dstchannel) + { + return offsets[dstchannel]; + } +} diff --git a/src/com/one/vector/Clip.java b/src/com/one/vector/Clip.java new file mode 100644 index 0000000..d5d2eb3 --- /dev/null +++ b/src/com/one/vector/Clip.java @@ -0,0 +1,172 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class Clip extends VectorElement +{ + protected float[] data = new float[4]; + protected int[] sdata = new int[4]; + protected boolean mode; + + public Clip() + { + mode = false; + + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + + mode = dis.readBoolean(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + + dos.writeBoolean(mode); + + writeTransformList(dos); + } + + public void rescale() + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + sdata[2] = getScaled(data[2], 2); + sdata[3] = getScaled(data[3], 3); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(mode) + { + g.setClip(sdata[0], sdata[1], sdata[2], sdata[3]); + } + else + { + g.clipRect(sdata[0], sdata[1], sdata[2], sdata[3]); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case X: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(data[0]); + + case Y: + return new Float(data[1]); + + case WIDTH: + return new Float(data[2]); + + case HEIGHT: + return new Float(data[3]); + + case MODE: + return new Boolean(mode); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + data[0] = ((Float)value).floatValue(); + break; + + case Y: + data[1] = ((Float)value).floatValue(); + break; + + case WIDTH: + data[2] = ((Float)value).floatValue(); + break; + + case HEIGHT: + data[3] = ((Float)value).floatValue(); + break; + + case MODE: + mode = ((Boolean)value).booleanValue(); + break; + } + } +} diff --git a/src/com/one/vector/ColorReplace.java b/src/com/one/vector/ColorReplace.java new file mode 100644 index 0000000..25b3186 --- /dev/null +++ b/src/com/one/vector/ColorReplace.java @@ -0,0 +1,66 @@ +package com.one.vector; + +import java.io.*; + +public class ColorReplace extends Effect +{ + protected int startcolor, endcolor; + + public ColorReplace() + { + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + hidden = dis.readBoolean(); + + startcolor = dis.readInt(); + endcolor = dis.readInt(); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeBoolean(hidden); + + dos.writeInt(startcolor); + dos.writeInt(endcolor); + } + + public void apply(int[] rgb, int[] temp, int width, int height) + { + if(hidden) + { + return; + } + + for(int i = 0; i < rgb.length; i++) + { + if(rgb[i] == startcolor) + { + rgb[i] = endcolor; + } + } + } + + public void setStartColor(int color) + { + startcolor = color; + } + + public void setEndColor(int color) + { + endcolor = color; + } + + public int getStartColor() + { + return startcolor; + } + + public int getEndColor() + { + return endcolor; + } +} diff --git a/src/com/one/vector/Comment.java b/src/com/one/vector/Comment.java new file mode 100644 index 0000000..bdfdc72 --- /dev/null +++ b/src/com/one/vector/Comment.java @@ -0,0 +1,170 @@ +package com.one.vector; + +import javax.microedition.lcdui.Font; +import java.io.*; + +public class Comment +{ + protected String name; + + protected String text; + protected Font font; + + protected int backcolor; + protected int forecolor; + + protected int startframe; + protected int endframe; + + public Comment() + { + name = VectorElement.defaultName(); + + text = ""; + font = Font.getDefaultFont(); + + backcolor = 0; + forecolor = -1; + + startframe = -1; + endframe = -1; + } + + public Comment(DataInputStream dis) throws IOException + { + read(dis); + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + + text = dis.readUTF(); + font = Font.getFont(dis.readInt(), dis.readInt(), dis.readInt()); + + backcolor = dis.readInt(); + forecolor = dis.readInt(); + + startframe = dis.readInt(); + endframe = dis.readInt(); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + + dos.writeUTF(text); + + dos.writeInt(font.getFace()); + dos.writeInt(font.getStyle()); + dos.writeInt(font.getSize()); + + dos.writeInt(backcolor); + dos.writeInt(forecolor); + + dos.writeInt(startframe); + dos.writeInt(endframe); + } + + public void setName(String nm) + { + if(nm != null) + { + name = nm; + } + else + { + name = VectorElement.defaultName(); + } + } + + public String getName() + { + return name; + } + + public void setText(String txt) + { + if(txt != null) + { + text = txt; + } + else + { + text = ""; + } + } + + public String getText() + { + return text; + } + + public void setFont(Font font) + { + this.font = font; + } + + public Font getFont() + { + return font; + } + + public void setColor(int backcolor, int forecolor) + { + this.backcolor = backcolor; + this.forecolor = forecolor; + } + + public int getBackColor() + { + return backcolor; + } + + public int getForeColor() + { + return forecolor; + } + + public void setBounds(int startframe, int endframe) + { + this.startframe = startframe; + this.endframe = endframe; + } + + public int getStartFrame() + { + return startframe; + } + + public int getEndFrame() + { + return endframe; + } + + public boolean isVisible(int frame) + { + if(startframe < 0) + { + return false; + } + else + { + if(endframe < 0) + { + return true; + } + else + { + if(frame >= startframe && frame <= endframe) + { + return true; + } + else + { + return false; + } + } + } + } +} diff --git a/src/com/one/vector/Effect.java b/src/com/one/vector/Effect.java new file mode 100644 index 0000000..91499c5 --- /dev/null +++ b/src/com/one/vector/Effect.java @@ -0,0 +1,115 @@ +package com.one.vector; + +import java.io.*; + +public abstract class Effect +{ + public static final int COLOR_REPLACE = 0, + AREA_FILL = 1, + LINE_FILL = 2, + CHANNEL_MATRIX = 3, + PIXEL_MATRIX = 4, + BITWISE_FUNCTION = 5; + + protected String name; + protected boolean hidden; + + public Effect() + { + name = VectorElement.defaultName(); + hidden = false; + } + + public abstract void read(DataInputStream dis) throws IOException; + public abstract void write(DataOutputStream dos) throws IOException; + + public abstract void apply(int[] rgb, int[] temp, int width, int height); + + public void setName(String nm) + { + if(nm != null) + { + name = nm; + } + else + { + name = VectorElement.defaultName(); + } + } + + public String getName() + { + return name; + } + + public void setHidden(boolean hidden) + { + this.hidden = hidden; + } + + public boolean isHidden() + { + return hidden; + } + + public static Effect getInstance(int type) + { + switch(type) + { + case COLOR_REPLACE: + return new ColorReplace(); + + case AREA_FILL: + return new AreaFill(); + + case LINE_FILL: + return new LineFill(); + + case CHANNEL_MATRIX: + return new ChannelMatrix(); + + case PIXEL_MATRIX: + return new PixelMatrix(); + + case BITWISE_FUNCTION: + return new BitwiseFunction(); + + default: + //throw new IllegalArgumentException("Unknown effect type: " + Integer.toString(type)); + throw new IllegalArgumentException(); + } + } + + public static int effectType(Effect effect) + { + if(effect instanceof ColorReplace) + { + return COLOR_REPLACE; + } + else if(effect instanceof AreaFill) + { + return AREA_FILL; + } + else if(effect instanceof LineFill) + { + return LINE_FILL; + } + else if(effect instanceof ChannelMatrix) + { + return CHANNEL_MATRIX; + } + else if(effect instanceof PixelMatrix) + { + return PIXEL_MATRIX; + } + else if(effect instanceof BitwiseFunction) + { + return BITWISE_FUNCTION; + } + else + { + //throw new IllegalArgumentException("Unknown effect: " + effect.getClass().getName()); + throw new IllegalArgumentException(); + } + } +} diff --git a/src/com/one/vector/GradientCircle.java b/src/com/one/vector/GradientCircle.java new file mode 100644 index 0000000..35c1066 --- /dev/null +++ b/src/com/one/vector/GradientCircle.java @@ -0,0 +1,269 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class GradientCircle extends VectorElement +{ + protected float[][] data = new float[4][]; + protected int[][] sdata; + protected int[] colors; + protected int count; + protected ArrayData pdata; + protected int angle; + + public GradientCircle() + { + pdata = new ArrayData(); + pdata.type = ArrayData.HARMONIC; + + count = 3; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + parseFlag(dis.readUnsignedByte()); + + pdata = new ArrayData(dis); + angle = dis.readShort(); + count = dis.readUnsignedShort() + 1; + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeByte(getFlag()); + + pdata.write(dos); + dos.writeShort(angle); + dos.writeShort(count - 1); + + writeTransformList(dos); + } + + public void create() + { + float x = pdata.vala; + float y = pdata.valb; + float width = pdata.diva / 2; + float height = -pdata.divb / 2; + + data[0] = AuxMath.specificArrayFloat(new ArrayData(x, x, width, width, angle + 270, -180), count); + data[1] = AuxMath.specificArrayFloat(new ArrayData(y, y, height, height, angle + 180, -180), count); + data[2] = AuxMath.specificArrayFloat(new ArrayData(x, x, width, width, angle + 270, 180), count); + data[3] = AuxMath.specificArrayFloat(new ArrayData(y, y, height, height, angle + 180, 180), count); + + colors = AuxMath.harmonicArrayRGB(new ArrayData(pdata.inta, pdata.intb), count - 1); + + sdata = new int[4][count]; + } + + public void rescale() + { + for(int i = 0; i < count; i++) + { + sdata[0][i] = getScaled(data[0][i], 0); + sdata[1][i] = getScaled(data[1][i], 1); + sdata[2][i] = getScaled(data[2][i], 0); + sdata[3][i] = getScaled(data[3][i], 1); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + for(int i = 1; i < count; i++) + { + g.setColor(colors[i - 1]); + + g.fillTriangle(sdata[0][i], sdata[1][i], sdata[0][i - 1], sdata[1][i - 1], sdata[2][i - 1], sdata[3][i - 1]); + g.fillTriangle(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], sdata[2][i - 1], sdata[3][i - 1]); + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + subparam = transform.getSubParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + switch(subparam) + { + case 0: + pdata.inta = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 1: + pdata.intb = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + + case X: + pdata.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + pdata.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + pdata.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + pdata.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case ANGLE: + angle = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case COLOR: + if(subparam == 0) + { + return new Integer(pdata.inta); + } + else if(subparam == 1) + { + return new Integer(pdata.intb); + } + else + { + return null; + } + + case X: + return new Float(pdata.vala); + + case Y: + return new Float(pdata.valb); + + case WIDTH: + return new Float(pdata.diva); + + case HEIGHT: + return new Float(pdata.divb); + + case ANGLE: + return new Integer(angle); + + case QUALITY: + return new Integer(count - 1); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case COLOR: + if(subparam == 0) + { + pdata.inta = ((Integer)value).intValue(); + } + else if(subparam == 1) + { + pdata.intb = ((Integer)value).intValue(); + } + break; + + case X: + pdata.vala = ((Float)value).floatValue(); + break; + + case Y: + pdata.valb = ((Float)value).floatValue(); + break; + + case WIDTH: + pdata.diva = ((Float)value).floatValue(); + break; + + case HEIGHT: + pdata.divb = ((Float)value).floatValue(); + break; + + case ANGLE: + angle = ((Integer)value).intValue(); + break; + + case QUALITY: + count = ((Integer)value).intValue() + 1; + break; + } + } + + public void writeSVG(PrintStream ps) + { + ps.println("\t\t\t"); + + for(int i = 1; i < count; i++) + { + ps.print("\t\t\t\t"); + } + + ps.println("\t\t\t"); + } +} diff --git a/src/com/one/vector/GradientRect.java b/src/com/one/vector/GradientRect.java new file mode 100644 index 0000000..a52cddd --- /dev/null +++ b/src/com/one/vector/GradientRect.java @@ -0,0 +1,266 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class GradientRect extends VectorElement +{ + protected float[][] data = new float[4][]; + protected int[][] sdata; + protected int[] colors; + protected int count; + protected ArrayData pdata; + protected int angle; + + public GradientRect() + { + pdata = new ArrayData(); + pdata.type = ArrayData.HARMONIC; + + count = 3; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + parseFlag(dis.readUnsignedByte()); + + pdata = new ArrayData(dis); + angle = dis.readShort(); + count = dis.readUnsignedShort() + 1; + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeByte(getFlag()); + + pdata.write(dos); + dos.writeShort(angle); + dos.writeShort(count - 1); + + writeTransformList(dos); + } + + public void create() + { + float[] r = AuxMath.plotRotRect(pdata.vala, pdata.valb, pdata.diva, pdata.divb, angle); + + data[0] = AuxMath.specificArrayFloat(new ArrayData(r[0], r[4]), count); + data[1] = AuxMath.specificArrayFloat(new ArrayData(r[1], r[5]), count); + data[2] = AuxMath.specificArrayFloat(new ArrayData(r[2], r[6]), count); + data[3] = AuxMath.specificArrayFloat(new ArrayData(r[3], r[7]), count); + + colors = AuxMath.linearArrayRGB(new ArrayData(pdata.inta, pdata.intb), count - 1); + + sdata = new int[4][count]; + } + + public void rescale() + { + for(int i = 0; i < count; i++) + { + sdata[0][i] = getScaled(data[0][i], 0); + sdata[1][i] = getScaled(data[1][i], 1); + sdata[2][i] = getScaled(data[2][i], 0); + sdata[3][i] = getScaled(data[3][i], 1); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + for(int i = 1; i < count; i++) + { + g.setColor(colors[i - 1]); + + g.fillTriangle(sdata[0][i], sdata[1][i], sdata[0][i - 1], sdata[1][i - 1], sdata[2][i - 1], sdata[3][i - 1]); + g.fillTriangle(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], sdata[2][i - 1], sdata[3][i - 1]); + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + subparam = transform.getSubParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + switch(subparam) + { + case 0: + pdata.inta = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 1: + pdata.intb = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + + case X: + pdata.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + pdata.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + pdata.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + pdata.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case ANGLE: + angle = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case COLOR: + if(subparam == 0) + { + return new Integer(pdata.inta); + } + else if(subparam == 1) + { + return new Integer(pdata.intb); + } + else + { + return null; + } + + case X: + return new Float(pdata.vala); + + case Y: + return new Float(pdata.valb); + + case WIDTH: + return new Float(pdata.diva); + + case HEIGHT: + return new Float(pdata.divb); + + case ANGLE: + return new Integer(angle); + + case QUALITY: + return new Integer(count - 1); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case COLOR: + if(subparam == 0) + { + pdata.inta = ((Integer)value).intValue(); + } + else if(subparam == 1) + { + pdata.intb = ((Integer)value).intValue(); + } + break; + + case X: + pdata.vala = ((Float)value).floatValue(); + break; + + case Y: + pdata.valb = ((Float)value).floatValue(); + break; + + case WIDTH: + pdata.diva = ((Float)value).floatValue(); + break; + + case HEIGHT: + pdata.divb = ((Float)value).floatValue(); + break; + + case ANGLE: + angle = ((Integer)value).intValue(); + break; + + case QUALITY: + count = ((Integer)value).intValue() + 1; + break; + } + } + + public void writeSVG(PrintStream ps) + { + ps.println("\t\t\t"); + + for(int i = 1; i < count; i++) + { + ps.print("\t\t\t\t"); + } + + ps.println("\t\t\t"); + } +} diff --git a/src/com/one/vector/Group.java b/src/com/one/vector/Group.java new file mode 100644 index 0000000..8903e6f --- /dev/null +++ b/src/com/one/vector/Group.java @@ -0,0 +1,560 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.util.Vector; +import java.util.Enumeration; +import java.lang.Math; +import java.io.*; + +public class Group extends VectorElement +{ + public VectorImage image; + + protected Vector effects; + + protected Vector elements; + protected int count; + + protected float[] data = new float[4]; + + public float[] param = new float[7]; + + protected int[] clip = new int[4]; + + public Group(DataInputStream dis) throws IOException + { + image = DEFAULT_IMAGE; + read(dis); + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + + param[0] = dis.readFloat(); + param[1] = dis.readFloat(); + param[4] = dis.readFloat(); + param[5] = dis.readFloat(); + + count = dis.readUnsignedShort(); + elements = new Vector(count); + + VectorElement ve; + + for(int i = 0; i < count; i++) + { + ve = VectorElement.getInstance(dis.readUnsignedByte()); + ve.read(dis); + + ve.create(); + ve.setGroup(this); + elements.addElement(ve); + } + + int fxcount = dis.readUnsignedShort(); + effects = new Vector(fxcount); + + Effect effect; + + for(int i = 0; i < fxcount; i++) + { + effect = Effect.getInstance(dis.readUnsignedByte()); + effect.read(dis); + + effects.addElement(effect); + } + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + + dos.writeFloat(param[0]); + dos.writeFloat(param[1]); + dos.writeFloat(param[4]); + dos.writeFloat(param[5]); + + dos.writeShort(count); + + VectorElement ve; + + for(int i = 0; i < count; i++) + { + ve = (VectorElement)elements.elementAt(i); + + dos.writeByte(VectorElement.elementType(ve)); + ve.write(dos); + } + + dos.writeShort(effects.size()); + + Effect effect; + + for(int i = 0; i < effects.size(); i++) + { + effect = (Effect)effects.elementAt(i); + + dos.writeByte(Effect.effectType(effect)); + effect.write(dos); + } + + writeTransformList(dos); + } + + public Group() + { + image = DEFAULT_IMAGE; + + color = 0xFF000000; + + data[0] = 0; + data[1] = 0; + data[2] = 1; + data[3] = 1; + + param[0] = 0; + param[1] = 0; + param[2] = 1; + param[3] = 1; + param[4] = 1; + param[5] = 1; + param[6] = 1; + + elements = new Vector(); + count = 0; + + effects = new Vector(); + } + + public void addElement(VectorElement ve) + { + ve.setName(image.nextElementName(elementType(ve))); + ve.setGroup(this); + ve.rescale(); + + elements.addElement(ve); + count = elements.size(); + } + + public void create() + { + for(int i = 0; i < count; i++) + { + ((VectorElement)elements.elementAt(i)).create(); + } + } + + public void rescale() + { + rescale(true); + } + + public void rescale(boolean flag) + { + param[2] = (1.0f / param[4]) * image.width; + param[3] = (1.0f / param[5]) * image.height; + + param[6] = (float)Math.sqrt((double)((param[2] * param[2] + param[3] * param[3]) / 2.0f)); + + if(flag) + { + for(int i = 0; i < count; i++) + { + ((VectorElement)elements.elementAt(i)).rescale(); + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int transparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(image.frame); + + if(transform.isApplied()) + { + transparam = transform.getParam(); + + switch(transparam) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + break; + + case Y: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + break; + + case WIDTH: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + break; + + case HEIGHT: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + break; + + case OFFSET_X: + param[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case OFFSET_Y: + param[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case SCALE_X: + param[4] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case SCALE_Y: + param[5] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + rescale(false); + } + + for(int i = 0; i < count; i++) + { + ((VectorElement)elements.elementAt(i)).update(flag, changed); + } + } + + public int getTranslateX() + { + return getScaled(data[0], 0); + } + + public int getTranslateY() + { + return getScaled(data[1], 1); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + clip[0] = g.getClipX(); + clip[1] = g.getClipY(); + clip[2] = g.getClipWidth(); + clip[3] = g.getClipHeight(); + + g.clipRect(getScaled(data[0], 0), getScaled(data[1], 1), getScaled(data[2], 2), getScaled(data[3], 3)); + g.translate(getScaled(data[0], 0), getScaled(data[1], 1)); + + for(int i = 0; i < count; i++) + { + ((VectorElement)elements.elementAt(i)).paint(g); + } + + g.translate(-getScaled(data[0], 0), -getScaled(data[1], 1)); + g.setClip(clip[0], clip[1], clip[2], clip[3]); + } + + public int getScaled(float v, int mode) + { + switch(mode) + { + case 0: + return (int)((v + image.param[0]) * image.param[2]); + + case 1: + return (int)((v + image.param[1]) * image.param[3]); + + case 2: + return (int)(v * image.param[2]); + + case 3: + return (int)(v * image.param[3]); + } + + return (int)v; + } + + public float getInternal(int v, int mode) + { + switch(mode) + { + case 0: + return (float)v / image.param[2] - image.param[0]; + + case 1: + return (float)v / image.param[3] - image.param[1]; + + case 2: + return (float)v / image.param[2]; + + case 3: + return (float)v / image.param[3]; + } + + return (float)v; + } + + public void setImage(VectorImage img) + { + if(img != null) + { + image = img; + } + else + { + image = DEFAULT_IMAGE; + } + } + + public VectorImage getImage() + { + return image; + } + + public Enumeration listElements() + { + return elements.elements(); + } + + public VectorElement getElement(String name) + { + VectorElement element; + + for(int i = 0; i < count; i++) + { + element = (VectorElement)elements.elementAt(i); + + if(element.getName().equals(name)) + { + return element; + } + } + + return null; + } + + public VectorElement getNextElement(VectorElement current) + { + for(int i = 0; i < count; i++) + { + if(elements.elementAt(i) == current) + { + if(i == count - 1) + { + return (VectorElement)elements.elementAt(0); + } + else + { + return (VectorElement)elements.elementAt(i + 1); + } + } + } + + return current; + } + + public VectorElement getPreviousElement(VectorElement current) + { + for(int i = 0; i < count; i++) + { + if(elements.elementAt(i) == current) + { + if(i == 0) + { + return (VectorElement)elements.elementAt(count - 1); + } + else + { + return (VectorElement)elements.elementAt(i - 1); + } + } + } + + return current; + } + + public void deleteElement(VectorElement ve) + { + elements.removeElement(ve); + count = elements.size(); + } + + public void arrangeElements(int index, int newindex) + { + if(index < 0) + { + index = 0; + } + else if(index >= elements.size()) + { + index = elements.size() - 1; + } + + if(newindex < 0) + { + newindex = 0; + } + else if(newindex >= elements.size()) + { + newindex = elements.size() - 1; + } + + Object temp = elements.elementAt(newindex); + elements.setElementAt(elements.elementAt(index), newindex); + elements.setElementAt(temp, index); + } + + public void addEffect(Effect effect) + { + effect.setName(image.nextEffectName(Effect.effectType(effect))); + effects.addElement(effect); + } + + public Enumeration listEffects() + { + return effects.elements(); + } + + public boolean hasEffects() + { + return effects.size() > 0; + } + + public Effect getEffect(String name) + { + Effect effect; + + for(int i = 0; i < effects.size(); i++) + { + effect = (Effect)effects.elementAt(i); + + if(effect.getName().equals(name)) + { + return effect; + } + } + + return null; + } + + public void deleteEffect(Effect effect) + { + effects.removeElement(effect); + } + + public void arrangeEffects(int index, int newindex) + { + if(index < 0) + { + index = 0; + } + else if(index >= effects.size()) + { + index = effects.size() - 1; + } + + if(newindex < 0) + { + newindex = 0; + } + else if(newindex >= effects.size()) + { + newindex = effects.size() - 1; + } + + Object temp = effects.elementAt(newindex); + effects.setElementAt(effects.elementAt(index), newindex); + effects.setElementAt(temp, index); + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(data[0]); + + case Y: + return new Float(data[1]); + + case WIDTH: + return new Float(data[2]); + + case HEIGHT: + return new Float(data[3]); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + data[0] = ((Float)value).floatValue(); + break; + + case Y: + data[1] = ((Float)value).floatValue(); + break; + + case WIDTH: + data[2] = ((Float)value).floatValue(); + break; + + case HEIGHT: + data[3] = ((Float)value).floatValue(); + break; + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t"); + + for(int i = 0; i < count; i++) + { + ((VectorElement)elements.elementAt(i)).writeSVG(ps); + } + + ps.println("\t\t"); + } +} diff --git a/src/com/one/vector/Line.java b/src/com/one/vector/Line.java new file mode 100644 index 0000000..67d30e6 --- /dev/null +++ b/src/com/one/vector/Line.java @@ -0,0 +1,202 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class Line extends VectorElement +{ + protected float[] data = new float[4]; + protected int[] sdata = new int[4]; + + public Line() + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + + writeTransformList(dos); + } + + public void rescale() + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + sdata[2] = getScaled(data[2], 0); + sdata[3] = getScaled(data[3], 1); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + g.setColor(color); + } + + g.setStrokeStyle(stroke); + g.drawLine(sdata[0], sdata[1], sdata[2], sdata[3]); + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + subparam = transform.getSubParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + switch(subparam) + { + case 1: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 2: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + + case Y: + switch(subparam) + { + case 1: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 2: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + } + } + } + + if(flag && changed) + { + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == X) + { + if(subparam == 1) + { + return new Float(data[0]); + } + else if(subparam == 2) + { + return new Float(data[2]); + } + } + else if(param == Y) + { + if(subparam == 1) + { + return new Float(data[1]); + } + else if(subparam == 2) + { + return new Float(data[3]); + } + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == X) + { + if(subparam == 1) + { + data[0] = ((Float)value).floatValue(); + } + else if(subparam == 2) + { + data[2] = ((Float)value).floatValue(); + } + } + else if(param == Y) + { + if(subparam == 1) + { + data[1] = ((Float)value).floatValue(); + } + else if(subparam == 2) + { + data[3] = ((Float)value).floatValue(); + } + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/LineArray.java b/src/com/one/vector/LineArray.java new file mode 100644 index 0000000..6e1a2f3 --- /dev/null +++ b/src/com/one/vector/LineArray.java @@ -0,0 +1,357 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class LineArray extends VectorElement +{ + protected float[][] data = new float[4][]; + protected int[][] sdata; + protected int[] colors; + protected int count; + protected ArrayData clr, x1, y1, x2, y2; + + public LineArray() + { + clr = new ArrayData(); + x1 = new ArrayData(); + y1 = new ArrayData(); + x2 = new ArrayData(); + y2 = new ArrayData(); + + count = 2; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + parseFlag(dis.readUnsignedByte()); + + count = dis.readUnsignedShort(); + + clr = new ArrayData(dis); + x1 = new ArrayData(dis); + y1 = new ArrayData(dis); + x2 = new ArrayData(dis); + y2 = new ArrayData(dis); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeByte(getFlag()); + + dos.writeShort(count); + + clr.write(dos); + x1.write(dos); + y1.write(dos); + x2.write(dos); + y2.write(dos); + + writeTransformList(dos); + } + + public void create() + { + colors = AuxMath.linearArrayRGB(clr, count); + + data[0] = AuxMath.specificArrayFloat(x1, count); + data[1] = AuxMath.specificArrayFloat(y1, count); + data[2] = AuxMath.specificArrayFloat(x2, count); + data[3] = AuxMath.specificArrayFloat(y2, count); + + sdata = new int[4][count]; + } + + public void rescale() + { + for(int i = 0; i < count; i++) + { + sdata[0][i] = getScaled(data[0][i], 0); + sdata[1][i] = getScaled(data[1][i], 1); + sdata[2][i] = getScaled(data[2][i], 0); + sdata[3][i] = getScaled(data[3][i], 1); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + g.setStrokeStyle(stroke); + + if(group.image.usecolor) + { + for(int i = 0; i < count; i++) + { + g.setColor(colors[i]); + g.drawLine(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i]); + } + } + else + { + for(int i = 0; i < count; i++) + { + g.drawLine(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i]); + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + ArrayData v; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else + { + subparam = transform.getSubParam(); + + if(subparam == 0) + { + if(param == INT_A) + { + clr.inta = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + else if(param == INT_B) + { + clr.intb = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + + continue; + } + else if(subparam == 1) + { + v = x1; + } + else if(subparam == 2) + { + v = y1; + } + else if(subparam == 3) + { + v = x2; + } + else if(subparam == 4) + { + v = y2; + } + else + { + continue; + } + + switch(param) + { + case VAL_A: + v.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case VAL_B: + v.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_A: + v.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_B: + v.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_C: + v.divc = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_D: + v.divd = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_A: + v.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_B: + v.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == COUNT) + { + return new Integer(count); + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x1; + } + else if(subparam == 2) + { + v = y1; + } + else if(subparam == 3) + { + v = x2; + } + else if(subparam == 4) + { + v = y2; + } + else + { + return null; + } + + switch(param) + { + case VAL_A: + return new Float(v.vala); + + case VAL_B: + return new Float(v.valb); + + case DIV_A: + return new Float(v.diva); + + case DIV_B: + return new Float(v.divb); + + case DIV_C: + return new Float(v.divc); + + case DIV_D: + return new Float(v.divd); + + case INT_A: + return new Integer(v.inta); + + case INT_B: + return new Integer(v.intb); + + case FUNCTION: + return new Integer(v.type); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == COUNT) + { + count = ((Integer)value).intValue(); + return; + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x1; + } + else if(subparam == 2) + { + v = y1; + } + else if(subparam == 3) + { + v = x2; + } + else if(subparam == 4) + { + v = y2; + } + else + { + return; + } + + switch(param) + { + case VAL_A: + v.vala = ((Float)value).floatValue(); + break; + + case VAL_B: + v.valb = ((Float)value).floatValue(); + break; + + case DIV_A: + v.diva = ((Float)value).floatValue(); + break; + + case DIV_B: + v.divb = ((Float)value).floatValue(); + break; + + case DIV_C: + v.divc = ((Float)value).floatValue(); + break; + + case DIV_D: + v.divd = ((Float)value).floatValue(); + break; + + case INT_A: + v.inta = ((Integer)value).intValue(); + break; + + case INT_B: + v.intb = ((Integer)value).intValue(); + break; + + case FUNCTION: + v.type = ((Integer)value).intValue(); + break; + } + } +} diff --git a/src/com/one/vector/LineFill.java b/src/com/one/vector/LineFill.java new file mode 100644 index 0000000..88a437b --- /dev/null +++ b/src/com/one/vector/LineFill.java @@ -0,0 +1,70 @@ +package com.one.vector; + +import java.io.*; + +public class LineFill extends Effect +{ + protected int color; + + public LineFill() + { + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + hidden = dis.readBoolean(); + + color = dis.readInt(); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeBoolean(hidden); + + dos.writeInt(color); + } + + public void apply(int[] rgb, int[] temp, int width, int height) + { + if(hidden) + { + return; + } + + boolean enabled = false; + boolean active = true; + + for(int i = 0; i < rgb.length; i++) + { + if(rgb[i] == color) + { + if(active) + { + enabled = !enabled; + active = false; + } + } + else + { + if(enabled) + { + rgb[i] = color; + } + + active = true; + } + } + } + + public void setColor(int color) + { + this.color = color; + } + + public int getColor() + { + return color; + } +} diff --git a/src/com/one/vector/ParametricCurve.java b/src/com/one/vector/ParametricCurve.java new file mode 100644 index 0000000..3aded64 --- /dev/null +++ b/src/com/one/vector/ParametricCurve.java @@ -0,0 +1,315 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class ParametricCurve extends VectorElement +{ + protected ArrayData x, y; + protected float[][] data = new float[2][]; + protected int[][] sdata = new int[2][]; + protected int count; + + public ParametricCurve() + { + x = new ArrayData(); + y = new ArrayData(); + + count = 3; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + count = dis.readUnsignedShort() + 1; + + x = new ArrayData(dis); + y = new ArrayData(dis); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeShort(count - 1); + + x.write(dos); + y.write(dos); + + writeTransformList(dos); + } + + public void create() + { + data[0] = AuxMath.specificArrayFloat(x, count); + data[1] = AuxMath.specificArrayFloat(y, count); + + sdata = new int[2][count]; + } + + public void rescale() + { + for(int i = 0; i < count; i++) + { + sdata[0][i] = getScaled(data[0][i], 0); + sdata[1][i] = getScaled(data[1][i], 1); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + g.setColor(color); + } + + g.setStrokeStyle(stroke); + + for(int i = 1; i < count; i++) + { + g.drawLine(sdata[0][i], sdata[1][i], sdata[0][i - 1], sdata[1][i - 1]); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + ArrayData v; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else if(param == COLOR) + { + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + else + { + subparam = transform.getSubParam(); + + if(subparam == 0) + { + v = x; + } + else if(subparam == 1) + { + v = y; + } + else + { + continue; + } + + switch(param) + { + case VAL_A: + v.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case VAL_B: + v.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_A: + v.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_B: + v.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_C: + v.divc = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_D: + v.divd = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_A: + v.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_B: + v.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == QUALITY) + { + return new Integer(count - 1); + } + + ArrayData v; + + if(subparam == 0) + { + v = x; + } + else if(subparam == 1) + { + v = y; + } + else + { + return null; + } + + switch(param) + { + case VAL_A: + return new Float(v.vala); + + case VAL_B: + return new Float(v.valb); + + case DIV_A: + return new Float(v.diva); + + case DIV_B: + return new Float(v.divb); + + case DIV_C: + return new Float(v.divc); + + case DIV_D: + return new Float(v.divd); + + case INT_A: + return new Integer(v.inta); + + case INT_B: + return new Integer(v.intb); + + case FUNCTION: + return new Integer(v.type); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == QUALITY) + { + count = ((Integer)value).intValue() + 1; + return; + } + + ArrayData v; + + if(subparam == 0) + { + v = x; + } + else if(subparam == 1) + { + v = y; + } + else + { + return; + } + + switch(param) + { + case VAL_A: + v.vala = ((Float)value).floatValue(); + break; + + case VAL_B: + v.valb = ((Float)value).floatValue(); + break; + + case DIV_A: + v.diva = ((Float)value).floatValue(); + break; + + case DIV_B: + v.divb = ((Float)value).floatValue(); + break; + + case DIV_C: + v.divc = ((Float)value).floatValue(); + break; + + case DIV_D: + v.divd = ((Float)value).floatValue(); + break; + + case INT_A: + v.inta = ((Integer)value).intValue(); + break; + + case INT_B: + v.intb = ((Integer)value).intValue(); + break; + + case FUNCTION: + v.type = ((Integer)value).intValue(); + break; + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/PixelMatrix.java b/src/com/one/vector/PixelMatrix.java new file mode 100644 index 0000000..b2728c1 --- /dev/null +++ b/src/com/one/vector/PixelMatrix.java @@ -0,0 +1,241 @@ +package com.one.vector; + +import javax.microedition.lcdui.Image; +import java.io.*; + +public class PixelMatrix extends Effect +{ + protected int[][] factors; + protected int[] divisors = new int[4]; + protected int[] offsets = new int[4]; + protected int size; + + protected int[] values = new int[4]; + protected int delta; + + public PixelMatrix() + { + setDelta(1); + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + hidden = dis.readBoolean(); + + setDelta(dis.readUnsignedByte()); + + int length = size * size; + + for(int i = 0; i < length; i++) + { + factors[0][i] = dis.readInt(); + factors[1][i] = dis.readInt(); + factors[2][i] = dis.readInt(); + factors[3][i] = dis.readInt(); + } + + divisors[0] = dis.readInt(); + divisors[1] = dis.readInt(); + divisors[2] = dis.readInt(); + divisors[3] = dis.readInt(); + + offsets[0] = dis.readInt(); + offsets[1] = dis.readInt(); + offsets[2] = dis.readInt(); + offsets[3] = dis.readInt(); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeBoolean(hidden); + + dos.writeByte(getDelta()); + + int length = size * size; + + for(int i = 0; i < length; i++) + { + dos.writeInt(factors[0][i]); + dos.writeInt(factors[1][i]); + dos.writeInt(factors[2][i]); + dos.writeInt(factors[3][i]); + } + + dos.writeInt(divisors[0]); + dos.writeInt(divisors[1]); + dos.writeInt(divisors[2]); + dos.writeInt(divisors[3]); + + dos.writeInt(offsets[0]); + dos.writeInt(offsets[1]); + dos.writeInt(offsets[2]); + dos.writeInt(offsets[3]); + } + + public void apply(int[] rgb, int[] temp, int width, int height) + { + if(hidden) + { + return; + } + + System.arraycopy(rgb, 0, temp, 0, rgb.length); + + int mcx = width - delta; + int mcy = height - delta; + + int cx, cy, x, y, mx, my, pi, fi; + int a, r, g, b; + + for(cx = delta; cx < mcx; cx++) + { + for(cy = delta; cy < mcy; cy++) + { + values[0] = 0; + values[1] = 0; + values[2] = 0; + values[3] = 0; + + mx = cx + delta; + my = cy + delta; + + for(x = cx - delta; x <= mx; x++) + { + for(y = cy - delta; y <= my; y++) + { + pi = x + y * width; + fi = (x - cx + delta) + (y - cy + delta) * size; + + values[0] += ((temp[pi] >> 24) & 0xFF) * factors[0][fi]; + values[1] += ((temp[pi] >> 16) & 0xFF) * factors[1][fi]; + values[2] += ((temp[pi] >> 8) & 0xFF) * factors[2][fi]; + values[3] += (temp[pi] & 0xFF) * factors[3][fi]; + } + } + + a = values[0] / divisors[0] + offsets[0]; + r = values[1] / divisors[1] + offsets[1]; + g = values[2] / divisors[2] + offsets[2]; + b = values[3] / divisors[3] + offsets[3]; + + if(a < 0) + { + a = 0; + } + else if(a > 255) + { + a = 255; + } + + if(r < 0) + { + r = 0; + } + else if(r > 255) + { + r = 255; + } + + if(g < 0) + { + g = 0; + } + else if(g > 255) + { + g = 255; + } + + if(b < 0) + { + b = 0; + } + else if(b > 255) + { + b = 255; + } + + rgb[cx + cy * width] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + } + + public void setSize(int sz) + { + setDelta((sz - 1) / 2); + } + + public int getSize() + { + return size; + } + + public void setDelta(int sz) + { + if(sz > 1) + { + delta = sz; + } + else + { + delta = 1; + } + + size = delta * 2 + 1; + + int length = size * size; + factors = new int[4][length]; + + int index = length / 2; + factors[0][index] = 1; + factors[1][index] = 1; + factors[2][index] = 1; + factors[3][index] = 1; + + divisors[0] = 1; + divisors[1] = 1; + divisors[2] = 1; + divisors[3] = 1; + + offsets[0] = 0; + offsets[1] = 0; + offsets[2] = 0; + offsets[3] = 0; + } + + public int getDelta() + { + return delta; + } + + public void setFactor(int channel, int index, int value) + { + factors[channel][index] = value; + } + + public void setDivisor(int channel, int value) + { + divisors[channel] = value; + } + + public void setOffset(int channel, int value) + { + offsets[channel] = value; + } + + public int getFactor(int channel, int index) + { + return factors[channel][index]; + } + + public int getDivisor(int channel) + { + return divisors[channel]; + } + + public int getOffset(int channel) + { + return offsets[channel]; + } +} diff --git a/src/com/one/vector/Point.java b/src/com/one/vector/Point.java new file mode 100644 index 0000000..84b66ba --- /dev/null +++ b/src/com/one/vector/Point.java @@ -0,0 +1,148 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class Point extends VectorElement +{ + protected float[] data = new float[2]; + protected int[] sdata = new int[2]; + + public Point() + { + data[0] = 0; + data[1] = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + + writeTransformList(dos); + } + + public void rescale() + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + g.setColor(color); + } + + g.setStrokeStyle(stroke); + g.drawLine(sdata[0], sdata[1], sdata[0], sdata[1]); + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(data[0]); + + case Y: + return new Float(data[1]); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + data[0] = ((Float)value).floatValue(); + break; + + case Y: + data[1] = ((Float)value).floatValue(); + break; + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/PointArray.java b/src/com/one/vector/PointArray.java new file mode 100644 index 0000000..298687e --- /dev/null +++ b/src/com/one/vector/PointArray.java @@ -0,0 +1,323 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class PointArray extends VectorElement +{ + protected float[][] data = new float[2][]; + protected int[][] sdata; + protected int[] colors; + protected int count; + protected ArrayData clr, x, y; + + public PointArray() + { + clr = new ArrayData(); + x = new ArrayData(); + y = new ArrayData(); + + count = 2; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + parseFlag(dis.readUnsignedByte()); + + count = dis.readUnsignedShort(); + + clr = new ArrayData(dis); + x = new ArrayData(dis); + y = new ArrayData(dis); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeByte(getFlag()); + + dos.writeShort(count); + + clr.write(dos); + x.write(dos); + y.write(dos); + + writeTransformList(dos); + } + + public void create() + { + colors = AuxMath.linearArrayRGB(clr, count); + + data[0] = AuxMath.specificArrayFloat(x, count); + data[1] = AuxMath.specificArrayFloat(y, count); + + sdata = new int[2][count]; + } + + public void rescale() + { + for(int i = 0; i < count; i++) + { + sdata[0][i] = getScaled(data[0][i], 0); + sdata[1][i] = getScaled(data[1][i], 1); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + g.setStrokeStyle(stroke); + + if(group.image.usecolor) + { + for(int i = 0; i < count; i++) + { + g.setColor(colors[i]); + g.drawLine(sdata[0][i], sdata[1][i], sdata[0][i], sdata[1][i]); + } + } + else + { + for(int i = 0; i < count; i++) + { + g.drawLine(sdata[0][i], sdata[1][i], sdata[0][i], sdata[1][i]); + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + ArrayData v; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else + { + subparam = transform.getSubParam(); + + if(subparam == 0) + { + if(param == INT_A) + { + clr.inta = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + else if(param == INT_B) + { + clr.intb = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + + continue; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else + { + continue; + } + + switch(param) + { + case VAL_A: + v.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case VAL_B: + v.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_A: + v.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_B: + v.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_C: + v.divc = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_D: + v.divd = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_A: + v.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_B: + v.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == COUNT) + { + return new Integer(count); + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else + { + return null; + } + + switch(param) + { + case VAL_A: + return new Float(v.vala); + + case VAL_B: + return new Float(v.valb); + + case DIV_A: + return new Float(v.diva); + + case DIV_B: + return new Float(v.divb); + + case DIV_C: + return new Float(v.divc); + + case DIV_D: + return new Float(v.divd); + + case INT_A: + return new Integer(v.inta); + + case INT_B: + return new Integer(v.intb); + + case FUNCTION: + return new Integer(v.type); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == COUNT) + { + count = ((Integer)value).intValue(); + return; + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else + { + return; + } + + switch(param) + { + case VAL_A: + v.vala = ((Float)value).floatValue(); + break; + + case VAL_B: + v.valb = ((Float)value).floatValue(); + break; + + case DIV_A: + v.diva = ((Float)value).floatValue(); + break; + + case DIV_B: + v.divb = ((Float)value).floatValue(); + break; + + case DIV_C: + v.divc = ((Float)value).floatValue(); + break; + + case DIV_D: + v.divd = ((Float)value).floatValue(); + break; + + case INT_A: + v.inta = ((Integer)value).intValue(); + break; + + case INT_B: + v.intb = ((Integer)value).intValue(); + break; + + case FUNCTION: + v.type = ((Integer)value).intValue(); + break; + } + } +} diff --git a/src/com/one/vector/Polygon.java b/src/com/one/vector/Polygon.java new file mode 100644 index 0000000..7f081f9 --- /dev/null +++ b/src/com/one/vector/Polygon.java @@ -0,0 +1,241 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class Polygon extends VectorElement +{ + protected float[][] data; + protected int[][] sdata; + protected ArrayData pdata; + protected int count; + + public Polygon() + { + pdata = new ArrayData(); + pdata.type = ArrayData.HARMONIC; + + count = 3; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + pdata = new ArrayData(dis); + count = dis.readUnsignedShort(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + pdata.write(dos); + dos.writeShort(count); + + writeTransformList(dos); + } + + public void create() + { + data = AuxMath.plotPolygon(pdata.vala, pdata.valb, pdata.diva, pdata.divb, count, pdata.inta, pdata.intb); + sdata = new int[data.length][2]; + } + + public void rescale() + { + for(int i = 0; i < data.length; i++) + { + sdata[i][0] = getScaled(data[i][0], 0); + sdata[i][1] = getScaled(data[i][1], 1); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + g.setColor(color); + } + + int i; + + if(fill) + { + for(i = 2; i < data.length; i++) + { + g.fillTriangle(sdata[0][0], sdata[0][1], sdata[i][0], sdata[i][1], sdata[i - 1][0], sdata[i - 1][1]); + } + } + else + { + g.setStrokeStyle(stroke); + + for(i = 1; i < data.length; i++) + { + g.drawLine(sdata[i][0], sdata[i][1], sdata[i - 1][0], sdata[i - 1][1]); + } + + i--; + + g.drawLine(sdata[0][0], sdata[0][1], sdata[i][0], sdata[i][1]); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + pdata.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + pdata.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + pdata.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + pdata.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case ROTATION: + pdata.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case ANGLE: + pdata.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(pdata.vala); + + case Y: + return new Float(pdata.valb); + + case WIDTH: + return new Float(pdata.diva); + + case HEIGHT: + return new Float(pdata.divb); + + case ROTATION: + return new Integer(pdata.inta); + + case ANGLE: + return new Integer(pdata.intb); + + case POLY_COUNT: + return new Integer(count); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + pdata.vala = ((Float)value).floatValue(); + break; + + case Y: + pdata.valb = ((Float)value).floatValue(); + break; + + case WIDTH: + pdata.diva = ((Float)value).floatValue(); + break; + + case HEIGHT: + pdata.divb = ((Float)value).floatValue(); + break; + + case ROTATION: + pdata.inta = ((Integer)value).intValue(); + break; + + case ANGLE: + pdata.intb = ((Integer)value).intValue(); + break; + + case POLY_COUNT: + count = ((Integer)value).intValue(); + break; + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/PolygonArray.java b/src/com/one/vector/PolygonArray.java new file mode 100644 index 0000000..79e4056 --- /dev/null +++ b/src/com/one/vector/PolygonArray.java @@ -0,0 +1,459 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class PolygonArray extends VectorElement +{ + protected float[][][] data; + protected int[][][] sdata; + protected int[] colors; + protected ArrayData clr, x, y, width, height, rotation, angle; + protected int count, polycount; + + public PolygonArray() + { + clr = new ArrayData(); + x = new ArrayData(); + y = new ArrayData(); + width = new ArrayData(); + height = new ArrayData(); + rotation = new ArrayData(); + angle = new ArrayData(); + polycount = 3; + + count = 2; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + parseFlag(dis.readUnsignedByte()); + + count = dis.readUnsignedShort(); + + clr = new ArrayData(dis); + x = new ArrayData(dis); + y = new ArrayData(dis); + width = new ArrayData(dis); + height = new ArrayData(dis); + rotation = new ArrayData(dis); + angle = new ArrayData(dis); + polycount = dis.readUnsignedShort(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeByte(getFlag()); + + dos.writeShort(count); + + clr.write(dos); + x.write(dos); + y.write(dos); + width.write(dos); + height.write(dos); + rotation.write(dos); + angle.write(dos); + dos.writeShort(polycount); + + writeTransformList(dos); + } + + public void create() + { + colors = AuxMath.linearArrayRGB(clr, count); + + float[][] r1 = new float[4][]; + + r1[0] = AuxMath.specificArrayFloat(x, count); + r1[1] = AuxMath.specificArrayFloat(y, count); + r1[2] = AuxMath.specificArrayFloat(width, count); + r1[3] = AuxMath.specificArrayFloat(height, count); + + int[][] r2 = new int[2][]; + + r2[0] = AuxMath.specificArrayInt(rotation, count); + r2[1] = AuxMath.specificArrayInt(angle, count); + + data = new float[count][][]; + + for(int i = 0; i < count; i++) + { + data[i] = AuxMath.plotPolygon(r1[0][i], r1[1][i], r1[2][i], r1[3][i], polycount, r2[0][i], r2[1][i]); + } + + sdata = new int[count][polycount][2]; + } + + public void rescale() + { + for(int j = 0; j < count; j++) + { + for(int i = 0; i < polycount; i++) + { + sdata[j][i][0] = getScaled(data[j][i][0], 0); + sdata[j][i][1] = getScaled(data[j][i][1], 1); + } + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + g.setStrokeStyle(stroke); + + int i, j; + + if(group.image.usecolor) + { + if(fill) + { + for(j = 0; j < count; j++) + { + g.setColor(colors[j]); + + for(i = 2; i < polycount; i++) + { + g.fillTriangle(sdata[j][0][0], sdata[j][0][1], sdata[j][i][0], sdata[j][i][1], sdata[j][i - 1][0], sdata[j][i - 1][1]); + } + } + } + else + { + for(j = 0; j < count; j++) + { + g.setColor(colors[j]); + + for(i = 1; i < data.length; i++) + { + g.drawLine(sdata[j][i][0], sdata[j][i][1], sdata[j][i - 1][0], sdata[j][i - 1][1]); + } + + i--; + + g.drawLine(sdata[j][0][0], sdata[j][0][1], sdata[j][i][0], sdata[j][i][1]); + } + } + } + else + { + if(fill) + { + for(j = 0; j < count; j++) + { + for(i = 2; i < polycount; i++) + { + g.fillTriangle(sdata[j][0][0], sdata[j][0][1], sdata[j][i][0], sdata[j][i][1], sdata[j][i - 1][0], sdata[j][i - 1][1]); + } + } + } + else + { + for(j = 0; j < count; j++) + { + for(i = 1; i < data.length; i++) + { + g.drawLine(sdata[j][i][0], sdata[j][i][1], sdata[j][i - 1][0], sdata[j][i - 1][1]); + } + + i--; + + g.drawLine(sdata[j][0][0], sdata[j][0][1], sdata[j][i][0], sdata[j][i][1]); + } + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + ArrayData v; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else + { + subparam = transform.getSubParam(); + + if(subparam == 0) + { + if(param == INT_A) + { + clr.inta = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + else if(param == INT_B) + { + clr.intb = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + + continue; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else if(subparam == 5) + { + v = rotation; + } + else if(subparam == 6) + { + v = angle; + } + else + { + continue; + } + + switch(param) + { + case VAL_A: + v.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case VAL_B: + v.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_A: + v.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_B: + v.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_C: + v.divc = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_D: + v.divd = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_A: + v.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_B: + v.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == COUNT) + { + return new Integer(count); + } + else if(param == POLY_COUNT) + { + return new Integer(polycount); + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else if(subparam == 5) + { + v = rotation; + } + else if(subparam == 6) + { + v = angle; + } + else + { + return null; + } + + switch(param) + { + case VAL_A: + return new Float(v.vala); + + case VAL_B: + return new Float(v.valb); + + case DIV_A: + return new Float(v.diva); + + case DIV_B: + return new Float(v.divb); + + case DIV_C: + return new Float(v.divc); + + case DIV_D: + return new Float(v.divd); + + case INT_A: + return new Integer(v.inta); + + case INT_B: + return new Integer(v.intb); + + case FUNCTION: + return new Integer(v.type); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == COUNT) + { + count = ((Integer)value).intValue(); + return; + } + else if(param == POLY_COUNT) + { + polycount = ((Integer)value).intValue(); + return; + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else if(subparam == 5) + { + v = rotation; + } + else if(subparam == 6) + { + v = angle; + } + else + { + return; + } + + switch(param) + { + case VAL_A: + v.vala = ((Float)value).floatValue(); + break; + + case VAL_B: + v.valb = ((Float)value).floatValue(); + break; + + case DIV_A: + v.diva = ((Float)value).floatValue(); + break; + + case DIV_B: + v.divb = ((Float)value).floatValue(); + break; + + case DIV_C: + v.divc = ((Float)value).floatValue(); + break; + + case DIV_D: + v.divd = ((Float)value).floatValue(); + break; + + case INT_A: + v.inta = ((Integer)value).intValue(); + break; + + case INT_B: + v.intb = ((Integer)value).intValue(); + break; + + case FUNCTION: + v.type = ((Integer)value).intValue(); + break; + } + } +} diff --git a/src/com/one/vector/Polyline.java b/src/com/one/vector/Polyline.java new file mode 100644 index 0000000..a1f8a1f --- /dev/null +++ b/src/com/one/vector/Polyline.java @@ -0,0 +1,222 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class Polyline extends VectorElement +{ + protected float[][] data; + protected int[][] sdata; + + public Polyline() + { + data = new float[3][2]; + data[0][0] = 0; + data[0][1] = 0; + data[1][0] = 0; + data[1][1] = 0; + data[2][0] = 0; + data[2][1] = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data = new float[dis.readUnsignedShort()][2]; + + for(int i = 0; i < data.length; i++) + { + data[i][0] = dis.readFloat(); + data[i][1] = dis.readFloat(); + } + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeShort(data.length); + + for(int i = 0; i < data.length; i++) + { + dos.writeFloat(data[i][0]); + dos.writeFloat(data[i][1]); + } + + writeTransformList(dos); + } + + public void create() + { + sdata = new int[data.length][2]; + } + + public void rescale() + { + for(int i = 0; i < data.length; i++) + { + sdata[i][0] = getScaled(data[i][0], 0); + sdata[i][1] = getScaled(data[i][1], 1); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + g.setColor(color); + } + + g.setStrokeStyle(stroke); + + for(int i = 1; i < sdata.length; i++) + { + g.drawLine(sdata[i][0], sdata[i][1], sdata[i - 1][0], sdata[i - 1][1]); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else if(param == COLOR) + { + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + else + { + subparam = transform.getSubParam() - 1; + + if(subparam >= 0 && subparam < data.length) + { + switch(param) + { + case X: + data[subparam][0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + data[subparam][1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + } + + if(flag && changed) + { + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == COUNT) + { + return new Integer(data.length); + } + else if(param == X) + { + subparam--; + + if(subparam >= 0 && subparam < data.length) + { + return new Float(data[subparam][0]); + } + } + else if(param == Y) + { + subparam--; + + if(subparam >= 0 && subparam < data.length) + { + return new Float(data[subparam][1]); + } + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == COUNT) + { + float[][] p = new float[((Integer)value).intValue()][2]; + int minlength = Math.min(data.length, p.length); + + for(int i = 0; i < minlength; i++) + { + p[i][0] = data[i][0]; + p[i][1] = data[i][1]; + } + + data = p; + } + else if(param == X) + { + subparam--; + + if(subparam >= 0 && subparam < data.length) + { + data[subparam][0] = ((Float)value).floatValue(); + } + } + else if(param == Y) + { + subparam--; + + if(subparam >= 0 && subparam < data.length) + { + data[subparam][1] = ((Float)value).floatValue(); + } + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/Rect.java b/src/com/one/vector/Rect.java new file mode 100644 index 0000000..66473ab --- /dev/null +++ b/src/com/one/vector/Rect.java @@ -0,0 +1,186 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class Rect extends VectorElement +{ + protected float[] data = new float[4]; + protected int[] sdata = new int[4]; + + public Rect() + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + + writeTransformList(dos); + } + + public void rescale() + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + sdata[2] = getScaled(data[2], 2); + sdata[3] = getScaled(data[3], 3); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + g.setColor(color); + } + + if(fill) + { + g.fillRect(sdata[0], sdata[1], sdata[2], sdata[3]); + } + else + { + g.setStrokeStyle(stroke); + g.drawRect(sdata[0], sdata[1], sdata[2], sdata[3]); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(data[0]); + + case Y: + return new Float(data[1]); + + case WIDTH: + return new Float(data[2]); + + case HEIGHT: + return new Float(data[3]); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + data[0] = ((Float)value).floatValue(); + break; + + case Y: + data[1] = ((Float)value).floatValue(); + break; + + case WIDTH: + data[2] = ((Float)value).floatValue(); + break; + + case HEIGHT: + data[3] = ((Float)value).floatValue(); + break; + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/RectArray.java b/src/com/one/vector/RectArray.java new file mode 100644 index 0000000..dafd6b1 --- /dev/null +++ b/src/com/one/vector/RectArray.java @@ -0,0 +1,378 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class RectArray extends VectorElement +{ + protected float[][] data = new float[4][]; + protected int[][] sdata; + protected int[] colors; + protected int count; + protected ArrayData clr, x, y, width, height; + + public RectArray() + { + clr = new ArrayData(); + x = new ArrayData(); + y = new ArrayData(); + width = new ArrayData(); + height = new ArrayData(); + + count = 2; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + parseFlag(dis.readUnsignedByte()); + + count = dis.readUnsignedShort(); + + clr = new ArrayData(dis); + x = new ArrayData(dis); + y = new ArrayData(dis); + width = new ArrayData(dis); + height = new ArrayData(dis); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeByte(getFlag()); + + dos.writeShort(count); + + clr.write(dos); + x.write(dos); + y.write(dos); + width.write(dos); + height.write(dos); + + writeTransformList(dos); + } + + public void create() + { + colors = AuxMath.linearArrayRGB(clr, count); + + data[0] = AuxMath.specificArrayFloat(x, count); + data[1] = AuxMath.specificArrayFloat(y, count); + data[2] = AuxMath.specificArrayFloat(width, count); + data[3] = AuxMath.specificArrayFloat(height, count); + + sdata = new int[4][count]; + } + + public void rescale() + { + for(int i = 0; i < count; i++) + { + sdata[0][i] = getScaled(data[0][i], 0); + sdata[1][i] = getScaled(data[1][i], 1); + sdata[2][i] = getScaled(data[2][i], 2); + sdata[3][i] = getScaled(data[3][i], 3); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + g.setStrokeStyle(stroke); + + if(group.image.usecolor) + { + if(fill) + { + for(int i = 0; i < count; i++) + { + g.setColor(colors[i]); + g.fillRect(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i]); + } + } + else + { + for(int i = 0; i < count; i++) + { + g.setColor(colors[i]); + g.drawRect(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i]); + } + } + } + else + { + if(fill) + { + for(int i = 0; i < count; i++) + { + g.fillRect(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i]); + } + } + else + { + for(int i = 0; i < count; i++) + { + g.drawRect(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i]); + } + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + ArrayData v; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else + { + subparam = transform.getSubParam(); + + if(subparam == 0) + { + if(param == INT_A) + { + clr.inta = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + else if(param == INT_B) + { + clr.intb = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + + continue; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else + { + continue; + } + + switch(param) + { + case VAL_A: + v.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case VAL_B: + v.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_A: + v.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_B: + v.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_C: + v.divc = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_D: + v.divd = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_A: + v.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_B: + v.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == COUNT) + { + return new Integer(count); + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else + { + return null; + } + + switch(param) + { + case VAL_A: + return new Float(v.vala); + + case VAL_B: + return new Float(v.valb); + + case DIV_A: + return new Float(v.diva); + + case DIV_B: + return new Float(v.divb); + + case DIV_C: + return new Float(v.divc); + + case DIV_D: + return new Float(v.divd); + + case INT_A: + return new Integer(v.inta); + + case INT_B: + return new Integer(v.intb); + + case FUNCTION: + return new Integer(v.type); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == COUNT) + { + count = ((Integer)value).intValue(); + return; + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else + { + return; + } + + switch(param) + { + case VAL_A: + v.vala = ((Float)value).floatValue(); + break; + + case VAL_B: + v.valb = ((Float)value).floatValue(); + break; + + case DIV_A: + v.diva = ((Float)value).floatValue(); + break; + + case DIV_B: + v.divb = ((Float)value).floatValue(); + break; + + case DIV_C: + v.divc = ((Float)value).floatValue(); + break; + + case DIV_D: + v.divd = ((Float)value).floatValue(); + break; + + case INT_A: + v.inta = ((Integer)value).intValue(); + break; + + case INT_B: + v.intb = ((Integer)value).intValue(); + break; + + case FUNCTION: + v.type = ((Integer)value).intValue(); + break; + } + } +} diff --git a/src/com/one/vector/RoundRect.java b/src/com/one/vector/RoundRect.java new file mode 100644 index 0000000..2ecbd5a --- /dev/null +++ b/src/com/one/vector/RoundRect.java @@ -0,0 +1,220 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class RoundRect extends VectorElement +{ + protected float[] data = new float[6]; + protected int[] sdata = new int[6]; + + public RoundRect() + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + data[5] = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + data[4] = dis.readFloat(); + data[5] = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + dos.writeFloat(data[4]); + dos.writeFloat(data[5]); + + writeTransformList(dos); + } + + public void rescale() + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + sdata[2] = getScaled(data[2], 2); + sdata[3] = getScaled(data[3], 3); + sdata[4] = getScaled(data[4], 2); + sdata[5] = getScaled(data[5], 3); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + g.setColor(color); + } + + if(fill) + { + g.fillRoundRect(sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]); + } + else + { + g.setStrokeStyle(stroke); + g.drawRoundRect(sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case ARC_WIDTH: + data[4] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case ARC_HEIGHT: + data[5] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(data[0]); + + case Y: + return new Float(data[1]); + + case WIDTH: + return new Float(data[2]); + + case HEIGHT: + return new Float(data[3]); + + case ARC_WIDTH: + return new Float(data[4]); + + case ARC_HEIGHT: + return new Float(data[5]); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + data[0] = ((Float)value).floatValue(); + break; + + case Y: + data[1] = ((Float)value).floatValue(); + break; + + case WIDTH: + data[2] = ((Float)value).floatValue(); + break; + + case HEIGHT: + data[3] = ((Float)value).floatValue(); + break; + + case ARC_WIDTH: + data[4] = ((Float)value).floatValue(); + break; + + case ARC_HEIGHT: + data[5] = ((Float)value).floatValue(); + break; + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/RoundRectArray.java b/src/com/one/vector/RoundRectArray.java new file mode 100644 index 0000000..9876e63 --- /dev/null +++ b/src/com/one/vector/RoundRectArray.java @@ -0,0 +1,412 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class RoundRectArray extends VectorElement +{ + protected float[][] data = new float[6][]; + protected int[][] sdata; + protected int[] colors; + protected int count; + protected ArrayData clr, x, y, width, height, arcw, arch; + + public RoundRectArray() + { + clr = new ArrayData(); + x = new ArrayData(); + y = new ArrayData(); + width = new ArrayData(); + height = new ArrayData(); + arcw = new ArrayData(); + arch = new ArrayData(); + + count = 2; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + parseFlag(dis.readUnsignedByte()); + + count = dis.readUnsignedShort(); + + clr = new ArrayData(dis); + x = new ArrayData(dis); + y = new ArrayData(dis); + width = new ArrayData(dis); + height = new ArrayData(dis); + arcw = new ArrayData(dis); + arch = new ArrayData(dis); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeByte(getFlag()); + + dos.writeShort(count); + + clr.write(dos); + x.write(dos); + y.write(dos); + width.write(dos); + height.write(dos); + arcw.write(dos); + arch.write(dos); + + writeTransformList(dos); + } + + public void create() + { + colors = AuxMath.linearArrayRGB(clr, count); + + data[0] = AuxMath.specificArrayFloat(x, count); + data[1] = AuxMath.specificArrayFloat(y, count); + data[2] = AuxMath.specificArrayFloat(width, count); + data[3] = AuxMath.specificArrayFloat(height, count); + data[4] = AuxMath.specificArrayFloat(arcw, count); + data[5] = AuxMath.specificArrayFloat(arch, count); + + sdata = new int[6][count]; + } + + public void rescale() + { + for(int i = 0; i < count; i++) + { + sdata[0][i] = getScaled(data[0][i], 0); + sdata[1][i] = getScaled(data[1][i], 1); + sdata[2][i] = getScaled(data[2][i], 2); + sdata[3][i] = getScaled(data[3][i], 3); + sdata[4][i] = getScaled(data[4][i], 2); + sdata[5][i] = getScaled(data[5][i], 3); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + g.setStrokeStyle(stroke); + + if(group.image.usecolor) + { + if(fill) + { + for(int i = 0; i < count; i++) + { + g.setColor(colors[i]); + g.fillRoundRect(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], sdata[4][i], sdata[5][i]); + } + } + else + { + for(int i = 0; i < count; i++) + { + g.setColor(colors[i]); + g.drawRoundRect(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], sdata[4][i], sdata[5][i]); + } + } + } + else + { + if(fill) + { + for(int i = 0; i < count; i++) + { + g.fillRoundRect(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], sdata[4][i], sdata[5][i]); + } + } + else + { + for(int i = 0; i < count; i++) + { + g.drawRoundRect(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], sdata[4][i], sdata[5][i]); + } + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + ArrayData v; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else + { + subparam = transform.getSubParam(); + + if(subparam == 0) + { + if(param == INT_A) + { + clr.inta = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + else if(param == INT_B) + { + clr.intb = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + + continue; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else if(subparam == 5) + { + v = arcw; + } + else if(subparam == 6) + { + v = arch; + } + else + { + continue; + } + + switch(param) + { + case VAL_A: + v.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case VAL_B: + v.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_A: + v.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_B: + v.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_C: + v.divc = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_D: + v.divd = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_A: + v.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_B: + v.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == COUNT) + { + return new Integer(count); + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else if(subparam == 5) + { + v = arcw; + } + else if(subparam == 6) + { + v = arch; + } + else + { + return null; + } + + switch(param) + { + case VAL_A: + return new Float(v.vala); + + case VAL_B: + return new Float(v.valb); + + case DIV_A: + return new Float(v.diva); + + case DIV_B: + return new Float(v.divb); + + case DIV_C: + return new Float(v.divc); + + case DIV_D: + return new Float(v.divd); + + case INT_A: + return new Integer(v.inta); + + case INT_B: + return new Integer(v.intb); + + case FUNCTION: + return new Integer(v.type); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == COUNT) + { + count = ((Integer)value).intValue(); + return; + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x; + } + else if(subparam == 2) + { + v = y; + } + else if(subparam == 3) + { + v = width; + } + else if(subparam == 4) + { + v = height; + } + else if(subparam == 5) + { + v = arcw; + } + else if(subparam == 6) + { + v = arch; + } + else + { + return; + } + + switch(param) + { + case VAL_A: + v.vala = ((Float)value).floatValue(); + break; + + case VAL_B: + v.valb = ((Float)value).floatValue(); + break; + + case DIV_A: + v.diva = ((Float)value).floatValue(); + break; + + case DIV_B: + v.divb = ((Float)value).floatValue(); + break; + + case DIV_C: + v.divc = ((Float)value).floatValue(); + break; + + case DIV_D: + v.divd = ((Float)value).floatValue(); + break; + + case INT_A: + v.inta = ((Integer)value).intValue(); + break; + + case INT_B: + v.intb = ((Integer)value).intValue(); + break; + + case FUNCTION: + v.type = ((Integer)value).intValue(); + break; + } + } +} diff --git a/src/com/one/vector/TextureArc.java b/src/com/one/vector/TextureArc.java new file mode 100644 index 0000000..38daad9 --- /dev/null +++ b/src/com/one/vector/TextureArc.java @@ -0,0 +1,381 @@ +package com.one.vector; + +import com.one.file.Connector; +import javax.microedition.lcdui.*; +import java.io.*; + +public class TextureArc extends VectorElement +{ + protected float[] data = new float[4]; + protected int[] sdata = new int[4]; + protected int start, length; + + protected String filename; + protected int[] texdata; + protected int texwidth, texheight; + + protected int[] imagedata; + protected int scanlength; + + protected boolean ready = false; + + public TextureArc() + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + start = 0; + length = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + + start = dis.readShort(); + length = dis.readShort(); + + System.gc(); + + try + { + if(dis.readBoolean()) + { + int blen = dis.readInt(); + byte[] b = new byte[blen]; + + dis.readFully(b); + Image texture = Image.createImage(b, 0, blen); + b = null; + + texwidth = texture.getWidth(); + texheight = texture.getHeight(); + + System.gc(); + texdata = new int[texwidth * texheight]; + texture.getRGB(texdata, 0, texwidth, 0, 0, texwidth, texheight); + } + else + { + texwidth = dis.readInt(); + texheight = dis.readInt(); + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = dis.readInt(); + } + } + } + catch(OutOfMemoryError oome) + { + texwidth = Bitmap.DEFTEX_WIDTH; + texheight = Bitmap.DEFTEX_HEIGHT; + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = color; + } + } + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + + dos.writeShort(start); + dos.writeShort(length); + + try + { + InputStream is = Connector.openInputStream("file:///" + filename); + + byte[] b = new byte[4096]; + + dos.writeBoolean(true); + dos.writeInt(is.available()); + + while(is.available() > 0) + { + dos.write(b, 0, is.read(b)); + } + + is.close(); + } + catch(Exception e) + { + dos.writeBoolean(false); + dos.writeInt(texwidth); + dos.writeInt(texheight); + + for(int i = 0; i < texdata.length; i++) + { + dos.writeInt(texdata[i]); + } + } + + writeTransformList(dos); + } + + public void create() + { + if(texdata == null) + { + try + { + InputStream is = Connector.openInputStream("file:///" + filename); + Image texture = Image.createImage(is); + is.close(); + + System.gc(); + + texwidth = texture.getWidth(); + texheight = texture.getHeight(); + + texdata = new int[texwidth * texheight]; + texture.getRGB(texdata, 0, texwidth, 0, 0, texwidth, texheight); + } + catch(Throwable t) + { + texwidth = Bitmap.DEFTEX_WIDTH; + texheight = Bitmap.DEFTEX_HEIGHT; + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = color; + } + } + } + } + + public void rescale() + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + sdata[2] = getScaled(data[2], 2); + sdata[3] = getScaled(data[3], 3); + + ready = false; + + try + { + int repx = (sdata[2] + texwidth - 1) / texwidth; + int repy = (sdata[3] + texheight - 1) / texheight; + + scanlength = texwidth * repx; + + System.gc(); + imagedata = new int[scanlength * texheight * repy]; + + int i, j, k; + + for(i = 0; i < repx; i++) + { + for(j = 0; j < repy; j++) + { + for(k = 0; k < texheight; k++) + { + System.arraycopy(texdata, texwidth * k, imagedata, texwidth * i + (texheight * j + k) * scanlength, texwidth); + } + } + } + + Image temp = Image.createImage(sdata[2], sdata[3]); + Graphics g = temp.getGraphics(); + + g.setColor(0); + g.fillRect(0, 0, sdata[2], sdata[3]); + g.setColor(0xFFFFFFFF); + g.fillArc(0, 0, sdata[2], sdata[3], start, length); + + System.gc(); + int[] shapedata = new int[imagedata.length]; + temp.getRGB(shapedata, 0, scanlength, 0, 0, sdata[2], sdata[3]); + + for(i = 0; i < shapedata.length; i++) + { + if((shapedata[i] & 0xFFFFFF) == 0) + { + imagedata[i] = 0; + } + } + + ready = true; + } + catch(Throwable t) + { + } + + System.gc(); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(ready && group.image.usecolor) + { + g.drawRGB(imagedata, 0, scanlength, sdata[0], sdata[1], sdata[2], sdata[3], true); + } + else + { + if(group.image.usecolor) + { + g.setColor(color); + } + + g.fillArc(sdata[0], sdata[1], sdata[2], sdata[3], start, length); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case START: + start = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + break; + + case LENGTH: + length = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + break; + } + } + } + + if(flag && changed) + { + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(data[0]); + + case Y: + return new Float(data[1]); + + case WIDTH: + return new Float(data[2]); + + case HEIGHT: + return new Float(data[3]); + + case START: + return new Integer(start); + + case LENGTH: + return new Integer(length); + + case FILE: + return filename; + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + data[0] = ((Float)value).floatValue(); + break; + + case Y: + data[1] = ((Float)value).floatValue(); + break; + + case WIDTH: + data[2] = ((Float)value).floatValue(); + break; + + case HEIGHT: + data[3] = ((Float)value).floatValue(); + break; + + case START: + start = ((Integer)value).intValue(); + break; + + case LENGTH: + length = ((Integer)value).intValue(); + break; + + case FILE: + filename = (String)value; + texdata = null; + break; + } + } +} diff --git a/src/com/one/vector/TexturePolygon.java b/src/com/one/vector/TexturePolygon.java new file mode 100644 index 0000000..dd6fd9b --- /dev/null +++ b/src/com/one/vector/TexturePolygon.java @@ -0,0 +1,410 @@ +package com.one.vector; + +import com.one.file.Connector; +import javax.microedition.lcdui.*; +import java.io.*; + +public class TexturePolygon extends VectorElement +{ + protected float[][] data; + protected int[][] sdata; + protected ArrayData pdata; + protected int count; + + protected float[] bounds = new float[4]; + protected int[] sbounds = new int[4]; + + protected String filename; + protected int[] texdata; + protected int texwidth, texheight; + + protected int[] imagedata; + protected int scanlength; + + protected boolean ready = false; + + public TexturePolygon() + { + pdata = new ArrayData(); + pdata.type = ArrayData.HARMONIC; + + count = 3; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + pdata = new ArrayData(dis); + count = dis.readUnsignedShort(); + + System.gc(); + + try + { + if(dis.readBoolean()) + { + int blen = dis.readInt(); + byte[] b = new byte[blen]; + + dis.readFully(b); + Image texture = Image.createImage(b, 0, blen); + b = null; + + texwidth = texture.getWidth(); + texheight = texture.getHeight(); + + System.gc(); + texdata = new int[texwidth * texheight]; + texture.getRGB(texdata, 0, texwidth, 0, 0, texwidth, texheight); + } + else + { + texwidth = dis.readInt(); + texheight = dis.readInt(); + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = dis.readInt(); + } + } + } + catch(OutOfMemoryError oome) + { + texwidth = Bitmap.DEFTEX_WIDTH; + texheight = Bitmap.DEFTEX_HEIGHT; + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = color; + } + } + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + pdata.write(dos); + dos.writeShort(count); + + try + { + InputStream is = Connector.openInputStream("file:///" + filename); + + byte[] b = new byte[4096]; + + dos.writeBoolean(true); + dos.writeInt(is.available()); + + while(is.available() > 0) + { + dos.write(b, 0, is.read(b)); + } + + is.close(); + } + catch(Exception e) + { + dos.writeBoolean(false); + dos.writeInt(texwidth); + dos.writeInt(texheight); + + for(int i = 0; i < texdata.length; i++) + { + dos.writeInt(texdata[i]); + } + } + + writeTransformList(dos); + } + + public void create() + { + data = AuxMath.plotPolygon(pdata.vala, pdata.valb, pdata.diva, pdata.divb, count, pdata.inta, pdata.intb); + sdata = new int[data.length][2]; + + float[] r = AuxMath.plotRotRect(pdata.vala, pdata.valb, pdata.diva, pdata.divb, pdata.intb); + + bounds[0] = Math.min(r[0], Math.min(r[2], Math.min(r[4], r[6]))); + bounds[1] = Math.min(r[1], Math.min(r[3], Math.min(r[5], r[7]))); + bounds[2] = Math.max(r[0], Math.max(r[2], Math.max(r[4], r[6]))) - bounds[0]; + bounds[3] = Math.max(r[1], Math.max(r[3], Math.max(r[5], r[7]))) - bounds[1]; + + if(texdata == null) + { + try + { + InputStream is = Connector.openInputStream("file:///" + filename); + Image texture = Image.createImage(is); + is.close(); + + System.gc(); + + texwidth = texture.getWidth(); + texheight = texture.getHeight(); + + texdata = new int[texwidth * texheight]; + texture.getRGB(texdata, 0, texwidth, 0, 0, texwidth, texheight); + } + catch(Throwable t) + { + texwidth = Bitmap.DEFTEX_WIDTH; + texheight = Bitmap.DEFTEX_HEIGHT; + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = color; + } + } + } + } + + public void rescale() + { + sbounds[0] = getScaled(bounds[0], 0); + sbounds[1] = getScaled(bounds[1], 1); + sbounds[2] = getScaled(bounds[2], 2); + sbounds[3] = getScaled(bounds[3], 3); + + for(int i = 0; i < data.length; i++) + { + sdata[i][0] = getScaled(data[i][0] - bounds[0], 0); + sdata[i][1] = getScaled(data[i][1] - bounds[1], 1); + } + + ready = false; + + try + { + int repx = (sbounds[2] + texwidth - 1) / texwidth; + int repy = (sbounds[3] + texheight - 1) / texheight; + + scanlength = texwidth * repx; + + System.gc(); + imagedata = new int[scanlength * texheight * repy]; + + int i, j, k; + + for(i = 0; i < repx; i++) + { + for(j = 0; j < repy; j++) + { + for(k = 0; k < texheight; k++) + { + System.arraycopy(texdata, texwidth * k, imagedata, texwidth * i + (texheight * j + k) * scanlength, texwidth); + } + } + } + + Image temp = Image.createImage(sbounds[2], sbounds[3]); + Graphics g = temp.getGraphics(); + + g.setColor(0); + g.fillRect(0, 0, sbounds[2], sbounds[3]); + g.setColor(0xFFFFFFFF); + + for(i = 2; i < data.length; i++) + { + g.fillTriangle(sdata[0][0], sdata[0][1], sdata[i][0], sdata[i][1], sdata[i - 1][0], sdata[i - 1][1]); + } + + System.gc(); + int[] shapedata = new int[imagedata.length]; + temp.getRGB(shapedata, 0, scanlength, 0, 0, sbounds[2], sbounds[3]); + + for(i = 0; i < shapedata.length; i++) + { + if((shapedata[i] & 0xFFFFFF) == 0) + { + imagedata[i] = 0; + } + } + + ready = true; + } + catch(Throwable t) + { + for(int i = 0; i < data.length; i++) + { + sdata[i][0] = getScaled(data[i][0], 0); + sdata[i][1] = getScaled(data[i][1], 1); + } + } + + System.gc(); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(ready && group.image.usecolor) + { + g.drawRGB(imagedata, 0, scanlength, sbounds[0], sbounds[1], sbounds[2], sbounds[3], true); + } + else + { + if(group.image.usecolor) + { + g.setColor(color); + } + + for(int i = 2; i < data.length; i++) + { + g.fillTriangle(sdata[0][0], sdata[0][1], sdata[i][0], sdata[i][1], sdata[i - 1][0], sdata[i - 1][1]); + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + pdata.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + pdata.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + pdata.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + pdata.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case ROTATION: + pdata.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case ANGLE: + pdata.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(pdata.vala); + + case Y: + return new Float(pdata.valb); + + case WIDTH: + return new Float(pdata.diva); + + case HEIGHT: + return new Float(pdata.divb); + + case ROTATION: + return new Integer(pdata.inta); + + case ANGLE: + return new Integer(pdata.intb); + + case POLY_COUNT: + return new Integer(count); + + case FILE: + return filename; + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + pdata.vala = ((Float)value).floatValue(); + break; + + case Y: + pdata.valb = ((Float)value).floatValue(); + break; + + case WIDTH: + pdata.diva = ((Float)value).floatValue(); + break; + + case HEIGHT: + pdata.divb = ((Float)value).floatValue(); + break; + + case ROTATION: + pdata.inta = ((Integer)value).intValue(); + break; + + case ANGLE: + pdata.intb = ((Integer)value).intValue(); + break; + + case POLY_COUNT: + count = ((Integer)value).intValue(); + break; + + case FILE: + filename = (String)value; + texdata = null; + break; + } + } +} diff --git a/src/com/one/vector/TextureRoundRect.java b/src/com/one/vector/TextureRoundRect.java new file mode 100644 index 0000000..d478094 --- /dev/null +++ b/src/com/one/vector/TextureRoundRect.java @@ -0,0 +1,379 @@ +package com.one.vector; + +import com.one.file.Connector; +import javax.microedition.lcdui.*; +import java.io.*; + +public class TextureRoundRect extends VectorElement +{ + protected float[] data = new float[6]; + protected int[] sdata = new int[6]; + + protected String filename; + protected int[] texdata; + protected int texwidth, texheight; + + protected int[] imagedata; + protected int scanlength; + + protected boolean ready = false; + + public TextureRoundRect() + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + data[5] = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + data[4] = dis.readFloat(); + data[5] = dis.readFloat(); + + System.gc(); + + try + { + if(dis.readBoolean()) + { + int blen = dis.readInt(); + byte[] b = new byte[blen]; + + dis.readFully(b); + Image texture = Image.createImage(b, 0, blen); + b = null; + + texwidth = texture.getWidth(); + texheight = texture.getHeight(); + + System.gc(); + texdata = new int[texwidth * texheight]; + texture.getRGB(texdata, 0, texwidth, 0, 0, texwidth, texheight); + } + else + { + texwidth = dis.readInt(); + texheight = dis.readInt(); + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = dis.readInt(); + } + } + } + catch(OutOfMemoryError oome) + { + texwidth = Bitmap.DEFTEX_WIDTH; + texheight = Bitmap.DEFTEX_HEIGHT; + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = color; + } + } + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.write(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + dos.writeFloat(data[4]); + dos.writeFloat(data[5]); + + try + { + InputStream is = Connector.openInputStream("file:///" + filename); + + byte[] b = new byte[4096]; + + dos.writeBoolean(true); + dos.writeInt(is.available()); + + while(is.available() > 0) + { + dos.write(b, 0, is.read(b)); + } + + is.close(); + } + catch(Exception e) + { + dos.writeBoolean(false); + dos.writeInt(texwidth); + dos.writeInt(texheight); + + for(int i = 0; i < texdata.length; i++) + { + dos.writeInt(texdata[i]); + } + } + + writeTransformList(dos); + } + + public void create() + { + if(texdata == null) + { + try + { + InputStream is = Connector.openInputStream("file:///" + filename); + Image texture = Image.createImage(is); + is.close(); + + System.gc(); + + texwidth = texture.getWidth(); + texheight = texture.getHeight(); + + texdata = new int[texwidth * texheight]; + texture.getRGB(texdata, 0, texwidth, 0, 0, texwidth, texheight); + } + catch(Throwable t) + { + texwidth = Bitmap.DEFTEX_WIDTH; + texheight = Bitmap.DEFTEX_HEIGHT; + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = color; + } + } + } + } + + public void rescale() + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + sdata[2] = getScaled(data[2], 2); + sdata[3] = getScaled(data[3], 3); + sdata[4] = getScaled(data[4], 2); + sdata[5] = getScaled(data[5], 3); + + ready = false; + + try + { + int repx = (sdata[2] + texwidth - 1) / texwidth; + int repy = (sdata[3] + texheight - 1) / texheight; + + scanlength = texwidth * repx; + + System.gc(); + imagedata = new int[scanlength * texheight * repy]; + + int i, j, k; + + for(i = 0; i < repx; i++) + { + for(j = 0; j < repy; j++) + { + for(k = 0; k < texheight; k++) + { + System.arraycopy(texdata, texwidth * k, imagedata, texwidth * i + (texheight * j + k) * scanlength, texwidth); + } + } + } + + Image temp = Image.createImage(sdata[2], sdata[3]); + Graphics g = temp.getGraphics(); + + g.setColor(0); + g.fillRect(0, 0, sdata[2], sdata[3]); + g.setColor(0xFFFFFFFF); + g.fillRoundRect(0, 0, sdata[2], sdata[3], sdata[4], sdata[5]); + + System.gc(); + int[] shapedata = new int[imagedata.length]; + temp.getRGB(shapedata, 0, scanlength, 0, 0, sdata[2], sdata[3]); + + for(i = 0; i < shapedata.length; i++) + { + if((shapedata[i] & 0xFFFFFF) == 0) + { + imagedata[i] = 0; + } + } + + ready = true; + } + catch(Throwable t) + { + } + + System.gc(); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(ready && group.image.usecolor) + { + g.drawRGB(imagedata, 0, scanlength, sdata[0], sdata[1], sdata[2], sdata[3], true); + } + else + { + if(group.image.usecolor) + { + g.setColor(color); + } + + g.fillRoundRect(sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case ARC_WIDTH: + data[4] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + break; + + case ARC_HEIGHT: + data[5] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + break; + } + } + } + + if(flag && changed) + { + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(data[0]); + + case Y: + return new Float(data[1]); + + case WIDTH: + return new Float(data[2]); + + case HEIGHT: + return new Float(data[3]); + + case ARC_WIDTH: + return new Float(data[4]); + + case ARC_HEIGHT: + return new Float(data[5]); + + case FILE: + return filename; + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + data[0] = ((Float)value).floatValue(); + break; + + case Y: + data[1] = ((Float)value).floatValue(); + break; + + case WIDTH: + data[2] = ((Float)value).floatValue(); + break; + + case HEIGHT: + data[3] = ((Float)value).floatValue(); + break; + + case ARC_WIDTH: + data[4] = ((Float)value).floatValue(); + break; + + case ARC_HEIGHT: + data[5] = ((Float)value).floatValue(); + break; + + case FILE: + filename = (String)value; + texdata = null; + break; + } + } +} diff --git a/src/com/one/vector/TextureTriangle.java b/src/com/one/vector/TextureTriangle.java new file mode 100644 index 0000000..82d386b --- /dev/null +++ b/src/com/one/vector/TextureTriangle.java @@ -0,0 +1,427 @@ +package com.one.vector; + +import com.one.file.Connector; +import javax.microedition.lcdui.*; +import java.io.*; + +public class TextureTriangle extends VectorElement +{ + protected float[] data = new float[6]; + protected int[] sdata = new int[6]; + + protected float[] bounds = new float[4]; + protected int[] sbounds = new int[4]; + + protected String filename; + protected int[] texdata; + protected int texwidth, texheight; + + protected int[] imagedata; + protected int scanlength; + + protected boolean ready = false; + + public TextureTriangle() + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + data[5] = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + data[4] = dis.readFloat(); + data[5] = dis.readFloat(); + + System.gc(); + + try + { + if(dis.readBoolean()) + { + int blen = dis.readInt(); + byte[] b = new byte[blen]; + + dis.readFully(b); + Image texture = Image.createImage(b, 0, blen); + b = null; + + texwidth = texture.getWidth(); + texheight = texture.getHeight(); + + System.gc(); + texdata = new int[texwidth * texheight]; + texture.getRGB(texdata, 0, texwidth, 0, 0, texwidth, texheight); + } + else + { + texwidth = dis.readInt(); + texheight = dis.readInt(); + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = dis.readInt(); + } + } + } + catch(OutOfMemoryError oome) + { + texwidth = Bitmap.DEFTEX_WIDTH; + texheight = Bitmap.DEFTEX_HEIGHT; + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = color; + } + } + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + dos.writeFloat(data[4]); + dos.writeFloat(data[5]); + + try + { + InputStream is = Connector.openInputStream("file:///" + filename); + + byte[] b = new byte[4096]; + + dos.writeBoolean(true); + dos.writeInt(is.available()); + + while(is.available() > 0) + { + dos.write(b, 0, is.read(b)); + } + + is.close(); + } + catch(Exception e) + { + dos.writeBoolean(false); + dos.writeInt(texwidth); + dos.writeInt(texheight); + + for(int i = 0; i < texdata.length; i++) + { + dos.writeInt(texdata[i]); + } + } + + writeTransformList(dos); + } + + public void create() + { + bounds[0] = Math.min(data[0], Math.min(data[2], data[4])); + bounds[1] = Math.min(data[1], Math.min(data[3], data[5])); + bounds[2] = Math.max(data[0], Math.max(data[2], data[4])) - bounds[0]; + bounds[3] = Math.max(data[1], Math.max(data[3], data[5])) - bounds[1]; + + if(texdata == null) + { + try + { + InputStream is = Connector.openInputStream("file:///" + filename); + Image texture = Image.createImage(is); + is.close(); + + System.gc(); + + texwidth = texture.getWidth(); + texheight = texture.getHeight(); + + texdata = new int[texwidth * texheight]; + texture.getRGB(texdata, 0, texwidth, 0, 0, texwidth, texheight); + } + catch(Throwable t) + { + texwidth = Bitmap.DEFTEX_WIDTH; + texheight = Bitmap.DEFTEX_HEIGHT; + + texdata = new int[texwidth * texheight]; + + for(int i = 0; i < texdata.length; i++) + { + texdata[i] = color; + } + } + } + } + + public void rescale() + { + sbounds[0] = getScaled(bounds[0], 0); + sbounds[1] = getScaled(bounds[1], 1); + sbounds[2] = getScaled(bounds[2], 2); + sbounds[3] = getScaled(bounds[3], 3); + + sdata[0] = getScaled(data[0] - bounds[0], 0); + sdata[1] = getScaled(data[1] - bounds[1], 1); + sdata[2] = getScaled(data[2] - bounds[0], 0); + sdata[3] = getScaled(data[3] - bounds[1], 1); + sdata[4] = getScaled(data[4] - bounds[0], 0); + sdata[5] = getScaled(data[5] - bounds[1], 1); + + ready = false; + + try + { + int repx = (sbounds[2] + texwidth - 1) / texwidth; + int repy = (sbounds[3] + texheight - 1) / texheight; + + scanlength = texwidth * repx; + + System.gc(); + imagedata = new int[scanlength * texheight * repy]; + + int i, j, k; + + for(i = 0; i < repx; i++) + { + for(j = 0; j < repy; j++) + { + for(k = 0; k < texheight; k++) + { + System.arraycopy(texdata, texwidth * k, imagedata, texwidth * i + (texheight * j + k) * scanlength, texwidth); + } + } + } + + Image temp = Image.createImage(sbounds[2], sbounds[3]); + Graphics g = temp.getGraphics(); + + g.setColor(0); + g.fillRect(0, 0, sbounds[2], sbounds[3]); + g.setColor(0xFFFFFFFF); + g.fillTriangle(sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]); + + System.gc(); + int[] shapedata = new int[imagedata.length]; + temp.getRGB(shapedata, 0, scanlength, 0, 0, sbounds[2], sbounds[3]); + + for(i = 0; i < shapedata.length; i++) + { + if((shapedata[i] & 0xFFFFFF) == 0) + { + imagedata[i] = 0; + } + } + + ready = true; + } + catch(Throwable t) + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + sdata[2] = getScaled(data[2], 0); + sdata[3] = getScaled(data[3], 1); + sdata[4] = getScaled(data[4], 0); + sdata[5] = getScaled(data[5], 1); + } + + System.gc(); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(ready && group.image.usecolor) + { + g.drawRGB(imagedata, 0, scanlength, sbounds[0], sbounds[1], sbounds[2], sbounds[3], true); + } + else + { + if(group.image.usecolor) + { + g.setColor(color); + } + + g.fillRoundRect(sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + subparam = transform.getSubParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + switch(subparam) + { + case 1: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 2: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 3: + data[4] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + + case Y: + switch(subparam) + { + case 1: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 2: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 3: + data[5] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == X) + { + if(subparam == 1) + { + return new Float(data[0]); + } + else if(subparam == 2) + { + return new Float(data[2]); + } + else if(subparam == 3) + { + return new Float(data[4]); + } + } + else if(param == Y) + { + if(subparam == 1) + { + return new Float(data[1]); + } + else if(subparam == 2) + { + return new Float(data[3]); + } + else if(subparam == 3) + { + return new Float(data[5]); + } + } + else if(param == FILE) + { + return filename; + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == X) + { + if(subparam == 1) + { + data[0] = ((Float)value).floatValue(); + } + else if(subparam == 2) + { + data[2] = ((Float)value).floatValue(); + } + else if(subparam == 3) + { + data[4] = ((Float)value).floatValue(); + } + } + else if(param == Y) + { + if(subparam == 1) + { + data[1] = ((Float)value).floatValue(); + } + else if(subparam == 2) + { + data[3] = ((Float)value).floatValue(); + } + else if(subparam == 3) + { + data[5] = ((Float)value).floatValue(); + } + } + else if(param == FILE) + { + filename = (String)value; + texdata = null; + } + } +} diff --git a/src/com/one/vector/ThickBezierCurve.java b/src/com/one/vector/ThickBezierCurve.java new file mode 100644 index 0000000..194b2ba --- /dev/null +++ b/src/com/one/vector/ThickBezierCurve.java @@ -0,0 +1,275 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class ThickBezierCurve extends VectorElement +{ + protected ThickLine[] lines; + protected float[][] points; + protected float thickness; + protected int count; + + public ThickBezierCurve() + { + points = new float[3][2]; + points[0][0] = 0; + points[0][1] = 0; + points[1][0] = 0; + points[1][1] = 0; + points[2][0] = 0; + points[2][1] = 0; + + count = 3; + + thickness = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + count = dis.readUnsignedShort() + 1; + + points = new float[dis.readUnsignedShort()][2]; + + for(int i = 0; i < points.length; i++) + { + points[i][0] = dis.readFloat(); + points[i][1] = dis.readFloat(); + } + + thickness = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeShort(count - 1); + + dos.writeShort(points.length); + + for(int i = 0; i < points.length; i++) + { + dos.writeFloat(points[i][0]); + dos.writeFloat(points[i][1]); + } + + dos.writeFloat(thickness); + + writeTransformList(dos); + } + + public void create() + { + float[][] data = AuxMath.plotBezierCurve(points, count); + + lines = new ThickLine[count - 1]; + + for(int i = 0; i < lines.length; i++) + { + lines[i] = new ThickLine(color, NORMAL, data[i][0], data[i][1], data[i + 1][0], data[i + 1][1], thickness); + lines[i].setGroup(group); + } + } + + public void rescale() + { + for(int i = 0; i < lines.length; i++) + { + lines[i].rescale(); + } + } + + public void setGroup(Group grp) + { + super.setGroup(grp); + + for(int i = 0; i < lines.length; i++) + { + lines[i].setGroup(grp); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + for(int i = 0; i < lines.length; i++) + { + lines[i].paint(g); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else if(param == COLOR) + { + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + changed = true; + } + else if(param == THICKNESS) + { + thickness = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + } + else + { + subparam = transform.getSubParam() - 1; + + if(subparam >= 0 && subparam < points.length) + { + switch(param) + { + case X: + points[subparam][0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + points[subparam][1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == COUNT) + { + return new Integer(points.length); + } + else if(param == QUALITY) + { + return new Integer(count - 1); + } + else if(param == X) + { + subparam--; + + if(subparam >= 0 && subparam < points.length) + { + return new Float(points[subparam][0]); + } + } + else if(param == Y) + { + subparam--; + + if(subparam >= 0 && subparam < points.length) + { + return new Float(points[subparam][1]); + } + } + else if(param == THICKNESS) + { + return new Float(thickness); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == COUNT) + { + float[][] p = new float[((Integer)value).intValue()][2]; + int minlength = Math.min(points.length, p.length); + + for(int i = 0; i < minlength; i++) + { + p[i][0] = points[i][0]; + p[i][1] = points[i][1]; + } + + points = p; + } + else if(param == QUALITY) + { + count = ((Integer)value).intValue() + 1; + } + else if(param == X) + { + subparam--; + + if(subparam >= 0 && subparam < points.length) + { + points[subparam][0] = ((Float)value).floatValue(); + } + } + else if(param == Y) + { + subparam--; + + if(subparam >= 0 && subparam < points.length) + { + points[subparam][1] = ((Float)value).floatValue(); + } + } + else if(param == THICKNESS) + { + thickness = ((Float)value).floatValue(); + } + } + + public void writeSVG(PrintStream ps) + { + float[][] data = AuxMath.plotBezierCurve(points, count); + + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/ThickLine.java b/src/com/one/vector/ThickLine.java new file mode 100644 index 0000000..a7d5c8c --- /dev/null +++ b/src/com/one/vector/ThickLine.java @@ -0,0 +1,264 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class ThickLine extends VectorElement +{ + protected float[] data; + protected int[] sdata; + protected float x1, y1, x2, y2, thickness; + + public ThickLine() + { + x1 = 0; + y1 = 0; + x2 = 0; + y2 = 0; + + thickness = 0; + } + + public ThickLine(int color, int flag, float x1, float y1, float x2, float y2, float thickness) + { + this.color = color; + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + this.thickness = thickness; + parseFlag(flag); + + create(); + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + x1 = dis.readFloat(); + y1 = dis.readFloat(); + x2 = dis.readFloat(); + y2 = dis.readFloat(); + thickness = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(x1); + dos.writeFloat(y1); + dos.writeFloat(x2); + dos.writeFloat(y2); + dos.writeFloat(thickness); + + writeTransformList(dos); + } + + public void create() + { + data = AuxMath.plotThickLine(x1, y1, x2, y2, thickness, true); + sdata = new int[data.length]; + } + + public void rescale() + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + sdata[2] = getScaled(data[2], 0); + sdata[3] = getScaled(data[3], 1); + sdata[4] = getScaled(data[4], 0); + sdata[5] = getScaled(data[5], 1); + sdata[6] = getScaled(data[6], 0); + sdata[7] = getScaled(data[7], 1); + + sdata[8] = getScaled(data[8], 0); + sdata[9] = getScaled(data[9], 1); + sdata[10] = getScaled(data[10], 0); + sdata[11] = getScaled(data[11], 1); + sdata[12] = getScaled(data[12], 2); + sdata[13] = getScaled(data[13], 3); + + sdata[8] -= sdata[12]; + sdata[9] -= sdata[13]; + sdata[10] -= sdata[12]; + sdata[11] -= sdata[13]; + sdata[12] *= 2; + sdata[13] *= 2; + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + g.setColor(color); + } + + g.fillTriangle(sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]); + g.fillTriangle(sdata[2], sdata[3], sdata[4], sdata[5], sdata[6], sdata[7]); + + g.fillArc(sdata[8], sdata[9], sdata[12], sdata[13], 0, 360); + g.fillArc(sdata[10], sdata[11], sdata[12], sdata[13], 0, 360); + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + subparam = transform.getSubParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + switch(subparam) + { + case 1: + x1 = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 2: + x2 = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + + case Y: + switch(subparam) + { + case 1: + y1 = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 2: + y2 = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + + case THICKNESS: + thickness = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == X) + { + if(subparam == 1) + { + return new Float(x1); + } + else if(subparam == 2) + { + return new Float(x2); + } + } + else if(param == Y) + { + if(subparam == 1) + { + return new Float(y1); + } + else if(subparam == 2) + { + return new Float(y2); + } + } + else if(param == THICKNESS) + { + return new Float(thickness); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == X) + { + if(subparam == 1) + { + x1 = ((Float)value).floatValue(); + } + else if(subparam == 2) + { + x2 = ((Float)value).floatValue(); + } + } + else if(param == Y) + { + if(subparam == 1) + { + y1 = ((Float)value).floatValue(); + } + else if(subparam == 2) + { + y2 = ((Float)value).floatValue(); + } + } + else if(param == THICKNESS) + { + thickness = ((Float)value).floatValue(); + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/ThickParametricCurve.java b/src/com/one/vector/ThickParametricCurve.java new file mode 100644 index 0000000..2122c16 --- /dev/null +++ b/src/com/one/vector/ThickParametricCurve.java @@ -0,0 +1,353 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class ThickParametricCurve extends VectorElement +{ + protected ThickLine[] lines; + protected ArrayData x, y; + protected float thickness; + protected int count; + + public ThickParametricCurve() + { + x = new ArrayData(); + y = new ArrayData(); + + count = 3; + + thickness = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + count = dis.readUnsignedShort() + 1; + + x = new ArrayData(dis); + y = new ArrayData(dis); + + thickness = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeShort(count - 1); + + x.write(dos); + y.write(dos); + + dos.writeFloat(thickness); + + writeTransformList(dos); + } + + public void create() + { + float[][] data = new float[2][]; + data[0] = AuxMath.specificArrayFloat(x, count); + data[1] = AuxMath.specificArrayFloat(y, count); + + lines = new ThickLine[count - 1]; + + for(int i = 0; i < lines.length; i++) + { + lines[i] = new ThickLine(color, NORMAL, data[0][i], data[1][i], data[0][i + 1], data[1][i + 1], thickness); + lines[i].setGroup(group); + } + } + + public void rescale() + { + for(int i = 0; i < lines.length; i++) + { + lines[i].rescale(); + } + } + + public void setGroup(Group grp) + { + super.setGroup(grp); + + for(int i = 0; i < lines.length; i++) + { + lines[i].setGroup(group); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + for(int i = 0; i < lines.length; i++) + { + lines[i].paint(g); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + ArrayData v; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else if(param == COLOR) + { + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + changed = true; + } + else if(param == THICKNESS) + { + thickness = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + } + else + { + subparam = transform.getSubParam(); + + if(subparam == 0) + { + v = x; + } + else if(subparam == 1) + { + v = y; + } + else + { + continue; + } + + switch(param) + { + case VAL_A: + v.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case VAL_B: + v.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_A: + v.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_B: + v.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_C: + v.divc = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_D: + v.divd = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_A: + v.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_B: + v.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == QUALITY) + { + return new Integer(count - 1); + } + else if(param == THICKNESS) + { + return new Float(thickness); + } + + ArrayData v; + + if(subparam == 0) + { + v = x; + } + else if(subparam == 1) + { + v = y; + } + else + { + return null; + } + + switch(param) + { + case VAL_A: + return new Float(v.vala); + + case VAL_B: + return new Float(v.valb); + + case DIV_A: + return new Float(v.diva); + + case DIV_B: + return new Float(v.divb); + + case DIV_C: + return new Float(v.divc); + + case DIV_D: + return new Float(v.divd); + + case INT_A: + return new Integer(v.inta); + + case INT_B: + return new Integer(v.intb); + + case FUNCTION: + return new Integer(v.type); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == QUALITY) + { + count = ((Integer)value).intValue() + 1; + return; + } + else if(param == THICKNESS) + { + thickness = ((Float)value).floatValue(); + return; + } + + ArrayData v; + + if(subparam == 0) + { + v = x; + } + else if(subparam == 1) + { + v = y; + } + else + { + return; + } + + switch(param) + { + case VAL_A: + v.vala = ((Float)value).floatValue(); + break; + + case VAL_B: + v.valb = ((Float)value).floatValue(); + break; + + case DIV_A: + v.diva = ((Float)value).floatValue(); + break; + + case DIV_B: + v.divb = ((Float)value).floatValue(); + break; + + case DIV_C: + v.divc = ((Float)value).floatValue(); + break; + + case DIV_D: + v.divd = ((Float)value).floatValue(); + break; + + case INT_A: + v.inta = ((Integer)value).intValue(); + break; + + case INT_B: + v.intb = ((Integer)value).intValue(); + break; + + case FUNCTION: + v.type = ((Integer)value).intValue(); + break; + } + } + + public void writeSVG(PrintStream ps) + { + float[][] data = new float[2][]; + data[0] = AuxMath.specificArrayFloat(x, count); + data[1] = AuxMath.specificArrayFloat(y, count); + + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/ThickPolygon.java b/src/com/one/vector/ThickPolygon.java new file mode 100644 index 0000000..db4e0d9 --- /dev/null +++ b/src/com/one/vector/ThickPolygon.java @@ -0,0 +1,254 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class ThickPolygon extends VectorElement +{ + protected ThickLine[] lines; + protected ArrayData pdata; + protected int count; + protected float thickness; + + public ThickPolygon() + { + pdata = new ArrayData(); + pdata.type = ArrayData.HARMONIC; + + count = 3; + + thickness = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + pdata = new ArrayData(dis); + count = dis.readUnsignedShort(); + thickness = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + pdata.write(dos); + dos.writeShort(count); + dos.writeFloat(thickness); + + writeTransformList(dos); + } + + public void create() + { + float[][] data = AuxMath.plotPolygon(pdata.vala, pdata.valb, pdata.diva, pdata.divb, count, pdata.inta, pdata.intb); + + lines = new ThickLine[data.length]; + + lines[0] = new ThickLine(color, NORMAL, data[data.length - 1][0], data[data.length - 1][1], data[0][0], data[0][1], thickness); + lines[0].setGroup(group); + + for(int i = 1; i < lines.length; i++) + { + lines[i] = new ThickLine(color, NORMAL, data[i - 1][0], data[i - 1][1], data[i][0], data[i][1], thickness); + lines[i].setGroup(group); + } + } + + public void rescale() + { + for(int i = 0; i < lines.length; i++) + { + lines[i].rescale(); + } + } + + public void setGroup(Group grp) + { + super.setGroup(grp); + + for(int i = 0; i < lines.length; i++) + { + lines[i].setGroup(grp); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + for(int i = 0; i < lines.length; i++) + { + lines[i].paint(g); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + changed = true; + break; + + case X: + pdata.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + pdata.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + pdata.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + pdata.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case ROTATION: + pdata.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case ANGLE: + pdata.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(pdata.vala); + + case Y: + return new Float(pdata.valb); + + case WIDTH: + return new Float(pdata.diva); + + case HEIGHT: + return new Float(pdata.divb); + + case ROTATION: + return new Integer(pdata.inta); + + case ANGLE: + return new Integer(pdata.intb); + + case POLY_COUNT: + return new Integer(count); + + case THICKNESS: + return new Float(thickness); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + pdata.vala = ((Float)value).floatValue(); + break; + + case Y: + pdata.valb = ((Float)value).floatValue(); + break; + + case WIDTH: + pdata.diva = ((Float)value).floatValue(); + break; + + case HEIGHT: + pdata.divb = ((Float)value).floatValue(); + break; + + case ROTATION: + pdata.inta = ((Integer)value).intValue(); + break; + + case ANGLE: + pdata.intb = ((Integer)value).intValue(); + break; + + case POLY_COUNT: + count = ((Integer)value).intValue(); + break; + + case THICKNESS: + thickness = ((Float)value).floatValue(); + break; + } + } + + public void writeSVG(PrintStream ps) + { + float[][] data = AuxMath.plotPolygon(pdata.vala, pdata.valb, pdata.diva, pdata.divb, count, pdata.inta, pdata.intb); + + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/ThickPolyline.java b/src/com/one/vector/ThickPolyline.java new file mode 100644 index 0000000..c0e02c8 --- /dev/null +++ b/src/com/one/vector/ThickPolyline.java @@ -0,0 +1,251 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class ThickPolyline extends VectorElement +{ + protected ThickLine[] lines; + protected float[][] data; + protected float thickness; + + public ThickPolyline() + { + data = new float[3][2]; + data[0][0] = 0; + data[0][1] = 0; + data[1][0] = 0; + data[1][1] = 0; + data[2][0] = 0; + data[2][1] = 0; + + thickness = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data = new float[dis.readUnsignedShort()][2]; + + for(int i = 0; i < data.length; i++) + { + data[i][0] = dis.readFloat(); + data[i][1] = dis.readFloat(); + } + + thickness = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeShort(data.length); + + for(int i = 0; i < data.length; i++) + { + dos.writeFloat(data[i][0]); + dos.writeFloat(data[i][1]); + } + + dos.writeFloat(thickness); + + writeTransformList(dos); + } + + public void create() + { + lines = new ThickLine[data.length - 1]; + + for(int i = 0; i < lines.length; i++) + { + lines[i] = new ThickLine(color, NORMAL, data[i][0], data[i][1], data[i + 1][0], data[i + 1][1], thickness); + lines[i].setGroup(group); + } + } + + public void rescale() + { + for(int i = 0; i < lines.length; i++) + { + lines[i].rescale(); + } + } + + public void setGroup(Group grp) + { + super.setGroup(grp); + + for(int i = 0; i < lines.length; i++) + { + lines[i].setGroup(grp); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + for(int i = 0; i < lines.length; i++) + { + lines[i].paint(g); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else if(param == COLOR) + { + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + changed = true; + } + else + { + subparam = transform.getSubParam() - 1; + + if(subparam >= 0 && subparam < data.length) + { + switch(param) + { + case X: + data[subparam][0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + data[subparam][1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == COUNT) + { + return new Integer(data.length); + } + else if(param == X) + { + subparam--; + + if(subparam >= 0 && subparam < data.length) + { + return new Float(data[subparam][0]); + } + } + else if(param == Y) + { + subparam--; + + if(subparam >= 0 && subparam < data.length) + { + return new Float(data[subparam][1]); + } + } + else if(param == THICKNESS) + { + return new Float(thickness); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == COUNT) + { + float[][] p = new float[((Integer)value).intValue()][2]; + int minlength = Math.min(data.length, p.length); + + for(int i = 0; i < minlength; i++) + { + p[i][0] = data[i][0]; + p[i][1] = data[i][1]; + } + + data = p; + } + else if(param == X) + { + subparam--; + + if(subparam >= 0 && subparam < data.length) + { + data[subparam][0] = ((Float)value).floatValue(); + } + } + else if(param == Y) + { + subparam--; + + if(subparam >= 0 && subparam < data.length) + { + data[subparam][1] = ((Float)value).floatValue(); + } + } + else if(param == THICKNESS) + { + thickness = ((Float)value).floatValue(); + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/ThickRect.java b/src/com/one/vector/ThickRect.java new file mode 100644 index 0000000..34ca909 --- /dev/null +++ b/src/com/one/vector/ThickRect.java @@ -0,0 +1,223 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class ThickRect extends VectorElement +{ + protected ThickLine[] lines = new ThickLine[4]; + protected float[] data = new float[4]; + protected float thickness; + + public ThickRect() + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + thickness = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + + thickness = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + + dos.writeFloat(thickness); + + writeTransformList(dos); + } + + public void create() + { + lines[0] = new ThickLine(color, NORMAL, data[0], data[1], data[0] + data[2], data[1], thickness); + lines[1] = new ThickLine(color, NORMAL, data[0], data[1], data[0], data[1] + data[3], thickness); + lines[2] = new ThickLine(color, NORMAL, data[0] + data[2], data[1], data[0] + data[2], data[1] + data[3], thickness); + lines[3] = new ThickLine(color, NORMAL, data[0], data[1] + data[3], data[0] + data[2], data[1] + data[3], thickness); + + lines[0].setGroup(group); + lines[1].setGroup(group); + lines[2].setGroup(group); + lines[3].setGroup(group); + } + + public void rescale() + { + lines[0].rescale(); + lines[1].rescale(); + lines[2].rescale(); + lines[3].rescale(); + } + + public void setGroup(Group grp) + { + super.setGroup(grp); + + lines[0].setGroup(grp); + lines[1].setGroup(grp); + lines[2].setGroup(grp); + lines[3].setGroup(grp); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + lines[0].paint(g); + lines[1].paint(g); + lines[2].paint(g); + lines[3].paint(g); + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + changed = true; + break; + + case X: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case Y: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case WIDTH: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case HEIGHT: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case THICKNESS: + thickness = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + switch(param) + { + case X: + return new Float(data[0]); + + case Y: + return new Float(data[1]); + + case WIDTH: + return new Float(data[2]); + + case HEIGHT: + return new Float(data[3]); + + case THICKNESS: + return new Float(thickness); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + switch(param) + { + case X: + data[0] = ((Float)value).floatValue(); + break; + + case Y: + data[1] = ((Float)value).floatValue(); + break; + + case WIDTH: + data[2] = ((Float)value).floatValue(); + break; + + case HEIGHT: + data[3] = ((Float)value).floatValue(); + break; + + case THICKNESS: + thickness = ((Float)value).floatValue(); + break; + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/ThickTriangle.java b/src/com/one/vector/ThickTriangle.java new file mode 100644 index 0000000..1efc9ff --- /dev/null +++ b/src/com/one/vector/ThickTriangle.java @@ -0,0 +1,270 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class ThickTriangle extends VectorElement +{ + protected ThickLine[] lines = new ThickLine[3]; + protected float[] data = new float[6]; + protected float thickness; + + public ThickTriangle() + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + data[5] = 0; + + thickness = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + data[4] = dis.readFloat(); + data[5] = dis.readFloat(); + + thickness = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + dos.writeFloat(data[4]); + dos.writeFloat(data[5]); + + dos.writeFloat(thickness); + + writeTransformList(dos); + } + + public void create() + { + lines[0] = new ThickLine(color, NORMAL, data[0], data[1], data[2], data[3], thickness); + lines[1] = new ThickLine(color, NORMAL, data[2], data[3], data[4], data[5], thickness); + lines[2] = new ThickLine(color, NORMAL, data[4], data[5], data[0], data[1], thickness); + + lines[0].setGroup(group); + lines[1].setGroup(group); + lines[2].setGroup(group); + } + + public void rescale() + { + lines[0].rescale(); + lines[1].rescale(); + lines[2].rescale(); + } + + public void setGroup(Group grp) + { + super.setGroup(grp); + + lines[0].setGroup(grp); + lines[1].setGroup(grp); + lines[2].setGroup(grp); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + lines[0].paint(g); + lines[1].paint(g); + lines[2].paint(g); + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + subparam = transform.getSubParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + changed = true; + break; + + case X: + switch(subparam) + { + case 1: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 2: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 3: + data[4] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + + case Y: + switch(subparam) + { + case 1: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 2: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 3: + data[5] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == X) + { + if(subparam == 1) + { + return new Float(data[0]); + } + else if(subparam == 2) + { + return new Float(data[2]); + } + else if(subparam == 3) + { + return new Float(data[4]); + } + } + else if(param == Y) + { + if(subparam == 1) + { + return new Float(data[1]); + } + else if(subparam == 2) + { + return new Float(data[3]); + } + else if(subparam == 3) + { + return new Float(data[5]); + } + } + else if(param == THICKNESS) + { + return new Float(thickness); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == X) + { + if(subparam == 1) + { + data[0] = ((Float)value).floatValue(); + } + else if(subparam == 2) + { + data[2] = ((Float)value).floatValue(); + } + else if(subparam == 3) + { + data[4] = ((Float)value).floatValue(); + } + } + else if(param == Y) + { + if(subparam == 1) + { + data[1] = ((Float)value).floatValue(); + } + else if(subparam == 2) + { + data[3] = ((Float)value).floatValue(); + } + else if(subparam == 3) + { + data[5] = ((Float)value).floatValue(); + } + } + else if(param == THICKNESS) + { + thickness = ((Float)value).floatValue(); + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/Transform.java b/src/com/one/vector/Transform.java new file mode 100644 index 0000000..2690ba4 --- /dev/null +++ b/src/com/one/vector/Transform.java @@ -0,0 +1,316 @@ +package com.one.vector; + +import java.io.*; + +public class Transform +{ + public static final int NORMAL = 0; + public static final int EXTEND = 1; + public static final int LOOP = 2; + public static final int SLIDE = 3; + public static final int TRIGGER = 4; + + protected String name; + protected ArrayData data; + protected int param, subparam; + protected int startframe, endframe; + protected int preposition, postposition; + protected int mode; + protected int length, activelength; + + protected int position; + + public Transform(ArrayData data, int param, int startframe, int endframe, int mode) + { + name = VectorElement.defaultName(); + + this.data = data; + this.param = param; + + subparam = -1; + + setBounds(startframe, endframe); + setMode(mode); + } + + public Transform(ArrayData data, int param, int startframe, int endframe, int pregap, int postgap, int mode) + { + name = VectorElement.defaultName(); + + this.data = data; + this.param = param; + + subparam = -1; + + setBounds(startframe, endframe, pregap, postgap); + setMode(mode); + } + + public Transform(ArrayData data, int param, int subparam, int startframe, int endframe, int mode) + { + name = VectorElement.defaultName(); + + this.data = data; + this.param = param; + this.subparam = subparam; + + setBounds(startframe, endframe); + setMode(mode); + } + + public Transform(ArrayData data, int param, int subparam, int startframe, int endframe, int pregap, int postgap, int mode) + { + name = VectorElement.defaultName(); + + this.data = data; + this.param = param; + this.subparam = subparam; + + setBounds(startframe, endframe, pregap, postgap); + setMode(mode); + } + + public Transform(DataInputStream dis) throws IOException + { + read(dis); + } + + public int getParam() + { + return param; + } + + public int getSubParam() + { + return subparam; + } + + public void setFrame(int frame) + { + position = frame - startframe; + + if(mode == LOOP) + { + if(position >= 0) + { + position %= length; + } + } + else if(mode == SLIDE) + { + if(position >= 0) + { + if(position / length % 2 == 0) + { + position %= length; + } + else + { + position = length - position % length; + } + } + } + } + + public boolean isApplied() + { + if(mode == EXTEND) + { + return true; + } + else if(mode == LOOP || mode == SLIDE) + { + return position >= preposition && position <= postposition; + } + else if(mode == TRIGGER) + { + return position == -1 || position == 0; + } + else + { + return position >= 0 && position <= length; + } + } + + public float getPosition() + { + if(mode == EXTEND) + { + return (float)position / (float)length; + } + else if(mode == LOOP || mode == SLIDE) + { + if(position >= 0) + { + if(position < preposition) + { + return 0.0f; + } + else if(position <= postposition) + { + return (float)(position - preposition) / (float)activelength; + } + else + { + return 1.0f; + } + } + else + { + return 0.0f; + } + } + else if(mode == TRIGGER) + { + if(position < 0) + { + return 0.0f; + } + else + { + return 1.0f; + } + } + else + { + if(position < 0) + { + return 0.0f; + } + else if(position <= length) + { + return (float)position / (float)length; + } + else + { + return 1.0f; + } + } + } + + public ArrayData getData() + { + return data; + } + + public void setBounds(int startframe, int endframe) + { + this.startframe = startframe; + this.endframe = endframe; + + length = endframe - startframe; + activelength = length; + + preposition = 0; + postposition = length; + } + + public void setBounds(int startframe, int endframe, int pregap, int postgap) + { + this.startframe = startframe; + this.endframe = endframe; + + length = endframe - startframe; + activelength = length - pregap - postgap; + + preposition = pregap; + postposition = length - postgap; + } + + public int getStartFrame() + { + return startframe; + } + + public int getEndFrame() + { + return endframe; + } + + public int getPreGap() + { + return preposition; + } + + public int getPostGap() + { + return length - postposition; + } + + public int getLength() + { + return length; + } + + public int getActiveLength() + { + return activelength; + } + + public void setMode(int mode) + { + this.mode = mode; + } + + public int getMode() + { + return mode; + } + + public void setName(String nm) + { + if(nm != null) + { + name = nm; + } + else + { + name = VectorElement.defaultName(); + } + } + + public String getName() + { + return name; + } + + public void setParam(int param) + { + this.param = param; + } + + public void setSubParam(int subparam) + { + this.subparam = subparam; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + + data = new ArrayData(dis); + + param = dis.readInt(); + subparam = dis.readInt(); + + setBounds(dis.readInt(), dis.readInt(), dis.readInt(), dis.readInt()); + setMode(dis.readUnsignedByte()); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + + data.write(dos); + + dos.writeInt(param); + dos.writeInt(subparam); + + dos.writeInt(getStartFrame()); + dos.writeInt(getEndFrame()); + dos.writeInt(getPreGap()); + dos.writeInt(getPostGap()); + + dos.writeByte(getMode()); + } +} diff --git a/src/com/one/vector/Triangle.java b/src/com/one/vector/Triangle.java new file mode 100644 index 0000000..27fad5b --- /dev/null +++ b/src/com/one/vector/Triangle.java @@ -0,0 +1,247 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class Triangle extends VectorElement +{ + protected float[] data = new float[6]; + protected int[] sdata = new int[6]; + + public Triangle() + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + data[5] = 0; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + color = dis.readInt(); + parseFlag(dis.readUnsignedByte()); + + data[0] = dis.readFloat(); + data[1] = dis.readFloat(); + data[2] = dis.readFloat(); + data[3] = dis.readFloat(); + data[4] = dis.readFloat(); + data[5] = dis.readFloat(); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeInt(color); + dos.writeByte(getFlag()); + + dos.writeFloat(data[0]); + dos.writeFloat(data[1]); + dos.writeFloat(data[2]); + dos.writeFloat(data[3]); + dos.writeFloat(data[4]); + dos.writeFloat(data[5]); + + writeTransformList(dos); + } + + public void rescale() + { + sdata[0] = getScaled(data[0], 0); + sdata[1] = getScaled(data[1], 1); + sdata[2] = getScaled(data[2], 0); + sdata[3] = getScaled(data[3], 1); + sdata[4] = getScaled(data[4], 0); + sdata[5] = getScaled(data[5], 1); + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + if(group.image.usecolor) + { + g.setColor(color); + } + + if(fill) + { + g.fillTriangle(sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]); + } + else + { + g.setStrokeStyle(stroke); + + g.drawLine(sdata[0], sdata[1], sdata[2], sdata[3]); + g.drawLine(sdata[2], sdata[3], sdata[4], sdata[5]); + g.drawLine(sdata[4], sdata[5], sdata[0], sdata[1]); + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + subparam = transform.getSubParam(); + + switch(param) + { + case SHOW: + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + break; + + case COLOR: + color = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + break; + + case X: + switch(subparam) + { + case 1: + data[0] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 2: + data[2] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 3: + data[4] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + + case Y: + switch(subparam) + { + case 1: + data[1] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 2: + data[3] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case 3: + data[5] = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + } + break; + } + } + } + + if(flag && changed) + { + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == X) + { + if(subparam == 1) + { + return new Float(data[0]); + } + else if(subparam == 2) + { + return new Float(data[2]); + } + else if(subparam == 3) + { + return new Float(data[4]); + } + } + else if(param == Y) + { + if(subparam == 1) + { + return new Float(data[1]); + } + else if(subparam == 2) + { + return new Float(data[3]); + } + else if(subparam == 3) + { + return new Float(data[5]); + } + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == X) + { + if(subparam == 1) + { + data[0] = ((Float)value).floatValue(); + } + else if(subparam == 2) + { + data[2] = ((Float)value).floatValue(); + } + else if(subparam == 3) + { + data[4] = ((Float)value).floatValue(); + } + } + else if(param == Y) + { + if(subparam == 1) + { + data[1] = ((Float)value).floatValue(); + } + else if(subparam == 2) + { + data[3] = ((Float)value).floatValue(); + } + else if(subparam == 3) + { + data[5] = ((Float)value).floatValue(); + } + } + } + + public void writeSVG(PrintStream ps) + { + ps.print("\t\t\t"); + } +} diff --git a/src/com/one/vector/TriangleArray.java b/src/com/one/vector/TriangleArray.java new file mode 100644 index 0000000..25bf719 --- /dev/null +++ b/src/com/one/vector/TriangleArray.java @@ -0,0 +1,417 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.io.*; + +public class TriangleArray extends VectorElement +{ + protected float[][] data = new float[6][]; + protected int[][] sdata; + protected int[] colors; + protected int count; + protected ArrayData clr, x1, y1, x2, y2, x3, y3; + + public TriangleArray() + { + clr = new ArrayData(); + x1 = new ArrayData(); + y1 = new ArrayData(); + x2 = new ArrayData(); + y2 = new ArrayData(); + x3 = new ArrayData(); + y3 = new ArrayData(); + + count = 2; + } + + public void read(DataInputStream dis) throws IOException + { + name = dis.readUTF(); + parseFlag(dis.readUnsignedByte()); + + count = dis.readUnsignedShort(); + + clr = new ArrayData(dis); + x1 = new ArrayData(dis); + y1 = new ArrayData(dis); + x2 = new ArrayData(dis); + y2 = new ArrayData(dis); + x3 = new ArrayData(dis); + y3 = new ArrayData(dis); + + readTransformList(dis); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeUTF(name); + dos.writeByte(getFlag()); + + dos.writeShort(count); + + clr.write(dos); + x1.write(dos); + y1.write(dos); + x2.write(dos); + y2.write(dos); + x3.write(dos); + y3.write(dos); + + writeTransformList(dos); + } + + public void create() + { + colors = AuxMath.linearArrayRGB(clr, count); + + data[0] = AuxMath.specificArrayFloat(x1, count); + data[1] = AuxMath.specificArrayFloat(y1, count); + data[2] = AuxMath.specificArrayFloat(x2, count); + data[3] = AuxMath.specificArrayFloat(y2, count); + data[4] = AuxMath.specificArrayFloat(x3, count); + data[5] = AuxMath.specificArrayFloat(y3, count); + + sdata = new int[6][count]; + } + + public void rescale() + { + for(int i = 0; i < count; i++) + { + sdata[0][i] = getScaled(data[0][i], 0); + sdata[1][i] = getScaled(data[1][i], 1); + sdata[2][i] = getScaled(data[2][i], 0); + sdata[3][i] = getScaled(data[3][i], 1); + sdata[4][i] = getScaled(data[4][i], 0); + sdata[5][i] = getScaled(data[5][i], 1); + } + } + + public void paint(Graphics g) + { + if(hidden) + { + return; + } + + g.setStrokeStyle(stroke); + + if(group.image.usecolor) + { + if(fill) + { + for(int i = 0; i < count; i++) + { + g.setColor(colors[i]); + g.fillTriangle(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], sdata[4][i], sdata[5][i]); + } + } + else + { + for(int i = 0; i < count; i++) + { + g.setColor(colors[i]); + + g.drawLine(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i]); + g.drawLine(sdata[2][i], sdata[3][i], sdata[4][i], sdata[5][i]); + g.drawLine(sdata[4][i], sdata[5][i], sdata[0][i], sdata[1][i]); + } + } + } + else + { + if(fill) + { + for(int i = 0; i < count; i++) + { + g.fillTriangle(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i], sdata[4][i], sdata[5][i]); + } + } + else + { + for(int i = 0; i < count; i++) + { + g.drawLine(sdata[0][i], sdata[1][i], sdata[2][i], sdata[3][i]); + g.drawLine(sdata[2][i], sdata[3][i], sdata[4][i], sdata[5][i]); + g.drawLine(sdata[4][i], sdata[5][i], sdata[0][i], sdata[1][i]); + } + } + } + } + + public void update(boolean flag, boolean changed) + { + Transform transform; + int param, subparam; + ArrayData v; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + transform.setFrame(group.image.frame); + + if(transform.isApplied()) + { + param = transform.getParam(); + + if(param == SHOW) + { + setHidden(AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition())); + } + else + { + subparam = transform.getSubParam(); + + if(subparam == 0) + { + if(param == INT_A) + { + clr.inta = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + else if(param == INT_B) + { + clr.intb = AuxMath.linearFunctionRGB(transform.getData(), transform.getPosition()); + } + + continue; + } + else if(subparam == 1) + { + v = x1; + } + else if(subparam == 2) + { + v = y1; + } + else if(subparam == 3) + { + v = x2; + } + else if(subparam == 4) + { + v = y2; + } + else if(subparam == 5) + { + v = x3; + } + else if(subparam == 6) + { + v = y3; + } + else + { + continue; + } + + switch(param) + { + case VAL_A: + v.vala = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case VAL_B: + v.valb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_A: + v.diva = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_B: + v.divb = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_C: + v.divc = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case DIV_D: + v.divd = AuxMath.specificFunctionFloat(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_A: + v.inta = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + + case INT_B: + v.intb = AuxMath.specificFunctionInt(transform.getData(), transform.getPosition()); + changed = true; + break; + } + } + } + } + + if(flag && changed) + { + create(); + rescale(); + } + } + + public Object getValue(int param, int subparam) + { + if(param == COUNT) + { + return new Integer(count); + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x1; + } + else if(subparam == 2) + { + v = y1; + } + else if(subparam == 3) + { + v = x2; + } + else if(subparam == 4) + { + v = y2; + } + else if(subparam == 5) + { + v = x3; + } + else if(subparam == 6) + { + v = y3; + } + else + { + return null; + } + + switch(param) + { + case VAL_A: + return new Float(v.vala); + + case VAL_B: + return new Float(v.valb); + + case DIV_A: + return new Float(v.diva); + + case DIV_B: + return new Float(v.divb); + + case DIV_C: + return new Float(v.divc); + + case DIV_D: + return new Float(v.divd); + + case INT_A: + return new Integer(v.inta); + + case INT_B: + return new Integer(v.intb); + + case FUNCTION: + return new Integer(v.type); + } + + return null; + } + + public void setValue(Object value, int param, int subparam) + { + if(param == COUNT) + { + count = ((Integer)value).intValue(); + return; + } + + ArrayData v; + + if(subparam == 0) + { + v = clr; + } + else if(subparam == 1) + { + v = x1; + } + else if(subparam == 2) + { + v = y1; + } + else if(subparam == 3) + { + v = x2; + } + else if(subparam == 4) + { + v = y2; + } + else if(subparam == 5) + { + v = x3; + } + else if(subparam == 6) + { + v = y3; + } + else + { + return; + } + + switch(param) + { + case VAL_A: + v.vala = ((Float)value).floatValue(); + break; + + case VAL_B: + v.valb = ((Float)value).floatValue(); + break; + + case DIV_A: + v.diva = ((Float)value).floatValue(); + break; + + case DIV_B: + v.divb = ((Float)value).floatValue(); + break; + + case DIV_C: + v.divc = ((Float)value).floatValue(); + break; + + case DIV_D: + v.divd = ((Float)value).floatValue(); + break; + + case INT_A: + v.inta = ((Integer)value).intValue(); + break; + + case INT_B: + v.intb = ((Integer)value).intValue(); + break; + + case FUNCTION: + v.type = ((Integer)value).intValue(); + break; + } + } +} diff --git a/src/com/one/vector/VectorElement.java b/src/com/one/vector/VectorElement.java new file mode 100644 index 0000000..bd3f7dc --- /dev/null +++ b/src/com/one/vector/VectorElement.java @@ -0,0 +1,710 @@ +package com.one.vector; + +import javax.microedition.lcdui.Graphics; +import java.util.Vector; +import java.util.Enumeration; +import java.io.*; + +public abstract class VectorElement +{ + public static final int NORMAL = 0; + public static final int DOTTED = 1; + public static final int FILL = 2; + public static final int HIDDEN = 4; + + public static final int SHOW = 0, + COLOR = 1, + X = 2, + Y = 3, + WIDTH = 4, + HEIGHT = 5, + ARC_WIDTH = 6, + ARC_HEIGHT = 7, + START = 8, + LENGTH = 9, + ROTATION = 10, + ANGLE = 11, + THICKNESS = 12, + OFFSET_X = 13, + OFFSET_Y = 14, + SCALE_X = 15, + SCALE_Y = 16, + VAL_A = 17, + VAL_B = 18, + DIV_A = 19, + DIV_B = 20, + DIV_C = 21, + DIV_D = 22, + INT_A = 23, + INT_B = 24, + FUNCTION = 25, + POLY_COUNT = 26, + COUNT = 27, + QUALITY = 28, + MODE = 29, + FILE = 30; + + public static final int CLIP = 0, + LINE = 1, + ARC = 2, + RECT = 3, + ROUND_RECT = 4, + POINT = 5, + TRIANGLE = 6, + POLYLINE = 7, + POLYGON = 8, + PARAMETRIC_CURVE = 9, + BEZIER_CURVE = 10, + THICK_LINE = 11, + THICK_RECT = 12, + THICK_TRIANGLE = 13, + THICK_POLYLINE = 14, + THICK_POLYGON = 15, + THICK_PARAMETRIC_CURVE = 16, + THICK_BEZIER_CURVE = 17, + BITMAP = 18, + TEXTURE_ARC = 19, + TEXTURE_ROUND_RECT = 20, + TEXTURE_TRIANGLE = 21, + TEXTURE_POLYGON = 22, + GRADIENT_RECT = 23, + GRADIENT_CIRCLE = 24, + LINE_ARRAY = 25, + ARC_ARRAY = 26, + RECT_ARRAY = 27, + ROUND_RECT_ARRAY = 28, + POINT_ARRAY = 29, + TRIANGLE_ARRAY = 30, + POLYGON_ARRAY = 31; + + public static final String[] OBJECT_NAMES = + { + "Group", + "Comment", + "Clip", "Line", "Arc", "Rect", "RoundRect", "Point", "Tringle", "Polyline", "Polygon", "ParametricCurve", "BezierCurve", + "ThickLine", "ThickRect", "ThickTriangle", "ThickPolyline", "ThickPolygon", "ThickParametricCurve", "ThickBezierCurve", + "Bitmap", "TextureArc", "TextureRoundRect", "TextureTriangle", "TexturePolygon", + "GradientRect", "GradientCircle", + "LineArray", "ArcArray", "RectArray", "RoundRectArray", "PointArray", "TriangleArray", "PolygonArray", + "Visibility", "Color", "X", "Y", "Width", "Height", + "ArcWidth", "ArcHeight", "Start", "Length", "Rotation", "Angle", "Thickness", + "HorizontalOffset", "VerticalOffset", "HorizontalScale", "VerticalScale", + "ValA", "ValB", "DivA", "DivB", "DivC", "DivD", "IntA", "IntB", + "ColorReplace", "AreaFill", "LineFill", "ChannelMatrix", "PixelMatrix", "BitwiseFunction" + }; + + public static final int OFFSET_ELEMENTS = 2; + public static final int OFFSET_TRANSFORMS = 34; + public static final int OFFSET_EFFECTS = 59; + + public static VectorImage DEFAULT_IMAGE; + public static Group DEFAULT_GROUP; + + static + { + DEFAULT_IMAGE = new VectorImage(); + DEFAULT_GROUP = new Group(); + DEFAULT_IMAGE.addGroup(DEFAULT_GROUP); + } + + public static String defaultName() + { + return Long.toString(System.currentTimeMillis(), Character.MAX_RADIX).toUpperCase(); + } + + public static String getElementPrefix(int type) + { + return OBJECT_NAMES[type + OFFSET_ELEMENTS]; + } + + public static String getTransformPrefix(int param, int subparam) + { + if(subparam >= 0) + { + return Integer.toString(subparam) + OBJECT_NAMES[param + OFFSET_TRANSFORMS]; + } + else + { + return OBJECT_NAMES[param + OFFSET_TRANSFORMS]; + } + } + + public static String getEffectPrefix(int type) + { + return OBJECT_NAMES[type + OFFSET_EFFECTS]; + } + + protected String name; + protected Group group; + protected Vector transforms; + protected int transcount; + protected int color; + protected boolean fill; + protected int stroke; + protected boolean hidden; + + public VectorElement() + { + name = defaultName(); + + group = DEFAULT_GROUP; + + transforms = new Vector(); + transcount = 0; + + color = -1; + + parseFlag(NORMAL); + } + + public abstract void read(DataInputStream dis) throws IOException; + public abstract void write(DataOutputStream dos) throws IOException; + + public void writeSVG(PrintStream ps) + { + } + + protected void writeSVGTail(PrintStream ps, boolean usedotted, boolean usefill) + { + if(usedotted && !fill && stroke == Graphics.DOTTED) + { + ps.print(" stroke-dasharray=\"2\""); + } + + ps.print(" stroke=\"" + formatColor(color) + "\""); + + if(usefill) + { + if(fill) + { + ps.print(" fill=\"" + formatColor(color) + "\""); + } + else + { + ps.print(" fill=\"none\""); + } + } + + if(hidden) + { + ps.print(" visibility=\"hidden\""); + } + } + + protected void readTransformList(DataInputStream dis) throws IOException + { + transcount = dis.readUnsignedShort(); + + transforms.removeAllElements(); + transforms.ensureCapacity(transcount); + + for(int i = 0; i < transcount; i++) + { + transforms.addElement(new Transform(dis)); + } + } + + protected void writeTransformList(DataOutputStream dos) throws IOException + { + dos.writeShort(transcount); + + for(int i = 0; i < transcount; i++) + { + ((Transform)transforms.elementAt(i)).write(dos); + } + } + + public abstract void paint(Graphics g); + + public void setGroup(Group grp) + { + if(grp != null) + { + group = grp; + } + else + { + group = DEFAULT_GROUP; + } + } + + public Group getGroup() + { + return group; + } + + protected void parseFlag(int flag) + { + fill = (flag & FILL) != 0; + hidden = (flag & HIDDEN) != 0; + stroke = ((flag & DOTTED) != 0) ? Graphics.DOTTED : Graphics.SOLID; + } + + protected int getFlag() + { + int flag = NORMAL; + + if(fill) + { + flag |= FILL; + } + + if(hidden) + { + flag |= HIDDEN; + } + + if(stroke == Graphics.DOTTED) + { + flag |= DOTTED; + } + + return flag; + } + + public void setHidden(boolean hidden) + { + this.hidden = hidden; + } + + protected void setHidden(float v) + { + hidden = v < 0.5f; + } + + public boolean isHidden() + { + return hidden; + } + + public void setFill(boolean fill) + { + this.fill = fill; + } + + public boolean isFill() + { + return fill; + } + + public void setDotted(boolean dotted) + { + stroke = dotted ? Graphics.DOTTED : Graphics.SOLID; + } + + public boolean isDotted() + { + return stroke == Graphics.DOTTED; + } + + public void setColor(int color) + { + this.color = color; + } + + public int getColor() + { + return color; + } + + public int getScaled(float v, int mode) + { + switch(mode) + { + case 0: + return (int)((v + group.param[0]) * group.param[2]); + + case 1: + return (int)((v + group.param[1]) * group.param[3]); + + case 2: + return (int)(v * group.param[2]); + + case 3: + return (int)(v * group.param[3]); + + case 4: + return (int)(v * group.param[6]); + } + + return (int)v; + } + + public float getInternal(int v, int mode) + { + switch(mode) + { + case 0: + return (float)v / group.param[2] - group.param[0]; + + case 1: + return (float)v / group.param[3] - group.param[1]; + + case 2: + return (float)v / group.param[2]; + + case 3: + return (float)v / group.param[3]; + + case 4: + return (float)v / group.param[6]; + } + + return (float)v; + } + + public void addTransform(Transform t, boolean flag) + { + if(flag) + { + t.setName(group.image.nextTransformName(t.getParam(), t.getSubParam())); + } + else + { + t.setName(group.image.currentTransformName(t.getParam(), t.getSubParam())); + } + + transforms.addElement(t); + transcount = transforms.size(); + } + + public void create() + { + } + + public abstract void rescale(); + public abstract void update(boolean crallow, boolean crforce); + + public void setName(String nm) + { + if(nm != null) + { + name = nm; + } + else + { + name = defaultName(); + } + } + + public String getName() + { + return name; + } + + public Enumeration listTransforms() + { + return transforms.elements(); + } + + public Transform getTransform(String name) + { + Transform transform; + + for(int i = 0; i < transcount; i++) + { + transform = (Transform)transforms.elementAt(i); + + if(transform.getName().equals(name)) + { + return transform; + } + } + + return null; + } + + public void deleteTransform(Transform transform) + { + transforms.removeElement(transform); + transcount = transforms.size(); + } + + public void arrangeTransforms(int index, int newindex) + { + if(index < 0) + { + index = 0; + } + else if(index >= transforms.size()) + { + index = transforms.size() - 1; + } + + if(newindex < 0) + { + newindex = 0; + } + else if(newindex >= transforms.size()) + { + newindex = transforms.size() - 1; + } + + Object temp = transforms.elementAt(newindex); + transforms.setElementAt(transforms.elementAt(index), newindex); + transforms.setElementAt(temp, index); + } + + public abstract Object getValue(int param, int subparam); + public abstract void setValue(Object value, int param, int subparam); + + public static String formatColor(int color) + { + String res = Integer.toHexString(color & 0xFFFFFF).toUpperCase(); + + while(res.length() < 6) + { + res = "0" + res; + } + + return "#" + res; + } + + public static VectorElement getInstance(int type) + { + switch(type) + { + case CLIP: + return new Clip(); + + case LINE: + return new Line(); + + case ARC: + return new Arc(); + + case RECT: + return new Rect(); + + case ROUND_RECT: + return new RoundRect(); + + case POINT: + return new Point(); + + case TRIANGLE: + return new Triangle(); + + case POLYLINE: + return new Polyline(); + + case POLYGON: + return new Polygon(); + + case PARAMETRIC_CURVE: + return new ParametricCurve(); + + case BEZIER_CURVE: + return new BezierCurve(); + + case THICK_LINE: + return new ThickLine(); + + case THICK_RECT: + return new ThickRect(); + + case THICK_TRIANGLE: + return new ThickTriangle(); + + case THICK_POLYLINE: + return new ThickPolyline(); + + case THICK_POLYGON: + return new ThickPolygon(); + + case THICK_PARAMETRIC_CURVE: + return new ThickParametricCurve(); + + case THICK_BEZIER_CURVE: + return new ThickBezierCurve(); + + case BITMAP: + return new Bitmap(); + + case TEXTURE_ARC: + return new TextureArc(); + + case TEXTURE_ROUND_RECT: + return new TextureRoundRect(); + + case TEXTURE_TRIANGLE: + return new TextureTriangle(); + + case TEXTURE_POLYGON: + return new TexturePolygon(); + + case GRADIENT_RECT: + return new GradientRect(); + + case GRADIENT_CIRCLE: + return new GradientCircle(); + + case LINE_ARRAY: + return new LineArray(); + + case ARC_ARRAY: + return new ArcArray(); + + case RECT_ARRAY: + return new RectArray(); + + case ROUND_RECT_ARRAY: + return new RoundRectArray(); + + case POINT_ARRAY: + return new PointArray(); + + case TRIANGLE_ARRAY: + return new TriangleArray(); + + case POLYGON_ARRAY: + return new PolygonArray(); + + default: + //throw new IllegalArgumentException("Unknown element type: " + Integer.toString(type)); + throw new IllegalArgumentException(); + } + } + + public static int elementType(VectorElement ve) + { + if(ve instanceof Clip) + { + return CLIP; + } + else if(ve instanceof Line) + { + return LINE; + } + else if(ve instanceof Arc) + { + return ARC; + } + else if(ve instanceof Rect) + { + return RECT; + } + else if(ve instanceof RoundRect) + { + return ROUND_RECT; + } + else if(ve instanceof Point) + { + return POINT; + } + else if(ve instanceof Triangle) + { + return TRIANGLE; + } + else if(ve instanceof Polyline) + { + return POLYLINE; + } + else if(ve instanceof Polygon) + { + return POLYGON; + } + else if(ve instanceof ParametricCurve) + { + return PARAMETRIC_CURVE; + } + else if(ve instanceof BezierCurve) + { + return BEZIER_CURVE; + } + else if(ve instanceof ThickLine) + { + return THICK_LINE; + } + else if(ve instanceof ThickRect) + { + return THICK_RECT; + } + else if(ve instanceof ThickTriangle) + { + return THICK_TRIANGLE; + } + else if(ve instanceof ThickPolyline) + { + return THICK_POLYLINE; + } + else if(ve instanceof ThickPolygon) + { + return THICK_POLYGON; + } + else if(ve instanceof ThickParametricCurve) + { + return THICK_PARAMETRIC_CURVE; + } + else if(ve instanceof ThickBezierCurve) + { + return THICK_BEZIER_CURVE; + } + else if(ve instanceof Bitmap) + { + return BITMAP; + } + else if(ve instanceof TextureArc) + { + return TEXTURE_ARC; + } + else if(ve instanceof TextureRoundRect) + { + return TEXTURE_ROUND_RECT; + } + else if(ve instanceof TextureTriangle) + { + return TEXTURE_TRIANGLE; + } + else if(ve instanceof TexturePolygon) + { + return TEXTURE_POLYGON; + } + else if(ve instanceof GradientRect) + { + return GRADIENT_RECT; + } + else if(ve instanceof GradientCircle) + { + return GRADIENT_CIRCLE; + } + else if(ve instanceof LineArray) + { + return LINE_ARRAY; + } + else if(ve instanceof ArcArray) + { + return ARC_ARRAY; + } + else if(ve instanceof RectArray) + { + return RECT_ARRAY; + } + else if(ve instanceof RoundRectArray) + { + return ROUND_RECT_ARRAY; + } + else if(ve instanceof PointArray) + { + return POINT_ARRAY; + } + else if(ve instanceof TriangleArray) + { + return TRIANGLE_ARRAY; + } + else if(ve instanceof PolygonArray) + { + return POLYGON_ARRAY; + } + else + { + //throw new IllegalArgumentException("Unknown element: " + ve.getClass().getName()); + throw new IllegalArgumentException(); + } + } + + public String toString() + { + return getElementPrefix(elementType(this)) + ":" + name + "@" + group.getName(); + } +} diff --git a/src/com/one/vector/VectorImage.java b/src/com/one/vector/VectorImage.java new file mode 100644 index 0000000..0850b34 --- /dev/null +++ b/src/com/one/vector/VectorImage.java @@ -0,0 +1,881 @@ +package com.one.vector; + +import javax.microedition.lcdui.*; +import java.util.*; +import java.io.*; +import com.vmx.ProgressCallback; + +public class VectorImage +{ + public static final int VERSION = 0x0400; + + protected Vector groups; + protected int count; + + protected String title; + protected String description; + protected Vector comments; + protected byte[] extra; + + protected int version; + + protected int backcolor; + protected boolean useback; + public boolean usecolor; + + public int width, height; + protected int nativewidth, nativeheight; + + public float[] param = new float[6]; + public int frame; + + protected float fps; + protected long framedelay; + protected int maxframe; + protected int loop; + + protected int[] clip = new int[4]; + protected int color, stroke; + + protected Image offscreen; + protected Graphics offgraphics; + protected int[] rgb; + protected int[] temp; + protected int fragcount; + protected int fragwidth, fragheight; + + protected int[] nametable = new int[VectorElement.OBJECT_NAMES.length]; + + public VectorImage(DataInputStream dis) throws IOException + { + read(dis); + } + + public void read(DataInputStream dis) throws IOException + { + if(dis.readInt() != 0x4D564900) + { + throw new IOException("MVI signature not found"); + } + + version = dis.readUnsignedShort(); + + if((version & 0xFF00) != (VERSION & 0xFF00)) + { + throw new IOException("Incompatible version: " + Integer.toHexString(version).toUpperCase()); + } + + title = dis.readUTF(); + description = dis.readUTF(); + + nativewidth = dis.readInt(); + nativeheight = dis.readInt(); + + param[0] = dis.readFloat(); + param[1] = dis.readFloat(); + param[4] = dis.readFloat(); + param[5] = dis.readFloat(); + + usecolor = dis.readBoolean(); + useback = dis.readBoolean(); + backcolor = dis.readInt(); + + maxframe = dis.readInt(); + loop = dis.readInt(); + setFPS(dis.readFloat()); + + int i, n; + + n = dis.readInt(); + + try + { + extra = new byte[n]; + dis.read(extra); + } + catch(OutOfMemoryError oome) + { + extra = new byte[0]; + dis.skip(n); + } + + n = dis.readUnsignedShort(); + + for(i = 0; i < n; i++) + { + if(i < nametable.length) + { + nametable[i] = dis.readUnsignedShort(); + } + else + { + dis.readUnsignedShort(); + } + } + + n = dis.readUnsignedShort(); + comments = new Vector(n); + + for(i = 0; i < n; i++) + { + comments.addElement(new Comment(dis)); + } + + count = dis.readUnsignedShort(); + groups = new Vector(count); + + Group grp; + + for(i = 0; i < count; i++) + { + grp = new Group(dis); + grp.setImage(this); + groups.addElement(grp); + } + + scale(-1, -1); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeInt(0x4D564900); + + dos.writeShort(VERSION); + + dos.writeUTF(title); + dos.writeUTF(description); + + dos.writeInt(nativewidth); + dos.writeInt(nativeheight); + + dos.writeFloat(param[0]); + dos.writeFloat(param[1]); + dos.writeFloat(param[4]); + dos.writeFloat(param[5]); + + dos.writeBoolean(usecolor); + dos.writeBoolean(useback); + dos.writeInt(backcolor); + + dos.writeInt(maxframe); + dos.writeInt(loop); + dos.writeFloat(fps); + + int i; + + dos.writeInt(extra.length); + dos.write(extra); + + dos.writeShort(nametable.length); + + for(i = 0; i < nametable.length; i++) + { + dos.writeShort(nametable[i]); + } + + dos.writeShort(comments.size()); + + for(i = 0; i < comments.size(); i++) + { + ((Comment)comments.elementAt(i)).write(dos); + } + + dos.writeShort(count); + + for(i = 0; i < count; i++) + { + ((Group)groups.elementAt(i)).write(dos); + } + + dos.writeShort(0); + } + + public VectorImage() + { + version = VERSION; + + title = VectorElement.defaultName(); + description = title; + + nativewidth = 1000; + nativeheight = 1000; + + param[0] = 0; + param[1] = 0; + param[2] = 1; + param[3] = 1; + param[4] = 1; + param[5] = 1; + + usecolor = true; + useback = true; + backcolor = 0xFF000000; + + maxframe = 0; + loop = 0; + setFPS(0); + + comments = new Vector(); + extra = new byte[0]; + + int i; + + for(i = 0; i < nametable.length; i++) + { + nametable[i] = 0; + } + + groups = new Vector(); + count = 0; + } + + public void writeSVG(PrintStream ps, String notice, ProgressCallback callback) + { + int prevwidth = width; + int prevheight = height; + int prevframe = frame; + + if(callback != null) + { + callback.setProgress(0); + callback.setMax(maxframe + 1); + } + + scale(-1, -1); + + ps.println(""); + + if(notice != null) + { + ps.println(""); + } + + ps.print(""); + + ps.println("\t" + title + ""); + ps.println("\t" + description + ""); + + ps.print("\t"); + + String dur = Float.toString((float)(framedelay) / 1000f); + Group grp; + + for(frame = 0; frame <= maxframe; frame++) + { + ps.println("\t"); + + ps.print("\t\t"); + + for(int i = 0; i < count; i++) + { + grp = (Group)groups.elementAt(i); + + grp.update(true, false); + grp.writeSVG(ps); + } + + ps.println("\t"); + + if(callback != null) + { + callback.progress(1); + } + } + + ps.println(""); + + gotoFrame(prevframe); + scale(prevwidth, prevheight); + } + + public void addGroup(Group grp) + { + grp.setName(nextGroupName()); + grp.setImage(this); + grp.rescale(); + + groups.addElement(grp); + count = groups.size(); + } + + public void gotoFrame(int target) + { + if(target < 0) + { + target = 0; + } + else if(target > maxframe) + { + target = maxframe; + } + + if(target > frame) + { + do + { + frame++; + + for(int i = 0; i < count; i++) + { + ((Group)groups.elementAt(i)).update(false, false); + } + } + while(frame < target); + } + else if(target < frame) + { + do + { + frame--; + + for(int i = 0; i < count; i++) + { + ((Group)groups.elementAt(i)).update(false, false); + } + } + while(frame > target); + } + + for(int i = 0; i < count; i++) + { + ((Group)groups.elementAt(i)).create(); + ((Group)groups.elementAt(i)).rescale(); + } + } + + public boolean nextFrame() + { + if(frame < maxframe) + { + frame++; + } + else if(loop != 0) + { + gotoFrame(0); + + if(loop > 0) + { + loop--; + } + } + else + { + return false; + } + + for(int i = 0; i < count; i++) + { + ((Group)groups.elementAt(i)).update(true, false); + } + + return true; + } + + public boolean prevFrame() + { + if(frame > 0) + { + frame--; + } + else if(loop != 0) + { + gotoFrame(maxframe); + + if(loop > 0) + { + loop--; + } + } + else + { + return false; + } + + for(int i = 0; i < count; i++) + { + ((Group)groups.elementAt(i)).update(true, false); + } + + return true; + } + + public int currentFrame() + { + return frame; + } + + public void update() + { + for(int i = 0; i < count; i++) + { + ((Group)groups.elementAt(i)).update(true, false); + } + } + + public void scale(int w, int h) + { + if(w < 0) + { + if(h < 0) + { + width = nativewidth; + height = nativeheight; + } + else + { + width = nativewidth * h / nativeheight; + height = h; + } + } + else + { + if(h < 0) + { + width = w; + height = nativeheight * w / nativewidth; + } + else + { + width = w; + height = h; + } + } + + param[2] = (1.0f / param[4]) * width; + param[3] = (1.0f / param[5]) * height; + + for(int i = 0; i < count; i++) + { + ((Group)groups.elementAt(i)).rescale(); + } + + System.gc(); + + try + { + offscreen = Image.createImage(width, height); + offgraphics = offscreen.getGraphics(); + + rgb = null; + temp = null; + fragcount = 1; + + do + { + fragwidth = width / fragcount; + fragheight = height / fragcount; + + try + { + rgb = new int[fragwidth * fragheight]; + temp = new int[rgb.length]; + } + catch(OutOfMemoryError oome) + { + rgb = null; + temp = null; + fragcount++; + } + } + while(rgb == null || temp == null); + } + catch(OutOfMemoryError oome) + { + offscreen = null; + offgraphics = null; + rgb = null; + temp = null; + } + } + + public void scaleToFit(int w, int h) + { + float nativeaspect = (float)nativewidth / (float)nativeheight; + float aspect = (float)w / (float)h; + + if(nativeaspect > aspect) + { + scale(w, (int)(w / nativeaspect)); + } + else + { + scale((int)(h * nativeaspect), h); + } + } + + public void setNativeSize(int nw, int nh) + { + nativewidth = nw; + nativeheight = nh; + } + + public int getWidth() + { + return width; + } + + public int getHeight() + { + return height; + } + + public int getNativeWidth() + { + return nativewidth; + } + + public int getNativeHeight() + { + return nativeheight; + } + + public void setUseColor(boolean usecolor) + { + this.usecolor = usecolor; + } + + public void setUseBack(boolean useback) + { + this.useback = useback; + } + + public boolean getUseColor() + { + return usecolor; + } + + public boolean getUseBack() + { + return useback; + } + + public void setBackColor(int backcolor) + { + this.backcolor = backcolor; + } + + public int getBackColor() + { + return backcolor; + } + + public void paint(Graphics g, int x, int y) + { + clip[0] = g.getClipX(); + clip[1] = g.getClipY(); + clip[2] = g.getClipWidth(); + clip[3] = g.getClipHeight(); + + color = g.getColor(); + stroke = g.getStrokeStyle(); + + g.clipRect(x, y, width, height); + g.translate(x, y); + + if(usecolor && useback) + { + g.setColor(backcolor); + g.fillRect(0, 0, width, height); + } + + if(offgraphics != null) + { + Group grp; + + for(int i = 0; i < count; i++) + { + grp = (Group)groups.elementAt(i); + + if(grp.hasEffects()) + { + offgraphics.translate(-offgraphics.getTranslateX(), -offgraphics.getTranslateY()); + offgraphics.setClip(0, 0, width, height); + + offgraphics.setColor(grp.getColor()); + offgraphics.fillRect(0, 0, width, height); + + offgraphics.translate(-grp.getTranslateX(), -grp.getTranslateY()); + grp.paint(offgraphics); + + Enumeration effects; + int fx, fy; + + for(fx = 0; fx < fragcount; fx++) + { + for(fy = 0; fy < fragcount; fy++) + { + offscreen.getRGB(rgb, 0, fragwidth, fx * fragwidth, fy * fragheight, fragwidth, fragheight); + effects = grp.listEffects(); + + while(effects.hasMoreElements()) + { + ((Effect)effects.nextElement()).apply(rgb, temp, fragwidth, fragheight); + } + + g.drawRGB(rgb, 0, fragwidth, grp.getTranslateX() + fx * fragwidth, grp.getTranslateY() + fy * fragheight, fragwidth, fragheight, true); + } + } + } + else + { + grp.paint(g); + } + } + } + else + { + for(int i = 0; i < count; i++) + { + ((Group)groups.elementAt(i)).paint(g); + } + } + + g.translate(-x, -y); + g.setClip(clip[0], clip[1], clip[2], clip[3]); + + g.setColor(color); + g.setStrokeStyle(stroke); + } + + public void setFPS(float fps) + { + this.fps = fps; + + if(fps <= 0) + { + framedelay = Integer.MAX_VALUE; + } + else if(fps <= 1000) + { + framedelay = (long)(1000f / fps); + } + else + { + framedelay = 1; + } + } + + public void setMaxFrame(int maxframe) + { + this.maxframe = maxframe; + } + + public void setLoopCount(int loop) + { + this.loop = loop; + } + + public float getFPS() + { + return fps; + } + + public long getFrameDelay() + { + return framedelay; + } + + public int getLoopCount() + { + return loop; + } + + public int getMaxFrame() + { + return maxframe; + } + + public int getVersion() + { + return version; + } + + public String nextGroupName() + { + return VectorElement.OBJECT_NAMES[0] + " " + Integer.toString(++nametable[0]); + } + + public String nextCommentName() + { + return VectorElement.OBJECT_NAMES[1] + " " + Integer.toString(++nametable[0]); + } + + public String nextElementName(int type) + { + return VectorElement.getElementPrefix(type) + " " + Integer.toString(++nametable[type + VectorElement.OFFSET_ELEMENTS]); + } + + public String currentElementName(int type) + { + return VectorElement.getElementPrefix(type) + " " + Integer.toString(nametable[type + VectorElement.OFFSET_ELEMENTS] + 1); + } + + public String nextTransformName(int param, int subparam) + { + return VectorElement.getTransformPrefix(param, subparam) + " " + Integer.toString(++nametable[param + VectorElement.OFFSET_TRANSFORMS]); + } + + public String currentTransformName(int param, int subparam) + { + return VectorElement.getTransformPrefix(param, subparam) + " " + Integer.toString(nametable[param + VectorElement.OFFSET_TRANSFORMS] + 1); + } + + public String nextEffectName(int type) + { + return VectorElement.getEffectPrefix(type) + " " + Integer.toString(++nametable[type + VectorElement.OFFSET_EFFECTS]); + } + + public Enumeration listGroups() + { + return groups.elements(); + } + + public Group getGroup(String name) + { + Group grp; + + for(int i = 0; i < count; i++) + { + grp = (Group)groups.elementAt(i); + + if(grp.getName().equals(name)) + { + return grp; + } + } + + return null; + } + + public void deleteGroup(Group grp) + { + groups.removeElement(grp); + count = groups.size(); + } + + public void arrangeGroups(int index, int newindex) + { + if(index < 0) + { + index = 0; + } + else if(index >= groups.size()) + { + index = groups.size() - 1; + } + + if(newindex < 0) + { + newindex = 0; + } + else if(newindex >= groups.size()) + { + newindex = groups.size() - 1; + } + + Object temp = groups.elementAt(newindex); + groups.setElementAt(groups.elementAt(index), newindex); + groups.setElementAt(temp, index); + } + + public void setTitle(String ttl) + { + if(ttl != null) + { + title = ttl; + } + else + { + title = ""; + } + } + + public void setDescription(String desc) + { + if(desc != null) + { + description = desc; + } + else + { + description = ""; + } + } + + public String getTitle() + { + return title; + } + + public String getDescription() + { + return description; + } + + public void setExtra(byte[] b) + { + if(b != null) + { + extra = b; + } + else + { + extra = new byte[0]; + } + } + + public byte[] getExtra() + { + return extra; + } + + public void addComment(Comment comment) + { + comments.addElement(comment); + } + + public Enumeration listComments() + { + return comments.elements(); + } + + public Comment getComment(String name) + { + Comment comment; + + for(int i = 0; i < count; i++) + { + comment = (Comment)comments.elementAt(i); + + if(comment.getName().equals(name)) + { + return comment; + } + } + + return null; + } + + public void deleteComment(Comment comment) + { + comments.removeElement(comment); + } +} diff --git a/src/com/vmx/AuxClass.java b/src/com/vmx/AuxClass.java new file mode 100644 index 0000000..0dd6d66 --- /dev/null +++ b/src/com/vmx/AuxClass.java @@ -0,0 +1,970 @@ +package com.vmx; + +import java.io.*; +import java.util.*; +import com.one.*; +import com.one.file.*; + +/** + * Ð’Ñпомогательный клаÑÑ. + * + * Сюда пихаетÑÑ Ð²Ñе, что должно быть доÑтупно вне пакета Ñ Ð¤Ðœ, + * но на ÑамоÑтоÑтельную библиотеку не Ñ‚Ñнет. + */ +public class AuxClass +{ + public static final int COPYBUFSIZE = 65536; + public static final int ARCBUFSIZE = 8192; + + public static final long MIN_THREAD_SLEEP = 10; + + public static final String RESTRICTED_CHARS = "\\/:*?\"<>|"; + public static final String SEPARATOR_CHARS = " *+-/;=|"; + public static final String TAB_AS_SPACES = " "; + + public static Random rnd = new Random(); + + // ÐÐ°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ…Ñ€Ð°Ð½Ð¸Ð»Ð¸Ñ‰ RMS + public static final String[] STORE_NAMES = + { + "options", + "favorites", + "bookmarks", + "panels", + "imgcache", + "mdlicons", + "mdldata", + "filetypes", + "uiicons" + }; + + public static final String STORE_PREFIX = "UniFM_"; // + + //Integer.toHexString((new AuxClass()).getClass().getName().hashCode()) + "_"; + + /** + * Получить название хранилища RMS в том виде, + * в каком его Ñледует иÑпользовать в программе. + * + * @param index номер хранилища + * @return Ð¸Ð¼Ñ Ñ…Ñ€Ð°Ð½Ð¸Ð»Ð¸Ñ‰Ð° + */ + public static String getStoreName(int index) + { + return STORE_PREFIX + STORE_NAMES[index]; + } + + /** + * ДоÑтать Ñлучайное чиÑло в диапазоне от from до to включительно. + */ + public static int randomFromRange(int from, int to) + { + return from + (rnd.nextInt() & 0x7FFFFFFF) % (to - from + 1); + } + + /** + * ДоÑтать Ñлучайное чиÑло в диапазоне от from до to включительно, + * причем такое, чтобы оно отличалоÑÑŒ от prev. + */ + public static int randomFromRange(int from, int to, int prev) + { + if(to - from < 1) + { + return randomFromRange(from, to); + } + + int curr; + + do + { + curr = randomFromRange(from, to); + } + while(curr == prev); + + return curr; + } + + /** + * Сформировать поÑледовательноÑÑ‚ÑŒ неповторÑющихÑÑ Ñлучайных чиÑел + * в диапазоне от from до to длиной count. + */ + public static int[] randomSequence(int from, int to, int count) + { + boolean[] flags = new boolean[to - from + 1]; + + if(count <= 0 || count > flags.length) + { + count = flags.length; + } + + int[] res = new int[count]; + + for(int i = 0; i < flags.length; i++) + { + flags[i] = false; + } + + int index; + + for(int i = 0; i < count; i++) + { + index = (rnd.nextInt() & 0x7FFFFFFF) % flags.length; + + if((index & 1) == 0) + { + while(flags[index]) + { + if(++index >= flags.length) + { + index = 0; + } + } + } + else + { + while(flags[index]) + { + if(--index < 0) + { + index = flags.length - 1; + } + } + } + + res[i] = from + index; + flags[index] = true; + } + + return res; + } + + /** + * Проверить Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° на наличие недопуÑтимых Ñимволов. + * К недопуÑтимым Ñимволам отноÑÑÑ‚ÑÑ \ / : * ? " < > | + * + * @param filename проверÑемое Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° + * @return true, еÑли Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° не Ñодержит недопуÑтимых Ñимволов + */ + public static boolean checkFileName(String filename) + { + char[] cs = RESTRICTED_CHARS.toCharArray(); + + for(int i = 0; i < cs.length; i++) + { + if(filename.indexOf(cs[i]) >= 0) + { + return false; + } + } + + return true; + } + + /** + * Вернуть общую чаÑÑ‚ÑŒ имен файлов fileA и fileB. + * + * Ðапример, Ð´Ð»Ñ Ð´Ð²ÑƒÑ… файлов: + * + * c:/folder1/folder2/folder10/folder20/file1.txt + * c:/folder3/folder10/folder20/file1.txt + * + * общей чаÑтью будет ÑвлÑÑ‚ÑŒÑÑ Ñтрока folder10/folder20/file1.txt + * + * @param fileA Ð¸Ð¼Ñ Ð¿ÐµÑ€Ð²Ð¾Ð³Ð¾ файла + * @param fileB Ð¸Ð¼Ñ Ð²Ñ‚Ð¾Ñ€Ð¾Ð³Ð¾ файла + * @return Ð¾Ð±Ñ‰Ð°Ñ Ñ‡Ð°ÑÑ‚ÑŒ имен файлов, или Ð¸Ð¼Ñ Ð¿ÐµÑ€Ð²Ð¾Ð³Ð¾ файла + */ + public static String getSharedNamePart(String fileA, String fileB) + { + if(fileA.equals(fileB)) + { + return fileA; + } + + int indexA = fileA.lastIndexOf('/', fileA.endsWith("/") ? fileA.length() - 2 : fileA.length() - 1); + int indexB = fileB.lastIndexOf('/', fileB.endsWith("/") ? fileB.length() - 2 : fileB.length() - 1); + + int index = -1; + + while(fileA.substring(indexA + 1).equals(fileB.substring(indexB + 1))) + { + index = indexA; + + indexA = fileA.lastIndexOf('/', indexA - 1); + indexB = fileB.lastIndexOf('/', indexB - 1); + } + + return fileA.substring(index + 1); + } + + /** + * Сделать из потенциально любой Ñтроки раÑширение файла. + * + * ЕÑли Ñтрока еÑÑ‚ÑŒ null, возвращаетÑÑ Ð¿ÑƒÑÑ‚Ð°Ñ Ñтрока. + * Иначе к ней, еÑли нужно, приклеиваетÑÑ Ñпереди точка. + * + * @param ext ... + * @return раÑширение файла + */ + public static String formatFileExtension(String ext) + { + if(ext == null) + { + return ""; + } + + if(ext.charAt(0) != '.') + { + ext = "." + ext; + } + + return ext; + } + + /** + * Превратить Ñтрочку в чиÑло. + * ЕÑли Ñто не получилоÑÑŒ, возвращаетÑÑ Ð²Ñ‚Ð¾Ñ€Ð¾Ð¹ параметр. + * + * @param s Ñтрочка Ñ Ñ‡Ð¸Ñлом + * @param v значение, которое вернетÑÑ, еÑли преобразование не удаÑÑ‚ÑÑ + * @return чиÑло, ÑодержащееÑÑ Ð² Ñтрочке, или второй параметр + */ + public static int parseInt(String s, int v) + { + try + { + return Integer.parseInt(s); + } + catch(Exception e) + { + return v; + } + } + + /** + * Превратить hex-Ñтрочку в чиÑло. + * ЕÑли Ñто не получилоÑÑŒ, возвращаетÑÑ Ð²Ñ‚Ð¾Ñ€Ð¾Ð¹ параметр. + * + * @param s Ñтрочка Ñ Ñ‡Ð¸Ñлом в hex + * @param v значение, которое вернетÑÑ, еÑли преобразование не удаÑÑ‚ÑÑ + * @return чиÑло, ÑодержащееÑÑ Ð² Ñтрочке, или второй параметр + */ + public static int parseHexInt(String s, int v) + { + try + { + return (int)Long.parseLong(s, 16); + } + catch(Exception e) + { + return v; + } + } + + /** + * Превратить Ñтрочку в дробное чиÑло. + * ЕÑли Ñто не получилоÑÑŒ, возвращаетÑÑ Ð²Ñ‚Ð¾Ñ€Ð¾Ð¹ параметр. + * + * @param s Ñтрочка Ñ Ð´Ñ€Ð¾Ð±Ð½Ñ‹Ð¼ чиÑлом + * @param v значение, которое вернетÑÑ, еÑли преобразование не удаÑÑ‚ÑÑ + * @return чиÑло, ÑодержащееÑÑ Ð² Ñтрочке, или второй параметр + */ + public static float parseFloat(String s, float v) + { + try + { + return Float.parseFloat(s); + } + catch(Exception e) + { + return v; + } + } + + /** + * Преобразовать double d в Ñтроку Ñ Ñ‚Ð¾Ñ‡Ð½Ð¾Ñтью afterdot знаков поÑле '.' + */ + public static String doubleToString(double d, int afterdot) + { + int factor = 1; + + for(int i = 0; i < afterdot; i++) + { + factor *= 10; + } + + if(afterdot == 0) + { + return Integer.toString((int)Math.floor(d * factor + 0.5) / factor); + } + else + { + return Double.toString(Math.floor(d * factor + 0.5) / factor); + } + } + + /** + * Преобразовать value в Ñтроку, дополнив Ñпереди нулÑми до pad знаков. + */ + public static String integerToString(int value, int pad) + { + StringBuffer res = new StringBuffer(pad); + + res.append(value); + + while(res.length() < pad) + { + res.insert(0, '0'); + } + + return res.toString(); + } + + /** + * Преобрразовать чиÑло Ñ Ñ„Ð¸ÐºÑированной точкой в Ñтроку. + * + * @param value чиÑло + * @param shift Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ñ„Ð¸ÐºÑированной точки + * @return Ñтрока Ñ Ñ‡Ð¸Ñлом + */ + public static String formatFPNumber(int value, int shift) + { + return Double.toString((double)value / (double)(1 << shift)); + } + + /** + * Преобразовать Exception в Ñтроку. + */ + public static String formatException(Throwable x) + { + String msg = x.getMessage(); + + if(msg != null) + { + msg = msg.trim(); + + if(msg.length() > 0) + { + return msg; + } + } + + return x.getClass().getName(); + } + + /** + * ПомеÑтить Ñлементы из Enumeration в вектор. + * ЕÑли вмеÑто вектора передать null, + * будет Ñоздан новый вектор. + * + * @param source Enumeration, из которого брать Ñлементы + * @param target вектор, в который их клаÑÑ‚ÑŒ, или null + * @return тот же вектор + */ + public static Vector enumerationToVector(Enumeration source, Vector target) + { + if(target == null) + { + target = new Vector(); + } + + while(source.hasMoreElements()) + { + target.addElement(source.nextElement()); + } + + return target; + } + + /** + * Проверить, ÑущеÑтвует ли клаÑÑ Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼ именем. + * + * @param name Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа + * @return true, еÑли такой клаÑÑ ÑущеÑтвует + */ + public static boolean classExists(String name) + { + try + { + return Class.forName(name) != null; + } + catch(Throwable t) + { + return false; + } + } + + /** + * ЗапиÑать блок данных в файл. + * ЗапиÑÑŒ производитÑÑ Ð² отрезок Ñо start до end, + * при Ñтом размер блока данных может не ÑоответÑтвовать + * размеру отрезка (в Ñтом Ñлучае изменÑетÑÑ Ñ€Ð°Ð·Ð¼ÐµÑ€ файла). + */ + public static int updateFileData(FileConnection fc, byte[] data, int start, int end) throws IOException + { + int oldlen = end - start; + int newlen = data.length; + + if(oldlen < 0 || newlen < 0) + { + return 0; + } + + OutputStream os; + + RandomAccessInputStream is = new FileInputStream(fc); + + int oldsize = is.getCapacity(); + + /* переходим к началу данных, + находÑщихÑÑ ÐŸÐžÐ¡Ð›Ð• изменÑемых */ + is.setPosition(end); + + if(newlen < oldlen) // еÑли так, то удалÑем куÑок потока + { + // то еÑÑ‚ÑŒ копируем данные поÑле изменÑемых Ñо Ñмещением ÐÐЗÐД + + byte[] copybs = new byte[COPYBUFSIZE]; + + os = fc.openOutputStream(start + newlen); + + while(is.available() > 0) + { + os.write(copybs, 0, is.read(copybs)); + } + + os.close(); + is.close(); + + fc.truncate(oldsize + newlen - oldlen); + } + else if(newlen > oldlen) // а еÑли так, то вÑтавлÑем Ñвободного меÑта + { + // то еÑÑ‚ÑŒ копируем данные поÑле изменÑемых Ñо Ñмещением ВПЕРЕД + + byte[] copybs = new byte[COPYBUFSIZE]; + + int copylen = is.available(); + int copycnt = (copylen + COPYBUFSIZE - 1) / COPYBUFSIZE; + int i = copycnt - 1, cblen; + + if(copycnt > 0) + { + /* + * ЗдеÑÑŒ проверка: + * Сколько еще нужно допиÑать в файл, чтобы можно было + * перейти в нем к началу БУДУЩЕГО ПОСЛЕДÐЕГО Ñкопированного блока + * (чтобы можно было уже ТÐÐœ открыть OutputStream и пиÑать Ñтот блок). + * Этого доÑтаточно, поÑкольку блоки копируютÑÑ Ð¾Ñ‚ поÑледнего к первому. + */ + int len = (start + newlen + i * COPYBUFSIZE) - oldsize + 1; + + if(len > 0) + { + os = fc.openOutputStream(oldsize); + + while(len > 0) + { + cblen = Math.min(len, COPYBUFSIZE); + os.write(copybs, 0, cblen); + len -= cblen; + } + + os.close(); + } + + do + { + is.setPosition(end + i * COPYBUFSIZE); + cblen = is.read(copybs); + + // здеÑÑŒ проверка, чтобы не прихватить + // вмеÑте Ñ Ð´Ð°Ð½Ð½Ñ‹Ð¼Ð¸ пуÑтышку, которую допиÑали выше + if(is.getPosition() > oldsize) + { + cblen -= is.getPosition() - oldsize; + } + + os = fc.openOutputStream(start + newlen + i * COPYBUFSIZE); + os.write(copybs, 0, cblen); + os.close(); + } + while(--i >= 0); + } + + is.close(); + } + else + { + is.close(); + } + + // запиÑываем данные + os = fc.openOutputStream(start); + os.write(data); + os.close(); + + return newlen - oldlen; + } + + /** + * ЗапиÑать данные замены из RISов в файл. + * При Ñтом Ñначала проверить, как Ñто получитÑÑ Ð±Ñ‹Ñтрее: + * поÑледовательно заменÑÑ‚ÑŒ в файле по одному блоку, + * или Ñразу перепиÑать веÑÑŒ файл из поÑледнего RISа. + */ + public static FileConnection updateFileData(FileConnection fc, ReplaceableInputStream ris) throws IOException + { + if(ris.getWriteCount() > fc.fileSize()) + { + String tempname = Connector.createTempFile(fc.getPath(), true); + + FileConnection temp = (FileConnection)Connector.open("file:///" + tempname); + temp.create(); + + OutputStream os = temp.openOutputStream(); + ris.setPosition(0); + + byte[] buf = new byte[COPYBUFSIZE]; + + while(ris.available() > 0) + { + os.write(buf, 0, ris.read(buf)); + } + + os.close(); + ris.getBaseStream().close(); + + String name = fc.getName(); + fc.delete(); + fc.close(); + + temp.rename(name); + + Connector.releaseTempFile(tempname); + + return temp; + } + else + { + Vector vector = new Vector(); + ris.traverseReplaceChain(vector); + + ris.getBaseStream().close(); + + for(int i = 0; i < vector.size(); i++) + { + ris = (ReplaceableInputStream)vector.elementAt(i); + updateFileData(fc, ris.getReplace(), ris.getReplaceStart(), ris.getReplaceEnd()); + } + + return fc; + } + } + + /** + * Перевод времени в Ñтроку вида 050101_150000 + */ + public static String timeToFileName(long time) + { + Calendar cal = Calendar.getInstance(); + + if(time >= 0) + { + cal.setTime(new Date(time)); + } + + StringBuffer res = new StringBuffer(13); + int temp; + + res.append(cal.get(Calendar.YEAR)); + + while(res.length() > 2) + { + res.deleteCharAt(0); + } + + temp = cal.get(Calendar.MONTH) + 1; + + if(temp < 10) + { + res.append('0'); + } + + res.append(temp); + + temp = cal.get(Calendar.DAY_OF_MONTH); + + if(temp < 10) + { + res.append('0'); + } + + res.append(temp); + res.append('_'); + + temp = cal.get(Calendar.HOUR_OF_DAY); + + if(temp < 10) + { + res.append('0'); + } + + res.append(temp); + + temp = cal.get(Calendar.MINUTE); + + if(temp < 10) + { + res.append('0'); + } + + res.append(temp); + + temp = cal.get(Calendar.SECOND); + + if(temp < 10) + { + res.append('0'); + } + + res.append(temp); + + return res.toString(); + } + + /** + * Перевод времени в Ñтроку вида 01.01.2005 15:00:00 + */ + public static String timeToString(long time, boolean millis) + { + Calendar cal = Calendar.getInstance(); + + if(time >= 0) + { + cal.setTime(new Date(time)); + } + + StringBuffer res = new StringBuffer(19); + int temp; + + temp = cal.get(Calendar.DAY_OF_MONTH) + 1; + + if(temp < 10) + { + res.append('0'); + } + + res.append(temp); + res.append('.'); + + temp = cal.get(Calendar.MONTH); + + if(temp < 10) + { + res.append('0'); + } + + res.append(temp); + res.append('.'); + + res.append(cal.get(Calendar.YEAR)); + res.append(' '); + + temp = cal.get(Calendar.HOUR_OF_DAY); + + if(temp < 10) + { + res.append('0'); + } + + res.append(temp); + res.append(':'); + + temp = cal.get(Calendar.MINUTE); + + if(temp < 10) + { + res.append('0'); + } + + res.append(temp); + res.append(':'); + + temp = cal.get(Calendar.SECOND); + + if(temp < 10) + { + res.append('0'); + } + + res.append(temp); + + if(millis) + { + res.append('.'); + + temp = cal.get(Calendar.MILLISECOND); + + if(temp < 10) + { + res.append('0'); + res.append('0'); + } + else if(temp < 100) + { + res.append('0'); + } + + res.append(temp); + } + + return res.toString(); + } + + /** + * Перевод времени из МИКРОÑекунд в Ñтроку вида 0:00 + */ + public static String mediaTimeToString(long time) + { + if(time < 0) + { + return ""; + } + + StringBuffer res = new StringBuffer(); + + int seconds = (int)(time / 1000000); + + int minutes = seconds / 60; + seconds %= 60; + + int hours = minutes / 60; + minutes %= 60; + + if(hours > 0) + { + res.append(hours); + res.append(':'); + + if(minutes < 10) + { + res.append('0'); + } + } + + res.append(minutes); + res.append(':'); + + if(seconds < 10) + { + res.append('0'); + } + + res.append(seconds); + + return res.toString(); + } + + /** + * Получить Ñтроку Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ð¼ временем + */ + public static String getCurrentTime() + { + Calendar cal = Calendar.getInstance(); + + StringBuffer res = new StringBuffer(); + int time; + + time = cal.get(Calendar.HOUR_OF_DAY); + + if(time < 10) + { + res.append('0'); + } + + res.append(time); + res.append(':'); + + time = cal.get(Calendar.MINUTE); + + if(time < 10) + { + res.append('0'); + } + + res.append(time); + + return res.toString(); + } + + /** + * Преобразовать чиÑло в Ñтроку вида 12,345,678 + */ + public static String formatNumber(long value) + { + if(value < 0) + { + return "-" + formatNumber(-value); + } + + StringBuffer res = new StringBuffer(); + String str; + + while(true) + { + if(value > 999) + { + res.insert(0, str = Long.toString(value % 1000)); + + if(str.length() == 1) + { + res.insert(0, ",00"); + } + else if(str.length() == 2) + { + res.insert(0, ",0"); + } + else + { + res.insert(0, ","); + } + + value /= 1000; + } + else + { + res.insert(0, Long.toString(value)); + break; + } + } + + return res.toString(); + } + + public static InputStream getResourceAsStream(String name) + { + if(!name.startsWith("/")) + { + name = "/" + name; + } + + return Object.class.getResourceAsStream(name); + } + + public static int allocateMemory(int size, int chunk) + { + Vector arrays = new Vector(); + int allocated = 0; + + if(chunk <= 0) + { + chunk = 65536; + } + + try + { + while(true) + { + byte[] b = new byte[chunk]; + arrays.addElement(b); + + allocated += chunk; + + if(size > 0 && allocated >= size) + { + break; + } + } + } + catch(OutOfMemoryError oome) + { + } + + return allocated; + } + + public static int readLeInt(InputStream is) throws IOException + { + return (is.read() & 0xFF) | ((is.read() & 0xFF) << 8) | ((is.read() & 0xFF) << 16) | ((is.read() & 0xFF) << 24); + } + + public static int readLeShort(InputStream is) throws IOException + { + return (is.read() & 0xFF) | ((is.read() & 0xFF) << 8); + } + + public static void writeLeInt(OutputStream os, int value) throws IOException + { + os.write(value & 0xFF); + os.write((value >> 8) & 0xFF); + os.write((value >> 16) & 0xFF); + os.write((value >> 24) & 0xFF); + } + + public static void writeLeShort(OutputStream os, int value) throws IOException + { + os.write(value & 0xFF); + os.write((value >> 8) & 0xFF); + } + + /** + * ДоÑтать логарифм чиÑла по оÑнованию 2. + * По Ñути Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¸Ñ‰ÐµÑ‚ первый ненулевой бит. + */ + public static int logBaseTwo(int value) + { + if(value == 0) + { + return 0; + } + else + { + value = Math.abs(value); + } + + int power = 31; + + while((value & (1 << power)) == 0) + { + power--; + } + + return power; + } + + /** + * Округлить чиÑло до ближайшей Ñтепени двойки. + */ + public static int roundBaseTwo(int value) + { + value &= 0x3FFFFFFF; + + if(value == 0) + { + return 0x40000000; + } + + // 00001011 01110011 00010001 10100111 + // ^ + // 00001000 00000000 00000000 00000000 + // 00010000 00000000 00000000 00000000 + // 00011000 00000000 00000000 00000000 + // 00001100 00000000 00000000 00000000 + + int power = logBaseTwo(value); + + int low = 1 << power; + int high = low << 1; + + int mid = (low + high) >>> 1; + + if(value >= mid) + { + return high; + } + else + { + return low; + } + } +} diff --git a/src/com/vmx/BufDataInputStream.java b/src/com/vmx/BufDataInputStream.java new file mode 100644 index 0000000..ff0deb3 --- /dev/null +++ b/src/com/vmx/BufDataInputStream.java @@ -0,0 +1,774 @@ +/**************************************\ + * Буферизованный ввод/вывод * + ** ** + * Буферизованный поток ввода * + * (C) 2005+, Vitali Filippov [VMX] * + * (C) 2010, Kulikov Dmitriy * + * * + * BufDataInputStream.java * + * Created on 24 Oct 2005, 13:25 * +\**************************************/ + +package com.vmx; + +import java.io.*; +import com.one.RandomAccessInputStream; +import java.util.Vector; + +/** + * КлаÑÑ Ð´Ð»Ñ Ñ…Ð¸Ñ‚Ñ€Ð¾Ð³Ð¾ буферизованного ввода. + * По мере необходимоÑти размещает в памÑти блоки данных указанного размера; + * новые, еÑли получитÑÑ, или повторно иÑпользует ÑущеÑтвующие. + * Таким образом значительно повышаетÑÑ ÑффективноÑÑ‚ÑŒ работы + * Ñ Ð¼ÐµÐ´Ð»ÐµÐ½Ð½Ñ‹Ð¼Ð¸ входными потоками, где Ñвободный поиÑк затруднен. + */ + +/* + * Class for buffered data input. + * For documentation, see java.io.DataInput. + */ +public class BufDataInputStream extends RandomAccessInputStream implements DataInput +{ + protected static class DataBlock + { + public byte[] data; + public int start, end, len; + + public DataBlock(int size) + { + data = new byte[size]; + } + + public void read(RandomAccessInputStream is) throws IOException + { + start = is.getPosition(); + len = is.read(data); + end = start + len - 1; + } + + public boolean contains(int pos) + { + return pos >= start && pos <= end; + } + + public String toString() + { + return "[" + start + ".." + end + "]"; + } + } + + protected byte[] buffer; + protected int bmax, blen, bpos; + protected int currpos, markedpos; + protected int capacity; + protected RandomAccessInputStream is; + + protected Vector datablocks; + + /** + * КонÑтруктор. + * ИÑпользуетÑÑ Ð±ÑƒÑ„ÐµÑ€ Ñтандартного размера (4 КБ). + */ + public BufDataInputStream(RandomAccessInputStream iis) throws IOException + { + this(iis, -1); + } + + /** + * КонÑтруктор. + * ИÑпользуетÑÑ Ð±ÑƒÑ„ÐµÑ€ заданного размера. + */ + public BufDataInputStream(RandomAccessInputStream iis, int bufsize) throws IOException + { + if(bufsize <= 0) + { + bufsize = 4096; + } + + bmax = bufsize; + currpos = 0; + markedpos = 0; + + is = iis; + + capacity = is.getCapacity(); + is.mark(capacity + 0x100); + + datablocks = new Vector(); + + bufferize(); + } + + /** + * УÑтановить новый базовый поток Ð´Ð»Ñ Ñтого буферизованного потока. + * При Ñтом буфер автоматичеÑки обновлÑетÑÑ. + */ + public void setInputStream(RandomAccessInputStream iis) throws IOException + { + is = iis; + updateBuffer(); + } + + /** + * Закрытие буферизованного потока. + * Базовый поток ÐЕ оÑтаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ Ð´Ð»Ñ Ð´Ð°Ð»ÑŒÐ½ÐµÐ¹ÑˆÐµÐ³Ð¾ иÑпользованиÑ. + */ + public void close() throws IOException + { + is.close(); + } + + /** + * Возвращает количеÑтво байт, которые ещё возможно прочеÑÑ‚ÑŒ из + * Ñтого буферизованного потока. + */ + public int available() + { + return capacity - currpos; + } + + /** + * Получить объём потока + */ + public int getCapacity() + { + return capacity; + } + + /** + * Перейти к положению pos + */ + public void setPosition(int pos) throws IOException + { + if(pos < 0) + { + currpos = 0; + } + else if(pos > capacity) + { + currpos = capacity; + } + else + { + currpos = pos; + } + + blen = -1; + bpos = -1; + } + + /** + * Возвращает текущую позицию в буферизованном потоке. + */ + public int getPosition() + { + return currpos; + } + + /** + * Ставит метку, на которую возвращатьÑÑ Ð¿Ð¾Ñ‚Ð¾Ð¼ можно по reset. + */ + public void mark(int readlimit) + { + markedpos = currpos; + } + + /** + * Перейти на поÑледнюю заданную mark'ом позицию. + */ + public void reset() throws IOException + { + currpos = markedpos; + blen = -1; + bpos = -1; + } + + /** + * ПропуÑтить n байт + */ + public long skip(long n) throws IOException + { + if(n > available()) + { + n = available(); + } + + bpos += n; + currpos += n; + + return n; + } + + /** + * Прочитать маÑÑив из потока: прочитать и запиÑать макÑимум len байт, + * запиÑать их в b[], Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñо ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ off, и вернуть количеÑтво + * Ñчитанных байт. + */ + public int read(byte[] b, int off, int len) throws IOException + { + int available = available(); + + if(available <= 0) + { + return -1; + } + + if(len > available) + { + len = available; + } + + int rest = len; + int count; + + while(rest > 0) + { + if(bpos >= blen && !bufferize()) + { + break; + } + + count = Math.min(rest, blen - bpos); + System.arraycopy(buffer, bpos, b, off, count); + + bpos += count; + currpos += count; + off += count; + rest -= count; + } + + return len - rest; + } + + /** + * Прочитать маÑÑив b[] полноÑтью - Ñквивалентно read(b, 0, b.length); + */ + public int read(byte[] b) throws IOException + { + return read(b, 0, b.length); + } + + /** + * Прочитать 1 байт из потока, вернуть его, еÑли уÑпешно, и -1, + * еÑли доÑтигнут конец потока. + */ + public int read() throws IOException + { + if(currpos >= capacity) + { + return -1; + } + + if(bpos >= blen) + { + bufferize(); + } + + currpos++; + + return ((int)buffer[bpos++]) & 0xFF; + } + + /** + * Прочитать 1 байт из потока назад, еÑли начало файла - вернуть -1. + * Ð”Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ требуетÑÑ Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶ÐºÐ° mark() и reset() + */ + public int readBack() throws IOException + { + if(currpos <= 0) + { + return -1; + } + + currpos--; + bpos--; + + if(bpos < 0) + { + bufferize(); + } + + return ((int)buffer[bpos]) & 0xFF; + } + + /** + * Получить буфер, Ñодержащий текущую позицию в потоке. + * Это может быть как новый буфер, так и Ñохраненный Ñтарый. + */ + protected boolean bufferize() throws IOException + { + DataBlock currblock = null; + + for(int i = 0; i < datablocks.size(); i++) + { + currblock = (DataBlock)datablocks.elementAt(i); + + if(currblock.contains(currpos)) + { + break; + } + else + { + currblock = null; + } + } + + if(currblock == null) + { + boolean set = false; + + for(int i = 0; i < datablocks.size(); i++) + { + currblock = (DataBlock)datablocks.elementAt(i); + + if(currblock.start > currpos) + { + if(currblock.start - bmax <= currpos) + { + is.setPosition(currblock.start - bmax); + set = true; + } + + break; + } + } + + if(!set) + { + if(currpos > capacity - bmax) + { + is.setPosition(capacity - bmax); + } + else + { + is.setPosition(currpos); + } + } + + try + { + currblock = new DataBlock(bmax); + currblock.read(is); + } + catch(OutOfMemoryError oome) + { + if(datablocks.size() > 0) + { + int index; + + if(currpos < ((DataBlock)datablocks.elementAt(0)).start) + { + index = datablocks.size() - 1; + } + else + { + index = 0; + } + + currblock = (DataBlock)datablocks.elementAt(index); + currblock.read(is); + + datablocks.removeElementAt(index); + } + else + { + throw new RuntimeException("Consider this as \"OutOfMemoryError\""); + } + } + + boolean added = false; + + for(int i = 0; i < datablocks.size(); i++) + { + if(((DataBlock)datablocks.elementAt(i)).start > currblock.start) + { + datablocks.insertElementAt(currblock, i); + added = true; + + break; + } + } + + if(!added) + { + datablocks.addElement(currblock); + } + } + + buffer = currblock.data; + blen = currblock.len; + bpos = currpos - currblock.start; + + return blen > 0; + } + + /** + * Обновить Ñодержимое буфера в ÑоответÑтвии Ñ Ð¿Ð¾Ñ‚Ð¾ÐºÐ¾Ð¼ + */ + protected void updateBuffer() throws IOException + { + capacity = is.getCapacity(); + + if(currpos > capacity) + { + currpos = capacity; + } + + datablocks.removeAllElements(); + bufferize(); + } + + /** + * Общее обновление потока. + */ + public void update() throws IOException + { + is.update(); + updateBuffer(); + } + + /** + * Прочитать булево значение из потока (Ñм. DataInput) + */ + public boolean readBoolean() throws IOException + { + int r = read(); + + if(r == -1) + { + throw new IOException("EOF"); + } + + return r != 0; + } + + /** + * Прочитать байт из потока; еÑли доÑтигнут конец потока, + * генерируетÑÑ Ð¸Ñключение IOException Ñ Ñообщением "EOF" (Ñм. DataInput) + */ + public byte readByte() throws IOException + { + int r = read(); + + if(r == -1) + { + throw new IOException("EOF"); + } + + return (byte)r; + } + + /** + * Прочитать Ñимвол (Unicode Big Endian) из потока (Ñм. DataInput) + */ + public char readChar() throws IOException + { + //return (char)((readUnsignedByte() << 8) | readUnsignedByte()); + return (char)((read() << 8) | read()); + } + + /** + * Прочитать Ñимвол (Unicode Big Endian) из потока ÐÐЗÐД (Ñм. DataInput) + */ + public char readCharBack() throws IOException + { + return (char)(readBack() | (readBack() << 8)); + } + + /** + * Прочитать чиÑло Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой двойной точноÑти (Ñм. DataInput) + */ + public double readDouble() throws IOException + { + return Double.longBitsToDouble(readLong()); + } + + /** + * Прочитать чиÑло Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой одинарной точноÑти (Ñм. DataInput) + */ + public float readFloat() throws IOException + { + return Float.intBitsToFloat(readInt()); + } + + /** + * Прочитать маÑÑив b[] из потока целиком, еÑли целиком не получитÑÑ, + * Ñгенерировать иÑключение IOException Ñ Ñообщением "EOF" + */ + public void readFully(byte[] b) throws IOException + { + if(read(b) < b.length) + { + throw new IOException("EOF"); + } + } + + /** + * Прочитать в точноÑти len байт и запиÑать их в маÑÑив b[], Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ + * Ñо ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ off. ЕÑли доÑтигнут конец файла - Ñгенерировать + * иÑключение IOException Ñ Ñообщением "EOF" + */ + public void readFully(byte[] b, int off, int len) throws IOException + { + if(read(b, off, len) < len) + { + throw new IOException("EOF"); + } + } + + /** + * Прочитать из потока целое чиÑло (Ñм. DataInput) + */ + public int readInt() throws IOException + { + return (readUnsignedByte() << 24) | + (readUnsignedByte() << 16) | + (readUnsignedByte() << 8) | + (readUnsignedByte()); + } + + /** + * Прочитать из потока целое чиÑло (Little Endian) + */ + public int readLeInt() throws IOException + { + return (readUnsignedByte()) | + (readUnsignedByte() << 8) | + (readUnsignedByte() << 16) | + (readUnsignedByte() << 24); + } + + /** + * Прочитать из потока длинное целое чиÑло (Ñм. DataInput) + */ + public long readLong() throws IOException + { + return ((long)readUnsignedByte() << 56) | + ((long)readUnsignedByte() << 48) | + ((long)readUnsignedByte() << 40) | + ((long)readUnsignedByte() << 32) | + ((long)readUnsignedByte() << 24) | + ((long)readUnsignedByte() << 16) | + ((long)readUnsignedByte() << 8) | + ((long)readUnsignedByte()); + } + + /** + * Прочитать из потока короткое целое чиÑло (Ñм. DataInput) + */ + public short readShort() throws IOException + { + return (short)((readUnsignedByte() << 8) | readUnsignedByte()); + } + + public short readLeShort() throws IOException + { + return (short)(readUnsignedByte() | (readUnsignedByte() << 8)); + } + + /** + * Прочитать из потока беззнаковый байт (Ñм. DataInput) + */ + public int readUnsignedByte() throws IOException + { + return ((int)readByte()) & 0xFF; + } + + /** + * Прочитать из потока беззнаковое короткое целое (Ñм. DataInput) + */ + public int readUnsignedShort() throws IOException + { + return ((int)readShort()) & 0xFFFF; + } + + public int readUnsignedLeShort() throws IOException + { + return ((int)readLeShort()) & 0xFFFF; + } + + /** + * ПропуÑтить len байт (Ñм. DataInput) + */ + public int skipBytes(int len) throws IOException + { + return (int)skip(len); + } + + /** + * Прочитать из потока Ñтроку в UTF-8 в ÑоответÑтвии Ñо + * Ñпецификацией в DataInput (Ñм. DataInput) + */ + public String readUTF() throws IOException, UTFDataFormatException + { + int n = readUnsignedShort(); + + byte b[] = new byte[n]; + readFully(b); + + return new String(b, 0, b.length, "UTF-8"); + } + + /** + * Прочитать из потока Ñимвол в кодировке UTF-8. + * ПоÑкольку возможна ÑитуациÑ, когда текÑÑ‚ + * ÐЕ в UTF-8 будет читатьÑÑ ÐºÐ°Ðº UTF-8, + * UTFDataFormatException здеÑÑŒ не иÑпользуетÑÑ. + * ВмеÑто Ñтого возвращаетÑÑ Ð½ÑƒÐ»ÐµÐ²Ð¾Ð¹ Ñимвол. + */ + public char readCharUTF() throws IOException + { + int b, c, d; + + b = read(); + + if(b == -1) + { + return (char)-1; + } + + if((b & 0x80) == 0) + { + return (char)b; + } + else if((b & 0xE0) == 0xC0) + { + c = read(); + + if((c & 0xC0) == 0x80) + { + return (char)(((b & 0x1F) << 6) | (c & 0x3F)); + } + } + else if((b & 0xF0) == 0xE0) + { + c = read(); + d = read(); + + if((c & 0xC0) == 0x80 && (d & 0xC0) == 0x80) + { + return (char)(((b & 0x0F) << 12) | ((c & 0x3F) << 6) | (d & 0x3F)); + } + } + + return 0; + } + + /** + * Прочитать из потока Ñимвол в кодировке UTF-8 ÐÐЗÐД. + * ПоÑкольку возможна ÑитуациÑ, когда текÑÑ‚ + * ÐЕ в UTF-8 будет читатьÑÑ ÐºÐ°Ðº UTF-8, + * UTFDataFormatException здеÑÑŒ не иÑпользуетÑÑ. + * ВмеÑто Ñтого возвращаетÑÑ Ð½ÑƒÐ»ÐµÐ²Ð¾Ð¹ Ñимвол. + */ + public char readCharBackUTF() throws IOException + { + int b, c, d; + + d = readBack(); + + if(d == -1) + { + return (char)-1; + } + + if((d & 0x80) == 0) + { + return (char)d; + } + else if((d & 0xC0) == 0x80) + { + c = readBack(); + + if((c & 0xE0) == 0xC0) + { + return (char)(((c & 0x1F) << 6) | (d & 0x3F)); + } + else if((c & 0xC0) == 0x80) + { + b = readBack(); + + if((b & 0xF0) == 0xE0) + { + return (char)(((b & 0x0F) << 12) | ((c & 0x3F) << 6) | (d & 0x3F)); + } + } + } + + return 0; + } + + /** + * Прочитать из потока Ñимвол в кодировке UTF-16 (Little Endian) + */ + public char readLeChar() throws IOException + { + return (char)(read() | (read() << 8)); + } + + /** + * Прочитать из потока Ñимвол в кодировке UTF-16 (Little Endian) ÐÐЗÐД + */ + public char readLeCharBack() throws IOException + { + return (char)((readBack() << 8) | readBack()); + } + + /** + * Прочитать из потока макÑимум count Ñимволов в кодировке UTF-8 + */ + public String readUTF(int count) throws IOException, UTFDataFormatException + { + StringBuffer s = new StringBuffer(); + + for(int i = 0; i < count && available() > 0; i++) + { + s.append(readCharUTF()); + } + + return s.toString(); + } + + /** + * ПропуÑтить в потоке макÑимум count Ñимволов в кодировке UTF-8. + * Ðе очень чётко проверÑет ÑоответÑтвие данных кодировке. + */ + public int skipUTF(int count) throws IOException, UTFDataFormatException + { + byte b; + int i = 0, r = 0; + + while(i < count) + { + b = readByte(); + + if((b & 0x80) == 0) + { + r++; + } + else if((((int)b) & 0xE0) == 0xC0) + { + readByte(); + r += 2; + } + else if((((int)b) & 0xF0) == 0xE0) + { + readShort(); + r += 3; + } + else + { + throw new UTFDataFormatException(); + } + + i++; + } + + return r; + } + +// private static void out(String s) +// { +// System.out.println("[BufDataInputStream] " + s); +// } +} diff --git a/src/com/vmx/FontWidthCache.java b/src/com/vmx/FontWidthCache.java new file mode 100644 index 0000000..035d6c7 --- /dev/null +++ b/src/com/vmx/FontWidthCache.java @@ -0,0 +1,303 @@ +package com.vmx; + +import javax.microedition.lcdui.Font; +import java.util.*; + +public class FontWidthCache +{ + protected static Vector fwc = new Vector(); + protected static Vector fwc_f = new Vector(); + + /** + * Получить кÑш ширины Ð´Ð»Ñ ÑˆÑ€Ð¸Ñ„Ñ‚Ð° font + */ + public static FontWidthCache getCache(Font font) + { + for(int i = 0; i < fwc.size(); i++) + { + if(fwc_f.elementAt(i).equals(font)) + { + return (FontWidthCache)fwc.elementAt(i); + } + } + + fwc_f.addElement(font); + FontWidthCache f; + fwc.addElement(f = new FontWidthCache(font)); + + return f; + } + + protected Font font; + protected byte caches[][]; + protected int hi, lo; + + /** + * Защищённый конÑтруктор + */ + protected FontWidthCache(Font font) + { + this.font = font; + caches = new byte[256][]; + + for(int i = 0; i < 256; i++) + { + caches[i] = null; + } + } + + /** + * ПодÑчитать (или взÑÑ‚ÑŒ из кÑша) и вернуть ширину Ñимвола ch + */ + public int charWidth(char ch) + { + hi = (ch >> 8) & 0xFF; + lo = (ch) & 0xFF; + + if(caches[hi] == null) + { + caches[hi] = new byte[256]; + + for(int i = 0; i < 256; i++) + { + caches[hi][i] = -1; + } + } + + if(caches[hi][lo] == -1) + { + caches[hi][lo] = (byte)font.charWidth(ch); + } + + return ((int)caches[hi][lo]) & 0xFF; + } + + /** + * ПодÑчитать и вернуть ширину Ñтроки s + */ + public int stringWidth(String s) + { + int l = s.length(), i, r; + + for(r = 0, i = 0; i < l; i++) + { + r += charWidth(s.charAt(i)); + } + + return r; + } + + /** + * ПодÑчитать и вернуть выÑоту Ñтроки s + */ + public int stringHeight(String s) + { + if(s == null) + { + return 0; + } + + int i, l = s.length(), c; + + for(c = 1, i = 0; i < l; i++) + { + if(s.charAt(i) == '\n') + { + c++; + } + } + + return c * font.getHeight(); + } + + /** + * Разбить Ñтроку, чтобы она впиÑывалаÑÑŒ по ширине + * в Ñкран шириной maxStrWidth + */ + public String[] splitString1(String text, int maxStrWidth) + { + StringBuffer s = new StringBuffer(); + + int afterspace; + int cut; + int strwidth; + boolean wordwrap; + char c; + + Vector v = new Vector(); + char[] cs = text.toCharArray(); + int index = 0; + + while(index < cs.length) + { + afterspace = -1; + cut = 0; + strwidth = 0; + wordwrap = true; + + do + { + if(index >= cs.length) + { + wordwrap = false; + break; + } + + c = cs[index++]; + + if(c == '\n') + { + wordwrap = false; + break; + } + else if(c == '\t') + { + for(int i = 0; i < 4; i++) + { + s.append(' '); + strwidth += charWidth(' '); + } + + c = ' '; + } + else if(c != '\r') + { + s.append(c); + strwidth += charWidth(c); + } + + if(AuxClass.SEPARATOR_CHARS.indexOf(c) >= 0) + { + afterspace = 0; + } + else if(afterspace >= 0) + { + afterspace++; + } + } + while(strwidth < maxStrWidth); + + if(wordwrap && afterspace >= 0) + { + cut = afterspace; + } + else if(strwidth > maxStrWidth) + { + cut = 1; + } + + if(cut > 0) + { + index -= cut; + s.setLength(s.length() - cut); + } + + v.addElement(s.toString().trim()); + s.setLength(0); + } + + String[] res = new String[v.size()]; + v.copyInto(res); + + return res; + } + + public String[] splitString(String text, int maxStrWidth) + { + StringBuffer buf = new StringBuffer(); + String s = ""; + + int afterspace; + int cut; + int strwidth; + boolean wordwrap; + int tab; + char c; + + Vector v = new Vector(); + char[] cs = text.toCharArray(); + int index = 0; + + while(index < cs.length) + { + afterspace = -1; + cut = 0; + strwidth = 0; + wordwrap = true; + + do + { + if(index >= cs.length) + { + wordwrap = false; + break; + } + + c = cs[index++]; + + if(c == '\n') + { + wordwrap = false; + break; + } + else if(c == '\t') + { + buf.append('\t'); + + strwidth += stringWidth(AuxClass.TAB_AS_SPACES); + c = ' '; + } + else if(c != '\r') + { + buf.append(c); + strwidth += charWidth(c); + } + + if(AuxClass.SEPARATOR_CHARS.indexOf(c) >= 0) + { + afterspace = 0; + } + else if(afterspace >= 0) + { + afterspace++; + } + } + while(strwidth < maxStrWidth); + + s = buf.toString(); + + if(wordwrap && afterspace >= 0) + { + cut = afterspace; + } + else if(strwidth > maxStrWidth) + { + cut = 1; + } + + if(cut > 0) + { + s = s.substring(0, s.length() - cut); + index -= cut; + } + + while((tab = s.indexOf('\t')) >= 0) + { + s = s.substring(0, tab) + AuxClass.TAB_AS_SPACES + s.substring(tab + 1); + } + + v.addElement(s.trim()); + buf.setLength(0); + } + + String[] res = new String[v.size()]; + v.copyInto(res); + + return res; + } + +// private static void out(String s) +// { +// System.out.println("[FontWidthCache] " + s); +// } +} diff --git a/src/com/vmx/InputStreamDecoder.java b/src/com/vmx/InputStreamDecoder.java new file mode 100644 index 0000000..b952ef1 --- /dev/null +++ b/src/com/vmx/InputStreamDecoder.java @@ -0,0 +1,282 @@ +package com.vmx; + +import java.io.*; +import com.one.*; +import com.one.file.FileConnection; + +public class InputStreamDecoder +{ + BufDataInputStream bdis; + int enc; + + /** + * КонÑтруктор + */ + public InputStreamDecoder(BufDataInputStream bdis, int enc) // throws UnsupportedEncodingException + { + this.enc = enc; + this.bdis = bdis; + } + + /** + * Создать InputStreamDecoder Ð´Ð»Ñ Ð´ÐµÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ€ÐµÑурÑа resname + */ + public static InputStreamDecoder getResourceDecoder(String resname) throws IOException + { + RandomAccessInputStream is = new BufferedInputStream(AuxClass.getResourceAsStream(resname)); + int encoding = detectEncoding(is, StringEncoder.ENC_DEFAULT); + return new InputStreamDecoder(new BufDataInputStream(is), encoding); + } + + /** + * Создать InputStreamDecoder Ð´Ð»Ñ Ð´ÐµÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾Ñ‚Ð¾ÐºÐ° iis + */ + public static InputStreamDecoder getStreamDecoder(InputStream iis) throws IOException + { + RandomAccessInputStream is = new BufferedInputStream(iis); + int encoding = detectEncoding(is, StringEncoder.ENC_DEFAULT); + return new InputStreamDecoder(new BufDataInputStream(is), encoding); + } + + /** + * Создать InputStreamDecoder Ð´Ð»Ñ Ð´ÐµÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° + */ + public static InputStreamDecoder getFileDecoder(FileConnection fc) throws IOException + { + RandomAccessInputStream is = new FileInputStream(fc); + int encoding = detectEncoding(is, StringEncoder.ENC_DEFAULT); + return new InputStreamDecoder(new BufDataInputStream(is), encoding); + } + + /** + * ОÑознать, в какой кодировке is. + * ЕÑли в UTF (еÑÑ‚ÑŒ BOM Ñигнатура), вернуть ENC_UTFx. + * ЕÑли нет, то вернуть переданную кодировку (по умолчанию). + * + * Ð’ качеÑтве побочного Ñффекта: + * еÑли в потоке дейÑтвительно еÑÑ‚ÑŒ Ñигнатура, то поток не ÑбраÑываетÑÑ, + * и из него можно Ñразу читать нормальный Ñимвол. + */ + public static int detectEncoding(RandomAccessInputStream is, int defenc) throws IOException + { + is.mark(4); + + /* + * BOM Ñигнатура предÑтавлÑет Ñобой Ñимвол + * U+FEFF (неразрывный пробел Ñ Ð½ÑƒÐ»ÐµÐ²Ð¾Ð¹ шириной), + * запиÑаный тем или иным образом. + * СоответÑтвенно здеÑÑŒ проверÑетÑÑ Ð½Ð°Ð»Ð¸Ñ‡Ð¸Ðµ + * в начале потока Ñтого Ñимвола в формате + * UTF-16 Big Endian (0xFEFF), + * UTF-16 Little Endian (0xFFFE) и + * UTF-8 (0xEFBBBF) + */ + + int a, b, c; + + if(is.available() >= 2) + { + a = is.read(); + b = is.read(); + + if(a == 0xFE && b == 0xFF) + { + return StringEncoder.ENC_UTF16N; + } + else if(a == 0xFF && b == 0xFE) + { + return StringEncoder.ENC_UTF16L; + } + else if(is.available() >= 1) + { + c = is.read(); + + if(a == 0xEF && b == 0xBB && c == 0xBF) + { + return StringEncoder.ENC_UTF8; + } + } + } + + /* мы Ñчитали не Ñигнатуру, возвращаемÑÑ Ð½Ð°Ð·Ð°Ð´ */ + is.reset(); + + return defenc; // StringEncoder.ENC_DEFAULT; + } + + /** + * Считать Ñимвол + */ + public char readChar() throws IOException + { + if(bdis.available() > 0) + { + if(enc >= 0) + { + return StringEncoder.decodeChar(bdis.read(), enc); + } + else if(enc == StringEncoder.ENC_UTF8) + { + return bdis.readCharUTF(); + } + else if(enc == StringEncoder.ENC_UTF16N) + { + return bdis.readChar(); + } + else if(enc == StringEncoder.ENC_UTF16L) + { + return bdis.readLeChar(); + } + } + + throw new EOFException(); + } + + /** + * Считать Ñимвол назад + */ + public char readCharBack() throws IOException + { + if(bdis.getPosition() > 0) + { + if(enc >= 0) + { + return StringEncoder.decodeChar(bdis.readBack(), enc); + } + else if(enc == StringEncoder.ENC_UTF8) + { + return bdis.readCharBackUTF(); + } + else if(enc == StringEncoder.ENC_UTF16N) + { + return bdis.readCharBack(); + } + else if(enc == StringEncoder.ENC_UTF16L) + { + return bdis.readLeCharBack(); + } + } + + throw new EOFException(); + } + + public int gotoLineNum(int linenum) throws IOException + { + bdis.setPosition(0); + detectEncoding(bdis, enc); + + int currline = 1; + + while(bdis.available() > 0 && currline < linenum) + { + if(readChar() == '\n') + { + currline++; + } + } + + return bdis.getPosition(); + } + + /** + * ПоиÑк текÑта в потоке. + * ЕÑли startIndex >= 0, то поиÑк ведетÑÑ Ñо startIndex, иначе Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ позиции. + * ЕÑли endIndex >= 0, то поиÑк идет макÑимум до endIndex, иначе до конца потока. + * ЕÑли ignoreCase = true, то поиÑк ведетÑÑ Ð±ÐµÐ· учета региÑтра. + * ПоÑле поиÑка поток возвращаетÑÑ Ð½Ð° прежнюю позицию. + */ + public int indexOf(String text, int startIndex, int endIndex, boolean ignoreCase) throws IOException + { + int prevpos = bdis.getPosition(); + + if(startIndex >= 0) + { + bdis.setPosition(startIndex); + } + + char[] data; + + if(ignoreCase) + { + data = text.toLowerCase().toCharArray(); + } + else + { + data = text.toCharArray(); + } + + int end = data.length; + int index = -1; + int i = 0; + + char c; + + while(bdis.available() > 0) + { + if(ignoreCase) + { + c = Character.toLowerCase(readChar()); + } + else + { + c = readChar(); + } + + if(c == data[i]) + { + if(index < 0) + { + index = bdis.getPosition() - 1; + } + + if(++i >= end) + { + break; + } + } + else if(c == data[0]) + { + index = bdis.getPosition() - 1; + i = 0; + } + else + { + index = -1; + i = 0; + } + + if(endIndex >= 0 && bdis.getPosition() >= endIndex) + { + break; + } + } + + bdis.setPosition(prevpos); + + return index; + } + + /** + * Сколько еще можно Ñчитать из Ñтого потока. + * ВозвращаетÑÑ ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑтво байт, а не Ñимволов, + * поÑтому при иÑпользовании UTF-8 Ñто значение + * имеет ÑмыÑл проверÑÑ‚ÑŒ лишь на неравенÑтво 0. + */ + public int available() throws IOException + { + return bdis.available(); + } + + /** + * Закрытие декодера вмеÑте Ñ Ð¿Ð¾Ñ‚Ð¾ÐºÐ¾Ð¼, на котором он оÑнован + */ + public void close() throws IOException + { + bdis.close(); + } + +// private static void out(String s) +// { +// System.out.println("[InputStreamDecoder] " + s); +// } +} diff --git a/src/com/vmx/IntVector.java b/src/com/vmx/IntVector.java new file mode 100644 index 0000000..e6d4367 --- /dev/null +++ b/src/com/vmx/IntVector.java @@ -0,0 +1,132 @@ +package com.vmx; + +public class IntVector +{ + public static final int DELTA = 4096; + + protected int[] array; + protected int count; + + public IntVector() + { + array = new int[0]; + count = 0; + } + + public IntVector(int capacity) + { + array = new int[capacity]; + count = 0; + } + + /** + * Добавить в array значение n + */ + public void add(int el) + { + if(count >= array.length) + { + try + { + int[] newarray = new int[array.length + DELTA]; + System.arraycopy(array, 0, newarray, 0, array.length); + array = newarray; + } + catch(OutOfMemoryError oome) + { + return; + } + } + + array[count++] = el; + } + + /** + * Удалить Ñлементы Ñ first по first + n - 1 + */ + public void remove(int first, int n) + { + if(first < 0 || first >= count || n <= 0) + { + return; + } + + if(first + n >= count) + { + count = first; + } + else + { + for(int i = first; i < count - n; i++) + { + array[i] = array[i + n]; + } + } + + while(count + DELTA * 2 < array.length) + { + try + { + int[] newarray = new int[array.length - DELTA]; + System.arraycopy(array, 0, newarray, 0, newarray.length); + array = newarray; + } + catch(OutOfMemoryError oome) + { + break; + } + } + } + + /** + * Получить Ñлемент номер index + */ + public int get(int index) + { + return array[index]; + } + + public void set(int index, int value) + { + if(index >= 0 && index < count) + { + array[index] = value; + } + } + + /** + * Ðайти value в векторе + */ + public int find(int value) + { + int i; + + for(i = 0; i < count; i++) + { + if(array[i] == value) + { + break; + } + } + + if(i >= count) + { + return -1; + } + + return i; + } + + /** + * Получить размер + */ + public int size() + { + return count; + } + + public void copyInto(int[] dest) + { + System.arraycopy(array, 0, dest, 0, count); + } +} diff --git a/src/com/vmx/Locale.java b/src/com/vmx/Locale.java new file mode 100644 index 0000000..c851068 --- /dev/null +++ b/src/com/vmx/Locale.java @@ -0,0 +1,359 @@ +package com.vmx; + +import java.io.*; +import java.util.Vector; +import com.one.*; +import filemanager.main; +import java.util.Hashtable; + +public class Locale +{ + public static final int SELECT_DRIVE = 0, FAVOURITE = 1, OPTIONS_CMD = 2, + EXIT_CMD = 3, DISK = 4, DISK_INFO = 5, DISK_TOTAL_SIZE = 6, KB = 7, + BYTE = 8, DISK_AVAILABLE = 9, SELECT_CMD = 10, DELETE_CMD = 11, + DELETE_ALL_CMD = 12, BACK_CMD = 13, RESTRICTED_FILE_NAME = 14, + CONFIRMATION = 15, DEL_RECORD_FAVOR = 16, DEL_ALL_FAVOR = 17, // 16, 17 + YES_CMD = 18, NO_CMD = 19, SAVE_CMD = 20, CLEAR_CMD = 21, + ERROR = 22, NAME_EXIST_OVERWRITE_QUESTION = 23, FILE_NOT_COPIED = 24, + FILE_NOT_MOVED = 25, FORMAT_NOT_SUPP = 26, OPEN_CMD = 27, + INSERT_CMD = 28, PROPERTY_CMD = 29, RENAME_CMD = 30, COPY_CMD = 31, + MOVE_CMD = 32, NEW_FOLDER_CMD = 33, NEW_FILE_CMD = 34, + TO_FAVOUR_CMD = 35, DISK_INFO_CMD = 36, PREF_ESCAPED_STRINGS = 37, + PREFERENCES_CMD = 38, HELP_CMD = 39, OK_CMD = 40, CANCEL_CMD = 41, + SELECT_PASTE_IN_FOLDER = 42, INFORMATION = 43, FOLDER_NAME = 44, + FILE_NAME = 45, SIZE = 46, ATTR = 47, LAST_MODIF = 48, RENAME = 49, + NAME = 50, NAME_EXIST_SELECT_ANOTHER = 51, FILE_READ_ONLY = 52, + NOT_RENAMED = 53, PREF_SHOW_HIDDEN_FILES = 54, PREF_VISUAL = 55, + PREF_BROWSE = 56, PREF_USE_FULL_MENU = 57, ROTATE_BY = 58, + PREF_SHOW_ERRORS = 59, CREATE_NEW_FOLDER = 60, CREATE_NEW_FILE = 61, + NOT_CREATE_NEW_FOLDER = 62, WAIT_PLEASE = 63, WAIT = 64, + SEARCH_CURRENT_FOLDER = 65, SEARCH_CURRENT_DISK = 66, SEARCH_ALL_DISKS = 67, + IMAGEVIEW_SCALED = 68, ATTENTION = 69, SOURCE_FILE_READONLY_BE_COPIED = 70, + DEL_SELECTED_FILE = 71, DEL_MARKED_FILES = 72, FOLDER_DELETED = 73, + FOLDER_NOT_EMPTY = 74, FILE_DELETED = 75, FILE_NOT_DELETED = 76, + LICENSE_AGR = 77, FILE_TYPE = 78, FILE_NOT_SAVED_EXIT = 79, + SAVED = 80, BUFFER = 81, FIRST_COPY_NAME = 82, NEXT_COPY_NAME = 83, + OPERATION_OK = 84, FILE = 85, FILE_NOT_SAVED = 86, GB = 87, MARK_CMD = 88, + MARK_ALL_CMD = 89, DEMARK_ALL_CMD = 90, PREF_OPEN_NOT_SUPP = 91, + MENU_LIST_SORT = 92, PREF_SCREEN_TRANSFORM = 93, NEED_RESTART = 94, + EXTRACT_CMD = 95, EXTRACT_ALL_CMD = 96, EXTRACT_TO = 97, + FOLDER_IMPOSSIBLE = 98, FILES_EXTRACTED = 99, YES_FOR_ALL = 100, + NO_FOR_ALL = 101, PREF_KEY_VIBRA_DURATION = 102, COMPRESSED_SIZE = 103, + MENU_FILE = 104, MENU_ARCHIVE = 105, MENU_PROPERTIES = 106, + MENU_OPERATIONS = 107, MENU_CREATE = 108, MENU_SHOW = 109, + PREF_NO_EFFECTS = 110, CREATE_ARCHIVE = 111, COMPRESSION_LEVEL = 112, + TAG_EDITOR = 113, ID3_SONG = 114, ID3_ARTIST = 115, ID3_ALBUM = 116, + ID3_YEAR = 117, ID3_COMMENT = 118, ID3_TRACKNUM = 119, ID3_GENRE = 120, + MB = 121, KEY_LEFT = 122, KEY_RIGHT = 123, KEY_UP = 124, KEY_DOWN = 125, + KEY_LSK = 126, KEY_RSK = 127, KEY_JOY = 128, KEY_DIAL = 129, + KEY_CANCEL = 130, PREV_SCREEN_CMD = 131, NEXT_SCREEN_CMD = 132, + PREV_LINE_CMD = 133, NEXT_LINE_CMD = 134, HOT_KEYS = 135, + MENU_ADDITIONAL = 136, PANELS = 137, PANEL_NUMS = 138 /*[+0..9]*/, + FULLSCREEN_CMD = 148, KEY_NO_ACTION = 149, KEYBOARD_CONFIG_CMD = 150, + PREF_LANG = 151, COLOR_SCHEME = 152, PREF_CHECK_FILE_ATTRIB = 153, + PREF_ACCURATE_DIR_CHECK = 154, PREF_SORT_FILE_LIST = 155, ATTR_READ_ONLY = 156, + ATTR_HIDDEN = 157, CONTENTS = 158, CONTENTS_PATTERN = 159, PREF_PLAYER_SETUP = 160, + PREF_ID3_ENCODING = 161, PREF_SHOW_PLAY_PROGRESS = 162, PREF_MOD_BUF_SIZE = 163, + DONE = 164, PREF_TEXT_SETUP = 165, PREF_SHOW_CR = 166, PREF_SHOW_LF = 167, + PREF_SUBST_TAB = 168, GOTO_CMD = 169, PREF_PAGE_SCROLL = 170, PREF_KEYMAP = 171, + INITIAL_SETUP = 172, CLOCK_MODE = 173, SWITCH = 174, NEXT_PANEL = 175, + PREV_PANEL = 176, NEXT_FREE = 177, PREV_FREE = 178, QUICK_SWITCH = 179, + EDIT_CMD = 180, MENU_SEARCH = 181, FONT_CMD = 182, ENCODING_CMD = 183, + RECURSIVE_SEARCH = 184, HASH_SUM = 185, CRYPT_CMD = 186, PASSWORD = 187, + CRYPT_USAGE = 188, SIZE_SMALL = 189, SIZE_MEDIUM = 190, SIZE_LARGE = 191, + FONT_FACE = 192, FONT_STYLE = 193, FONT_BOLD = 194, FONT_ITALIC = 195, + FONT_MONOSPACE = 196, FONT_PROPORTIONAL = 197, FONT_SYSTEM = 198, + FONT_UNDERLINED = 199, PREF_SHOW_MENU_NUM = 200, PREF_SHUFFLE_PLAY = 201, + TRANSCODE = 202, PREF_CUSTOM_COLOR_SCHEME = 203, CREATE_PLAYLIST = 204, + SEARCH_INSIDE_ARCHIVES = 205, AUDIO = 206, VIDEO = 207, + PATH_SAVE = 208, PATH_ABSOLUTE = 209, PATH_RELATIVE = 210, + PREF_FRAME_CURSOR = 221, MODE_NO_CHANGE = 222, MODE_SET = 223, MODE_CLEAR = 224, + EXT_BACK_IMAGE = 225, NAME_TEMPLATE = 226, MINIMIZE_CMD = 227, CONFIRM_SAVE = 228, + SAVE_AS_CMD = 229, MENU_EDIT = 230, UNDO_CMD = 231, REDO_CMD = 232, FIND_CMD = 233, + FIND_NEXT_CMD = 234, MENU_TEXT = 235, PREF_ARCHIVE_ENCODING = 236, LINE_NUMBER = 237, + PREF_REMEMBER_PATH = 238, TEMPLATES_CMD = 239, USE_UTF_BOM = 240, + SEARCH_EOF_QUESTION = 241, GOTO_START_CMD = 242, GOTO_END_CMD = 243, ADD_CMD = 244, + PREF_PLAY_ALERT_SOUNDS = 245, PREF_SWAP_SOFT_KEYS = 246, IGNORE_CASE = 247, + SORT_NONE = 248, SORT_BY_NAME = 249, SORT_BY_TYPE = 250, SORT_BY_DATE = 251, SORT_BY_SIZE = 252, + PREF_SORT_OPTIONS = 253, SORT_REVERSE_ORDER = 254, RESTART_CMD = 255, + PREF_MARK_MOVE_NEXT = 256, REPLACE_CMD = 257, REPLACE_ALL_CMD = 258, + REPLACE_WITH = 259, PREF_ALTER_CLOCK_POS = 260, SEARCH_MATCHES = 261, + EQUALIZER = 262, HZ = 263, KHZ = 264, DB = 265, PREF_USE_ACCELEROMETER = 266, + PREF_LIGHT_CONTROL_MODE = 267, PREF_MOD_SAMPLE_RATE = 268, PREF_MOD_QUALITY = 269, + QUALITY_LOW = 270, QUALITY_MEDIUM = 271, QUALITY_HIGH = 272, DISABLED = 273, + ENABLED = 274, AUTOMATIC = 275, ESCAPE_CMD = 276, UNESCAPE_CMD = 277, + BUFFER_EMPTY = 278, MODULES_CMD = 279, PACKING_FILE = 280, CHARACTER = 283, + PREF_TEXTBOX_TITLE = 284, NORMAL = 285, TICKER = 286, UNPACKING_FILE = 289, + MEMORY_MONITOR = 290, UPDATE_CMD = 291, FILL_CMD = 292, USED_MEMORY = 293, + TOTAL_MEMORY = 294, PREF_MM_DELAY = 295, PREF_MM_THRESHOLD = 296, CONTAINERS = 297, + CLOSE_CMD = 298, CLOSE_ALL_CMD = 299, WRITING_FILE = 300, PALETTE_CMD = 301, + COLOR_SELECTOR = 302, CONTAINER_INFO = 303, PREF_LONG_SCROLL_SPEED = 304, + INSTALLING_COLOR_SCHEME = 305, PREF_DITHER_GRADIENTS = 306, PREF_ALPHA_GRADIENTS = 307, + PREF_TEXT_BUFFER_SIZE = 308, PREF_FULL_FILE_NAMES = 309, IN_BUFFER = 310, + IN_FAVOURITES = 311, ENTER_CMD = 312, KEY_ASSIGNMENT = 313, USER_KEYS = 314, + KEY_EDITOR = 315, KEY_CODE = 316, ABBREVIATION = 318, PRESS_A_KEY = 319, + HOT_KEY_NAME = 320, HELD_KEY_NAME = 321, ROOT = 322, FILE_LIST = 323, + BIT_BUCKET = 324, ASSIGN_CMD = 326, RESET_CMD = 327, PREF_CACHE_CODE_PAGES = 328, + PREF_LARGE_FONT = 329, IN_FILE_LIST = 330, IN_MENU = 331, PREF_EXIT_FROM_DRIVE_LIST = 332, + METADATA_FORMAT = 333, PREF_SHOW_META_KEYS = 334, REG_EXP_CMD = 335, RE_MATCH_MULTILINE = 336, + RE_REPLACE_BACKREF = 337; + + public static String ABOUT_MIDLET_NAME = TextProcessor.byteArrayToString(new byte[] { 85, 110, 105, 70, 77, 32, 118 }) + + main.loader.getAppProperty(TextProcessor.byteArrayToString(new byte[] { 77, 73, 68, 108, 101, 116, 45, 86, 101, 114, 115, 105, 111, 110 })); + + public static String ABOUT_DEPLOYMENT_NUMBER = main.loader.getAppProperty(TextProcessor.byteArrayToString(new byte[] { 68, 101, 112, 108, 111, 121, 109, 101, 110, 116, 45, 78, 117, 109, 98, 101, 114 })); + + //protected static String[] Strings; + //protected static final int STRING_COUNT = 278; + + protected static Hashtable strings = new Hashtable(); + protected static Hashtable offsets = new Hashtable(); + + public static String lang; + + public static String[] locales = null; // имена Ñзыков типа "ru", "en"... + public static String[] languages = null; // Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñзыков (руÑÑкий, english, ...) + + /** + * КонÑтруктор + */ + public Locale() + { + } + + public static void loadLocale(String newlang) throws IOException + { + lang = newlang; + +// Strings = new String[STRING_COUNT]; +// +// /* +// for(int k = 0; k < STRING_COUNT; k++) +// { +// Strings[k] = Integer.toString(k); +// } +// */ + + strings.clear(); + + InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/lang/" + lang + "/strings.ini"); + IniRecord record = null; + + int offset = 0; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + try + { + if(record.key.startsWith("[") && record.key.endsWith("]")) + { + offset = Integer.parseInt(record.key.substring(1, record.key.length() - 1).trim()); + } + else + { + //Strings[Integer.parseInt(record.key)] = TextProcessor.unescapeString(record.value); + strings.put(new Integer(Integer.parseInt(record.key) + offset), TextProcessor.unescapeString(record.value)); + } + } + catch(Exception e) + { + System.out.println(e.toString() + " because of " + record.key + ", " + record.value); + } + } + + ini.close(); + + offsets.clear(); + + try + { + ini = InputStreamDecoder.getResourceDecoder("/lang/" + lang + "/offsets.ini"); + record = null; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + try + { + offsets.put(record.key, new Integer(Integer.parseInt(record.value))); + } + catch(Exception e) + { + } + } + + ini.close(); + } + catch(Exception e) + { + // файла может и не быть + } + } + + public static int getOffset(Object object) + { + Integer offset = object != null ? (Integer)offsets.get(object instanceof String ? object : object.getClass().getName()) : null; + + if(offset != null) + { + return offset.intValue(); + } + + return 0; + } + + public static String getString(Object object, int index) + { + //return Strings[index]; + + Integer key = new Integer(index + getOffset(object)); + String res = (String)strings.get(key); + + if(res == null) + { + return key.toString(); + } + else if(res.startsWith("#")) + { + return getString(object, Integer.parseInt(res.substring(1).trim())); + } + + return res; + } + + public static String getString(Object object, int index, String token) + { + return TextProcessor.replaceText(getString(object, index), "%A", token); + } + + public static String getString(Object object, int index, String[] tokens) + { + String res = getString(object, index); + + for(int i = 0; i < tokens.length; i++) + { + res = TextProcessor.replaceText(res, "%" + (char)('A' + i), tokens[i]); + } + + return res; + } + + /** + * Получить поток Ñ Ñ‚ÐµÐºÑтом about'а + */ + public static InputStream getAboutStream() + { + try + { + return AuxClass.getResourceAsStream("/lang/" + lang + "/about.txt"); + } + catch(Exception e) + { + ErrScreen.showErrMsg(54, e); + return null; + } + } + + // ТекÑÑ‚ лицензии + public static String getLicenseString() + { + try + { + InputStreamDecoder isd = InputStreamDecoder.getResourceDecoder("/lang/" + lang + "/license.txt"); + + String s = ""; + + while(isd.available() > 0) + { + s += isd.readChar(); + } + + isd.close(); + + return s; + } + catch(Exception e) + { + ErrScreen.showErrMsg(55, e); + return null; + } + } + + /** + * Получить ÑпиÑок доÑтупных Ñзыков + */ + public static boolean readLocaleList() + { + Vector v = new Vector(); + String s; + char c; + int index; + + try + { + InputStreamDecoder isd = InputStreamDecoder.getResourceDecoder("/lang/lang.ini"); + + while(isd.available() > 0) + { + s = ""; + + while(isd.available() > 0) + { + c = isd.readChar(); + + if(c == '\n') + { + break; + } + else if(c == '\t') + { + c = ' '; + } + + if(c != '\r') + { + s += c; + } + } + + index = s.indexOf(';'); + + if(index >= 0) + { + s = s.substring(0, index); + } + + s = s.trim(); + + if(s.length() > 0) + { + index = s.indexOf('='); + + if(index > 0) + { + v.addElement(s); + } + } + } + + isd.close(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(56, e); + return false; + } + + languages = new String[v.size()]; + locales = new String[v.size()]; + + for(int i = 0; i < languages.length; i++) + { + s = (String)(v.elementAt(i)); + index = s.indexOf("="); + locales[i] = s.substring(0, index).trim(); + languages[i] = s.substring(index + 1).trim(); + } + + return true; + } +} diff --git a/src/com/vmx/OutputStreamEncoder.java b/src/com/vmx/OutputStreamEncoder.java new file mode 100644 index 0000000..3700cf2 --- /dev/null +++ b/src/com/vmx/OutputStreamEncoder.java @@ -0,0 +1,106 @@ +package com.vmx; + +import java.io.*; + +public class OutputStreamEncoder +{ + OutputStream os; + int enc; + + /** + * КонÑтруктор + */ + public OutputStreamEncoder(OutputStream os, int enc) // throws UnsupportedEncodingException + { + this.enc = enc; + this.os = os; + } + + /** + * ЗапиÑать BOM Ñигнатуру + */ + public void writeBOM() throws IOException + { + if(enc == StringEncoder.ENC_UTF8) + { + os.write(0xEF); + os.write(0xBB); + os.write(0xBF); + } + else if(enc == StringEncoder.ENC_UTF16N) + { + os.write(0xFE); + os.write(0xFF); + } + else if(enc == StringEncoder.ENC_UTF16L) + { + os.write(0xFF); + os.write(0xFE); + } + } + + /** + * ЗапиÑать Ñимвол + */ + public void writeChar(char ch) throws IOException + { + if(enc >= 0) + { + os.write(StringEncoder.encodeChar(ch, enc)); + } + else if(enc == StringEncoder.ENC_UTF8) + { + if(ch <= 0x7F) + { + os.write(ch); + } + else if(ch <= 0x7FF) + { + os.write(0xC0 | ((ch >> 6) & 0x1F)); + os.write(0x80 | (ch & 0x3F)); + } + else + { + os.write(0xE0 | ((ch >> 12) & 0xF)); + os.write(0x80 | ((ch >> 6) & 0x3F)); + os.write(0x80 | (ch & 0x3F)); + } + } + else if(enc == StringEncoder.ENC_UTF16N) + { + os.write(ch >>> 8); + os.write(ch & 0xFF); + } + else if(enc == StringEncoder.ENC_UTF16L) + { + os.write(ch & 0xFF); + os.write(ch >>> 8); + } + } + + /** + * ЗапиÑать Ñтроку + */ + public void writeString(String text) throws IOException + { + char[] as = text.toCharArray(); + + for(int i = 0; i < as.length; i++) + { + writeChar(as[i]); + } + } + + /** + * Закрытие кодировщика вмеÑте Ñ Ð¿Ð¾Ñ‚Ð¾ÐºÐ¾Ð¼, на котором он оÑнован + */ + public void close() throws IOException + { + os.close(); + } + +// private static void out(String s) +// { +// System.out.println("[OutputStreamEncoder] " + s); +// } +} diff --git a/src/com/vmx/ProgressCallback.java b/src/com/vmx/ProgressCallback.java new file mode 100644 index 0000000..6b7260a --- /dev/null +++ b/src/com/vmx/ProgressCallback.java @@ -0,0 +1,19 @@ +package com.vmx; + +public interface ProgressCallback +{ + public void setMax(int max); + public void setProgress(int progress); + public void rise(int plus); + public void progress(int plus); + public void setText(String text); + + public int getMax(); + public int getProgress(); + public String getText(); + + public void setPercentMode(boolean mode); + + public void setCancelFlag(boolean flag); + public boolean getCancelFlag(); +} diff --git a/src/com/vmx/StringEncoder.java b/src/com/vmx/StringEncoder.java new file mode 100644 index 0000000..aa34876 --- /dev/null +++ b/src/com/vmx/StringEncoder.java @@ -0,0 +1,457 @@ +package com.vmx; + +import java.io.*; +import java.util.Vector; +import com.one.*; +import com.one.file.FileConnection; + +public class StringEncoder +{ + public static final char EMPTY_CHAR = ' '; + + /** Таблицы кодировок */ + protected static char[][] codepage; + protected static byte[][] fcetable; + + /** ÐÐ°Ð·Ð²Ð°Ð½Ð¸Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð¾Ðº */ + public static String[] encodings; + public static String[] encnames; + + public static final int ENC_UTF8 = -1; + public static final int ENC_UTF16N = -2; // Network Order + public static final int ENC_UTF16L = -3; // Little Endian + + public static final String ENC_NAME_UTF8 = "Unicode UTF-8"; + public static final String ENC_NAME_UTF16N = "Unicode UTF-16n"; + public static final String ENC_NAME_UTF16L = "Unicode UTF-16l"; + + public static int ENC_DEFAULT = 0; + public static int ENC_ARCHIVE = 0; + + /** + * КонÑтруктор. ПуÑтой. + */ + public StringEncoder() + { + } + + /** + * Загрузить кодовые таблицы + */ + public static void loadCodePages(boolean loadfce) throws IOException + { + Vector v = new Vector(); + + String defenc = null; + String arcenc = null; + + RandomAccessInputStream is = new BufferedInputStream(AuxClass.getResourceAsStream("/enc/enc.ini")); + + int enc = InputStreamDecoder.detectEncoding(is, ENC_UTF8); + //int pos = is.tell(); + //is.reset(); + + BufDataInputStream bdis = new BufDataInputStream(is); + //bdis.seek(pos); + + InputStreamDecoder isd = new InputStreamDecoder(bdis, enc); + IniRecord record = null; + + while((record = IniRecord.getNextRecord(isd)) != null) + { + if(defenc == null && record.key.equals("DEFAULT")) + { + defenc = record.value; + } + else if(arcenc == null && record.key.equals("ARCHIVE")) + { + arcenc = record.value; + } + else + { + v.addElement(record); + } + } + + isd.close(); + + codepage = new char[v.size()][128]; + encnames = new String[v.size()]; + encodings = new String[v.size()]; + + DataInputStream dis = null; + + for(int i = 0; i < v.size(); i++) + { + encnames[i] = ((IniRecord)v.elementAt(i)).key; + encodings[i] = ((IniRecord)v.elementAt(i)).value; + + try + { + isd = InputStreamDecoder.getResourceDecoder("/enc/" + encodings[i] + ".ini"); + + for(int j = 0; j < 128; j++) + { + codepage[i][j] = (char)j; + } + + while((record = IniRecord.getNextRecord(isd)) != null) + { + try + { + codepage[i][Integer.parseInt(record.key, 16) - 128] = (char)Integer.parseInt(record.value, 16); + } + catch(Exception e) + { + } + } + } + catch(NullPointerException npe) + { + // текÑтового файла нет - + // пробуем открыть двоичный + + try + { + dis = new DataInputStream(AuxClass.getResourceAsStream("/enc/" + encodings[i] + ".enc")); + + for(int j = 0; j < 128; j++) + { + codepage[i][j] = dis.readChar(); + } + + dis.close(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(39, e); + } + } + catch(Exception e) + { + ErrScreen.showErrMsg(39, e); + } + } + + if(loadfce) + { + try + { + fcetable = new byte[v.size()][65536]; + + for(int i = 0; i < v.size(); i++) + { + for(int j = 0; j < 65536; j++) + { + fcetable[i][j] = (byte)EMPTY_CHAR; + } + + for(int j = 0; j < 128; j++) + { + fcetable[i][codepage[i][j]] = (byte)(j + 128); + } + } + } + catch(OutOfMemoryError oome) + { + fcetable = null; + } + } + else + { + fcetable = null; + } + + if(defenc != null) + { + ENC_DEFAULT = findEncoding(defenc); + } + + if(arcenc != null) + { + ENC_ARCHIVE = findEncoding(arcenc); + } + } + + /** + * Кодировать Ñтроку s в кодировку enc + */ + public static byte[] encodeString(String s, int enc) + { + if(enc >= 0) + { + byte[] bs = new byte[s.length()]; + char[] cs = s.toCharArray(); + + for(int i = 0; i < s.length(); i++) + { + bs[i] = (byte)encodeChar(cs[i], enc); + } + + return bs; + } + else if(enc == ENC_UTF8) + { + try + { + return s.getBytes("UTF-8"); + } + catch(UnsupportedEncodingException x) + { + ErrScreen.showErrMsg(40, x); + return null; + } + } + else if(enc == ENC_UTF16N) + { + byte[] bs = new byte[s.length() * 2]; + char[] cs = s.toCharArray(); + + for(int i = 0; i < s.length(); i++) + { + bs[i * 2] = (byte)(cs[i] >>> 8); + bs[i * 2 + 1] = (byte)(cs[i] & 0xFF); + } + + return bs; + } + else if(enc == ENC_UTF16L) + { + byte[] bs = new byte[s.length() * 2]; + char[] cs = s.toCharArray(); + + for(int i = 0; i < s.length(); i++) + { + bs[i * 2] = (byte)(cs[i] & 0xFF); + bs[i * 2 + 1] = (byte)(cs[i] >>> 8); + } + + return bs; + } + + return null; + } + + /** + * Получить длину Ñтроки s в байтах в кодировке enc + */ + public static int getEncodedLength(String s, int enc) + { + if(enc >= 0) + { + return s.length(); + } + else if(enc == ENC_UTF8) + { + try + { + return s.getBytes("UTF-8").length; + } + catch(UnsupportedEncodingException x) + { + ErrScreen.showErrMsg(41, x); + return -1; + } + } + else if(enc == ENC_UTF16N || enc == ENC_UTF16L) + { + return s.length() * 2; + } + + return -1; + } + + /** + * Прочитать из потока Ñтроку длиной len байт в кодировке enc + */ + public static String readString(InputStream is, int len, int enc) throws IOException + { + byte[] b = new byte[len]; + len = is.read(b, 0, len); + + return StringEncoder.decodeString(b, 0, len, enc); + } + + /** + * Декодировать учаÑток маÑÑива b длиной len Ñо ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ off из кодировки enc + */ + public static String decodeString(byte[] bs, int off, int len, int enc) + { + if(enc >= 0) + { + StringBuffer s = new StringBuffer(bs.length); + + for(int i = 0; i < len; i++) + { + s.append(decodeChar(bs[off + i], enc)); + } + + return s.toString(); + } + else if(enc == ENC_UTF8) + { + try + { + return new String(bs, off, len, "UTF-8"); + } + catch(UnsupportedEncodingException x) + { + ErrScreen.showErrMsg(42, x); + return null; + } + } + else if(enc == ENC_UTF16N) + { + StringBuffer s = new StringBuffer(bs.length / 2); + + if(len % 2 != 0) + { + len--; + } + + for(int i = off; i < off + len; i += 2) + { + s.append((char)(((char)bs[i] << 8) | bs[i + 1])); + } + + return s.toString(); + } + else if(enc == ENC_UTF16L) + { + StringBuffer s = new StringBuffer(bs.length / 2); + + if(len % 2 != 0) + { + len--; + } + + for(int i = off; i < off + len; i += 2) + { + s.append((char)(((char)bs[i + 1] << 8) | bs[i])); + } + + return s.toString(); + } + + return null; + } + + /** + * Декодировать Ñимвол + */ + public static char decodeChar(int b, int enc) + { + if(b < 0) + { + b += 256; + } + + if(b < 128) + { + return (char)b; + } + else + { + return codepage[enc][b - 128]; + } + } + + /** + * Кодировать Ñимвол + */ + public static int encodeChar(char ch, int enc) + { + if(ch < 128) + { + return (int)ch; + } + else if(fcetable != null) + { + return (int)fcetable[enc][ch] & 0xFF; + } + else + { + for(int i = 0; i < 128; i++) + { + if(ch == codepage[enc][i]) + { + return i + 128; + } + } + + return (int)EMPTY_CHAR; //0x3F; // '?' - неизвеÑтный Ñимвол + } + } + + /** + * Перекодировать текÑÑ‚ из одной кодировки в другую. + * + * Ð”Ð»Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð»ÑŽÐ±Ñ‹Ñ… операций Ñ Ð®Ð½Ð¸ÐºÐ¾Ð´Ð¾Ð¼ необходимы два различных файла. + * Ð”Ð»Ñ Ð¾Ð´Ð½Ð¾Ð±Ð°Ð¹Ñ‚Ð¾Ð²Ñ‹Ñ… кодировок доÑтаточно одного файла. + * + * @param src FileConnection Ñ Ð¸Ñходным текÑтом + * @param dst FileConnection Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи перекодированного текÑта + * @param srcenc кодировка иÑходного текÑта + * @param dstenc кодировка, в которую перекодировать + * @param useBOM иÑпользовать ли UTF BOM Ñигнатуру + * @throws IOException еÑли иÑпользуетÑÑ Ð®Ð½Ð¸ÐºÐ¾Ð´ и оба FileConnection ÑоответÑтвуют одному файлу + */ + public static void transcode(FileConnection src, FileConnection dst, int srcenc, int dstenc, boolean useBOM) throws IOException + { + if((srcenc < 0 || dstenc < 0) && (src.getPath() + src.getName()).equals(dst.getPath() + dst.getName())) + { + throw new IOException("For Unicode conversion source and destination files must be distinct"); + } + + BufDataInputStream bdis = new BufDataInputStream(new FileInputStream(src)); + + // еÑли там еÑÑ‚ÑŒ BOM Ñигнатура, ее надо пропуÑтить + InputStreamDecoder.detectEncoding(bdis, StringEncoder.ENC_DEFAULT); + + InputStreamDecoder isd = new InputStreamDecoder(bdis, srcenc); + OutputStreamEncoder ose = new OutputStreamEncoder(dst.openOutputStream(), dstenc); + + if(useBOM) + { + ose.writeBOM(); + } + + while(isd.available() > 0) + { + ose.writeChar(isd.readChar()); + } + + ose.close(); + isd.close(); + } + + /** + * Получить номер кодировки enc. + * + */ + public static int findEncoding(String enc) + { + try + { + return Integer.parseInt(enc); + } + catch(NumberFormatException nfe) + { + } + + for(int i = 0; i < encodings.length; i++) + { + if(encodings[i].equals(enc)) + { + return i; + } + } + + return 0; + } + +// private static void out(String s) +// { +// System.out.println("[StringEncoder] " + s); +// } +} diff --git a/src/com/vmx/gkcCanvas.java b/src/com/vmx/gkcCanvas.java new file mode 100644 index 0000000..cce98f7 --- /dev/null +++ b/src/com/vmx/gkcCanvas.java @@ -0,0 +1,571 @@ +/* + * gkcCanvas.java + * + * Get Key Codes canvas + * (c) 2006, Виталий Филиппов [VMX] + */ + +package com.vmx; + +import java.util.Vector; +import com.one.*; +import javax.microedition.lcdui.Font; +import javax.microedition.lcdui.game.Sprite; + +public abstract class gkcCanvas extends PaintableObject +{ + public static int KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_FIRE; + public static int KEY_LSK, KEY_RSK, KEY_DIAL, KEY_CANCEL; // KEY_BACK, KEY_CLEAR, KEY_DIAL, KEY_CANCEL; + public static final int KEY_INVALID = 0; + + public static final int KEY_HELD = 0x80000000 >>> 1; + public static final int KEY_HOT = KEY_HELD >>> 1; + + public static String[] platforms; + public static int[][] keycodes; + public static final int KEYS_COUNT = 9; + + public static int PTX = 0; // Ñмещение ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ Ð¿Ð¾ горизонтали + public static int PTY = 0; // Ñмещение ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ Ð¿Ð¾ вертикали + public static int PCW = Font.getDefaultFont().getHeight(); // ширина Ñчейки ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ + public static int PCH = Font.getDefaultFont().getHeight(); // выÑота Ñчейки ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ + public static int PSF = Font.getDefaultFont().getHeight(); // выÑота облаÑти Ñофт-клавиш + + public static int[][] POINTER_GRID = + { + { KEY_NUM1, KEY_NUM2, KEY_NUM3 }, + { KEY_NUM4, KEY_NUM5, KEY_NUM6 }, + { KEY_NUM7, KEY_NUM8, KEY_NUM9 }, + { KEY_STAR, KEY_NUM0, KEY_POUND } + }; + + protected int pointx, pointy; + protected boolean ptr_flag; + protected boolean ptr_mode; + + public static int getDisplayWidth() + { + return getRenderer().getWidth(); + } + + public static int getDisplayHeight() + { + return getRenderer().getHeight(); + } + + public gkcCanvas() + { + } + + public static void readKeyMapList() + { + Vector vplatform = new Vector(); + Vector vcode = new Vector(); + + try + { + InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/config/keymap.ini"); + IniRecord record = null; + + int[] array; + Vector tokens; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + try + { + vplatform.addElement(record.key); + + array = new int[KEYS_COUNT]; + tokens = StringPattern.tokenizeString(record.value, ' '); + + for(int i = 0; i < KEYS_COUNT; i++) + { + try + { + array[i] = Integer.parseInt(((String)tokens.elementAt(i)).trim()); + } + catch(NumberFormatException nfe) + { + array[i] = 0; + } + } + + vcode.addElement(array); + } + catch(Exception e) + { + } + } + + ini.close(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(96, e); + } + + platforms = new String[vplatform.size()]; + vplatform.copyInto(platforms); + + keycodes = new int[vcode.size()][]; + vcode.copyInto(keycodes); + } + + public static int setKeyMap(int plindex, int transform) + { + int res = -1; + + if(plindex < 0) + { + Renderer rn = getRenderer(); + + KEY_UP = rn.getKeyCode(UP); + KEY_DOWN = rn.getKeyCode(DOWN); + KEY_LEFT = rn.getKeyCode(LEFT); + KEY_RIGHT = rn.getKeyCode(RIGHT); + KEY_FIRE = rn.getKeyCode(FIRE); + + for(plindex = 0; plindex < keycodes.length; plindex++) + { + if(KEY_UP == keycodes[plindex][0] && + KEY_DOWN == keycodes[plindex][1] && + KEY_LEFT == keycodes[plindex][2] && + KEY_RIGHT == keycodes[plindex][3] && + KEY_FIRE == keycodes[plindex][4]) + { + switch(transform) + { + case Sprite.TRANS_ROT90: + case Sprite.TRANS_MIRROR_ROT90: + KEY_UP = keycodes[plindex][3]; + KEY_DOWN = keycodes[plindex][2]; + KEY_LEFT = keycodes[plindex][0]; + KEY_RIGHT = keycodes[plindex][1]; + break; + + case Sprite.TRANS_ROT180: + case Sprite.TRANS_MIRROR_ROT180: + KEY_UP = keycodes[plindex][1]; + KEY_DOWN = keycodes[plindex][0]; + KEY_LEFT = keycodes[plindex][3]; + KEY_RIGHT = keycodes[plindex][2]; + break; + + case Sprite.TRANS_ROT270: + case Sprite.TRANS_MIRROR_ROT270: + KEY_UP = keycodes[plindex][2]; + KEY_DOWN = keycodes[plindex][3]; + KEY_LEFT = keycodes[plindex][1]; + KEY_RIGHT = keycodes[plindex][0]; + break; + } + + KEY_LSK = keycodes[plindex][5]; + KEY_RSK = keycodes[plindex][6]; + KEY_DIAL = keycodes[plindex][7]; + KEY_CANCEL = keycodes[plindex][8]; + + /* + KEY_DIAL = keycodes[plindex][7]; + KEY_CANCEL = keycodes[plindex][8]; + KEY_BACK = keycodes[plindex][9]; + KEY_CLEAR = keycodes[plindex][10]; + */ + + res = plindex; + break; + } + } + } + else if(plindex < keycodes.length) + { + switch(transform) + { + case Sprite.TRANS_ROT90: + case Sprite.TRANS_MIRROR_ROT90: + KEY_UP = keycodes[plindex][3]; + KEY_DOWN = keycodes[plindex][2]; + KEY_LEFT = keycodes[plindex][0]; + KEY_RIGHT = keycodes[plindex][1]; + break; + + case Sprite.TRANS_ROT180: + case Sprite.TRANS_MIRROR_ROT180: + KEY_UP = keycodes[plindex][1]; + KEY_DOWN = keycodes[plindex][0]; + KEY_LEFT = keycodes[plindex][3]; + KEY_RIGHT = keycodes[plindex][2]; + break; + + case Sprite.TRANS_ROT270: + case Sprite.TRANS_MIRROR_ROT270: + KEY_UP = keycodes[plindex][2]; + KEY_DOWN = keycodes[plindex][3]; + KEY_LEFT = keycodes[plindex][1]; + KEY_RIGHT = keycodes[plindex][0]; + break; + + default: + KEY_UP = keycodes[plindex][0]; + KEY_DOWN = keycodes[plindex][1]; + KEY_LEFT = keycodes[plindex][2]; + KEY_RIGHT = keycodes[plindex][3]; + break; + } + + KEY_FIRE = keycodes[plindex][4]; + + KEY_LSK = keycodes[plindex][5]; + KEY_RSK = keycodes[plindex][6]; + KEY_DIAL = keycodes[plindex][7]; + KEY_CANCEL = keycodes[plindex][8]; + + /* + KEY_DIAL = keycodes[plindex][7]; + KEY_CANCEL = keycodes[plindex][8]; + KEY_BACK = keycodes[plindex][9]; + KEY_CLEAR = keycodes[plindex][10]; + */ + + res = plindex; + } + + return res; + } + + /** + * УÑтанавливаем везде автоматичеÑкую + * обработку повторений как нажатий. + */ + public void keyRepeated(int keyCode) + { + keyPressed(keyCode); + } + + public void pointerPressed(int x, int y) + { + if(ptr_mode) + { + gridPointerPressed(x, y); + } + else + { + listPointerPressed(x, y); + } + } + + public void pointerDragged(int x, int y) + { + if(ptr_mode) + { + gridPointerDragged(x, y); + } + else + { + listPointerDragged(x, y); + } + } + + public void pointerReleased(int x, int y) + { + if(ptr_mode) + { + gridPointerReleased(x, y); + } + else + { + listPointerReleased(x, y); + } + } + + /** + * Переключение режимов перевода Ñобытий ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ Ð² ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ. + * @param mode true - иÑпользуетÑÑ ÐºÐ½Ð¾Ð¿Ð¾Ñ‡Ð½Ð°Ñ Ñетка, false - иÑпользуетÑÑ ÑпиÑок и Ñофт-кнопки + */ + public void setPointerMode(boolean mode) + { + ptr_mode = mode; + } + + public void gridPointerPressed(int x, int y) + { + x += PTX; + y += PTY; + + x /= getDisplayWidth() / POINTER_GRID[0].length; + y /= getDisplayHeight() / POINTER_GRID.length; + + keyPressed(POINTER_GRID[y][x]); + } + + public void gridPointerDragged(int x, int y) + { + x += PTX; + y += PTY; + + x /= getDisplayWidth() / POINTER_GRID[0].length; + y /= getDisplayHeight() / POINTER_GRID.length; + + keyRepeated(POINTER_GRID[y][x]); + } + + public void gridPointerReleased(int x, int y) + { + x += PTX; + y += PTY; + + x /= getDisplayWidth() / POINTER_GRID[0].length; + y /= getDisplayHeight() / POINTER_GRID.length; + + keyReleased(POINTER_GRID[y][x]); + } + + /** + * ЗдеÑÑŒ запоминаем начальную точку. + */ + public void listPointerPressed(int x, int y) + { + x += PTX; + y += PTY; + + if(y > getDisplayHeight() - PSF) + { + if(x < getDisplayWidth() / 2) + { + keyPressed(KEY_LSK); + } + else + { + keyPressed(KEY_RSK); + } + + ptr_flag = false; + } + else + { + pointx = x; + pointy = y; + + ptr_flag = true; + } + } + + /** + * ЗдеÑÑŒ обрабатываем Ñдвиг указателÑ. + */ + public void listPointerDragged(int x, int y) + { + x += PTX; + y += PTY; + + int deltaX = x - pointx; + int deltaY = y - pointy; + + if(Math.abs(deltaX) > Math.abs(deltaY)) + { + if(deltaX >= PCW) + { + while(deltaX >= PCW) + { + keyPressed(KEY_RIGHT); + deltaX -= PCW; + } + + deltaY = 0; + + ptr_flag = false; + } + else if(deltaX <= -PCW) + { + deltaX = -deltaX; + + while(deltaX >= PCW) + { + keyPressed(KEY_LEFT); + deltaX -= PCW; + } + + deltaX = -deltaX; + deltaY = 0; + + ptr_flag = false; + } + } + else + { + if(deltaY >= PCH) + { + while(deltaY >= PCH) + { + keyPressed(KEY_DOWN); + deltaY -= PCH; + } + + deltaX = 0; + + ptr_flag = false; + } + else if(deltaY <= -PCH) + { + deltaY = -deltaY; + + while(deltaY >= PCH) + { + keyPressed(KEY_UP); + deltaY -= PCH; + } + + deltaY = -deltaY; + deltaX = 0; + + ptr_flag = false; + } + } + + pointx = x - deltaX; + pointy = y - deltaY; + } + + public void listPointerReleased(int x, int y) + { + x += PTX; + y += PTY; + + if(y > getDisplayHeight() - PSF) + { + if(x < getDisplayWidth() / 2) + { + keyReleased(KEY_LSK); + } + else + { + keyReleased(KEY_RSK); + } + + ptr_flag = false; + } + else + { + if(ptr_flag) + { + keyPressed(KEY_FIRE); + keyReleased(KEY_FIRE); + } + } + } + + /** + * Проверка, ÑвлÑетÑÑ Ð»Ð¸ Ð½Ð°Ð¶Ð°Ñ‚Ð°Ñ ÐºÐ»Ð°Ð²Ð¸ÑˆÐ° цифровой. + */ + public static boolean isKeyNum(int keyCode) + { + keyCode &= ~(KEY_HELD | KEY_HOT); + return (keyCode >= KEY_NUM0 && keyCode <= KEY_NUM9) || keyCode == KEY_STAR || keyCode == KEY_POUND; + } + + /** + * ТранÑлировать Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ Ñ†Ð¸Ñ„Ñ€Ð¾Ð²Ñ‹Ñ… клавиш + * к нажатиÑм джойÑтика. + */ + public static int translateKey(int keyCode) + { + switch(keyCode) + { + case KEY_NUM2: + return KEY_UP; + + case KEY_NUM4: + return KEY_LEFT; + + case KEY_NUM5: + return KEY_FIRE; + + case KEY_NUM6: + return KEY_RIGHT; + + case KEY_NUM8: + return KEY_DOWN; + + default: + return keyCode; + } + } + + /** + * Повернуть джойÑтик. + */ + public static int rotateKey(int keyCode, int transform) + { + if(keyCode == KEY_UP) + { + switch(transform) + { + case Sprite.TRANS_ROT90: + case Sprite.TRANS_MIRROR_ROT90: + return KEY_LEFT; + + case Sprite.TRANS_ROT180: + case Sprite.TRANS_MIRROR_ROT180: + return KEY_DOWN; + + case Sprite.TRANS_ROT270: + case Sprite.TRANS_MIRROR_ROT270: + return KEY_LEFT; + } + } + else if(keyCode == KEY_DOWN) + { + switch(transform) + { + case Sprite.TRANS_ROT90: + case Sprite.TRANS_MIRROR_ROT90: + return KEY_RIGHT; + + case Sprite.TRANS_ROT180: + case Sprite.TRANS_MIRROR_ROT180: + return KEY_UP; + + case Sprite.TRANS_ROT270: + case Sprite.TRANS_MIRROR_ROT270: + return KEY_RIGHT; + } + } + else if(keyCode == KEY_LEFT) + { + switch(transform) + { + case Sprite.TRANS_ROT90: + case Sprite.TRANS_MIRROR_ROT90: + return KEY_DOWN; + + case Sprite.TRANS_ROT180: + case Sprite.TRANS_MIRROR_ROT180: + return KEY_RIGHT; + + case Sprite.TRANS_ROT270: + case Sprite.TRANS_MIRROR_ROT270: + return KEY_UP; + } + } + else if(keyCode == KEY_RIGHT) + { + switch(transform) + { + case Sprite.TRANS_ROT90: + case Sprite.TRANS_MIRROR_ROT90: + return KEY_UP; + + case Sprite.TRANS_ROT180: + case Sprite.TRANS_MIRROR_ROT180: + return KEY_LEFT; + + case Sprite.TRANS_ROT270: + case Sprite.TRANS_MIRROR_ROT270: + return KEY_DOWN; + } + } + + return keyCode; + } +} diff --git a/src/filemanager/Buffer.java b/src/filemanager/Buffer.java new file mode 100644 index 0000000..8172416 --- /dev/null +++ b/src/filemanager/Buffer.java @@ -0,0 +1,293 @@ +package filemanager; + +import com.vmx.Locale; +import javax.microedition.lcdui.*; +import java.util.*; + +/** + * Буфер обмена. + */ +public class Buffer +{ + /** + * Поток, управлÑющий операциÑми. + * При Ñоздании запуÑкает операцию в отдельном потоке, + * Ñоздает и выводит на Ñкран Ñообщение "Подождите...", + * ждет, пока тот поток завершитÑÑ, и, наконец, + * показывает Ñообщение об ошибках или их отÑутÑтвии. + * ПредоÑтавлÑет ÑредÑтва Ð´Ð»Ñ ÑÐ²Ð¾Ñ€Ð°Ñ‡Ð¸Ð²Ð°Ð½Ð¸Ñ / отмены операции. + */ + protected static class OperationHandler implements Runnable, CommandListener + { + protected Operation operation; + protected Thread thread; + protected GraphicAlert alert; + + public OperationHandler(Operation operation) + { + this.operation = operation; + + alert = new GraphicAlert(Locale.getString(this, Locale.WAIT), Locale.getString(this, Locale.WAIT_PLEASE), images.getAlertIcon(AlertType.INFO), AlertType.INFO); + alert.setIndicator(true); + operation.setProgressCallback(alert); + + //alert.addCommand(new Command(Locale.getString(this, Locale.MINIMIZE_CMD), Command.OK, 1)); + alert.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.CANCEL, 2)); + alert.setCommandListener(this); + + main.dsp.setCurrent(alert); + + thread = new Thread(operation, "OperationHandler/Operation"); + thread.start(); + } + + public void display() + { + main.dsp.setCurrent(alert); + } + + public void run() + { + if(thread.isAlive()) + { + try + { + thread.join(); + } + catch(InterruptedException ie) + { + } + } + + main.dsp.setCurrent(new alMessage(operation.getErrors())); + Buffer.disposeOperationHandler(); + + if(operation.getClearFlag()) + { + Buffer.clear(); + } + } + + public void commandAction(Command c, Displayable dp) + { + if(c.getCommandType() == Command.OK) + { + main.FileSelect.showWait(main.currentFile); + } + else + { + operation.stop(); + } + } + } + + protected static Vector buf = new Vector(); + protected static Hashtable moveit = new Hashtable(); + protected static OperationHandler handler = null; + + /** + * Добавить в буфер. + */ + public static void add(String file, boolean move) + { + add(file, move, false); + } + + /** + * Добавить в буфер. + * ЕÑли flatten = true, то Ñтруктура файлов + * из добавлÑемых папок разворачиваетÑÑ. + */ + protected static void add(String file, boolean move, boolean flatten) + { + if(flatten && filesystem.isDir(file)) + { + Enumeration files = filesystem.listNoArchives(file, options.showHidden); + + while(files.hasMoreElements()) + { + add(file + (String)files.nextElement(), move, true); + } + } + else + { + buf.removeElement(file); + buf.addElement(file); + + moveit.remove(file); + moveit.put(file, new Boolean(move)); + } + } + + /** + * Удалить из буфера. + */ + public static void remove(String file) + { + buf.removeElement(file); + moveit.remove(file); + } + + /** + * Удалить из буфера. + */ + public static void remove(int index) + { + remove((String)buf.elementAt(index)); + +// Enumeration files = moveit.keys(); +// +// for(int i = 0; i < index && files.hasMoreElements(); i++, files.nextElement()); +// +// if(files.hasMoreElements()) +// { +// moveit.remove(files.nextElement()); +// } + } + + /** + * ОчиÑтить буфер. + */ + public static void clear() + { + buf.removeAllElements(); + moveit.clear(); + } + + /** + * Развернуть файловую Ñтруктуру в буфере, + * чтобы там оÑталиÑÑŒ только файлы. + */ + public static void flattenBuffer() + { + Vector vtemp = buf; + buf = new Vector(); + + Hashtable htemp = moveit; + moveit = new Hashtable(); + + Enumeration files = vtemp.elements(); // htemp.keys(); + String s; + + while(files.hasMoreElements()) + { + s = (String)files.nextElement(); + add(s, ((Boolean)htemp.get(s)).booleanValue(), true); + } + } + + /** + * Сортировать файлы в буфере. + */ + public static void sortBuffer() + { + Vector items = new Vector(); + + Enumeration files = buf.elements(); + + while(files.hasMoreElements()) + { + items.addElement(new FileItem((String)files.nextElement(), false)); + } + + if(options.listSortBy > 0) + { + FileItem.sortFileList(items, options.listSortBy, options.listSortIgnoreCase, !options.listSortReverseOrder, 1, items.size() - 1); + } + + buf.removeAllElements(); + + files = items.elements(); + + while(files.hasMoreElements()) + { + buf.addElement(((FileItem)files.nextElement()).getFullName()); + } + } + + /** + * Вернуть буфер как Enumeration Ñтрок. + */ + public static Enumeration getBuffer() + { + return buf.elements(); // moveit.keys(); + } + + /** + * Вернуть количеÑтво файлов в буфере. + */ + public static int getSize() + { + return buf.size(); // moveit.size(); + } + + /** + * ТребуетÑÑ Ð»Ð¸ перемеÑтить файл file, + * или проÑто Ñкопировать. + */ + public static boolean isMoved(String file) + { + Boolean move = (Boolean)moveit.get(file); + + if(move != null) + { + return move.booleanValue(); + } + + return false; + } + + /** + * Сотворить что-нибудь (Ñ Ñ„Ð°Ð¹Ð»Ð°Ð¼Ð¸ в буфере). + * ЕÑли же в фоне уже выполнÑетÑÑ ÐºÐ°ÐºÐ°Ñ-либо операциÑ, она разворачиваетÑÑ. + */ + public static void startOperation(Operation operation) + { + if(handler != null) + { + throw new IllegalStateException(); + } + + handler = new OperationHandler(operation); + (new Thread(handler, "Buffer/OperationHandler")).start(); + } + + /** + * Текущий OperationHandler более не нужен. + * ВызываетÑÑ Ñамим OperationHandler'ом. + * Попутно буфер очищаетÑÑ. + */ + public static void disposeOperationHandler() + { + if(handler != null) + { + handler = null; + } + } + + /** + * Проверить, не выполнÑетÑÑ Ð»Ð¸ уже (в фоне) какаÑ-либо операциÑ. + */ + public static boolean isOperationRunning() + { + return handler != null; + } + + /** + * Развернуть выполнÑемую (в фоне) операцию. + * ЕÑли такой операции нет, ничего не проиÑходит. + * ВозвращаетÑÑ true, еÑли Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð´ÐµÐ¹Ñтвительно была развернута. + */ + public static boolean displayCurrentOperation() + { + if(handler != null) + { + handler.display(); + return true; + } + else + { + return false; + } + } +} diff --git a/src/filemanager/ColorScheme.java b/src/filemanager/ColorScheme.java new file mode 100644 index 0000000..1f7c388 --- /dev/null +++ b/src/filemanager/ColorScheme.java @@ -0,0 +1,327 @@ +package filemanager; + +import java.io.*; +import com.one.*; +import com.vmx.*; +import java.util.Vector; +import javax.microedition.lcdui.Image; + +/** + * КлаÑÑ Ñодержит цветовую Ñхему + */ +public class ColorScheme +{ + public static final int SCHEME_CUSTOM = -1; + + public static String[] schemes; + + public static final int fore = 0, + altfore = 1, + hlfore = 2, + ltborder = 3, + mdborder = 4, + dkborder = 5, + disabled = 6, + back1 = 7, + back2 = 8, + selfore = 9, + selback1 = 10, + selback2 = 11, + mnfore = 12, + mnaltfore = 13, + mnback1 = 14, + mnback2 = 15, + mnselfore = 16, + mnselback1 = 17, + mnselback2 = 18, + skfore = 19, + skselfore = 20, + skselback1 = 21, + skselback2 = 22, + drap = 23, + sbline = 24, + sbfore = 25; + + public static int[] colors = new int[] + { + 0xFF000080, // Fore + 0xFF008000, // AltFore + 0xFFFF0000, // HLFore + + 0xFFFFFFFF, // LTBorder + 0xFF000080, // MDBorder + 0xFF000000, // DKBorder + + 0xFF808080, // Disabled + + 0xFFD0D0D0, // Back1 + 0xFFD0D0D0, // Back2 + 0xFFFFFFFF, // SelFore + 0xFF000080, // SelBack1 + 0xFF000080, // SelBack2 + + 0xFF000080, // MnFore + 0xFF008000, // MnAltFore + 0xFFD0D0D0, // MnBack1 + 0xFFD0D0D0, // MnBack2 + 0xFFFFFFFF, // MnSelFore + 0xFF000080, // MnSelBack1 + 0xFF000080, // MnSelBack2 + + 0xFF000080, // SKFore + 0xFFFFFFFF, // SKSelFore + 0xFF000080, // SKSelBack1 + 0xFF000080, // SKSelBack2 + + 0xD0D0D0D0, // Drap + + 0xFFFFFFFF, // SBLine + 0xFF000080 // SBFore + }; + + public static String[] cnames = new String[] + { + "Fore", + "AltFore", + "HLFore", + + "LTBorder", + "MDBorder", + "DKBorder", + + "Disabled", + + "Back1", + "Back2", + "SelFore", + "SelBack1", + "SelBack2", + + "MnFore", + "MnAltFore", + "MnBack1", + "MnBack2", + "MnSelFore", + "MnSelBack1", + "MnSelBack2", + + "SKFore", + "SKSelFore", + "SKSelBack1", + "SKSelBack2", + + "Drap", + + "SBLine", + "SBFore" + }; + + public static void readSchemeList() + { + Vector v = new Vector(); + + try + { + InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/style/style.ini"); + IniRecord record = null; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + v.addElement(record.value); + } + + ini.close(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(43, e); + } + + schemes = new String[v.size()]; + v.copyInto(schemes); + } + + public static boolean loadColorScheme(int scheme) throws IOException + { + if(scheme < 0 || scheme >= schemes.length) + { + return false; + } + + PlainPackage ppk = new PlainPackage(); + ppk.init(new BufferedInputStream(AuxClass.getResourceAsStream("/style/" + schemes[scheme] + ".ncs"))); + + boolean flag = loadModernColorScheme(ppk); + + ppk.close(); + + return flag; + } + + public static void loadLegacyColorScheme(DataInputStream dis) throws IOException + { + colors[fore] = dis.readInt(); + colors[altfore] = dis.readInt(); + colors[hlfore] = dis.readInt(); + colors[dkborder] = dis.readInt(); + colors[disabled] = dis.readInt(); + colors[back1] = dis.readInt(); + colors[back2] = dis.readInt(); + colors[selfore] = dis.readInt(); + colors[selback1] = dis.readInt(); + colors[selback2] = dis.readInt(); + + colors[ltborder] = colors[selfore]; + colors[mdborder] = colors[fore]; + + colors[mnfore] = colors[fore]; + colors[mnaltfore] = colors[altfore]; + colors[mnback1] = colors[back1]; + colors[mnback2] = colors[back2]; + colors[mnselfore] = colors[selfore]; + colors[mnselback1] = colors[selback1]; + colors[mnselback2] = colors[selback2]; + + colors[skfore] = colors[fore]; + colors[skselfore] = colors[selfore]; + colors[skselback1] = colors[selback1]; + colors[skselback2] = colors[selback2]; + + colors[sbline] = colors[fore]; + colors[sbfore] = colors[fore]; + + for(int i = 0; i < colors.length; i++) + { + colors[i] |= 0xFF000000; + } + + colors[drap] = (colors[back1] & 0xFFFFFF) | 0xC0000000; // (((((colors[back1] >> 16) & 0xFF) + ((colors[back1] >> 8) & 0xFF) + (colors[back1] & 0xFF)) / 3) << 24); + } + + public static boolean loadModernColorScheme(PlainPackage ppk) throws IOException + { + boolean flag = false; + + InputStream is = ppk.getInputStream(ppk.getEntry("scheme.ini")); + + if(is != null) + { + InputStreamDecoder isd = InputStreamDecoder.getStreamDecoder(is); + IniFile ini = new IniFile(isd, true); + isd.close(); + + for(int i = 0; i < colors.length; i++) + { + colors[i] = AuxClass.parseHexInt(ini.getRecord("Colors", cnames[i]), colors[i]); + } + } + + is = ppk.getInputStream(ppk.getEntry("images.ini")); + + if(is != null) + { + InputStreamDecoder ini = InputStreamDecoder.getStreamDecoder(is); + IniRecord record = null; + + InputStream iis; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + iis = ppk.getInputStream(ppk.getEntry(record.value)); + + if(iis != null) + { + try + { + ImageProcessor.addImageToCache(record.key, Image.createImage(iis)); + iis.close(); + } + catch(Exception e) + { + } + } + } + + ini.close(); + } + + is = ppk.getInputStream(ppk.getEntry("icons.ini")); + + if(is != null) + { + ProgressBar.show(); + + InputStreamDecoder ini = InputStreamDecoder.getStreamDecoder(is); + images.loadIcons(ini, ProgressBar.getProgressCallback(), options.noEffects); + ini.close(); + + flag = true; + } + + is = ppk.getInputStream(ppk.getEntry("modules.ini")); + + if(is != null) + { + ProgressBar.show(); + + InputStreamDecoder ini = InputStreamDecoder.getStreamDecoder(is); + ModuleRegistry.loadIcons(ini, ProgressBar.getProgressCallback(), options.noEffects); + ini.close(); + + flag = true; + } + + ImageProcessor.releaseCachedImages(); + + ProgressBar.hide(); + + return flag; + } + + public static void saveColorScheme(OutputStream os) throws IOException + { + IniFile ini = new IniFile(false); + + for(int i = 0; i < colors.length; i++) + { + ini.addRecord("Colors", cnames[i], Integer.toHexString(colors[i]).toUpperCase()); + } + + OutputStreamEncoder ose = new OutputStreamEncoder(os, StringEncoder.ENC_DEFAULT); + ose.writeBOM(); + + ini.write(ose); + + ose.close(); + } + + public static void readSchemeData(DataInputStream dis) throws IOException + { + int count = dis.readInt(); + + if(count == colors.length) + { + for(int i = 0; i < count; i++) + { + colors[i] = dis.readInt(); + } + } + else + { + for(int i = 0; i < count; i++) + { + dis.readInt(); + } + } + } + + public static void writeSchemeData(DataOutputStream dos) throws IOException + { + dos.writeInt(colors.length); + + for(int i = 0; i < colors.length; i++) + { + dos.writeInt(colors[i]); + } + } +} diff --git a/src/filemanager/ColorSelector.java b/src/filemanager/ColorSelector.java new file mode 100644 index 0000000..dae36d8 --- /dev/null +++ b/src/filemanager/ColorSelector.java @@ -0,0 +1,514 @@ +package filemanager; + +import javax.microedition.lcdui.*; +import com.vmx.*; + +public class ColorSelector extends gkcCanvas implements Runnable +{ + public static class KeyRepeatThread implements Runnable + { + protected ColorSelector canvas; + + protected Thread thread; + protected final Object waiter; + protected boolean isrunning; + + protected boolean enabled; + protected int key; + + public KeyRepeatThread(ColorSelector canvas) + { + this.canvas = canvas; + + waiter = new Object(); + + thread = new Thread(this, "ColorSelector/KeyRepeat"); + thread.start(); + } + + public void start(int key) + { + if(isrunning) + { + return; + } + + this.key = key; + + enabled = true; + + synchronized(waiter) + { + waiter.notifyAll(); + } + } + + public void stop() + { + enabled = false; + thread.interrupt(); + } + + public boolean isRunning() + { + return isrunning; + } + + public void run() + { + while(true) + { + try + { + synchronized(waiter) + { + isrunning = false; + waiter.wait(); + } + + isrunning = true; + Thread.sleep(450); + + while(enabled) + { + canvas.keyPressed(key); + Thread.yield(); + } + } + catch(InterruptedException ie) + { + } + } + } + } + + protected int CELL; + + protected Font ttlfont, font; + protected int ttlfnth, fnth; + + protected int width, height; + + protected int ttlx, ttly, ttlh, ttlw; + + protected Image transp; + protected int linex, linew, lineh; + protected int[] liney = new int[5]; + protected int cr, cg, cb, ca; + protected int[] lnr, lng, lnb, lna, lnc; + protected boolean interactive; + + protected String clr; + protected int clrx, clry; + + protected CommandMenu cmenu; + + protected final Image offscreen; + protected Graphics offgraphics; + + protected Thread thread; + protected final Object waiter; + protected boolean ispainting; + protected boolean isshown; + + protected KeyRepeatThread repthread; + + protected Image background; + + public ColorSelector() + { + setFullScreenMode(true); + + width = getWidth(); + height = getHeight(); + + offscreen = Image.createImage(width, height); + offgraphics = offscreen.getGraphics(); + + ttlfont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM); + font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, options.largeFontInMenu ? Font.SIZE_MEDIUM : Font.SIZE_SMALL); + + ttlfnth = ttlfont.getHeight(); + fnth = font.getHeight(); + + ttlw = ttlfont.stringWidth(Locale.getString(this, Locale.COLOR_SELECTOR)) + ttlfnth; + ttlh = ttlfnth * 3 / 2; + ttlx = ttlfnth / 2; + ttly = (ttlh - ttlfnth) / 2; + + cmenu = new CommandMenu(getRenderer(), null, width, height, options.largeFontInMenu ? Font.SIZE_MEDIUM : Font.SIZE_SMALL, true, false, false, false, false); + + lineh = (height - ttlh - cmenu.getSoftHeight() - ttlfnth * 2) / 5; + CELL = lineh / 4; + lineh -= lineh % CELL; + lineh += 2; + + linew = width - fnth; + linew -= linew % CELL; + linew += 2; + + linex = (width - linew) / 2; + + liney[0] = ttlh + (height - ttlh - cmenu.getSoftHeight() - (lineh - 1) * 5) / 2; + liney[1] = liney[0] + lineh - 1; + liney[2] = liney[1] + lineh - 1; + liney[3] = liney[2] + lineh - 1; + liney[4] = liney[3] + lineh - 1; + + clrx = linex + fnth / 2; + clry = liney[4] + (lineh - fnth) / 2; + + transp = LineEffect.createCheckedField(-1, 0, linew, lineh, CELL); + + lnr = new int[linew]; + lng = new int[linew]; + lnb = new int[linew]; + lna = new int[linew]; + lnc = new int[linew]; + + interactive = true; + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.PALETTE_CMD), Command.ITEM, 2)); + addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.CANCEL, 3)); + + waiter = new Object(); + + thread = new Thread(this, "ColorSelector/AsyncPaint"); + thread.start(); + + repthread = new KeyRepeatThread(this); + } + + public void setInteractive(boolean flag) + { + interactive = flag; + + if(!interactive) + { + createGradientLine(lna, 0, 0, 0, 0, 255, 0, 0, 0); + createGradientLine(lnr, 0, 0, 0, 0, 0, 255, 0, 0); + createGradientLine(lng, 0, 0, 0, 0, 0, 0, 255, 0); + createGradientLine(lnb, 0, 0, 0, 0, 0, 0, 0, 255); + } + } + + public void setColor(int color) + { + ca = (color >> 24) & 0xFF; + cr = (color >> 16) & 0xFF; + cg = (color >> 8) & 0xFF; + cb = color & 0xFF; + + startRepaint(); + } + + public int getColor() + { + return (ca << 24) | (cr << 16) | (cg << 8) | cb; + } + + public void startRepaint() + { + synchronized(waiter) + { + if(!ispainting) + { + waiter.notifyAll(); + } + } + } + + public void waitForRepaint() + { + synchronized(waiter) + { + if(ispainting) + { + try + { + waiter.wait(); + } + catch(InterruptedException ie) + { + } + } + } + } + + public void showNotify() + { + isshown = true; + startRepaint(); + } + + public void hideNotify() + { + isshown = false; + repthread.stop(); + } + + public void paint(Graphics g) + { + synchronized(offscreen) + { + g.drawImage(offscreen, 0, 0, Graphics.LEFT | Graphics.TOP); + } + } + + public void run() + { + try + { + while(true) + { + synchronized(waiter) + { + ispainting = false; + + waiter.notifyAll(); + waiter.wait(); + + ispainting = true; + } + + createGradientLine(lnc, ca, cr, cg, cb, ca, cr, cg, cb); + + if(interactive) + { + createGradientLine(lna, 0, cr, cg, cb, 255, cr, cg, cb); + createGradientLine(lnr, ca, 0, cg, cb, ca, 255, cg, cb); + createGradientLine(lng, ca, cr, 0, cb, ca, cr, 255, cb); + createGradientLine(lnb, ca, cr, cg, 0, ca, cr, cg, 255); + } + + clr = Integer.toHexString(getColor()).toUpperCase(); + + synchronized(offscreen) + { + //offgraphics.setColor(ColorScheme.colors[ColorScheme.back1]); + //offgraphics.fillRect(0, 0, width, height); + + if(background != null) + { + offgraphics.drawImage(background, 0, 0, Graphics.LEFT | Graphics.TOP); + } + else + { + images.drawVGradient(offgraphics, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, width, height, options.ditherGradients, options.alphaGradients); + } + + offgraphics.setColor(ColorScheme.colors[ColorScheme.fore]); + offgraphics.setFont(ttlfont); + offgraphics.drawString(Locale.getString(this, Locale.COLOR_SELECTOR), ttlx, ttly, Graphics.LEFT | Graphics.TOP); + + offgraphics.setColor(ColorScheme.colors[ColorScheme.ltborder]); + offgraphics.drawLine(0, ttlh, ttlw, ttlh); + + offgraphics.setClip(linex, liney[0], linew, (lineh - 1) * 5 + 1); + + offgraphics.drawImage(transp, linex + 1, liney[0] + 1, Graphics.LEFT | Graphics.TOP); + offgraphics.drawImage(transp, linex + 1, liney[1] + 1, Graphics.LEFT | Graphics.TOP); + offgraphics.drawImage(transp, linex + 1, liney[2] + 1, Graphics.LEFT | Graphics.TOP); + offgraphics.drawImage(transp, linex + 1, liney[3] + 1, Graphics.LEFT | Graphics.TOP); + offgraphics.drawImage(transp, linex + 1, liney[4] + 1, Graphics.LEFT | Graphics.TOP); + + for(int i = 0; i < lineh; i++) + { + offgraphics.drawRGB(lnr, 0, linew, linex, liney[0] + i, linew, 1, interactive); + offgraphics.drawRGB(lng, 0, linew, linex, liney[1] + i, linew, 1, interactive); + offgraphics.drawRGB(lnb, 0, linew, linex, liney[2] + i, linew, 1, interactive); + offgraphics.drawRGB(lna, 0, linew, linex, liney[3] + i, linew, 1, true); + offgraphics.drawRGB(lnc, 0, linew, linex, liney[4] + i, linew, 1, interactive); + } + + int color = getColor(); + int alpha = ((ca << 16) | (ca << 8) | ca); + int pos; + + offgraphics.setColor(color ^ 0xC0C0C0); + pos = linex + linew * cr / 256; + offgraphics.drawLine(pos, liney[0], pos, liney[0] + 3); + offgraphics.drawLine(pos - 1, liney[0] + 2, pos + 1, liney[0] + 2); + offgraphics.drawLine(pos - 2, liney[0] + 1, pos + 2, liney[0] + 1); + offgraphics.drawLine(pos, liney[0] + lineh - 1, pos, liney[0] + lineh - 4); + offgraphics.drawLine(pos - 1, liney[0] + lineh - 3, pos + 1, liney[0] + lineh - 3); + offgraphics.drawLine(pos - 2, liney[0] + lineh - 2, pos + 2, liney[0] + lineh - 2); + + offgraphics.setColor(color ^ 0xC0C0C0); + pos = linex + linew * cg / 256; + offgraphics.drawLine(pos, liney[1], pos, liney[1] + 3); + offgraphics.drawLine(pos - 1, liney[1] + 2, pos + 1, liney[1] + 2); + offgraphics.drawLine(pos - 2, liney[1] + 1, pos + 2, liney[1] + 1); + offgraphics.drawLine(pos, liney[1] + lineh - 1, pos, liney[1] + lineh - 4); + offgraphics.drawLine(pos - 1, liney[1] + lineh - 3, pos + 1, liney[1] + lineh - 3); + offgraphics.drawLine(pos - 2, liney[1] + lineh - 2, pos + 2, liney[1] + lineh - 2); + + offgraphics.setColor(color ^ 0xC0C0C0); + pos = linex + linew * cb / 256; + offgraphics.drawLine(pos, liney[2], pos, liney[2] + 3); + offgraphics.drawLine(pos - 1, liney[2] + 2, pos + 1, liney[2] + 2); + offgraphics.drawLine(pos - 2, liney[2] + 1, pos + 2, liney[2] + 1); + offgraphics.drawLine(pos, liney[2] + lineh - 1, pos, liney[2] + lineh - 4); + offgraphics.drawLine(pos - 1, liney[2] + lineh - 3, pos + 1, liney[2] + lineh - 3); + offgraphics.drawLine(pos - 2, liney[2] + lineh - 2, pos + 2, liney[2] + lineh - 2); + + offgraphics.setColor(color ^ alpha); + pos = linex + linew * ca / 256; + offgraphics.drawLine(pos, liney[3], pos, liney[3] + 3); + offgraphics.drawLine(pos - 1, liney[3] + 2, pos + 1, liney[3] + 2); + offgraphics.drawLine(pos - 2, liney[3] + 1, pos + 2, liney[3] + 1); + offgraphics.drawLine(pos, liney[3] + lineh - 1, pos, liney[3] + lineh - 4); + offgraphics.drawLine(pos - 1, liney[3] + lineh - 3, pos + 1, liney[3] + lineh - 3); + offgraphics.drawLine(pos - 2, liney[3] + lineh - 2, pos + 2, liney[3] + lineh - 2); + + offgraphics.setFont(font); + + if(interactive) + { + offgraphics.setColor(color); + LineEffect.drawTextOutline(offgraphics, clr, clrx, clry, 3); + } + + offgraphics.setColor(color ^ 0xC0C0C0); + offgraphics.drawString(clr, clrx, clry, Graphics.LEFT | Graphics.TOP); + + offgraphics.setColor(ColorScheme.colors[ColorScheme.ltborder]); + offgraphics.drawRect(linex, liney[0], linew - 1, lineh - 1); + offgraphics.drawRect(linex, liney[1], linew - 1, lineh - 1); + offgraphics.drawRect(linex, liney[2], linew - 1, lineh - 1); + offgraphics.drawRect(linex, liney[3], linew - 1, lineh - 1); + offgraphics.drawRect(linex, liney[4], linew - 1, lineh - 1); + + offgraphics.setClip(0, 0, width, height); + + cmenu.paint(offgraphics); + } + + if(isshown) + { + repaint(); + } + } + } + catch(InterruptedException ie) + { + } + } + + public void addCommand(Command c) + { + cmenu.addCommand(c); + } + + public void setCommandListener(CommandListener cl) + { + cmenu.setCommandListener(cl); + } + + public void keyPressed(int keyCode) + { + if(cmenu.keyPressed(keyCode)) + { + startRepaint(); + return; + } + + repthread.start(keyCode); + + if(keyCode == KEY_NUM1 && cr > 0) + { + cr--; + } + else if(keyCode == KEY_NUM3 && cr < 255) + { + cr++; + } + else if(keyCode == KEY_NUM4 && cg > 0) + { + cg--; + } + else if(keyCode == KEY_NUM6 && cg < 255) + { + cg++; + } + else if(keyCode == KEY_NUM7 && cb > 0) + { + cb--; + } + else if(keyCode == KEY_NUM9 && cb < 255) + { + cb++; + } + else if(keyCode == KEY_STAR && ca > 0) + { + ca--; + } + else if(keyCode == KEY_POUND && ca < 255) + { + ca++; + } + else if(keyCode == KEY_NUM2) + { + cr ^= 0xFF; + } + else if(keyCode == KEY_NUM5) + { + cg ^= 0xFF; + } + else if(keyCode == KEY_NUM8) + { + cb ^= 0xFF; + } + else if(keyCode == KEY_NUM0) + { + ca ^= 0xFF; + } + else + { + return; + } + + startRepaint(); + } + + public void keyReleased(int keyCode) + { + repthread.stop(); + + if(cmenu.keyReleased(keyCode)) + { + startRepaint(); + return; + } + } + + public void keyRepeated(int keyCode) + { + if(cmenu.isInMenu()) + { + keyPressed(keyCode); + } + } + + public static void createGradientLine(int[] rgb, int sa, int sr, int sg, int sb, int ea, int er, int eg, int eb) + { + rgb[0] = (sa << 24) | (sr << 16) | (sg << 8) | sb; + rgb[rgb.length - 1] = (ea << 24) | (er << 16) | (eg << 8) | eb; + + int a, r, g, b; + int i, j, n; + + for(i = 1, n = rgb.length - 2; i <= n; i++) + { + j = n - i; + + a = (sa * j + ea * i) / n; + r = (sr * j + er * i) / n; + g = (sg * j + eg * i) / n; + b = (sb * j + eb * i) / n; + + rgb[i] = (a << 24) | (r << 16) | (g << 8) | b; + } + } +} \ No newline at end of file diff --git a/src/filemanager/CommandMenu.java b/src/filemanager/CommandMenu.java new file mode 100644 index 0000000..5c11f64 --- /dev/null +++ b/src/filemanager/CommandMenu.java @@ -0,0 +1,786 @@ +package filemanager; + +import javax.microedition.lcdui.*; +import java.util.Vector; +import com.vmx.*; + +public class CommandMenu +{ + protected Displayable caller; + + protected Font font; + protected FontWidthCache fwc; + protected boolean lskp, rskp; + protected String lsktext, rsktext; + protected int lskx, rskx, sky, skh; + protected int w2, h2; + protected int width, height; + + protected Vector commands; + protected boolean inmenu; + protected int mx, my, mw, mh, mlh; + protected CommandListener listener; + protected int msel; + protected int iok, icancel; + protected boolean okp, cancelp; + protected HotKeyListener hklistener; + protected boolean hkmode; + protected boolean skvisible; + protected Image drap; + + protected boolean center; + protected boolean extkey; + protected boolean hotkey; + protected boolean hidesoft; + protected boolean showdrap; + + /** + * Создать командное меню. + * + * @param caller Displayable, который будет передаватьÑÑ Ð²Ñ‚Ð¾Ñ€Ñ‹Ð¼ параметром в commandAction() + * @param hklistener обработчик "горÑчих клавиш", или null + * @param width ширина Ñкрана + * @param height выÑота Ñкрана + * @param fntsize размер шрифта (конÑтанта из Font) + * @param center центрировать меню на Ñкране, или прилепить к правому Ñофту + * @param extkey иÑпользовать ли цифровые клавиши Ð´Ð»Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¼ÐµÐ½ÑŽ + * @param hotkey разрешить ли режим "горÑчих клавиш" + * @param hidesoft Ñкрывать ли Ñофт-Ñтроку, когда мы не в меню + * @param showdrap драпировать ли фон, когда мы в меню + */ + public CommandMenu(Displayable caller, HotKeyListener hklistener, int width, int height, int fntsize, boolean center, boolean extkey, boolean hotkey, boolean hidesoft, boolean showdrap) + { + this.caller = caller; + this.hklistener = hklistener; + + this.width = width; + this.height = height; + + this.center = center; + this.extkey = extkey; + this.hotkey = hotkey; + this.hidesoft = hidesoft; + this.showdrap = showdrap; + + if(showdrap) + { + int[] rgb = new int[width * height]; + + for(int i = 0; i < rgb.length; i++) + { + rgb[i] = ColorScheme.colors[ColorScheme.drap]; + } + + drap = Image.createRGBImage(rgb, width, height, true); + } + + font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, fntsize); + fwc = FontWidthCache.getCache(font); + + skh = font.getHeight() + font.getHeight() / 3; + w2 = width / 2; + h2 = height - skh; + + lsktext = ""; + rsktext = ""; + + lskp = false; + rskp = false; + + sky = h2 + (skh - font.getHeight()) / 2; + lskx = (w2 - fwc.stringWidth(lsktext)) / 2; + rskx = w2 + (w2 - fwc.stringWidth(rsktext)) / 2; + + skvisible = false; + + commands = new Vector(); + + iok = -1; + icancel = -1; + + okp = false; + cancelp = false; + + inmenu = false; + mw = w2; + mh = 0; + mx = w2; + my = height - skh - mh; + mlh = skh; + } + + public int getSoftHeight() + { + return skh; + } + + public boolean isInMenu() + { + return inmenu; + } + + public void addCommand(Command c) + { + if(commands.contains(c)) + { + return; + } + + boolean added = false; + int i; + + for(i = 0; i < commands.size(); i++) + { + if(((Command)commands.elementAt(i)).getPriority() > c.getPriority()) + { + commands.insertElementAt(c, i); + added = true; + break; + } + } + + if(!added) + { + commands.addElement(c); + } + + iok = -1; + icancel = -1; + + if(extkey) + { + for(i = 0; i < commands.size(); i++) + { + c = (Command)commands.elementAt(i); + + if(iok < 0 && (c.getCommandType() == Command.OK || + c.getCommandType() == Command.ITEM)) + { + iok = i; + } + else if(icancel < 0 && (c.getCommandType() == Command.CANCEL || + c.getCommandType() == Command.BACK || + c.getCommandType() == Command.EXIT)) + { + icancel = i; + } + } + } + + lsktext = ((Command)commands.elementAt(0)).getLabel(); + + if(commands.size() == 2) + { + rsktext = ((Command)commands.elementAt(1)).getLabel(); + } + else if(commands.size() > 2) + { + rsktext = Locale.getString(this, Locale.OPTIONS_CMD); + + if(center) + { + mw = 0; + int sw; + + for(i = 1; i < commands.size(); i++) + { + sw = fwc.stringWidth(((Command)commands.elementAt(i)).getLabel()) + font.getHeight() / 3 * 2; + + if(sw > mw) + { + mw = sw; + } + } + + mx = (width - mw) / 2; + + mh = (commands.size() - 1) * mlh; + my = (height - mh) / 2; + } + else + { + mh = (commands.size() - 1) * mlh; + my = height - skh - mh + 1; + } + } + else + { + rsktext = ""; + } + + lskx = (w2 - fwc.stringWidth(lsktext)) / 2; + rskx = w2 + (w2 - fwc.stringWidth(rsktext)) / 2; + } + + public void removeCommand(Command c) + { + if(!commands.contains(c)) + { + return; + } + + commands.removeElement(c); + + iok = -1; + icancel = -1; + + if(extkey) + { + for(int i = 0; i < commands.size(); i++) + { + c = (Command)commands.elementAt(i); + + if(iok < 0 && (c.getCommandType() == Command.OK || + c.getCommandType() == Command.ITEM)) + { + iok = i; + } + else if(icancel < 0 && (c.getCommandType() == Command.CANCEL || + c.getCommandType() == Command.BACK || + c.getCommandType() == Command.EXIT)) + { + icancel = i; + } + } + } + + if(commands.size() > 0) + { + lsktext = ((Command)commands.elementAt(0)).getLabel(); + + if(commands.size() == 2) + { + rsktext = ((Command)commands.elementAt(1)).getLabel(); + } + else if(commands.size() > 2) + { + rsktext = Locale.getString(this, Locale.OPTIONS_CMD); + + if(center) + { + mw = 0; + int i, sw; + + for(i = 1; i < commands.size(); i++) + { + sw = fwc.stringWidth(((Command)commands.elementAt(i)).getLabel()) + font.getHeight() / 3 * 2; + + if(sw > mw) + { + mw = sw; + } + } + + mx = (width - mw) / 2; + + mh = (commands.size() - 1) * mlh; + my = (height - mh) / 2; + } + else + { + mh = (commands.size() - 1) * mlh; + my = height - skh - mh + 1; + } + } + else + { + rsktext = ""; + } + } + else + { + lsktext = ""; + rsktext = ""; + } + + lskx = (w2 - fwc.stringWidth(lsktext)) / 2; + rskx = w2 + (w2 - fwc.stringWidth(rsktext)) / 2; + } + + public void removeAllCommands() + { + commands.removeAllElements(); + + iok = -1; + icancel = -1; + + lsktext = ""; + rsktext = ""; + + lskx = (w2 - fwc.stringWidth(lsktext)) / 2; + rskx = w2 + (w2 - fwc.stringWidth(rsktext)) / 2; + } + + public int commandCount() + { + return commands.size(); + } + + public void setCommandListener(CommandListener cl) + { + listener = cl; + } + + public CommandListener getCommandListener() + { + return listener; + } + + public void commandAction(Command c, Displayable dp) + { + if(listener != null) + { + listener.commandAction(c, dp); + } + } + + public boolean keyPressed(int keyCode) + { + if(hotkey && hkmode) + { + hkmode = false; + + int index = keyCode - gkcCanvas.KEY_NUM0; + + if(index >= 0 && index < commands.size() && listener != null) + { + listener.commandAction((Command)commands.elementAt(index), caller); + } + else if(hklistener != null) + { + hklistener.hotKeyAction(keyCode); + } + + return true; + } + + if(extkey) + { + keyCode = gkcCanvas.translateKey(keyCode); + + if(keyCode == gkcCanvas.KEY_NUM1) + { + keyCode = gkcCanvas.KEY_LSK; + } + else if(keyCode == gkcCanvas.KEY_NUM3) + { + keyCode = gkcCanvas.KEY_RSK; + } + } + + if(inmenu) + { + if(keyCode == gkcCanvas.KEY_LSK || + keyCode == gkcCanvas.KEY_LEFT || + keyCode == gkcCanvas.KEY_CANCEL) + { + inmenu = false; + skvisible = false; + } + else if(keyCode == gkcCanvas.KEY_RSK || + keyCode == gkcCanvas.KEY_FIRE || + keyCode == gkcCanvas.KEY_RIGHT || + keyCode == gkcCanvas.KEY_DIAL) + { + inmenu = false; + skvisible = false; + + if(listener != null) + { + listener.commandAction((Command)commands.elementAt(msel + 1), caller); + } + } + else if(keyCode == gkcCanvas.KEY_UP) + { + if(--msel < 0) + { + msel = commands.size() - 2; + } + } + else if(keyCode == gkcCanvas.KEY_DOWN) + { + if(++msel > commands.size() - 2) + { + msel = 0; + } + } + else + { + return false; + } + + return true; + } + else + { + if(hotkey && keyCode == gkcCanvas.KEY_POUND) + { + hkmode = true; + return true; + } + + if(extkey) + { + if(keyCode == gkcCanvas.KEY_FIRE) + { + if(options.noEffects) + { + skvisible = false; + + if(iok >= 0 && listener != null) + { + listener.commandAction((Command)commands.elementAt(iok), caller); + } + + return hidesoft; + } + else + { + okp = true; + + if(iok == 0) + { + lskp = true; + skvisible = hidesoft; + } + else if(iok == 1 && commands.size() == 2) + { + rskp = true; + skvisible = hidesoft; + } + + return true; + } + } + else if(keyCode == gkcCanvas.KEY_CANCEL) + { + if(options.noEffects) + { + skvisible = false; + + if(icancel >= 0 && listener != null) + { + listener.commandAction((Command)commands.elementAt(icancel), caller); + } + + return hidesoft; + } + else + { + cancelp = true; + + if(icancel == 0) + { + lskp = true; + skvisible = hidesoft; + } + else if(icancel == 1 && commands.size() == 2) + { + rskp = true; + skvisible = hidesoft; + } + + return true; + } + } + } + + if(skvisible || !hidesoft) + { + if(keyCode == gkcCanvas.KEY_LSK) + { + if(options.noEffects) + { + skvisible = false; + + if(commands.size() > 0 && listener != null) + { + listener.commandAction((Command)commands.elementAt(0), caller); + } + + return hidesoft; + } + else + { + lskp = true; + } + } + else if(keyCode == gkcCanvas.KEY_RSK) + { + if(options.noEffects) + { + if(commands.size() > 2) + { + inmenu = true; + + if(msel < 0) + { + msel = 0; + } + else if(msel > commands.size() - 2) + { + msel = commands.size() - 2; + } + + return true; + } + else + { + skvisible = false; + + if(commands.size() == 2 && listener != null) + { + listener.commandAction((Command)commands.elementAt(1), caller); + } + + return hidesoft; + } + } + else + { + rskp = true; + } + } + else if(hidesoft) + { + skvisible = false; + } + else + { + return false; + } + + return true; + } + else + { + if(keyCode == gkcCanvas.KEY_LSK || + keyCode == gkcCanvas.KEY_RSK) + { + skvisible = true; + } + else + { + return false; + } + + return true; + } + } + } + + public boolean keyReleased(int keyCode) + { + if(inmenu) + { + return true; + } + + if(extkey) + { + keyCode = gkcCanvas.translateKey(keyCode); + + if(keyCode == gkcCanvas.KEY_NUM1) + { + keyCode = gkcCanvas.KEY_LSK; + } + else if(keyCode == gkcCanvas.KEY_NUM3) + { + keyCode = gkcCanvas.KEY_RSK; + } + + if(keyCode == gkcCanvas.KEY_FIRE) + { + if(okp) + { + okp = false; + + if(iok == 0) + { + lskp = false; + skvisible = false; + } + else if(iok == 1 && commands.size() == 2) + { + rskp = false; + skvisible = false; + } + + if(iok >= 0 && listener != null) + { + listener.commandAction((Command)commands.elementAt(iok), caller); + } + + return true; + } + } + else if(keyCode == gkcCanvas.KEY_CANCEL) + { + if(cancelp) + { + cancelp = false; + + if(icancel == 0) + { + lskp = false; + skvisible = false; + } + else if(icancel == 1 && commands.size() == 2) + { + rskp = false; + skvisible = false; + } + + if(icancel >= 0 && listener != null) + { + listener.commandAction((Command)commands.elementAt(icancel), caller); + } + + return true; + } + } + } + + if(skvisible || !hidesoft) + { + if(keyCode == gkcCanvas.KEY_LSK) + { + if(lskp) + { + lskp = false; + skvisible = false; + + if(commands.size() > 0 && listener != null) + { + listener.commandAction((Command)commands.elementAt(0), caller); + } + + return true; + } + } + else if(keyCode == gkcCanvas.KEY_RSK) + { + if(rskp) + { + rskp = false; + + if(commands.size() > 2) + { + inmenu = true; + + if(msel < 0) + { + msel = 0; + } + else if(msel > commands.size() - 2) + { + msel = commands.size() - 2; + } + } + else + { + skvisible = false; + + if(commands.size() == 2 && listener != null) + { + listener.commandAction((Command)commands.elementAt(1), caller); + } + } + + return true; + } + } + } + + return false; + } + + public void paint(Graphics g) + { + g.setFont(font); + + if(showdrap && (inmenu || skvisible)) + { + g.drawImage(drap, 0, 0, Graphics.LEFT | Graphics.TOP); + } + + if(skvisible || !hidesoft) + { + if(lskp) + { + //g.setColor(ColorScheme.colors[ColorScheme.selback1]); + //g.fillRect(0, h2, w2, skh); + images.drawHGradient(g, ColorScheme.colors[ColorScheme.skselback1], ColorScheme.colors[ColorScheme.skselback2], 0, h2, w2, skh, options.ditherGradients, options.alphaGradients); + g.setColor(ColorScheme.colors[ColorScheme.skselfore]); + } + else + { + //g.setColor(ColorScheme.colors[ColorScheme.back1]); + //g.fillRect(0, h2, w2, skh); + g.setColor(ColorScheme.colors[ColorScheme.skfore]); + } + + g.drawString(lsktext, lskx, sky, Graphics.LEFT | Graphics.TOP); + + if(rskp) + { + //g.setColor(ColorScheme.colors[ColorScheme.selback1]); + //g.fillRect(w2, h2, w2, skh); + images.drawHGradient(g, ColorScheme.colors[ColorScheme.skselback2], ColorScheme.colors[ColorScheme.skselback1], w2, h2, w2, skh, options.ditherGradients, options.alphaGradients); + g.setColor(ColorScheme.colors[ColorScheme.skselfore]); + } + else + { + //g.setColor(ColorScheme.colors[ColorScheme.back1]); + //g.fillRect(w2, h2, w2, skh); + g.setColor(ColorScheme.colors[ColorScheme.skfore]); + } + + g.drawString(rsktext, rskx, sky, Graphics.LEFT | Graphics.TOP); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawRect(0, h2, w2, skh - 1); + g.drawRect(w2, h2, w2 - 1, skh - 1); + } + + if(inmenu) + { + //g.setColor(ColorScheme.colors[ColorScheme.back1]); + //g.fillRect(mx, my, mw, mh); + + images.drawVGradient(g, ColorScheme.colors[ColorScheme.mnback1], ColorScheme.colors[ColorScheme.mnback2], mx, my, mw, mh, options.ditherGradients, options.alphaGradients); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawRect(mx, my, mw - 1, mh - 1); + + String s; + int x, y; + + for(int i = 0; i < commands.size() - 1; i++) + { + s = ((Command)commands.elementAt(i + 1)).getLabel(); + x = mx + (mw - fwc.stringWidth(s)) / 2; + y = my + i * mlh + (mlh - font.getHeight()) / 2; + + if(i == msel) + { + //g.setColor(ColorScheme.colors[ColorScheme.selback1]); + //g.fillRect(mx, my + i * mlh, mw, mlh); + + images.drawHGradient(g, ColorScheme.colors[ColorScheme.mnselback1], ColorScheme.colors[ColorScheme.mnselback2], mx, my + i * mlh, mw, mlh, options.ditherGradients, options.alphaGradients); + + g.setColor(ColorScheme.colors[ColorScheme.mnselfore]); + g.drawString(s, x, y, Graphics.LEFT | Graphics.TOP); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawRect(mx, my + i * mlh, mw - 1, mlh - 1); + } + else + { + g.setColor(ColorScheme.colors[ColorScheme.mnfore]); + g.drawString(s, x, y, Graphics.LEFT | Graphics.TOP); + } + } + } + } +} diff --git a/src/filemanager/CopyMoveThread.java b/src/filemanager/CopyMoveThread.java new file mode 100644 index 0000000..2526a99 --- /dev/null +++ b/src/filemanager/CopyMoveThread.java @@ -0,0 +1,189 @@ +package filemanager; + +import com.vmx.Locale; +import java.util.Enumeration; +import java.util.Vector; + +public class CopyMoveThread extends Operation +{ + public CopyMoveThread() + { + } + + public void run() + { + Enumeration files; + + if(callback != null) + { + files = Buffer.getBuffer(); + long size = 0; + + while(enabled && files.hasMoreElements()) + { + size += filesystem.getSize((String)files.nextElement(), true); + } + + callback.setMax((int)size); + } + + // папка, куда копируем/перемещаем + String targetPath = main.currentPath; + String targetFileFullName; + + // файл Ð´Ð»Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ð¸ + String sourceFileFullName; + String sourceOnlyName; + boolean mustMove; + boolean forAll = false, yes = false, fileExists = false; + Vector vector = new Vector(); + + files = Buffer.getBuffer(); + + while(enabled && files.hasMoreElements()) + { + sourceFileFullName = (String)files.nextElement(); + sourceOnlyName = sourceFileFullName.substring(noLastSlash(sourceFileFullName).lastIndexOf('/') + 1); + targetFileFullName = targetPath + sourceOnlyName; + + fileExists = filesystem.isFileExist(targetFileFullName); + mustMove = Buffer.isMoved(sourceFileFullName); // true, еÑли надо перемещать! + + if(fileExists) + { + // ЕÑли копируем файл в ту же папку, то проÑто даем копии новое имÑ, как Ñто делает винда. + // Иначе Ñпрашиваем, что делать. + + if(sourceFileFullName.equalsIgnoreCase(targetFileFullName)) + { + String name, ext; + + if(sourceOnlyName.endsWith("/")) + { + name = sourceOnlyName.substring(0, sourceOnlyName.length() - 1); + ext = "/"; + } + else + { + int index = sourceOnlyName.lastIndexOf('.'); + + if(index >= 0) + { + name = sourceOnlyName.substring(0, index); + ext = sourceOnlyName.substring(index); + } + else + { + name = sourceOnlyName; + ext = ""; + } + } + + targetFileFullName = targetPath + Locale.getString(this, Locale.FIRST_COPY_NAME, name) + ext; + fileExists = filesystem.isFileExist(targetFileFullName); + + if(fileExists) + { + int copynum = 2; + + do + { + targetFileFullName = targetPath + Locale.getString(this, Locale.NEXT_COPY_NAME, new String[] { name, Integer.toString(copynum++) }) + ext; + fileExists = filesystem.isFileExist(targetFileFullName); + } + while(fileExists); + } + + mustMove = false; + } + else if(!forAll) // файл ÑущеÑтвует и ещё не было команды "... Ð´Ð»Ñ Ð²Ñех!" + { + alConfirmOverwrite al = new alConfirmOverwrite(sourceOnlyName, main.FileSelect); + main.dsp.setCurrent(al); + al.t.start(); + + try + { + al.t.join(); // ждём, пока он СДОХÐЕТ :) + } + catch(InterruptedException x) + { + } + + yes = false; + + if(al.modalResult == al.cmdYes || al.modalResult == al.cmdYesForAll) + { + // еÑли да или да Ð´Ð»Ñ Ð²Ñех => yes! + yes = true; + } + + if(al.modalResult == al.cmdCancel) + { + // еÑли "отмена", значит Ñтоп. + break; + } + + if(al.modalResult == al.cmdYesForAll || al.modalResult == al.cmdNoForAll) + { + // команда Ð´Ð»Ñ Ð²Ñех + forAll = true; + } + + al = null; + Buffer.displayCurrentOperation(); + } + } + + if(!fileExists || yes) + { + if(!mustMove) // копирование + { + if(!filesystem.copyFile(sourceFileFullName, targetFileFullName, callback, vector)) + { + printErrors(vector, Locale.FILE_NOT_COPIED); + vector.removeAllElements(); + } + } + else // перемещение + { + if(!filesystem.copyFile(sourceFileFullName, targetFileFullName, callback, vector)) // Ñкопирован? + { + printErrors(vector, Locale.FILE_NOT_MOVED); + vector.removeAllElements(); + } + + if(filesystem.isReadOnly(sourceFileFullName)) // иÑточник readonly + { + errors.append(Locale.getString(this, Locale.SOURCE_FILE_READONLY_BE_COPIED, sourceOnlyName)); + } + else + { + filesystem.deleteFile(sourceFileFullName, true, callback); // удалÑем иÑходный файл + } + } + } + } + } + + protected void printErrors(Vector vector, int pattern) + { + for(int i = 0; i < vector.size(); i++) + { + errors.append(Locale.getString(this, pattern, (String[])vector.elementAt(i))); + } + } + + /** + * Обрезание поÑледнего ÑлÑша у s + */ + public static String noLastSlash(String s) + { + if(s.charAt(s.length() - 1) == '/') + { + return s.substring(0, s.length() - 1); + } + + return s; + } +} diff --git a/src/filemanager/CryptThread.java b/src/filemanager/CryptThread.java new file mode 100644 index 0000000..b0b8866 --- /dev/null +++ b/src/filemanager/CryptThread.java @@ -0,0 +1,107 @@ +package filemanager; + +import java.util.*; +import java.io.*; +import com.one.RTEF; +import com.one.file.*; + +/** + * Поток ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² + */ +public class CryptThread extends Operation +{ + protected RTEF rtef; + + public CryptThread(String password) + { + rtef = new RTEF(password); + Buffer.flattenBuffer(); + } + + /** + * ФункциÑ, оÑущеÑтвлÑÑŽÑ‰Ð°Ñ ÑобÑтвенно шифрование + */ + public void run() + { + FileConnection fc = null; + InputStream is = null; + OutputStream os = null; + + try + { + Enumeration files; + + if(callback != null) + { + files = Buffer.getBuffer(); + int max = 0; + + while(files.hasMoreElements()) + { + max += filesystem.getSize((String)files.nextElement(), true); + } + + callback.setMax(max); + callback.setProgress(0); + } + + files = Buffer.getBuffer(); + + int cp; + String fname; + + while(enabled && files.hasMoreElements()) + { + fname = (String)files.nextElement(); + + if(callback != null) + { + callback.setText(fname); // fname.substring(fname.lastIndexOf('/') + 1)); + } + + fc = (FileConnection)Connector.open("file:///" + fname); + is = fc.openInputStream(); + os = fc.openOutputStream(); + + cp = is.available(); + + rtef.crypt(is, os, callback); + + os.flush(); + os.close(); + is.close(); + fc.close(); + + os = null; + is = null; + fc = null; + System.gc(); + + if(callback != null) + { + callback.progress(cp); + } + } + } + catch(Exception ex) + { + logError(ex); + + if(fc != null) + { + try + { + fc.close(); + } + catch(Exception xx) + { + } + } + } + } + +// private static void out(String s) +// { +// System.out.println("[CryptThread] " + s); +// } +} diff --git a/src/filemanager/FileItem.java b/src/filemanager/FileItem.java new file mode 100644 index 0000000..25a6cac --- /dev/null +++ b/src/filemanager/FileItem.java @@ -0,0 +1,536 @@ +package filemanager; + +import com.one.IntStack; +import com.one.ModuleRegistry; +import javax.microedition.lcdui.Image; +import java.util.Vector; + +public class FileItem +{ + public static final int COMPARE_NAME = 1; + public static final int COMPARE_TYPE = 2; + public static final int COMPARE_LAST_MODIFIED = 3; + public static final int COMPARE_SIZE = 4; + + protected String path; + protected String name; + protected String fullname; + protected String dispname; + protected Image icon; + protected boolean readonly; + protected boolean hidden; + + protected String type; + protected long lastmod; + protected long size; + protected boolean lmexact; + protected boolean szexact; + + protected String fullnamelc; + protected String namelc; + protected String typelc; + + protected boolean dir; + protected boolean marked; + protected boolean exact; + protected boolean special; + + public FileItem(String fullname, boolean dispfullname) + { + this.fullname = fullname; + + int index = fullname.substring(0, fullname.length() - 1).lastIndexOf('/') + 1; + + path = fullname.substring(0, index); + name = fullname.substring(index); + + init(dispfullname); + } + + public FileItem(String path, String name, boolean dispfullname) + { + this.path = path; + this.name = name; + + fullname = path + name; + + init(dispfullname); + } + + protected void init(boolean dispfullname) + { + if(dispfullname) + { + dispname = fullname; + } + else + { + dispname = name; + } + + readonly = false; + hidden = false; + + int index = name.lastIndexOf('.'); + + if(index >= 0) + { + type = name.substring(index + 1); + } + else + { + type = ""; + } + + fullnamelc = fullname.toLowerCase(); + namelc = name.toLowerCase(); + typelc = type.toLowerCase(); + + lastmod = -1; + size = -1; + lmexact = false; + szexact = false; + + dir = false; + marked = false; + exact = false; + special = false; + } + + public FileItem(String name, Image icon) + { + this.name = name; + this.icon = icon; + + path = ""; + readonly = false; + hidden = false; + + type = ""; + + fullname = name; + dispname = name; + + namelc = name.toLowerCase(); + typelc = type.toLowerCase(); + + fullnamelc = namelc; + + lastmod = -1; + size = -1; + lmexact = false; + szexact = false; + + dir = true; + marked = false; + exact = true; + special = true; + } + + public String getPath() + { + return path; + } + + public String getName() + { + return name; + } + + public String getFullName() + { + return fullname; + } + + public String getDisplayName() + { + return dispname; + } + + public String getType() + { + return type; + } + + public Image getIcon() + { + if(!exact) + { + updateFileType(); + } + + return icon; + } + + public boolean isReadOnly() + { + if(!exact) + { + updateFileType(); + } + + return readonly; + } + + public boolean isHidden() + { + if(!exact) + { + updateFileType(); + } + + return hidden; + } + + public boolean isDirectory() + { + if(!exact) + { + updateFileType(); + } + + return dir; + } + + public long getLastModified() + { + if(!lmexact && !special) + { + lastmod = filesystem.lastModified(getFullName()); + lmexact = true; + } + + return lastmod; + } + + public long getSize() + { + if(!szexact && !special) + { + size = filesystem.getSize(getFullName(), true); + szexact = true; + } + + return size; + } + + public boolean isMarked() + { + return marked; + } + + public void setMarked(boolean marked) + { + if(special) + { + return; + } + + this.marked = marked; + } + + public boolean isSpecial() + { + return special; + } + + public void updateFileType() + { + if(special) + { + return; + } + + String file = fullname; + + if(options.checkFileAttrib) + { + readonly = filesystem.isReadOnly(file); + hidden = filesystem.isHidden(file); + } + + if(dir = filesystem.isDir(file)) + { + if(options.checkFileAttrib && filesystem.isHidden(file)) + { + icon = images.getIcon(images.iHiddenFolder); + } + else + { + icon = images.getIcon(images.iFolder); + } + } + else + { + icon = ModuleRegistry.getIcon(type); + + if(icon == null) + { + icon = images.getIcon(images.iFile); + } + } + + exact = true; + } + + public void invalidate() + { + exact = false; + } + + public String getFullNameLowerCase() + { + return fullnamelc; + } + + public String getNameLowerCase() + { + return namelc; + } + + public String getTypeLowerCase() + { + return typelc; + } + + public int compareTo(FileItem item, int param, boolean ignorecase, boolean order) + { + if(!exact) + { + updateFileType(); + } + + if(dir) + { + if(!item.isDirectory()) + { + return -1; + } + } + else + { + if(item.isDirectory()) + { + return 1; + } + } + + int res = 0; + + if(order) + { + if(param == COMPARE_NAME) + { + if(ignorecase) + { + return namelc.compareTo(item.getNameLowerCase()); + } + else + { + return name.compareTo(item.getName()); + } + } + else if(param == COMPARE_TYPE) + { + if(ignorecase) + { + res = typelc.compareTo(item.getTypeLowerCase()); + } + else + { + res = type.compareTo(item.getType()); + } + } + else if(param == COMPARE_LAST_MODIFIED) + { + res = (int)(getLastModified() - item.getLastModified()); + } + else if(param == COMPARE_SIZE) + { + res = (int)(getSize() - item.getSize()); + } + + if(res == 0) + { + if(ignorecase) + { + return namelc.compareTo(item.getNameLowerCase()); + } + else + { + return name.compareTo(item.getName()); + } + } + } + else + { + if(param == COMPARE_NAME) + { + if(ignorecase) + { + return item.getNameLowerCase().compareTo(namelc); + } + else + { + return item.getName().compareTo(name); + } + } + else if(param == COMPARE_TYPE) + { + if(ignorecase) + { + res = item.getTypeLowerCase().compareTo(typelc); + } + else + { + res = item.getType().compareTo(type); + } + } + else if(param == COMPARE_LAST_MODIFIED) + { + res = (int)(item.getLastModified() - getLastModified()); + } + else if(param == COMPARE_SIZE) + { + res = (int)(item.getSize() - getSize()); + } + + if(res == 0) + { + if(ignorecase) + { + return namelc.compareTo(item.getNameLowerCase()); + } + else + { + return name.compareTo(item.getName()); + } + } + } + + return res; + } + + protected static IntStack lbstack = new IntStack(); + protected static IntStack ubstack = new IntStack(); + + public static void sortFileList(Vector files, int param, boolean ignorecase, boolean order, int first, int last) + { + if(first == last || first < 0 || last < 0 || first >= files.size() || last >= files.size()) + { + return; + } + + int i, j; + int lb, ub; + + int ppos; + FileItem pivot; + Object temp; + + lbstack.clear(); + ubstack.clear(); + + lbstack.push(first); + ubstack.push(last); + + do + { + lb = lbstack.pop(); + ub = ubstack.pop(); + + do + { + ppos = (lb + ub) >>> 1; + + i = lb; + j = ub; + + pivot = (FileItem)files.elementAt(ppos); + + do + { + while(((FileItem)files.elementAt(i)).compareTo(pivot, param, ignorecase, order) < 0) i++; + while(((FileItem)files.elementAt(j)).compareTo(pivot, param, ignorecase, order) > 0) j--; + + if(i <= j) + { + temp = files.elementAt(i); + files.setElementAt(files.elementAt(j), i); + files.setElementAt(temp, j); + + i++; + j--; + } + } + while(i <= j); + + if(i < ppos) + { + if(i < ub) + { + lbstack.push(i); + ubstack.push(ub); + } + + ub = j; + } + else + { + if(j > lb) + { + lbstack.push(lb); + ubstack.push(j); + } + + lb = i; + } + } + while(lb < ub); + } + while(!lbstack.empty()); + } + + /* + public static void sortFileList(Vector files, int param, boolean ignorecase, boolean order, int first, int last) + { + if(first < 0 || last < 0 || first >= files.size() || last >= files.size()) + { + return; + } + + FileItem p = (FileItem)files.elementAt((last - first) / 2 + first); + + Object temp; + + int i = first; + int j = last; + + while(i <= j) + { + while(((FileItem)files.elementAt(i)).compareTo(p, param, ignorecase, order) < 0 && i++ < last); + while(((FileItem)files.elementAt(j)).compareTo(p, param, ignorecase, order) > 0 && j-- > first); + + if(i <= j) + { + temp = files.elementAt(i); + files.setElementAt(files.elementAt(j), i); + files.setElementAt(temp, j); + + i++; + j--; + } + } + + if(j > first) + { + sortFileList(files, param, ignorecase, order, first, j); + } + + if(i < last) + { + sortFileList(files, param, ignorecase, order, i, last); + } + } + */ +} diff --git a/src/filemanager/GraphicAlert.java b/src/filemanager/GraphicAlert.java new file mode 100644 index 0000000..2b605ae --- /dev/null +++ b/src/filemanager/GraphicAlert.java @@ -0,0 +1,476 @@ +package filemanager; + +import javax.microedition.lcdui.*; +import com.vmx.*; +import com.one.*; + +public class GraphicAlert extends gkcCanvas implements AutoAdvanceScreen, ProgressCallback +{ +// public static final int SMALL_SPACE = 2; +// public static final int MEDIUM_SPACE = 4; +// public static final int LARGE_SPACE = 7; + + protected static Display alertDisplay; + + protected int w, h; + protected int header, footer; + + protected CommandMenu cmenu; + + protected long maxval, value; + protected int pbx, pby, pbw, pbh, pbfill; + protected String percent; + protected int perx, pery; + protected boolean useindicator; + protected boolean percentmode; + protected boolean cancelflag; + + protected Image image; + protected String title; + protected int ttlx, ttly, ttlw; + protected int imgx, imgy; + + protected String text; + protected String[] message; + protected int[] msgx; + protected int msgy, msgheight; + protected int maxMsgWidth, maxMsgHeight; + protected int linesPerScreen; + + protected Font f; + protected FontWidthCache fwc; + protected int fh; + + protected boolean isShown; + protected long lastpaint; + + protected AlertType alertType; + protected int timeout; + + public static void setAlertDisplay(Display d) + { + alertDisplay = d; + } + + public GraphicAlert(String title) + { + this(title, null, null, null); + } + + public GraphicAlert(String title, String text, Image image, AlertType type) + { + isShown = false; + setFullScreenMode(true); + + w = getWidth(); + h = getHeight(); + + cmenu = new CommandMenu(getRenderer(), null, w, h, Font.SIZE_MEDIUM, false, true, true, false, false); + + f = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM); + fwc = FontWidthCache.getCache(f); + fh = f.getHeight(); + + header = fh * 3 / 2 + 1; + footer = cmenu.getSoftHeight() + 1; + + ttlx = fh / 2; + ttly = (header - fh - 1) / 2; + + pbx = ttlx; + pbw = w - pbx * 2 - 1; + pbh = fh * 3 / 2; + pby = h - cmenu.getSoftHeight() - pbh - fh; + + percentmode = true; + + pery = pby + (pbh - fh) / 2; + + maxMsgWidth = pbw; + + setMax(1); + setProgress(0); + + setTimeout(Alert.FOREVER); + setIndicator(false); + + setTitle(title); + setString(text); + setImage(image); + setType(type); + } + + public void addCommand(Command c) + { + cmenu.addCommand(c); + repaintAll(); + } + + public void removeCommand(Command c) + { + cmenu.removeCommand(c); + repaintAll(); + } + + public void setCommandListener(CommandListener cl) + { + cmenu.setCommandListener(cl); + } + + public void setTitle(String ttl) + { + if(ttl != null) + { + title = ttl; + } + else + { + title = ""; + } + + ttlw = fwc.stringWidth(title) + fh; + } + + public void setImage(Image img) + { + image = img; + + if(image != null) + { + imgx = w - image.getWidth() - ttlx / 2; + imgy = ttlx / 2; + } + } + + public void setIndicator(boolean useindicator) + { + this.useindicator = useindicator; + + if(useindicator) + { + maxMsgHeight = pby - header - fh * 2; + } + else + { + maxMsgHeight = h - footer - header - fh * 2; + } + + linesPerScreen = maxMsgHeight / fh; + + setString(text); + } + + public void setString(String str) + { + if(str != null) + { + text = str; + } + else + { + text = ""; + } + + message = fwc.splitString(text, maxMsgWidth); + msgheight = fh * message.length; + + msgx = new int[message.length]; + + for(int i = 0; i < message.length; i++) + { + msgx[i] = pbx + (maxMsgWidth - fwc.stringWidth(message[i])) / 2; + } + + msgy = (maxMsgHeight - msgheight) / 2; + + if(msgy < 0) + { + msgy = 0; + timeout = Alert.FOREVER; + } + + msgy += header + fh; + + repaintAll(); + } + + public void setTimeout(int time) + { + timeout = time; + } + + public void setType(AlertType type) + { + alertType = type; + } + + public void setMax(int max) + { + maxval = max; + + if(maxval < 1) + { + maxval = 1; + } + + updateProgress(); + } + + public void setProgress(int progress) + { + value = progress; + + if(value < 0) + { + value = 0; + } + else if(value > maxval) + { + value = maxval; + } + + updateProgress(); + } + + public void rise(int plus) + { + maxval += plus; + + if(maxval < 1) + { + maxval = 1; + } + + if(value > maxval) + { + value = maxval; + } + + updateProgress(); + } + + public void progress(int plus) + { + value += plus; + + if(value < 0) + { + value = 0; + } + else if(value > maxval) + { + value = maxval; + } + + updateProgress(); + } + + protected void updateProgress() + { + pbfill = (int)(pbw * value / maxval); + + if(percentmode) + { + percent = Integer.toString((int)(value * 100 / maxval)) + "%"; + } + else + { + percent = Long.toString(value) + " / " + Long.toString(maxval); + } + + perx = pbx + (pbw - fwc.stringWidth(percent)) / 2; + + if(useindicator) + { + repaintAll(); + } + } + + public void setText(String text) + { + setString(text); + } + + public int getMax() + { + return (int)maxval; + } + + public int getProgress() + { + return (int)value; + } + + public String getText() + { + return text; + } + + public void setPercentMode(boolean mode) + { + percentmode = mode; + } + + public void setCancelFlag(boolean flag) + { + cancelflag = flag; + } + + public boolean getCancelFlag() + { + return cancelflag; + } + + public void showNotify() + { + isShown = true; + + if(options.playAlertSounds && alertType != null && alertDisplay != null) + { + alertType.playSound(alertDisplay); + } + + main.startLightControl(true); + } + + public void hideNotify() + { + isShown = false; + main.startLightControl(false); + } + + protected void repaintAll() + { + repaint(); + + if(isShown && System.currentTimeMillis() - lastpaint > 100) + { + serviceRepaints(); + lastpaint = System.currentTimeMillis(); + } + } + + public void paint(Graphics g) + { + //g.setColor(ColorScheme.colors[ColorScheme.back1]); + //g.fillRect(0, 0, w, h); + + images.drawVGradient(g, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, w, h, options.ditherGradients, options.alphaGradients); + + g.setFont(f); + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.drawString(title, ttlx, ttly, Graphics.LEFT | Graphics.TOP); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawLine(0, header - 1, ttlw, header - 1); + + if(image != null) + { + g.drawImage(image, imgx, imgy, Graphics.LEFT | Graphics.TOP); + } + + g.setClip(pbx, header + fh, maxMsgWidth, maxMsgHeight); + g.setColor(ColorScheme.colors[ColorScheme.fore]); + + for(int i = 0; i < message.length; i++) + { + g.drawString(message[i], msgx[i], msgy + i * fh, Graphics.LEFT | Graphics.TOP); + } + + if(useindicator) + { + g.setClip(pbx, pby, pbfill, pbh); + images.drawHGradient(g, ColorScheme.colors[ColorScheme.selback1], ColorScheme.colors[ColorScheme.selback2], pbx, pby, pbw, pbh, options.ditherGradients, options.alphaGradients); + //g.setColor(ColorScheme.colors[ColorScheme.selback1]); + //g.fillRect(pbx, pby, pbfill, pbh); + + g.setColor(ColorScheme.colors[ColorScheme.selfore]); + g.drawString(percent, perx, pery, Graphics.LEFT | Graphics.TOP); + + g.setClip(pbx + pbfill, pby, pbw - pbfill, pbh); + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.drawString(percent, perx, pery, Graphics.LEFT | Graphics.TOP); + + g.setClip(pbx, pby, pbw, pbh); + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawRect(pbx, pby, pbw - 1, pbh - 1); + } + + g.setClip(0, 0, w, h); + cmenu.paint(g); + } + + public void keyPressed(int keyCode) + { + if(cmenu.keyPressed(keyCode)) + { + repaintAll(); + } + else + { + if(keyCode == KEY_UP) + { + if(msgheight > maxMsgHeight && msgy < header + 2) + { + msgy += fh; + } + } + else if(keyCode == KEY_DOWN) + { + if(msgheight > maxMsgHeight && msgy + msgheight > header + 2 + maxMsgHeight) + { + msgy -= fh; + } + } + else if(keyCode == KEY_LEFT) + { + if(msgheight > maxMsgHeight && msgy < header + 2) + { + msgy += fh * linesPerScreen; + } + } + else if(keyCode == KEY_RIGHT) + { + if(msgheight > maxMsgHeight && msgy + msgheight > header + 2 + maxMsgHeight) + { + msgy -= fh * linesPerScreen; + } + } + else + { + return; + } + + repaintAll(); + } + } + + public void keyReleased(int keyCode) + { + if(cmenu.keyReleased(keyCode)) + { + repaintAll(); + } + } + + public boolean finiteTimeout() + { + return timeout != Alert.FOREVER && cmenu.commandCount() < 2; + } + + public void run() + { + if(finiteTimeout()) + { + try + { + Thread.sleep(timeout); + cmenu.commandAction(Alert.DISMISS_COMMAND, getRenderer()); + } + catch(InterruptedException ie) + { + } + } + } +} diff --git a/src/filemanager/HotKeyListener.java b/src/filemanager/HotKeyListener.java new file mode 100644 index 0000000..ec1beb2 --- /dev/null +++ b/src/filemanager/HotKeyListener.java @@ -0,0 +1,6 @@ +package filemanager; + +public interface HotKeyListener +{ + public void hotKeyAction(int keyCode); +} diff --git a/src/filemanager/LineEffect.java b/src/filemanager/LineEffect.java new file mode 100644 index 0000000..9bf00e6 --- /dev/null +++ b/src/filemanager/LineEffect.java @@ -0,0 +1,250 @@ +package filemanager; + +import javax.microedition.lcdui.*; +import java.util.Random; + +public class LineEffect +{ + protected int x1, y1, x2, y2; + protected int[] lndata = new int[12]; + protected long delay; + + public LineEffect(int x, int y, int width, int height) + { + x1 = x; + y1 = y; + x2 = x + width - 1; + y2 = y + height - 1; + + delay = 8000 / Math.min(width, height); + + Random rnd = new Random(); + + lndata[0] = x + Math.abs(rnd.nextInt()) % width; + lndata[1] = y + Math.abs(rnd.nextInt()) % height; + lndata[2] = x + Math.abs(rnd.nextInt()) % width; + lndata[3] = y + Math.abs(rnd.nextInt()) % height; + + lndata[4] = rnd.nextInt() > 0 ? 1 : -1; + lndata[5] = rnd.nextInt() > 0 ? 1 : -1; + lndata[6] = rnd.nextInt() > 0 ? 1 : -1; + lndata[7] = rnd.nextInt() > 0 ? 1 : -1; + + lndata[8] = rnd.nextInt() > 0 ? 1 : -1; + lndata[9] = rnd.nextInt() > 0 ? 1 : -1; + lndata[10] = -lndata[8]; + lndata[11] = -lndata[9]; + } + + public void drawLines(Graphics g) + { + g.drawLine(lndata[0], y1, lndata[0], y2); + g.drawLine(x1, lndata[1], x2, lndata[1]); + g.drawLine(lndata[2], y1, lndata[2], y2); + g.drawLine(x1, lndata[3], x2, lndata[3]); + } + + public void moveLines() + { + if(lndata[8] == 0) + { + lndata[8] = 1; + } + else + { + lndata[0] += lndata[4]; + + if(lndata[8] == 1) + { + lndata[8] = 0; + } + } + + if(lndata[9] == 0) + { + lndata[9] = 1; + } + else + { + lndata[1] += lndata[5]; + + if(lndata[9] == 1) + { + lndata[9] = 0; + } + } + + if(lndata[10] == 0) + { + lndata[10] = 1; + } + else + { + lndata[2] += lndata[6]; + + if(lndata[10] == 1) + { + lndata[10] = 0; + } + } + + if(lndata[11] == 0) + { + lndata[11] = 1; + } + else + { + lndata[3] += lndata[7]; + + if(lndata[11] == 1) + { + lndata[11] = 0; + } + } + + if(lndata[0] < x1) + { + lndata[0] = x1; + lndata[4] = -lndata[4]; + } + else if(lndata[0] > x2) + { + lndata[0] = x2; + lndata[4] = -lndata[4]; + } + + if(lndata[1] < y1) + { + lndata[1] = y1; + lndata[5] = -lndata[5]; + } + else if(lndata[1] > y2) + { + lndata[1] = y2; + lndata[5] = -lndata[5]; + } + + if(lndata[2] < x1) + { + lndata[2] = x1; + lndata[6] = -lndata[6]; + } + else if(lndata[2] > x2) + { + lndata[2] = x2; + lndata[6] = -lndata[6]; + } + + if(lndata[3] < y1) + { + lndata[3] = y1; + lndata[7] = -lndata[7]; + } + else if(lndata[3] > y2) + { + lndata[3] = y2; + lndata[7] = -lndata[7]; + } + } + + public long getDelay() + { + return delay; + } + + public static void drawTextOutline(Graphics g, String text, int x, int y) + { + g.drawString(text, x, y - 1, Graphics.LEFT | Graphics.TOP); + g.drawString(text, x + 1, y - 1, Graphics.LEFT | Graphics.TOP); + g.drawString(text, x + 1, y, Graphics.LEFT | Graphics.TOP); + g.drawString(text, x + 1, y + 1, Graphics.LEFT | Graphics.TOP); + g.drawString(text, x, y + 1, Graphics.LEFT | Graphics.TOP); + g.drawString(text, x - 1, y + 1, Graphics.LEFT | Graphics.TOP); + g.drawString(text, x - 1, y, Graphics.LEFT | Graphics.TOP); + g.drawString(text, x - 1, y - 1, Graphics.LEFT | Graphics.TOP); + } + + public static void drawTextOutline(Graphics g, String text, int x, int y, int width) + { + int sx = x - width; + int ex = x + width; + + int sy = y - width; + int ey = y + width; + + for(x = sx; x <= ex; x++) + { + for(y = sy; y <= ey; y++) + { + g.drawString(text, x, y, Graphics.LEFT | Graphics.TOP); + } + } + } + + public static Image createDrap(int color, int width, int height) + { + try + { + int[] rgb = new int[width * height]; + + for(int i = 0; i < rgb.length; i++) + { + rgb[i] = color; + } + + return Image.createRGBImage(rgb, width, height, true); + } + catch(OutOfMemoryError oome) + { + return null; + } + } + + public static Image createCheckedField(int color1, int color2, int width, int height, int cell) + { + Image image = Image.createImage(width, height); + Graphics g = image.getGraphics(); + + g.setColor(color1); + g.fillRect(0, 0, width, height); + + g.setColor(color2); + + boolean flag = false; + int cell2 = cell * 2; + int x, y; + + for(x = 0; x < width; x += cell) + { + if(flag) + { + y = cell; + flag = false; + } + else + { + y = 0; + flag = true; + } + + for(; y < height; y += cell2) + { + g.fillRect(x, y, cell, cell); + } + } + + return image; + } + + public static void drawScaledRGB(Graphics g, int[] rgb, int x, int y, int width, int height, int scale) + { + for(int i = 0; i < width; i++) + { + for(int j = 0; j < height; j++) + { + g.setColor(rgb[i + j * width]); + g.fillRect(x + i * scale, y + j * scale, scale, scale); + } + } + } +} diff --git a/src/filemanager/ListMenu.java b/src/filemanager/ListMenu.java new file mode 100644 index 0000000..a23edd1 --- /dev/null +++ b/src/filemanager/ListMenu.java @@ -0,0 +1,910 @@ +package filemanager; + +import com.one.vector.AuxMath; +import javax.microedition.lcdui.*; +import java.util.Vector; +import java.util.Enumeration; +import com.vmx.*; + +public class ListMenu extends gkcCanvas implements Runnable, HotKeyListener +{ + public static final int CURSOR_MOVED = 0; + public static final int CURSOR_CHANGED = 1; + public static final int ELEMENT_ADDED = 2; + public static final int ELEMENT_DELETED = 3; + public static final int ELEMENT_CHANGED = 4; + + protected Font ttlfont, subttlfont, font; + protected FontWidthCache ttlfwc, subttlfwc, fwc; + protected int width, height; + + protected String title, subtitle; + protected int[] ttlpos = new int[8]; + protected int[] sttlpos = new int[8]; + protected int[] sbpos = new int[7]; + protected int header, footer, listpos; + + protected Vector elements; + protected IntVector elempos; + protected int scrstart, scrsel, scrlen; + protected int count; + protected int lineh; + + protected CommandMenu cmenu; + + protected ListStateListener statelistener; + + protected LineEffect lfx; + protected Thread t; + protected boolean isshown; + + protected int ofnw, ofnx, ofnstep, ofndelay; + protected int OFN_DEF_DELAY; + + protected Image background, cursor; + + public ListMenu() + { + setFullScreenMode(true); + + width = getWidth(); + height = getHeight(); + + elements = new Vector(); + elempos = new IntVector(); + count = 0; + + lfx = new LineEffect(1, 1, width - 2, height - 2); + + ttlfont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM); + subttlfont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM); + font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, options.largeFontInList ? Font.SIZE_MEDIUM : Font.SIZE_SMALL); + + ttlfwc = FontWidthCache.getCache(ttlfont); + subttlfwc = FontWidthCache.getCache(subttlfont); + fwc = FontWidthCache.getCache(font); + + ttlpos[0] = 0; + ttlpos[1] = 0; + ttlpos[2] = width; + ttlpos[3] = ttlfont.getHeight() + ttlfont.getHeight() / 4; + ttlpos[4] = subttlfont.getHeight() / 2; + ttlpos[5] = ttlpos[1] + (ttlpos[3] - ttlfont.getHeight()) / 2; + ttlpos[6] = ttlpos[2] - ttlfont.getHeight(); + ttlpos[7] = ttlfont.getHeight(); + + sttlpos[0] = 0; + sttlpos[1] = ttlpos[1] + ttlpos[3] - 1; + sttlpos[2] = width; + sttlpos[3] = subttlfont.getHeight() + subttlfont.getHeight() / 4; + sttlpos[4] = subttlfont.getHeight() / 2; + sttlpos[5] = sttlpos[1] + (sttlpos[3] - subttlfont.getHeight()) / 2; + sttlpos[6] = sttlpos[2] - subttlfont.getHeight(); + sttlpos[7] = subttlfont.getHeight(); + + cmenu = new CommandMenu(getRenderer(), this, width, height, options.largeFontInMenu ? Font.SIZE_MEDIUM : Font.SIZE_SMALL, false, true, true, false, false); + + sbpos[2] = width; + sbpos[3] = 7; + sbpos[0] = 0; + sbpos[1] = height - cmenu.getSoftHeight() - sbpos[3] + 1; + sbpos[4] = sbpos[1] + 3; + sbpos[5] = 0; + sbpos[6] = width; + + header = sttlpos[1] + sttlpos[3]; + footer = cmenu.getSoftHeight() + sbpos[3] - 1; + + lineh = font.getHeight() + 2; + scrlen = (height - header - footer) / lineh; + listpos = header + (height - header - footer - lineh * scrlen) / 2; + + scrstart = 0; + scrsel = 0; + + setTitle(null); + setSubTitle(null, false); + } + +// public void updateGradients() +// { +// Graphics g; +// +// if(options.ditherGradients) +// { +// if(!options.alphaGradients || (images.isColorOpaque(ColorScheme.colors[ColorScheme.back1]) && images.isColorOpaque(ColorScheme.colors[ColorScheme.back2]))) +// { +// background = Image.createImage(width, height); +// g = background.getGraphics(); +// images.drawVGradient(g, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, width, height, true, false); +// } +// else +// { +// background = null; +// } +// +// if(!options.alphaGradients || (images.isColorOpaque(ColorScheme.colors[ColorScheme.selback1]) && images.isColorOpaque(ColorScheme.colors[ColorScheme.selback2]))) +// { +// cursor = Image.createImage(width, lineh); +// g = cursor.getGraphics(); +// images.drawHGradient(g, ColorScheme.colors[ColorScheme.selback1], ColorScheme.colors[ColorScheme.selback2], 0, 0, width, lineh, true, false); +// } +// else +// { +// cursor = null; +// } +// } +// else +// { +// background = null; +// cursor = null; +// } +// } + + public void addCommand(Command c) + { + cmenu.addCommand(c); + } + + public void removeCommand(Command c) + { + cmenu.removeCommand(c); + } + + public void removeAllCommands() + { + cmenu.removeAllCommands(); + } + + public void setCommandListener(CommandListener cl) + { + cmenu.setCommandListener(cl); + } + + public void setStateListener(ListStateListener lsl) + { + statelistener = lsl; + } + + public void setTitle(String ttl) + { + if(ttl == null) + { + ttl = ""; + } + + int ttlw = ttlfwc.stringWidth(ttl); + + if(ttlw <= ttlpos[6]) + { + title = ttl; + } + else + { + int i = ttl.length(); + + do + { + title = ttl.substring(0, --i).trim() + "..."; + ttlw = ttlfwc.stringWidth(title); + } + while(ttlw > ttlpos[6]); + } + + repaintAll(); + } + + public void setSubTitle(String sttl, boolean mode) + { + if(sttl == null) + { + sttl = ""; + } + + int sttlw = subttlfwc.stringWidth(sttl); + + if(sttlw <= sttlpos[6]) + { + subtitle = sttl; + } + else + { + if(mode) + { + int i = 0; + + do + { + subtitle = "..." + sttl.substring(++i).trim(); + sttlw = subttlfwc.stringWidth(subtitle); + } + while(sttlw > sttlpos[6]); + } + else + { + int i = sttl.length(); + + do + { + subtitle = sttl.substring(0, --i).trim() + "..."; + sttlw = subttlfwc.stringWidth(subtitle); + } + while(sttlw > sttlpos[6]); + } + } + + repaintAll(); + } + + protected int getElementPosition(String text) + { + int pos = (width - fwc.stringWidth(text)) / 2; + + if(pos >= 1) + { + return pos; + } + else + { + return 1; + } + } + + public void setString(String text, int index) + { + elements.setElementAt(text, index); + elempos.set(index, getElementPosition(text)); + + if(index == scrsel) + { + updateScroll(); + } + + if(statelistener != null) + { + statelistener.listStateChanged(this, ELEMENT_CHANGED); + } + + repaintAll(); + } + + public void append(String element) + { + elements.addElement(element); + elempos.add(getElementPosition(element)); + count = elements.size(); + + sbpos[5] = width * scrstart / count; + sbpos[6] = width * scrlen / count; + + if(count == 1) + { + updateScroll(); + } + + if(statelistener != null) + { + statelistener.listStateChanged(this, ELEMENT_ADDED); + } + + repaintAll(); + } + + public void append(Enumeration enumeration) + { + if(enumeration == null) + { + return; + } + + String s; + + while(enumeration.hasMoreElements()) + { + s = (String)enumeration.nextElement(); + + elements.addElement(s); + elempos.add(getElementPosition(s)); + } + + count = elements.size(); + + if(count > 0) + { + sbpos[5] = width * scrstart / count; + sbpos[6] = width * scrlen / count; + } + else + { + sbpos[5] = 0; + sbpos[6] = width; + } + + if(count == 1) + { + updateScroll(); + } + + if(statelistener != null) + { + statelistener.listStateChanged(this, ELEMENT_ADDED); + } + + repaintAll(); + } + + public void delete(int index) + { + elements.removeElementAt(index); + elempos.remove(index, 1); + + count = elements.size(); + + if(scrstart > count - 1) + { + scrstart = count - 1; + + if(scrstart < 0) + { + scrstart = 0; + } + } + + if(scrsel >= count) + { + scrsel = count - 1; + } + + if(count > 0) + { + sbpos[5] = width * scrstart / count; + sbpos[6] = width * scrlen / count; + } + else + { + sbpos[5] = 0; + sbpos[6] = width; + } + + updateScroll(); + + if(statelistener != null) + { + statelistener.listStateChanged(this, ELEMENT_DELETED); + } + + repaintAll(); + } + + public void deleteAll() + { + elements.removeAllElements(); + elempos.remove(0, elempos.size()); + + count = 0; + scrstart = 0; + scrsel = 0; + + sbpos[5] = 0; + sbpos[6] = width; + + updateScroll(); + + if(statelistener != null) + { + statelistener.listStateChanged(this, ELEMENT_DELETED); + } + + repaintAll(); + } + + public String getString(int index) + { + return (String)elements.elementAt(index); + } + + public int getSelectedIndex() + { + return scrsel; + } + + public void setSelectedIndex(int index) + { + if(index >= 0 && index < count) + { + scrsel = index; + + if(scrsel >= scrstart + scrlen) + { + do + { + scrstart++; + } + while(scrsel >= scrstart + scrlen); + } + else if(scrsel < scrstart) + { + do + { + scrstart--; + } + while(scrsel < scrstart); + } + + if(count > 0) + { + sbpos[5] = width * scrstart / count; + sbpos[6] = width * scrlen / count; + } + else + { + sbpos[5] = 0; + sbpos[6] = width; + } + + updateScroll(); + + if(statelistener != null) + { + statelistener.listStateChanged(this, CURSOR_CHANGED); + } + + repaintAll(); + } + } + + public void select(String text) + { + int index = -1; + + for(int i = 0; i < count; i++) + { + if(((String)elements.elementAt(i)).equals(text)) + { + index = i; + break; + } + } + + if(index >= 0) + { + setSelectedIndex(index); + } + } + + protected void updateScroll() + { + ofnx = 1; + ofndelay = OFN_DEF_DELAY; + + if(elements.size() > 0) + { + ofnw = fwc.stringWidth((String)elements.elementAt(scrsel)); + } + else + { + ofnw = 0; + } + + if(ofnw > width - 2) + { + ofnstep = -1; + } + else + { + ofnstep = 0; + } + } + + public int size() + { + return count; + } + + public void showNotify() + { + if(t != null && t.isAlive()) + { + try + { + t.join(); + } + catch(Exception e) + { + } + } + + isshown = true; + + //updateGradients(); + + if(options.longScrollSpeed > 0) + { + (t = new Thread(this, "ListMenu/Animation")).start(); + } + } + + public void hideNotify() + { + isshown = false; + } + + public void directKeyPressed(int keyCode) + { + } + + public void hotKeyAction(int keyCode) + { + } + + public void keyPressed(int keyCode) + { + if(cmenu.keyPressed(keyCode)) + { + repaintAll(); + return; + } + + if(count == 0) + { + return; + } + + keyCode = translateKey(keyCode); + + if(keyCode == KEY_DOWN) + { + scrsel++; + + if(scrsel >= count) + { + scrsel = 0; + scrstart = 0; + } + else if(scrsel >= scrstart + scrlen) + { + scrstart++; + } + } + else if(keyCode == KEY_UP) + { + scrsel--; + + if(scrsel < 0) + { + scrsel = count - 1; + scrstart = count - scrlen; + + if(scrstart < 0) + { + scrstart = 0; + } + } + else if(scrsel < scrstart) + { + scrstart--; + } + } + else if(keyCode == KEY_RIGHT) + { + if(scrsel == count - 1) + { + scrsel = 0; + scrstart = 0; + } + else + { + scrsel += scrlen; + + if(scrsel > count - 1) + { + scrsel = count - 1; + } + + while(scrsel >= scrstart + scrlen) + { + scrstart++; + } + } + } + else if(keyCode == KEY_LEFT) + { + if(scrsel == 0) + { + scrsel = count - 1; + scrstart = count - scrlen; + + if(scrstart < 0) + { + scrstart = 0; + } + } + else + { + scrsel -= scrlen; + + if(scrsel < 0) + { + scrsel = 0; + } + + while(scrsel < scrstart) + { + scrstart--; + } + } + } + else + { + return; + } + + if(count > 0) + { + sbpos[5] = width * scrstart / count; + sbpos[6] = width * scrlen / count; + } + else + { + sbpos[5] = 0; + sbpos[6] = width; + } + + updateScroll(); + + if(statelistener != null) + { + statelistener.listStateChanged(this, CURSOR_MOVED); + } + + repaintAll(); + } + + public void keyReleased(int keyCode) + { + if(cmenu.keyReleased(keyCode)) + { + repaintAll(); + } + } + + public void repaintAll() + { + if(isshown && options.longScrollSpeed <= 0) + { + repaint(); + } + } + + public void paint(Graphics g) + { + g.setClip(0, 0, width, height); + + //g.setColor(ColorScheme.colors[ColorScheme.back1]); + //g.fillRect(0, 0, width, height); + + if(background != null) + { + g.drawImage(background, 0, 0, Graphics.LEFT | Graphics.TOP); + } + else + { + images.drawVGradient(g, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, width, height, options.ditherGradients, options.alphaGradients); + } + + if(!options.noEffects && options.longScrollSpeed > 0) + { + g.setClip(0, header, width, height - header - footer); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + lfx.drawLines(g); + + g.setClip(0, 0, width, height); + } + + //----------------------------------------------------------------------------------------- + + //g.setColor(ColorScheme.colors[ColorScheme.back1]); + //g.fillRect(ttlpos[0], ttlpos[1], ttlpos[2], ttlpos[3]); + + g.setFont(ttlfont); + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.drawString(title, ttlpos[4], ttlpos[5], Graphics.LEFT | Graphics.TOP); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawRect(ttlpos[0], ttlpos[1], ttlpos[2] - 1, ttlpos[3] - 1); + + //----------------------------------------------------------------------------------------- + + //g.setColor(ColorScheme.colors[ColorScheme.back1]); + //g.fillRect(sttlpos[0], sttlpos[1], sttlpos[2], sttlpos[3]); + + g.setFont(subttlfont); + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.drawString(subtitle, sttlpos[4], sttlpos[5], Graphics.LEFT | Graphics.TOP); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawRect(sttlpos[0], sttlpos[1], sttlpos[2] - 1, sttlpos[3] - 1); + + //----------------------------------------------------------------------------------------- + + //g.setColor(ColorScheme.colors[ColorScheme.back1]); + //g.fillRect(sbpos[0], sbpos[1], sbpos[2], sbpos[3]); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawLine(sbpos[0], sbpos[4], sbpos[0] + sbpos[2], sbpos[4]); + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.drawLine(sbpos[5], sbpos[4], sbpos[5] + sbpos[6], sbpos[4]); + g.drawLine(sbpos[5] + 1, sbpos[4] - 1, sbpos[5] + sbpos[6] - 1, sbpos[4] - 1); + g.drawLine(sbpos[5] + 1, sbpos[4] + 1, sbpos[5] + sbpos[6] - 1, sbpos[4] + 1); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawRect(sbpos[0], sbpos[1], sbpos[2] - 1, sbpos[3] - 1); + + //----------------------------------------------------------------------------------------- + + g.setFont(font); + + String s; + int x, y; + int i, p; + + g.setClip(1, 0, width - 1, height); + + for(i = scrstart, p = 0; i < count && i < scrstart + scrlen; i++, p++) + { + s = (String)elements.elementAt(i); + x = elempos.get(i); + y = listpos + p * lineh; + + if(i == scrsel) + { + if(ofnstep != 0) + { + x = ofnx; + } + + g.setClip(0, 0, width, height); + + //g.setColor(ColorScheme.colors[ColorScheme.selback1]); + //g.fillRect(0, y - 1, width, lineh); + + if(cursor != null) + { + g.drawImage(cursor, 0, y - 1, Graphics.LEFT | Graphics.TOP); + } + else + { + images.drawHGradient(g, ColorScheme.colors[ColorScheme.selback1], ColorScheme.colors[ColorScheme.selback2], 0, y - 1, width, lineh, options.ditherGradients, false); + } + + g.setColor(ColorScheme.colors[ColorScheme.selfore]); + g.drawString(s, x, y, Graphics.LEFT | Graphics.TOP); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawRect(0, y - 1, width - 1, lineh - 1); + + g.setClip(1, 0, width - 1, height); + } + else + { + if(!options.noEffects && (ColorScheme.colors[ColorScheme.back1] & 0xFFFFFF) == (ColorScheme.colors[ColorScheme.back2] & 0xFFFFFF)) + { + g.setColor(ColorScheme.colors[ColorScheme.back1]); + LineEffect.drawTextOutline(g, s, x, y); + } + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.drawString(s, x, y, Graphics.LEFT | Graphics.TOP); + } + } + + //----------------------------------------------------------------------------------------- + + cmenu.paint(g); + } + + public void run() + { + try + { + long lfxsleep = lfx.getDelay(); + + long ofnsleep = (int)(8000f / options.longScrollSpeed / Math.min(width, height)); + OFN_DEF_DELAY = (int)(600 / ofnsleep); + + if(options.noEffects) + { + lfxsleep = ofnsleep; + } + + long target = AuxMath.gcd((int)lfxsleep, (int)ofnsleep); + long sleep; + + if(target < AuxClass.MIN_THREAD_SLEEP) + { + target = AuxClass.MIN_THREAD_SLEEP; + } + + long current; + long ofnprev = System.currentTimeMillis(); + long lfxprev = System.currentTimeMillis(); + + boolean flag = false; + + while(isshown) + { + current = System.currentTimeMillis(); + + while(current - ofnprev >= ofnsleep) + { + ofnprev += ofnsleep; + + if(ofnstep != 0) + { + if(ofndelay > 0) + { + ofndelay--; + } + else + { + ofnx += ofnstep; + } + + if(ofnstep > 0) + { + if(ofnx > 1) + { + ofnx = 1; + ofnstep = -ofnstep; + ofndelay = OFN_DEF_DELAY; + } + } + else + { + if(ofnx < width - 1 - ofnw) + { + ofnx = width - 1 - ofnw; + ofnstep = -ofnstep; + ofndelay = OFN_DEF_DELAY; + } + } + + flag = true; + } + } + + while(current - lfxprev >= lfxsleep) + { + lfxprev += lfxsleep; + lfx.moveLines(); + + flag = true; + } + + if(flag) + { + repaint(); + //serviceRepaints(); + + flag = false; + } + + sleep = target - (current - Math.min(ofnprev, lfxprev)); + + if(sleep > 0) + { + Thread.sleep(sleep); + } + } + } + catch(InterruptedException ie) + { + } + + t = null; + } +} diff --git a/src/filemanager/ListStateListener.java b/src/filemanager/ListStateListener.java new file mode 100644 index 0000000..ea7e2bb --- /dev/null +++ b/src/filemanager/ListStateListener.java @@ -0,0 +1,6 @@ +package filemanager; + +public interface ListStateListener +{ + public void listStateChanged(ListMenu list, int action); +} diff --git a/src/filemanager/MemoryMonitor.java b/src/filemanager/MemoryMonitor.java new file mode 100644 index 0000000..afd182c --- /dev/null +++ b/src/filemanager/MemoryMonitor.java @@ -0,0 +1,356 @@ +package filemanager; + +import com.one.ErrScreen; +import com.one.PaintableObject; +import com.one.Renderer; +import com.one.file.TransparentConnector; +import javax.microedition.lcdui.*; +import com.vmx.*; +import java.io.IOException; + +public class MemoryMonitor extends gkcCanvas implements Runnable, CommandListener, HotKeyListener +{ + protected Object parent; + + protected Font ttlfont, font; + protected FontWidthCache fwc; + protected int ttlfnth, fnth; + + protected int ttlx, ttly, ttlw, ttlh; + + protected Image histogram; + protected Graphics hgraphics; + protected int hx, hy, hw, hh; + protected long[] usedvalues; + protected long[] totalvalues; + protected long maxvalue; + + protected String usedmem; + protected int[] umpos = new int[8]; + + protected String totalmem; + protected int[] tmpos = new int[8]; + + protected int width, height; + protected long delay; + protected int threshold; + protected boolean isshown; + protected long used, total; + protected boolean offscreen; + + protected CommandMenu cmenu; + + protected Thread t; + + protected Command cmdUpdate, cmdClear, cmdFill, cmdBack; + + public MemoryMonitor() + { + setFullScreenMode(true); + + width = getWidth(); + height = getHeight(); + + ttlfont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM); + font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, options.largeFontInMenu ? Font.SIZE_MEDIUM : Font.SIZE_SMALL); + fwc = FontWidthCache.getCache(font); + + ttlfnth = ttlfont.getHeight(); + fnth = font.getHeight(); + + ttlw = ttlfont.stringWidth(Locale.getString(this, Locale.MEMORY_MONITOR)) + ttlfnth; + ttlh = ttlfnth * 3 / 2; + ttlx = ttlfnth / 2; + ttly = (ttlh - ttlfnth) / 2; + + cmenu = new CommandMenu(getRenderer(), this, width, height, options.largeFontInMenu ? Font.SIZE_MEDIUM : Font.SIZE_SMALL, true, true, true, false, false); + + hw = width - ttlfnth; + hh = height - ttlh - cmenu.getSoftHeight() - ttlfnth * 2 - fnth * 3; + hx = (width - hw) / 2; + hy = ttlh + ttlfnth; + + histogram = Image.createImage(hw, hh); + hgraphics = histogram.getGraphics(); + hgraphics.setColor(ColorScheme.colors[ColorScheme.back1]); + hgraphics.fillRect(0, 0, hw, hh); + + usedvalues = new long[hw]; + totalvalues = new long[hw]; + + usedmem = AuxClass.formatNumber(0); + totalmem = AuxClass.formatNumber(0); + + umpos[0] = hx; + umpos[1] = hy + hh - 1; + umpos[2] = hw; + umpos[3] = fnth * 3 / 2; + umpos[4] = umpos[0] + fnth / 2; + umpos[5] = umpos[1] + (umpos[3] - fnth) / 2; + umpos[7] = umpos[5]; + + tmpos[0] = umpos[0]; + tmpos[1] = umpos[1] + umpos[3] - 1; + tmpos[2] = umpos[2]; + tmpos[3] = umpos[3]; + tmpos[4] = umpos[4]; + tmpos[5] = tmpos[1] + (tmpos[3] - fnth) / 2; + tmpos[7] = tmpos[5]; + + cmdUpdate = new Command(Locale.getString(this, Locale.UPDATE_CMD), Command.ITEM, 1); + cmdClear = new Command(Locale.getString(this, Locale.CLEAR_CMD), Command.OK, 2); + cmdFill = new Command(Locale.getString(this, Locale.FILL_CMD), Command.OK, 3); + cmdBack = new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 5); + + addCommand(cmdUpdate); + addCommand(cmdClear); + addCommand(cmdFill); + addCommand(cmdBack); + setCommandListener(this); + } + + public void update() + { + total = Runtime.getRuntime().totalMemory(); + used = total - Runtime.getRuntime().freeMemory(); + + if(used > total * threshold / 100) + { + System.gc(); + + total = Runtime.getRuntime().totalMemory(); + used = total - Runtime.getRuntime().freeMemory(); + } + + if(isshown || offscreen) + { + maxvalue = 1; + + for(int i = 1; i < hw; i++) + { + usedvalues[i - 1] = usedvalues[i]; + totalvalues[i - 1] = totalvalues[i]; + + if(usedvalues[i] > maxvalue) + { + maxvalue = usedvalues[i]; + } + + if(totalvalues[i] > maxvalue) + { + maxvalue = totalvalues[i]; + } + } + + usedvalues[hw - 1] = used; + totalvalues[hw - 1] = total; + + if(used > maxvalue) + { + maxvalue = used; + } + + if(total > maxvalue) + { + maxvalue = total; + } + + if(isshown) + { + usedmem = AuxClass.formatNumber(used); + totalmem = AuxClass.formatNumber(total); + + umpos[6] = umpos[0] + umpos[2] - fnth / 2 - fwc.stringWidth(usedmem); + tmpos[6] = tmpos[0] + tmpos[2] - fnth / 2 - fwc.stringWidth(totalmem); + + repaint(); + } + } + } + + protected void drawHistogram(Graphics g, boolean clear) + { + if(clear) + { + g.setColor(ColorScheme.colors[ColorScheme.back1]); + g.fillRect(0, 0, hw, hh); + } + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + + for(int i = 1; i < hw; i++) + { + g.drawLine(i - 1, hh - (int)(usedvalues[i - 1] * (hh - 1) / maxvalue) - 1, i, hh - (int)(usedvalues[i] * (hh - 1) / maxvalue) - 1); + } + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawRect(0, 0, hw - 1, hh - 1); + } + + public void paint(Graphics g) + { + //g.setColor(ColorScheme.colors[ColorScheme.back1]); + //g.fillRect(0, 0, width, height); + + images.drawVGradient(g, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, width, height, options.ditherGradients, false); + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.setFont(ttlfont); + g.drawString(Locale.getString(this, Locale.MEMORY_MONITOR), ttlx, ttly, Graphics.LEFT | Graphics.TOP); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawLine(0, ttlh, ttlw, ttlh); + + //g.drawImage(histogram, hx, hy, Graphics.LEFT | Graphics.TOP); + g.translate(hx, hy); + drawHistogram(g, false); + g.translate(-hx, -hy); + g.drawRect(hx, hy, hw - 1, hh - 1); + + g.drawRect(umpos[0], umpos[1], umpos[2] - 1, umpos[3] - 1); + g.drawRect(tmpos[0], tmpos[1], tmpos[2] - 1, tmpos[3] - 1); + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.setFont(font); + + g.drawString(Locale.getString(this, Locale.USED_MEMORY), umpos[4], umpos[5], Graphics.LEFT | Graphics.TOP); + g.drawString(Locale.getString(this, Locale.TOTAL_MEMORY), tmpos[4], tmpos[5], Graphics.LEFT | Graphics.TOP); + + g.drawString(usedmem, umpos[6], umpos[7], Graphics.LEFT | Graphics.TOP); + g.drawString(totalmem, tmpos[6], tmpos[7], Graphics.LEFT | Graphics.TOP); + + cmenu.paint(g); + } + + public void setDelay(long delay) + { + this.delay = delay; + + if(t != null && t.isAlive()) + { + t.interrupt(); + } + + if(delay > 0) + { + (t = new Thread(this, "MemoryMonitor/Update")).start(); + } + } + + public void setThreshold(int percent) + { + if(percent < 0) + { + threshold = 0; + } + else if(percent <= 100) + { + threshold = percent; + } + else + { + threshold = 100; + } + } + + public void setOffscreenUpdate(boolean flag) + { + offscreen = flag; + } + + public void show(Object parent) + { + this.parent = parent; + main.dsp.setCurrent(this); + } + + public void showNotify() + { + isshown = true; + update(); + } + + public void hideNotify() + { + isshown = false; + } + + public void run() + { + try + { + while(true) + { + update(); + Thread.sleep(delay); + } + } + catch(InterruptedException ie) + { + } + } + + public void commandAction(Command c, Displayable dp) + { + if(c == cmdUpdate) + { + update(); + } + else if(c == cmdClear) + { + System.gc(); + } + else if(c == cmdFill) + { + AuxClass.allocateMemory(-1, -1); + } + else if(c == cmdBack) + { + main.dsp.setCurrent(parent); + } + } + + public void addCommand(Command c) + { + cmenu.addCommand(c); + } + + public void removeCommand(Command c) + { + cmenu.removeCommand(c); + } + + public void removeAllCommands() + { + cmenu.removeAllCommands(); + } + + public void setCommandListener(CommandListener cl) + { + cmenu.setCommandListener(cl); + } + + public void hotKeyAction(int keyCode) + { + if(keyCode == KEY_STAR) + { + main.dsp.setCurrent(parent); + } + } + + public void keyPressed(int keyCode) + { + if(cmenu.keyPressed(keyCode)) + { + repaint(); + } + } + + public void keyReleased(int keyCode) + { + if(cmenu.keyReleased(keyCode)) + { + repaint(); + } + } +} \ No newline at end of file diff --git a/src/filemanager/MenuListener.java b/src/filemanager/MenuListener.java new file mode 100644 index 0000000..782f7ee --- /dev/null +++ b/src/filemanager/MenuListener.java @@ -0,0 +1,9 @@ +package filemanager; + +public interface MenuListener +{ + /** + * Выполнить дейÑтвие Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ Locale.getString(this, code) + */ + public void menuAction(int code); +} diff --git a/src/filemanager/Operation.java b/src/filemanager/Operation.java new file mode 100644 index 0000000..8cba1d7 --- /dev/null +++ b/src/filemanager/Operation.java @@ -0,0 +1,47 @@ +package filemanager; + +import com.vmx.ProgressCallback; + +public abstract class Operation implements Runnable +{ + protected ProgressCallback callback; + protected StringBuffer errors; + protected boolean enabled; + protected boolean clear; + + public Operation() + { + errors = new StringBuffer(); + enabled = true; + clear = true; + } + + public void stop() + { + enabled = false; + callback.setCancelFlag(true); + } + + public void setProgressCallback(ProgressCallback callback) + { + this.callback = callback; + callback.setCancelFlag(false); + } + + public String getErrors() + { + return errors.toString(); + } + + protected void logError(Throwable t) + { + errors.append(t); + errors.append('\n'); + errors.append('\n'); + } + + public boolean getClearFlag() + { + return clear; + } +} diff --git a/src/filemanager/Palette.java b/src/filemanager/Palette.java new file mode 100644 index 0000000..a09d1b7 --- /dev/null +++ b/src/filemanager/Palette.java @@ -0,0 +1,283 @@ +package filemanager; + +import javax.microedition.lcdui.*; +import java.io.IOException; +import com.one.gif.GIFFile; +import com.one.*; +import com.vmx.*; + +public class Palette extends gkcCanvas +{ + public static int[] UNIFIED_PALETTE = new int[256]; + + public static int PALETTE_COLUMNS = 8; + public static int PALETTE_ROWS = 6; + + protected static int[] colors; + protected int colorindex; + + protected Font ttlfont, font; + protected int ttlfnth, fnth; + + protected int width, height; + + protected int ttlx, ttly, ttlw, ttlh; + + protected int cellw, cellh; + protected int[] cellx; + protected int[] celly; + + protected String clr; + protected int clrx, clry, clrh; + + protected CommandMenu cmenu; + + public Palette() + { + setFullScreenMode(true); + + width = getWidth(); + height = getHeight(); + + ttlfont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM); + font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, options.largeFontInMenu ? Font.SIZE_MEDIUM : Font.SIZE_SMALL); + + ttlfnth = ttlfont.getHeight(); + fnth = font.getHeight(); + + ttlw = ttlfont.stringWidth(Locale.getString(this, Locale.PALETTE_CMD)) + ttlfnth; + ttlh = ttlfnth * 3 / 2; + ttlx = ttlfnth / 2; + ttly = (ttlh - ttlfnth) / 2; + + cmenu = new CommandMenu(getRenderer(), null, width, height, options.largeFontInMenu ? Font.SIZE_MEDIUM : Font.SIZE_SMALL, true, true, false, false, false); + + clrh = fnth * 3 / 2; + + cellw = (width - fnth) / PALETTE_COLUMNS + 1; + cellh = (height - ttlh - cmenu.getSoftHeight() - ttlfnth * 2 - clrh) / PALETTE_ROWS + 1; + + if(cellh > cellw) + { + cellh = cellw; + } + + if(clrh < cellh) + { + clrh = cellh; + } + + cellx = new int[PALETTE_COLUMNS]; + cellx[0] = (width - (cellw - 1) * PALETTE_COLUMNS) / 2; + + for(int i = 1; i < cellx.length; i++) + { + cellx[i] = cellx[i - 1] + cellw - 1; + } + + celly = new int[PALETTE_ROWS + 1]; + celly[0] = ttlh + (height - ttlh - cmenu.getSoftHeight() - clrh - (cellh - 1) * PALETTE_ROWS) / 2; + + for(int i = 1; i < celly.length; i++) + { + celly[i] = celly[i - 1] + cellh - 1; + } + + clr = ""; + clrx = cellx[0] + fnth / 2; + clry = celly[PALETTE_ROWS] + (clrh - fnth) / 2; + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.EDIT_CMD), Command.ITEM, 2)); + addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.CANCEL, 3)); + } + + public boolean setColor(int color) + { + colorindex = GIFFile.nearestColor(color, colors); + return colors[colorindex] == color; + } + + public int getColor() + { + return colors[colorindex]; + } + + public void paint(Graphics g) + { + //g.setColor(ColorScheme.colors[ColorScheme.back1]); + //g.fillRect(0, 0, width, height); + + images.drawVGradient(g, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, width, height, options.ditherGradients, options.alphaGradients); + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.setFont(ttlfont); + g.drawString(Locale.getString(this, Locale.PALETTE_CMD), ttlx, ttly, Graphics.LEFT | Graphics.TOP); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawLine(0, ttlh, ttlw, ttlh); + + int column, row; + int index; + + for(column = 0; column < PALETTE_COLUMNS; column++) + { + for(row = 0; row < PALETTE_ROWS; row++) + { + index = row + column * PALETTE_ROWS; + + g.setColor(colors[index]); + g.fillRect(cellx[column], celly[row], cellw, cellh); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawRect(cellx[column], celly[row], cellw - 1, cellh - 1); + + if(index == colorindex) + { + g.setColor(colors[index] ^ 0xC0C0C0); + g.drawRect(cellx[column] + 2, celly[row] + 2, cellw - 5, cellh - 5); + } + } + } + + clr = Integer.toHexString(getColor()).toUpperCase(); + + g.setColor(colors[colorindex]); + g.fillRect(cellx[0], celly[PALETTE_ROWS], (cellw - 1) * PALETTE_COLUMNS + 1, clrh); + + g.setColor(colors[colorindex] ^ 0xC0C0C0); + g.setFont(font); + g.drawString(clr, clrx, clry, Graphics.LEFT | Graphics.TOP); + + g.setColor(ColorScheme.colors[ColorScheme.ltborder]); + g.drawRect(cellx[0], celly[PALETTE_ROWS], (cellw - 1) * PALETTE_COLUMNS, clrh - 1); + + cmenu.paint(g); + } + + public void keyPressed(int keyCode) + { + if(cmenu.keyPressed(keyCode)) + { + repaint(); + return; + } + + keyCode = translateKey(keyCode); + + int selcolumn = colorindex / PALETTE_ROWS; + int selrow = colorindex % PALETTE_ROWS; + + if(keyCode == KEY_UP) + { + if(--selrow < 0) + { + selrow = PALETTE_ROWS - 1; + } + } + else if(keyCode == KEY_DOWN) + { + if(++selrow >= PALETTE_ROWS) + { + selrow = 0; + } + } + else if(keyCode == KEY_LEFT) + { + if(--selcolumn < 0) + { + selcolumn = PALETTE_COLUMNS - 1; + } + } + else if(keyCode == KEY_RIGHT) + { + if(++selcolumn >= PALETTE_COLUMNS) + { + selcolumn = 0; + } + } + + colorindex = selrow + selcolumn * PALETTE_ROWS; + + repaint(); + } + + public void keyReleased(int keyCode) + { + if(cmenu.keyReleased(keyCode)) + { + repaint(); + return; + } + } + + public void addCommand(Command c) + { + cmenu.addCommand(c); + } + + public void setCommandListener(CommandListener listener) + { + cmenu.setCommandListener(listener); + } + + public static void loadPalette() throws IOException + { + InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/config/palette.ini"); + IniRecord record = null; + + int state = 1; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + try + { + if(state == 0) + { + colors[Integer.parseInt(record.key)] = (int)Long.parseLong(record.value, 16); + } + else if(state == 1) + { + if(record.key.equalsIgnoreCase("COLS")) + { + PALETTE_COLUMNS = Integer.parseInt(record.value); + state = 2; + } + } + else if(state == 2) + { + if(record.key.equalsIgnoreCase("ROWS")) + { + PALETTE_ROWS = Integer.parseInt(record.value); + colors = new int[PALETTE_COLUMNS * PALETTE_ROWS]; + state = 0; + } + } + } + catch(Exception e) + { + } + } + + ini.close(); + } + + public static void loadUnifiedPalette() throws IOException + { + InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/config/unipalette.ini"); + IniRecord record = null; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + try + { + UNIFIED_PALETTE[Integer.parseInt(record.key)] = (int)Long.parseLong(record.value, 16); + } + catch(Exception e) + { + } + } + + ini.close(); + } +} \ No newline at end of file diff --git a/src/filemanager/PanelManager.java b/src/filemanager/PanelManager.java new file mode 100644 index 0000000..ff8f49a --- /dev/null +++ b/src/filemanager/PanelManager.java @@ -0,0 +1,566 @@ +package filemanager; + +import javax.microedition.lcdui.*; +import javax.microedition.rms.*; +import java.io.*; +import com.one.*; +import com.vmx.AuxClass; + +/** + * КлаÑÑ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ð°Ð½ÐµÐ»Ñми. + * Ðа панелÑÑ… может быть не только FileSelect, + * но и плеер, проÑмотр текÑта и Ñ‚. д. + */ +public class PanelManager +{ + protected String[] currpath; + protected String[] currfile; + protected Object[] currdisp; + protected int[] associat; + protected String[] currname; + + protected DisplayManager dsp; + protected int pcount; + protected int currpanel, prevpanel; + protected int prevpanelreq; + + public PanelManager(DisplayManager dsp, int pcount) + { + this.dsp = dsp; + this.pcount = pcount; + + currpath = new String[pcount]; + currfile = new String[pcount]; + currdisp = new Object[pcount]; + associat = new int[pcount]; + currname = new String[pcount]; + + for(int i = 0; i < pcount; i++) + { + currpath[i] = ""; + currfile[i] = ""; + currdisp[i] = main.FileSelect; + associat[i] = -1; + currname[i] = ""; + } + + currpanel = 0; + prevpanel = pcount > 1 ? currpanel + 1 : currpanel; + prevpanelreq = -1; + } + + /** + * Сохранение данных панелей. + * СохранÑетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ путь и Ð¸Ð¼Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ³Ð¾ файла. + */ + public void savePanels() + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(pcount); + dos.writeInt(currpanel); + dos.writeInt(prevpanel); + + for(int i = 0; i < pcount; i++) + { + dos.writeUTF(currpath[i]); + dos.writeUTF(currfile[i]); + } + + byte[] data = baos.toByteArray(); + dos.close(); + + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(3), true); + + if(rs.getNumRecords() == 0) + { + rs.addRecord(data, 0, data.length); + } + else + { + rs.setRecord(1, data, 0, data.length); + } + + rs.closeRecordStore(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(101, e); + } + + //printPanelData(); + } + + /** + * ВоÑÑтановить данные панелей. + */ + public void restorePanels() + { + try + { + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(3), true); + + if(rs.getNumRecords() == 0) + { + rs.closeRecordStore(); + return; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(rs.getRecord(1))); + + int count = dis.readInt(); + + if(count > pcount) + { + count = pcount; + } + + currpanel = dis.readInt(); + prevpanel = dis.readInt(); + + if(currpanel < 0) + { + currpanel = 0; + } + else if(currpanel >= pcount) + { + currpanel = pcount - 1; + } + + if(prevpanel < 0) + { + prevpanel = 0; + } + else if(prevpanel >= pcount) + { + prevpanel = pcount - 1; + } + + for(int i = 0; i < count; i++) + { + currpath[i] = dis.readUTF(); + currfile[i] = dis.readUTF(); + } + + dis.close(); + + rs.closeRecordStore(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(102, e); + } + + //printPanelData(); + } + +// public void printPanelData() +// { +// System.out.println(); +// System.out.println("Current panel: " + (currpanel + 1)); +// System.out.println("Previous panel: " + (prevpanel + 1)); +// System.out.println(); +// +// for(int i = 0; i < pcount; i++) +// { +// System.out.println("Panel " + (i + 1) + ": '" + currpath[i] + currfile[i] + "', " + currdisp[i].getClass().getName() + ", associated with " + (associat[i] + 1)); +// } +// +// System.out.println(); +// } + + public void storePanel(int panel) + { + currpath[panel] = main.currentPath; + currfile[panel] = main.currentFile; + currdisp[panel] = dsp.getCurrent(); + } + + public void showPanel(int panel) + { + main.currentPath = currpath[panel]; + main.currentFile = currfile[panel]; + + if(currdisp[panel] == main.FileSelect) + { + main.FileSelect.showWait(currfile[panel]); + } + else + { + dsp.setCurrent(currdisp[panel]); + } + } + + public void setPanelName(int panel, String name) + { + currname[panel] = name; + } + + public String getPanelName(int panel) + { + return currname[panel]; + } + + public String getCurrentFileName(int panel) + { + return currpath[panel] + currfile[panel]; + } + + /** + * Возврат к FileSelect + */ + public void ret() + { + if(associat[currpanel] >= 0) + { + // еÑли Ñ Ñтой панелью какаÑ-то была ÑвÑзана, + // переноÑим ее на Ñту + int panel = associat[currpanel]; + + currpath[currpanel] = currpath[panel]; + currfile[currpanel] = currfile[panel]; + currdisp[currpanel] = currdisp[panel]; + associat[currpanel] = associat[panel]; + currname[currpanel] = currname[panel]; + + // а ÑвÑзанную возвращаем в иÑходное ÑоÑтоÑние + currpath[panel] = ""; + currfile[panel] = ""; + currdisp[panel] = main.FileSelect; + associat[panel] = -1; + currname[panel] = ""; + + showPanel(currpanel); + } + else + { + setCurrent(main.FileSelect, currpanel); + } + } + + /** + * Показываем что-нибудь на заданной панели + */ + public void setCurrent(Object dp, int panel) + { + if(dp != main.wait && dp != main.FileSelect) + { + deassociate(panel); + } + else + { + currname[panel] = ""; + } + + currdisp[panel] = dp; + + if(panel == currpanel) + { + dsp.setCurrent(dp); + } + } + + /** + * Показываем что-нибудь на текущей панели + */ + public void setCurrent(Object dp) + { + if(dp != main.wait && dp != main.FileSelect) + { + deassociate(currpanel); + } + else + { + currname[currpanel] = ""; + } + + currdisp[currpanel] = dp; + + dsp.setCurrent(dp); + } + + public void setCurrent(Alert al, Object dp, int panel) + { + if(dp != main.wait && dp != main.FileSelect) + { + deassociate(panel); + } + else + { + currname[panel] = ""; + } + + currdisp[panel] = dp; + + dsp.setCurrent(al, currdisp[currpanel]); + } + + public void setCurrent(AutoAdvanceScreen al, Object dp, int panel) + { + if(dp != main.wait && dp != main.FileSelect) + { + deassociate(panel); + } + else + { + currname[panel] = ""; + } + + currdisp[panel] = dp; + + dsp.setCurrent(al, currdisp[currpanel]); + } + + /** + * Показать панель nextpanel + */ + public void changePanel(int nextpanel) + { + if(nextpanel < 0 || nextpanel >= pcount) + { + return; + } + + if(nextpanel != currpanel) + { + storePanel(currpanel); + + prevpanel = currpanel; + currpanel = nextpanel; + } + + showPanel(currpanel); + } + + /** + * Показать Ñледующую панель + */ + public void showNextPanel() + { + storePanel(currpanel); + + prevpanel = currpanel; + + if(++currpanel >= pcount) + { + currpanel = 0; + } + + showPanel(currpanel); + } + + /** + * Показать предыдущую панель + */ + public void showPrevPanel() + { + storePanel(currpanel); + + prevpanel = currpanel; + + if(--currpanel < 0) + { + currpanel = pcount - 1; + } + + showPanel(currpanel); + } + + public void showNextFreePanel() + { + storePanel(currpanel); + + prevpanel = currpanel; + + do + { + if(++currpanel >= pcount) + { + currpanel = 0; + } + + if(currdisp[currpanel] == main.FileSelect) + { + break; + } + } while(currpanel != prevpanel); + + showPanel(currpanel); + } + + public void showPrevFreePanel() + { + storePanel(currpanel); + + prevpanel = currpanel; + + do + { + if(--currpanel < 0) + { + currpanel = pcount - 1; + } + + if(currdisp[currpanel] == main.FileSelect) + { + break; + } + } while(currpanel != prevpanel); + + showPanel(currpanel); + } + + /** + * Свернуть текущую панель - Ñкопировать путь в другую + */ + public void minimizePanel() + { + storePanel(currpanel); + + prevpanel = currpanel; + + if(associat[currpanel] < 0) + { + associat[currpanel] = newPanel(); + + currpath[associat[currpanel]] = currpath[currpanel]; + currfile[associat[currpanel]] = currfile[currpanel]; + } + + currpanel = associat[currpanel]; + showPanel(currpanel); + } + + public void updateAssociation(int panel, String filename) + { + if(filename == null) + { + return; + } + + int index = filename.lastIndexOf('/', filename.length() - 2) + 1; + + if(index > 0) + { + currpath[panel] = filename.substring(0, index); + currfile[panel] = filename.substring(index); + } + else + { + currpath[panel] = ""; + currfile[panel] = filename; + } + } + + protected void deassociate(int panel) + { + for(int i = 0; i < pcount; i++) + { + if(associat[i] == panel) + { + associat[i] = -1; + } + } + } + + /** + * Узнать номер текущей панели + */ + public int currentPanel() + { + return currpanel; + } + + /** + * Узнать общее чиÑло панелей + */ + public int panelsCount() + { + return pcount; + } + + /** + * Узнать номер предыдущей панели + */ + public int prevPanel() + { + return prevpanel; + } + + /** + * Ðайти незанÑтую панель (на которой отображаетÑÑ FileSelect) + */ + public int newPanel() + { + for(int i = 0; i < pcount; i++) + { + if(currdisp[i] == main.FileSelect && currpath[i].length() == 0) + { + return i; + } + } + + return prevpanel; + } + + public boolean isShown(Displayable dp) + { + return dsp.getCurrent() == dp; + } + +// /** +// * Подготовка к открытию файла filename из панели panel +// */ +// public void requirePanel(int panel) throws Exception +// { +// if(panel < 0 || panel >= pcount || panel == currpanel) +// { +// return; +// } +// +// storePanel(currpanel); +// +// prevpanelreq = currpanel; +// currpanel = panel; +// +// main.FileSelect.lock(); +// +// /* +// int index = filename.lastIndexOf('/') + 1; +// +// main.currentPath = filename.substring(0, index); +// main.currentFile = filename.substring(index); +// */ +// +// main.currentPath = currpath[currpanel]; +// main.currentFile = currfile[currpanel]; +// +// main.FileSelect.list(main.currentFile); +// } +// +// /** +// * Завершение процедуры Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° +// */ +// public void releaseRequiredPanel() +// { +// main.FileSelect.unlock(); +// +// if(prevpanelreq < 0 || prevpanelreq >= pcount) +// { +// return; +// } +// +// currpanel = prevpanelreq; +// prevpanelreq = -1; +// +// showPanel(currpanel); +// } + +// private static void out(String s) +// { +// System.out.println("[PanelManager] " + s); +// } +} diff --git a/src/filemanager/Renamer.java b/src/filemanager/Renamer.java new file mode 100644 index 0000000..74be90a --- /dev/null +++ b/src/filemanager/Renamer.java @@ -0,0 +1,281 @@ +package filemanager; + +import java.util.*; +import com.one.file.*; + +public class Renamer extends Operation +{ + protected String template; + protected int counter; + + public Renamer(String template) + { + this.template = template; + counter = -1; + + Buffer.flattenBuffer(); + } + + /** + * ФункциÑ, оÑущеÑтвлÑÑŽÑ‰Ð°Ñ ÑобÑтвенно переименование + */ + public void run() + { + FileConnection fc = null; + String path = null; + String name = null; + int index = -1; + + if(callback != null) + { + callback.setMax(Buffer.getSize()); + callback.setProgress(0); + } + + initState(); + + try + { + Enumeration files = Buffer.getBuffer(); + + while(enabled && files.hasMoreElements()) + { + name = (String)files.nextElement(); + + if(callback != null) + { + callback.setText(name); + } + + index = name.lastIndexOf('/') + 1; + + path = name.substring(0, index); + name = name.substring(index); + + fc = (FileConnection)Connector.open("file:///" + path + name); + fc.rename(getNewName(name)); + fc.close(); + + if(callback != null) + { + callback.progress(1); + } + } + } + catch(Exception ex) + { + logError(ex); + + if(fc != null) + { + try + { + fc.close(); + } + catch(Exception xx) + { + } + } + } + } + + protected void initState() + { + String s = ""; + int len = template.length(); + boolean intoken = false; + boolean incounter = false; + char c; + + for(int i = 0; i < len; i++) + { + c = template.charAt(i); + + switch(c) + { + case '[': + if(intoken) + { + intoken = false; + } + else + { + intoken = true; + } + + s += c; + + break; + + case 'C': + case 'c': + if(intoken) + { + if(counter < 0) + { + counter = 0; + incounter = true; + } + } + + s += c; + + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if(incounter) + { + counter = counter * 10 + (c - '0'); + } + else + { + s += c; + } + + break; + + case ']': + if(intoken) + { + incounter = false; + intoken = false; + } + + s += c; + + break; + + default: + s += c; + } + } + + template = s; + } + + protected String getNewName(String oldname) + { + String s = ""; + String ext = ""; + int len = template.length(); + boolean intoken = false; + boolean incounter = false; + char c; + + int index = oldname.lastIndexOf('.'); + + if(index >= 0 && index < oldname.length()) + { + ext = oldname.substring(index + 1); + oldname = oldname.substring(0, index); + } + + for(int i = 0; i < len; i++) + { + c = template.charAt(i); + + switch(c) + { + case '[': + if(intoken) + { + intoken = false; + s += c; + } + else + { + intoken = true; + } + break; + + case 'N': + case 'n': + if(intoken) + { + s += oldname; + } + else + { + s += c; + } + break; + + case 'E': + case 'e': + if(intoken) + { + s += ext; + } + else + { + s += c; + } + break; + + case 'C': + case 'c': + if(intoken) + { + s += Integer.toString(counter); + } + else + { + s += c; + } + break; + + case '+': + if(intoken) + { + counter++; + } + else + { + s += c; + } + break; + + case '-': + if(intoken) + { + counter--; + } + else + { + s += c; + } + break; + + case ']': + if(intoken) + { + intoken = false; + } + else + { + s += c; + } + break; + + default: + s += c; + } + } + + return s; + } + +// private static void out(String s) +// { +// System.out.println("[Renamer] " + s); +// } +} diff --git a/src/filemanager/SearchThread.java b/src/filemanager/SearchThread.java new file mode 100644 index 0000000..d6a3c66 --- /dev/null +++ b/src/filemanager/SearchThread.java @@ -0,0 +1,113 @@ +package filemanager; + +import com.one.ModuleRegistry; +import java.util.Enumeration; +import com.one.StringPattern; + +public class SearchThread extends Operation +{ + protected StringPattern pattern; + protected String path; + protected boolean recursive; + protected boolean archives; + + public SearchThread(StringPattern pattern, String path, boolean recursive, boolean archives) + { + this.pattern = pattern; + this.path = path; + this.recursive = recursive; + this.archives = archives; + + clear = false; + } + + public void run() + { + if(callback != null) + { + callback.setMax(1); + callback.setProgress(0); + callback.setPercentMode(false); + } + + if(path == null || path.length() == 0) + { + Enumeration roots = filesystem.listRoots(); + + if(roots != null) + { + while(enabled && roots.hasMoreElements()) + { + search(pattern, (String)roots.nextElement()); + } + } + } + else + { + search(pattern, path); + } + + main.oldPath = main.currentPath; + main.oldFile = main.currentFile; + + main.currentPath = "buf:/"; + main.currentFile = ""; + } + + protected void search(StringPattern pattern, String path) + { + if(!enabled) + { + return; + } + + String file, fullname; + + if(callback != null) + { +// file = path.substring(0, path.length() - 1); +// callback.setText(file.substring(file.lastIndexOf('/') + 1)); + callback.setText(path); + } + + Enumeration files = filesystem.list(path, options.showHidden); + + if(files == null) + { + return; + } + + while(files.hasMoreElements()) + { + file = (String)files.nextElement(); + fullname = path + file; + + if(pattern.matchesWith(file)) + { + Buffer.add(fullname, false); + + if(callback != null) + { + callback.progress(1); + } + } + + if(callback != null) + { + callback.rise(1); + } + + if(recursive) + { + if(filesystem.isDir(fullname)) + { + search(pattern, fullname); + } + else if(archives && ModuleRegistry.getAction(file.substring(file.lastIndexOf('.') + 1)) == ModuleRegistry.ACTION_EXPLORE) + { + search(pattern, fullname + "/"); + } + } + } + } +} diff --git a/src/filemanager/SplashScreen.java b/src/filemanager/SplashScreen.java new file mode 100644 index 0000000..55b52c1 --- /dev/null +++ b/src/filemanager/SplashScreen.java @@ -0,0 +1,263 @@ +package filemanager; + +import com.vmx.Locale; +import javax.microedition.lcdui.*; +import com.one.*; +import com.one.vector.AuxMath; +import com.vmx.AuxClass; +import com.vmx.ProgressCallback; + +public class SplashScreen extends PaintableObject implements ProgressCallback +{ + protected static final int COLOR_GRADATIONS = 8; + + protected Image splashBack; + protected Image splashAbout; + protected int width, height; + protected int curstate, maxstate; + protected Font font; + protected int pbx, pby, pbw, pbh; + protected int arcsz; + + protected int max, progress; + protected int pb2x, pb2y, pb2w, pb2h; + + public SplashScreen() + { + setFullScreenMode(true); + + width = getWidth(); + height = getHeight(); + + font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE); + + pbw = width - 4; + pbh = 3; + pbx = 2; + pby = 2; + + pb2w = pbw; + pb2h = pbh; + pb2x = pbx; + pb2y = pby + pbh + pby; + + progress = 0; + max = 1; + + arcsz = Math.min(pbw, pbh) / 2; + + curstate = 0; + maxstate = 1; + + try + { + splashAbout = Image.createImage("/img/about.png"); + } + catch(Exception e) + { + } + } + + public void createBackground() + { + splashBack = Image.createImage(width, height); + Graphics g = splashBack.getGraphics(); + + int sqsize = width == height ? width / 8 : AuxMath.gcd(width, height) / 2; + + if(sqsize <= 1) + { + sqsize = (width + height) / 16; + } + + int sqxcount = width / sqsize; + int sqycount = height / sqsize; + + int colorA = ColorScheme.colors[AuxClass.randomFromRange(0, ColorScheme.colors.length - 1)]; + int colorB; + + int count = 0; + + do + { + colorB = ColorScheme.colors[AuxClass.randomFromRange(0, ColorScheme.colors.length - 1)]; + } + while((colorA & 0xFFFFFF) == (colorB & 0xFFFFFF) && count++ < ColorScheme.colors.length); + + for(int y = 0; y < sqycount; y++) + { + for(int x = 0; x < sqxcount; x++) + { + g.setColor(images.blendColors(colorA, colorB, AuxClass.randomFromRange(0, COLOR_GRADATIONS), COLOR_GRADATIONS)); + g.fillRect(x * sqsize, y * sqsize, sqsize, sqsize); + } + } + + int msgx = (width - font.stringWidth(Locale.ABOUT_MIDLET_NAME)) / 2; + int msgy = (height - font.getHeight()) / 2; + + g.setColor(images.blendColors(ColorScheme.colors[ColorScheme.selback1], ColorScheme.colors[ColorScheme.selback2], 1, 2)); + LineEffect.drawTextOutline(g, Locale.ABOUT_MIDLET_NAME, msgx, msgy); + + g.setColor(ColorScheme.colors[ColorScheme.selfore]); + g.drawString(Locale.ABOUT_MIDLET_NAME, msgx, msgy, Graphics.LEFT | Graphics.TOP); + } + + public void setMaxState(int value) + { + maxstate = value; + + repaint(); + serviceRepaints(); + } + + public void setState(int value) + { + curstate = value; + + repaint(); + serviceRepaints(); + } + + public void nextState() + { + curstate++; + + repaint(); + serviceRepaints(); + } + + public int getMaxState() + { + return maxstate; + } + + public int getState() + { + return curstate; + } + + public void setMax(int max) + { + if(max < 1) + { + max = 1; + } + + this.max = max; + + repaint(); + serviceRepaints(); + } + + public void setProgress(int progress) + { + if(progress < 0) + { + progress = 0; + } + else if(progress > max) + { + progress = max; + } + + this.progress = progress; + + repaint(); + serviceRepaints(); + } + + public void rise(int plus) + { + setMax(max + plus); + } + + public void progress(int plus) + { + setProgress(progress + plus); + } + + public void setText(String text) + { + } + + public int getMax() + { + return max; + } + + public int getProgress() + { + return progress; + } + + public String getText() + { + return ""; + } + + public void setPercentMode(boolean mode) + { + } + + public void setCancelFlag(boolean flag) + { + } + + public boolean getCancelFlag() + { + return false; + } + + public void paint(Graphics g) + { + if(images.splashBack != null) + { + g.drawImage(images.splashBack, 0, 0, Graphics.LEFT | Graphics.TOP); + } + else if(splashBack != null) + { + g.drawImage(splashBack, 0, 0, Graphics.LEFT | Graphics.TOP); + +// int colorA = ColorScheme.colors[ColorScheme.back1]; +// int colorB = ColorScheme.colors[ColorScheme.fore]; +// +// for(int y = 0; y < sqycount; y++) +// { +// for(int x = 0; x < sqxcount; x++) +// { +// g.setColor(images.blendColors(colorA, colorB, sqmatrix[y][x], 8)); +// g.fillRect(x * sqsize, y * sqsize, sqsize, sqsize); +// } +// } +// +// g.setColor(ColorScheme.colors[ColorScheme.back1]); +// g.fillRoundRect(rrx, rry, rrw, rrh, rra, rra); +// +// g.setColor(ColorScheme.colors[ColorScheme.fore]); +// g.drawString(Locale.ABOUT_MIDLET_NAME, msgx, msgy, Graphics.LEFT | Graphics.TOP); + } + else + { + return; + } + + if(splashAbout != null) + { + g.drawImage(splashAbout, width, height, Graphics.RIGHT | Graphics.BOTTOM); + } + + g.setColor(ColorScheme.colors[ColorScheme.altfore]); + + if(curstate >= 0 && curstate <= maxstate) + { + g.fillRect(pbx, pby, pbw * curstate / maxstate, pbh); + } + else + { + g.fillRect(pbx, pby, pbw, pbh); + } + + g.fillRect(pb2x, pb2y, pb2w * progress / max, pbh); + } +} diff --git a/src/filemanager/TemplateManager.java b/src/filemanager/TemplateManager.java new file mode 100644 index 0000000..851c18e --- /dev/null +++ b/src/filemanager/TemplateManager.java @@ -0,0 +1,43 @@ +package filemanager; + +import com.one.ErrScreen; +import com.one.IniRecord; +import com.vmx.InputStreamDecoder; +import java.util.Vector; + +public class TemplateManager +{ + public static String[] templates; + public static String[] tempnames; + + public static void readTemplateList() + { + Vector v = new Vector(); + + try + { + InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/temp/template.ini"); + IniRecord record = null; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + v.addElement(record); + } + + ini.close(); + + tempnames = new String[v.size()]; + templates = new String[v.size()]; + + for(int i = 0; i < v.size(); i++) + { + tempnames[i] = ((IniRecord)v.elementAt(i)).key; + templates[i] = ((IniRecord)v.elementAt(i)).value; + } + } + catch(Exception e) + { + ErrScreen.showErrMsg(89, e); + } + } +} diff --git a/src/filemanager/WorkingMenu.java b/src/filemanager/WorkingMenu.java new file mode 100644 index 0000000..fde6afa --- /dev/null +++ b/src/filemanager/WorkingMenu.java @@ -0,0 +1,389 @@ +package filemanager; + +import modules.text.cvsTextView; +import com.one.ErrScreen; +import com.one.FileSource; +import javax.microedition.lcdui.*; +import java.util.Enumeration; +import com.vmx.*; + +public class WorkingMenu implements MenuListener +{ + protected cvsMenu mn; + + public WorkingMenu(cvsMenu menu) + { + mn = menu; + } + + /** + * Обработчик Ð´Ð»Ñ Ð¼ÐµÐ½ÑŽ + */ + public void menuAction(int string) + { + if(string < 0) + { + return; + } + else if(string >= Locale.PANEL_NUMS && string < Locale.PANEL_NUMS + 10) + { + //main.FileSelect.changePanel(string - Locale.PANEL_NUMS); + mn.ret(); + main.manager.changePanel(string - Locale.PANEL_NUMS); + return; + } + else if(string >= Locale.SORT_NONE && string <= Locale.SORT_BY_SIZE) + { + options.listSortBy = string - Locale.SORT_NONE; + main.FileSelect.showWait(main.currentFile); + return; + } + + boolean moveit = false; + //main.currentFile = main.FileSelect.getFileItem(main.FileSelect.getSelectedIndex()).getName(); + + main.FileSelect.setMenuType(mn); + + if(string == Locale.PROPERTY_CMD && mn.type == 3 && main.currentPath.endsWith(":/") && "..".equals(main.currentFile)) + { + string = Locale.DISK_INFO_CMD; + } + + if(!mn.isActionAllowed(string)) + { + return; + } + + switch(string) + { + case Locale.HOT_KEYS: + mn.ret(); + main.FileSelect.toggleHotKeyMode(); + break; + + case Locale.EXIT_CMD: // выход + mn.ret(); + main.destroyApp(); + break; + + case Locale.MINIMIZE_CMD: + mn.ret(); + try + { + main.dsp.setCurrent(null); + } + catch(Exception e) + { + } + break; + + case Locale.MARK_CMD: // выделить + main.FileSelect.markSelected(); + mn.ret(); + break; + + case Locale.MARK_ALL_CMD: // выделить вÑе + main.FileSelect.markAll(); + mn.ret(); + break; + + case Locale.DEMARK_ALL_CMD: // ÑброÑить выделение + main.FileSelect.demarkAll(); + mn.ret(); + break; + + case Locale.HELP_CMD: // Ñправка + cvsTextView.getInstance().openStream(Locale.getAboutStream(), Locale.ABOUT_MIDLET_NAME + "." + Locale.ABOUT_DEPLOYMENT_NUMBER); + break; + + case Locale.TO_FAVOUR_CMD: // папку в избранное + if("..".equals(main.currentFile)) + { + options.addFavorite(main.currentPath); + } + else if(main.currentPath.length() > 0) + { + options.addFavorite(main.currentPath + main.currentFile); + } + else + { + options.addFavorite(main.currentFile.substring(0, 3)); + } + + main.dsp.setCurrent(mn.parent); + break; + + case Locale.DISK_INFO_CMD: // инфо о диÑке + if(!"fav:/".equals(main.currentPath) && !Locale.getString(this, Locale.FAVOURITE).equals(main.currentFile) && + !"null:/".equals(main.currentPath) && !Locale.getString(this, Locale.BIT_BUCKET).equals(main.currentFile)) + { + main.dsp.setCurrent(new diskInfo(mn.parent)); + } + break; + + case Locale.PROPERTY_CMD: // ÑвойÑтва + if(!"fav:/".equals(main.currentPath) && !Locale.getString(this, Locale.FAVOURITE).equals(main.currentFile) && + !"null:/".equals(main.currentPath) && !Locale.getString(this, Locale.BIT_BUCKET).equals(main.currentFile)) + { + main.dsp.setCurrent(new frmProperties(mn.parent)); + } + break; + + case Locale.BUFFER: // показать буфер обмена + main.FileSelect.showBuffer(); + break; + + case Locale.OPEN_CMD: // открыть + mn.ret(); + main.FileSelect.selectFile(); + break; + + case Locale.MODULES_CMD: + main.FileSelect.showModuleList(); + break; + + case Locale.CRYPT_CMD: + main.dsp.setCurrent(new frmCrypt(mn.parent)); + break; + + case Locale.MENU_SEARCH: + main.dsp.setCurrent(new frmSearch(mn.parent)); + break; + + case Locale.RENAME_CMD: // переименовать + main.dsp.setCurrent(new frmRename(mn.parent)); + break; + + case Locale.DELETE_CMD: // удалить выбранный/выделенные + if("fav:/".equals(main.currentPath)) // удалÑем из избранного + { + if(main.FileSelect.getMarkCount() > 0) + { + Enumeration files = main.FileSelect.elements(); + FileItem item; + + while(files.hasMoreElements()) + { + item = (FileItem)files.nextElement(); + + if(item.isMarked()) + { + options.deleteFavorite(item.getFullName()); + } + } + } + else if(main.FileSelect.getSelectedIndex() > 0) + { + options.deleteFavorite(main.FileSelect.getFileItem(main.FileSelect.getSelectedIndex()).getFullName()); + } + + cvsWait.start(mn); + } + else if("buf:/".equals(main.currentPath)) // удалÑем из буфера + { + if(main.FileSelect.getMarkCount() > 0) + { + Enumeration files = main.FileSelect.elements(); + FileItem item; + + while(files.hasMoreElements()) + { + item = (FileItem)files.nextElement(); + + if(item.isMarked()) + { + Buffer.remove(item.getFullName()); + } + } + } + else if(main.FileSelect.getSelectedIndex() > 0) + { + Buffer.remove(main.FileSelect.getFileItem(main.FileSelect.getSelectedIndex()).getFullName()); + } + + cvsWait.start(mn); + } + else + { + if(main.FileSelect.getMarkCount() <= 0) // удалÑем проÑто немаркированный файл + { + main.dsp.setCurrent(new alConfirmDelete(main.currentPath + main.currentFile, mn.parent)); + } + else + { + main.dsp.setCurrent(new alConfirmDeleteSel(mn.parent)); + } + } + + break; + + case Locale.NEW_FOLDER_CMD: // Ñоздать папку + main.dsp.setCurrent(new frmNewFolder(mn.parent)); + break; + + case Locale.NEW_FILE_CMD: // Ñоздать файл + main.dsp.setCurrent(new frmNewFile(mn.parent, FileSource.TYPE_NORMAL_FILE)); + break; + + case Locale.MOVE_CMD: // перемеÑтить + moveit = true; + + case Locale.EXTRACT_CMD: + case Locale.EXTRACT_ALL_CMD: + if(string == Locale.EXTRACT_ALL_CMD) + { + main.FileSelect.markAll(); + } + + case Locale.COPY_CMD: // копировать + if(main.FileSelect.getMarkCount() <= 0) // копируем поодиночку + { + Buffer.add(main.FileSelect.getFileItem(main.FileSelect.getSelectedIndex()).getFullName(), moveit); + } + else // копируем выделенные в буфер + { + Enumeration files = main.FileSelect.elements(); + FileItem item; + + while(files.hasMoreElements()) + { + item = (FileItem)files.nextElement(); + + if(item.isMarked()) + { + Buffer.add(item.getFullName(), moveit); + } + } + + main.FileSelect.demarkAll(); + } + + if("buf:/".equals(main.currentPath)) + { + mn.ret(); + } + else + { + main.showMessage(Locale.getString(this, Locale.DONE), Locale.getString(this, Locale.SELECT_PASTE_IN_FOLDER), AlertType.INFO, 1500, mn.parent); + } + break; + + case Locale.ADD_CMD: + case Locale.INSERT_CMD: // вÑтавить + Buffer.startOperation(new CopyMoveThread()); + break; + + case Locale.FAVOURITE: // показать избранное + main.currentPath = "fav:/"; + cvsWait.start(mn); + break; + + case Locale.PREFERENCES_CMD: // наÑтройки + main.dsp.setCurrent(new frmOptions(mn.parent)); + break; + + case Locale.CREATE_ARCHIVE: // Ñоздать архив из файлов из буфера + main.dsp.setCurrent(new frmNewFile(mn.parent, FileSource.TYPE_CONTAINER)); + break; + + case Locale.SELECT_CMD: + mn.ret(); + main.FileSelect.fireSelectAction(); + break; + + case Locale.PREV_LINE_CMD: + main.FileSelect.directKeyPressed(gkcCanvas.KEY_UP); + mn.ret(); + break; + + case Locale.NEXT_LINE_CMD: + main.FileSelect.directKeyPressed(gkcCanvas.KEY_DOWN); + mn.ret(); + break; + + case Locale.PREV_SCREEN_CMD: + main.FileSelect.directKeyPressed(gkcCanvas.KEY_LEFT); + mn.ret(); + break; + + case Locale.NEXT_SCREEN_CMD: + main.FileSelect.directKeyPressed(gkcCanvas.KEY_RIGHT); + mn.ret(); + break; + + case Locale.OPTIONS_CMD: + main.FileSelect.showMenu(); + break; + + case Locale.FULLSCREEN_CMD: + main.FileSelect.changeFSMode(); + mn.ret(); + break; + + case Locale.BACK_CMD: + main.FileSelect.upDir(); + break; + + case Locale.KEYBOARD_CONFIG_CMD: + main.keycfg.show(); + break; + + case Locale.CLOCK_MODE: + options.clockMode = !options.clockMode; + main.FileSelect.repaint(); + break; + + case Locale.NEXT_PANEL: + mn.ret(); + main.manager.showNextPanel(); + break; + + case Locale.PREV_PANEL: + mn.ret(); + main.manager.showPrevPanel(); + break; + + case Locale.NEXT_FREE: + mn.ret(); + main.manager.showNextFreePanel(); + break; + + case Locale.PREV_FREE: + mn.ret(); + main.manager.showPrevFreePanel(); + break; + + case Locale.QUICK_SWITCH: + mn.ret(); + main.manager.changePanel(main.manager.prevPanel()); + break; + + case Locale.PANELS: + main.dsp.setCurrent(new lstPanels(mn.parent)); + break; + + case Locale.SORT_REVERSE_ORDER: + options.listSortReverseOrder = !options.listSortReverseOrder; + main.FileSelect.showWait(main.currentFile); + break; + + case Locale.IGNORE_CASE: + options.listSortIgnoreCase = !options.listSortIgnoreCase; + main.FileSelect.showWait(main.currentFile); + break; + + case Locale.MEMORY_MONITOR: + main.monitor.show(mn.parent); + break; + + case Locale.CONTAINERS: + main.dsp.setCurrent(new lstContainers(mn.parent)); + break; + + case Locale.COLOR_SCHEME: + options.colorScheme = ColorScheme.SCHEME_CUSTOM; + main.showColorSchemeEditor(mn.parent); + break; + } + } +} diff --git a/src/filemanager/alConfirmDelete.java b/src/filemanager/alConfirmDelete.java new file mode 100644 index 0000000..c548901 --- /dev/null +++ b/src/filemanager/alConfirmDelete.java @@ -0,0 +1,116 @@ +package filemanager; // переведен + +import com.vmx.Locale; +import javax.microedition.lcdui.*; + +public class alConfirmDelete extends GraphicAlert implements CommandListener +{ + Command cmdYes = new Command(Locale.getString(this, Locale.YES_CMD), Command.OK, 1); + Command cmdNo = new Command(Locale.getString(this, Locale.NO_CMD), Command.CANCEL, 2); + + //public static boolean yes = false; + Object parent; + String fn; + boolean tryrec; + + public alConfirmDelete(String fileName, Object parent) + { + super("", "", images.getAlertIcon(AlertType.CONFIRMATION), AlertType.CONFIRMATION); + + setTitle(Locale.getString(this, Locale.CONFIRMATION)); + setText(Locale.getString(this, Locale.DEL_SELECTED_FILE)); + + this.parent = parent; + this.fn = fileName; + this.tryrec = false; + + addCommand(cmdYes); + addCommand(cmdNo); + + setCommandListener(this); + } + + public void commandAction(Command command, Displayable displayable) + { + if(command == cmdYes) + { + setType(AlertType.INFO); + setImage(images.getAlertIcon(AlertType.INFO)); + setTitle(Locale.getString(this, Locale.WAIT)); + setString(Locale.getString(this, Locale.WAIT_PLEASE)); + setTimeout(Alert.FOREVER); + removeCommand(cmdYes); + removeCommand(cmdNo); + main.dsp.setCurrent(this, parent); + + if(filesystem.isDir(fn)) // Ñто папка + { + if(filesystem.isReadOnly(fn)) + { + // файл только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.FILE_READ_ONLY, fn), AlertType.WARNING, 3000, parent); + } + else if(filesystem.deleteFile(fn, tryrec, this)) + { + // файл удален + + main.FileSelect.delete(main.FileSelect.getSelectedIndex()); + + main.showMessage(Locale.getString(this, Locale.DONE), Locale.getString(this, Locale.FOLDER_DELETED), AlertType.INFO, 1500, parent); + } + else + { + // не получилоÑÑŒ удалить... + + if(tryrec) + { + // рекурÑивно уже пробовали, + // вÑе равно не вышло по неизвеÑтным причинам + + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.FILE_NOT_DELETED, fn), AlertType.ERROR, 3000, parent); + } + else + { + // может быть получитÑÑ Ñ€ÐµÐºÑƒÑ€Ñивно + + setType(AlertType.CONFIRMATION); + setImage(images.getAlertIcon(AlertType.CONFIRMATION)); + setTitle(Locale.getString(this, Locale.CONFIRMATION)); + setString(Locale.getString(this, Locale.FOLDER_NOT_EMPTY)); + setTimeout(Alert.FOREVER); + addCommand(cmdYes); + addCommand(cmdNo); + tryrec = true; + main.dsp.setCurrent(this, parent); + } + } + } + else // Ñто файл + { + if(filesystem.isReadOnly(fn)) + { + // файл только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ + + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.FILE_READ_ONLY, fn), AlertType.WARNING, 3000, parent); + } + else if(filesystem.deleteFile(fn, false, this)) + { + // файл удален + + main.FileSelect.delete(main.FileSelect.getSelectedIndex()); + main.showMessage(Locale.getString(this, Locale.DONE), Locale.getString(this, Locale.FILE_DELETED), AlertType.INFO, 1500, parent); + } + else + { + // файл не удален неивеÑтно почему + + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.FILE_NOT_DELETED, fn), AlertType.ERROR, 3000, parent); + } + } + } + else + { + main.dsp.setCurrent(parent); + } + } +} diff --git a/src/filemanager/alConfirmDeleteSel.java b/src/filemanager/alConfirmDeleteSel.java new file mode 100644 index 0000000..50cd556 --- /dev/null +++ b/src/filemanager/alConfirmDeleteSel.java @@ -0,0 +1,77 @@ +package filemanager; // переведен + +import com.vmx.Locale; +import javax.microedition.lcdui.*; +import java.util.Enumeration; + +public class alConfirmDeleteSel extends GraphicAlert implements CommandListener +{ + Command cmdYes = new Command(Locale.getString(this, Locale.YES_CMD), Command.OK, 1); + Command cmdNo = new Command(Locale.getString(this, Locale.NO_CMD), Command.CANCEL, 2); + + Object parent; + String fileFullName, fileOnlyName; + StringBuffer errors = new StringBuffer(); + + public alConfirmDeleteSel(Object parent) + { + super("", "", images.getAlertIcon(AlertType.CONFIRMATION), AlertType.CONFIRMATION); + + setTitle(Locale.getString(this, Locale.CONFIRMATION)); + setText(Locale.getString(this, Locale.DEL_MARKED_FILES)); + + this.parent = parent; + + addCommand(cmdYes); + addCommand(cmdNo); + + setCommandListener(this); + } + + public void commandAction(Command command, Displayable displayable) + { + if(command == cmdYes) + { + setType(AlertType.WARNING); + setTitle(Locale.getString(this, Locale.WAIT)); + setString(Locale.getString(this, Locale.WAIT_PLEASE)); + setImage(null); + setTimeout(Alert.FOREVER); + removeCommand(cmdYes); + removeCommand(cmdNo); + main.dsp.setCurrent(this, parent); + + Enumeration files = main.FileSelect.elements(); + FileItem item; + + while(files.hasMoreElements()) + { + item = (FileItem)files.nextElement(); + + if(item.isSpecial() || !item.isMarked()) + { + continue; + } + + if(item.isReadOnly()) + { + // файл только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ + errors.append(Locale.getString(this, Locale.FILE_READ_ONLY, item.getName())); + errors.append("\n\n"); + } + else if(!filesystem.deleteFile(item.getFullName(), true, this)) + { + // файл не удален неизвеÑтно почему + errors.append(Locale.getString(this, Locale.FILE_NOT_DELETED, item.getName())); + errors.append("\n\n"); + } + } + + main.dsp.setCurrent(new alMessage(errors.toString())); + } + else if(command == cmdNo) + { + main.dsp.setCurrent(parent); + } + } +} diff --git a/src/filemanager/alConfirmOverwrite.java b/src/filemanager/alConfirmOverwrite.java new file mode 100644 index 0000000..59d3b88 --- /dev/null +++ b/src/filemanager/alConfirmOverwrite.java @@ -0,0 +1,82 @@ +package filemanager; + +import com.vmx.Locale; +import javax.microedition.lcdui.*; + +/** + * КлаÑÑ Ð´Ð»Ñ Ð²Ñ‹Ð´Ð°Ñ‡Ð¸ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ‚Ð¸Ð¿Ð° "Файл ... ÑущеÑтвует. ПерезапиÑать?" + * Ñ Ð²Ð°Ñ€Ð¸Ð°Ð½Ñ‚Ð°Ð¼Ð¸ ответа Да / Ðет / Да Ð´Ð»Ñ Ð²Ñех / Ðет Ð´Ð»Ñ Ð²Ñех / Отмена + */ +public class alConfirmOverwrite extends GraphicAlert implements CommandListener, Runnable +{ + public Command cmdYes = new Command(Locale.getString(this, Locale.YES_CMD), Command.OK, 1); + public Command cmdNo = new Command(Locale.getString(this, Locale.NO_CMD), Command.CANCEL, 2); + public Command cmdYesForAll = new Command(Locale.getString(this, Locale.YES_FOR_ALL), Command.OK, 3); + public Command cmdNoForAll = new Command(Locale.getString(this, Locale.NO_FOR_ALL), Command.CANCEL, 4); + public Command cmdCancel = new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 5); + + public Command modalResult; + public Thread t; + + private Object nextShow; + private final Object waiter; + + /** + * КонÑтруирует клаÑÑ Ð¸ Ñоздаёт поток, ожидающий выбора команды. + * Ð Buffer юзает al.t.join() Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы подождать. + */ + public alConfirmOverwrite(String filename, Object nextDsp) + { + super("", "", images.getAlertIcon(AlertType.CONFIRMATION), AlertType.CONFIRMATION); + + setTitle(Locale.getString(this, Locale.CONFIRMATION)); + setText(Locale.getString(this, Locale.NAME_EXIST_OVERWRITE_QUESTION, filename)); + + addCommand(cmdYes); + addCommand(cmdNo); + addCommand(cmdYesForAll); + addCommand(cmdNoForAll); + addCommand(cmdCancel); + + setCommandListener(this); + + setTimeout(Alert.FOREVER); + + nextShow = nextDsp; + waiter = new Object(); + + t = new Thread(this, "ConfirmOverwrite/ModalWait"); + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° команды + */ + public void run() + { + try + { + synchronized(waiter) + { + waiter.wait(); + } + } + catch(InterruptedException ie) + { + } + + main.dsp.setCurrent(nextShow); + } + + /** + * Обработка команды - прерывает поток Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¸ задаёт modalResult + */ + public void commandAction(Command c, Displayable d) + { + modalResult = c; + + synchronized(waiter) + { + waiter.notifyAll(); + } + } +} diff --git a/src/filemanager/alMessage.java b/src/filemanager/alMessage.java new file mode 100644 index 0000000..fefaccf --- /dev/null +++ b/src/filemanager/alMessage.java @@ -0,0 +1,69 @@ +package filemanager; // переведен + +import com.vmx.Locale; +import javax.microedition.lcdui.*; + +public class alMessage extends GraphicAlert implements Runnable, CommandListener +{ + private Thread t; + private boolean ok; + + public alMessage(String text) + { + super("", "", null, null); + + if(text == null || text.length() == 0) // копирование переименование удаление без ошибок + { + setType(AlertType.INFO); + setImage(images.getAlertIcon(AlertType.INFO)); + setTitle(Locale.getString(this, Locale.DONE)); + setString(Locale.getString(this, Locale.OPERATION_OK)); + + ok = true; + } + else + { + setType(AlertType.ERROR); + setImage(images.getAlertIcon(AlertType.ERROR)); + setTitle(Locale.getString(this, Locale.ERROR)); + setString(text); + + ok = false; + } + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + setCommandListener(this); + + t = new Thread(this, "Message/Delay"); + t.start(); + } + + public void run() + { + if(ok) + { + try + { + Thread.sleep(1500); + } + catch(InterruptedException ie) + { + } + + main.FileSelect.showWait(main.currentFile); // переход + } + } + + public void commandAction(Command command, Displayable displayable) + { + if(command.getCommandType() == Command.OK) + { + t.interrupt(); // прерываем таймер выше, там будет переход + + if(!ok) + { + main.FileSelect.showWait(main.currentFile); + } + } + } +} diff --git a/src/filemanager/cvsContextMenu.java b/src/filemanager/cvsContextMenu.java new file mode 100644 index 0000000..e2e328b --- /dev/null +++ b/src/filemanager/cvsContextMenu.java @@ -0,0 +1,552 @@ +package filemanager; + +import com.one.PaintableObject; +import javax.microedition.lcdui.*; +import com.vmx.*; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class cvsContextMenu extends gkcCanvas +{ + protected Object parent; + + protected MenuListener listen; + + protected int w, h; + protected int sel1, sel2; + + protected int mw1, mw2, mh1, mh2; // width & height Ð´Ð»Ñ Ð¼ÐµÐ½ÑŽ и подменю + protected int mx1, mx2, my1, my2; // положение меню и подменю + + protected Font mf; // шрифт меню + protected int mfh; // выÑота шрифта + protected int mlh; // выÑота Ñтроки меню + protected FontWidthCache mfwc; // кÑш ширины шрифта %))) + + protected int[][] menu; + protected int[][] keyConfig; + protected boolean[] keyAllowed; + + protected boolean enabled[][]; + protected int keyHeld; + + /** КонÑтруктор */ + public cvsContextMenu(int[][] menu, int[][] keyConfig, boolean[] keyAllowed) + { + this.menu = menu; + this.keyConfig = keyConfig; + this.keyAllowed = keyAllowed; + + sel1 = 0; + sel2 = -1; + + setFullScreenMode(true); + + w = getWidth(); + h = getHeight(); + + mf = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); + mfh = mf.getHeight() + 1; + mfwc = FontWidthCache.getCache(mf); + + //mlh = main.max(images.iconHeight + 1, mfh); + mlh = mfh; + + // ПодÑчёт требуемой ширины и выÑоты меню ... + int i, j, tt; + int add = mfwc.stringWidth(" 0+"); + int add1 = mfwc.stringWidth(" >"); + + for(mw1 = 0, i = 0, tt = 0; i < menu.length; i++) + { + tt = mfwc.stringWidth(Locale.getString(this, menu[i][0])) + add1; + + if(tt > mw1) + { + mw1 = tt; + } + } + + mw1 += 4; // по 1 на рамку + по 1 отÑтуп + mh1 = mlh * menu.length + 3; // по 1 на рамку + 1 отÑтуп Ñверху, отÑтуп Ñнизу учтен в mfh + + //mx1 = 7; + //my1 = h - mh1 - 7; + mx1 = my1 = 7; + + // ... и подменю + for(mw2 = 0, i = 0, tt = 0; i < menu.length; i++) + { + for(j = 1; j < menu[i].length; j++) + { + tt = mfwc.stringWidth(Locale.getString(this, menu[i][j])) + add; + + if(tt > mw2) + { + mw2 = tt; + } + } + } + + //mw2 += images.iconWidth + 5; // по 1 на рамку + по 1 на отÑтуп + 1 между значком и текÑтом + mw2 += 4; // по 1 на рамку + по 1 на отÑтуп + mh2 = -1; + //mx2 = 14; + + if(mx1 + mw1 + mw2 > w) + { + mx2 = w - mw2; + } + else + { + mx2 = mx1 + mw1 - 1; + } + + //mw1 = main.max(mw1, mw2); + + // а также Ñоздаём и заполнÑем enabled + enabled = new boolean[menu.length][]; + + for(i = 0; i < menu.length; i++) + { + enabled[i] = new boolean[menu[i].length]; + + for(j = 0; j < menu[i].length; j++) + { + enabled[i][j] = true; + } + } + } + + public void setListener(MenuListener listen) + { + this.listen = listen; + } + + public void setEnabledFlags(boolean[][] enabledFlags) + { + for(int i = 0; i < enabled.length; i++) + { + System.arraycopy(enabledFlags[i], 0, enabled[i], 0, enabledFlags[i].length); + } + + for(int i = 0; i < enabled.length; i++) + { + enabled[i][0] = false; + + for(int j = 1; j < enabled[i].length; j++) + { + if(enabled[i][j]) + { + enabled[i][0] = true; + break; + } + } + } + } + + public void show(Object parent) + { + this.parent = parent; + + sel1 = 0; + sel2 = -1; + + main.dsp.setCurrent(this); + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð¸Ñовки + */ + public void paint(Graphics g) + { + if(parent instanceof PaintableObject) + { + ((PaintableObject)parent).paint(g); + g.setClip(0, 0, w, h); + } + else + { + images.drawVGradient(g, ColorScheme.colors[ColorScheme.mnback1], ColorScheme.colors[ColorScheme.mnback2], 0, 0, w, h, options.ditherGradients, options.alphaGradients); + } + + g.setColor(ColorScheme.colors[ColorScheme.mnback1]); + + images.drawVGradient(g, ColorScheme.colors[ColorScheme.mnback1], ColorScheme.colors[ColorScheme.mnback2], mx1, my1, mw1, mh1, options.ditherGradients, options.alphaGradients); + + g.setColor(ColorScheme.colors[ColorScheme.dkborder]); + g.drawRect(mx1, my1, mw1 - 1, mh1 - 1); + g.setFont(mf); + + // ОтриÑовка меню + for(int i = 0; i < menu.length; i++) + { + if(enabled[i][0]) + { + if(i == sel1) + { + g.setColor(ColorScheme.colors[ColorScheme.mnselback1]); + + if(options.frameCursor) + { + g.drawRect(mx1 + 1, my1 + 1 + i * mlh, mw1 - 3, mlh); + } + else + { + images.drawHGradient(g, ColorScheme.colors[ColorScheme.mnselback1], ColorScheme.colors[ColorScheme.mnselback2], mx1 + 1, my1 + 1 + i * mlh, mw1 - 2, mlh + 1, options.ditherGradients, options.alphaGradients); + } + + g.setColor(ColorScheme.colors[ColorScheme.mnselfore]); + g.drawString(Locale.getString(this, menu[i][0]), mx1 + 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + } + else + { + g.setColor(ColorScheme.colors[ColorScheme.mnfore]); + g.drawString(Locale.getString(this, menu[i][0]), mx1 + 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + g.setColor(ColorScheme.colors[ColorScheme.mnaltfore]); + } + } + else + { + g.setColor(ColorScheme.colors[ColorScheme.disabled]); + g.drawString(Locale.getString(this, menu[i][0]), mx1 + 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + } + + g.drawChar('>', mx1 + mw1 - 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.RIGHT | Graphics.TOP); + } + + // ЕÑли отображено подменю - риÑуем его + if(sel2 >= 0) + { + int m2l = menu[sel1].length - 1; + + mh2 = m2l * mlh + 3; + //my2 = my1 + 2 + sel1 * mlh + mlh / 2; + my2 = my1 + sel1 * mlh; + + if(my2 + mh2 > h - 14) + { + my2 = h - mh2 - 14; + } + + if(my2 < 0) + { + my2 = 0; + } + + g.setColor(ColorScheme.colors[ColorScheme.mnback1]); + + images.drawVGradient(g, ColorScheme.colors[ColorScheme.mnback1], ColorScheme.colors[ColorScheme.mnback2], mx2, my2, mw2, mh2, options.ditherGradients, options.alphaGradients); + + g.setColor(ColorScheme.colors[ColorScheme.dkborder]); + g.drawRect(mx2, my2, mw2 - 1, mh2 - 1); + + for(int i = 0; i < m2l; i++) + { + if(enabled[sel1][i + 1]) + { + if(i == sel2) + { + g.setColor(ColorScheme.colors[ColorScheme.mnselback1]); + + if(options.frameCursor) + { + g.drawRect(mx2 + 1, my2 + 1 + i * mlh, mw2 - 3, mlh); + } + else + { + images.drawHGradient(g, ColorScheme.colors[ColorScheme.mnselback1], ColorScheme.colors[ColorScheme.mnselback2], mx2 + 1, my2 + 1 + i * mlh, mw2 - 2, mlh + 1, options.ditherGradients, options.alphaGradients); + } + + g.setColor(ColorScheme.colors[ColorScheme.mnselfore]); + g.drawString(Locale.getString(this, menu[sel1][i + 1]), mx2 + 2, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + } + else + { + g.setColor(ColorScheme.colors[ColorScheme.mnfore]); + g.drawString(Locale.getString(this, menu[sel1][i + 1]), mx2 + 2, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + g.setColor(ColorScheme.colors[ColorScheme.mnaltfore]); + } + } + else + { + g.setColor(ColorScheme.colors[ColorScheme.disabled]); + g.drawString(Locale.getString(this, menu[sel1][i + 1]), mx2 + 2, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + } + + //images.drawIcon(g, menu[sel1][i * 2 + 2], mx2 + 2, my2 + 2 + i * mlh + (mlh - images.iconHeight) / 2); + + if(keyConfig[sel1][i] != KEY_INVALID) + { + g.drawChars(keyToChar(keyConfig[sel1][i]), 0, 2, mx2 + mw2 - 2, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.RIGHT | Graphics.TOP); + } + } + } + } + + protected static char[] chs = new char[2]; + + public static char[] keyToChar(int keyCode) + { + if((keyCode & KEY_HELD) != 0) + { + chs[0] = (char)(keyCode & ~KEY_HELD); + chs[1] = '+'; + } + else + { + chs[0] = ' '; + chs[1] = (char)keyCode; + } + + return chs; + } + + /** Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ðº предыдущему Ñкрану (к parent) */ + public void ret() + { + if(parent != null) + { + if(main.dsp.getCurrent() != parent) + { + main.dsp.setCurrent(parent); + } + + parent = null; + } + } + + /** + * Обработчик нажатий клавиш. + * Формально здеÑÑŒ обрабатываетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ джойÑтик, + * но из keyReleased могут быть транÑлированы + * Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ Ñ†Ð¸Ñ„Ñ€Ð¾Ð²Ñ‹Ñ… клавиш как джойÑтика. + */ + public void keyPressed(int keyCode) + { + int osel, ml; + + if(options.swapSoftKeys) + { + if(keyCode == KEY_LSK) + { + keyCode = KEY_RSK; + } + else if(keyCode == KEY_RSK) + { + keyCode = KEY_LSK; + } + } + + if(keyCode == KEY_DOWN) + { + if(sel2 == -1) // гулÑем по меню + { + osel = sel1; + ml = menu.length; + + do + { + sel1 = (sel1 + 1) % ml; + } + while(!enabled[sel1][0] && sel2 != osel); + } + else // гулÑем по подменю + { + osel = sel2; + ml = menu[sel1].length - 1; + + do + { + sel2 = (sel2 + 1) % ml; + } + while(!enabled[sel1][1 + sel2] && sel2 != osel); + } + + repaint(); + } + else if(keyCode == KEY_UP) + { + if(sel2 == -1) // гулÑем по меню + { + osel = sel1; + ml = menu.length; + + do + { + sel1 = (sel1 - 1 + ml) % ml; + } + while(!enabled[sel1][0] && sel2 != osel); + } + else // гулÑем по подменю + { + osel = sel2; + ml = menu[sel1].length - 1; + + do + { + sel2 = (sel2 - 1 + ml) % ml; + } + while(!enabled[sel1][1 + sel2] && sel2 != osel); + } + + repaint(); + } + else if(keyCode == KEY_LSK || + keyCode == KEY_LEFT || + keyCode == KEY_CANCEL) + { + if(sel2 == -1) + { + ret(); + } + else + { + sel2 = -1; + repaint(); + } + } + else if(keyCode == KEY_FIRE || + keyCode == KEY_RIGHT || + keyCode == KEY_RSK || + keyCode == KEY_DIAL) + { + if(sel2 == -1) + { + sel2 = 0; + + while(!enabled[sel1][1 + sel2]) + { + sel2++; + } + + repaint(); + } + else if(listen != null) + { + listen.menuAction(menu[sel1][1 + sel2]); + } + } + } + + /** + * Обработчик повторений клавиш. + * ЕÑли нажатую клавишу можно иÑпользовать в качеÑтве горÑчей, + * то ждем трехкратного ÑƒÐ´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ Ð¸ переназначаем. + * ЕÑли нельзÑ, то обрабатываем Ñто как обычные нажатиÑ. + */ + public void keyRepeated(int keyCode) + { + if(isKeyAllowed(keyCode)) + { + if(++keyHeld == 3) + { + keyConfig[sel1][sel2] = keyCode; + repaint(); + } + else if(keyHeld == 7) + { + keyConfig[sel1][sel2] |= KEY_HELD; + repaint(); + } + } + else + { + keyPressed(translateKey(keyCode)); + } + } + + /** + * Обработка отпуÑÐºÐ°Ð½Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ. + * ЕÑли отпуÑтили цифровую клавишу и не было удержаниÑ, + * то транÑлируем ее к джойÑтику и передаем keyPressed. + */ + public void keyReleased(int keyCode) + { + if(keyHeld < 3) + { + if(isKeyNum(keyCode)) + { + keyPressed(translateKey(keyCode)); + } + } + else + { + for(int i = 0; i < keyConfig.length; i++) + { + for(int j = 0; j < keyConfig[i].length; j++) + { + if(keyConfig[i][j] == keyConfig[sel1][sel2] && !(i == sel1 && j == sel2)) + { + keyConfig[i][j] = KEY_INVALID; + } + } + } + + repaint(); + } + + keyHeld = 0; + } + + /** + * Совершить дейÑтвие, которое назначено + * Ð´Ð»Ñ Ð½ÐµÐºÐ¾Ñ‚Ð¾Ñ€Ð¾Ð¹ горÑчей клавиши + * Ð´Ð»Ñ Ð½ÐµÐºÐ¾Ñ‚Ð¾Ñ€Ð¾Ð³Ð¾ типа меню. + * ЕÑли получилоÑÑŒ, возвращаетÑÑ true. + */ + public boolean keyAction(int keyCode) + { + for(int i = 0; i < keyConfig.length; i++) + { + for(int j = 0; j < keyConfig[i].length; j++) + { + if(keyConfig[i][j] == keyCode) + { + listen.menuAction(menu[i][j + 1]); + return true; + } + } + } + + return false; + } + + /** + * Можно ли данную клавишу в данном меню + * иÑпользовать в качеÑтве горÑчей. + */ + public boolean isKeyAllowed(int keyCode) + { + return (keyCode == KEY_STAR && keyAllowed[0]) || + (keyCode == KEY_POUND && keyAllowed[1]) || + (keyCode >= KEY_NUM0 && keyCode <= KEY_NUM9 && keyAllowed[keyCode - KEY_NUM0 + 2]); + } + + public static void readKeyConfig(int[][] keyConfig, DataInputStream dis) throws IOException + { + int i, j; + + for(i = 0; i < keyConfig.length; i++) + { + for(j = 0; j < keyConfig[i].length; j++) + { + keyConfig[i][j] = dis.readInt(); + } + } + } + + public static void writeKeyConfig(int[][] keyConfig, DataOutputStream dos) throws IOException + { + int i, j; + + for(i = 0; i < keyConfig.length; i++) + { + for(j = 0; j < keyConfig[i].length; j++) + { + dos.writeInt(keyConfig[i][j]); + } + } + } +} \ No newline at end of file diff --git a/src/filemanager/cvsFileSelect.java b/src/filemanager/cvsFileSelect.java new file mode 100644 index 0000000..d6ad0f8 --- /dev/null +++ b/src/filemanager/cvsFileSelect.java @@ -0,0 +1,1741 @@ +package filemanager; // переведен + +import modules.text.cvsTextView; +import java.util.*; +import javax.microedition.lcdui.*; +import com.vmx.*; +import com.one.*; +import com.one.file.Connector; +import com.one.file.TransparentConnector; +import com.one.vector.AuxMath; +import java.io.IOException; + +public class cvsFileSelect extends gkcCanvas implements Runnable, CommandListener +{ +// protected static final FileItem PARENT_DIR = new FileItem("..", images.getIcon(images.iUp)); +// protected static final FileItem FAVOURITES = new FileItem(Locale.getString(this, Locale.FAVOURITES), images.getIcon( + + /** Данные ÑпиÑка */ + private String title; + private Vector items; + + /** Фильтры */ + private StringPattern tmpfilter; + + /** Ð’Ñпомогательные данные */ + private int scrStart, scrSel, scrLen; + private int w, h, allh, fileH, header, footer; + private int skw, firew; // меÑто, отводимое под надпиÑи над Ñофт - кнопками и джойÑтиком + private boolean fsmode; // полноÑкранный режим + private Font mf, mfro, mfhn, mfrh, fd; + private FontWidthCache fcd; // кÑши ширины шрифтов %) + private int fdh; + private boolean lskp = false, rskp = false, firep = false; // Ð´Ð»Ñ Ð¼Ð¸Ð³Ð°Ð½Ð¸Ñ + //boolean markMode = false; + private int markCount = 0; + private int keyHeld = 0; + private boolean keyReleaseAllowed = false; + private boolean hotKeyMode = false; + private boolean isshown; + private List modlist; + private int fireIcon; + + private int ofnw, ofnx, ofnstep, ofndelay; // прокрутка длинных имен + private int OFN_DEF_DELAY; + private Thread t; + protected LineEffect lfx; + + protected final Object waiter = new Object(); + + private Image background, cursor; + private Image offscreen; + private Graphics offgraphics; + private boolean repaints; + + /** + * ЗапуÑк реÑкана каталога через cvsWait + */ + public void showWait() + { + cvsWait.start(this); + } + + /** + * ЗапуÑк реÑкана каталога через cvsWait, поÑле реÑкана надо выбрать + * файл selectAfter + */ + public void showWait(String selectAfter) + { + cvsWait.start(this, selectAfter); + } + + /** + * Показ буфера обмена + */ + public void showBuffer() + { + main.oldPath = main.currentPath; + main.oldFile = ((FileItem)items.elementAt(scrSel)).getName(); // files[scrSel]; + + main.currentPath = "buf:/"; + showWait(); + } + + private Command cmdOpen = new Command(Locale.getString(this, Locale.OPEN_CMD), Command.ITEM, 1); + private Command cmdAssign = new Command(Locale.getString(this, Locale.ASSIGN_CMD), Command.OK, 2); + private Command cmdReset = new Command(Locale.getString(this, Locale.RESET_CMD), Command.OK, 3); + private Command cmdCancel = new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 4); + + /** + * КонÑтруктор + */ + public cvsFileSelect() + { + setFullScreenMode(true); + + int fsize = options.largeFontInList ? Font.SIZE_MEDIUM : Font.SIZE_SMALL; + + mf = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, fsize); + mfro = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, fsize); + mfhn = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_ITALIC, fsize); + mfrh = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD | Font.STYLE_ITALIC, fsize); + + fd = Font.getDefaultFont(); + fcd = FontWidthCache.getCache(fd); + fdh = fd.getHeight(); + + title = ""; + items = new Vector(); + + tmpfilter = new StringPattern("~*.tmp", true); + + fsmode = false; + repaints = true; + updateLayout(); + + modlist = new List(Locale.getString(null, Locale.MODULES_CMD), Choice.IMPLICIT); + + updateModuleList(); + + modlist.addCommand(cmdOpen); + + modlist.setSelectCommand(cmdOpen); + modlist.removeCommand(List.SELECT_COMMAND); + + modlist.addCommand(cmdAssign); + modlist.addCommand(cmdReset); + modlist.addCommand(cmdCancel); + + modlist.setCommandListener(this); + + findFireIcon(); + } + + public void updateLayout() + { + setFullScreenMode(true); + + w = getWidth(); + h = allh = getHeight(); + + fileH = Math.max(images.iconHeight, mf.getHeight()); + + offscreen = Image.createImage(w, allh); + offgraphics = offscreen.getGraphics(); + + initFSMode(fsmode); + + lfx = new LineEffect(1, 1, w - 2, allh - 2); + } + +// public void updateGradients() +// { +// Graphics g; +// +// if(options.ditherGradients) +// { +// if(!options.alphaGradients || (images.isColorOpaque(ColorScheme.colors[ColorScheme.back1]) && images.isColorOpaque(ColorScheme.colors[ColorScheme.back2]))) +// { +// background = Image.createImage(w, allh); +// g = background.getGraphics(); +// images.drawVGradient(g, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, w, allh, true, false); +// } +// else +// { +// background = null; +// } +// +// if(!options.alphaGradients || (images.isColorOpaque(ColorScheme.colors[ColorScheme.selback1]) && images.isColorOpaque(ColorScheme.colors[ColorScheme.selback2]))) +// { +// cursor = Image.createImage(w - 3, fileH); +// g = cursor.getGraphics(); +// images.drawHGradient(g, ColorScheme.colors[ColorScheme.selback1], ColorScheme.colors[ColorScheme.selback2], 0, 0, w - 3, fileH, true, false); +// } +// else +// { +// cursor = null; +// } +// } +// else +// { +// background = null; +// cursor = null; +// } +// } + + public void updateModuleList() + { + modlist.deleteAll(); + + Enumeration modules = ModuleRegistry.listModules(); + String module; + + while(modules.hasMoreElements()) + { + module = (String)modules.nextElement(); + modlist.append(ModuleRegistry.getModuleName(module), ModuleRegistry.getIcon(module)); + } + } + + /** + * Получить вÑе Ñлементы ÑпиÑка + */ + public Enumeration elements() + { + return items.elements(); + } + + /** + * Получить один Ñлемент из ÑпиÑка + */ + public FileItem getFileItem(int index) + { + return (FileItem)items.elementAt(index); + } + + public int getSelectedIndex() + { + return scrSel; + } + + public int getMarkCount() + { + return markCount; + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ ÑпиÑка - по возможноÑти поÑле Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ + * выберетÑÑ Ñ„Ð°Ð¹Ð»/папка/диÑк selectAfter + */ + public void list(String selectAfter) + { + repaints = false; + markCount = -1; + + if(main.currentPath.length() == 0) + { + listDrives(selectAfter); + } + else if(main.currentPath.equals("fav:/")) + { + listFavorites(selectAfter); + } + else if(main.currentPath.equals("null:/")) + { + listBucket(); + } + else if(main.currentPath.equals("buf:/")) + { + listBuffer(); + } + else + { + int index; + + while(!listFiles(selectAfter)) + { + main.currentPath = main.currentPath.substring(0, main.currentPath.length() - 1); + index = main.currentPath.lastIndexOf('/'); + + if(index >= 0) + { + main.currentPath = main.currentPath.substring(0, index); + } + else + { + main.currentPath = ""; + } + + if(main.currentPath.length() > 0) + { + main.currentPath += '/'; + } + else + { + listDrives(selectAfter); + break; + } + } + } + + repaints = true; + + lskp = rskp = firep = false; + select(scrSel); + + synchronized(waiter) + { + waiter.notifyAll(); + } + } + + /** Удаление из ÑпиÑка файла #x */ + public void delete(int x) + { + if(x < 1 || x >= items.size()) + { + return; + } + + items.removeElementAt(x); + + select(scrSel); + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ ÑпиÑка диÑков + */ + public void listDrives(String selectAfter) + { + title = Locale.getString(this, Locale.SELECT_DRIVE); + + items.removeAllElements(); + + scrStart = 0; + scrSel = 0; + + Enumeration roots = filesystem.listRoots(); + String s; + + if(roots != null) + { + while(roots.hasMoreElements()) + { + s = (String)roots.nextElement(); + items.addElement(new FileItem(s, images.getIcon(images.iDisk))); + + if(s.equals(selectAfter)) + { + scrSel = items.size() - 1; + } + } + } + + if(Buffer.getSize() > 0) + { + items.addElement(new FileItem(Locale.getString(this, Locale.BIT_BUCKET), images.getIcon(images.iFavorites))); + + if("null:/".equals(selectAfter) || Locale.getString(this, Locale.BIT_BUCKET).equals(selectAfter)) + { + scrSel = items.size() - 1; + } + } + else + { + items.addElement(new FileItem(Locale.getString(this, Locale.FAVOURITE), images.getIcon(images.iFavorites))); + + if("fav:/".equals(selectAfter) || Locale.getString(this, Locale.FAVOURITE).equals(selectAfter)) + { + scrSel = items.size() - 1; + } + } + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ ÑпиÑка файлов + */ + public boolean listFiles(String selectAfter) + { + Enumeration files = filesystem.list(main.currentPath, options.showHidden); + String filename; + + if(files == null) + { + return false; + } + + title = getLastPartOfString(main.currentPath, w - images.iconWidth - 6 - fcd.stringWidth(AuxClass.getCurrentTime())); // Integer.toString(panels.length)) - 3); + + items.removeAllElements(); + + items.addElement(new FileItem("..", images.getIcon(images.iUp))); + + while(files.hasMoreElements()) + { + filename = (String)files.nextElement(); + + if(!(tmpfilter.matchesWith(filename) && Connector.isTempFileUsed(main.currentPath + filename))) + { + items.addElement(new FileItem(main.currentPath, filename, false)); + } + } + + if(options.listSortBy > 0) + { + FileItem.sortFileList(items, options.listSortBy, options.listSortIgnoreCase, !options.listSortReverseOrder, 1, items.size() - 1); + } + + scrStart = 0; + scrSel = 1; + + if(selectAfter != null && selectAfter.length() > 0) + { + for(int i = 1; i < items.size(); i++) + { + if(((FileItem)items.elementAt(i)).getDisplayName().equals(selectAfter)) + { + scrSel = i; + break; + } + } + } + + return true; + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ ÑпиÑка "Избранное" + */ + public void listFavorites(String selectAfter) + { + Enumeration files = options.getFavorites(); + + title = Locale.getString(this, Locale.FAVOURITE); + + items.removeAllElements(); + + scrStart = 0; + scrSel = 1; + + items.addElement(new FileItem("..", images.getIcon(images.iUp))); + + while(files.hasMoreElements()) + { + items.addElement(new FileItem((String)files.nextElement(), options.fullNamesInFav)); + } + + if(options.listSortBy > 0) + { + FileItem.sortFileList(items, options.listSortBy, options.listSortIgnoreCase, !options.listSortReverseOrder, 1, items.size() - 1); + } + + if(selectAfter != null && selectAfter.length() > 0) + { + for(int i = 1; i < items.size(); i++) + { + if(((FileItem)items.elementAt(i)).getDisplayName().equals(selectAfter)) + { + scrSel = i; + break; + } + } + } + } + + public void listBucket() + { + title = Locale.getString(this, Locale.BIT_BUCKET); + + items.removeAllElements(); + + scrStart = 0; + scrSel = 1; + + items.addElement(new FileItem("..", images.getIcon(images.iUp))); + } + + public void listBuffer() + { + Enumeration files = Buffer.getBuffer(); + + title = Locale.getString(this, Locale.BUFFER); + + items.removeAllElements(); + + scrStart = 0; + scrSel = 1; + + items.addElement(new FileItem("..", images.getIcon(images.iUp))); + + while(files.hasMoreElements()) + { + items.addElement(new FileItem((String)files.nextElement(), options.fullNamesInBuf)); + } + + /* + if(options.listSortBy > 0) + { + FileItem.sortFileList(items, options.listSortBy, true, 1, items.size() - 1); + } + */ + } + + /** + * Обновить тип файла #i + */ + public void updateFileType(int i) + { + if(i < 1 || i >= items.size() || main.currentPath.length() == 0) + { + return; + } + + ((FileItem)items.elementAt(i)).updateFileType(); + } + + /** + * Обновить Ð¸Ð¼Ñ (в ÑпиÑке) файла #i. + * Тип здеÑÑŒ обновлÑетÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки. + */ + public void updateFileName(String newname, int i) + { + if(i < 1 || i >= items.size() || main.currentPath.length() == 0) + { + return; + } + + boolean flag = false; + + if("fav:/".equals(main.currentPath)) + { + flag = options.fullNamesInFav; + } + else if("buf:/".equals(main.currentPath)) + { + flag = options.fullNamesInBuf; + } + + items.setElementAt(new FileItem(main.currentPath, newname, flag), i); + } + + /** + * Ð˜Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ€ÐµÐ¶Ð¸Ð¼Ð° Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸Ñ + */ + public void startMarkMode() + { + for(Enumeration e = items.elements(); e.hasMoreElements(); ((FileItem)e.nextElement()).setMarked(false)); + markCount = 0; + } + + /** + * Пометить выбранный + */ + public void markSelected() + { + if(main.currentPath.length() > 0) + { + if(markCount < 0) + { + startMarkMode(); + } + + if(scrSel > 0) + { + FileItem item = (FileItem)items.elementAt(scrSel); + + if(item.isMarked()) + { + item.setMarked(false); + markCount--; + } + else + { + item.setMarked(true); + markCount++; + } + } + + // когда Ñнимаем выделение Ñ Ð¿Ð¾Ñледнего файла, + // выключаем режим Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸Ñ + if(markCount == 0) + { + markCount = -1; + } + else + { + select(scrSel + 1); + } + + repaint(); + } + } + + /** + * Пометить вÑе + */ + public void markAll() + { + if(main.currentPath.length() > 0) + { + if(markCount < 0) + { + startMarkMode(); + } + + for(Enumeration e = items.elements(); e.hasMoreElements(); ((FileItem)e.nextElement()).setMarked(true)); + markCount = items.size() - 1; + + repaint(); + } + } + + /** + * СброÑить вÑе отметки. + * При Ñтом автоматичеÑки выключаетÑÑ Ñ€ÐµÐ¶Ð¸Ð¼ выделениÑ. + */ + public void demarkAll() + { + if(markCount >= 0) + { + for(Enumeration e = items.elements(); e.hasMoreElements(); ((FileItem)e.nextElement()).setMarked(false)); + markCount = -1; + + repaint(); + } + } + + /** + * Перемещение по дереву каталогов вверх, переключение на меню + * выбора диÑков или Избранное, или выход из программы наффик + */ + public void upDir() + { + if(main.currentPath.length() == 0) + { + if(options.exitFromDriveList) + { + main.destroyApp(); + } + + return; + } + + int sindex, pindex; + String str = null; + + if(main.currentPath.equals("fav:/")) + { + str = "fav:/"; + main.currentPath = ""; + } + else if(main.currentPath.equals("buf:/")) + { + str = main.oldFile; + main.currentPath = main.oldPath; + } + else + { + str = main.currentPath.substring(0, main.currentPath.length() - 1); + sindex = str.lastIndexOf('/') + 1; + + if(sindex > 0) + { + str = main.currentPath.substring(sindex); + pindex = str.lastIndexOf('.') + 1; + + if(pindex > 0 && ModuleRegistry.getAction(str.substring(pindex, str.length() - 1)) == ModuleRegistry.ACTION_EXPLORE) + { + str = str.substring(0, str.length() - 1); + } + + main.currentPath = main.currentPath.substring(0, sindex); + } + else + { + str = main.currentPath; + main.currentPath = ""; + } + } + + showWait(str); + } + + /** + * Выбор текущего файла из ÑпиÑка. + * ПроÑмотр файла запуÑкаетÑÑ Ð² текущей панели. + */ + public void selectFile() + { + prevpath = main.currentPath; + + if(main.currentFile.equals("..")) + { + // еÑли выбрано .. или Ðазад переходим по папке вверх + upDir(); + return; + } + + FileItem item = (FileItem)items.elementAt(scrSel); + + main.currentPath = item.getPath(); + main.currentFile = item.getName(); + + if(main.currentPath.length() == 0) + { + if(main.currentFile.equals(Locale.getString(this, Locale.FAVOURITE))) + { + main.currentFile = "fav:/"; + } + else if(main.currentFile.equals(Locale.getString(this, Locale.BIT_BUCKET))) + { + main.currentFile = "null:/"; + } + else + { + int index = main.currentFile.lastIndexOf('/') + 1; + + if(index > 0) + { + main.currentFile = main.currentFile.substring(0, index); + } + else + { + main.currentFile += '/'; + } + } + } + + if(main.currentFile.charAt(main.currentFile.length() - 1) == '/') + { + // еÑли выбранный файл Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ñ‚Ð¾ входим в нее + main.currentPath = main.currentPath + main.currentFile; + showWait(); + } + else + { + // Рчто, вообще-то, Ñ Ñ‚Ð°ÐºÐ¸Ð¼Ð¸ файлами делают? + int action = ModuleRegistry.getAction(main.currentFile.substring(main.currentFile.lastIndexOf('.') + 1)); + + if(action == ModuleRegistry.ACTION_EXPLORE) + { + // Открываем файл как папку (архив) + main.currentPath = main.currentPath + main.currentFile + "/"; + showWait(); + } + else + { + // Открываем файл как именно файл + executeFile(main.currentPath + main.currentFile); + } + } + } + + /** + * ЗапуÑтить поÑмотр файла filename. + * При Ñтом формируетÑÑ ÑпиÑок из файлов, Ð´Ð»Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… иÑпользуетÑÑ Ñ‚Ð¾Ñ‚ же модуль. + */ + public void executeFile(String filename) + { + PlayList playlist = new PlayList(filesystem.listFilesOfType(filename, null, options.showHidden)); + + playlist.selectElement(filename); + playlist.waitForElementFound(); + + executeFile(playlist, null, main.manager.currentPanel()); + } + + /** + * ЗапуÑтить проÑмотр текущего файла из ÑпиÑка filelist, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð¼Ð¾Ð´ÑƒÐ»ÑŒ module. + * ЕÑли вмеÑто Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‚ÑŒ null, модуль определÑетÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки по раÑширению. + */ + public void executeFile(PlayList filelist, String module, int panel) + { + String filename = filelist.getCurrentElement(); + String ext = filename.substring(filename.lastIndexOf('.') + 1); + + if(panel == main.manager.currentPanel()) + { + select(filename); + } + + // Рчто, вообще-то, Ñ Ñ‚Ð°ÐºÐ¸Ð¼Ð¸ файлами делают? + int action = ModuleRegistry.getAction(module != null ? module : ext); + + if(action == ModuleRegistry.ACTION_OPEN) + { + if(module == null) + { + module = ModuleRegistry.getModule(ext); + } + + try + { + ((Application)ModuleRegistry.getModuleInstance(module)).openFile(filename, filelist); + } + catch(Exception e) + { + ErrScreen.showErrMsg(122, e); + } + + main.manager.setPanelName(panel, ModuleRegistry.getModuleName(module)); + } + else if(options.openNotSupported && AuxClass.classExists(main.TEXT_VIEW_CLASS)) + { + cvsTextView.getInstance().openFile(filename); + } + else + { + //main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.FORMAT_NOT_SUPP), AlertType.WARNING, 3000, this); + showModuleList(); + } + } + + public void commandAction(Command c, Displayable dp) + { + if(dp == modlist) + { + main.dsp.setCurrent(this); + + if(c == cmdOpen || c == List.SELECT_COMMAND) + { + String module = ModuleRegistry.getModule(modlist.getSelectedIndex()); + + if(ModuleRegistry.getAction(module) == ModuleRegistry.ACTION_OPEN) + { + executeFile(new PlayList(main.currentPath + main.currentFile), module, main.manager.currentPanel()); + } + else + { + associateAndSelect(module, false); + } + } + else if(c == cmdAssign) + { + associateAndSelect(ModuleRegistry.getModule(modlist.getSelectedIndex()), true); + } + else if(c == cmdReset) + { + associateAndSelect(null, true); + } + } + } + + /** + * СвÑзать файл, заданный main.currentPath и main.currentFile + * Ñ Ð¼Ð¾Ð´ÑƒÐ»ÐµÐ¼ module и выбрать его через selectFile(). + */ + public void associateAndSelect(String module, boolean all) + { + int index = main.currentFile.lastIndexOf('.') + 1; + String ext; + + if(index > 0) + { + ext = main.currentFile.substring(index); + } + else + { + ext = main.currentPath + main.currentFile; + } + + String prev = ModuleRegistry.associate(ext, module, all); + + if(all) + { + Enumeration files = items.elements(); + + while(files.hasMoreElements()) + { + ((FileItem)files.nextElement()).invalidate(); + } + } + + try + { + TransparentConnector.closeContainer(main.currentPath + main.currentFile); + } + catch(IOException x) + { + x.printStackTrace(); + } + + if(module != null) + { + synchronized(waiter) + { + selectFile(); + + if(!all) + { + try + { + waiter.wait(); + } + catch(InterruptedException ie) + { + } + + ModuleRegistry.associate(ext, prev, all); + } + } + } + } + + public void showModuleList() + { + main.dsp.setCurrent(modlist); + } + + /** + * Показать меню + */ + public void showMenu() + { + setMenuType(main.menu); + + main.menu.parent = this; + main.dsp.setCurrent(main.menu); + } + + public void setMenuType(cvsMenu menu) + { + int menuType; + + if(main.currentPath.length() > 0) + { + if(main.currentPath.equals("fav:/")) + { + menuType = cvsMenu.MENU_FAVORITES_SELECTED; + } + else if(main.currentPath.equals("null:/")) + { + menuType = cvsMenu.MENU_BUCKET_SELECTED; + } + else if(main.currentPath.equals("buf:/")) + { + menuType = cvsMenu.MENU_BUFFER_SELECTED; + } + else if(TransparentConnector.hasOpenContainer(main.currentPath)) + { + menuType = cvsMenu.MENU_INSIDE_ARCHIVE; + } + else + { + if("..".equals(main.currentFile)) + { + menuType = cvsMenu.MENU_DOTDOT_SELECTED; + } + else + { + if(filesystem.isDir(main.currentPath + main.currentFile)) + { + menuType = cvsMenu.MENU_FOLDER_SELECTED; + } + else + { + menuType = cvsMenu.MENU_FILE_SELECTED; + } + } + } + } + else // if (!Locale.getString(this, Locale.FAVOURITE).equals (main.currentFile)) // выбран диÑк + { + menuType = cvsMenu.MENU_DISK_SELECTED; + } + //else menuType = cvsMenu.MENU_FAVORITES_SELECTED; + + menu.setType(menuType); + } + + /** + * Выбрать Ñлемент, заданный полным именем. + */ + public void select(String filename) + { + FileItem item; + + for(int i = 0; i < items.size(); i++) + { + item = (FileItem)items.elementAt(i); + + if(item.getFullName().equals(filename)) + { + select(i); + break; + } + } + } + + /** + * Выбрать файл #index + */ + public void select(int index) + { + scrSel = index; + + if(scrSel >= items.size()) + { + scrSel = items.size() - 1; + } + + scrStart = scrSel - scrLen / 2; + + if(scrStart + scrLen >= items.size()) + { + scrStart = items.size() - scrLen; + } + + if(scrStart < 0) + { + scrStart = 0; + } + + FileItem item = (FileItem)items.elementAt(scrSel); + main.currentFile = item.getName(); + + if(item.isReadOnly()) + { + if(item.isHidden()) + { + ofnw = mfrh.stringWidth(item.getDisplayName()); + } + else + { + ofnw = mfro.stringWidth(item.getDisplayName()); + } + } + else + { + if(item.isHidden()) + { + ofnw = mfhn.stringWidth(item.getDisplayName()); + } + else + { + ofnw = mf.stringWidth(item.getDisplayName()); + } + } + + ofnx = images.iconWidth + 2; + ofndelay = OFN_DEF_DELAY; + + if(ofnw > w - images.iconWidth - 5) + { + //ofnstep = -(ofnw / main.currentFile.length()); + ofnstep = -1; + } + else + { + ofnstep = 0; + } + + repaint(); + } + + public void changeFSMode() + { + initFSMode(!fsmode); + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿ÐµÑ€ÐµÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñƒ ÑобÑтвенными полноÑкранным + * и неполноÑкранным режимами + */ + public void initFSMode(boolean mode) + { + fsmode = mode; + + if(fsmode) + { + header = footer = 0; + } + else + { + header = Math.max(images.iconHeight + 2, fdh + 2); + footer = header; + } + + h = allh - header - footer; + + scrLen = h / fileH; + + if(items.size() > 0) + { + select(scrSel); + } + } + + public void findFireIcon() + { + fireIcon = images.iSelect; + + int action = keyConfig.getAction(KEY_FIRE); + boolean notfound = true; + + for(int i = 0; i < cvsMenu.menu.length && notfound; i++) + { + for(int j = 1; j < cvsMenu.menu[i].length && notfound; j += 2) + { + if(cvsMenu.menu[i][j] == action) + { + fireIcon = cvsMenu.menu[i][j + 1]; + notfound = false; + } + } + } + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð¸Ñовки + */ + public void paint(Graphics g) + { + if(repaints) + { + int i, fh, p, icon; + + offgraphics.setFont(fd); + offgraphics.setClip(0, 0, w, allh); + + if(background != null) + { + offgraphics.drawImage(background, 0, 0, Graphics.LEFT | Graphics.TOP); + } + else + { + images.drawVGradient(offgraphics, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, w, allh, options.ditherGradients, options.alphaGradients); + } + + boolean inBuffer = "buf:/".equals(main.currentPath); + + if(!fsmode) // риÑуем Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ + { + offgraphics.setColor(ColorScheme.colors[ColorScheme.mdborder]); + offgraphics.drawLine(0, header - 1, w, header - 1); + offgraphics.drawLine(0, allh - footer, w, allh - footer); + + icon = images.iFolder; + + if(title.endsWith(":/")) + { + icon = images.iDisk; + } + else if(title.equals(Locale.getString(this, Locale.SELECT_DRIVE))) + { + icon = images.iSieFM; + } + else if(title.equals(Locale.getString(this, Locale.FAVOURITE))) + { + icon = images.iFavorites; + } + else if(title.equals(Locale.getString(this, Locale.BUFFER))) + { + icon = images.iClipboard; + } + + images.drawIcon(offgraphics, icon, 1, (header - images.iconHeight) / 2); + + // заглавие + offgraphics.setColor(ColorScheme.colors[ColorScheme.fore]); + offgraphics.drawString(title, images.iconWidth + 3, (header - fdh) / 2, Graphics.LEFT | Graphics.TOP); + + offgraphics.setColor(ColorScheme.colors[ColorScheme.altfore]); + + if(options.alterClockPos) + { + firew = fcd.stringWidth(AuxClass.getCurrentTime()) * 4 / 3; + skw = (w - firew) / 2; + } + else + { + firew = images.iconWidth * 3 / 2; + skw = (w - firew) / 2; + + if(options.clockMode) + { + // Ð²Ñ€ÐµÐ¼Ñ + offgraphics.drawString(AuxClass.getCurrentTime(), w - 1, (header - fdh) / 2, Graphics.RIGHT | Graphics.TOP); + } + else + { + // номер панели + offgraphics.drawString("-" + Integer.toString(main.manager.currentPanel() + 1) + "-", w - 1, (header - fdh) / 2, Graphics.RIGHT | Graphics.TOP); + } + } + + // подпиÑи к LSK, RSK и джойÑтику + int lskstr = keyConfig.getAction(KEY_LSK), + rskstr = keyConfig.getAction(KEY_RSK); + + if(options.exitFromDriveList && main.currentPath.length() == 0) + { + if(lskstr == Locale.BACK_CMD) + { + lskstr = Locale.EXIT_CMD; + } + + if(rskstr == Locale.BACK_CMD) + { + rskstr = Locale.EXIT_CMD; + } + } + + if(lskp) + { + images.drawHGradient(offgraphics, ColorScheme.colors[ColorScheme.skselback1], ColorScheme.colors[ColorScheme.skselback2], 0, allh - footer + 1, skw, footer - 1, options.ditherGradients, options.alphaGradients); + offgraphics.setColor(ColorScheme.colors[ColorScheme.skselfore]); + } + else + { + offgraphics.setColor(ColorScheme.colors[ColorScheme.skfore]); + } + + offgraphics.setClip(0, allh - footer + 1, skw, footer - 1); + + if(lskstr >= 0) + { + offgraphics.drawString(Locale.getString(this, lskstr), skw / 2, allh - footer + (footer - fdh) / 2, Graphics.HCENTER | Graphics.TOP); + } + + offgraphics.setClip(0, 0, w, allh); + + if(rskp) + { + images.drawHGradient(offgraphics, ColorScheme.colors[ColorScheme.skselback2], ColorScheme.colors[ColorScheme.skselback1], w - skw, allh - footer + 1, skw, footer - 1, options.ditherGradients, options.alphaGradients); + offgraphics.setColor(ColorScheme.colors[ColorScheme.skselfore]); + } + else + { + offgraphics.setColor(ColorScheme.colors[ColorScheme.skfore]); + } + + offgraphics.setClip(w - skw, allh - footer + 1, skw, footer - 1); + + if(rskstr >= 0) + { + offgraphics.drawString(Locale.getString(this, rskstr), w - skw / 2 - 1, allh - footer + (footer - fdh) / 2, Graphics.HCENTER | Graphics.TOP); + } + + offgraphics.setClip(0, 0, w, allh); + + if(firep) + { + offgraphics.setColor(ColorScheme.colors[ColorScheme.skselback2]); + offgraphics.fillRect((w - firew) / 2, allh - footer + 1, firew, footer - 1); + } + + if(options.alterClockPos) + { + offgraphics.setColor(firep ? ColorScheme.colors[ColorScheme.selfore] : ColorScheme.colors[ColorScheme.altfore]); + + if(options.clockMode) + { + // Ð²Ñ€ÐµÐ¼Ñ + offgraphics.drawString(AuxClass.getCurrentTime(), w / 2, allh - footer + (footer - fdh) / 2, Graphics.HCENTER | Graphics.TOP); + } + else + { + // номер панели + offgraphics.drawString("-" + Integer.toString(main.manager.currentPanel() + 1) + "-", w / 2, allh - footer + (footer - fdh) / 2, Graphics.HCENTER | Graphics.TOP); + } + } + else + { + images.drawIcon(offgraphics, fireIcon, (w - images.iconWidth) / 2, allh - footer + (footer - images.iconHeight) / 2); + } + } + + offgraphics.translate(0, header); + + FileItem item; + + for(i = scrStart, p = 0; i < items.size() && i < scrStart + scrLen + 1; i++, p++) + { + item = (FileItem)items.elementAt(i); + + offgraphics.setClip(0, 0, w - 3, h); + + if(i == scrSel) + { + if(options.frameCursor) + { + offgraphics.setColor(ColorScheme.colors[ColorScheme.selback1]); + offgraphics.drawRect(0, p * fileH, w - 4, fileH); + } + else if(cursor != null) + { + offgraphics.drawImage(cursor, 0, p * fileH, Graphics.LEFT | Graphics.TOP); + } + else + { + images.drawHGradient(offgraphics, ColorScheme.colors[ColorScheme.selback1], ColorScheme.colors[ColorScheme.selback2], 0, p * fileH, w - 3, fileH, options.ditherGradients, options.alphaGradients); + } + + offgraphics.setColor(ColorScheme.colors[ColorScheme.selfore]); + } + else + { + if(markCount >= 0 && item.isMarked()) + { + offgraphics.setColor(ColorScheme.colors[ColorScheme.hlfore]); + } + else + { + offgraphics.setColor(ColorScheme.colors[ColorScheme.fore]); + } + } + + if(markCount >= 0 && item.isMarked()) + { + images.drawIcon(offgraphics, images.iMark, 1, p * fileH); + } + else if(item.getIcon() != null) + { + offgraphics.drawImage(item.getIcon(), 1, p * fileH, Graphics.LEFT | Graphics.TOP); + } + + if(inBuffer && i > 0 && Buffer.isMoved(item.getFullName())) + { + images.drawIcon(offgraphics, images.iMoveIt, 1, p * fileH); + } + + if(item.isReadOnly()) + { + if(item.isHidden()) + { + fh = mfrh.getHeight(); + offgraphics.setFont(mfrh); + } + else + { + fh = mfro.getHeight(); + offgraphics.setFont(mfro); + } + } + else + { + if(item.isHidden()) + { + fh = mfhn.getHeight(); + offgraphics.setFont(mfhn); + } + else + { + fh = mf.getHeight(); + offgraphics.setFont(mf); + } + } + + offgraphics.setClip(images.iconWidth + 2, 0, w - images.iconWidth - 5, h); + + if(i == scrSel) + { + offgraphics.drawString(item.getDisplayName(), ofnx, p * fileH + fileH / 2 - fh / 2, Graphics.LEFT | Graphics.TOP); + } + else + { + offgraphics.drawString(item.getDisplayName(), images.iconWidth + 2, p * fileH + fileH / 2 - fh / 2, Graphics.LEFT | Graphics.TOP); + } + } + + offgraphics.setClip(w - 3, 0, 3, h); + offgraphics.setColor(ColorScheme.colors[ColorScheme.sbline]); + + offgraphics.drawLine(w - 2, 0, w - 2, h); + + int sbstart, sbsize; + + if(items.size() > 0) + { + sbstart = h * scrStart / items.size(); + sbsize = h * scrLen / items.size(); + + if(sbsize > h) + { + sbsize = h; + } + } + else + { + sbstart = 0; + sbsize = h; + } + + offgraphics.setColor(ColorScheme.colors[ColorScheme.sbfore]); + + offgraphics.drawLine(w - 3, sbstart, w - 3, sbstart + sbsize); + offgraphics.drawLine(w - 1, sbstart, w - 1, sbstart + sbsize); + offgraphics.drawLine(w - 2, sbstart - 1, w - 2, sbstart + sbsize + 1); + + offgraphics.translate(0, -header); + } + + g.drawImage(offscreen, 0, 0, Graphics.LEFT | Graphics.TOP); + } + + public void enableRepaint(boolean value) + { + repaints = value; + } + + public void run() + { + try + { + long lfxsleep = lfx.getDelay(); + + long ofnsleep = (int)(8000f / options.longScrollSpeed / Math.min(w, allh)); + OFN_DEF_DELAY = (int)(600 / ofnsleep); + + if(options.noEffects) + { + lfxsleep = ofnsleep; + } + + long target = AuxMath.gcd((int)lfxsleep, (int)ofnsleep); + long sleep; + + if(target < AuxClass.MIN_THREAD_SLEEP) + { + target = AuxClass.MIN_THREAD_SLEEP; + } + + long current; + long ofnprev = System.currentTimeMillis(); + long lfxprev = System.currentTimeMillis(); + + boolean flag = false; + + while(isshown) + { + current = System.currentTimeMillis(); + + while(current - ofnprev >= ofnsleep) + { + ofnprev += ofnsleep; + + if(ofnstep != 0) + { + if(ofndelay > 0) + { + ofndelay--; + } + else + { + ofnx += ofnstep; + } + + if(ofnstep > 0) + { + if(ofnx > images.iconWidth + 2) + { + ofnx = images.iconWidth + 2; + ofnstep = -ofnstep; + ofndelay = OFN_DEF_DELAY; + } + } + else + { + if(ofnx < w - 5 - ofnw) + { + ofnx = w - 5 - ofnw; + ofnstep = -ofnstep; + ofndelay = OFN_DEF_DELAY; + } + } + + flag = true; + } + } + + while(current - lfxprev >= lfxsleep) + { + lfxprev += lfxsleep; + lfx.moveLines(); + + flag = true; + } + + if(flag) + { + repaint(); + //serviceRepaints(); + + flag = false; + } + + sleep = target - (current - Math.min(ofnprev, lfxprev)); + + if(sleep > 0) + { + Thread.sleep(sleep); + } + } + } + catch(InterruptedException ie) + { + } + + t = null; + } + + public void showNotify() + { + if(t != null && t.isAlive()) + { + try + { + //t.interrupt(); + t.join(); + } + catch(Exception e) + { + } + } + + isshown = true; + + //updateGradients(); + + if(options.longScrollSpeed > 0) + { + (t = new Thread(this, "FileSelect/Repaint")).start(); + } + + keyReleaseAllowed = false; + } + + public void hideNotify() + { + isshown = false; + } + + public void toggleHotKeyMode() + { + hotKeyMode = !hotKeyMode; + } + + /** + * Обработчик нажатий клавиш + */ + public void keyPressed(int keyCode) + { + keyReleaseAllowed = true; + + if(isKeyNum(keyCode)) + { + return; + } + + if(!fsmode && !options.noEffects) + { + if(keyCode == KEY_FIRE) + { + firep = true; + repaint(); + return; + } + else if(keyCode == KEY_LSK) + { + lskp = true; + repaint(); + return; + } + else if(keyCode == KEY_RSK) + { + rskp = true; + repaint(); + return; + } + } + + int action = keyConfig.getAction(keyCode); + + if(action >= 0) + { + main.menu.parent = this; + main.menu.listen.menuAction(action); + } + } + + public void numKeyPressed(int keyCode) + { + int action = keyConfig.getAction(keyCode); + + if(action >= 0) + { + main.menu.parent = this; + main.menu.listen.menuAction(action); + } + } + + public void directKeyPressed(int keyCode) + { + if(keyCode == KEY_DOWN) + { + if(++scrSel >= items.size()) + { + scrSel = 0; + } + } + else if(keyCode == KEY_UP) + { + if(--scrSel < 0) + { + scrSel = items.size() - 1; + } + } + else if(keyCode == KEY_RIGHT) + { + if(scrSel == items.size() - 1) + { + scrSel = main.currentPath.length() == 0 ? 0 : 1; + } + else + { + scrSel += scrLen; + + if(scrSel > items.size() - 1) + { + scrSel = items.size() - 1; + } + } + } + else if(keyCode == KEY_LEFT) + { + if(main.currentPath.length() == 0 ? scrSel == 0 : scrSel == 1) + { + scrSel = items.size() - 1; + } + else + { + scrSel -= scrLen; + + if(scrSel < 1) + { + scrSel = main.currentPath.length() == 0 ? 0 : 1; + } + } + } + + select(scrSel); + } + + /** + * Выделение по нажатию кнопы "огонь", Ñ‚.е джойÑтика + */ + public void fireSelectAction() + { + if(markCount < 0) + { + selectFile(); + } + else // еÑли идёт процеÑÑ Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸Ñ + { + markSelected(); + repaint(); + } + } + + public String prevpath; + + /** + * Обработчик отпуÑканий клавиш + */ + public void keyReleased(int keyCode) + { + if(!keyReleaseAllowed) + { + return; + } + + if(hotKeyMode) + { + keyCode |= KEY_HOT; + hotKeyMode = false; + } + + if(keyHeld < 3 && isKeyNum(keyCode)) + { + numKeyPressed(keyCode); + } + else if(!fsmode && !options.noEffects) + { + int action = -1; + + if(keyCode == KEY_LSK && lskp) + { + action = keyConfig.getAction(KEY_LSK); + lskp = false; + } + else if(keyCode == KEY_RSK && rskp) + { + action = keyConfig.getAction(KEY_RSK); + rskp = false; + } + else if(keyCode == KEY_FIRE && firep) + { + action = keyConfig.getAction(KEY_FIRE); + firep = false; + } + + if(action >= 0) + { + main.menu.parent = this; + main.menu.listen.menuAction(action); + } + } + + keyHeld = 0; + } + + /** + * Обработчик повторений клавиш + */ + + public void keyRepeated(int keyCode) + { + if(isKeyNum(keyCode)) + { + if(++keyHeld == 3) + { + keyHeld = 0; + keyReleaseAllowed = false; + + numKeyPressed(keyCode | KEY_HELD); + } + } + else + { + keyPressed(keyCode); + } + } + + /** + * Получить поÑледние n Ñимволов (Ð´Ð»Ñ Ñ‚Ð¸Ñ‚ÑƒÐ»Ð°) + * + * @param path String + * @param n int + * @return String + */ + private String getLastPartOfString(String path, int w) + { + if(fcd.stringWidth(path) <= w) + { + return path; + } + else + { + int n = 0; + + while(fcd.stringWidth(".." + path.substring(++n)) > w); + + return ".." + path.substring(n).trim(); + } + } + +// private static void out(String s) +// { +// System.out.println("[cvsFileSelect] " + s); +// } +} diff --git a/src/filemanager/cvsMenu.java b/src/filemanager/cvsMenu.java new file mode 100644 index 0000000..81286ce --- /dev/null +++ b/src/filemanager/cvsMenu.java @@ -0,0 +1,792 @@ +package filemanager; + +import com.one.PaintableObject; +import javax.microedition.lcdui.*; +import com.vmx.*; + +public class cvsMenu extends gkcCanvas +{ + public Object parent; + + public MenuListener listen; + + protected int type, w, h; + protected int sel1, sel2; + protected int m2l; + + protected int[] menu_width; // width Ð´Ð»Ñ Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð½Ñ‹Ñ… (под)меню + protected int[] menu_height; // height Ð´Ð»Ñ Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð½Ñ‹Ñ… (под)меню + + protected int mw1, mw2, mh1, mh2; // width & height Ð´Ð»Ñ Ð¼ÐµÐ½ÑŽ и подменю + protected int mx1, mx2, my1, my2; // положение меню и подменю + + protected Font mf; // шрифт меню + protected int mfh; // выÑота шрифта + protected int mlh; // выÑота Ñтроки меню + protected FontWidthCache mfwc; // кÑш ширины шрифта %))) + protected Image drap; + + public boolean enabled[][]; + public static final int MENU_DISK_SELECTED = 0, MENU_FILE_SELECTED = 1, + MENU_FOLDER_SELECTED = 2, MENU_DOTDOT_SELECTED = 3, + MENU_FAVORITES_SELECTED = 4, MENU_INSIDE_ARCHIVE = 5, + MENU_BUFFER_SELECTED = 6, MENU_BUCKET_SELECTED = 7, + MENU_SELECT_ACTION = 0x100; + + /** КонÑтруктор */ + public cvsMenu() + { + int i, j, tt; + int add = 0; + + listen = null; + parent = null; + type = -1; + sel1 = 0; + sel2 = -1; + + setFullScreenMode(true); + + w = getWidth(); + h = getHeight(); + + //drap = LineEffect.createDrap(Colors.colors[Colors.drap], w, h); + + menu_length = menu_length_fix; + + mf = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, options.largeFontInMenu ? Font.SIZE_MEDIUM : Font.SIZE_SMALL); + mfh = mf.getHeight() + 1; + mfwc = FontWidthCache.getCache(mf); + + mlh = Math.max(images.iconHeight + 1, mfh); + + if(options.showMenuNum) + { + add = mfwc.stringWidth(" 0"); + } + + int add1 = mfwc.stringWidth(" > "); + + menu_width = new int[menu.length + 2]; // ширина Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ подменю + две ширины оÑновного + menu_height = new int[menu.length + 2]; // то же Ñамое, только Ð´Ð»Ñ Ð²Ñ‹Ñоты + + // ПодÑчёт требуемой ширины и выÑоты меню ... + + for(mw1 = 0, i = 0; i < menu_length_fix; i++) + { + tt = mfwc.stringWidth(Locale.getString(this, menu[i][0])) + add1; + + if(i < 10) + { + tt += add; + } + + if(tt > mw1) + { + mw1 = tt; + } + } + + menu_width[0] = mw1 + 4; // по 1 на рамку + по 1 отÑтуп + menu_height[0] = mlh * menu_length_fix + 3; // по 1 на рамку + 1 отÑтуп Ñверху, отÑтуп Ñнизу учтен в mfh + + for(; i < menu.length; i++) + { + tt = mfwc.stringWidth(Locale.getString(this, menu[i][0])) + add1; + + if(i < 10) + { + tt += add; + } + + if(tt > mw1) + { + mw1 = tt; + } + } + + menu_width[1] = mw1 + 4; + menu_height[1] = mlh * menu.length + 3; + + // ... и подменю + + for(i = 0; i < menu.length; i++) + { + m2l = (menu[i].length - 1) / 2; + + for(mw2 = 0, j = 0; j < m2l; j++) + { + tt = mfwc.stringWidth(Locale.getString(this, menu[i][1 + j * 2])); + + if(j < 10) + { + tt += add; + } + + if(tt > mw2) + { + mw2 = tt; + } + } + + menu_width[i + 2] = mw2 + images.iconWidth + 5; // по 1 на рамку + по 1 на отÑтуп + 1 между значком и текÑтом + menu_height[i + 2] = mlh * m2l + 3; + } + + // а также Ñоздаём и заполнÑем enabled + enabled = new boolean[menu.length][]; + + for(i = 0; i < menu.length; i++) + { + enabled[i] = new boolean[1 + (menu[i].length - 1) / 2]; + + for(j = 0; j < 1 + (menu[i].length - 1) / 2; j++) + { + enabled[i][j] = true; + } + } + + listen = new WorkingMenu(this); + } + + /** + * Смена типа меню (затемнение ненужных Ñлементов) + */ + public void setType(int type) + { + this.type = type; + sel1 = 0; + sel2 = -1; + + if(type >= MENU_DISK_SELECTED && type <= MENU_BUCKET_SELECTED) + { + if(options.useFullMenu) + { + menu_length = menu.length; + + mw1 = menu_width[1]; + mh1 = menu_height[1]; + mx1 = 7; + my1 = h - menu_height[1] - 7; + } + else + { + menu_length = menu_length_fix; + + mw1 = menu_width[0]; + mh1 = menu_height[0]; + mx1 = 7; + my1 = h - menu_height[0] - 7; + } + + for(int i = 0; i < menu_length_fix; i++) + { + System.arraycopy(enabledModes[type][i], 0, enabled[i], 0, enabledModes[type][i].length); + } + + if(type == MENU_FILE_SELECTED || + type == MENU_FOLDER_SELECTED || + type == MENU_DOTDOT_SELECTED || + type == MENU_INSIDE_ARCHIVE || + type == MENU_BUCKET_SELECTED) + { + enabled[3][1] = Buffer.getSize() > 0; //???// + + if(type == MENU_INSIDE_ARCHIVE) + { + enabled[1][3] = enabled[3][1]; + } + + //enabled[4][3] = true; + //enabled[4][4] = true; + } + + enabled[5][1] = Buffer.getSize() > 0; + +// if(type == MENU_FILE_SELECTED && main.currentFile.toLowerCase().endsWith(".mp3")) +// { +// enabled[0][6] = true; +// } + +// if(type == MENU_INSIDE_ARCHIVE) +// { +// enabled[1][3] = Buffer.getSize() > 0; +// enabled[3][4] = true; +// enabled[3][5] = true; +// } + + for(int i = 0; i < enabled.length; i++) + { + enabled[i][0] = false; + + for(int j = 1; j < enabled[i].length; j++) + { + if(enabled[i][j]) + { + enabled[i][0] = true; + break; + } + } + } + + if(type == MENU_DISK_SELECTED && (Locale.getString(this, Locale.FAVOURITE).equals(main.currentFile) || Locale.getString(this, Locale.BIT_BUCKET).equals(main.currentFile))) + { + enabled[2][0] = false; + enabled[3][0] = false; + } + + enabled[5][3] = AuxClass.classExists(main.TEXT_VIEW_CLASS); + } + else if(type == MENU_SELECT_ACTION) + { + menu_length = menu.length; + + mw1 = menu_width[1]; + mh1 = menu_height[1]; + mx1 = 7; + my1 = h - menu_height[1] - 7; + + for(int i = 0; i < menu.length; i++) + { + for(int j = 0; j < 1 + (menu[i].length - 1) / 2; j++) + { + enabled[i][j] = true; + } + } + } + } + + public boolean isActionAllowed(int action) + { + for(int i = 0; i < menu.length; i++) + { + for(int j = 1; j < menu[i].length; j += 2) + { + if(menu[i][j] == action) + { + return enabled[i][(j - 1) / 2 + 1]; + } + } + } + + return true; + } + + /** Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð¸Ñовки */ + public void paint(Graphics g) + { + if(parent instanceof PaintableObject) + { + ((PaintableObject)parent).paint(g); + } + else + { + images.drawVGradient(g, ColorScheme.colors[ColorScheme.mnback1], ColorScheme.colors[ColorScheme.mnback2], 0, 0, w, h, options.ditherGradients, options.alphaGradients); + } + + g.setClip(0, 0, w, h); + + if(sel2 < 0 && drap != null) + { + g.drawImage(drap, 0, 0, Graphics.LEFT | Graphics.TOP); + } + + if(my1 + sel1 * mlh < 0) + { + my1 = -sel1 * mlh; + } + else if(my1 + (sel1 + 1) * mlh > h - 3) + { + my1 = h - (sel1 + 1) * mlh - 3; + } + + g.setColor(ColorScheme.colors[ColorScheme.mnback1]); + + images.drawVGradient(g, ColorScheme.colors[ColorScheme.mnback1], ColorScheme.colors[ColorScheme.mnback2], mx1, my1, mw1, mh1, options.ditherGradients, options.alphaGradients); + + g.setColor(ColorScheme.colors[ColorScheme.dkborder]); + g.drawRect(mx1, my1, mw1 - 1, mh1 - 1); + g.setFont(mf); + + // ОтриÑовка меню + for(int i = 0; i < menu_length; i++) + { + if(enabled[i][0]) + { + if(i == sel1) + { + g.setColor(ColorScheme.colors[ColorScheme.mnselback1]); + + if(options.frameCursor) + { + g.drawRect(mx1 + 1, my1 + 1 + i * mlh, mw1 - 3, mlh); + } + else + { + images.drawHGradient(g, ColorScheme.colors[ColorScheme.mnselback1], ColorScheme.colors[ColorScheme.mnselback2], mx1 + 1, my1 + 1 + i * mlh, mw1 - 2, mlh + 1, options.ditherGradients, options.alphaGradients); + } + + g.setColor(ColorScheme.colors[ColorScheme.mnselfore]); + g.drawString(Locale.getString(this, menu[i][0]) + " >", mx1 + 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + } + else + { + g.setColor(ColorScheme.colors[ColorScheme.mnfore]); + g.drawString(Locale.getString(this, menu[i][0]) + " >", mx1 + 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + g.setColor(ColorScheme.colors[ColorScheme.mnaltfore]); + } + } + else + { + g.setColor(ColorScheme.colors[ColorScheme.disabled]); + g.drawString(Locale.getString(this, menu[i][0]) + " >", mx1 + 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + } + + if(options.showMenuNum) + { + if(i < 9) + { + g.drawChar((char)(KEY_NUM1 + i), mx1 + mw1 - 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.RIGHT | Graphics.TOP); + } + else if(i == 9) + { + g.drawChar((char)KEY_NUM0, mx1 + mw1 - 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.RIGHT | Graphics.TOP); + } + } + } + + // ЕÑли отображено подменю - риÑуем его + if(sel2 >= 0) + { + if(drap != null) + { + g.drawImage(drap, 0, 0, Graphics.LEFT | Graphics.TOP); + } + + if(my2 + sel2 * mlh < 0) + { + my2 = -sel2 * mlh; + } + else if(my2 + (sel2 + 1) * mlh > h - 3) + { + my2 = h - (sel2 + 1) * mlh - 3; + } + + g.setColor(ColorScheme.colors[ColorScheme.mnback1]); + + images.drawVGradient(g, ColorScheme.colors[ColorScheme.mnback1], ColorScheme.colors[ColorScheme.mnback2], mx2, my2, mw2, mh2, options.ditherGradients, options.alphaGradients); + + g.setColor(ColorScheme.colors[ColorScheme.dkborder]); + g.drawRect(mx2, my2, mw2 - 1, mh2 - 1); + + for(int i = 0; i < m2l; i++) + { + if(enabled[sel1][i + 1]) + { + if(i == sel2) + { + g.setColor(ColorScheme.colors[ColorScheme.mnselback1]); + + if(options.frameCursor) + { + g.drawRect(mx2 + 1, my2 + 1 + i * mlh, mw2 - 3, mlh); + } + else + { + images.drawHGradient(g, ColorScheme.colors[ColorScheme.mnselback1], ColorScheme.colors[ColorScheme.mnselback2], mx2 + 1, my2 + 1 + i * mlh, mw2 - 2, mlh + 1, options.ditherGradients, options.alphaGradients); + } + + g.setColor(ColorScheme.colors[ColorScheme.mnselfore]); + g.drawString(Locale.getString(this, menu[sel1][i * 2 + 1]), mx2 + images.iconWidth + 3, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + } + else + { + g.setColor(ColorScheme.colors[ColorScheme.mnfore]); + g.drawString(Locale.getString(this, menu[sel1][i * 2 + 1]), mx2 + images.iconWidth + 3, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + g.setColor(ColorScheme.colors[ColorScheme.mnaltfore]); + } + } + else + { + g.setColor(ColorScheme.colors[ColorScheme.disabled]); + g.drawString(Locale.getString(this, menu[sel1][i * 2 + 1]), mx2 + images.iconWidth + 3, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP); + } + + images.drawIcon(g, menu[sel1][i * 2 + 2], mx2 + 2, my2 + 2 + i * mlh + (mlh - images.iconHeight) / 2); + + if(options.showMenuNum) + { + if(i < 9) + { + g.drawChar((char)(KEY_NUM1 + i), mx2 + mw2 - 2, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.RIGHT | Graphics.TOP); + } + else if(i == 9) + { + g.drawChar((char)KEY_NUM0, mx2 + mw2 - 2, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.RIGHT | Graphics.TOP); + } + } + } + } + } + + /** Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ðº предыдущему Ñкрану (к parent) */ + public void ret() + { + if(parent != null) + { + if(main.dsp.getCurrent() != parent) + { + main.dsp.setCurrent(parent); + } + + parent = null; + } + } + + /** Обработчик нажатий клавиш */ + public void keyPressed(int keyCode) + { + int osel, ml; + + if(!options.showMenuNum) + { + keyCode = translateKey(keyCode); + } + + if(options.swapSoftKeys) + { + if(keyCode == KEY_LSK) + { + keyCode = KEY_RSK; + } + else if(keyCode == KEY_RSK) + { + keyCode = KEY_LSK; + } + } + + if(keyCode == KEY_DOWN) + { + if(sel2 == -1) // гулÑем по меню + { + osel = sel1; + ml = menu_length; + + do + { + sel1 = (sel1 + 1) % ml; + } + while(!enabled[sel1][0] && sel2 != osel); + } + else // гулÑем по подменю + { + osel = sel2; + ml = (menu[sel1].length - 1) / 2; + + do + { + sel2 = (sel2 + 1) % ml; + } + while(!enabled[sel1][1 + sel2] && sel2 != osel); + } + + repaint(); + } + else if(keyCode == KEY_UP) + { + if(sel2 == -1) // гулÑем по меню + { + osel = sel1; + ml = menu_length; + + do + { + sel1 = (sel1 - 1 + ml) % ml; + } + while(!enabled[sel1][0] && sel2 != osel); + } + else // гулÑем по подменю + { + osel = sel2; + ml = (menu[sel1].length - 1) / 2; + + do + { + sel2 = (sel2 - 1 + ml) % ml; + } + while(!enabled[sel1][1 + sel2] && sel2 != osel); + } + + repaint(); + } + else if(keyCode == KEY_LSK || + keyCode == KEY_LEFT || + keyCode == KEY_CANCEL) + { + if(sel2 == -1) + { + ret(); + } + else + { + sel2 = -1; + repaint(); + } + } + else if(keyCode == KEY_FIRE || + keyCode == KEY_RIGHT || + keyCode == KEY_RSK || + keyCode == KEY_DIAL) + { + if(sel2 == -1) + { + sel2 = 0; + + while(!enabled[sel1][1 + sel2]) + { + sel2++; + } + + m2l = (menu[sel1].length - 1) / 2; + + mw2 = menu_width[sel1 + 2]; + mh2 = menu_height[sel1 + 2]; + + mx2 = 14; + my2 = my1 + 2 + sel1 * mlh + mlh / 2; + + if(my2 + mh2 > h - 14) + { + my2 = h - mh2 - 14; + } + + repaint(); + } + else if(listen != null) + { + listen.menuAction(menu[sel1][1 + sel2 * 2]); + } + } + else if((keyCode >= KEY_NUM1 && keyCode <= KEY_NUM9) || keyCode == KEY_NUM0) + { + if(!options.showMenuNum) + { + return; + } + + if(keyCode == KEY_NUM0) + { + keyCode = 9; + } + else + { + keyCode -= KEY_NUM1; + } + + try + { + if(sel2 < 0) + { + if(enabled[keyCode][0]) + { + sel1 = keyCode; + keyPressed(KEY_FIRE); + } + } + else + { + if(enabled[sel1][1 + keyCode]) + { + sel2 = keyCode; + keyPressed(KEY_FIRE); + } + } + } + catch(ArrayIndexOutOfBoundsException e) + { + } + } + } + + /** + * Обработчик повторений клавиш + */ +// protected void keyRepeated(int keyCode) +// { +// if(keyCode == KEY_DOWN || keyCode == KEY_UP) +// { +// keyPressed(keyCode); +// } +// } + + /** Данные меню */ + static final int menu[][] = + { + { + Locale.MENU_FILE, + Locale.OPEN_CMD, images.iNext, + Locale.MODULES_CMD, images.iNext, + Locale.MARK_CMD, images.iMark, + Locale.MARK_ALL_CMD, images.iMarkAll, + Locale.DEMARK_ALL_CMD, images.iDemarkAll, + Locale.MENU_SEARCH, images.iSearch + }, + { + Locale.MENU_ARCHIVE, + Locale.EXTRACT_CMD, images.iUnpack, + Locale.EXTRACT_ALL_CMD, images.iUnpack, + Locale.ADD_CMD, images.iPack + }, + { + Locale.MENU_PROPERTIES, + Locale.PROPERTY_CMD, images.iProperties, + Locale.DISK_INFO_CMD, images.iDisk + }, + { + Locale.MENU_OPERATIONS, + Locale.INSERT_CMD, images.iPaste, + Locale.COPY_CMD, images.iCopy, + Locale.MOVE_CMD, images.iMove, + Locale.DELETE_CMD, images.iDelete, + Locale.RENAME_CMD, images.iRename, + Locale.TO_FAVOUR_CMD, images.iFavorites + }, + { + Locale.MENU_CREATE, + Locale.NEW_FILE_CMD, images.iFile, + Locale.NEW_FOLDER_CMD, images.iFolder, + Locale.CREATE_ARCHIVE, images.iPack, + }, + { + Locale.MENU_SHOW, + Locale.BUFFER, images.iClipboard, + Locale.FAVOURITE, images.iFavorites, + Locale.HELP_CMD, images.iHelp, + Locale.PREFERENCES_CMD, images.iOptions, + Locale.KEYBOARD_CONFIG_CMD, images.iKey, + Locale.MINIMIZE_CMD, images.iMinimize, + Locale.EXIT_CMD, images.iExit + }, + { + Locale.MENU_ADDITIONAL, + Locale.KEY_NO_ACTION, images.iMoveIt, + Locale.OPTIONS_CMD, images.iMenu, + Locale.SELECT_CMD, images.iSelect, + Locale.PREV_LINE_CMD, -1, + Locale.NEXT_LINE_CMD, -1, + Locale.PREV_SCREEN_CMD, -1, + Locale.NEXT_SCREEN_CMD, -1, + Locale.CLOCK_MODE, -1, + Locale.FULLSCREEN_CMD, -1, + Locale.BACK_CMD, -1, + Locale.HOT_KEYS, -1 + }, + { + Locale.PANELS, + Locale.PANEL_NUMS+0, -1, + Locale.PANEL_NUMS+1, -1, + Locale.PANEL_NUMS+2, -1, + Locale.PANEL_NUMS+3, -1, + Locale.PANEL_NUMS+4, -1, + Locale.PANEL_NUMS+5, -1, + Locale.PANEL_NUMS+6, -1, + Locale.PANEL_NUMS+7, -1, + Locale.PANEL_NUMS+8, -1, + Locale.PANEL_NUMS+9, -1 + }, + { + Locale.SWITCH, + Locale.NEXT_PANEL, -1, + Locale.PREV_PANEL, -1, + Locale.NEXT_FREE, -1, + Locale.PREV_FREE, -1, + Locale.QUICK_SWITCH, -1, + Locale.MEMORY_MONITOR, -1, + Locale.CONTAINERS, -1, + Locale.COLOR_SCHEME, -1, + Locale.PANELS, -1 + }, + { + Locale.MENU_LIST_SORT, + Locale.SORT_NONE, -1, + Locale.SORT_BY_NAME, -1, + Locale.SORT_BY_TYPE, -1, + Locale.SORT_BY_DATE, -1, + Locale.SORT_BY_SIZE, -1, + Locale.SORT_REVERSE_ORDER, -1, + Locale.IGNORE_CASE, -1 + } + }; + + static int menu_length = 6; + static final int menu_length_fix = 6; + + /* Данные enabled режимов меню */ + static final boolean enabledModes[][][] = + { + { // выбран диÑк + { false, true, false, false, false, false, false }, + { false, false, false, false }, + { false, false, true }, + { false, false, false, false, false, false, true }, + { false, false, false, false }, + { false, false, true, true, true, true, true, true } + }, + { // выбран файл + { false, true, true, true, true, true, true }, + { false, false, false, false }, + { false, true, true }, + { false, false, true, true, true, true, false }, + { false, true, true, true }, + { false, false, true, true, true, true, true, true } + }, + { // выбрана папка + { false, true, false, true, true, true, true }, + { false, false, false, false }, + { false, true, true }, + { false, false, true, true, true, true, true }, + { false, true, true, true }, + { false, false, true, true, true, true, true, true } + }, + { // выбрано .. + { false, true, false, false, true, true, true }, + { false, false, false, false }, + { false, true, true }, + { false, false, false, false, false, false, true }, + { false, true, true, true }, + { false, false, true, true, true, true, true, true } + }, + { // находимÑÑ Ð² избранном + { false, true, false, true, true, true, false }, + { false, false, false, false }, + { false, true, false }, + { false, false, false, false, true, false, false }, + { false, false, false, false }, + { false, false, true, true, true, true, true, true } + }, + { // находимÑÑ Ð² архиве + { false, true, false, true, true, true, true }, + { false, true, true, false }, + { false, true, true }, + { false, false, true, true, true, true, true }, + { false, true, true, true }, + { false, false, true, true, true, true, true, true } + }, + { // находимÑÑ Ð² буфере обмена + { false, true, false, true, true, true, false }, + { false, false, false, false }, + { false, false, false }, + { false, false, true, true, true, false, false }, + { false, false, false, false }, + { false, false, true, true, true, true, true, true } + }, + { // находимÑÑ Ð² корзине + { false, true, false, false, false, false, false }, + { false, false, false, false }, + { false, false, false }, + { false, false, false, false, false, false, false }, + { false, false, false, false }, + { false, false, true, true, true, true, true, true } + } + }; +} diff --git a/src/filemanager/cvsWait.java b/src/filemanager/cvsWait.java new file mode 100644 index 0000000..4bc4cf0 --- /dev/null +++ b/src/filemanager/cvsWait.java @@ -0,0 +1,200 @@ +package filemanager; // переведен + +import com.one.ErrScreen; +import com.one.PaintableObject; +import javax.microedition.lcdui.*; +import javax.microedition.lcdui.game.Sprite; +import java.util.*; +import com.vmx.*; + +class waitTimerTask extends TimerTask +{ + cvsWait parent; + + public waitTimerTask(cvsWait p) + { + parent = p; + } + + public void run() + { + parent.repaint(); + //parent.serviceRepaints(); + } +}; + +/** Пишем "ПожалуйÑта, ждите..." и читаем ÑпиÑок файлов Ð´Ð»Ñ FileSelect */ +public class cvsWait extends gkcCanvas implements Runnable +{ + private Object parent; + private Thread t; + private Timer timer; + private waitTimerTask timerTask; + private int counter = 0; + private String selectAfter; + private int w, h, x, y; + private Font f; + private FontWidthCache fwc; + private int fh; + private String[] msg; + private int i, msgx, msgy; + private int runpanel; + + /** + * ПуÑтой конÑтруктор + */ + public cvsWait() + { + setFullScreenMode(true); + + w = (120 * 110 / 120) * getWidth() / 132; + h = (84 * 110 / 120) * getWidth() / 132; + x = (getWidth() - w) / 2; + y = (getHeight() - h) / 2; + + f = Font.getFont(0, 1, 0); + fwc = FontWidthCache.getCache(f); + fh = f.getHeight(); + + msg = fwc.splitString(Locale.getString(this, Locale.WAIT_PLEASE), w - 47); + + msgx = x + images.waitAnimWidth + 10; // 5 Ñлева + значок + 5 Ñправа от значка + msgy = y + (h - fh * msg.length) / 2; + } + + public static void start(Object parent) + { + start(parent, main.manager.currentPanel()); + } + + public static void start(Object parent, String selectAfter) + { + start(parent, main.manager.currentPanel(), selectAfter); + } + + /** + * start Ð´Ð»Ñ ÑлучаÑ, когда поÑле загрузки ÑпиÑка + * файлов надо выбрать первый файл + */ + public static void start(Object parent, int panel) + { + main.wait.parent = parent; + main.wait.runpanel = panel; + main.wait.selectAfter = null; + main.wait.init(); + } + + /** + * start Ð´Ð»Ñ ÑлучаÑ, когда поÑле загрузки ÑпиÑка + * указываетÑÑ Ñ‚Ð¾, какой файл надо выбрать + */ + public static void start(Object parent, int panel, String selectAfter) + { + main.wait.parent = parent; + main.wait.runpanel = panel; + main.wait.selectAfter = selectAfter; + main.wait.init(); + } + + /** ÐžÐ±Ñ‰Ð°Ñ Ñ‡Ð°ÑÑ‚ÑŒ конÑтруктора */ + public void init() + { + if(t != null && t.isAlive()) + { + t.interrupt(); + t = null; + } + + if(timer != null) + { + timer.cancel(); + timer = null; + } + + timerTask = new waitTimerTask(this); + timer = new Timer(); + timer.schedule(timerTask, 0, 100); + + t = new Thread(this, "Wait/Listing"); + t.start(); + } + + /** Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿Ð¾Ñ‚Ð¾ÐºÐ° */ + public void run() + { + //String err = null; + Exception e = null; + //boolean erred = false; + + try + { + if(!options.noEffects) + { + main.manager.setCurrent(main.wait, runpanel); + } + + main.FileSelect.list(selectAfter); + timer.cancel(); + } + catch(Exception ex) + { + //ErrScreen.showErrMsg(ex); + //err = ex.getMessage(); + //erred = true; + e = ex; + timer.cancel(); + timer = null; + } + finally + { + if(e != null) + { + //Alert al = new Alert("Error", err, images.error, AlertType.ERROR); + //al.setTimeout(3000); + main.currentPath = main.FileSelect.prevpath; + main.manager.setCurrent(main.FileSelect, runpanel); + ErrScreen.showErrMsg(37, e); + } + else if(!options.noEffects || main.dsp.getCurrent() != main.FileSelect) + { + main.manager.setCurrent(main.FileSelect, runpanel); + } + } + } + + /** Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð¸Ñовки */ + public void paint(Graphics g) + { + if(parent != null && parent instanceof PaintableObject) + { + ((PaintableObject)parent).paint(g); + } + else + { + g.setColor(ColorScheme.colors[ColorScheme.back1]); + g.fillRect(0, 0, getWidth(), getHeight()); + } + + g.setColor(ColorScheme.colors[ColorScheme.back1]); + g.fillRoundRect(x, y, w, h, 8, 8); + + g.setColor(ColorScheme.colors[ColorScheme.dkborder]); + g.drawRoundRect(x, y, w, h, 8, 8); + + if(images.waitAnim != null) + { + g.drawRegion(images.waitAnim, images.waitAnimWidth * counter, 0, images.waitAnimWidth, images.waitAnimHeight, Sprite.TRANS_NONE, x + 5, y + h / 2, 6); + counter = (counter + 1) % images.waitAnimFrames; + } + + g.setFont(f); + g.setColor(ColorScheme.colors[ColorScheme.fore]); +// gWait.translate(this.getWidth() / 2 - 25, this.getHeight() / 2 - 14); +// gWait.drawString(Locale.getString(this, Locale.WAIT_PLEASE), 0, 0, 20); + + for(i = 0; i < msg.length; i++) + { + g.drawString(msg[i], msgx, msgy + i * fh, Graphics.LEFT | Graphics.TOP); + } + } +} diff --git a/src/filemanager/diskInfo.java b/src/filemanager/diskInfo.java new file mode 100644 index 0000000..0f19ceb --- /dev/null +++ b/src/filemanager/diskInfo.java @@ -0,0 +1,68 @@ +package filemanager; + +//import javax.bluetooth.LocalDevice; +import com.vmx.Locale; +import javax.microedition.lcdui.*; + +public class diskInfo extends Form implements CommandListener +{ + private Object parent; + + /** Показ информации о диÑке */ + public diskInfo(Object parent) + { + super(""); + setTitle(Locale.getString(this, Locale.DISK_INFO)); + + this.parent = parent; + + String disk; + String s; + + if(main.currentPath.length() > 0) + { + disk = main.currentPath; + } + else + { + disk = main.currentFile; + } + + int index = disk.indexOf('/'); + + if(index > 0) + { + disk = disk.substring(0, index); + } + + //StringItem si = new StringItem("", Locale.getString(this, Locale.DISK) + " " + disk + "\n"); + append(new TextField(Locale.getString(this, Locale.DISK), disk, disk.length(), TextField.ANY)); + + long size = filesystem.getDiskSpaceTotal(disk + "/"); + + if(size >= 0) + { + //si = new StringItem(Locale.getString(this, Locale.DISK_TOTAL_SIZE), filesystem.getSizeString(size)); + + s = filesystem.getSizeString(size, true); + append(new TextField(Locale.getString(this, Locale.DISK_TOTAL_SIZE), s, s.length(), TextField.ANY)); + } + + size = filesystem.getDiskSpaceAvailable(disk + "/"); + + if(size >= 0) + { + s = filesystem.getSizeString(size, true); + append(new TextField(Locale.getString(this, Locale.DISK_AVAILABLE), s, s.length(), TextField.ANY)); + } + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.BACK, 1)); + setCommandListener(this); + } + + /** Обработчик команд от формы ÑвойÑтв */ + public void commandAction(Command c, Displayable d) + { + main.dsp.setCurrent(parent); + } +} diff --git a/src/filemanager/filesystem.java b/src/filemanager/filesystem.java new file mode 100644 index 0000000..e214309 --- /dev/null +++ b/src/filemanager/filesystem.java @@ -0,0 +1,1276 @@ +package filemanager; + +import java.io.*; +import java.util.*; +import com.one.file.*; +import com.vmx.*; +import com.one.*; + +public class filesystem +{ + public static Hashtable mtypes; + + /** + * КонÑтруктор + */ + public filesystem() + { + } + + public static void init() throws IOException + { + mtypes = new Hashtable(); + + InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/config/mime.ini"); + IniRecord record = null; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + try + { + mtypes.put(record.key, record.value); + } + catch(Exception e) + { + } + } + + ini.close(); + } + + /** + * Проверка "Ñто директориÑ"? + * + * @param filename String - Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° + * @return boolean True - да, False - нет + */ + public static boolean isDir(String fn) + { + if(fn.charAt(fn.length() - 1) == '/') + { + return true; + } + + boolean r = false; + + if(options.accurateDirCheck) + { + try + { + FileConnection conn = (FileConnection)Connector.open("file:///" + fn, Connector.READ); + r = conn.isDirectory(); + conn.close(); + } + catch(Exception e) + { + r = false; + } + } + + return r; + } + + /** + * Файл ÑущеÑтвует? + * + * @param fileName name of file to be examined + * @return true if file exists, false otherwise + */ + public static boolean isFileExist(String fileName) + { + FileConnection conn = null; + boolean r = false; + + try + { + conn = (FileConnection)Connector.open("file:///" + fileName, Connector.READ); + r = conn.exists(); + conn.close(); + } + catch(Exception e) + { + //ErrScreen.showErrMsg(109, e); + r = false; + } + + return r; + } + + /** + * Получить ÑпиÑок доÑтупных диÑков телефона 0:/ 1:/ ... + * + * @throws IOException + * @return String[] - ÑпиÑок Ñтрок Ñ Ð¸Ð¼ÐµÐ½Ð°Ð¼Ð¸ доÑтупных диÑков + */ + /* + public static String[] listRoots() throws IOException + { + String roots[] = null; + Vector vector = new Vector(); + + for(Enumeration enumeration = FileSystemRegistry.listRoots(); enumeration.hasMoreElements(); vector.addElement((String)enumeration.nextElement())); + + roots = new String[vector.size()]; + vector.copyInto(roots); + + return roots; + } + */ + + public static Enumeration listRoots() + { + try + { + return Connector.listRoots(); + } + catch(Exception e) + { + //ErrScreen.showErrMsg(110, e); + return null; // (new Vector()).elements(); + } + } + + /** + * Получить ÑпиÑок файлов и папок в данной папке. + * Работа Ñ Ð°Ñ€Ñ…Ð¸Ð²Ð°Ð¼Ð¸ прозрачнаÑ. + * + * @param path Ð¸Ð¼Ñ Ð¿Ñ€Ð¾Ñматриваемой папки + * @param includeHidden включать Ñкрытые файлы в ÑпиÑок + * @return ÑпиÑок файлов + */ + public static Enumeration list(String folder, boolean includeHidden) + { + Enumeration files = null; + + try + { + FileConnection fc = (FileConnection)Connector.open("file:///" + folder, Connector.READ); + files = fc.list("*", includeHidden); + fc.close(); + } + catch(Exception e) + { + //ErrScreen.showErrMsg(114, e); + e.printStackTrace(); + } + + return files; + } + + /** + * Получить ÑпиÑок файлов и папок в данной папке. + * Ðрхивы ÑчитаютÑÑ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ файлами. + * + * @param path Ð¸Ð¼Ñ Ð¿Ñ€Ð¾Ñматриваемой папки + * @param includeHidden включать Ñкрытые файлы в ÑпиÑок + * @return ÑпиÑок файлов + */ + public static Enumeration listNoArchives(String folder, boolean includeHidden) + { + Enumeration files = null; + + try + { + FileConnection fc = (FileConnection)Connector.openDirectConnection("file:///" + folder, Connector.READ); + files = fc.list("*", includeHidden); + fc.close(); + } + catch(Exception e) + { + } + + return files; + } + + /** + * ОпределÑем MIME тип файла по раÑширению. + * ТребуетÑÑ Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ð°ÑƒÐ´Ð¸Ð¾ из потока. + */ + public static String mimeType(String fileName) + { + return (String)mtypes.get(fileName.substring(fileName.lastIndexOf('.')).toLowerCase()); + } + + public static void deleteFileExFC(String fileName, boolean recursively, ProgressCallback callback) throws IOException + { + FileConnection conn = (FileConnection)Connector.open("file:///" + fileName); + + if(conn.isDirectory() && recursively) + { + if(fileName.charAt(fileName.length() - 1) == '/') + { + fileName = fileName.substring(0, fileName.length() - 1); + } + + Enumeration en = conn.list("*", true); + + while(en.hasMoreElements()) + { + deleteFileExFC(fileName + "/" + (String)(en.nextElement()), true, callback); + } + } + + if(callback != null) + { + callback.setText(fileName); // fileName.substring(fileName.lastIndexOf('/') + 1)); + } + + conn.delete(); + conn.close(); + } + + /** + * Удалить файл / папку + * + * @param fileName String - Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° + * @return boolean Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ ÑƒÐ´Ð°Ñ‡Ð½Ð° + */ + public static boolean deleteFile(String fileName, boolean recursively, ProgressCallback callback) + { + FileConnection conn = null; + + try + { + if(recursively) + { + deleteFileExFC(fileName, true, callback); + } + else + { + if(callback != null) + { + callback.setText(fileName); // fileName.substring(fileName.lastIndexOf('/') + 1)); + } + + conn = (FileConnection)Connector.open("file:///" + fileName); + conn.delete(); + conn.close(); + } + } + catch(Exception e) + { + return false; + } + + return true; + } + + /** + * Папка / файл Ñкрытый ? + * + * @param fileName String + * @return boolean + */ + public static boolean isHidden(String fn) + { + FileConnection conn = null; + boolean r = false; + + try + { + conn = (FileConnection)Connector.open("file:///" + fn, Connector.READ); + r = conn.isHidden(); + conn.close(); + } + catch(Exception e) + { + //System.out.println("is Hidden error"); + //e.printStackTrace(); + r = false; + } + + return r; + } + + /** + * Размер файла или папки + * + * @param fileName String Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°/папки + * @return long размер в байтах + */ + public static long getSize(String fileName, boolean includeSubDirs) + { + long size = -1; + + try + { + FileConnection conn = (FileConnection)Connector.open("file:///" + fileName, Connector.READ); + + if(conn.isDirectory()) + { + size = conn.directorySize(includeSubDirs); + + if(size < 0) + { + size = -2; + } + } + else + { + size = conn.fileSize(); + } + + conn.close(); + } + catch(Exception e) + { + size = -1; + } + + return size; + } + + public static long getCompressedSize(String fileName) + { + long size = -1; + + try + { + FileConnection conn = (FileConnection)Connector.open("file:///" + fileName, Connector.READ); + + if(conn.isDirectory()) + { + size = -2; + } + else if(conn instanceof ContainerFileConnection) + { + size = ((ContainerFileConnection)conn).compressedSize(); + } + + conn.close(); + } + catch(Exception e) + { + size = -1; + } + + return size; + } + + public static int[] getFileCount(String path, boolean includeHidden) + { + int[] res = new int[2]; + + if(!path.endsWith("/")) + { + path += "/"; + } + + try + { + Enumeration files = list(path, includeHidden); + String file; + + if(options.accurateDirCheck) + { + while(files.hasMoreElements()) + { + file = (String)files.nextElement(); + + if(isDir(path + file)) + { + res[0]++; + } + else + { + res[1]++; + } + } + } + else + { + while(files.hasMoreElements()) + { + file = (String)files.nextElement(); + + if(file.charAt(file.length() - 1) == '/') + { + res[0]++; + } + else + { + res[1]++; + } + } + } + } + catch(Exception e) + { + } + + return res; + } + + /** + * Файл только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ ? + * + * @param filename String + * @return boolean + */ + public static boolean isReadOnly(String fn) + { + FileConnection conn = null; + boolean r = false; + + try + { + conn = (FileConnection)Connector.open("file:///" + fn, Connector.READ); + r = !conn.canWrite(); + conn.close(); + } + catch(Exception e) + { + r = false; + } + + return r; + } + + /** + * ДоÑтупный размер диÑка + * + * @param filename String + * @return long + */ + public static long getDiskSpaceAvailable(String fn) + { + long size = -1; + FileConnection conn = null; + try + { + conn = (FileConnection)Connector.open("file:///" + fn, Connector.READ); + size = conn.availableSize(); + conn.close(); + } + catch(Exception e) + { + } + return size; + } + + /** + * Общий размер диÑка + * + * @param filename String + * @return long + */ + public static long getDiskSpaceTotal(String fn) + { + long size = -1; + FileConnection conn = null; + try + { + conn = (FileConnection)Connector.open("file:///" + fn, Connector.READ); + size = conn.totalSize(); + conn.close(); + } + catch(Exception e) + { + } + return size; + } + + /** + * Сделать файл Read-only + * + * @param filename String файл/папка + * @param yes boolean да/нет + * @return boolean Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ ÑƒÑпешна да/нет + */ + public static boolean setReadOnly(String fn, boolean readOnly) + { + FileConnection conn = null; + try + { + conn = (FileConnection)Connector.open("file:///" + fn, Connector.READ_WRITE); + conn.setWritable(!readOnly); + conn.close(); + } + catch(Exception e) + { + return false; + } + return true; + } + + /** + * Сделать файл Ñкрытым + * + * @param filename String файл/папка + * @param yes boolean да/нет + * @return boolean Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ ÑƒÑпешна да/нет + */ + public static boolean setHidden(String fn, boolean hidden) + { + FileConnection conn = null; + try + { + conn = (FileConnection)Connector.open("file:///" + fn, Connector.READ_WRITE); + conn.setHidden(hidden); + conn.close(); + } + catch(Exception e) + { + return false; + } + return true; + } + + /** + * Дата поÑледнего Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° + * + * @param filename String Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° + * @return long + */ + public static long lastModified(String fn) + { + long time = 0; + + FileConnection conn = null; + + try + { + conn = (FileConnection)Connector.open("file:///" + fn, Connector.READ); + time = conn.lastModified(); + conn.close(); + } + catch(Exception e) + { + } + + return time; + } + + /** + * Переименовать файл/папку + * + * @param oldName String + * @param newName String + * @return boolean + */ + public static boolean renameFile(String oldName, String newName, ProgressCallback callback) + { + FileConnection conn = null; + + try + { + if(callback != null) + { + callback.setText(oldName); // oldName.substring(oldName.lastIndexOf('/') + 1)); + } + + conn = (FileConnection)Connector.open("file:///" + oldName); + conn.rename(newName); + conn.close(); + } + catch(Exception e) + { + return false; + } + + return true; + } + + /** + * ÐерекурÑивно Ñоздать папку + */ + public static boolean makeNewDirNotRec(String fn) + { + FileConnection conn = null; + + try + { + conn = (FileConnection)Connector.open("file:///" + fn, Connector.READ_WRITE); + + if(!conn.exists() || !conn.isDirectory()) + { + conn.mkdir(); + } + + conn.close(); + + return true; + } + catch(Exception e) + { + return false; + } + } + + /** + * РекурÑивно Ñоздать папку (Ñ‚.е можно Ñоздавать Folder1/Folder2 где не + * ÑущеÑтвует ещё даже Folder1) + */ + public static boolean makeNewDir(String fn) + { + if(!makeNewDirNotRec(fn)) + { + if(fn.charAt(fn.length() - 1) == '/') + { + fn = fn.substring(0, fn.length() - 1); + } + + if(makeNewDir(fn.substring(0, fn.lastIndexOf('/')))) + { + return makeNewDirNotRec(fn + "/"); + } + } + else + { + return true; + } + + return false; + } + + /** + * Копировать Ñодержимое папки. + * + * @param oldName + * @param newName + * @param callback + * @return + */ + public static boolean copyDirectoryContents(String oldName, String newName, ProgressCallback callback, Vector errors) + { + if(oldName.charAt(oldName.length() - 1) != '/') + { + oldName += "/"; + } + + if(newName.charAt(newName.length() - 1) != '/') + { + newName += "/"; + } + + boolean r = true; + + Enumeration files = list(oldName, true); + String s; + + while(files.hasMoreElements()) + { + s = (String)files.nextElement(); + r &= copyFile(oldName + s, newName + s, callback, errors); + } + + return r; + } + + /** + * Копировать файл. + * Папки копируютÑÑ Ñ€ÐµÐºÑƒÑ€Ñивно. + * + * Ð’ Ñлучае Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½Ð¾Ð²ÐµÐ½Ð¸Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ¸ в переданный вектор кладетÑÑ Ð¿Ð°Ñ€Ð° вида + * new String[] { Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°, ошибка } + * + * @param oldFileName Ð¸Ð¼Ñ Ð¸Ñходного файла + * @param newFileName Ð¸Ð¼Ñ ÐºÐ¾Ð½ÐµÑ‡Ð½Ð¾Ð³Ð¾ файла + * @param callback кому Ñообщать о прогреÑÑе + * @param errors вектор, в который Ñкладывать ошибки + * @return true, еÑли копирование удалоÑÑŒ + */ + public static boolean copyFile(String oldFileName, String newFileName, ProgressCallback callback, Vector errors) + { + if(callback != null) + { + if(callback.getCancelFlag()) + { + return true; + } + + callback.setText(AuxClass.getSharedNamePart(oldFileName, newFileName)); + } + + FileConnection fc1 = null, fc2 = null; + + int bufsize = AuxClass.COPYBUFSIZE; + + //System.out.println (oldFileName + " -> " + newFileName); + + if(newFileName.startsWith("null:/")) + { + return true; + } + + try + { + fc1 = (FileConnection)Connector.open("file:///" + oldFileName, Connector.READ); + + if(!fc1.exists()) + { + throw new IOException("Source file does not exist"); + } + + if(fc1.isDirectory()) + { + fc2 = (FileConnection)Connector.open("file:///" + newFileName); + + if(fc2.exists() && !fc2.isDirectory()) + { + fc2.delete(); + } + + if(!fc2.exists()) + { + fc2.close(); + makeNewDir(newFileName); + } + else + { + fc2.close(); + } + + fc1.close(); + + return copyDirectoryContents(oldFileName, newFileName, callback, errors); + } + + fc2 = (FileConnection)Connector.open("file:///" + newFileName); + + if(!fc2.exists()) + { + fc2.create(); + } + else + { + fc2.truncate(0); + } + + byte[] buf = new byte[bufsize]; + + InputStream is = fc1.openInputStream(); + OutputStream os = fc2.openOutputStream(); + int len; + + if(callback != null) + { + len = (int)fc1.fileSize(); + + if(callback.getMax() <= len) + { + callback.setProgress(0); + callback.setMax(len); + } + + while((len = is.read(buf)) > 0) + { + os.write(buf, 0, len); + callback.progress(len); + } + } + else + { + while((len = is.read(buf)) > 0) + { + os.write(buf, 0, len); + } + } + + os.close(); + is.close(); + fc2.close(); + fc1.close(); + } + catch(IOException x) + { + //ErrScreen.showErrMsg(137, e); + + x.printStackTrace(); + errors.addElement(new String[] { oldFileName, AuxClass.formatException(x) }); + + return false; + } + + return true; + } + + /** + * Создать новый файл, запиÑать туда text в UTF-8 + * и опционально BOM UTF-8 Ñигнатуру. + */ + public static boolean makeNewFile(String fn, String text) + { + try + { + FileConnection fc = (FileConnection)Connector.open("file:///" + fn); + + if(fc.exists()) + { + fc.truncate(0); + } + else + { + fc.create(); + } + + DataOutputStream dos = fc.openDataOutputStream(); + + dos.write(StringEncoder.encodeString(text, StringEncoder.ENC_UTF8)); + + dos.close(); + fc.close(); + } + catch(Exception e) + { + return false; + } + + return true; + } + + /** + * Создать новый файл длиной len + * и заполнить его байтами b. + */ + public static boolean makeNewFile(String filename, String fill, int len) + { + try + { + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + + if(fc.exists()) + { + fc.truncate(0); + } + else + { + fc.create(); + } + + OutputStream os = fc.openOutputStream(); + + if(fill != null && fill.length() > 0) + { + int b = fill.charAt(0); + + try + { + byte[] buf = new byte[len]; + + for(int i = 0; i < len; i++) + { + buf[i] = (byte)b; + } + + os.write(buf); + } + catch(OutOfMemoryError oome) + { + for(int i = 0; i < len; i++) + { + os.write(b); + } + } + } + else + { + Random rnd = new Random(); + + for(int i = 0; i < len; i++) + { + os.write(rnd.nextInt()); + } + } + + os.close(); + fc.close(); + + return true; + } + catch(IOException ioe) + { + } + + return false; + } + + /** + * Преобразовывает чиÑло байт в нормальную Ñтроку Ñ Ñ€Ð°Ð·Ð¼ÐµÑ€Ð¾Ð¼ + */ + public static String getSizeString(long bytes, boolean fine) + { + String res; + + if(bytes < 1024) + { + res = Long.toString(bytes) + " " + Locale.getString(null, Locale.BYTE); + } + else if(bytes < 1048576) + { + res = AuxClass.doubleToString((double)bytes / 1024, 2) + " " + Locale.getString(null, Locale.KB); + } + else if(bytes < 1073741824) + { + res = AuxClass.doubleToString((double)bytes / 1048576, 2) + " " + Locale.getString(null, Locale.MB); + } + else + { + res = AuxClass.doubleToString((double)bytes / 1073741824, 2) + " " + Locale.getString(null, Locale.GB); + } + + if(fine && bytes >= 1024) + { + res += "\n" + AuxClass.formatNumber(bytes) + " " + Locale.getString(null, Locale.BYTE); + } + + return res; + } + + public static Enumeration listFilesOfType(String filename, String module, boolean includeHidden) + { + if(module == null) + { + module = ModuleRegistry.getModule(filename.substring(filename.lastIndexOf('.') + 1)); + + if(module == null) + { + Vector res = new Vector(1); + res.addElement(filename); + + return res.elements(); + } + } + + String folder = filename.substring(0, filename.lastIndexOf('/') + 1); + Enumeration items; + + if(folder.equals(main.currentPath)) + { + items = main.FileSelect.elements(); + } + else + { + Vector vector = new Vector(); + Enumeration files = list(folder, includeHidden); + + if(files == null) + { + return null; + } + + while(files.hasMoreElements()) + { + vector.addElement(new FileItem(folder, (String)files.nextElement(), false)); + } + + if(options.listSortBy > 0) + { + FileItem.sortFileList(vector, options.listSortBy, options.listSortIgnoreCase, !options.listSortReverseOrder, 1, vector.size() - 1); + } + + items = vector.elements(); + } + + Vector res = new Vector(); + FileItem file; + + while(items.hasMoreElements()) + { + file = (FileItem)items.nextElement(); + + if(module.equals(ModuleRegistry.getModule(file.getType()))) + { + res.addElement(file.getFullName()); + } + } + + return res.elements(); + } + + /* + protected static void listFilesRec(Vector target, String path, int type, boolean includeHidden) + { + Vector dirs = new Vector(); + String s = ""; + + try + { + String[] flist = list(path, includeHidden); + + if(path.charAt(path.length() - 1) != '/') + { + path += '/'; + } + + for(int i = 0; i < flist.length; i++) + { + if(fileType(flist[i]) == type) + { + target.addElement(path + flist[i]); + } + else + { + flist[i] = path + flist[i]; + + if(isDir(flist[i])) + { + dirs.addElement(flist[i]); + } + } + } + } + catch(Exception e) + { + ErrScreen.showErrMsg("List files rec error", e); + return; + } + + for(int i = 0; i < dirs.size(); i++) // Enumeration e = dirs.elements(); e != null && e.hasMoreElements(); s = (String)e.nextElement()) + { + listFilesRec(target, path + dirs.elementAt(i), type, includeHidden); + } + } + */ + + /* + public static void sortFileList(String[] fileList) throws IOException + { + if(options.listSortBy == 0) + { + return; + } + + Vector vdirs = new Vector(); + Vector vfiles = new Vector(); + + String[] dirs, files; + + for(int i = 0; i < fileList.length; i++) + { + if(isDir(fileList[i])) + { + vdirs.addElement(fileList[i]); + } + else + { + vfiles.addElement(fileList[i]); + } + } + + dirs = new String[vdirs.size()]; + vdirs.copyInto(dirs); + vdirs = null; + + files = new String[vfiles.size()]; + vfiles.copyInto(files); + vfiles = null; + + String[] as = null; + long[] al = null; + + if(dirs.length > 0) + { + if(options.listSortBy == 1) + { + quickSort(dirs, 0, dirs.length - 1); + } + else if(options.listSortBy == 3) + { + al = new long[dirs.length]; + + for(int i = 0; i < al.length; i++) + { + al[i] = lastModified(main.currentPath + dirs[i]); + } + + quickSortLong(al, dirs, 0, al.length - 1); + } + else if(options.listSortBy == 4) + { + al = new long[dirs.length]; + + for(int i = 0; i < al.length; i++) + { + al[i] = getSize(main.currentPath + dirs[i]); + } + + quickSortLong(al, dirs, 0, al.length - 1); + } + } + + if(files.length > 0) + { + if(options.listSortBy == 1) + { + quickSort(files, 0, files.length - 1); + } + else if(options.listSortBy == 2) + { + as = new String[files.length]; + + for(int i = 0; i < as.length; i++) + { + as[i] = files[i].substring(files[i].lastIndexOf('.') + 1); + } + + quickSortString(as, files, 0, as.length - 1); + } + else if(options.listSortBy == 3) + { + al = new long[files.length]; + + for(int i = 0; i < al.length; i++) + { + al[i] = lastModified(main.currentPath + files[i]); + } + + quickSortLong(al, files, 0, al.length - 1); + } + else if(options.listSortBy == 4) + { + al = new long[files.length]; + + for(int i = 0; i < al.length; i++) + { + al[i] = getSize(main.currentPath + files[i]); + } + + quickSortLong(al, files, 0, al.length - 1); + } + } + + System.arraycopy(dirs, 0, fileList, 0, dirs.length); + System.arraycopy(files, 0, fileList, dirs.length, files.length); + + dirs = null; + files = null; + } + */ + + public static void quickSort(String[] arr, int first, int last) + { + String p = arr[(last - first) / 2 + first].toLowerCase(); + String temp; + int i = first, j = last; + + while(i <= j) + { + while(arr[i].toLowerCase().compareTo(p) < 0 && i <= last) + { + i++; + } + + while(arr[j].toLowerCase().compareTo(p) > 0 && j >= first) + { + j--; + } + + if(i <= j) + { + temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + + i++; + j--; + } + } + + if(j > first) + { + quickSort(arr, first, j); + } + + if(i < last) + { + quickSort(arr, i, last); + } + } + + /* + public static void quickSortString(String[] arr, String[] val, int first, int last) + { + String p = arr[(last - first) / 2 + first].toLowerCase(); + String temp, vtemp; + int i = first, j = last; + + while(i <= j) + { + while(arr[i].toLowerCase().compareTo(p) < 0 && i <= last) + { + i++; + } + + while(arr[j].toLowerCase().compareTo(p) > 0 && j >= first) + { + j--; + } + + if(i <= j) + { + temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + + vtemp = val[i]; + val[i] = val[j]; + val[j] = vtemp; + + i++; + j--; + } + } + + if(j > first) + { + quickSortString(arr, val, first, j); + } + + if(i < last) + { + quickSortString(arr, val, i, last); + } + } + + public static void quickSortLong(long[] arr, String[] val, int first, int last) + { + long p = arr[(last - first) / 2 + first]; + long temp; + String vtemp; + int i = first, j = last; + + while(i <= j) + { + while(arr[i] < p && i <= last) + { + i++; + } + + while(arr[j] > p && j >= first) + { + j--; + } + + if(i <= j) + { + temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + + vtemp = val[i]; + val[i] = val[j]; + val[j] = vtemp; + + i++; + j--; + } + } + + if(j > first) + { + quickSortLong(arr, val, first, j); + } + + if(i < last) + { + quickSortLong(arr, val, i, last); + } + } + */ + +// private static void out(String s) +// { +// System.out.println("[filesystem] " + s); +// } +} diff --git a/src/filemanager/frmCrypt.java b/src/filemanager/frmCrypt.java new file mode 100644 index 0000000..649b685 --- /dev/null +++ b/src/filemanager/frmCrypt.java @@ -0,0 +1,50 @@ +package filemanager; + +import com.vmx.Locale; +import javax.microedition.lcdui.*; + +public class frmCrypt extends Form implements CommandListener +{ + Object parent; + TextField tf; + + public frmCrypt(Object p) + { + super(""); + setTitle(Locale.getString(this, Locale.CRYPT_CMD)); + + parent = p; + + if(Buffer.getSize() == 0) + { + Buffer.add(main.currentPath + main.currentFile, false); + } + + tf = new TextField(Locale.getString(this, Locale.PASSWORD), "", 1024, TextField.ANY); + append(tf); + + append(Locale.getString(this, Locale.CRYPT_USAGE)); + + addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 1)); + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + + setCommandListener(this); + } + + /** + * Обработчик команд + */ + public void commandAction(Command c, Displayable d) + { + main.dsp.setCurrent(parent); + + if(c.getCommandType() == Command.OK) + { + Buffer.startOperation(new CryptThread(tf.getString())); + } + else + { + Buffer.clear(); + } + } +} diff --git a/src/filemanager/frmEULA.java b/src/filemanager/frmEULA.java new file mode 100644 index 0000000..7bcbd3f --- /dev/null +++ b/src/filemanager/frmEULA.java @@ -0,0 +1,32 @@ +package filemanager; + +import com.vmx.Locale; +import javax.microedition.lcdui.*; + +public class frmEULA extends Form implements CommandListener +{ + public frmEULA() + { + super(""); + setTitle(Locale.getString(this, Locale.LICENSE_AGR)); + + append(Locale.getLicenseString()); + addCommand(new Command(Locale.getString(this, Locale.NO_CMD), Command.EXIT, 1)); + addCommand(new Command(Locale.getString(this, Locale.YES_CMD), Command.OK, 1)); + setCommandListener(this); + } + + public void commandAction(Command command, Displayable displayable) + { + if(command.getCommandType() == Command.OK) + { + options.firstTime = 0; + main.startUI(); + } + else if(command.getCommandType() == Command.EXIT) + { + options.firstTime = 1; + main.destroyApp(); + } + } +} diff --git a/src/filemanager/frmHash.java b/src/filemanager/frmHash.java new file mode 100644 index 0000000..4b4ec54 --- /dev/null +++ b/src/filemanager/frmHash.java @@ -0,0 +1,69 @@ +package filemanager; + +import com.vmx.Locale; +import javax.microedition.lcdui.*; +import java.io.*; +import com.one.*; +import com.vmx.AuxClass; + +public class frmHash extends Form implements CommandListener +{ + protected Displayable parent; + + protected TextField tfSHA1, tfMD5; + + public frmHash(InputStream is, Displayable p) throws IOException + { + super(""); + setTitle(Locale.getString(this, Locale.HASH_SUM)); + + parent = p; + + MD5 md5 = new MD5(); + SHA1 sha1 = new SHA1(); + + byte[] b = new byte[AuxClass.COPYBUFSIZE]; + int len; + + while(is.available() > 0) + { + len = is.read(b); + + md5.update(b, 0, len); + sha1.update(b, 0, len); + } + + String temp; + + tfMD5 = new TextField("MD5", temp = intArrayToHexString(md5.digest()), temp.length(), TextField.ANY); + tfSHA1 = new TextField("SHA-1", temp = intArrayToHexString(sha1.digest()), temp.length(), TextField.ANY); + + append(tfMD5); + append(tfSHA1); + + addCommand(new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 1)); + setCommandListener(this); + } + + public static String intArrayToHexString(int[] arr) + { + if(arr.length == 0) + { + return ""; + } + + String temp = Integer.toHexString(arr[0]).toUpperCase(); + + for(int i = 1; i < arr.length; i++) + { + temp += " " + Integer.toHexString(arr[i]).toUpperCase(); + } + + return temp; + } + + public void commandAction(Command c, Displayable dp) + { + main.dsp.setCurrent(parent); + } +} diff --git a/src/filemanager/frmInitialSetup.java b/src/filemanager/frmInitialSetup.java new file mode 100644 index 0000000..c0c62ef --- /dev/null +++ b/src/filemanager/frmInitialSetup.java @@ -0,0 +1,62 @@ +package filemanager; + +import com.vmx.Locale; +import javax.microedition.lcdui.*; +import com.vmx.gkcCanvas; + +public class frmInitialSetup extends Form implements CommandListener +{ + protected ChoiceGroup cgKeyMap, + cgLang; + + public frmInitialSetup() + { + super(""); + setTitle(Locale.getString(this, Locale.INITIAL_SETUP)); + + cgKeyMap = new ChoiceGroup(Locale.getString(this, Locale.PREF_KEYMAP), ChoiceGroup.EXCLUSIVE); + + for(int i = 0; i < gkcCanvas.platforms.length; i++) + { + cgKeyMap.append(gkcCanvas.platforms[i], null); + cgKeyMap.setSelectedIndex(i, i == options.keyMap); + } + + cgLang = new ChoiceGroup(Locale.getString(this, Locale.PREF_LANG), ChoiceGroup.EXCLUSIVE); + + for(int i = 0; i < Locale.languages.length; i++) + { + cgLang.append(Locale.languages[i], null); + cgLang.setSelectedIndex(i, options.language.equals(Locale.locales[i])); + } + + append(cgLang); + append(cgKeyMap); + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + setCommandListener(this); + } + + public void commandAction(Command c, Displayable dp) + { + if(dp == this) + { + options.keyMap = (byte)cgKeyMap.getSelectedIndex(); + options.language = Locale.locales[cgLang.getSelectedIndex()]; + options.firstTime = 1; + + gkcCanvas.setKeyMap(options.keyMap, options.screenTransform); + keyConfig.addDefaultKeys(); + + GraphicAlert alert = new GraphicAlert(Locale.getString(this, Locale.ATTENTION), Locale.getString(this, Locale.NEED_RESTART), images.getAlertIcon(AlertType.INFO), null); + alert.setTimeout(3000); + alert.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + alert.setCommandListener(this); + main.dsp.setCurrent(alert); + } + else + { + main.loader.restartApp(); + } + } +} diff --git a/src/filemanager/frmNewFile.java b/src/filemanager/frmNewFile.java new file mode 100644 index 0000000..479dabb --- /dev/null +++ b/src/filemanager/frmNewFile.java @@ -0,0 +1,130 @@ +package filemanager; + +import com.one.ErrScreen; +import com.one.FileSource; +import com.one.ModuleRegistry; +import javax.microedition.lcdui.*; +import com.vmx.*; +import java.util.Enumeration; +import java.util.Vector; + +public class frmNewFile extends Form implements CommandListener, ItemStateListener +{ + private Object parent; + + private Vector filesources; + private String filext; + + private TextField tf; + private ChoiceGroup cg; + + public frmNewFile(Object parent, int type) + { + super(""); + setTitle(Locale.getString(this, Locale.CREATE_NEW_FILE)); + + this.parent = parent; + + Enumeration fse = (type == FileSource.TYPE_CONTAINER ? ModuleRegistry.listContainerSources() : ModuleRegistry.listFileSources()); + String filesource; + + cg = new ChoiceGroup(Locale.getString(this, Locale.FILE_TYPE), Choice.EXCLUSIVE); + filesources = new Vector(); + int index = 0; + + while(fse.hasMoreElements()) + { + filesource = (String)fse.nextElement(); + + cg.append(ModuleRegistry.getModuleName(filesource), ModuleRegistry.getIcon(filesource)); + filesources.addElement(filesource); + } + + if(filesources.isEmpty()) + { + addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 2)); + setCommandListener(this); + } + else + { + cg.setSelectedIndex(index, true); + + filext = AuxClass.formatFileExtension(ModuleRegistry.getExtension((String)filesources.elementAt(index))); + + // if(filext.length() == 0) + // { + // filext = null; + // } + + tf = new TextField(Locale.getString(this, Locale.NAME), AuxClass.timeToFileName(-1) + filext, 256, TextField.ANY); + + append(tf); + append(cg); + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 2)); + setCommandListener(this); + setItemStateListener(this); + } + } + + public void commandAction(Command command, Displayable displayable) + { + if(command.getCommandType() == Command.OK) + { + String filename = main.currentPath + tf.getString(); + + if(filesystem.isFileExist(filename)) // уже ÑущеÑтвует + { + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.NAME_EXIST_SELECT_ANOTHER), AlertType.WARNING, 3000, this); + } + else + { + try + { + ((FileSource)ModuleRegistry.getModuleInstance((String)filesources.elementAt(cg.getSelectedIndex()))).createFile(filename); + } + catch(Exception e) + { + ErrScreen.showErrMsg(128, e); + } + } + } + else + { + main.dsp.setCurrent(parent); + } + } + + public void itemStateChanged(Item item) + { + if(item == cg) + { + String newext = AuxClass.formatFileExtension(ModuleRegistry.getExtension((String)filesources.elementAt(cg.getSelectedIndex()))); + + String filename = tf.getString(); + int index = filename.lastIndexOf('.'); + + if(index >= 0) + { + String ext = filename.substring(index); + + if(ext.equalsIgnoreCase(filext)) + { + filename = filename.substring(0, index) + newext; + } + else if(!ext.equalsIgnoreCase(newext)) + { + filename += newext; + } + } + else + { + filename += newext; + } + + tf.setString(filename); + filext = newext; + } + } +} diff --git a/src/filemanager/frmNewFolder.java b/src/filemanager/frmNewFolder.java new file mode 100644 index 0000000..d916d47 --- /dev/null +++ b/src/filemanager/frmNewFolder.java @@ -0,0 +1,67 @@ +package filemanager; // переведен + +import com.vmx.Locale; +import com.one.TextProcessor; +import com.vmx.AuxClass; +import javax.microedition.lcdui.*; + +public class frmNewFolder extends Form implements CommandListener +{ + private Object parent; + private TextField tf; + + public frmNewFolder(Object parent) + { + super(""); + setTitle(Locale.getString(this, Locale.CREATE_NEW_FOLDER)); + + this.parent = parent; + + tf = new TextField(Locale.getString(this, Locale.NAME), AuxClass.timeToFileName(-1), 256, TextField.ANY); + + append(tf); + + addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 1)); + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + setCommandListener(this); + } + + public void commandAction(Command command, Displayable displayable) + { + if(command.getCommandType() == Command.OK) + { + String s = tf.getString(); + + if(s.length() == 0) + { + return; + } + + if(!AuxClass.checkFileName(s)) + { + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.RESTRICTED_FILE_NAME, TextProcessor.interlaceString(AuxClass.RESTRICTED_CHARS, " ")), AlertType.WARNING, 3000, this); + return; + } + + s = main.currentPath + s + "/"; + + if(filesystem.isFileExist(s)) + { + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.NAME_EXIST_SELECT_ANOTHER), AlertType.WARNING, 3000, this); + return; + } + + if(!filesystem.makeNewDir(s)) + { + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.NOT_CREATE_NEW_FOLDER), AlertType.ERROR, 3000, parent); + return; + } + + cvsWait.start(main.FileSelect, tf.getString() + "/"); + } + else + { + main.dsp.setCurrent(parent); + } + } +} diff --git a/src/filemanager/frmOptions.java b/src/filemanager/frmOptions.java new file mode 100644 index 0000000..9c0e458 --- /dev/null +++ b/src/filemanager/frmOptions.java @@ -0,0 +1,498 @@ +package filemanager; // переведен + +import com.vmx.Locale; +import com.one.ErrScreen; +import com.one.ModuleRegistry; +import com.one.OptionStorage; +import com.one.Renderer; +import com.vmx.StringEncoder; +import java.util.Enumeration; +import java.util.Vector; +import javax.microedition.lcdui.*; + +public class frmOptions extends Form implements CommandListener, ItemStateListener +{ + protected ChoiceGroup cgLang, + cgVisual, + cgBrowse, + cgListSortBy, + cgSortOptions, + cgColorScheme, + cgArcEnc, + cgLightControl, + //cgOptions_screenTransform, + cgFullFileNames, + cgLargeFont; + + protected TextField tfKeyVibraDuration, + tfMMDelay, + tfMMThreshold, + tfLongScrollSpeed; + + protected Object parent; + protected boolean restart_flag = false; + + protected Vector modules; + protected List modlist; + + protected Command cmdOK, cmdModules, cmdBack; + + public frmOptions(Object parent) + { + super(""); + setTitle(Locale.getString(this, Locale.PREFERENCES_CMD)); + + this.parent = parent; + + // *** Визуальные Ñффекты *** + cgVisual = new ChoiceGroup(Locale.getString(this, Locale.PREF_VISUAL), Choice.MULTIPLE); + + // Ðе показывать "ПожалуйÑта, подождите" (cvsWait) + cgVisual.append(Locale.getString(this, Locale.PREF_NO_EFFECTS), null); + cgVisual.setSelectedIndex(0, options.noEffects); + + // Показывать ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ð± ошибках + cgVisual.append(Locale.getString(this, Locale.PREF_SHOW_ERRORS), null); + cgVisual.setSelectedIndex(1, options.showErrors); + + // Показывать номера в меню + cgVisual.append(Locale.getString(this, Locale.PREF_SHOW_MENU_NUM), null); + cgVisual.setSelectedIndex(2, options.showMenuNum); + + // КурÑор в виде рамки + cgVisual.append(Locale.getString(this, Locale.PREF_FRAME_CURSOR), null); + cgVisual.setSelectedIndex(3, options.frameCursor); + + // Проигрывать Ñигналы в ÑообщениÑÑ… + cgVisual.append(Locale.getString(this, Locale.PREF_PLAY_ALERT_SOUNDS), null); + cgVisual.setSelectedIndex(4, options.playAlertSounds); + + // РаÑширенное меню + cgVisual.append(Locale.getString(this, Locale.PREF_USE_FULL_MENU), null); + cgVisual.setSelectedIndex(5, options.useFullMenu); + + // ЧаÑÑ‹ внизу Ñкрана + cgVisual.append(Locale.getString(this, Locale.PREF_ALTER_CLOCK_POS), null); + cgVisual.setSelectedIndex(6, options.alterClockPos); + + // ПоменÑÑ‚ÑŒ Ñофт-клавиши + cgVisual.append(Locale.getString(this, Locale.PREF_SWAP_SOFT_KEYS), null); + cgVisual.setSelectedIndex(7, options.swapSoftKeys); + + // Переводить курÑор при выделении + cgVisual.append(Locale.getString(this, Locale.PREF_MARK_MOVE_NEXT), null); + cgVisual.setSelectedIndex(8, options.markMoveNext); + + // Улучшенные градиенты + cgVisual.append(Locale.getString(this, Locale.PREF_DITHER_GRADIENTS), null); + cgVisual.setSelectedIndex(9, options.ditherGradients); + + // Прозрачные градиенты + cgVisual.append(Locale.getString(this, Locale.PREF_ALPHA_GRADIENTS), null); + cgVisual.setSelectedIndex(10, options.alphaGradients); + + // "Выход" в ÑпиÑке диÑков + cgVisual.append(Locale.getString(this, Locale.PREF_EXIT_FROM_DRIVE_LIST), null); + cgVisual.setSelectedIndex(11, options.exitFromDriveList); + + // *** Полные имена файлов *** + cgFullFileNames = new ChoiceGroup(Locale.getString(this, Locale.PREF_FULL_FILE_NAMES), Choice.MULTIPLE); + + cgFullFileNames.append(Locale.getString(this, Locale.IN_BUFFER), null); + cgFullFileNames.setSelectedIndex(0, options.fullNamesInBuf); + + cgFullFileNames.append(Locale.getString(this, Locale.IN_FAVOURITES), null); + cgFullFileNames.setSelectedIndex(1, options.fullNamesInFav); + + // *** Крупный шрифт *** + cgLargeFont = new ChoiceGroup(Locale.getString(this, Locale.PREF_LARGE_FONT), Choice.MULTIPLE); + + cgLargeFont.append(Locale.getString(this, Locale.IN_FILE_LIST), null); + cgLargeFont.setSelectedIndex(0, options.largeFontInList); + + cgLargeFont.append(Locale.getString(this, Locale.IN_MENU), null); + cgLargeFont.setSelectedIndex(1, options.largeFontInMenu); + + // *** Поворот Ñкрана *** +// cgOptions_screenTransform = new ChoiceGroup(Locale.getString(this, Locale.PREF_SCREEN_TRANSFORM), Choice.EXCLUSIVE); +// +// cgOptions_screenTransform.append(Locale.getString(this, Locale.ROTATE_BY, "0"), null); +// cgOptions_screenTransform.append(Locale.getString(this, Locale.ROTATE_BY, "90"), null); +// cgOptions_screenTransform.append(Locale.getString(this, Locale.ROTATE_BY, "180"), null); +// cgOptions_screenTransform.append(Locale.getString(this, Locale.ROTATE_BY, "270"), null); +// +// switch(options.screenTransform) +// { +// case Sprite.TRANS_ROT90: +// cgOptions_screenTransform.setSelectedIndex(1, true); +// break; +// +// case Sprite.TRANS_ROT180: +// cgOptions_screenTransform.setSelectedIndex(2, true); +// break; +// +// case Sprite.TRANS_ROT270: +// cgOptions_screenTransform.setSelectedIndex(3, true); +// break; +// +// default: +// cgOptions_screenTransform.setSelectedIndex(0, true); +// break; +// } + + // *** ПоÑтоÑÐ½Ð½Ð°Ñ Ð¿Ð¾Ð´Ñветка *** + cgLightControl = new ChoiceGroup(Locale.getString(this, Locale.PREF_LIGHT_CONTROL_MODE), Choice.EXCLUSIVE); + + cgLightControl.append(Locale.getString(this, Locale.DISABLED), null); + cgLightControl.append(Locale.getString(this, Locale.ENABLED), null); + cgLightControl.append(Locale.getString(this, Locale.AUTOMATIC), null); + + cgLightControl.setSelectedIndex(options.lightControlMode, true); + + // *** Параметры проÑмотра и Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ *** + cgBrowse = new ChoiceGroup(Locale.getString(this, Locale.PREF_BROWSE), Choice.MULTIPLE); + + // Показывать Ñкрытые файлы и папки + cgBrowse.append(Locale.getString(this, Locale.PREF_SHOW_HIDDEN_FILES), null); + cgBrowse.setSelectedIndex(0, options.showHidden); + + // ПроверÑÑ‚ÑŒ аттрибуты файлов + cgBrowse.append(Locale.getString(this, Locale.PREF_CHECK_FILE_ATTRIB), null); + cgBrowse.setSelectedIndex(1, options.checkFileAttrib); + + // Ð¢Ð¾Ñ‡Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° директорий (через FileConnection) + cgBrowse.append(Locale.getString(this, Locale.PREF_ACCURATE_DIR_CHECK), null); + cgBrowse.setSelectedIndex(2, options.accurateDirCheck); + + // Открывать неподдерживаемые как текÑÑ‚ + cgBrowse.append(Locale.getString(this, Locale.PREF_OPEN_NOT_SUPP), null); + cgBrowse.setSelectedIndex(3, options.openNotSupported); + + // СохранÑÑ‚ÑŒ открытые пути + cgBrowse.append(Locale.getString(this, Locale.PREF_REMEMBER_PATH), null); + cgBrowse.setSelectedIndex(4, options.rememberPath); + + // Загружать "комплементарные кодовые таблицы" % + cgBrowse.append(Locale.getString(this, Locale.PREF_CACHE_CODE_PAGES), null); + cgBrowse.setSelectedIndex(5, options.cacheCodePages); + + // *** ÐаÑтройка Ñортировки *** + cgListSortBy = new ChoiceGroup(Locale.getString(this, Locale.PREF_SORT_FILE_LIST), Choice.EXCLUSIVE); + + cgListSortBy.append(Locale.getString(this, Locale.SORT_NONE), null); + cgListSortBy.append(Locale.getString(this, Locale.SORT_BY_NAME), null); + cgListSortBy.append(Locale.getString(this, Locale.SORT_BY_TYPE), null); + cgListSortBy.append(Locale.getString(this, Locale.SORT_BY_DATE), null); + cgListSortBy.append(Locale.getString(this, Locale.SORT_BY_SIZE), null); + + cgListSortBy.setSelectedIndex(options.listSortBy, true); + + // *** Опции Ñортировки *** + cgSortOptions = new ChoiceGroup(Locale.getString(this, Locale.PREF_SORT_OPTIONS), Choice.MULTIPLE); + + // Ð’ обратном порÑдке + cgSortOptions.append(Locale.getString(this, Locale.SORT_REVERSE_ORDER), null); + cgSortOptions.setSelectedIndex(0, options.listSortReverseOrder); + + // Ðе учитывать региÑÑ‚Ñ€ + cgSortOptions.append(Locale.getString(this, Locale.IGNORE_CASE), null); + cgSortOptions.setSelectedIndex(1, options.listSortIgnoreCase); + + // *** СкороÑÑ‚ÑŒ прокрутки длинных имен + tfLongScrollSpeed = new TextField(Locale.getString(this, Locale.PREF_LONG_SCROLL_SPEED), Float.toString(options.longScrollSpeed), 20, TextField.DECIMAL); + + // *** Ð’Ð¸Ð±Ñ€Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸ нажатии клавиш *** + tfKeyVibraDuration = new TextField(Locale.getString(this, Locale.PREF_KEY_VIBRA_DURATION), Integer.toString(options.keyVibraDuration), 3, TextField.NUMERIC); + + // *** ÐаÑтройки монитора памÑти *** + + // Шаг монитора памÑти + tfMMDelay = new TextField(Locale.getString(this, Locale.PREF_MM_DELAY), Integer.toString(options.mmDelay), 4, TextField.NUMERIC); + + // Порог Ñборщика муÑора + tfMMThreshold = new TextField(Locale.getString(this, Locale.PREF_MM_THRESHOLD), Integer.toString(options.mmThreshold), 3, TextField.NUMERIC); + + // *** Цветовые Ñхемы *** + cgColorScheme = new ChoiceGroup(Locale.getString(this, Locale.COLOR_SCHEME), Choice.EXCLUSIVE); + + for(int i = 0; i < ColorScheme.schemes.length; i++) + { + cgColorScheme.append(ColorScheme.schemes[i], null); + } + + cgColorScheme.append(Locale.getString(this, Locale.PREF_CUSTOM_COLOR_SCHEME), null); + + if(options.colorScheme == ColorScheme.SCHEME_CUSTOM) + { + cgColorScheme.setSelectedIndex(cgColorScheme.size() - 1, true); + } + else + { + cgColorScheme.setSelectedIndex(options.colorScheme, true); + } + + // *** СпиÑок Ñзыков *** + cgLang = new ChoiceGroup(Locale.getString(this, Locale.PREF_LANG), Choice.EXCLUSIVE); + + for(int i = 0; i < Locale.languages.length; i++) + { + cgLang.append(Locale.languages[i], null); + cgLang.setSelectedIndex(i, options.language.equals(Locale.locales[i])); + } + + // *** Кодировка архивов *** + cgArcEnc = new ChoiceGroup(Locale.getString(this, Locale.PREF_ARCHIVE_ENCODING), Choice.EXCLUSIVE); + + cgArcEnc.append(StringEncoder.ENC_NAME_UTF8, null); + + for(int i = 0; i < StringEncoder.encnames.length; i++) + { + cgArcEnc.append(StringEncoder.encnames[i], null); + } + + if(options.arcEnc == StringEncoder.ENC_UTF8) + { + cgArcEnc.setSelectedIndex(0, true); + } + else + { + cgArcEnc.setSelectedIndex(options.arcEnc + 1, true); + } + + append(cgLang); + append(cgBrowse); + append(cgListSortBy); + append(cgSortOptions); + append(cgVisual); + append(cgFullFileNames); + append(cgLargeFont); + append(cgLightControl); + append(cgColorScheme); + //append(cgOptions_screenTransform); + append(tfLongScrollSpeed); + append(tfKeyVibraDuration); + append(cgArcEnc); + append(tfMMDelay); + append(tfMMThreshold); + + addCommand(cmdOK = new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + addCommand(cmdModules = new Command(Locale.getString(this, Locale.MODULES_CMD), Command.OK, 2)); + addCommand(cmdBack = new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 3)); + + setCommandListener(this); + setItemStateListener(this); + + modules = new Vector(); + modlist = new List(Locale.getString(this, Locale.MODULES_CMD), Choice.IMPLICIT); + + Enumeration e = ModuleRegistry.listOptionStores(); + String s; + + while(e.hasMoreElements()) + { + s = (String)e.nextElement(); + + modules.addElement(s); + modlist.append(ModuleRegistry.getModuleName(s), null); + } + + modlist.addCommand(cmdBack); + modlist.setCommandListener(this); + } + + /** + * Обработчик команд + */ + public void commandAction(Command c, Displayable d) + { + if(d == this) + { + if(c == cmdOK) + { + options.noEffects = cgVisual.isSelected(0); + options.showErrors = cgVisual.isSelected(1); + options.showMenuNum = cgVisual.isSelected(2); + options.frameCursor = cgVisual.isSelected(3); + options.playAlertSounds = cgVisual.isSelected(4); + options.useFullMenu = cgVisual.isSelected(5); + options.alterClockPos = cgVisual.isSelected(6); + options.swapSoftKeys = cgVisual.isSelected(7); + options.markMoveNext = cgVisual.isSelected(8); + options.ditherGradients = cgVisual.isSelected(9); + options.alphaGradients = cgVisual.isSelected(10); + options.exitFromDriveList = cgVisual.isSelected(11); + + options.fullNamesInBuf = cgFullFileNames.isSelected(0); + options.fullNamesInFav = cgFullFileNames.isSelected(1); + + options.largeFontInList = cgLargeFont.isSelected(0); + options.largeFontInMenu = cgLargeFont.isSelected(1); + + options.lightControlMode = cgLightControl.getSelectedIndex(); + + options.keyVibraDuration = Integer.parseInt(tfKeyVibraDuration.getString()); + Renderer.setVibraDuration(options.keyVibraDuration); + + options.longScrollSpeed = Float.parseFloat(tfLongScrollSpeed.getString()); + + options.mmDelay = Integer.parseInt(tfMMDelay.getString()); + options.mmThreshold = Integer.parseInt(tfMMThreshold.getString()); + + main.monitor.setDelay(options.mmDelay); + main.monitor.setThreshold(options.mmThreshold); + + if(cgArcEnc.getSelectedIndex() == 0) + { + options.arcEnc = StringEncoder.ENC_UTF8; + } + else + { + options.arcEnc = cgArcEnc.getSelectedIndex() - 1; + } + + StringEncoder.ENC_ARCHIVE = options.arcEnc; + + //images.loadIcons(); + + // if(cgOptions_show3.isSelected(0) != options.showDisk3) + // { + // options.showDisk3 = cgOptions_show3.isSelected(0); + // cvsWait.start(); + // } + + //options.showDisk3 = cgOptions_show3.isSelected(0); + + options.showHidden = cgBrowse.isSelected(0); + options.checkFileAttrib = cgBrowse.isSelected(1); + options.accurateDirCheck = cgBrowse.isSelected(2); + options.openNotSupported = cgBrowse.isSelected(3); + options.rememberPath = cgBrowse.isSelected(4); + options.cacheCodePages = cgBrowse.isSelected(5); + + options.listSortBy = cgListSortBy.getSelectedIndex(); + + options.listSortReverseOrder = cgSortOptions.isSelected(0); + options.listSortIgnoreCase = cgSortOptions.isSelected(1); + + options.colorScheme = cgColorScheme.getSelectedIndex(); + + if(options.colorScheme == cgColorScheme.size() - 1) + { + options.colorScheme = ColorScheme.SCHEME_CUSTOM; + } + else + { + try + { + if(ColorScheme.loadColorScheme(options.colorScheme)) + { + main.FileSelect.updateModuleList(); + } + + //main.FileSelect.updateGradients(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(49, e); + } + } + + try + { + Locale.loadLocale(Locale.locales[cgLang.getSelectedIndex()]); + options.language = Locale.lang; + } + catch(Exception e) + { + ErrScreen.showErrMsg(50, e); + + try + { + Locale.loadLocale(options.language); + } + catch(Exception e1) + { + //ErrScreen.showErrMsg("Cannot load even previous \"" + Locale.lang + "\" locale", e); + } + } + + main.startLightControl(false); + + // switch(cgOptions_screenTransform.getSelectedIndex()) + // { + // case 0: + // options.screenTransform = Sprite.TRANS_NONE; + // break; + // + // case 1: + // options.screenTransform = Sprite.TRANS_ROT90; + // break; + // + // case 2: + // options.screenTransform = Sprite.TRANS_ROT180; + // break; + // + // case 3: + // options.screenTransform = Sprite.TRANS_ROT270; + // break; + // } + + options.saveOptions(); + + if(restart_flag) + { + main.loader.restartApp(); + } + else + { + cvsWait.start(main.FileSelect, main.currentFile); + } + } + else if(c == cmdModules) + { + main.dsp.setCurrent(modlist); + } + else if(c == cmdBack) + { + main.dsp.setCurrent(parent); + } + } + else if(d == modlist) + { + if(c == List.SELECT_COMMAND) + { + ((OptionStorage)ModuleRegistry.getModuleInstance((String)modules.elementAt(modlist.getSelectedIndex()))).showEditor(modlist); + } + else + { + main.dsp.setCurrent(this); + } + } + } + + /** + * Обработчик Ð¿ÐµÑ€ÐµÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ ÑоÑтоÑÐ½Ð¸Ñ Ñлемента + */ + public void itemStateChanged(Item item) + { + if(item == cgLang || + item == cgLargeFont) + { + if(restart_flag) + { + return; + } + + main.showMessage(Locale.getString(this, Locale.ATTENTION), Locale.getString(this, Locale.NEED_RESTART), AlertType.INFO, 3000, this); + + restart_flag = true; + } + else if(item == cgColorScheme) + { + if(cgColorScheme.getSelectedIndex() == cgColorScheme.size() - 1) + { + main.showColorSchemeEditor(this); + } + } + } +} diff --git a/src/filemanager/frmProperties.java b/src/filemanager/frmProperties.java new file mode 100644 index 0000000..3b88eb1 --- /dev/null +++ b/src/filemanager/frmProperties.java @@ -0,0 +1,165 @@ +package filemanager; // переведен + +import com.vmx.Locale; +import javax.microedition.lcdui.*; +import com.vmx.AuxClass; + +public class frmProperties extends Form implements CommandListener +{ + private Command cmdPropOK = new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1); + private Command cmdPropBack = new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 1); + private ChoiceGroup cgAttrib; + private Object parent; + private boolean hidden, readonly; + private String tmp; + + /** + * КонÑтруктор + */ + public frmProperties(Object parent) + { + super(""); + setTitle(Locale.getString(this, Locale.INFORMATION)); + + this.parent = parent; + tmp = main.currentPath; + + if("fav:/".equals(tmp)) + { + tmp = ""; + } + + if(!main.currentFile.equalsIgnoreCase("..")) + { + tmp += main.currentFile; + } + + // Значок файла или папки + /* + if(filesystem.isDir(tmp)) + { + if(filesystem.isHidden(tmp)) + { + append(images.getIcon(images.iHiddenFolder)); + } + else + { + append(images.getIcon(images.iFolder)); + } + } + else + { + append(images.getIcon(filesystem.typeIcon(filesystem.fileType(tmp)))); + } + + append("\n"); + */ + + String s; + boolean isdir = filesystem.isDir(tmp); + + // Ð˜Ð¼Ñ + if(isdir) + { + append(new TextField(Locale.getString(this, Locale.FOLDER_NAME), tmp, tmp.length(), TextField.ANY)); + } + else + { + append(new TextField(Locale.getString(this, Locale.FILE_NAME), tmp, tmp.length(), TextField.ANY)); + } + + // Размер + long size = filesystem.getSize(tmp, true); // options.checkFileAttrib); + + if(size < 0) + { + size = filesystem.getSize(tmp, false); + } + + if(size >= 0) + { + s = filesystem.getSizeString(size, true); + append(new TextField(Locale.getString(this, Locale.SIZE), s, s.length(), TextField.ANY)); + } + + // Сжатый размер + long compsize = filesystem.getCompressedSize(tmp); + + if(compsize >= 0) + { + s = filesystem.getSizeString(compsize, true); + append(new TextField(Locale.getString(this, Locale.COMPRESSED_SIZE), s, s.length(), TextField.ANY)); + } + + // ПоÑл изм. + long time = filesystem.lastModified(tmp); + + if(time > 0) + { + s = AuxClass.timeToString(time, false); + append(new TextField(Locale.getString(this, Locale.LAST_MODIF), s, s.length(), TextField.ANY)); + } + + // Счетчик файлов + if(isdir) // && options.checkFileAttrib) + { + int[] count = filesystem.getFileCount(tmp, options.showHidden); + s = Locale.getString(this, Locale.CONTENTS_PATTERN, new String[] { Integer.toString(count[0]), Integer.toString(count[1]) }); + append(new TextField(Locale.getString(this, Locale.CONTENTS), s, s.length(), TextField.ANY)); + } + + // Attributes + if(!main.currentFile.equalsIgnoreCase("..")) + { + cgAttrib = new ChoiceGroup(Locale.getString(this, Locale.ATTR), ChoiceGroup.MULTIPLE); + + cgAttrib.append(Locale.getString(this, Locale.ATTR_READ_ONLY), null); + readonly = filesystem.isReadOnly(tmp); + cgAttrib.setSelectedIndex(0, readonly); + + if(true) // options.showHidden) + { + cgAttrib.append(Locale.getString(this, Locale.ATTR_HIDDEN), null); + hidden = filesystem.isHidden(tmp); + cgAttrib.setSelectedIndex(1, hidden); + } + + append(cgAttrib); + } + + if(cgAttrib != null) + { + addCommand(cmdPropOK); + } + + addCommand(cmdPropBack); + setCommandListener(this); + } + + public void commandAction(Command command, Displayable displayable) + { + // Команда ОК - изменÑем ÑвойÑтва файла или папки + if(command == cmdPropOK) + { + if((readonly != cgAttrib.isSelected(0)) || (hidden != cgAttrib.isSelected(1))) + { + filesystem.setReadOnly(main.currentPath + main.currentFile, cgAttrib.isSelected(0)); + filesystem.setHidden(main.currentPath + main.currentFile, cgAttrib.isSelected(1)); + + main.FileSelect.updateFileType(main.FileSelect.getSelectedIndex()); + } + + main.dsp.setCurrent(parent); + } + // ÐÐЗÐД - ВЫХОД ИЗ ОКÐРСВОЙСТВ + else if(command == cmdPropBack) + { + main.dsp.setCurrent(parent); + } + } + +// private static void out(String s) +// { +// System.out.println("[frmProperties] " + s); +// } +} diff --git a/src/filemanager/frmRename.java b/src/filemanager/frmRename.java new file mode 100644 index 0000000..6a782f5 --- /dev/null +++ b/src/filemanager/frmRename.java @@ -0,0 +1,170 @@ +package filemanager; + +import com.vmx.Locale; +import javax.microedition.lcdui.*; +import com.vmx.ProgressCallback; + +public class frmRename extends Form implements CommandListener, ProgressCallback +{ + private String oldFileName; + private String newFileName; + private TextField tf; + private StringItem si; + private Object parent; + private boolean isFolder = false; + + private boolean cancelflag; + + public frmRename(Object parent) + { + super(""); + setTitle(Locale.getString(this, Locale.RENAME)); + + this.parent = parent; + + if(Buffer.getSize() == 0) + { + oldFileName = main.currentFile; + + if(oldFileName.endsWith("/")) //еÑли выбранный файл - папка, убираем поÑл/ Ñлеш + { + oldFileName = oldFileName.substring(0, oldFileName.length() - 1); + isFolder = true; + } + + tf = new TextField(Locale.getString(this, Locale.NAME), oldFileName, 256, TextField.ANY); + } + else + { + tf = new TextField(Locale.getString(this, Locale.NAME_TEMPLATE), "[N].[E]", 1024, TextField.ANY); + } + + si = new StringItem(null, null); + + append(tf); + append(si); + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 1)); + + setCommandListener(this); + } + + public void setMax(int max) + { + } + + public void setProgress(int progress) + { + } + + public void rise(int plus) + { + } + + public void progress(int plus) + { + } + + public void setText(String text) + { + si.setText(text); + } + + public int getMax() + { + return 1; + } + + public int getProgress() + { + return 0; + } + + public String getText() + { + return si.getText(); + } + + public void setPercentMode(boolean mode) + { + } + + public void setCancelFlag(boolean flag) + { + cancelflag = flag; + } + + public boolean getCancelFlag() + { + return cancelflag; + } + + public void commandAction(Command command, Displayable displayable) + { + if(command.getCommandType() == Command.BACK) + { + main.dsp.setCurrent(parent); + } + else if(command.getCommandType() == Command.OK) + { + if(Buffer.getSize() == 0) + { + if(isFolder) + { + oldFileName += "/"; + newFileName = tf.getString() + "/"; + } + else + { + newFileName = tf.getString(); + } + + if(newFileName.equals(oldFileName)) // Ð¸Ð¼Ñ Ð½Ðµ изменилоÑÑŒ + { + main.dsp.setCurrent(parent); + } + else + { + setText(Locale.getString(this, Locale.WAIT_PLEASE)); + + if(filesystem.isFileExist(main.currentPath + newFileName)) + { + setText(Locale.getString(this, Locale.NAME_EXIST_SELECT_ANOTHER)); + /* + Alert al = new Alert(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.NAME_EXIST_SELECT_ANOTHER), images.error, AlertType.ERROR); + al.setTimeout(3000); + main.dsp.setCurrent(al, this); + */ + } + else // переименовываем + { + if(filesystem.renameFile(main.currentPath + oldFileName, newFileName, this)) // еÑли переименован + { + // менÑем Ð¸Ð¼Ñ Ð¸, еÑли не папка, значок + + main.FileSelect.updateFileName(newFileName, main.FileSelect.getSelectedIndex()); + + main.dsp.setCurrent(parent); + } + else // не переименован + { + if(filesystem.isReadOnly(main.currentPath + main.currentFile)) // ReadOnly + { + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.FILE_READ_ONLY, main.currentPath + main.currentFile), AlertType.WARNING, 3000, parent); + } + else + { + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.NOT_RENAMED, main.currentPath + main.currentFile), AlertType.ERROR, 3000, parent); + } + } + } + } + } + else + { + Buffer.startOperation(new Renamer(tf.getString())); + } + } + } +} diff --git a/src/filemanager/frmSearch.java b/src/filemanager/frmSearch.java new file mode 100644 index 0000000..1e5d2a7 --- /dev/null +++ b/src/filemanager/frmSearch.java @@ -0,0 +1,67 @@ +package filemanager; + +import com.vmx.Locale; +import javax.microedition.lcdui.*; +import com.one.StringPattern; + +public class frmSearch extends Form implements CommandListener +{ + protected Object parent; + + protected TextField tfText; + protected ChoiceGroup cgSearchIn, cgOptions; + + public frmSearch(Object p) + { + super(""); + setTitle(Locale.getString(this, Locale.MENU_SEARCH)); + + parent = p; + + tfText = new TextField(Locale.getString(this, Locale.FIND_CMD), "", 256, TextField.ANY); + + cgSearchIn = new ChoiceGroup(null, Choice.EXCLUSIVE); + cgSearchIn.append(Locale.getString(this, Locale.SEARCH_CURRENT_FOLDER), null); + cgSearchIn.append(Locale.getString(this, Locale.SEARCH_CURRENT_DISK), null); + cgSearchIn.append(Locale.getString(this, Locale.SEARCH_ALL_DISKS), null); + + cgOptions = new ChoiceGroup(null, Choice.MULTIPLE); + cgOptions.append(Locale.getString(this, Locale.IGNORE_CASE), null); + cgOptions.append(Locale.getString(this, Locale.RECURSIVE_SEARCH), null); + cgOptions.append(Locale.getString(this, Locale.SEARCH_INSIDE_ARCHIVES), null); + + append(tfText); + append(cgSearchIn); + append(cgOptions); + + addCommand(new Command(Locale.getString(this, Locale.FIND_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 2)); + + setCommandListener(this); + } + + public void commandAction(Command c, Displayable dp) + { + main.dsp.setCurrent(parent); + + if(c.getCommandType() == Command.OK) + { + String path; + + if(cgSearchIn.isSelected(0)) + { + path = main.currentPath; + } + else if(cgSearchIn.isSelected(1)) + { + path = main.currentPath.substring(0, main.currentPath.indexOf('/') + 1); + } + else + { + path = ""; + } + + Buffer.startOperation(new SearchThread(new StringPattern(tfText.getString(), cgOptions.isSelected(0)), path, cgOptions.isSelected(1), cgOptions.isSelected(2))); + } + } +} diff --git a/src/filemanager/images.java b/src/filemanager/images.java new file mode 100644 index 0000000..af8d806 --- /dev/null +++ b/src/filemanager/images.java @@ -0,0 +1,1111 @@ +package filemanager; + +import com.one.ErrScreen; +import javax.microedition.lcdui.*; +import javax.microedition.lcdui.game.*; +import javax.microedition.rms.*; +import java.io.*; +import com.one.ImageProcessor; +import com.one.IniFile; +import com.one.IniRecord; +import com.one.ProgressBar; +import com.one.RootLoader; +import com.vmx.AuxClass; +import com.vmx.InputStreamDecoder; +import com.vmx.ProgressCallback; +import com.vmx.gkcCanvas; + +public class images +{ + public static final int STORE_VERSION = 13; + public static final int FP_SHIFT = 16; + + public static final int iFile = 0, + iFolder = 1, + iHiddenFolder = 2, + iDisk = 3, + iFavorites = 4, + iUp = 5, + iClipboard = 6, + iSieFM = 7, + iCopy = 8, + iMove = 9, + iPaste = 10, + iProperties = 11, + iOptions = 12, + iRename = 13, + iHelp = 14, + iDelete = 15, + iExit = 16, + iNext = 17, + iUnpack = 18, + iMark = 19, + iMarkAll = 20, + iDemarkAll = 21, + iNoMute = 22, + iMute = 23, + iSelect = 24, + iMoveIt = 25, + iPack = 26, + iKey = 27, + iMenu = 28, + iSearch = 29, + iMinimize = 30, + iCrypt = 31; + + public static final int iconsCount = 32; + + public static final int[] TEST_COLORS = + { + 0xFFC0C0C0, + 0xFFC0C000, + 0xFF00C0C0, + 0xFF00C000, + 0xFFC000C0, + 0xFFC00000, + 0xFF0000C0, + 0xFF000000 + }; + + public static int cPlayTitle = 0xFFFFFFFF, + cPlayFore1 = 0xFF800000, + cPlayFore2 = 0xFF000080, + cImgBack = 0xFF000000, + cVisArrowCap = 0xFF000080, + cVisArrowLine = 0xFFEFEFFF, + cVisBack1 = 0xFFD0D0E0, + cVisBack2 = 0xFFB0B0C0; + + public static int iconWidth = 16, + iconHeight = 16, + origIconWidth = 16, + origIconHeight = 16, + uiTopHeight = 20, + uiBottomHeight = 28, + uiWidth = 25, + uiTopHSpace = 6, + uiTopVSpace = 0, + uiBottomHOffset = 7, + uiBottomVOffset = 2, + uiBottomVSpace = 0, + btnX = 28, + btnY = 22, + btnWidth = 23, + btnHeight = 23, + playAnimWidth = 101, + playAnimHeight = 36, + playAnimFrames = 4, + waitAnimWidth = 32, + waitAnimHeight = 32, + waitAnimFrames = 4; + + public static Image splashBack, playerUI, minUI, buttons, waitAnim; + public static Image mb_information, mb_question, mb_exclamation, mb_critical; + + protected static Image[] iconsExplode; + + protected static int[] alphaline; + + /** + * Загрузка картинок в ÑтатичеÑкие Ð¿Ð¾Ð»Ñ + */ + public static void loadImages() + { + try + { + InputStreamDecoder isd = InputStreamDecoder.getResourceDecoder("/img/layout.ini"); + IniFile ini = new IniFile(isd, true); + isd.close(); + + cPlayTitle = AuxClass.parseHexInt(ini.getRecord("Colors", "cPlayTitle" ), cPlayTitle ); + cPlayFore1 = AuxClass.parseHexInt(ini.getRecord("Colors", "cPlayFore1" ), cPlayFore1 ); + cPlayFore2 = AuxClass.parseHexInt(ini.getRecord("Colors", "cPlayFore2" ), cPlayFore2 ); + cImgBack = AuxClass.parseHexInt(ini.getRecord("Colors", "cImgBack" ), cImgBack ); + cVisArrowCap = AuxClass.parseHexInt(ini.getRecord("Colors", "cVisArrowCap" ), cVisArrowCap ); + cVisArrowLine = AuxClass.parseHexInt(ini.getRecord("Colors", "cVisArrowLine" ), cVisArrowLine ); + cVisBack1 = AuxClass.parseHexInt(ini.getRecord("Colors", "cVisBack1" ), cVisBack1 ); + cVisBack2 = AuxClass.parseHexInt(ini.getRecord("Colors", "cVisBack2" ), cVisBack2 ); + + origIconWidth = AuxClass.parseInt(ini.getRecord("Positions", "iconWidth" ), origIconWidth ); + origIconHeight = AuxClass.parseInt(ini.getRecord("Positions", "iconHeight" ), origIconHeight ); + uiTopHeight = AuxClass.parseInt(ini.getRecord("Positions", "uiTopHeight" ), uiTopHeight ); + uiBottomHeight = AuxClass.parseInt(ini.getRecord("Positions", "uiBottomHeight" ), uiBottomHeight ); + uiTopHSpace = AuxClass.parseInt(ini.getRecord("Positions", "uiTopHSpace" ), uiTopHSpace ); + uiTopVSpace = AuxClass.parseInt(ini.getRecord("Positions", "uiTopVSpace" ), uiTopVSpace ); + uiBottomHOffset = AuxClass.parseInt(ini.getRecord("Positions", "uiBottomHOffset" ), uiBottomHOffset ); + uiBottomVOffset = AuxClass.parseInt(ini.getRecord("Positions", "uiBottomVOffset" ), uiBottomVOffset ); + uiBottomVSpace = AuxClass.parseInt(ini.getRecord("Positions", "uiBottomVSpace" ), uiBottomVSpace ); + btnX = AuxClass.parseInt(ini.getRecord("Positions", "btnX" ), btnX ); + btnY = AuxClass.parseInt(ini.getRecord("Positions", "btnY" ), btnY ); + btnWidth = AuxClass.parseInt(ini.getRecord("Positions", "btnWidth" ), btnWidth ); + btnHeight = AuxClass.parseInt(ini.getRecord("Positions", "btnHeight" ), btnHeight ); + playAnimWidth = AuxClass.parseInt(ini.getRecord("Positions", "playAnimWidth" ), playAnimWidth ); + playAnimHeight = AuxClass.parseInt(ini.getRecord("Positions", "playAnimHeight" ), playAnimHeight ); + playAnimFrames = AuxClass.parseInt(ini.getRecord("Positions", "playAnimFrames" ), playAnimFrames ); + waitAnimWidth = AuxClass.parseInt(ini.getRecord("Positions", "waitAnimWidth" ), waitAnimWidth ); + waitAnimHeight = AuxClass.parseInt(ini.getRecord("Positions", "waitAnimHeight" ), waitAnimHeight ); + waitAnimFrames = AuxClass.parseInt(ini.getRecord("Positions", "waitAnimFrames" ), waitAnimFrames ); + } + catch(IOException e) + { + System.out.println("External layout not loaded: " + e.toString()); + } + + iconsExplode = new Image[iconsCount]; + + gkcCanvas.getRenderer().setFullScreenMode(true); + int width = gkcCanvas.getDisplayWidth(); + int height = gkcCanvas.getDisplayHeight(); + + alphaline = new int[Math.max(width, height)]; + + ProgressCallback callback = ProgressBar.getProgressCallback(); + + if(!loadScaledImages(width, height)) + { + callback.setProgress(0); + callback.setMax(8); + callback.setText("Preparing UI for " + width + "x" + height + " display, this may take several minutes..."); + ProgressBar.show(); + + try + { + Image img = Image.createImage("/img/player_ui.png"); + callback.progress(1); + + int imgWidth = img.getWidth(); + int imgHeight = img.getHeight(); + + int topFH = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL).getHeight(); + int bottomFH = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL).getHeight(); + + int newHeight = Math.max(imgHeight * (topFH + uiTopVSpace * 2) / uiTopHeight, imgHeight * (bottomFH * 2 + uiBottomVSpace * 3) / uiBottomHeight); + int newWidth = imgWidth * newHeight / imgHeight; + + newWidth += 6 - newWidth % 6; + newHeight = imgHeight * newWidth / imgWidth; + + if(newWidth < imgWidth || newHeight < imgHeight) + { + newWidth = imgWidth; + newHeight = imgHeight; + } + + img = ImageProcessor.scaleImage(img, newWidth, newHeight, true, false); + callback.progress(1); + + uiWidth = newWidth / 6; + uiTopHeight = (uiTopHeight * newHeight + imgHeight / 2) / imgHeight; + uiBottomHeight = newHeight - uiTopHeight; + + uiTopVSpace = (uiTopHeight - topFH) / 2; + uiBottomVSpace = (uiBottomHeight - bottomFH * 2) / 3; + + uiTopHSpace = (uiTopHSpace * newHeight + imgHeight / 2) / imgHeight; + uiBottomHOffset = uiBottomHOffset * newHeight / imgHeight; + uiBottomVOffset = uiBottomVOffset * newHeight / imgHeight; + + playerUI = Image.createImage(width, height); + minUI = Image.createImage(width, uiBottomHeight); + + Graphics pgraphics = playerUI.getGraphics(); + Graphics mgraphics = minUI.getGraphics(); + + pgraphics.setColor(cImgBack); + pgraphics.fillRect(0, 0, width, height); + + mgraphics.setColor(cImgBack); + mgraphics.fillRect(0, 0, width, uiBottomHeight); + callback.progress(1); + + pgraphics.drawImage(ImageProcessor.scaleImage(Image.createImage("/img/player_bg.png"), width, height - uiTopHeight - uiBottomHeight - 1, true, false), 0, uiTopHeight, Graphics.LEFT | Graphics.TOP); + callback.progress(1); + + pgraphics.drawRegion(img, 0, 0, uiWidth, uiTopHeight, Sprite.TRANS_NONE, 0, 0, Graphics.LEFT | Graphics.TOP); + pgraphics.drawRegion(img, 0, uiTopHeight, uiWidth, uiBottomHeight, Sprite.TRANS_NONE, 0, height - uiBottomHeight, Graphics.LEFT | Graphics.TOP); + mgraphics.drawRegion(img, 0, uiTopHeight, uiWidth, uiBottomHeight, Sprite.TRANS_NONE, 0, 0, Graphics.LEFT | Graphics.TOP); + + for(int x = uiWidth; x <= width - uiWidth; x += uiWidth) + { + pgraphics.drawRegion(img, uiWidth * 4, 0, uiWidth, uiTopHeight, Sprite.TRANS_NONE, x, 0, Graphics.LEFT | Graphics.TOP); + pgraphics.drawRegion(img, uiWidth * 4, uiTopHeight, uiWidth, uiBottomHeight, Sprite.TRANS_NONE, x, height - uiBottomHeight, Graphics.LEFT | Graphics.TOP); + mgraphics.drawRegion(img, uiWidth * 4, uiTopHeight, uiWidth, uiBottomHeight, Sprite.TRANS_NONE, x, 0, Graphics.LEFT | Graphics.TOP); + } + + pgraphics.drawRegion(img, uiWidth * 5, 0, uiWidth, uiTopHeight, Sprite.TRANS_NONE, width - uiWidth, 0, Graphics.LEFT | Graphics.TOP); + pgraphics.drawRegion(img, uiWidth * 5, uiTopHeight, uiWidth, uiBottomHeight, Sprite.TRANS_NONE, width - uiWidth, height - uiBottomHeight, Graphics.LEFT | Graphics.TOP); + mgraphics.drawRegion(img, uiWidth * 5, uiTopHeight, uiWidth, uiBottomHeight, Sprite.TRANS_NONE, width - uiWidth, 0, Graphics.LEFT | Graphics.TOP); + + btnX = (btnX * newHeight + imgHeight / 2) / imgHeight; + btnY = (btnY * newHeight + imgHeight / 2) / imgHeight; + btnWidth = (btnWidth * newHeight + imgHeight / 2) / imgHeight; + btnHeight = (btnHeight * newHeight + imgHeight / 2) / imgHeight; + + /* + buttons = new Image[3]; + buttons[0] = Image.createImage(img, btnX, btnY, btnWidth, btnHeight, Sprite.TRANS_NONE); + buttons[1] = Image.createImage(img, btnX + btnWidth, btnY, btnWidth, btnHeight, Sprite.TRANS_NONE); + buttons[2] = Image.createImage(img, btnX + btnWidth * 2, btnY, btnWidth, btnHeight, Sprite.TRANS_NONE); + */ + + buttons = Image.createImage(img, btnX, btnY, btnWidth * 3, btnHeight, Sprite.TRANS_NONE); + + //playAnim = Image.createImage("/img/play.png"); + + playAnimWidth = width * 3 / 4; + playAnimHeight = playAnimWidth * 36 / 101; // playAnim.getHeight() * playAnimWidth / playAnim.getWidth(); + +// if(playAnimWidth < playAnim.getWidth() || playAnimHeight < playAnim.getHeight()) +// { +// playAnimWidth = playAnim.getWidth(); +// playAnimHeight = playAnim.getHeight(); +// } + + //playAnim = ImageProcessor.scaleImage(playAnim, playAnimWidth, playAnimHeight, true); + + playAnimFrames = 1; + playAnimHeight /= playAnimFrames; + + iconHeight = Font.getDefaultFont().getHeight(); + iconWidth = (origIconWidth * iconHeight + origIconHeight / 2) / origIconHeight; + + System.out.println("Rescaling icons from " + origIconWidth + "x" + origIconHeight + " to " + iconWidth + "x" + iconHeight); + + callback.progress(1); + } + catch(Exception e) + { + callback.setProgress(5); + } + + try + { + waitAnim = Image.createImage("/img/wait.png"); + + waitAnimWidth = waitAnim.getWidth() / waitAnimFrames; + waitAnimHeight = waitAnim.getHeight(); + } + catch(Exception e) + { + } + callback.progress(1); + + try + { + splashBack = ImageProcessor.scaleImage(Image.createImage("/img/splash.png"), width, height, true, false); + } + catch(Exception e) + { + } + callback.progress(1); + + try + { + mb_information = Image.createImage("/img/mb_information.png"); + mb_question = Image.createImage("/img/mb_question.png"); + mb_exclamation = Image.createImage("/img/mb_exclamation.png"); + mb_critical = Image.createImage("/img/mb_critical.png"); + } + catch(Exception e) + { + } + callback.progress(1); + + saveScaledImages(width, height, callback); + + ProgressBar.hide(); + } + } + + public static void loadIcons(ProgressCallback callback, boolean noEffects) + { + if(!loadScaledIcons()) + { + try + { + InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/img/icons.ini"); + loadIcons(ini, callback, noEffects); + ini.close(); + } + catch(Exception e) + { + } + } + } + + public static void loadIcons(InputStreamDecoder ini, ProgressCallback callback, boolean noEffects) + { + callback.setProgress(0); + callback.setMax(iconsCount * 2); + + IniRecord record = null; + Image icon; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + try + { + icon = ImageProcessor.getImage("/img/", record.value); + icon = ImageProcessor.scaleImage(icon, -1, iconHeight, !noEffects, true); + + iconsExplode[Integer.parseInt(record.key)] = icon; + callback.progress(1); + } + catch(Exception e) + { + System.out.println("Failed to load icon: " + record.key + " = " + record.value); + } + } + + saveScaledIcons(callback); + } + + public static boolean isTransformLandscape(int transform) + { + return transform == Sprite.TRANS_ROT90 || + transform == Sprite.TRANS_ROT270 || + transform == Sprite.TRANS_MIRROR_ROT90 || + transform == Sprite.TRANS_MIRROR_ROT270; + } + + public static void drawVAlphaLine(Graphics g, int color, int x, int y, int height) + { + for(int i = 0; i < height; i++) + { + alphaline[i] = color; + } + + g.drawRGB(alphaline, 0, 1, x, y, 1, height, true); + } + + public static void drawHAlphaLine(Graphics g, int color, int x, int y, int width) + { + for(int i = 0; i < width; i++) + { + alphaline[i] = color; + } + + g.drawRGB(alphaline, 0, width, x, y, width, 1, true); + } + + public static boolean drawVGradient(Graphics g, int topColor, int bottomColor, int x, int y, int w, int h, boolean dither, boolean alpha) + { + if(isColorOpaque(topColor) && isColorOpaque(bottomColor)) + { + alpha = false; + } + + if(!alpha && (topColor & 0xFFFFFF) == (bottomColor & 0xFFFFFF)) + { + g.setColor(topColor); + g.fillRect(x, y, w, h); + + return false; + } + + int x2 = x + w - 1; + int y2 = y + h; + + if(dither) + { + int ia = ((topColor >> 24) & 0xFF) << FP_SHIFT; + int ir = ((topColor >> 16) & 0xFF) << FP_SHIFT; + int ig = ((topColor >> 8) & 0xFF) << FP_SHIFT; + int ib = (topColor & 0xFF) << FP_SHIFT; + + int sa = ((((bottomColor >> 24) & 0xFF) << FP_SHIFT) - ia) / h; + int sr = ((((bottomColor >> 16) & 0xFF) << FP_SHIFT) - ir) / h; + int sg = ((((bottomColor >> 8) & 0xFF) << FP_SHIFT) - ig) / h; + int sb = (((bottomColor & 0xFF) << FP_SHIFT) - ib) / h; + + int cr = ir; + int cg = ig; + int cb = ib; + + Image image = Image.createImage(1, 1); + Graphics graphics = image.getGraphics(); + int[] pixel = new int[1]; + + int dr, dg, db; + + if(alpha) + { + for(; y < y2; y++) + { + graphics.setColor(getColor(0, cr >> FP_SHIFT, cg >> FP_SHIFT, cb >> FP_SHIFT)); + graphics.drawLine(0, 0, 0, 0); + + image.getRGB(pixel, 0, 1, 0, 0, 1, 1); + + dr = (ir - (((pixel[0] >> 16) & 0xFF) << FP_SHIFT)); + dg = (ig - (((pixel[0] >> 8) & 0xFF) << FP_SHIFT)); + db = (ib - ((pixel[0] & 0xFF) << FP_SHIFT)); + + cr += dr; + cg += dg; + cb += db; + + drawHAlphaLine(g, getColor(ia >> FP_SHIFT, cr >> FP_SHIFT, cg >> FP_SHIFT, cb >> FP_SHIFT), x, y, w); + + cr += sr; + cg += sg; + cb += sb; + + ia += sa; + ir += sr; + ig += sg; + ib += sb; + } + } + else + { + for(; y < y2; y++) + { + graphics.setColor(getColor(0, cr >> FP_SHIFT, cg >> FP_SHIFT, cb >> FP_SHIFT)); + graphics.drawLine(0, 0, 0, 0); + + image.getRGB(pixel, 0, 1, 0, 0, 1, 1); + + dr = (ir - (((pixel[0] >> 16) & 0xFF) << FP_SHIFT)); + dg = (ig - (((pixel[0] >> 8) & 0xFF) << FP_SHIFT)); + db = (ib - ((pixel[0] & 0xFF) << FP_SHIFT)); + + cr += dr; + cg += dg; + cb += db; + + g.setColor(getColor(0, cr >> FP_SHIFT, cg >> FP_SHIFT, cb >> FP_SHIFT)); + g.drawLine(x, y, x2, y); + + cr += sr; + cg += sg; + cb += sb; + + ir += sr; + ig += sg; + ib += sb; + } + } + } + else + { + int sa = (topColor >> 24) & 0xFF; + int sr = (topColor >> 16) & 0xFF; + int sg = (topColor >> 8) & 0xFF; + int sb = topColor & 0xFF; + + int ea = (bottomColor >> 24) & 0xFF; + int er = (bottomColor >> 16) & 0xFF; + int eg = (bottomColor >> 8) & 0xFF; + int eb = bottomColor & 0xFF; + + int ca, cr, cg, cb; + + if(alpha) + { + for(; y < y2; y++) + { + ca = (sa * (y2 - y) + ea * (h - y2 + y)) / h; + cr = (sr * (y2 - y) + er * (h - y2 + y)) / h; + cg = (sg * (y2 - y) + eg * (h - y2 + y)) / h; + cb = (sb * (y2 - y) + eb * (h - y2 + y)) / h; + + drawHAlphaLine(g, getColor(ca, cr, cg, cb), x, y, w); + } + } + else + { + for(; y < y2; y++) + { + cr = (sr * (y2 - y) + er * (h - y2 + y)) / h; + cg = (sg * (y2 - y) + eg * (h - y2 + y)) / h; + cb = (sb * (y2 - y) + eb * (h - y2 + y)) / h; + + g.setColor(cr, cg, cb); + g.drawLine(x, y, x2, y); + } + } + } + + return alpha; + } + + public static boolean drawHGradient(Graphics g, int leftColor, int rightColor, int x, int y, int w, int h, boolean dither, boolean alpha) + { + if(isColorOpaque(leftColor) && isColorOpaque(rightColor)) + { + alpha = false; + } + + if(!alpha && (leftColor & 0xFFFFFF) == (rightColor & 0xFFFFFF)) + { + g.setColor(leftColor); + g.fillRect(x, y, w, h); + + return false; + } + + int x2 = x + w; + int y2 = y + h - 1; + + if(dither) + { + int ia = ((leftColor >> 24) & 0xFF) << FP_SHIFT; + int ir = ((leftColor >> 16) & 0xFF) << FP_SHIFT; + int ig = ((leftColor >> 8) & 0xFF) << FP_SHIFT; + int ib = (leftColor & 0xFF) << FP_SHIFT; + + int sa = ((((rightColor >> 24) & 0xFF) << FP_SHIFT) - ia) / w; + int sr = ((((rightColor >> 16) & 0xFF) << FP_SHIFT) - ir) / w; + int sg = ((((rightColor >> 8) & 0xFF) << FP_SHIFT) - ig) / w; + int sb = (((rightColor & 0xFF) << FP_SHIFT) - ib) / w; + + int cr = ir; + int cg = ig; + int cb = ib; + + Image image = Image.createImage(1, 1); + Graphics graphics = image.getGraphics(); + int[] pixel = new int[1]; + + int dr, dg, db; + + if(alpha) + { + for(; x < x2; x++) + { + graphics.setColor(getColor(0, cr >> FP_SHIFT, cg >> FP_SHIFT, cb >> FP_SHIFT)); + graphics.drawLine(0, 0, 0, 0); + + image.getRGB(pixel, 0, 1, 0, 0, 1, 1); + + dr = (ir - (((pixel[0] >> 16) & 0xFF) << FP_SHIFT)); + dg = (ig - (((pixel[0] >> 8) & 0xFF) << FP_SHIFT)); + db = (ib - ((pixel[0] & 0xFF) << FP_SHIFT)); + + cr += dr; + cg += dg; + cb += db; + + drawVAlphaLine(g, getColor(ia >> FP_SHIFT, cr >> FP_SHIFT, cg >> FP_SHIFT, cb >> FP_SHIFT), x, y, h); + + cr += sr; + cg += sg; + cb += sb; + + ia += sa; + ir += sr; + ig += sg; + ib += sb; + } + } + else + { + for(; x < x2; x++) + { + graphics.setColor(getColor(0, cr >> FP_SHIFT, cg >> FP_SHIFT, cb >> FP_SHIFT)); + graphics.drawLine(0, 0, 0, 0); + + image.getRGB(pixel, 0, 1, 0, 0, 1, 1); + + dr = (ir - (((pixel[0] >> 16) & 0xFF) << FP_SHIFT)); + dg = (ig - (((pixel[0] >> 8) & 0xFF) << FP_SHIFT)); + db = (ib - ((pixel[0] & 0xFF) << FP_SHIFT)); + + cr += dr; + cg += dg; + cb += db; + + g.setColor(getColor(0, cr >> FP_SHIFT, cg >> FP_SHIFT, cb >> FP_SHIFT)); + g.drawLine(x, y, x, y2); + + cr += sr; + cg += sg; + cb += sb; + + ir += sr; + ig += sg; + ib += sb; + } + } + } + else + { + int sa = (leftColor >> 24) & 0xFF; + int sr = (leftColor >> 16) & 0xFF; + int sg = (leftColor >> 8) & 0xFF; + int sb = leftColor & 0xFF; + + int ea = (rightColor >> 24) & 0xFF; + int er = (rightColor >> 16) & 0xFF; + int eg = (rightColor >> 8) & 0xFF; + int eb = rightColor & 0xFF; + + int ca, cr, cg, cb; + + if(alpha) + { + for(; x < x2; x++) + { + ca = (sa * (x2 - x) + ea * (w - x2 + x)) / w; + cr = (sr * (x2 - x) + er * (w - x2 + x)) / w; + cg = (sg * (x2 - x) + eg * (w - x2 + x)) / w; + cb = (sb * (x2 - x) + eb * (w - x2 + x)) / w; + + drawVAlphaLine(g, getColor(ca, cr, cg, cb), x, y, h); + } + } + else + { + for(; x < x2; x++) + { + cr = (sr * (x2 - x) + er * (w - x2 + x)) / w; + cg = (sg * (x2 - x) + eg * (w - x2 + x)) / w; + cb = (sb * (x2 - x) + eb * (w - x2 + x)) / w; + + g.setColor(cr, cg, cb); + g.drawLine(x, y, x, y2); + } + } + } + + return alpha; + } + + public static void fillVLineRect(Graphics g, int x, int y, int w, int h) + { + int ex = x + w - 1; + int ey = y + h - 1; + + while(x <= ex) + { + g.drawLine(x, y, x, ey); + x += 2; + } + } + + public static void fillHLineRect(Graphics g, int x, int y, int w, int h) + { + int ex = x + w - 1; + int ey = y - h + 1; + + while(y >= ey) + { + g.drawLine(x, y, ex, y); + y -= 2; + } + } + + public static void drawVColorTest(Graphics g, int x, int y, int w, int h) + { + int delta = w / TEST_COLORS.length; + + for(int i = 0; i < TEST_COLORS.length; i++) + { + g.setColor(TEST_COLORS[i]); + g.fillRect(x + i * delta, y, delta, h); + } + } + + public static void drawHColorTest(Graphics g, int x, int y, int w, int h) + { + int delta = h / TEST_COLORS.length; + + for(int i = 0; i < TEST_COLORS.length; i++) + { + g.setColor(TEST_COLORS[i]); + g.fillRect(x, y + i * delta, w, delta); + } + } + + public static boolean isColorOpaque(int color) + { + return (color & 0xFF000000) == 0xFF000000; + } + + public static int getColor(int ca, int cr, int cg, int cb) + { + if(ca < 0) + { + ca = 0; + } + else if(ca > 255) + { + ca = 255; + } + + if(cr < 0) + { + cr = 0; + } + else if(cr > 255) + { + cr = 255; + } + + if(cg < 0) + { + cg = 0; + } + else if(cg > 255) + { + cg = 255; + } + + if(cb < 0) + { + cb = 0; + } + else if(cb > 255) + { + cb = 255; + } + + return (ca << 24) | (cr << 16) | (cg << 8) | cb; + } + + public static int blendColors(int color1, int color2, int factor, int divisor) + { + if(factor == 0) + { + return color1; + } + else if(factor == divisor) + { + return color2; + } + else + { + int r1 = color1 & 0xFF0000; + int g1 = color1 & 0xFF00; + int b1 = color1 & 0xFF; + + int r2 = (((color2 & 0xFF0000) - r1) * factor / divisor & 0xFF0000) + r1; + int g2 = (((color2 & 0xFF00) - g1) * factor / divisor & 0xFF00) + g1; + int b2 = ((color2 & 0xFF) - b1) * factor / divisor + b1; + + return r2 | g2 | b2; + } + } + + public static Image createColorSample(int color, int width, int height) + { + Image image = Image.createImage(width, height); + Graphics g = image.getGraphics(); + + try + { + int rgb[] = new int[width * height]; + + for(int i = 0; i < rgb.length; i++) + { + rgb[i] = color; + } + + g.setColor(0xFF000000); + g.fillRect(0, 0, width, height); + + g.setColor(0xFFFFFFFF); + g.fillRect((width + 1) >> 1, 0, width >> 1, height >> 1); + g.fillRect(0, (height + 1) >> 1, width >> 1, height >> 1); + + g.drawRGB(rgb, 0, width, 0, 0, width, height, true); + } + catch(OutOfMemoryError oome) + { + g.setColor(color); + g.fillRect(0, 0, width, height); + } + + return image; + } + + /** + * ДоÑтать подходÑщий значек Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾Ñ‚Ð¸Ð¿Ð° ÑообщениÑ. + * + * @param type AlertType + * @return значек, ÑоответÑтвующий данному AlertType + */ + public static Image getAlertIcon(AlertType type) + { + if(type == AlertType.INFO) + { + return mb_information; + } + else if(type == AlertType.CONFIRMATION) + { + return mb_question; + } + else if(type == AlertType.ALARM || + type == AlertType.WARNING) + { + return mb_exclamation; + } + else if(type == AlertType.ERROR) + { + return mb_critical; + } + else + { + return null; + } + } + + /** + * Получить иконку Ñ Ð½Ð¾Ð¼ÐµÑ€Ð¾Ð¼ index - вырезать из icons еÑли ещё не вырезана + */ + public static Image getIcon(int index) + { + if(index < 0 || index >= iconsExplode.length) + { + return null; + } + + return iconsExplode[index]; + } + + /** + * ÐариÑовать иконку Ñ Ð½Ð¾Ð¼ÐµÑ€Ð¾Ð¼ index на объекте Graphics g + * в положении x,y + */ + public static void drawIcon(Graphics g, int index, int x, int y) + { + Image icon = getIcon(index); + + if(icon != null) + { + g.drawImage(icon, x, y, Graphics.LEFT | Graphics.TOP); + } + } + + protected static boolean loadScaledImages(int width, int height) + { + try + { + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(4), true); + + if(rs.getNumRecords() == 0) + { + rs.closeRecordStore(); + return false; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(rs.getRecord(1))); + + if(dis.readInt() != STORE_VERSION || + dis.readInt() != width || + dis.readInt() != height) + { + dis.close(); + rs.closeRecordStore(); + + RecordStore.deleteRecordStore(AuxClass.getStoreName(4)); + + return false; + } + + iconWidth = dis.readInt(); + iconHeight = dis.readInt(); + origIconWidth = dis.readInt(); + origIconHeight = dis.readInt(); + uiTopHeight = dis.readInt(); + uiBottomHeight = dis.readInt(); + uiWidth = dis.readInt(); + uiTopHSpace = dis.readInt(); + uiTopVSpace = dis.readInt(); + uiBottomHOffset = dis.readInt(); + uiBottomVOffset = dis.readInt(); + uiBottomVSpace = dis.readInt(); + btnX = dis.readInt(); + btnY = dis.readInt(); + btnWidth = dis.readInt(); + btnHeight = dis.readInt(); + playAnimWidth = dis.readInt(); + playAnimHeight = dis.readInt(); + playAnimFrames = dis.readInt(); + waitAnimWidth = dis.readInt(); + waitAnimHeight = dis.readInt(); + waitAnimFrames = dis.readInt(); + + playerUI = ImageProcessor.readImage(dis); + minUI = ImageProcessor.readImage(dis); + buttons = ImageProcessor.readImage(dis); + waitAnim = ImageProcessor.readImage(dis); + //playAnim = readImage(dis); + splashBack = ImageProcessor.readImage(dis); + + mb_information = ImageProcessor.readImage(dis); + mb_question = ImageProcessor.readImage(dis); + mb_exclamation = ImageProcessor.readImage(dis); + mb_critical = ImageProcessor.readImage(dis); + + dis.close(); + + rs.closeRecordStore(); + + return true; + } + catch(Throwable e) + { + ErrScreen.showErrMsg(106, e); + return false; + } + } + + protected static void saveScaledImages(int width, int height, ProgressCallback callback) + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(STORE_VERSION); + + dos.writeInt(width); + dos.writeInt(height); + + dos.writeInt(iconWidth); + dos.writeInt(iconHeight); + dos.writeInt(origIconWidth); + dos.writeInt(origIconHeight); + dos.writeInt(uiTopHeight); + dos.writeInt(uiBottomHeight); + dos.writeInt(uiWidth); + dos.writeInt(uiTopHSpace); + dos.writeInt(uiTopVSpace); + dos.writeInt(uiBottomHOffset); + dos.writeInt(uiBottomVOffset); + dos.writeInt(uiBottomVSpace); + dos.writeInt(btnX); + dos.writeInt(btnY); + dos.writeInt(btnWidth); + dos.writeInt(btnHeight); + dos.writeInt(playAnimWidth); + dos.writeInt(playAnimHeight); + dos.writeInt(playAnimFrames); + dos.writeInt(waitAnimWidth); + dos.writeInt(waitAnimHeight); + dos.writeInt(waitAnimFrames); + + String prefix = callback.getText() + "\n\nWriting image "; + String suffuix = " / 9..."; + int counter = 1; + + callback.setText(prefix + Integer.toString(counter++) + suffuix); + ImageProcessor.writeImage(dos, playerUI, true, callback); + + callback.setText(prefix + Integer.toString(counter++) + suffuix); + ImageProcessor.writeImage(dos, minUI, true, callback); + + callback.setText(prefix + Integer.toString(counter++) + suffuix); + ImageProcessor.writeImage(dos, buttons, true, callback); + + callback.setText(prefix + Integer.toString(counter++) + suffuix); + ImageProcessor.writeImage(dos, waitAnim, true, callback); + + callback.setText(prefix + Integer.toString(counter++) + suffuix); + ImageProcessor.writeImage(dos, splashBack, true, callback); + + callback.setText(prefix + Integer.toString(counter++) + suffuix); + ImageProcessor.writeImage(dos, mb_information, true, callback); + + callback.setText(prefix + Integer.toString(counter++) + suffuix); + ImageProcessor.writeImage(dos, mb_question, true, callback); + + callback.setText(prefix + Integer.toString(counter++) + suffuix); + ImageProcessor.writeImage(dos, mb_exclamation, true, callback); + + callback.setText(prefix + Integer.toString(counter++) + suffuix); + ImageProcessor.writeImage(dos, mb_critical, true, callback); + + byte[] data = baos.toByteArray(); + dos.close(); + + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(4), true); + + if(rs.getNumRecords() == 0) + { + rs.addRecord(data, 0, data.length); + } + else + { + rs.setRecord(1, data, 0, data.length); + } + + rs.closeRecordStore(); + } + catch(Throwable e) + { + ErrScreen.showErrMsg(107, e); + } + } + + protected static boolean loadScaledIcons() + { + try + { + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(8), true); + + if(rs.getNumRecords() == 0) + { + rs.closeRecordStore(); + return false; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(rs.getRecord(1))); + + for(int i = 0; i < iconsCount; i++) + { + iconsExplode[i] = ImageProcessor.readImage(dis); + } + + dis.close(); + + rs.closeRecordStore(); + + return true; + } + catch(Throwable t) + { + return false; + } + } + + protected static void saveScaledIcons(ProgressCallback callback) + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + for(int i = 0; i < iconsCount; i++) + { + ImageProcessor.writeImage(dos, iconsExplode[i], true, null); + + if(callback != null) + { + callback.progress(1); + } + } + + byte[] data = baos.toByteArray(); + dos.close(); + + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(8), true); + + if(rs.getNumRecords() == 0) + { + rs.addRecord(data, 0, data.length); + } + else + { + rs.setRecord(1, data, 0, data.length); + } + + rs.closeRecordStore(); + } + catch(Throwable t) + { + } + } +} diff --git a/src/filemanager/keyConfig.java b/src/filemanager/keyConfig.java new file mode 100644 index 0000000..e0e7db7 --- /dev/null +++ b/src/filemanager/keyConfig.java @@ -0,0 +1,342 @@ +package filemanager; + +import com.vmx.Locale; +import com.vmx.gkcCanvas; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +public class keyConfig +{ + public static final int ID_USER = 256; + + public static final String HOT_KEY_SUFFIX = "!"; + public static final String HELD_KEY_SUFFIX = "+"; + + public static class KeyInfo + { + private int id; + private int code; + private String name; + private String abbr; + + public KeyInfo(int id, int code, String name, String abbr) + { + this.id = id; + this.code = code; + this.name = name; + this.abbr = abbr; + } + + public KeyInfo(DataInputStream dis) throws IOException + { + id = dis.readInt(); + code = dis.readInt(); + name = dis.readUTF(); + abbr = dis.readUTF(); + } + + public void write(DataOutputStream dos) throws IOException + { + dos.writeInt(id); + dos.writeInt(code); + dos.writeUTF(name); + dos.writeUTF(abbr); + } + + public void setCode(int code) + { + this.code = code; + } + + public void setName(String name) + { + this.name = name; + } + + public void setAbbreviation(String abbr) + { + this.abbr = abbr; + } + + public int getCode() + { + return code; + } + + public String getName() + { + return name; + } + + public String getAbbreviation() + { + return abbr; + } + + public int hashCode() + { + return id; + } + + public boolean equals(Object obj) + { + if(obj == null) + { + return false; + } + + if(getClass() != obj.getClass()) + { + return false; + } + + final KeyInfo other = (KeyInfo)obj; + + if(this.id != other.id) + { + return false; + } + + return true; + } + } + + protected static Hashtable keys = new Hashtable(); + protected static Hashtable actions = new Hashtable(); + + public static int getNextID(boolean system) + { + Enumeration e = keys.elements(); + + int maxid = -1; + int id; + + if(system) + { + while(e.hasMoreElements()) + { + id = ((KeyInfo)e.nextElement()).hashCode(); + + if(id < ID_USER && id > maxid) + { + maxid = id; + } + } + + return maxid + 1; + } + else + { + while(e.hasMoreElements()) + { + id = ((KeyInfo)e.nextElement()).hashCode(); + + if(id >= ID_USER && id > maxid) + { + maxid = id; + } + } + + if(maxid >= 0) + { + return maxid + 1; + } + else + { + return ID_USER; + } + } + } + + public static KeyInfo addKey(int keyCode, String name, String abbreviation, int action, boolean system) + { + KeyInfo key = new KeyInfo(getNextID(system), keyCode, name, abbreviation); + + keys.put(new Integer(keyCode), key); + actions.put(key, new Integer(action)); + + return key; + } + + public static void deleteKey(KeyInfo key) + { + keys.remove(new Integer(key.getCode())); + actions.remove(key); + } + + public static void setAction(KeyInfo key, int action) + { + actions.put(key, new Integer(action)); + } + + public static int getAction(int keyCode) + { + KeyInfo key = (KeyInfo)keys.get(new Integer(keyCode)); + + if(key == null) + { + return -1; + } + + return getAction(key); + } + + public static int getAction(KeyInfo key) + { + Integer action = (Integer)actions.get(key); + + if(action != null) + { + return action.intValue(); + } + + return -1; + } + + public static Enumeration listKeys() + { + Vector vector = new Vector(actions.size()); + + Enumeration e = actions.keys(); + KeyInfo key; + boolean added; + + while(e.hasMoreElements()) + { + key = (KeyInfo)e.nextElement(); + added = false; + + for(int i = 0; i < vector.size(); i++) + { + if(key.hashCode() < ((KeyInfo)vector.elementAt(i)).hashCode()) + { + vector.insertElementAt(key, i); + added = true; + break; + } + } + + if(!added) + { + vector.addElement(key); + } + } + + return vector.elements(); + } + + public static void writeConfig(DataOutputStream dos) throws IOException + { + dos.writeInt(actions.size()); + + Enumeration e = actions.keys(); + KeyInfo key; + + while(e.hasMoreElements()) + { + key = (KeyInfo)e.nextElement(); + + key.write(dos); + dos.writeInt(((Integer)actions.get(key)).intValue()); + } + } + + public static void readConfig(DataInputStream dis) throws IOException + { + int count = dis.readInt(); + + KeyInfo key; + + for(int i = 0; i < count; i++) + { + key = new KeyInfo(dis); + + keys.put(new Integer(key.getCode()), key); + actions.put(key, new Integer(dis.readInt())); + } + } + + public static void addDefaultKeys() + { + actions.clear(); + keys.clear(); + + addKey(gkcCanvas.KEY_LSK, keyName(Locale.KEY_LSK), "LS", Locale.OPTIONS_CMD, true); + addKey(gkcCanvas.KEY_RSK, keyName(Locale.KEY_RSK), "RS", Locale.BACK_CMD, true); + addKey(gkcCanvas.KEY_DIAL, keyName(Locale.KEY_DIAL), "S", Locale.MARK_CMD, true); + addKey(gkcCanvas.KEY_CANCEL, keyName(Locale.KEY_CANCEL), "E", Locale.BACK_CMD, true); + addKey(gkcCanvas.KEY_UP, keyName(Locale.KEY_UP), "U", Locale.PREV_LINE_CMD, true); + addKey(gkcCanvas.KEY_DOWN, keyName(Locale.KEY_DOWN), "D", Locale.NEXT_LINE_CMD, true); + addKey(gkcCanvas.KEY_LEFT, keyName(Locale.KEY_LEFT), "L", Locale.PREV_SCREEN_CMD, true); + addKey(gkcCanvas.KEY_RIGHT, keyName(Locale.KEY_RIGHT), "R", Locale.NEXT_SCREEN_CMD, true); + addKey(gkcCanvas.KEY_FIRE, keyName(Locale.KEY_JOY), "F", Locale.SELECT_CMD, true); + + addNumKey(gkcCanvas.KEY_STAR, Locale.QUICK_SWITCH); + addNumKey(gkcCanvas.KEY_POUND, Locale.HOT_KEYS); + addNumKey(gkcCanvas.KEY_NUM0, Locale.CLOCK_MODE); + addNumKey(gkcCanvas.KEY_NUM1, Locale.PREV_PANEL); + addNumKey(gkcCanvas.KEY_NUM2, Locale.NEXT_PANEL); + addNumKey(gkcCanvas.KEY_NUM3, Locale.MEMORY_MONITOR); + addNumKey(gkcCanvas.KEY_NUM4, Locale.PREV_FREE); + addNumKey(gkcCanvas.KEY_NUM5, Locale.NEXT_FREE); + addNumKey(gkcCanvas.KEY_NUM6, Locale.CONTAINERS); + addNumKey(gkcCanvas.KEY_NUM7, Locale.MARK_ALL_CMD); + addNumKey(gkcCanvas.KEY_NUM8, Locale.DEMARK_ALL_CMD); + addNumKey(gkcCanvas.KEY_NUM9, Locale.PANELS); + + addNumKey(gkcCanvas.KEY_STAR | gkcCanvas.KEY_HOT, Locale.MINIMIZE_CMD); + addNumKey(gkcCanvas.KEY_POUND | gkcCanvas.KEY_HOT, Locale.FULLSCREEN_CMD); + addNumKey(gkcCanvas.KEY_NUM0 | gkcCanvas.KEY_HOT, Locale.FAVOURITE); + addNumKey(gkcCanvas.KEY_NUM1 | gkcCanvas.KEY_HOT, Locale.INSERT_CMD); + addNumKey(gkcCanvas.KEY_NUM2 | gkcCanvas.KEY_HOT, Locale.COPY_CMD); + addNumKey(gkcCanvas.KEY_NUM3 | gkcCanvas.KEY_HOT, Locale.MOVE_CMD); + addNumKey(gkcCanvas.KEY_NUM4 | gkcCanvas.KEY_HOT, Locale.DELETE_CMD); + addNumKey(gkcCanvas.KEY_NUM5 | gkcCanvas.KEY_HOT, Locale.RENAME_CMD); + addNumKey(gkcCanvas.KEY_NUM6 | gkcCanvas.KEY_HOT, Locale.MENU_SEARCH); + addNumKey(gkcCanvas.KEY_NUM7 | gkcCanvas.KEY_HOT, Locale.PROPERTY_CMD); + addNumKey(gkcCanvas.KEY_NUM8 | gkcCanvas.KEY_HOT, Locale.DISK_INFO_CMD); + addNumKey(gkcCanvas.KEY_NUM9 | gkcCanvas.KEY_HOT, Locale.MODULES_CMD); + + addNumKey(gkcCanvas.KEY_STAR | gkcCanvas.KEY_HELD, Locale.KEYBOARD_CONFIG_CMD); + addNumKey(gkcCanvas.KEY_POUND | gkcCanvas.KEY_HELD, Locale.COLOR_SCHEME); + addNumKey(gkcCanvas.KEY_NUM0 | gkcCanvas.KEY_HELD, Locale.TO_FAVOUR_CMD); + addNumKey(gkcCanvas.KEY_NUM1 | gkcCanvas.KEY_HELD, Locale.SORT_BY_NAME); + addNumKey(gkcCanvas.KEY_NUM2 | gkcCanvas.KEY_HELD, Locale.SORT_BY_TYPE); + addNumKey(gkcCanvas.KEY_NUM3 | gkcCanvas.KEY_HELD, Locale.SORT_BY_DATE); + addNumKey(gkcCanvas.KEY_NUM4 | gkcCanvas.KEY_HELD, Locale.SORT_BY_SIZE); + addNumKey(gkcCanvas.KEY_NUM5 | gkcCanvas.KEY_HELD, Locale.SORT_REVERSE_ORDER); + addNumKey(gkcCanvas.KEY_NUM6 | gkcCanvas.KEY_HELD, Locale.IGNORE_CASE); + addNumKey(gkcCanvas.KEY_NUM7 | gkcCanvas.KEY_HELD, Locale.NEW_FILE_CMD); + addNumKey(gkcCanvas.KEY_NUM8 | gkcCanvas.KEY_HELD, Locale.NEW_FOLDER_CMD); + addNumKey(gkcCanvas.KEY_NUM9 | gkcCanvas.KEY_HELD, Locale.CREATE_ARCHIVE); + } + + protected static void addNumKey(int code, int action) + { + String name; + + if((code & gkcCanvas.KEY_HOT) != 0) + { + name = String.valueOf((char)code) + HOT_KEY_SUFFIX; + } + else if((code & gkcCanvas.KEY_HELD) != 0) + { + name = String.valueOf((char)code) + HELD_KEY_SUFFIX; + } + else + { + name = String.valueOf((char)code); + } + + addKey(code, name, name, action, true); + } + + public static String keyName(int name) + { + return "#" + Integer.toString(name); + } +} diff --git a/src/filemanager/lstColorScheme.java b/src/filemanager/lstColorScheme.java new file mode 100644 index 0000000..4f0f7b8 --- /dev/null +++ b/src/filemanager/lstColorScheme.java @@ -0,0 +1,148 @@ +package filemanager; + +import com.one.IniFile; +import com.one.PaintableObject; +import com.one.Renderer; +import com.vmx.Locale; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.List; + +public class lstColorScheme extends List implements CommandListener +{ + public Object parent; + + protected Palette palette; + protected ColorSelector selector; + + protected int index; + protected IniFile clocnames; + + public lstColorScheme() + { + super(null, IMPLICIT); + setTitle(Locale.getString(this, Locale.COLOR_SCHEME)); + + palette = new Palette(); + selector = new ColorSelector(); + + palette.setCommandListener(this); + selector.setCommandListener(this); + + selector.setInteractive(!options.noEffects); + + try + { + clocnames = new IniFile("/lang/" + Locale.lang + "/colors.ini", true); + } + catch(Exception e) + { + e.printStackTrace(); + } + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + setCommandListener(this); + } + + public void updateList() + { + if(size() > 0) + { + index = getSelectedIndex(); + } + + deleteAll(); + + if(clocnames != null) + { + String clocname; + + for(int i = 0; i < ColorScheme.colors.length; i++) + { + clocname = clocnames.getRecord(null, ColorScheme.cnames[i]); + append(clocname != null ? clocname : ColorScheme.cnames[i], images.createColorSample(ColorScheme.colors[i], images.iconWidth, images.iconHeight)); + } + } + else + { + for(int i = 0; i < ColorScheme.colors.length; i++) + { + append(ColorScheme.cnames[i], images.createColorSample(ColorScheme.colors[i], images.iconWidth, images.iconHeight)); + } + } + + setSelectedIndex(index, true); + } + + public void commandAction(Command c, Displayable dp) + { + if(dp == this) + { + if(c == SELECT_COMMAND) + { + index = getSelectedIndex(); + + if(palette.setColor(ColorScheme.colors[index])) + { + main.dsp.setCurrent(palette); + } + else + { + selector.setColor(ColorScheme.colors[index]); + main.dsp.setCurrent(selector); + } + } + else + { + //main.FileSelect.updateGradients(); + main.dsp.setCurrent(parent); + } + } + else if(dp instanceof Renderer) + { + PaintableObject po = ((Renderer)dp).getCurrent(); + + if(po == palette) + { + switch(c.getCommandType()) + { + case Command.OK: + ColorScheme.colors[getSelectedIndex()] = palette.getColor(); + updateList(); + main.dsp.setCurrent(this); + break; + + case Command.ITEM: + selector.setColor(palette.getColor()); + main.dsp.setCurrent(selector); + break; + + case Command.CANCEL: + main.dsp.setCurrent(this); + break; + } + } + else if(po == selector) + { + switch(c.getCommandType()) + { + case Command.OK: + ColorScheme.colors[getSelectedIndex()] = selector.getColor(); + updateList(); + main.dsp.setCurrent(this); + break; + + case Command.ITEM: + palette.setColor(selector.getColor()); + main.dsp.setCurrent(palette); + break; + + case Command.CANCEL: + main.dsp.setCurrent(this); + break; + } + } + } + } +} diff --git a/src/filemanager/lstContainers.java b/src/filemanager/lstContainers.java new file mode 100644 index 0000000..90abce5 --- /dev/null +++ b/src/filemanager/lstContainers.java @@ -0,0 +1,167 @@ +package filemanager; + +import com.one.ErrScreen; +import com.one.file.TransparentConnector; +import com.vmx.Locale; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.List; + +public class lstContainers extends ListMenu implements CommandListener, ListStateListener +{ + protected Object parent; + protected Vector containers; + protected Vector usecounts; + protected Vector depcounts; + + protected Command cmdClose = new Command(Locale.getString(this, Locale.CLOSE_CMD), Command.OK, 1); + protected Command cmdCloseAll = new Command(Locale.getString(this, Locale.CLOSE_ALL_CMD), Command.OK, 2); + protected Command cmdBack = new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 3); + + public lstContainers(Object parent) + { + //super(null, MULTIPLE); + setTitle(Locale.getString(this, Locale.CONTAINERS)); + + this.parent = parent; + + containers = new Vector(); + usecounts = new Vector(); + depcounts = new Vector(); + + addCommand(cmdClose); + //addCommand(cmdCloseAll); + addCommand(cmdBack); + setCommandListener(this); + setStateListener(this); + + updateList(); + } + + public void updateList() + { + containers.removeAllElements(); + usecounts.removeAllElements(); + depcounts.removeAllElements(); + + Enumeration contnames = TransparentConnector.listContainers(); + String contname; + Integer usecount; + Integer depcount; + boolean added; + + while(contnames.hasMoreElements()) + { + contname = (String)contnames.nextElement(); + usecount = new Integer(TransparentConnector.getUseCount(contname)); + depcount = new Integer(TransparentConnector.getDependentCount(contname)); + + added = false; + + for(int i = 0; i < usecounts.size(); i++) + { + if(usecount.intValue() >= ((Integer)usecounts.elementAt(i)).intValue()) + { + containers.insertElementAt(contname, i); + usecounts.insertElementAt(usecount, i); + depcounts.insertElementAt(depcount, i); + + added = true; + + break; + } + } + + if(!added) + { + containers.addElement(contname); + usecounts.addElement(usecount); + depcounts.addElement(depcount); + } + } + + deleteAll(); + + for(int i = 0; i < containers.size(); i++) + { + contname = (String)containers.elementAt(i); + + contname = contname.substring(0, contname.length() - 1); + //contname = contname.substring(contname.lastIndexOf('/') + 1); + + append(contname); // + " (" + ((Integer)usecounts.elementAt(i)).toString() + ")"); //, null); + } + } + + public void commandAction(Command c, Displayable dp) + { + if(c == cmdClose || c == List.SELECT_COMMAND) + { + if(size() > 0) + { + //main.dsp.setCurrent(parent); + //main.dsp.setRenderMode(); + + try + { + TransparentConnector.closeContainer((String)containers.elementAt(getSelectedIndex())); + } + catch(IOException e) + { + ErrScreen.showErrMsg(136, e); + } + + updateList(); + //main.dsp.setCurrent(this); + } + } + else if(c == cmdCloseAll) + { + if(size() > 0) + { + //main.dsp.setCurrent(parent); + //main.dsp.setRenderMode(); + + try + { + TransparentConnector.closeContainers(); + } + catch(IOException e) + { + ErrScreen.showErrMsg(136, e); + } + + updateList(); + //main.dsp.setCurrent(this); + } + } + else if(c == cmdBack) + { + main.dsp.setCurrent(parent); + } + } + + public void listStateChanged(ListMenu list, int action) + { + if(list.size() > 0) + { + int index = list.getSelectedIndex(); + + String[] tokens = new String[] + { + ((Integer)usecounts.elementAt(index)).toString(), + ((Integer)depcounts.elementAt(index)).toString(), + }; + + list.setSubTitle(Locale.getString(this, Locale.CONTAINER_INFO, tokens), false); + } + else + { + list.setSubTitle("", false); + } + } +} diff --git a/src/filemanager/lstKeyConfig.java b/src/filemanager/lstKeyConfig.java new file mode 100644 index 0000000..1c024eb --- /dev/null +++ b/src/filemanager/lstKeyConfig.java @@ -0,0 +1,411 @@ +package filemanager; + +import com.one.PaintableObject; +import com.one.Renderer; +import com.one.TextProcessor; +import com.vmx.Locale; +import com.vmx.gkcCanvas; +import filemanager.keyConfig.KeyInfo; +import java.util.Enumeration; +import java.util.Vector; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Font; +import javax.microedition.lcdui.Form; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.TextField; + +public class lstKeyConfig extends ListMenu implements CommandListener, MenuListener, ListStateListener +{ + public static final int MODE_ACTIONS = 0; + public static final int MODE_KEYS = 1; + + protected class KeyInputCanvas extends PaintableObject + { + protected int width, height; + protected Font font; + + protected String msg; + protected int msgx, msgy; + + public KeyInputCanvas() + { + width = getWidth(); + height = getHeight(); + font = Font.getDefaultFont(); + + msg = Locale.getString(this, Locale.PRESS_A_KEY); + msgx = (width - font.stringWidth(msg)) / 2; + msgy = (height - font.getHeight()) / 2; + } + + public void paint(Graphics g) + { + g.setColor(ColorScheme.colors[ColorScheme.back1]); + g.fillRect(0, 0, width, height); + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.drawString(msg, msgx, msgy, Graphics.LEFT | Graphics.TOP); + } + + public void keyReleased(int keyCode) + { + acceptKeyCode(keyCode); + } + } + + protected Object parent; + protected MenuListener oldMML; + protected Vector keys; + protected int mode; + + protected Form form; + protected TextField tfName; + protected TextField tfAbbr; + protected TextField tfKeyCode; + protected boolean addnew; + + protected KeyInputCanvas canvas; + + protected Command cmdSelect = new Command(Locale.getString(this, Locale.SELECT_CMD), Command.OK, 1); + protected Command cmdAdd = new Command(Locale.getString(this, Locale.ADD_CMD), Command.OK, 2); + protected Command cmdEdit = new Command(Locale.getString(this, Locale.EDIT_CMD), Command.OK, 3); + protected Command cmdDelete = new Command(Locale.getString(this, Locale.DELETE_CMD), Command.OK, 4); + protected Command cmdBack = new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 5); + + protected Command cmdOK = new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1); + protected Command cmdEnter = new Command(Locale.getString(this, Locale.ENTER_CMD), Command.ITEM, 2); + + public lstKeyConfig() + { + setTitle(Locale.getString(this, Locale.KEYBOARD_CONFIG_CMD)); + + keys = new Vector(); + + setCommandListener(this); + setStateListener(this); + + form = new Form(Locale.getString(this, Locale.KEY_EDITOR)); + + tfName = new TextField(Locale.getString(this, Locale.NAME), "", 256, TextField.ANY); + tfAbbr = new TextField(Locale.getString(this, Locale.ABBREVIATION), "", 256, TextField.ANY); + tfKeyCode = new TextField(Locale.getString(this, Locale.KEY_CODE), "", 20, TextField.NUMERIC); + + form.append(tfName); + form.append(tfAbbr); + form.append(tfKeyCode); + + form.addCommand(cmdOK); + form.addCommand(cmdEnter); + form.addCommand(cmdBack); + form.setCommandListener(this); + + canvas = new KeyInputCanvas(); + } + + public void show() + { + mode = MODE_ACTIONS; + updateList(size() > 0 ? (KeyInfo)keys.elementAt(getSelectedIndex()) : null); + + oldMML = main.menu.listen; + parent = main.menu.parent; + main.dsp.setCurrent(this); + } + + public void updateList(KeyInfo selectAfter) + { + keys.removeAllElements(); + deleteAll(); + + Enumeration e = keyConfig.listKeys(); + KeyInfo key; + + if(mode == MODE_ACTIONS) + { + setSubTitle(Locale.getString(this, Locale.KEY_ASSIGNMENT), false); + + while(e.hasMoreElements()) + { + key = (KeyInfo)e.nextElement(); + + keys.addElement(key); + append(formatKeyAction(key)); + + if(key.equals(selectAfter)) + { + setSelectedIndex(size() - 1); + } + } + + removeAllCommands(); + + addCommand(cmdEdit); + addCommand(cmdBack); + + if(size() > 0) + { + addCommand(cmdSelect); + } + } + else if(mode == MODE_KEYS) + { + setSubTitle(Locale.getString(this, Locale.USER_KEYS), false); + + while(e.hasMoreElements()) + { + key = (KeyInfo)e.nextElement(); + + if(true) // key.hashCode() >= keyConfig.ID_USER) + { + keys.addElement(key); + append(formatKeyAbbreviation(key)); + + if(key.equals(selectAfter)) + { + setSelectedIndex(size() - 1); + } + } + } + + removeAllCommands(); + + addCommand(cmdAdd); + addCommand(cmdBack); + + if(size() > 0) + { + addCommand(cmdEdit); + addCommand(cmdDelete); + } + } + } + + protected String getKeyName(KeyInfo key) + { + String name = key.getName(); + + if(name.endsWith(keyConfig.HOT_KEY_SUFFIX)) + { + return Locale.getString(this, Locale.HOT_KEY_NAME, TextProcessor.getString(this, name.substring(0, name.length() - 1).trim())); + } + else if(name.endsWith(keyConfig.HELD_KEY_SUFFIX)) + { + return Locale.getString(this, Locale.HELD_KEY_NAME, TextProcessor.getString(this, name.substring(0, name.length() - 1).trim())); + } + else + { + return TextProcessor.getString(this, name); + } + } + + protected String formatKeyAction(KeyInfo key) + { + return getKeyName(key) + ": " + Locale.getString(this, keyConfig.getAction(key)); + } + + protected String formatKeyAbbreviation(KeyInfo key) + { + String name = getKeyName(key); + + if(key.getAbbreviation().equals(name)) + { + return getKeyName(key); + } + else + { + return getKeyName(key) + " (" + key.getAbbreviation() + ")"; + } + } + + protected void acceptKeyCode(int keyCode) + { + tfKeyCode.setString(Integer.toString(keyCode)); + + if(addnew) + { + tfName.setString(canvas.getKeyName(keyCode)); + tfAbbr.setString(canvas.getKeyName(keyCode)); + } + + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable dp) + { + if(dp instanceof Renderer) + { + PaintableObject po = ((Renderer)dp).getCurrent(); + + if(po == this) + { + if(mode == MODE_ACTIONS) + { + if(c == cmdSelect) + { + main.menu.listen = this; + main.menu.parent = this; + main.menu.setType(cvsMenu.MENU_SELECT_ACTION); + main.dsp.setCurrent(main.menu); + } + else if(c == cmdEdit) + { + mode = MODE_KEYS; + updateList(size() > 0 ? (KeyInfo)keys.elementAt(getSelectedIndex()) : null); + } + else if(c == cmdBack) + { + main.menu.listen = oldMML; + main.dsp.setCurrent(parent); + } + } + else if(mode == MODE_KEYS) + { + if(c == cmdAdd) + { + addnew = true; + +// tfName.setString(AuxClass.timeToFileName(-1)); +// tfKeyCode.setString("0"); +// +// String s = Long.toString(System.currentTimeMillis(), Character.MAX_RADIX); +// tfAbbr.setString(s.substring(s.length() - 2)); +// +// main.dsp.setCurrent(form); + + main.dsp.setCurrent(canvas); + + } + else if(c == cmdEdit) + { + addnew = false; + + KeyInfo key = (KeyInfo)keys.elementAt(getSelectedIndex()); + + int code = key.getCode(); + String name = key.getName(); + + if(name.endsWith(keyConfig.HOT_KEY_SUFFIX)) + { + code &= ~gkcCanvas.KEY_HOT; + } + else if(name.endsWith(keyConfig.HELD_KEY_SUFFIX)) + { + code &= ~gkcCanvas.KEY_HELD; + } + + tfName.setString(name); + tfAbbr.setString(key.getAbbreviation()); + tfKeyCode.setString(Integer.toString(code)); + + main.dsp.setCurrent(form); + } + else if(c == cmdDelete) + { + int index = getSelectedIndex(); + + keyConfig.deleteKey((KeyInfo)keys.elementAt(index)); + delete(index); + } + else if(c == cmdBack) + { + mode = MODE_ACTIONS; + updateList(size() > 0 ? (KeyInfo)keys.elementAt(getSelectedIndex()) : null); + } + } + } + } + else if(dp == form) + { + if(c == cmdEnter) + { + main.dsp.setCurrent(canvas); + return; + } + else if(c == cmdOK) + { + int code = Integer.parseInt(tfKeyCode.getString()); + String name = tfName.getString(); + + if(code > 0) + { + if(name.endsWith(keyConfig.HOT_KEY_SUFFIX)) + { + code |= gkcCanvas.KEY_HOT; + } + else if(name.endsWith(keyConfig.HELD_KEY_SUFFIX)) + { + code |= gkcCanvas.KEY_HELD; + } + } + else if(name.endsWith(keyConfig.HOT_KEY_SUFFIX) || name.endsWith(keyConfig.HELD_KEY_SUFFIX)) + { + name = name.substring(0, name.length() - 1); + } + + if(addnew) + { + KeyInfo key = keyConfig.addKey(code, name, tfAbbr.getString(), Locale.KEY_NO_ACTION, false); + + keys.addElement(key); + append(formatKeyAbbreviation(key)); + + setSelectedIndex(size() - 1); + } + else + { + KeyInfo key = (KeyInfo)keys.elementAt(getSelectedIndex()); + + key.setCode(code); + key.setName(name); + key.setAbbreviation(tfAbbr.getString()); + + setString(formatKeyAbbreviation((KeyInfo)keys.elementAt(getSelectedIndex())), getSelectedIndex()); + } + } + + main.dsp.setCurrent(this); + } + } + + public void menuAction(int action) + { + keyConfig.setAction((KeyInfo)keys.elementAt(getSelectedIndex()), action); + main.menu.ret(); + + //updateList((KeyInfo)keys.elementAt(getSelectedIndex())); + setString(formatKeyAction((KeyInfo)keys.elementAt(getSelectedIndex())), getSelectedIndex()); + } + + public void listStateChanged(ListMenu list, int action) + { + if(action == ELEMENT_ADDED || action == ELEMENT_DELETED) + { + if(size() > 0) + { + if(mode == MODE_ACTIONS) + { + addCommand(cmdSelect); + } + else if(mode == MODE_KEYS) + { + addCommand(cmdEdit); + addCommand(cmdDelete); + } + } + else + { + if(mode == MODE_ACTIONS) + { + removeCommand(cmdSelect); + } + else if(mode == MODE_KEYS) + { + removeCommand(cmdEdit); + removeCommand(cmdDelete); + } + } + } + } +} diff --git a/src/filemanager/lstPanels.java b/src/filemanager/lstPanels.java new file mode 100644 index 0000000..926ad6e --- /dev/null +++ b/src/filemanager/lstPanels.java @@ -0,0 +1,78 @@ +package filemanager; + +import com.vmx.Locale; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; + +public class lstPanels extends ListMenu implements CommandListener, ListStateListener +{ + protected Object parent; + + public lstPanels(Object parent) + { + setTitle(Locale.getString(this, Locale.PANELS)); + + this.parent = parent; + + addCommand(new Command(Locale.getString(this, Locale.OPEN_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 2)); + + setCommandListener(this); + setStateListener(this); + + updateList(); + } + + public void updateList() + { + main.manager.storePanel(main.manager.currentPanel()); + + deleteAll(); + + int pcount = main.manager.panelsCount(); + String filename; + + for(int i = 0; i < pcount; i++) + { + filename = main.manager.getCurrentFileName(i); + + if(filename.length() == 0) + { + filename = Locale.getString(this, Locale.ROOT); + } + + //append(Integer.toString(i + 1) + ") " + filename); + append(filename); + } + + setSelectedIndex(main.manager.currentPanel()); + } + + public void commandAction(Command c, Displayable dp) + { + main.dsp.setCurrent(parent); + + if(c.getCommandType() == Command.OK) + { + main.manager.changePanel(getSelectedIndex()); + } + } + + public void listStateChanged(ListMenu list, int action) + { + if(size() > 0) + { + String pname = main.manager.getPanelName(getSelectedIndex()); + + if(pname.length() > 0) + { + setSubTitle(pname, false); + } + else + { + setSubTitle(Locale.getString(this, Locale.FILE_LIST), false); + } + } + } +} diff --git a/src/filemanager/main.java b/src/filemanager/main.java new file mode 100644 index 0000000..1d246e2 --- /dev/null +++ b/src/filemanager/main.java @@ -0,0 +1,552 @@ +package filemanager; + +import javax.microedition.lcdui.*; +import java.io.*; +import com.vmx.*; +import com.one.*; +import com.one.file.Connector; +import com.one.file.TransparentConnector; +import javax.microedition.midlet.MIDletStateChangeException; + +public class main implements Runnable // extends MIDlet +{ + public static final String TEXT_VIEW_CLASS = "modules.text.cvsTextView"; + + public static RootLoader loader; + public static String currentPath = "", currentFile = ""; + public static String oldPath = "", oldFile = ""; + public static cvsFileSelect FileSelect; + public static lstKeyConfig keycfg; + public static diskInfo diskinfo; + public static cvsMenu menu; + public static DisplayManager dsp; + public static PanelManager manager; + public static cvsWait wait; + public static MemoryMonitor monitor; + public static lstColorScheme colors; + + public static Accelerometer accelerometer; + + private boolean alreadyStarted = false; + private Thread closingThread; + + public main(RootLoader rl) + { + System.out.println("Starting with loader " + rl.getClass().getName() + "..."); + + loader = rl; + + Display d = rl.getDisplay(); + + dsp = new DisplayManager(d); + PaintableObject.setRenderer(dsp.getRenderer()); + GraphicAlert.setAlertDisplay(d); + Renderer.setVibraDisplay(d); + + ErrScreen.setRootLoader(rl); + ErrScreen.setDisplayManager(dsp); + + ProgressBar.setDisplayManager(dsp); + + Connector.setConnectionProvider(loader.getConnectionProvider()); + } + + public void restartApp() + { + options.saveOptions(); + + alreadyStarted = false; + startApp(); + } + + public void startApp() + { + if(alreadyStarted) + { + return; + } + + alreadyStarted = true; + + ModuleRegistry.reset(); + + SplashScreen splash = new SplashScreen(); + splash.setMaxState(35); + splash.setState(0); + dsp.setCurrent(splash); + + try + { + byte[][] vendors = new byte[][] + { + { 77, 73, 68, 108, 101, 116, 45, 86, 101, 110, 100, 111, 114 }, + { 83, 105, 108, 101, 110, 116, 75, 110, 105, 103, 104, 116, 44 }, + { 86, 77, 88 }, + { 68, 105, 72, 76, 111, 83 } + }; + + String s = loader.getAppProperty(TextProcessor.byteArrayToString(vendors[0])); + + for(int i = 1; i < vendors.length; i++) + { + if(s.indexOf(TextProcessor.byteArrayToString(vendors[i])) < 0) + { + throw new RuntimeException(); + } + } + + splash.nextState(); + + loadKernel(splash); + + if(options.firstTime < 2) + { + loadShell(splash); + } + else + { + splash.setState(splash.getMaxState()); + } + + System.out.println(Integer.toString(splash.getState()) + " of " + Integer.toString(splash.getMaxState()) + " load stages passed"); + + startUI(); + } + catch(Throwable t) + { + ErrScreen.showStopMsg(splash.getState(), t); + ErrScreen.getInstance().setNextDisplayable(null); + } + } + + protected static void loadKernel(SplashScreen splash) throws IOException + { + options.restoreOptions(); + + if(options.firstTime == 2 && loader.useNoEffects()) + { + options.noEffects = true; + options.longScrollSpeed = 0; + options.ditherGradients = false; + options.alphaGradients = false; + options.mmDelay = 500; + options.mmThreshold = 0; + options.cacheCodePages = false; + } + + splash.createBackground(); + splash.nextState(); + + images.loadImages(); + splash.nextState(); + + StringEncoder.loadCodePages(options.cacheCodePages); + splash.nextState(); + + String s = loader.getAppProperty("Default-Encoding"); + + if(s != null) + { + StringEncoder.ENC_DEFAULT = StringEncoder.findEncoding(s); + } + splash.nextState(); + + if(options.firstTime == 2) + { + s = loader.getAppProperty("Archive-Encoding"); + + if(s != null) + { + StringEncoder.ENC_ARCHIVE = StringEncoder.findEncoding(s); + } + + options.textEnc = StringEncoder.ENC_DEFAULT; + options.arcEnc = StringEncoder.ENC_ARCHIVE; + } + else + { + StringEncoder.ENC_ARCHIVE = options.arcEnc; + } + splash.nextState(); + + ColorScheme.readSchemeList(); + splash.nextState(); + + if(options.colorScheme != ColorScheme.SCHEME_CUSTOM) + { + try + { + ColorScheme.loadColorScheme(options.colorScheme); + } + catch(Exception e) + { + ErrScreen.showErrMsg(67, e); + } + } + splash.nextState(); + + gkcCanvas.readKeyMapList(); + splash.nextState(); + + options.keyMap = gkcCanvas.setKeyMap(options.keyMap, options.screenTransform); + splash.nextState(); + + // Загружаем ÑпиÑок Ñзыков и Ñзык + if(!Locale.readLocaleList()) + { + ErrScreen.showErrMsg(68, null); + } + splash.nextState(); + + if(options.language.length() == 0) + { + s = System.getProperty("microedition.locale"); + System.out.println("Default locale is " + s); + + if(s != null) + { + s = s.toLowerCase(); + + for(int i = 0; i < Locale.locales.length; i++) + { + if(s.startsWith(Locale.locales[i].toLowerCase())) + { + options.language = Locale.locales[i]; + break; + } + } + } + } + splash.nextState(); + + try + { + Locale.loadLocale(options.language); + } + catch(Exception e) + { + ErrScreen.showErrMsg(69, e); + options.language = "en"; + + try + { + Locale.loadLocale("en"); + } + catch(Exception e1) + { + ErrScreen.showErrMsg(70, e1); + } + } + splash.nextState(); + + ProgressBar.setDisplayable(createLocalizedProgressScreen()); + splash.nextState(); + + Renderer.setVibraDuration(options.keyVibraDuration); + } + + protected static void loadShell(SplashScreen splash) throws IOException + { + images.loadIcons(splash, options.noEffects); + splash.nextState(); + + options.loadBookMarks(); + splash.nextState(); + + options.loadFavorites(); + splash.nextState(); + + TemplateManager.readTemplateList(); + splash.nextState(); + + keycfg = new lstKeyConfig(); + splash.nextState(); + + wait = new cvsWait(); + splash.nextState(); + + menu = new cvsMenu(); + splash.nextState(); + + try + { + filesystem.init(); + } + catch(IOException ioe) + { + ErrScreen.showErrMsg(72, ioe); + } + splash.nextState(); + + //ModuleRegistry.loadLocale(loader, options.language); + //splash.nextState(); + + ModuleRegistry.readModuleList(splash, options.noEffects); + splash.nextState(); + + ModuleRegistry.readTypeList(); + splash.nextState(); + + ModuleRegistry.readGroupList(); + splash.nextState(); + + ModuleRegistry.readOptionStoreList(); + splash.nextState(); + + ModuleRegistry.restoreModuleOptions(); + splash.nextState(); + + FileSelect = new cvsFileSelect(); + splash.nextState(); + + manager = new PanelManager(dsp, 10); + splash.nextState(); + + if(options.rememberPath) + { + manager.restorePanels(); + } + splash.nextState(); + + monitor = new MemoryMonitor(); + monitor.setDelay(options.mmDelay); + monitor.setThreshold(options.mmThreshold); + monitor.setOffscreenUpdate(true); + splash.nextState(); + + Palette.loadPalette(); + splash.nextState(); + + Palette.loadUnifiedPalette(); + splash.nextState(); + + accelerometer = loader.getAccelerometer(); + + if(accelerometer == null) + { + accelerometer = new Accelerometer() + { + public int getValue(int channel) + { + return 0; + } + + public int getDelta(int channel, int threshold) + { + return 0; + } + }; + } + splash.nextState(); + + startLightControl(false); + splash.nextState(); + + ImageProcessor.releaseCachedImages(); + + gkcCanvas.PTX = AuxClass.parseInt(loader.getAppProperty("Pointer-Translate-X"), 0); + gkcCanvas.PTY = AuxClass.parseInt(loader.getAppProperty("Pointer-Translate-Y"), 0); + + float fdh = Font.getDefaultFont().getHeight(); + + gkcCanvas.PCW = (int)(fdh * AuxClass.parseFloat(loader.getAppProperty("Pointer-Cell-Width"), 1.0f)); + gkcCanvas.PCH = (int)(fdh * AuxClass.parseFloat(loader.getAppProperty("Pointer-Cell-Height"), 1.0f)); + gkcCanvas.PSF = (int)(fdh * AuxClass.parseFloat(loader.getAppProperty("Pointer-Soft-Height"), 1.0f)); + } + + /** + * ЗапуÑк интерфейÑа + */ + public static void startUI() + { + images.splashBack = null; + + if(options.firstTime == 2) + { + dsp.setCurrent(new frmInitialSetup()); + } + else if(options.firstTime == 1) + { + dsp.setCurrent(new frmEULA()); + } + else + { + manager.showPanel(manager.currentPanel()); + } + } + + /** + * ЗапуÑтить поÑтоÑнную подÑветку (еÑли можно). + * @param flag - еÑли поÑдветка горит не вÑегда, то она горит, еÑли здеÑÑŒ true + */ + public static void startLightControl(boolean flag) + { + LightControl.startLightControl(options.lightControlMode == 1 || (options.lightControlMode == 2 && flag)); + } + + /** + * Создать Ñкран прогреÑÑа, иÑпользующий текущую локаль. + */ + protected static Object createLocalizedProgressScreen() + { + GraphicAlert al = new GraphicAlert(Locale.getString(null, Locale.WAIT), Locale.getString(null, Locale.WAIT_PLEASE), null, AlertType.WARNING); + al.setTimeout(Alert.FOREVER); + al.setIndicator(true); + + return al; + } + + /** + * Показать Alert Ñ Ñообщением. + * + * "Фишка" здеÑÑŒ в том, что значек выбираетÑÑ + * иÑÑ…Ð¾Ð´Ñ Ð¸Ð· переданного AlertType. + * + * @param title заголовок ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ + * @param text текÑÑ‚ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ + * @param type тип ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ + * @param timeout как долго его держать на Ñкране + * @param parent что Ñтавить на Ñкран поÑле + */ + public static void showMessage(String title, String text, AlertType type, int timeout, Object parent) + { + GraphicAlert al = new GraphicAlert(title, text, images.getAlertIcon(type), type); + al.addCommand(new Command(Locale.getString(null, Locale.OK_CMD), Command.OK, 0)); + al.setTimeout(timeout); + + dsp.setCurrent(al, parent != null ? parent : dsp.getCurrent()); + } + + /** + * Показать редактор цветовой Ñхемы. + * ЕÑли он еще не загружен, загрузить его. + * + * @param parent что Ñтавить на Ñкран поÑле + */ + public static void showColorSchemeEditor(Object parent) + { + if(colors == null) + { + colors = new lstColorScheme(); + } + + colors.updateList(); + + colors.parent = parent; + dsp.setCurrent(colors); + } + +// public static void setScreenTransform(int transform) +// { +// Renderer rn = PaintableObject.getRenderer(); +// +// if(rn.getTransform() == transform) +// { +// return; +// } +// +// rn.setEnabled(false); +// +// rn.setTransform(transform); +// images.loadImages(images.isTransformLandscape(transform)); +// gkcCanvas.setKeyMap(options.keyMap, transform); +// +// FileSelect.updateLayout(); +// +// rn.setEnabled(true); +// } + + /** + * ПриоÑтановить выполнение Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ - вызываетÑÑ JRE + */ + public void pauseApp() + { + loader.notifyPaused(); + } + + /** + * Уничтожить приложение - вызываетÑÑ Ñамим приложением + */ + public static void destroyApp() + { + try + { + loader.destroyApp(false); + } + catch(MIDletStateChangeException _) + { + } + } + + /** + * Уничтожить приложение - вызываетÑÑ JRE + */ + public void destroyApp(boolean unconditional) throws MIDletStateChangeException + { + System.out.print("Saving settings..."); + + options.saveOptions(); + options.saveFavorites(); + options.saveBookMarks(); + + ModuleRegistry.saveModuleOptions(); + + if(manager != null) + { + manager.storePanel(manager.currentPanel()); + manager.savePanels(); + } + + System.out.println(" done"); + + if(unconditional) + { + // ЗавершитьÑÑ ÐºÐ°Ðº положено нам не дадут, + // так что лучше и не пытатьÑÑ + + loader.notifyDestroyed(); + } + else + { + if(closingThread == null) + { + if(TransparentConnector.hasOpenContainers()) + { + closingThread = new Thread(this); + closingThread.start(); + } + else + { + loader.notifyDestroyed(); + } + } + + throw new MIDletStateChangeException(); + } + } + + public void run() + { + System.out.print("Closing containers..."); + + try + { + TransparentConnector.closeContainers(); + } + catch(IOException e) + { + ErrScreen.showErrMsg(136, e); + } + + System.out.println(" done"); + + closingThread = null; + + loader.notifyDestroyed(); + } + +// private static void out(String s) +// { +// System.out.println("[main] " + s); +// } +} diff --git a/src/filemanager/options.java b/src/filemanager/options.java new file mode 100644 index 0000000..7890339 --- /dev/null +++ b/src/filemanager/options.java @@ -0,0 +1,481 @@ +package filemanager; + +import com.one.ErrScreen; +import com.vmx.AuxClass; +import javax.microedition.rms.*; +import java.io.*; +import java.util.Vector; +import java.util.Enumeration; + +public class options +{ + // ВерÑÐ¸Ñ Ð½Ð°Ñтроек... МенÑетÑÑ, когда изменÑетÑÑ Ð¸Ñ… Ñтруктура в RMS + public static final int OPTIONS_VERSION = 45; + + // Хранилище Ð´Ð»Ñ Ð½Ð°Ñтроек + private static RecordStore favoritesStore; + private static RecordStore bookmarksStore; + + // ÐаÑтройки + public static int firstTime = 2; // первый раз запущен + public static boolean showHidden = false; // показывать Ñкрытые + public static boolean openNotSupported = false; // показывать неподдерживаемые + public static boolean noEffects = false; // Ñффекты, в чаÑтноÑти, маÑштабируемые Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ + public static String language = ""; + public static boolean showErrors = true; + public static int colorScheme = 0; + public static boolean checkFileAttrib = false; + public static boolean accurateDirCheck = false; + public static int keyMap = -1; + public static boolean clockMode = true; + public static int textEnc = 0; + public static int arcEnc = 0; + public static boolean showMenuNum = true; + public static String extColorScheme = ""; + public static boolean frameCursor = false; + public static boolean rememberPath = true; + public static boolean playAlertSounds = true; + public static boolean swapSoftKeys = false; + public static int listSortBy = 1; + public static boolean listSortReverseOrder = false; + public static boolean listSortIgnoreCase = true; + public static boolean useFullMenu = false; + public static boolean markMoveNext = true; + public static boolean alterClockPos = false; + public static int lightControlMode = 2; + public static int screenTransform = 0; + public static int keyVibraDuration = 0; + public static int mmDelay = 1000; + public static int mmThreshold = 100; + public static float longScrollSpeed = 1; + public static boolean ditherGradients = true; + public static boolean alphaGradients = true; + public static boolean fullNamesInFav = false; + public static boolean fullNamesInBuf = true; + public static boolean cacheCodePages = true; + public static boolean largeFontInList = false; + public static boolean largeFontInMenu = false; + public static boolean exitFromDriveList = true; + + // еще наÑтройки + + // Избранное + protected static Vector favorites = new Vector(); + + // Закладки + protected static Vector bookmarks = new Vector(); + + protected static class BookMarkRecord + { + public String name; + public int position; + } + + /** + * ПуÑтой конÑтруктор + */ + public options() + { + } + + /** + * Сохранение наÑтроек + */ + public static void saveOptions() + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(OPTIONS_VERSION); + dos.writeInt(firstTime); + dos.writeBoolean(showHidden); + dos.writeBoolean(openNotSupported); + dos.writeBoolean(noEffects); + dos.writeUTF(language); + dos.writeBoolean(showErrors); + dos.writeInt(colorScheme); + dos.writeBoolean(checkFileAttrib); + dos.writeBoolean(accurateDirCheck); + dos.writeInt(keyMap); + dos.writeBoolean(clockMode); + dos.writeInt(textEnc); + dos.writeInt(arcEnc); + dos.writeBoolean(showMenuNum); + dos.writeUTF(extColorScheme); + dos.writeBoolean(frameCursor); + dos.writeBoolean(rememberPath); + dos.writeBoolean(playAlertSounds); + dos.writeBoolean(swapSoftKeys); + dos.writeInt(listSortBy); + dos.writeBoolean(listSortReverseOrder); + dos.writeBoolean(listSortIgnoreCase); + dos.writeBoolean(useFullMenu); + dos.writeBoolean(markMoveNext); + dos.writeBoolean(alterClockPos); + dos.writeInt(lightControlMode); + dos.writeInt(screenTransform); + dos.writeInt(keyVibraDuration); + dos.writeInt(mmDelay); + dos.writeInt(mmThreshold); + dos.writeFloat(longScrollSpeed); + dos.writeBoolean(ditherGradients); + dos.writeBoolean(alphaGradients); + dos.writeBoolean(fullNamesInFav); + dos.writeBoolean(fullNamesInBuf); + dos.writeBoolean(cacheCodePages); + dos.writeBoolean(largeFontInList); + dos.writeBoolean(largeFontInMenu); + dos.writeBoolean(exitFromDriveList); + + keyConfig.writeConfig(dos); + + ColorScheme.writeSchemeData(dos); + + byte[] data = baos.toByteArray(); + dos.close(); + + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(0), true); + + if(rs.getNumRecords() == 0) + { + rs.addRecord(data, 0, data.length); + } + else + { + rs.setRecord(1, data, 0, data.length); + } + + rs.closeRecordStore(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(103, e); + } + } + + /** + * ВоÑÑтановить наÑтройки + */ + public static void restoreOptions() + { + try + { + RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(0), true); + + if(rs.getNumRecords() == 0) + { + rs.closeRecordStore(); + return; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(rs.getRecord(1))); + + if(dis.readInt() != OPTIONS_VERSION) + { + // Что-то поменÑлоÑÑŒ в Ñтруктуре, + // и воÑÑтановить Ñтарые наÑтройки уже не получитÑÑ. + // СбраÑываем наÑтройки на иÑходные. + + dis.close(); + rs.closeRecordStore(); + + resetOptions(); + + return; + } + + firstTime = dis.readInt(); // первый раз запущен + showHidden = dis.readBoolean(); // показывать Ñкрытые + openNotSupported = dis.readBoolean(); // показывать неподдерживаемые + noEffects = dis.readBoolean(); // без "подождите" + language = dis.readUTF(); + showErrors = dis.readBoolean(); + colorScheme = dis.readInt(); + checkFileAttrib = dis.readBoolean(); + accurateDirCheck = dis.readBoolean(); + keyMap = dis.readInt(); + clockMode = dis.readBoolean(); + textEnc = dis.readInt(); + arcEnc = dis.readInt(); + showMenuNum = dis.readBoolean(); + extColorScheme = dis.readUTF(); + frameCursor = dis.readBoolean(); + rememberPath = dis.readBoolean(); + playAlertSounds = dis.readBoolean(); + swapSoftKeys = dis.readBoolean(); + listSortBy = dis.readInt(); + listSortReverseOrder = dis.readBoolean(); + listSortIgnoreCase = dis.readBoolean(); + useFullMenu = dis.readBoolean(); + markMoveNext = dis.readBoolean(); + alterClockPos = dis.readBoolean(); + lightControlMode = dis.readInt(); + screenTransform = dis.readInt(); + keyVibraDuration = dis.readInt(); + mmDelay = dis.readInt(); + mmThreshold = dis.readInt(); + longScrollSpeed = dis.readFloat(); + ditherGradients = dis.readBoolean(); + alphaGradients = dis.readBoolean(); + fullNamesInFav = dis.readBoolean(); + fullNamesInBuf = dis.readBoolean(); + cacheCodePages = dis.readBoolean(); + largeFontInList = dis.readBoolean(); + largeFontInMenu = dis.readBoolean(); + exitFromDriveList = dis.readBoolean(); + + keyConfig.readConfig(dis); + + ColorScheme.readSchemeData(dis); + + dis.close(); + + rs.closeRecordStore(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(104, e); + } + } + + public static void resetOptions() + { + try + { + RecordStore.deleteRecordStore(AuxClass.getStoreName(0)); + } + catch(Exception e) + { + ErrScreen.showErrMsg(105, e); + } + } + + /** + * Сохранение избранного + */ + public static void saveFavorites() + { + try + { + RecordStore.deleteRecordStore(AuxClass.getStoreName(1)); + } + catch(RecordStoreException e) + { + } + + try + { + favoritesStore = RecordStore.openRecordStore(AuxClass.getStoreName(1), true); + + for(int i = 0; i < favorites.size(); i++) + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeUTF((String)favorites.elementAt(i)); + byte b[] = baos.toByteArray(); + favoritesStore.addRecord(b, 0, b.length); + } + catch(Exception e) + { + } + } + + favoritesStore.closeRecordStore(); + } + catch(Exception e) + { + } + } + + /** + * Получение избранного + */ + public static Enumeration getFavorites() + { + return favorites.elements(); + } + + /** + * Добавление в избранное + */ + public static void addFavorite(String nf) + { + favorites.addElement(nf); + } + + /** + * Удаление из избранного + */ + public static void deleteFavorite(String ff) + { + favorites.removeElement(ff); + } + + /** + * Чтение Ñтрок из хранилища + */ + public static void loadFavorites() + { + favorites.removeAllElements(); + + try + { + favoritesStore = RecordStore.openRecordStore(AuxClass.getStoreName(1), true); + + try + { + for(RecordEnumeration enumX = favoritesStore.enumerateRecords(null, null, true); enumX.hasNextElement(); ) + { + int recId = enumX.nextRecordId(); + ByteArrayInputStream bais = new ByteArrayInputStream(favoritesStore.getRecord(recId)); + DataInputStream dis = new DataInputStream(bais); + String in = dis.readUTF(); + favorites.addElement(in); + } + } + catch(Exception e) + { + } + + favoritesStore.closeRecordStore(); + } + catch(RecordStoreNotFoundException e) + { + } + catch(RecordStoreException e) + { + } + } + + public static void setBookMark(String name, int position) + { + BookMarkRecord bmr = null; + + for(int i = 0; i < bookmarks.size(); i++) + { + bmr = (BookMarkRecord)bookmarks.elementAt(i); + + if(bmr.name.equals(name)) + { + bmr.position = position; + return; + } + } + + bmr = new BookMarkRecord(); + bmr.name = name; + bmr.position = position; + + bookmarks.addElement(bmr); + } + + public static int getBookMark(String name) + { + BookMarkRecord bmr = null; + int r = 0; + + for(int i = 0; i < bookmarks.size(); i++) + { + bmr = (BookMarkRecord)bookmarks.elementAt(i); + + if(bmr.name.equals(name)) + { + r = bmr.position; + break; + } + } + + return r; + } + + /** + * Сохранение закладок + */ + public static void saveBookMarks() + { + try + { + RecordStore.deleteRecordStore(AuxClass.getStoreName(2)); + } + catch(RecordStoreException e) + { + } + + try + { + bookmarksStore = RecordStore.openRecordStore(AuxClass.getStoreName(2), true); + + for(int i = 0; i < bookmarks.size(); i++) + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeUTF(((BookMarkRecord)bookmarks.elementAt(i)).name); + dos.writeInt(((BookMarkRecord)bookmarks.elementAt(i)).position); + + byte b[] = baos.toByteArray(); + bookmarksStore.addRecord(b, 0, b.length); + } + catch(Exception e) + { + } + } + + bookmarksStore.closeRecordStore(); + } + catch(Exception e) + { + } + } + + /** + * Чтение закладок из хранилища + */ + public static void loadBookMarks() + { + bookmarks.removeAllElements(); + + try + { + bookmarksStore = RecordStore.openRecordStore(AuxClass.getStoreName(2), true); + + try + { + for(RecordEnumeration enumX = bookmarksStore.enumerateRecords(null, null, true); enumX.hasNextElement(); ) + { + int recId = enumX.nextRecordId(); + ByteArrayInputStream bais = new ByteArrayInputStream(bookmarksStore.getRecord(recId)); + DataInputStream dis = new DataInputStream(bais); + + BookMarkRecord bmr = new BookMarkRecord(); + bmr.name = dis.readUTF(); + bmr.position = dis.readInt(); + + bookmarks.addElement(bmr); + } + } + catch(Exception e) + { + } + + bookmarksStore.closeRecordStore(); + } + catch(RecordStoreNotFoundException e) + { + } + catch(RecordStoreException e) + { + } + } + +// private static void out(String s) +// { +// System.out.println("[options] " + s); +// } +} diff --git a/src/mcp/InternalConnections.java b/src/mcp/InternalConnections.java new file mode 100644 index 0000000..1b9eff7 --- /dev/null +++ b/src/mcp/InternalConnections.java @@ -0,0 +1,534 @@ +package mcp; + +//#if JSR75 == "auto" + +import java.io.*; +import javax.microedition.io.Connection; +import java.util.Enumeration; + +class SiemensFileConnection implements com.one.file.FileConnection +{ + protected com.siemens.mp.io.file.FileConnection conn; + + public static Enumeration listRoots() + { + return com.siemens.mp.io.file.FileSystemRegistry.listRoots(); + } + + public SiemensFileConnection(Connection conn) + { + this.conn = (com.siemens.mp.io.file.FileConnection)conn; + } + + public void close() throws IOException + { + conn.close(); + } + + public boolean isOpen() + { + return conn.isOpen(); + } + + public InputStream openInputStream() throws IOException + { + return conn.openInputStream(); + } + + public DataInputStream openDataInputStream() throws IOException + { + return conn.openDataInputStream(); + } + + public OutputStream openOutputStream() throws IOException + { + return conn.openOutputStream(); + } + + public DataOutputStream openDataOutputStream() throws IOException + { + return conn.openDataOutputStream(); + } + + public OutputStream openOutputStream(long byteOffset) throws IOException + { + return conn.openOutputStream(byteOffset); + } + + public long totalSize() + { + return conn.totalSize(); + } + + public long availableSize() + { + return conn.availableSize(); + } + + public long usedSize() + { + return conn.usedSize(); + } + + public long directorySize(boolean includeSubDirs) throws IOException + { + return conn.directorySize(includeSubDirs); + } + + public long fileSize() throws IOException + { + return conn.fileSize(); + } + + public boolean canRead() + { + return conn.canRead(); + } + + public boolean canWrite() + { + return conn.canWrite(); + } + + public boolean isHidden() + { + return conn.isHidden(); + } + + public void setReadable(boolean readable) throws IOException + { + conn.setReadable(readable); + } + + public void setWritable(boolean writable) throws IOException + { + conn.setWritable(writable); + } + + public void setHidden(boolean hidden) throws IOException + { + conn.setHidden(hidden); + } + + public Enumeration list() throws IOException + { + return conn.list(); + } + + public Enumeration list(String filter, boolean includeHidden) throws IOException + { + return conn.list(filter, includeHidden); + } + + public void create() throws IOException + { + conn.create(); + } + + public void mkdir() throws IOException + { + conn.mkdir(); + } + + public boolean exists() + { + return conn.exists(); + } + + public boolean isDirectory() + { + return conn.isDirectory(); + } + + public void delete() throws IOException + { + conn.delete(); + } + + public void rename(String newName) throws IOException + { + conn.rename(newName); + } + + public void truncate(long byteOffset) throws IOException + { + conn.truncate(byteOffset); + } + + public void setFileConnection(String fileName) throws IOException + { + conn.setFileConnection(fileName); + } + + public String getName() + { + return conn.getName(); + } + + public String getPath() + { + return conn.getPath(); + } + + public String getURL() + { + return conn.getURL(); + } + + public long lastModified() + { + return conn.lastModified(); + } +} + +class MotorolaTypeAFileConnection implements com.one.file.FileConnection +{ + protected com.motorola.io.FileConnection conn; + + public static Enumeration listRoots() + { + return com.motorola.io.FileSystemRegistry.listRoots(); + } + + public MotorolaTypeAFileConnection(Connection conn) + { + this.conn = (com.motorola.io.FileConnection)conn; + } + + public void close() throws IOException + { + conn.close(); + } + + public boolean isOpen() + { + return conn.isOpen(); + } + + public InputStream openInputStream() throws IOException + { + return conn.openInputStream(); + } + + public DataInputStream openDataInputStream() throws IOException + { + return conn.openDataInputStream(); + } + + public OutputStream openOutputStream() throws IOException + { + return conn.openOutputStream(); + } + + public DataOutputStream openDataOutputStream() throws IOException + { + return conn.openDataOutputStream(); + } + + public OutputStream openOutputStream(long byteOffset) throws IOException + { + return conn.openOutputStream(byteOffset); + } + + public long totalSize() + { + return conn.totalSize(); + } + + public long availableSize() + { + return conn.availableSize(); + } + + public long usedSize() + { + return conn.usedSize(); + } + + public long directorySize(boolean includeSubDirs) throws IOException + { + return conn.directorySize(includeSubDirs); + } + + public long fileSize() throws IOException + { + return conn.fileSize(); + } + + public boolean canRead() + { + return conn.canRead(); + } + + public boolean canWrite() + { + return conn.canWrite(); + } + + public boolean isHidden() + { + return conn.isHidden(); + } + + public void setReadable(boolean readable) throws IOException + { + conn.setReadable(readable); + } + + public void setWritable(boolean writable) throws IOException + { + conn.setWritable(writable); + } + + public void setHidden(boolean hidden) throws IOException + { + conn.setHidden(hidden); + } + + public Enumeration list() throws IOException + { + return conn.list(); + } + + public Enumeration list(String filter, boolean includeHidden) throws IOException + { + return conn.list(filter, includeHidden); + } + + public void create() throws IOException + { + conn.create(); + } + + public void mkdir() throws IOException + { + conn.mkdir(); + } + + public boolean exists() + { + return conn.exists(); + } + + public boolean isDirectory() + { + return conn.isDirectory(); + } + + public void delete() throws IOException + { + conn.delete(); + } + + public void rename(String newName) throws IOException + { + conn.rename(newName); + } + + public void truncate(long byteOffset) throws IOException + { + conn.truncate(byteOffset); + } + + public void setFileConnection(String fileName) throws IOException + { + conn.setFileConnection(fileName); + } + + public String getName() + { + return conn.getName(); + } + + public String getPath() + { + return conn.getPath(); + } + + public String getURL() + { + return conn.getURL(); + } + + public long lastModified() + { + return conn.lastModified(); + } +} + +class MotorolaTypeBFileConnection implements com.one.file.FileConnection +{ + protected com.motorola.io.file.FileConnection conn; + + public static Enumeration listRoots() + { + return com.motorola.io.file.FileSystemRegistry.listRoots(); + } + + public MotorolaTypeBFileConnection(Connection conn) + { + this.conn = (com.motorola.io.file.FileConnection)conn; + } + + public void close() throws IOException + { + conn.close(); + } + + public boolean isOpen() + { + return conn.isOpen(); + } + + public InputStream openInputStream() throws IOException + { + return conn.openInputStream(); + } + + public DataInputStream openDataInputStream() throws IOException + { + return conn.openDataInputStream(); + } + + public OutputStream openOutputStream() throws IOException + { + return conn.openOutputStream(); + } + + public DataOutputStream openDataOutputStream() throws IOException + { + return conn.openDataOutputStream(); + } + + public OutputStream openOutputStream(long byteOffset) throws IOException + { + return conn.openOutputStream(byteOffset); + } + + public long totalSize() + { + return conn.totalSize(); + } + + public long availableSize() + { + return conn.availableSize(); + } + + public long usedSize() + { + return conn.usedSize(); + } + + public long directorySize(boolean includeSubDirs) throws IOException + { + return conn.directorySize(includeSubDirs); + } + + public long fileSize() throws IOException + { + return conn.fileSize(); + } + + public boolean canRead() + { + return conn.canRead(); + } + + public boolean canWrite() + { + return conn.canWrite(); + } + + public boolean isHidden() + { + return conn.isHidden(); + } + + public void setReadable(boolean readable) throws IOException + { + conn.setReadable(readable); + } + + public void setWritable(boolean writable) throws IOException + { + conn.setWritable(writable); + } + + public void setHidden(boolean hidden) throws IOException + { + conn.setHidden(hidden); + } + + public Enumeration list() throws IOException + { + return conn.list(); + } + + public Enumeration list(String filter, boolean includeHidden) throws IOException + { + return conn.list(filter, includeHidden); + } + + public void create() throws IOException + { + conn.create(); + } + + public void mkdir() throws IOException + { + conn.mkdir(); + } + + public boolean exists() + { + return conn.exists(); + } + + public boolean isDirectory() + { + return conn.isDirectory(); + } + + public void delete() throws IOException + { + conn.delete(); + } + + public void rename(String newName) throws IOException + { + conn.rename(newName); + } + + public void truncate(long byteOffset) throws IOException + { + conn.truncate(byteOffset); + } + + public void setFileConnection(String fileName) throws IOException + { + conn.setFileConnection(fileName); + } + + public String getName() + { + return conn.getName(); + } + + public String getPath() + { + return conn.getPath(); + } + + public String getURL() + { + return conn.getURL(); + } + + public long lastModified() + { + return conn.lastModified(); + } +} + +//#endif \ No newline at end of file diff --git a/src/mcp/MultiConnectionProvider.java b/src/mcp/MultiConnectionProvider.java new file mode 100644 index 0000000..15e1148 --- /dev/null +++ b/src/mcp/MultiConnectionProvider.java @@ -0,0 +1,119 @@ +package mcp; + +import com.one.file.ConnectionProvider; +import com.one.file.FileConnection; +import com.one.file.GenericFileConnection; +import com.vmx.AuxClass; +import java.util.Enumeration; +import javax.microedition.io.Connection; + +public class MultiConnectionProvider implements ConnectionProvider +{ + static final int API_UNKNOWN = 0; + static final int API_GENERIC = 1; + static final int API_SIEMENS = 2; + static final int API_MOTOROLA_TYPE_A = 3; + static final int API_MOTOROLA_TYPE_B = 4; + + private static int apitype = -1; + + private static void detectApiType() + { + //#if JSR75 == "auto" + + if(AuxClass.classExists("javax.microedition.io.file.FileConnection")) + { + apitype = API_GENERIC; + } + else if(AuxClass.classExists("com.siemens.mp.io.file.FileConnection")) + { + apitype = API_SIEMENS; + } + else if(AuxClass.classExists("com.motorola.io.FileConnection")) + { + apitype = API_MOTOROLA_TYPE_A; + } + else if(AuxClass.classExists("com.motorola.io.file.FileConnection")) + { + apitype = API_MOTOROLA_TYPE_B; + } + else + { + apitype = API_UNKNOWN; + } + + //#else +//# +//# apitype = API_GENERIC; +//# + //#endif + } + + private static int getApiType() + { + if(apitype < 0) + { + detectApiType(); + } + + return apitype; + } + + public Enumeration listRoots() + { + //#if JSR75 == "auto" + + switch(getApiType()) + { + case API_GENERIC: + return GenericFileConnection.listRoots(); + + case API_SIEMENS: + return SiemensFileConnection.listRoots(); + + case API_MOTOROLA_TYPE_A: + return MotorolaTypeAFileConnection.listRoots(); + + case API_MOTOROLA_TYPE_B: + return MotorolaTypeBFileConnection.listRoots(); + + default: + return null; + } + + //#else +//# +//# return GenericFileConnection.listRoots(); +//# + //#endif + } + + public FileConnection convertFileConnection(Connection conn) + { + //#if JSR75 == "auto" + + switch(getApiType()) + { + case API_GENERIC: + return new GenericFileConnection(conn); + + case API_SIEMENS: + return new SiemensFileConnection(conn); + + case API_MOTOROLA_TYPE_A: + return new MotorolaTypeAFileConnection(conn); + + case API_MOTOROLA_TYPE_B: + return new MotorolaTypeBFileConnection(conn); + + default: + return null; + } + + //#else +//# +//# return new GenericFileConnection(conn); +//# + //#endif + } +} diff --git a/src/modules/DummyModule.java b/src/modules/DummyModule.java new file mode 100644 index 0000000..cc26820 --- /dev/null +++ b/src/modules/DummyModule.java @@ -0,0 +1,34 @@ +package modules; + +import com.one.Application; +import com.one.ModuleRegistry; +import com.one.PlayList; +import com.vmx.Locale; +import filemanager.main; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; + +public class DummyModule implements Application, CommandListener +{ + protected Object parent; + + public void openFile(String filename, PlayList filelist) + { + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + form.append(filename); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + form.setCommandListener(this); + + parent = main.dsp.getCurrent(); + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable dp) + { + main.dsp.setCurrent(parent); + } +} diff --git a/src/modules/FileSplicer.java b/src/modules/FileSplicer.java new file mode 100644 index 0000000..8ee1b2b --- /dev/null +++ b/src/modules/FileSplicer.java @@ -0,0 +1,67 @@ +package modules; + +import com.one.FileSource; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.AuxClass; +import com.vmx.Locale; +import filemanager.Buffer; +import filemanager.main; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import javax.microedition.lcdui.AlertType; + +public class FileSplicer implements FileSource +{ + public void createFile(String filename) throws IOException + { + if(Buffer.getSize() == 0) + { + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.BUFFER_EMPTY), AlertType.WARNING, 3000, main.dsp.getCurrent()); + return; + } + + FileConnection target = (FileConnection)Connector.open("file:///" + filename); + + if(target.exists()) + { + target.truncate(0); + } + else + { + target.create(); + } + + Buffer.flattenBuffer(); + //Buffer.sortBuffer(); + + Enumeration files = Buffer.getBuffer(); + + OutputStream os = target.openOutputStream(); + InputStream is; + + byte[] buf = new byte[AuxClass.COPYBUFSIZE]; + int len; + + while(files.hasMoreElements()) + { + is = Connector.openInputStream("file:///" + files.nextElement()); + + while((len = is.read(buf)) > 0) + { + os.write(buf, 0, len); + } + + is.close(); + } + + os.close(); + target.close(); + + Buffer.clear(); + + main.FileSelect.showWait(filename.substring(filename.lastIndexOf('/') + 1)); + } +} diff --git a/src/modules/FileSplitter.java b/src/modules/FileSplitter.java new file mode 100644 index 0000000..8c1b15c --- /dev/null +++ b/src/modules/FileSplitter.java @@ -0,0 +1,185 @@ +package modules; + +import com.one.Application; +import com.one.ErrScreen; +import com.one.ModuleRegistry; +import com.one.PlayList; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.AuxClass; +import com.vmx.Locale; +import filemanager.filesystem; +import filemanager.main; +import java.io.InputStream; +import java.io.OutputStream; +import javax.microedition.lcdui.AlertType; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; +import javax.microedition.lcdui.Item; +import javax.microedition.lcdui.ItemStateListener; +import javax.microedition.lcdui.TextField; + +public class FileSplitter implements Application, CommandListener, ItemStateListener +{ + public static final int PARTS_COUNT = 2, PART_SIZE = 3, SIZE_UNKNOWN = 4; + + protected Object parent; + protected String filename; + protected int filesize; + + protected TextField tfNumParts; + protected TextField tfPartSize; + + public void openFile(String filename, PlayList filelist) + { + this.filename = filename; + this.filesize = (int)filesystem.getSize(filename, false); + + if(filesize <= 0) + { + main.showMessage(Locale.getString(null, Locale.ERROR), Locale.getString(this, SIZE_UNKNOWN), AlertType.WARNING, 3000, null); + return; + } + + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + tfNumParts = new TextField(Locale.getString(this, PARTS_COUNT), "1", 20, TextField.NUMERIC); + tfPartSize = new TextField(Locale.getString(this, PART_SIZE), Integer.toString(filesize), 20, TextField.NUMERIC); + + form.append(tfNumParts); + form.append(tfPartSize); + + form.addCommand(new Command(Locale.getString(null, Locale.OK_CMD), Command.OK, 1)); + form.addCommand(new Command(Locale.getString(null, Locale.CANCEL_CMD), Command.CANCEL, 2)); + form.setCommandListener(this); + form.setItemStateListener(this); + + parent = main.dsp.getCurrent(); + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable dp) + { + if(c.getCommandType() == Command.OK) + { + try + { + InputStream is = Connector.openInputStream("file:///" + filename); + + FileConnection fc; + OutputStream os; + + int partsize = Integer.parseInt(tfPartSize.getString()); + int total = 0; + + byte[] buf = new byte[Math.min(partsize, AuxClass.COPYBUFSIZE)]; + int len; + + int part = 1; + int inpart; + + String name, ext; + + inpart = filename.lastIndexOf('.'); + + if(inpart >= 0) + { + name = filename.substring(0, inpart); + ext = filename.substring(inpart); + } + else + { + name = filename; + ext = ""; + } + + while(total < filesize) + { + fc = (FileConnection)Connector.open("file:///" + name + "." + AuxClass.integerToString(part++, 2) + ext); + + if(fc.exists()) + { + fc.truncate(0); + } + else + { + fc.create(); + } + + os = fc.openOutputStream(); + inpart = 0; + + partsize = Math.min(partsize, filesize - total); + + while(inpart < partsize) + { + len = is.read(buf); + + if(len <= 0) + { + break; + } + + os.write(buf, 0, len); + inpart += len; + } + + os.close(); + fc.close(); + + total += inpart; + } + + is.close(); + + main.FileSelect.showWait(filename.substring(filename.lastIndexOf('/') + 1)); + } + catch(Exception e) + { + ErrScreen.showErrMsg(ModuleRegistry.getErrCode(getClass().getName()) * 100 + 1, e); + } + } + else + { + main.dsp.setCurrent(parent); + } + } + + public void itemStateChanged(Item item) + { + if(item == tfNumParts) + { + int numparts = Integer.parseInt(tfNumParts.getString()); + + if(numparts < 1) + { + numparts = 1; + } + else if(numparts > filesize) + { + numparts = filesize; + } + + tfNumParts.setString(Integer.toString(numparts)); + tfPartSize.setString(Integer.toString((filesize + numparts - 1) / numparts)); + } + else if(item == tfPartSize) + { + int partsize = Integer.parseInt(tfPartSize.getString()); + + if(partsize < 1) + { + partsize = 1; + } + else if(partsize > filesize) + { + partsize = filesize; + } + + tfNumParts.setString(Integer.toString((filesize + partsize - 1) / partsize)); + tfPartSize.setString(Integer.toString(partsize)); + } + } +} diff --git a/src/modules/FishlabsUncoder.java b/src/modules/FishlabsUncoder.java new file mode 100644 index 0000000..ee56850 --- /dev/null +++ b/src/modules/FishlabsUncoder.java @@ -0,0 +1,58 @@ +package modules; + +import com.one.Application; +import com.one.PlayList; +import com.one.file.Connector; +import com.one.file.FileConnection; +import filemanager.filesystem; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class FishlabsUncoder implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + + String tempname = Connector.createTempFile(filename, true); + FileConnection temp = (FileConnection)Connector.open("file:///" + tempname); + temp.create(); + + byte[] code; + int len = (int) filesystem.getSize(filename, false); + code = new byte[len]; + DataInputStream dis = fc.openDataInputStream(); + dis.read(code, 0, len); + dis.close(); + int j; + if (len < 100) { + j = 10 + len % 10; + } else if (len < 200) { + j = 50 + len % 20; + } else if (len < 300) { + j = 80 + len % 20; + } else { + j = 100 + len % 50; + } + for (int k = 0; k < j; k++) { + byte byte0 = code[k]; + code[k] = code[len - k - 1]; + code[len - k - 1] = byte0; + } + DataOutputStream dos = temp.openDataOutputStream(); + dos.write(code, 0, code.length); + dos.close(); + + filename = fc.getName(); + fc.delete(); + fc.close(); + + temp.rename(filename); + temp.close(); + + Connector.releaseTempFile(tempname); + code = null; + System.gc(); + } +} diff --git a/src/modules/HideFile.java b/src/modules/HideFile.java new file mode 100644 index 0000000..e1959d9 --- /dev/null +++ b/src/modules/HideFile.java @@ -0,0 +1,19 @@ +package modules; + +import com.one.Application; +import com.one.PlayList; +import com.one.file.Connector; +import com.one.file.FileConnection; +import java.io.IOException; + +public class HideFile implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + filename = fc.getName(); + if(filename.endsWith(".$")) fc.rename(filename.substring(0, filename.length()-2)); + else fc.rename(filename + ".$"); + fc.close(); + } +} diff --git a/src/modules/NullFileSource.java b/src/modules/NullFileSource.java new file mode 100644 index 0000000..603861b --- /dev/null +++ b/src/modules/NullFileSource.java @@ -0,0 +1,63 @@ +package modules; + +import com.one.ErrScreen; +import com.one.FileSource; +import com.one.ModuleRegistry; +import com.one.TextProcessor; +import com.vmx.Locale; +import filemanager.filesystem; +import filemanager.main; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; +import javax.microedition.lcdui.TextField; + +public class NullFileSource implements FileSource, CommandListener +{ + protected Object parent; + protected String filename; + + protected TextField tfByte; + protected TextField tfLength; + + public void createFile(String filename) + { + this.filename = filename; + + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + tfByte = new TextField(Locale.getString(this, Locale.CHARACTER), "\\0", 6, TextField.ANY); + tfLength = new TextField(Locale.getString(this, Locale.SIZE), "0", 20, TextField.NUMERIC); + + form.append(tfByte); + form.append(tfLength); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.CANCEL, 1)); + form.setCommandListener(this); + + parent = main.dsp.getCurrent(); + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable dp) + { + if(c.getCommandType() == Command.OK) + { + try + { + filesystem.makeNewFile(filename, TextProcessor.unescapeString(tfByte.getString()), Integer.parseInt(tfLength.getString())); + main.FileSelect.showWait(filename.substring(filename.lastIndexOf('/') + 1)); + } + catch(Exception e) + { + ErrScreen.showErrMsg(ModuleRegistry.getErrCode(getClass().getName()) * 100 + 1, e); + } + } + else + { + main.dsp.setCurrent(parent); + } + } +} \ No newline at end of file diff --git a/src/modules/PPKFileSource.java b/src/modules/PPKFileSource.java new file mode 100644 index 0000000..3fbdde9 --- /dev/null +++ b/src/modules/PPKFileSource.java @@ -0,0 +1,22 @@ +package modules; + +import com.one.Container; +import com.one.FileSource; +import com.one.PlainPackage; +import com.one.file.Connector; +import com.one.file.FileConnection; +import filemanager.main; +import java.io.IOException; + +public class PPKFileSource implements FileSource +{ + public void createFile(String filename) throws IOException + { + Container container = new PlainPackage(); + + container.init((FileConnection)Connector.open("file:///" + filename), true); + container.close(); + + main.FileSelect.showWait(filename.substring(filename.lastIndexOf('/') + 1)); + } +} diff --git a/src/modules/RarOptions.java b/src/modules/RarOptions.java new file mode 100644 index 0000000..28b19c4 --- /dev/null +++ b/src/modules/RarOptions.java @@ -0,0 +1,210 @@ +package modules; + +import com.innosystec.unrar.unpack.Unpack; +import com.innosystec.unrar.unpack.decode.Compress; +import com.innosystec.unrar.unpack.vm.BitInput; +import com.innosystec.unrar.unpack.vm.RarVM; +import com.one.ModuleRegistry; +import com.one.OptionStorage; +import com.vmx.AuxClass; +import com.vmx.Locale; +import filemanager.filesystem; +import filemanager.main; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; +import javax.microedition.lcdui.Gauge; +import javax.microedition.lcdui.Item; +import javax.microedition.lcdui.ItemStateListener; + +public class RarOptions implements OptionStorage, CommandListener, ItemStateListener +{ + public static final int OPTIONS_VERSION = 1; + + protected static final int MAX_SHIFT = 8; + protected static final int PRE_SHIFT = 4; + + protected static int Compress_CODEBUFSIZE = Compress.CODEBUFSIZE << PRE_SHIFT; + protected static int Compress_MAXWINSIZE = Compress.MAXWINSIZE << PRE_SHIFT; + protected static int Compress_MAXWINMASK = Compress.MAXWINMASK << PRE_SHIFT; + protected static int BitInput_MAXSIZE = BitInput.MAX_SIZE << PRE_SHIFT; + protected static int RarVM_MEMSIZE = RarVM.VM_MEMSIZE << PRE_SHIFT; + protected static int RarVM_MEMMASK = RarVM.VM_MEMMASK << PRE_SHIFT; + protected static int RarVM_GLOBALMEMADDR = RarVM.VM_GLOBALMEMADDR << PRE_SHIFT; + protected static int RarVM_GLOBALMEMSIZE = RarVM.VM_GLOBALMEMSIZE << PRE_SHIFT; + protected static int Unpack_BUFSIZE = Unpack.BUFSIZE << PRE_SHIFT; + + protected Object parent; + + protected Gauge gCompress_CODEBUFSIZE; + protected Gauge gCompress_MAXWINSIZE; + protected Gauge gBitInput_MAXSIZE; + protected Gauge gRarVM_MEMSIZE; + protected Gauge gUnpack_BUFSIZE; + + public void showEditor(Object parent) + { + this.parent = parent; + + restoreOptions(); + + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + gCompress_CODEBUFSIZE = new Gauge(null, true, MAX_SHIFT, MAX_SHIFT - (AuxClass.logBaseTwo(Compress_CODEBUFSIZE) - AuxClass.logBaseTwo(Compress.CODEBUFSIZE))); + gCompress_MAXWINSIZE = new Gauge(null, true, MAX_SHIFT, MAX_SHIFT - (AuxClass.logBaseTwo(Compress_MAXWINSIZE) - AuxClass.logBaseTwo(Compress.MAXWINSIZE))); + gBitInput_MAXSIZE = new Gauge(null, true, MAX_SHIFT, MAX_SHIFT - (AuxClass.logBaseTwo(BitInput_MAXSIZE) - AuxClass.logBaseTwo(BitInput.MAX_SIZE))); + gRarVM_MEMSIZE = new Gauge(null, true, MAX_SHIFT, MAX_SHIFT - (AuxClass.logBaseTwo(RarVM_MEMSIZE) - AuxClass.logBaseTwo(RarVM.VM_MEMSIZE))); + gUnpack_BUFSIZE = new Gauge(null, true, MAX_SHIFT, MAX_SHIFT - (AuxClass.logBaseTwo(Unpack_BUFSIZE) - AuxClass.logBaseTwo(Unpack.BUFSIZE))); + + itemStateChanged(gCompress_CODEBUFSIZE); + itemStateChanged(gCompress_MAXWINSIZE); + itemStateChanged(gBitInput_MAXSIZE); + itemStateChanged(gRarVM_MEMSIZE); + itemStateChanged(gUnpack_BUFSIZE); + + form.append(gCompress_MAXWINSIZE); + //form.append(gCompress_CODEBUFSIZE); + //form.append(gBitInput_MAXSIZE); + form.append(gRarVM_MEMSIZE); + form.append(gUnpack_BUFSIZE); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + //form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 2)); + + form.setCommandListener(this); + form.setItemStateListener(this); + + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable d) + { + if(c.getCommandType() == Command.OK) + { + saveOptions(); + } + + main.dsp.setCurrent(parent); + } + + public void itemStateChanged(Item item) + { + int shift; + + if(item == gCompress_CODEBUFSIZE) + { + shift = gCompress_CODEBUFSIZE.getMaxValue() - gCompress_CODEBUFSIZE.getValue(); + + Compress.CODEBUFSIZE = Compress_CODEBUFSIZE >>> shift; + + gCompress_CODEBUFSIZE.setLabel("Code: " + filesystem.getSizeString(Compress.CODEBUFSIZE, false)); + } + else if(item == gCompress_MAXWINSIZE) + { + shift = gCompress_MAXWINSIZE.getMaxValue() - gCompress_MAXWINSIZE.getValue(); + + Compress.MAXWINSIZE = Compress_MAXWINSIZE >>> shift; + Compress.MAXWINMASK = Compress_MAXWINMASK >>> shift; + + gCompress_MAXWINSIZE.setLabel("Window: " + filesystem.getSizeString(Compress.MAXWINSIZE, false)); + } + else if(item == gBitInput_MAXSIZE) + { + shift = gBitInput_MAXSIZE.getMaxValue() - gBitInput_MAXSIZE.getValue(); + + BitInput.MAX_SIZE = BitInput_MAXSIZE >>> shift; + + gBitInput_MAXSIZE.setLabel("Bit Input: " + filesystem.getSizeString(BitInput.MAX_SIZE, false)); + } + else if(item == gRarVM_MEMSIZE) + { + shift = gRarVM_MEMSIZE.getMaxValue() - gRarVM_MEMSIZE.getValue(); + + RarVM.VM_MEMSIZE = RarVM_MEMSIZE >>> shift; + RarVM.VM_MEMMASK = RarVM_MEMMASK >>> shift; + RarVM.VM_GLOBALMEMADDR = RarVM_GLOBALMEMADDR >>> shift; + RarVM.VM_GLOBALMEMSIZE = RarVM_GLOBALMEMSIZE >>> shift; + + gRarVM_MEMSIZE.setLabel("VM Memory: " + filesystem.getSizeString(RarVM.VM_MEMSIZE, false)); + } + else if(item == gUnpack_BUFSIZE) + { + shift = gUnpack_BUFSIZE.getMaxValue() - gUnpack_BUFSIZE.getValue(); + + Unpack.BUFSIZE = Unpack_BUFSIZE >>> shift; + + gUnpack_BUFSIZE.setLabel("Unstore: " + filesystem.getSizeString(Unpack.BUFSIZE, false)); + } + } + + public void restoreOptions() + { + try + { + byte[] data = ModuleRegistry.getModuleData(getClass().getName()); + + if(data == null || data.length == 0) + { + return; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data)); + + if(dis.readInt() != OPTIONS_VERSION) + { + dis.close(); + return; + } + + Compress.CODEBUFSIZE = dis.readInt(); + Compress.MAXWINSIZE = dis.readInt(); + Compress.MAXWINMASK = dis.readInt(); + BitInput.MAX_SIZE = dis.readInt(); + RarVM.VM_MEMSIZE = dis.readInt(); + RarVM.VM_MEMMASK = dis.readInt(); + RarVM.VM_GLOBALMEMADDR = dis.readInt(); + RarVM.VM_GLOBALMEMSIZE = dis.readInt(); + Unpack.BUFSIZE = dis.readInt(); + + dis.close(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + + public void saveOptions() + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(OPTIONS_VERSION); + dos.writeInt(Compress.CODEBUFSIZE); + dos.writeInt(Compress.MAXWINSIZE); + dos.writeInt(Compress.MAXWINMASK); + dos.writeInt(BitInput.MAX_SIZE); + dos.writeInt(RarVM.VM_MEMSIZE); + dos.writeInt(RarVM.VM_MEMMASK); + dos.writeInt(RarVM.VM_GLOBALMEMADDR); + dos.writeInt(RarVM.VM_GLOBALMEMSIZE); + dos.writeInt(Unpack.BUFSIZE); + + byte[] data = baos.toByteArray(); + dos.close(); + + ModuleRegistry.setModuleData(getClass().getName(), data); + } + catch(Exception e) + { + e.printStackTrace(); + } + } +} diff --git a/src/modules/SWFCanvas.java b/src/modules/SWFCanvas.java new file mode 100644 index 0000000..f569034 --- /dev/null +++ b/src/modules/SWFCanvas.java @@ -0,0 +1,179 @@ +package modules; + +import com.one.PlayList; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.sonyericsson.capuchin.FlashImage; +import com.vmx.gkcCanvas; +import filemanager.images; +import filemanager.main; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import javax.microedition.lcdui.*; + +/** + * + * @author aNNiMON + */ +public class SWFCanvas extends gkcCanvas { + + public static final int MODEL_INFO = 3; + private boolean allowKeyRelease = true; + private boolean enableUI = true; + private String OnlyFileName = ""; + private Thread t; + protected PlayList playlist; + private int w, h; + private Font nameFont; + private int runpanel; + private static SWFCanvas instance; + private FlashImage flashImage; + + public static SWFCanvas getInstance() { + if (instance == null) { + instance = new SWFCanvas(); + } + + return instance; + } + + private class ImgChanger implements Runnable { + + private int dir; + + public ImgChanger(int dir) { + this.dir = dir; + } + + public void run() { + if (t != null && t.isAlive()) { + try { + t.join(); + } catch (InterruptedException ie) { + } + } + + if (dir > 0) { + playlist.nextElement(false); + } else if (dir < 0) { + playlist.prevElement(false); + } + + main.FileSelect.executeFile(playlist, null, runpanel); + } + } + + public SWFCanvas() { + setFullScreenMode(true); + nameFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); + } + + + public void init(String modelName) { + try { + FileConnection fc = (FileConnection) Connector.open("file:///" + modelName, Connector.READ); + InputStream is = fc.openInputStream(); + flashImage = FlashImage.createImage(is, null); + if(is!=null) is.close(); + if(fc!=null) fc.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + initPanels(); + initPlayList(modelName); + repaint(); + } + + public void setPlayList(PlayList newlist) { + playlist = newlist; + } + + public void setPlayList(Enumeration newlist) { + playlist = new PlayList(newlist); + } + + protected void initPanels() { + if (runpanel < 0) { + runpanel = main.manager.currentPanel(); + } + + main.manager.setCurrent(this, runpanel); + main.manager.updateAssociation(runpanel, playlist.getCurrentElement()); + main.manager.changePanel(runpanel); + } + + protected void initPlayList(String file) { + OnlyFileName = file.substring(file.lastIndexOf('/') + 1); + + if (playlist == null) { + playlist = new PlayList(file); + } + + playlist.selectElement(file); + } + + /** + * ÑÐ»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + */ + public void nextImage() { + (new Thread(new ImgChanger(1))).start(); + } + + /** + * Ð¿Ñ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + */ + public void prevModel() { + (new Thread(new ImgChanger(-1))).start(); + } + + public void paint(Graphics g) { + g.setColor(images.cImgBack); + g.fillRect(0, 0, w, h); + flashImage.render(g, 0, 0, w, h); + if (enableUI) { + if (images.minUI != null) { + g.drawImage(images.minUI, 0, h, Graphics.LEFT | Graphics.BOTTOM); + } + g.setFont(nameFont); + + g.setColor(images.cPlayFore1); //0x800000); + g.drawString(OnlyFileName, w / 2, h - images.uiBottomHeight + images.uiBottomVSpace, Graphics.TOP | Graphics.HCENTER); + } + repaint(); + } + + public void keyReleased(int keyCode) { + if (allowKeyRelease) { + handleKeyAction(keyCode); + } else { + allowKeyRelease = true; + } + } + + public void keyRepeated(int keyCode) { + allowKeyRelease = false; + handleKeyAction(keyCode); + } + + public void handleKeyAction(int key) { + if (key == KEY_RSK) { + playlist.cancelSearch(); + playlist = null; + + main.manager.ret(); + runpanel = -1; + } else if (key == KEY_CANCEL) { + main.manager.minimizePanel(); + } else if (key == KEY_RIGHT || key == KEY_DOWN) { + nextImage(); + } else if (key == KEY_LEFT || key == KEY_UP) { + prevModel(); + } else { + if (key == KEY_POUND) { + enableUI = !enableUI; + } + repaint(); + } + } +} diff --git a/src/modules/SWFViewer.java b/src/modules/SWFViewer.java new file mode 100644 index 0000000..314e4a7 --- /dev/null +++ b/src/modules/SWFViewer.java @@ -0,0 +1,28 @@ +/* + * aNNiMON 2010 + * For more info visit http://annimon.com/ + */ +package modules; + +import com.one.Application; +import com.one.PlayList; +import java.io.*; + +/** + * + * @author aNNiMON + */ +public class SWFViewer implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + SWFCanvas mc = SWFCanvas.getInstance(); + + if(filelist != null) + { + mc.setPlayList(filelist); + } + + mc.init(filename); + } +} diff --git a/src/modules/ZipFileSource.java b/src/modules/ZipFileSource.java new file mode 100644 index 0000000..80118b7 --- /dev/null +++ b/src/modules/ZipFileSource.java @@ -0,0 +1,57 @@ +package modules; + +import com.classpath.zip.ZipFile; +import com.one.Container; +import com.one.FileSource; +import com.one.file.Connector; +import com.one.file.FileConnection; +import filemanager.main; +import java.io.IOException; + +public class ZipFileSource implements FileSource //, CommandListener +{ +// protected Object parent; +// protected String filename; +// +// protected Gauge gCompLevel; + + public void createFile(String filename) throws IOException + { +// this.filename = filename; +// +// Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); +// +// gCompLevel = new Gauge(Locale.getString(this, Locale.COMPRESSION_LEVEL), true, Deflater.BEST_COMPRESSION, Deflater.BEST_COMPRESSION); +// +// form.append(gCompLevel); +// +// form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); +// form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.CANCEL, 2)); +// form.setCommandListener(this); +// +// parent = main.dsp.getCurrent(); +// main.dsp.setCurrent(form); + + Container container = new ZipFile(); + + container.init((FileConnection)Connector.open("file:///" + filename), true); + container.close(); + + main.FileSelect.showWait(filename.substring(filename.lastIndexOf('/') + 1)); + } + +// public void commandAction(Command c, Displayable dp) +// { +// if(c.getCommandType() == Command.OK) +// { +// try +// { +// +// } +// catch(Exception e) +// { +// ErrScreen.showErrMsg(ModuleRegistry.getErrCode(getClass().getName()) * 100 + 1, e); +// } +// } +// } +} diff --git a/src/modules/ZipOptions.java b/src/modules/ZipOptions.java new file mode 100644 index 0000000..3221999 --- /dev/null +++ b/src/modules/ZipOptions.java @@ -0,0 +1,108 @@ +package modules; + +import com.classpath.zip.Deflater; +import com.classpath.zip.ZipFile; +import com.one.ModuleRegistry; +import com.one.OptionStorage; +import com.vmx.Locale; +import filemanager.main; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; +import javax.microedition.lcdui.Gauge; + +public class ZipOptions implements OptionStorage, CommandListener +{ + public static final int OPTIONS_VERSION = 1; + + protected Object parent; + + protected Gauge gCompLevel; + + public void showEditor(Object parent) + { + this.parent = parent; + + restoreOptions(); + + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + gCompLevel = new Gauge(Locale.getString(this, Locale.COMPRESSION_LEVEL), true, Deflater.BEST_COMPRESSION - Deflater.NO_COMPRESSION, ZipFile.getCompressionLevel() - Deflater.NO_COMPRESSION); + + form.append(gCompLevel); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 2)); + + form.setCommandListener(this); + + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable d) + { + if(c.getCommandType() == Command.OK) + { + ZipFile.setCompressionLevel(gCompLevel.getValue() + Deflater.NO_COMPRESSION); + + saveOptions(); + } + + main.dsp.setCurrent(parent); + } + + public void restoreOptions() + { + try + { + byte[] data = ModuleRegistry.getModuleData(getClass().getName()); + + if(data == null || data.length == 0) + { + return; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data)); + + if(dis.readInt() != OPTIONS_VERSION) + { + dis.close(); + return; + } + + ZipFile.setCompressionLevel(dis.readInt()); + + dis.close(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + + public void saveOptions() + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(OPTIONS_VERSION); + dos.writeInt(ZipFile.getCompressionLevel()); + + byte[] data = baos.toByteArray(); + dos.close(); + + ModuleRegistry.setModuleData(getClass().getName(), data); + } + catch(Exception e) + { + e.printStackTrace(); + } + } +} diff --git a/src/modules/audio/AudioModule.java b/src/modules/audio/AudioModule.java new file mode 100644 index 0000000..5107c4e --- /dev/null +++ b/src/modules/audio/AudioModule.java @@ -0,0 +1,19 @@ +package modules.audio; + +import com.one.Application; +import com.one.PlayList; + +public class AudioModule implements Application +{ + public void openFile(String filename, PlayList filelist) + { + cvsPlayer player = cvsPlayer.getInstance(); + + if(filelist != null) + { + player.setPlayList(filelist); + } + + player.playSound(filename); + } +} diff --git a/src/modules/audio/AudioOptions.java b/src/modules/audio/AudioOptions.java new file mode 100644 index 0000000..e8ab932 --- /dev/null +++ b/src/modules/audio/AudioOptions.java @@ -0,0 +1,267 @@ +package modules.audio; + +import com.one.ModulePlayer; +import com.one.ModuleRegistry; +import com.one.OptionStorage; +import com.vmx.Locale; +import com.vmx.StringEncoder; +import filemanager.main; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.util.Enumeration; +import java.util.Hashtable; +import javax.microedition.lcdui.Choice; +import javax.microedition.lcdui.ChoiceGroup; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; +import javax.microedition.lcdui.TextField; + +public class AudioOptions implements CommandListener, OptionStorage +{ + public static final int OPTIONS_VERSION = 5; + + public static int volume = 100; // громкоÑÑ‚ÑŒ аудио плейера + public static boolean muted = false; // отключен звук в аудиоплейере? + public static int modBufSize = 10; + public static int modSampleRate = 0; + public static int modQuality = 1; + public static int playerVisualMode = 0; + public static int playerVisualVariant = 0; + public static boolean useAccelerometer = false; + public static boolean shufflePlay = false; + public static boolean showPlayProgress = true; + public static int id3Enc = 0; + public static String metaDataFormat = "author, title, album"; + public static boolean showMetaKeys = false; + + // Уровни Ñквалайзера + public static Hashtable eqlevels = new Hashtable(); + + protected Object parent; + + protected ChoiceGroup cgPlayer; + protected ChoiceGroup cgModSampleRate; + protected ChoiceGroup cgModQuality; + //protected ChoiceGroup cgID3Enc; + + protected TextField tfModBufSize; + protected TextField tfMetaDataFormat; + + public void showEditor(Object parent) + { + this.parent = parent; + + restoreOptions(); + + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + // *** ÐаÑтройки плеера *** + cgPlayer = new ChoiceGroup(Locale.getString(this, Locale.PREF_PLAYER_SETUP), Choice.MULTIPLE); + + // Показывать ключи метаданных + cgPlayer.append(Locale.getString(this, Locale.PREF_SHOW_META_KEYS), null); + cgPlayer.setSelectedIndex(0, showMetaKeys); + + // Показывать прогреÑÑ-бар при воÑпроизведении + cgPlayer.append(Locale.getString(this, Locale.PREF_SHOW_PLAY_PROGRESS), null); + cgPlayer.setSelectedIndex(1, showPlayProgress); + + // ИÑпользовать акÑелерометр + cgPlayer.append(Locale.getString(this, Locale.PREF_USE_ACCELEROMETER), null); + cgPlayer.setSelectedIndex(2, useAccelerometer); + + // *** Размер буфера плеера *** + tfModBufSize = new TextField(Locale.getString(this, Locale.PREF_MOD_BUF_SIZE), Integer.toString(modBufSize), 4, TextField.NUMERIC); + + // *** ЧаÑтота диÑкретизации модулей *** + cgModSampleRate = new ChoiceGroup(Locale.getString(this, Locale.PREF_MOD_SAMPLE_RATE), Choice.EXCLUSIVE); + + for(int i = 0; i < ModulePlayer.SAMPLE_RATES.length; i++) + { + cgModSampleRate.append(Integer.toString(ModulePlayer.SAMPLE_RATES[i]) + " " + Locale.getString(this, Locale.HZ), null); + } + + cgModSampleRate.setSelectedIndex(modSampleRate, true); + + // *** КачеÑтво модулей *** + cgModQuality = new ChoiceGroup(Locale.getString(this, Locale.PREF_MOD_QUALITY), Choice.EXCLUSIVE); + + cgModQuality.append(Locale.getString(this, Locale.QUALITY_LOW), null); + cgModQuality.append(Locale.getString(this, Locale.QUALITY_MEDIUM), null); + cgModQuality.append(Locale.getString(this, Locale.QUALITY_HIGH), null); + + cgModQuality.setSelectedIndex(modQuality, true); + + tfMetaDataFormat = new TextField(Locale.getString(this, Locale.METADATA_FORMAT), metaDataFormat, 256, TextField.ANY); + +// // *** Кодировка ID3 *** +// cgID3Enc = new ChoiceGroup(Locale.getString(this, Locale.PREF_ID3_ENCODING), Choice.EXCLUSIVE); +// +// cgID3Enc.append(StringEncoder.ENC_NAME_UTF8, null); +// +// for(int i = 0; i < StringEncoder.encnames.length; i++) +// { +// cgID3Enc.append(StringEncoder.encnames[i], null); +// } +// +// if(id3Enc == StringEncoder.ENC_UTF8) +// { +// cgID3Enc.setSelectedIndex(0, true); +// } +// else +// { +// cgID3Enc.setSelectedIndex(id3Enc + 1, true); +// } + + form.append(cgPlayer); + form.append(tfMetaDataFormat); + form.append(tfModBufSize); + form.append(cgModSampleRate); + form.append(cgModQuality); + //form.append(cgID3Enc); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 2)); + + form.setCommandListener(this); + + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable d) + { + if(c.getCommandType() == Command.OK) + { + showMetaKeys = cgPlayer.isSelected(0); + showPlayProgress = cgPlayer.isSelected(1); + useAccelerometer = cgPlayer.isSelected(2); + + modBufSize = Integer.parseInt(tfModBufSize.getString()); + modSampleRate = cgModSampleRate.getSelectedIndex(); + modQuality = cgModQuality.getSelectedIndex(); + + metaDataFormat = tfMetaDataFormat.getString(); + +// if(cgID3Enc.getSelectedIndex() == 0) +// { +// id3Enc = StringEncoder.ENC_UTF8; +// } +// else +// { +// id3Enc = cgID3Enc.getSelectedIndex() - 1; +// } + + saveOptions(); + } + + main.dsp.setCurrent(parent); + } + + public void restoreOptions() + { + String s = main.loader.getAppProperty("ID3-Encoding"); + + if(s != null) + { + id3Enc = StringEncoder.findEncoding(s); + } + + try + { + byte[] data = ModuleRegistry.getModuleData(getClass().getName()); + + if(data == null || data.length == 0) + { + return; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data)); + + if(dis.readInt() != OPTIONS_VERSION) + { + dis.close(); + return; + } + + volume = dis.readInt(); + muted = dis.readBoolean(); + modBufSize = dis.readInt(); + modSampleRate = dis.readInt(); + modQuality = dis.readInt(); + playerVisualMode = dis.readInt(); + playerVisualVariant = dis.readInt(); + useAccelerometer = dis.readBoolean(); + shufflePlay = dis.readBoolean(); + showPlayProgress = dis.readBoolean(); + /*id3Enc =*/ dis.readInt(); + metaDataFormat = dis.readUTF(); + showMetaKeys = dis.readBoolean(); + + int count = dis.readInt(); + + eqlevels.clear(); + + for(int i = 0; i < count; i++) + { + eqlevels.put(new Integer(dis.readInt()), new Integer(dis.readInt())); + } + + dis.close(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + + public void saveOptions() + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(OPTIONS_VERSION); + dos.writeInt(volume); + dos.writeBoolean(muted); + dos.writeInt(modBufSize); + dos.writeInt(modSampleRate); + dos.writeInt(modQuality); + dos.writeInt(playerVisualMode); + dos.writeInt(playerVisualVariant); + dos.writeBoolean(useAccelerometer); + dos.writeBoolean(shufflePlay); + dos.writeBoolean(showPlayProgress); + dos.writeInt(id3Enc); + dos.writeUTF(metaDataFormat); + dos.writeBoolean(showMetaKeys); + + dos.writeInt(eqlevels.size()); + + Enumeration levels = eqlevels.keys(); + Integer freq, level; + + while(levels.hasMoreElements()) + { + freq = (Integer)levels.nextElement(); + level = (Integer)eqlevels.get(freq); + + dos.writeInt(freq.intValue()); + dos.writeInt(level.intValue()); + } + + byte[] data = baos.toByteArray(); + dos.close(); + + ModuleRegistry.setModuleData(getClass().getName(), data); + } + catch(Exception e) + { + e.printStackTrace(); + } + } +} diff --git a/src/modules/audio/EqualizerForm.java b/src/modules/audio/EqualizerForm.java new file mode 100644 index 0000000..34d7d50 --- /dev/null +++ b/src/modules/audio/EqualizerForm.java @@ -0,0 +1,116 @@ +package modules.audio; + +import com.vmx.AuxClass; +import com.vmx.Locale; +import filemanager.main; +import javax.microedition.amms.GlobalManager; +import javax.microedition.amms.control.audioeffect.EqualizerControl; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; +import javax.microedition.lcdui.Gauge; +import javax.microedition.lcdui.Item; +import javax.microedition.lcdui.ItemStateListener; + +/** + * Эквалайзер. + */ +public class EqualizerForm extends Form implements CommandListener, ItemStateListener +{ + protected Object parent; + protected EqualizerControl equalizer; + protected Gauge[] bands; + protected Integer[] frequencies; + protected String[] labels; + protected int minlevel, maxlevel; + protected int maxgauge; + + public EqualizerForm(Object parent) throws ClassNotFoundException + { + super(""); + setTitle(Locale.getString(this, Locale.EQUALIZER)); + + this.parent = parent; + + if(!AuxClass.classExists("javax.microedition.amms.control.audioeffect.EqualizerControl")) + { + throw new ClassNotFoundException(); + } + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + setCommandListener(this); + setItemStateListener(this); + } + + public void init() + { + if(equalizer != null) + { + return; + } + + equalizer = (EqualizerControl)GlobalManager.getControl("javax.microedition.amms.control.audioeffect.EqualizerControl"); + + if(equalizer == null) + { + return; + } + + equalizer.setEnabled(true); + + minlevel = equalizer.getMinBandLevel(); + maxlevel = equalizer.getMaxBandLevel(); + + maxgauge = (maxlevel - minlevel) / 100; + + bands = new Gauge[equalizer.getNumberOfBands()]; + frequencies = new Integer[bands.length]; + labels = new String[bands.length]; + + Integer level; + + for(int i = 0; i < bands.length; i++) + { + frequencies[i] = new Integer(equalizer.getCenterFreq(i)); + level = (Integer)AudioOptions.eqlevels.get(frequencies[i]); + + if(level != null) + { + equalizer.setBandLevel(level.intValue(), i); + } + else + { + AudioOptions.eqlevels.put(frequencies[i], level = new Integer(equalizer.getBandLevel(i))); + } + + labels[i] = (frequencies[i].intValue() >= 1000000 ? (Integer.toString(frequencies[i].intValue() / 1000000) + ((frequencies[i].intValue() / 1000) % 1000 > 0 ? ("." + Integer.toString((frequencies[i].intValue() / 1000) % 1000)) : "") + " " + Locale.getString(this, Locale.KHZ)) : (Integer.toString(frequencies[i].intValue() / 1000) + " " + Locale.getString(this, Locale.HZ))) + ": "; + bands[i] = new Gauge(labels[i] + (level.intValue() >= 0 ? "+" : "") + Integer.toString(level.intValue() / 100) + " " + Locale.getString(this, Locale.DB), true, maxgauge, (level.intValue() - minlevel) * maxgauge / (maxlevel - minlevel)); + + append(bands[i]); + } + } + + public void itemStateChanged(Item item) + { + for(int i = 0; i < bands.length; i++) + { + if(item == bands[i]) + { + int level = minlevel + (maxlevel - minlevel) * bands[i].getValue() / maxgauge; + + bands[i].setLabel(labels[i] + (level >= 0 ? "+" : "") + Integer.toString(level / 100) + " " + Locale.getString(this, Locale.DB)); + equalizer.setBandLevel(level, i); + + AudioOptions.eqlevels.put(frequencies[i], new Integer(level)); + + break; + } + } + } + + public void commandAction(Command c, Displayable dp) + { + main.dsp.setCurrent(parent); + } +} \ No newline at end of file diff --git a/src/modules/audio/TrackerModule.java b/src/modules/audio/TrackerModule.java new file mode 100644 index 0000000..c8a5317 --- /dev/null +++ b/src/modules/audio/TrackerModule.java @@ -0,0 +1,19 @@ +package modules.audio; + +import com.one.Application; +import com.one.PlayList; + +public class TrackerModule implements Application +{ + public void openFile(String filename, PlayList filelist) + { + cvsPlayer player = cvsPlayer.getInstance(); + + if(filelist != null) + { + player.setPlayList(filelist); + } + + player.playSoundModule(filename); + } +} diff --git a/src/modules/audio/VisualEffects.java b/src/modules/audio/VisualEffects.java new file mode 100644 index 0000000..1fc1c6c --- /dev/null +++ b/src/modules/audio/VisualEffects.java @@ -0,0 +1,308 @@ +package modules.audio; + +import com.one.SlidingNumber; +import com.one.VolumeUnit; +import com.one.vector.AuxMath; +import filemanager.images; +import java.util.Random; +import javax.microedition.lcdui.Graphics; + +/** + * Стрелочный индикатор + */ +class AnalogIndicator +{ + protected VolumeUnit vu; + + protected int width, height; + protected int orgx, orgy, radius, baseangle; + + public AnalogIndicator(int width, int height, int viswidth, int visheight, int radius) + { + this.width = width; + this.height = height; + + orgx = width / 2; + orgy = height - visheight + radius; + + this.radius = radius; + + double la = Math.toDegrees(AuxMath.atan2(radius, -viswidth / 2)); + double ra = Math.toDegrees(AuxMath.atan2(radius, viswidth / 2)); + + baseangle = (int)la; + vu = new VolumeUnit(0, baseangle - (int)ra, 8, 35, 2, 3); + } + + public void setTarget(int value) + { + vu.setTarget(value); + } + + public void setValue(int value) + { + vu.setValue(value); + } + + public void paint(Graphics g, int x, int y, boolean update) + { + g.translate(x, y); + g.setClip(0, 0, width, height); + + double angle = Math.toRadians((double)(baseangle - vu.nextValue(update))); + + double angsin = Math.sin(angle); + double angcos = Math.cos(angle); + + int x1 = orgx + (int)(radius * 88 / 100 * angcos); + int y1 = orgy - (int)(radius * 88 / 100 * angsin); + + int x2 = orgx + (int)(radius * angcos); + int y2 = orgy - (int)(radius * angsin); + + g.setColor(images.cVisArrowLine); + g.drawLine(orgx, orgy, x1, y1); + + g.setColor(images.cVisArrowCap); + + if(x2 < x1) // Ñтрелка наклонена влево + { + g.setClip(x2, y2, x1 - x2 + 1, y1 - y2 + 1); + } + else if(x2 > x1) // Ñтрелка наклонена вправо + { + g.setClip(x1, y2, x2 - x1 + 1, y1 - y2 + 1); + } + else // Ñтрелка Ñтоит вертикально + { + g.setClip(x2, y2, 1, y1 - y2 + 1); + } + + g.drawLine(orgx, orgy, x2, y2); + + g.translate(-x, -y); + } +} + +/** + * Визуалка aNNiMON'а + */ +class VisualEffect +{ + protected static Random rnd = new Random(); + + protected SlidingNumber slidingInnerR, slidingInnerG, slidingInnerB; + protected SlidingNumber slidingOuterR, slidingOuterG, slidingOuterB; + + protected int colorVariant; + protected int chains, links; + protected float[] data; + + protected int innerR, innerG, innerB; + protected int outerR, outerG, outerB; + + public VisualEffect(int chains, int links) + { + this.chains = chains; + this.links = links; + + data = new float[links]; + + colorVariant = 1; + + slidingInnerR = new SlidingNumber(18, 253, 64, 768); + slidingInnerG = new SlidingNumber(18, 253, 64, 768); + slidingInnerB = new SlidingNumber(18, 253, 64, 768); + + slidingOuterR = new SlidingNumber(18, 253, 64, 768); + slidingOuterG = new SlidingNumber(18, 253, 64, 768); + slidingOuterB = new SlidingNumber(18, 253, 64, 768); + + innerR = slidingInnerR.nextValue(); + innerG = slidingInnerG.nextValue(); + innerB = slidingInnerB.nextValue(); + + outerR = slidingOuterR.nextValue(); + outerG = slidingOuterG.nextValue(); + outerB = slidingOuterB.nextValue(); + } + + public void nextColor() + { + if(++colorVariant > 14) + { + colorVariant = 1; + } + } + + public void prevColor() + { + if(--colorVariant < 1) + { + colorVariant = 14; + } + } + + public void randomColor() + { + colorVariant = 1 + (rnd.nextInt() & 0x7FFFFFFF) % 14; + } + + public void drawVisual(Graphics g, int px, int py, int width, int height, boolean update) + { + float len, d, k, alpha1, alphaI; + float x1, y1, x2, y2; + + if(width > height) + { + len = height / links; + } + else + { + len = width / links; + } + + d = (float)(Math.PI * 2 / chains); + + if(update) + { + if(Math.abs(rnd.nextFloat()) * 50 < 5) + { + k = (float)(Math.abs(rnd.nextFloat() * 1440) * Math.PI / 180); + } + else + { + k = (float)(Math.abs(rnd.nextFloat() * 360) * Math.PI / 180); + } + + data[0] = (float)(data[0] + Math.sin(k) / (float)((Math.abs(rnd.nextInt()) % 9) + 1)); + + innerR = slidingInnerR.nextValue(); + innerG = slidingInnerG.nextValue(); + innerB = slidingInnerB.nextValue(); + + outerR = slidingOuterR.nextValue(); + outerG = slidingOuterG.nextValue(); + outerB = slidingOuterB.nextValue(); + } + + for(int i = 1; i < links; i++) + { + data[i] = (float)(data[i] + (data[i - 1] - data[i]) * 0.1); + } + + for(int j = 0; j < chains; j++) + { + x1 = (float)(0.5 * width); + y1 = (float)(0.5 * height); + + x2 = x1; + y2 = y1; + + for(int i = 1; i < links; i++) + { + alpha1 = j * d + data[1]; + alphaI = j * d + data[i]; + + if(AudioOptions.playerVisualVariant == 1) + { + x2 = (float)(x1 + Math.cos(alpha1) * len); + y2 = (float)(y1 + Math.sin(alphaI) * len); + x1 = x1 + (float)(Math.cos(alphaI) * len); + } + else if(AudioOptions.playerVisualVariant == 2) + { + x2 = (float)(x1 + Math.sin(alphaI) * len); + y2 = (float)(y1 + Math.cos(alphaI) * len); + } + else if(AudioOptions.playerVisualVariant == 3) + { + x2 = (float)(x1 + Math.tan(alpha1) * len); + y2 = (float)(y1 + Math.cos(alphaI) * len); + y1 = y1 - (float)(Math.sin(alphaI) * len); + } + else if(AudioOptions.playerVisualVariant == 4) + { + x2 = (float)(x1 + Math.tan(alpha1) * len); + y2 = (float)(y1 + Math.cos(alphaI) * len); + x1 = y1 - (float)(Math.sin(alphaI) * len); + } + else if(AudioOptions.playerVisualVariant == 5) + { + x2 = (float)(x1 + Math.tan(alpha1) * len); + y2 = (float)(y1 + Math.cos(alphaI) * len); + x1 = (float)(x1 * y2 * d + data[i] - (float)(Math.sin(alphaI) * len)); + } + else if(AudioOptions.playerVisualVariant == 6) + { + x2 = (float)(x1 + Math.cos(alpha1) * len); + y2 = (float)(y1 + Math.sin(alpha1) * len); + x1 = x1 + (float)(Math.sin(alphaI) * len); + y1 = y1 + (float)(Math.cos(alphaI) * len); + } + + if(colorVariant == 1) + { + g.setColor(innerR * (links - i) / links + outerR * i / links, innerG * (links - i) / links + outerG * i / links, innerB * (links - i) / links + outerB * i / links); + } + else if(colorVariant == 2) + { + g.setColor(255, 255 - 255 * i / links, 0); + } + else if(colorVariant == 3) + { + g.setColor(innerR, 255 - 255 * i / links, 255); + } + else if(colorVariant == 4) + { + g.setColor(255 - 255 * i / links, 255, 0); + } + else if(colorVariant == 5) + { + g.setColor(255 - 255 * i / links, 255 - 255 * i / links, 255); + } + else if(colorVariant == 6) + { + g.setColor(255 - 255 * i / links, 255, 255); + } + else if(colorVariant == 7) + { + g.setColor(0, 255, 255 - 255 * i / links); + } + else if(colorVariant == 8) + { + g.setColor(255, innerG, 255 - 255 * i / links); + } + else if(colorVariant == 9) + { + g.setColor(255, 255 - 255 * i / links, 255 - 255 * i / links); + } + else if(colorVariant == 10) + { + g.setColor(innerR, 255 - 255 * i / links, 0); + } + else if(colorVariant == 11) + { + g.setColor(255, 255 - 255 * i / links, 255); + } + else if(colorVariant == 12) + { + g.setColor(255 - 255 * i / links, 0, 255); + } + else if(colorVariant == 13) + { + g.setColor(255 - 255 * i / links, 255 * i / links, 0); + } + else if(colorVariant == 14) + { + g.setColor(innerB, 255, 255 - 255 * i / links); + } + + g.drawLine(px + (int)x1, py + (int)y1, px + (int)x2, py + (int)y2); + + x1 = x2; + y1 = y2; + } + } + } +} \ No newline at end of file diff --git a/src/modules/audio/cvsPlayer.java b/src/modules/audio/cvsPlayer.java new file mode 100644 index 0000000..41f2fa2 --- /dev/null +++ b/src/modules/audio/cvsPlayer.java @@ -0,0 +1,1258 @@ +package modules.audio; // переведен + +import javax.microedition.lcdui.*; +import javax.microedition.lcdui.game.*; +import javax.microedition.media.*; +import javax.microedition.media.control.*; +import com.vmx.*; +import java.io.*; +import com.one.file.*; +import com.one.*; +import filemanager.filesystem; +import modules.id3Editor; +import filemanager.images; +import filemanager.main; +import filemanager.options; +import java.util.*; + +/** + * Проигрыватель звуковых файлов + */ +public class cvsPlayer extends gkcCanvas implements PlayerListener, Runnable +{ + public static final String SHUFFLE_PLAY_MARK = "±"; // "°"; + + private static Player player; + private VolumeControl vc; + private InputStream is; + private boolean running, paused; + private Thread t = null; + private int w, h, w2, h2; + private int pbx, pby, pbw, pbh; // прогреÑÑ + private String currentFile, OnlyFileName; // tagstr = null; + private String[] tagstr; + private int[][] tagstrpos; + private int tagstrh; + private Font infoFont; + private int pax, pay; // Ð°Ð½Ð¸Ð¼Ð°Ñ†Ð¸Ñ + private long duration, time, tstep; + private boolean rtcFlag = false; + private boolean keyFlag = false; + private boolean wasPaused = false; + private int ofnw, ofnx, ofnstep, ofndelay; // прокрутка Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ + private static final int OFN_DEF_DELAY = 1; + private EqualizerForm eqform; + private VisualEffect visualfx; + private AnalogIndicator lai, rai; + private VolumeUnit lvu, rvu; + private VolumeUnit[] avu; + private int vux, lvuy, rvuy, avuy, avuw; + private int[] avux; + private int vutarget = 0; + private PlayList playlist; + + private int runpanel; // номер панели, в которой был запущен плеер + + private static cvsPlayer instance; + + public static void loadInstance() + { + if(instance == null) + { + instance = new cvsPlayer(); + } + } + + public static cvsPlayer getInstance() + { + loadInstance(); + return instance; + } + + public cvsPlayer() + { + setFullScreenMode(true); + + w = getWidth(); + h = getHeight(); + + w2 = w / 2; + h2 = h / 2; + + infoFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL); + + pax = (w - images.playAnimWidth) / 2; + pay = (h - images.playAnimHeight) / 2; + + pbw = images.playAnimWidth * 3 / 4; + pbh = infoFont.getHeight() * 3 / 4; + pbx = (w - pbw) / 2; + //pby = h - h / 4 - pbh; + //pby = pay + images.playAnimHeight / 4 + 2; + pby = (pay + images.playAnimHeight) + (h - images.uiBottomHeight - (pay + images.playAnimHeight) - pbh) / 2; + + lai = new AnalogIndicator(images.playAnimWidth / 2, images.playAnimHeight, images.playAnimWidth * 2 / 5, images.playAnimHeight * 4 / 5, images.playAnimHeight * 5 / 3); + rai = new AnalogIndicator(images.playAnimWidth / 2, images.playAnimHeight, images.playAnimWidth * 2 / 5, images.playAnimHeight * 4 / 5, images.playAnimHeight * 5 / 3); + + lvu = new VolumeUnit(1, pbw, 8, 35, 2, 3); + rvu = new VolumeUnit(1, pbw, 8, 35, 2, 3); + + int vspace = (images.playAnimHeight - pbh * 2 + 2) / 3; + + vux = pbx; + lvuy = pay + vspace; + rvuy = pay + images.playAnimHeight - pbh - vspace; + + avu = new VolumeUnit[12]; + avux = new int[avu.length]; + + avuw = (pbw + avu.length) / (avu.length * 2 - 1); + + int base = pax + (images.playAnimWidth - avuw * (avu.length * 2 - 1)) / 2; + + for(int i = 0; i < avu.length; i++) + { + avu[i] = new VolumeUnit(1, pbh * 2 + vspace, 8, 35, 2, 3); + avux[i] = base + avuw * i * 2; + } + + avuy = pay + images.playAnimHeight - vspace; + + playlist = null; + runpanel = -1; + + try + { + eqform = new EqualizerForm(this); + } + catch(Throwable t) + { + eqform = null; + } + + visualfx = new VisualEffect(12, 15); + } + + public void setPlayList(PlayList newlist) + { + playlist = newlist; + } + + public void setPlayList(Enumeration newlist) + { + playlist = new PlayList(newlist); + } + + protected void initScroll() + { + // только Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐºÑ€ÑƒÑ‚ÐºÐ¸ + OnlyFileName = currentFile.substring(currentFile.lastIndexOf('/') + 1); + + /* + if(AudioOptions.shufflePlay) + { + OnlyFileName += SHUFFLE_PLAY_MARK; + } + */ + + ofnw = infoFont.stringWidth(OnlyFileName); + ofnx = images.uiTopHSpace; + ofndelay = OFN_DEF_DELAY; + + if(ofnw > w - images.uiTopHSpace * 2) + { + ofnstep = -(ofnw / OnlyFileName.length()); + } + else + { + ofnstep = 0; + } + } + + protected void initTag() + { + if(player instanceof ModulePlayer) + { + tagstr = new String[1]; + tagstr[0] = ((ModulePlayer)player).getSongTitle().trim(); + } + else + { + MetaDataControl mdc = (MetaDataControl)player.getControl("MetaDataControl"); + + if(mdc != null) + { + String[] keys; + + if(AudioOptions.metaDataFormat.length() > 0) + { + keys = TextProcessor.vectorToStringArray(StringPattern.tokenizeString(AudioOptions.metaDataFormat, ',')); + } + else + { + keys = mdc.getKeys(); + } + + Vector values = new Vector(); + String value; + + for(int i = 0; i < keys.length; i++) + { + value = mdc.getKeyValue(keys[i].trim()); + + if(value != null) + { + value = value.trim(); + + if(value.length() > 0) + { + if(AudioOptions.showMetaKeys) + { + values.addElement(formatTagKey(keys[i]) + ": " + transcodeTagString(value)); + } + else + { + values.addElement(transcodeTagString(value)); + } + } + } + } + + tagstr = TextProcessor.vectorToStringArray(values); + } + else + { + tagstr = new String[0]; + } + } + + tagstrh = tagstr.length * infoFont.getHeight(); + + tagstrpos = new int[tagstr.length][2]; + + for(int i = 0; i < tagstr.length; i++) + { + tagstrpos[i][0] = (w - infoFont.stringWidth(tagstr[i])) / 2; + + if(tagstrpos[i][0] < 0) + { + tagstrpos[i][0] = 0; + } + + tagstrpos[i][1] = images.uiTopHeight + (pay - images.uiTopHeight - tagstrh) / 2 + i * infoFont.getHeight(); + } + } + + protected static String transcodeTagString(String text) + { + text = text.trim(); + + byte[] data = StringEncoder.encodeString(text, AudioOptions.id3Enc); + String res = StringEncoder.decodeString(data, 0, data.length, StringEncoder.ENC_DEFAULT); + + // Проверка: а Ñтоило ли перекодировать-то вообще? + + if(res.length() != text.length()) + { + return text; + } + + // Ищем некодируемые Ñимволы + + char[] ocs = text.toCharArray(); + char[] rcs = res.toCharArray(); + + int count = 0; + + for(int i = 0; i < rcs.length; i++) + { + if(rcs[i] == StringEncoder.EMPTY_CHAR && + ocs[i] != StringEncoder.EMPTY_CHAR) + { + count++; + } + } + + if(count > 0) // rcs.length / 4) + { + return text; + } + else + { + return res; + } + } + + protected static String formatTagKey(String key) + { + return key.substring(0, 1).toUpperCase() + key.substring(1).toLowerCase(); + } + + protected void initDuration() + { + duration = player.getDuration(); + tstep = duration / 100; + } + + protected void initPanels() + { + if(runpanel < 0) + { + runpanel = main.manager.currentPanel(); + } + + main.manager.setCurrent(this, runpanel); + main.manager.updateAssociation(runpanel, playlist.getCurrentElement()); + } + + protected void initPlayList(String file) + { + currentFile = file; + + if(playlist == null) + { + playlist = new PlayList(file); + } + + playlist.selectElement(file); + } + + public void playSound(String soundFile) + { + destroyPlayer(); + + initPanels(); + + player = null; + running = true; + rtcFlag = false; + + initPlayList(soundFile); + + initScroll(); + + try + { + player = Manager.createPlayer("file:///" + soundFile); + player.realize(); + player.prefetch(); + + player.addPlayerListener(this); + player.setLoopCount(1); + + initDuration(); + + vc = (VolumeControl)player.getControl("VolumeControl"); + vc.setLevel(AudioOptions.volume); + vc.setMute(AudioOptions.muted); + + if(eqform != null) + { + eqform.init(); + } + + initTag(); + } + catch(Exception e) + { + try + { + playSoundFromStream(Connector.openInputStream("file:///" + soundFile), soundFile.substring(soundFile.lastIndexOf('/') + 1)); + return; + } + catch(IOException ioe) + { + ErrScreen.showErrMsg(11, ioe); + } + } + + if(t == null) + { + t = new Thread(this, "Player/Update"); + t.start(); + } + } + + public void playSoundFromStream(InputStream is, String soundFile) + { + destroyPlayer(); + + initPanels(); + + player = null; + running = true; + rtcFlag = false; + + initPlayList(soundFile); + + initScroll(); + + try + { + this.is = is; + + try + { + player = Manager.createPlayer(is, filesystem.mimeType(soundFile)); + player.realize(); + player.prefetch(); + } + catch(Exception stupidEmulatorException) + { + player = Manager.createPlayer(is, "audio/mpeg"); + player.realize(); + player.prefetch(); + } + + player.addPlayerListener(this); + player.setLoopCount(1); + + initDuration(); + + vc =(VolumeControl)player.getControl("VolumeControl"); + vc.setLevel(AudioOptions.volume); + vc.setMute(AudioOptions.muted); + + if(eqform != null) + { + eqform.init(); + } + + initTag(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(12, e); + } + + if(t == null) + { + t = new Thread(this, "Player/Update"); + t.start(); + } + } + + public void playSoundModule(String soundFile) + { + try + { + playSoundModuleFromStream(Connector.openInputStream("file:///" + soundFile), soundFile); + } + catch(IOException ioe) + { + ErrScreen.showErrMsg(13, ioe); + } + } + + public void playSoundModuleFromStream(InputStream is, String soundFile) + { + destroyPlayer(); + + initPanels(); + + player = null; + running = true; + rtcFlag = false; + + initPlayList(soundFile); + + initScroll(); + + try + { + this.is = is; + + player = new ModulePlayer(is, AudioOptions.modSampleRate, AudioOptions.modQuality, AudioOptions.modBufSize); + + player.realize(); + player.prefetch(); + + player.addPlayerListener(this); + player.setLoopCount(1); + + initDuration(); + + vc = null; + + ((ModulePlayer)player).setVolumeLevel(AudioOptions.volume); + ((ModulePlayer)player).setVolumeMute(AudioOptions.muted); + + if(eqform != null) + { + eqform.init(); + } + + initTag(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(12, e); + } + + if(t == null) + { + t = new Thread(this, "Player/Update"); + t.start(); + } + } + + public void paint(Graphics g) + { + g.setClip(0, 0, w, h); + + // БÑкграунд + if(images.playerUI != null) + { + g.drawImage(images.playerUI, 0, 0, Graphics.LEFT | Graphics.TOP); + } + else + { + g.setColor(images.cImgBack); + g.fillRect(0, 0, w, h); + } + + if(images.buttons != null) + { + // Кнопка PLAY + g.drawRegion(images.buttons, 0, 0, images.btnWidth, images.btnHeight, Sprite.TRANS_NONE, images.uiBottomHOffset, h - images.uiBottomHeight + images.uiBottomVOffset, Graphics.LEFT | Graphics.TOP); + + // Кнопка STOP + g.drawRegion(images.buttons, images.btnWidth * 2, 0, images.btnWidth, images.btnHeight, Sprite.TRANS_NONE, w - images.btnWidth - images.uiBottomHOffset, h - images.uiBottomHeight + images.uiBottomVOffset, Graphics.LEFT | Graphics.TOP); + } + + g.setColor(images.cPlayFore2); + //g.setColor(images.playerUI != null ? images.cPlayFore2 : Colors.colors[Colors.fore]); + + int y = h - images.uiBottomHeight / 2; + //int trans = AudioOptions.shufflePlay ? Sprite.TRANS_MIRROR_ROT90 : Sprite.TRANS_NONE; + + if(AudioOptions.volume == 0) // вывод значка громкоÑти + { + images.drawIcon(g, images.iMute, w2 - images.iconWidth, y - images.iconHeight / 2); + //g.drawRegion(images.getIcon(images.iMute), 0, 0, images.iconWidth, images.iconHeight, trans, w2 - images.iconWidth, y - images.iconHeight / 2, Graphics.LEFT | Graphics.TOP); + g.fillRect(w2 + 4, y + 4, 10, 1); + } + else + { + if(!AudioOptions.muted) + { + images.drawIcon(g, images.iNoMute, w2 - images.iconWidth, y - images.iconHeight / 2); + //g.drawRegion(images.getIcon(images.iNoMute), 0, 0, images.iconWidth, images.iconHeight, trans, w2 - images.iconWidth, y - images.iconHeight / 2, Graphics.LEFT | Graphics.TOP); + } + else + { + images.drawIcon(g, images.iMute, w2 - images.iconWidth, y - images.iconHeight / 2); + //g.drawRegion(images.getIcon(images.iMute), 0, 0, images.iconWidth, images.iconHeight, trans, w2 - images.iconWidth, y - images.iconHeight / 2, Graphics.LEFT | Graphics.TOP); + } + + for(int i = 0; i < AudioOptions.volume; i += 25) + { + g.fillRect(w2 + 4, y + 3 - (i / 25) * 3, 10, 2); + } + } + + g.setFont(infoFont); + + if(AudioOptions.playerVisualMode != 0) + { + if(AudioOptions.playerVisualMode == 2) + { + g.setColor(images.cImgBack); + g.fillRect(0, images.uiTopHeight, w, h - images.uiTopHeight - images.uiBottomHeight); + } + + g.setClip(0, images.uiTopHeight, w, h - images.uiTopHeight - images.uiBottomHeight); + visualfx.drawVisual(g, 0, images.uiTopHeight, w, h - images.uiTopHeight - images.uiBottomHeight, !paused); + g.setClip(0, 0, w, h); + } + else + { + images.drawVGradient(g, images.cVisBack1, images.cVisBack2, pax, pay, images.playAnimWidth, images.playAnimHeight, options.ditherGradients, options.alphaGradients); + + if(AudioOptions.playerVisualVariant == 1) + { + lai.paint(g, pax, pay, !paused); + rai.paint(g, pax + images.playAnimWidth / 2, pay, !paused); + } + else if(AudioOptions.playerVisualVariant == 2) + { + g.setColor(images.cVisArrowCap); + + images.fillVLineRect(g, vux, lvuy, lvu.nextValue(!paused), pbh); + images.fillVLineRect(g, vux, rvuy, rvu.nextValue(!paused), pbh); + } + else if(AudioOptions.playerVisualVariant == 3) + { + g.setColor(images.cVisArrowCap); + + for(int i = 0; i < avu.length; i++) + { + images.fillHLineRect(g, avux[i], avuy, avuw, avu[i].nextValue(!paused)); + } + } + + g.setClip(0, 0, w, h); + g.setColor(images.cImgBack); + g.drawRect(pax, pay, images.playAnimWidth - 1, images.playAnimHeight - 1); + +// if(images.playAnim != null) +// { +// g.drawRegion(images.playAnim, 0, animFrame * images.playAnimHeight, images.playAnimWidth, images.playAnimHeight, Sprite.TRANS_NONE, pax, pay, Graphics.LEFT | Graphics.TOP); +// } + } + + g.setColor(images.cPlayFore1); + //g.setColor(images.playerUI != null ? images.cPlayFore1 : Colors.colors[Colors.fore]); + + if(AudioOptions.shufflePlay) + { + g.drawString(SHUFFLE_PLAY_MARK, w - 1, images.uiTopHeight, Graphics.RIGHT | Graphics.TOP); + } + + if(tagstr != null) + { + for(int i = 0; i < tagstr.length; i++) + { + g.drawString(tagstr[i], tagstrpos[i][0], tagstrpos[i][1], Graphics.LEFT | Graphics.TOP); + } + } + + if(player != null) + { + if(!keyFlag) + { + time = player.getMediaTime(); + + if(time > duration) + { + time = duration; + } + } + + if(duration > 0 && time >= 0 && AudioOptions.showPlayProgress) + { + g.drawRect(pbx, pby, pbw, pbh); + g.fillRect(pbx + 2, pby + 2, (int)((pbw - 3) * time / duration), pbh - 3); + } + else + { + g.drawString(AuxClass.mediaTimeToString(time), w2, pby, Graphics.TOP | Graphics.HCENTER); + } + } + else if(rtcFlag) + { + g.drawString(AuxClass.getCurrentTime(), w2, pby, Graphics.TOP | Graphics.HCENTER); + } + + if(!paused && images.buttons != null) + { + g.drawRegion(images.buttons, images.btnWidth, 0, images.btnWidth, images.btnHeight, Sprite.TRANS_NONE, images.uiBottomHOffset, h - images.uiBottomHeight + images.uiBottomVOffset, Graphics.LEFT | Graphics.TOP); + } + + g.setColor(images.cPlayTitle); + g.setClip(images.uiTopHSpace, images.uiTopVSpace, w - images.uiTopHSpace * 2, images.uiTopHeight - images.uiTopVSpace); + + if(OnlyFileName != null) + { + g.drawString(OnlyFileName, ofnx, images.uiTopVSpace, Graphics.LEFT | Graphics.TOP); + } + } + + public void playerUpdate(Player player, String event, Object data) + { + if(event.equals(PlayerListener.END_OF_MEDIA)) + { + nextSound(); + } + } + + public void run() + { + randomVisual(); + + if(wasPaused) + { + paused = true; + } + else + { + playerStart(); + } + + long prevtime = System.currentTimeMillis(); + + while(running) // цикл + { + if(System.currentTimeMillis() - prevtime > 300) + { + prevtime = System.currentTimeMillis(); + + if(ofndelay > 0) + { + ofndelay--; + } + else + { + ofnx += ofnstep; + } + + if(ofnstep > 0) + { + if(ofnx > images.uiTopHSpace) + { + ofnx = images.uiTopHSpace; + ofnstep = -ofnstep; + ofndelay = OFN_DEF_DELAY; + } + } + else if(ofnstep < 0) + { + if(ofnx < w - images.uiTopHSpace - ofnw) + { + ofnx = w - images.uiTopHSpace - ofnw; + ofnstep = -ofnstep; + ofndelay = OFN_DEF_DELAY; + } + } + + if(AudioOptions.useAccelerometer) + { + final int delta = main.accelerometer.getDelta(0, 1200); + + if(delta != 0) + { + Runnable runnable = new Runnable() + { + public void run() + { + if(delta > 0) + { + nextSound(); + } + else if(delta < 0) + { + prevSound(); + } + } + }; + + (new Thread(runnable, "Player/AccelEvent")).start(); + } + } + } + + repaint(); + //serviceRepaints(); + + try + { + Thread.sleep(60); + } + catch(InterruptedException ie) + { + } + } + } + + /** + * Обработчик Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ ÐºÐ½Ð¾Ð¿Ð¾Ðº + * + * @param key int + * @todo Implement this javax.microedition.lcdui.Canvas method + */ + public void keyPressed(int key) + { + if(key == KEY_RSK) // Ð¿Ñ€Ð°Ð²Ð°Ñ Ñофт - выход + { + destroyPlayer(); + wasPaused = false; + + // Возврат + //main.manager.setCurrent(main.FileSelect, runpanel); + main.manager.ret(); + + playlist.cancelSearch(); + playlist = null; + + runpanel = -1; + } + else if(key == KEY_CANCEL) // назад или краÑÐ½Ð°Ñ - ÑворачиваемÑÑ + { + main.manager.minimizePanel(); + } + else if(player != null) + { + if(key == KEY_LSK || key == KEY_FIRE || key == KEY_NUM5) // Ð»ÐµÐ²Ð°Ñ Ñофт или Ð·ÐµÐ»ÐµÐ½Ð°Ñ - пауза\воÑпроизв. + { + if(player.getState() == Player.STARTED) + { + playerPause(); + wasPaused = true; + } + else if(player.getState() == Player.PREFETCHED) + { + playerStart(); + wasPaused = false; + } + } + else if(key == KEY_UP || key == KEY_NUM2) // Volume up + { + if(!AudioOptions.muted) + { + AudioOptions.volume += 5; + + if(AudioOptions.volume > 100) + { + AudioOptions.volume = 100; + } + + if(vc != null) + { + vc.setLevel(AudioOptions.volume); + } + else if(player instanceof ModulePlayer) + { + ((ModulePlayer)player).setVolumeLevel(AudioOptions.volume); + } + } + } + else if(key == KEY_DOWN || key == KEY_NUM8) // Volume down + { + if(!AudioOptions.muted) + { + AudioOptions.volume -= 5; + + if(AudioOptions.volume < 0) + { + AudioOptions.volume = 0; + } + + if(vc != null) + { + vc.setLevel(AudioOptions.volume); + } + else if(player instanceof ModulePlayer) + { + ((ModulePlayer)player).setVolumeLevel(AudioOptions.volume); + } + } + } + else if(key == KEY_DIAL) // Volume mute + { + AudioOptions.muted = !AudioOptions.muted; + + if(vc != null) + { + vc.setMute(AudioOptions.muted); + } + else if(player instanceof ModulePlayer) + { + ((ModulePlayer)player).setVolumeMute(AudioOptions.muted); + } + } + else if(key == KEY_POUND) // Volume mute + { + if(++AudioOptions.playerVisualMode > 2) + { + AudioOptions.playerVisualMode = 0; + } + + randomVisual(); + } + else if(key == KEY_STAR) + { + AudioOptions.shufflePlay = !AudioOptions.shufflePlay; + } + else if(key == KEY_NUM0) + { + if(eqform != null) + { + main.dsp.setCurrent(eqform); + } + } + else if(key == KEY_NUM1) + { + prevVisual(); + } + else if(key == KEY_NUM3) + { + nextVisual(); + } + else if(key == KEY_NUM7) + { + if(AudioOptions.playerVisualMode == 0) + { + if(paused) + { + visualSetTarget(vutarget - 1); + } + } + else + { + visualfx.prevColor(); + } + } + else if(key == KEY_NUM9) + { + if(AudioOptions.playerVisualMode == 0) + { + if(paused) + { + visualSetTarget(vutarget + 1); + } + } + else + { + visualfx.nextColor(); + } + } + } + } + + public void keyReleased(int key) + { + if(keyFlag) + { + try + { + player.setMediaTime(time); + } + catch(MediaException me) + { + } + + if(!wasPaused) + { + playerStart(); + } + + keyFlag = false; + } + else + { + if((key == KEY_RIGHT) || (key == KEY_NUM6)) // Ñледующий звук + { + nextSound(); + } + else if((key == KEY_LEFT) || (key == KEY_NUM4)) // предыдущий звук + { + prevSound(); + } + } + } + + public void keyRepeated(int key) + { + if((key == KEY_RIGHT) || (key == KEY_NUM6)) // перемотка вперед + { + if(!keyFlag) + { + if(!wasPaused) + { + playerPause(); + } + + keyFlag = true; + } + + time += tstep; + + if(time > duration) + { + time = duration; + } + } + else if((key == KEY_LEFT) || (key == KEY_NUM4)) // перемотка назад + { + if(!keyFlag) + { + playerPause(); + keyFlag = true; + } + + time -= tstep; + + if(time < 0) + { + time = 0; + } + } + else + { + keyPressed(key); + } + } + + private void destroyPlayer() + { + visualSetValue(0); + + OnlyFileName = Locale.getString(this, Locale.WAIT_PLEASE); + ofnw = 0; + ofnx = images.uiTopHSpace; + ofnstep = 0; + + tagstr = null; + + time = 0; + + running = false; + + if(t != null) + { + if(t.isAlive()) + { + try + { + t.join(); + } + catch(InterruptedException ie) + { + } + } + + t = null; + } + + if(player != null) + { + try + { + player.stop(); + player.close(); + } + catch(Exception e) + { + //System.out.println ("Cannot stop and exit player"); + //e.printStackTrace (); + } + + player = null; + } + + if(is != null) + { + try + { + is.close(); + } + catch(Exception e) + { + } + + is = null; + } + + main.startLightControl(false); + } + + /** + * ОÑтанов плеера + */ + /* + private void playerStop() + { + if(player == null) + { + return; + } + + try + { + paused = false; + player.stop(); + player.setMediaTime(0); + repaint(); + } + catch(Exception e) + { + //System.out.println ("Cannot stop player"); + //e.printStackTrace (); + } + } + */ + + /** + * Пауза плеера + */ + private void playerPause() + { + if(player == null) + { + return; + } + + try + { + player.stop(); + + if(player.getState() == Player.PREFETCHED) + { + paused = true; + + visualSetTarget(0); + + repaint(); + } + } + catch(Exception e) + { + //System.out.println ("Cannot pause player"); + //e.printStackTrace (); + } + + main.startLightControl(false); + } + + /** + * ЗапуÑк плеера + */ + private void playerStart() + { + if(player == null) + { + return; + } + + try + { + player.start(); + + if(player.getState() == Player.STARTED) + { + paused = false; + repaint(); + + main.startLightControl(player instanceof ModulePlayer); + } + } + catch(Exception e) + { + ErrScreen.showErrMsg(15, e); + } + } + + /** + * Скроллинг текÑта TEXT (кол-во Ñимволов COUNT) + * + * @param text String + * @param count int + * @return String + */ + /* + private String scrollText(String text, int count) + { + + String tmp = text; + int len = text.length(); + int scr = len - count; + + if(len > count) + { + tmp = text.substring(scrollPos, scrollPos + count); + + if(scrolldirection) + { + scrollPos--; + } + else + { + scrollPos++; + } + + if(scrollPos > scr) + { + scrollPos--; + scrolldirection = !scrolldirection; + } + else if(scrollPos < 0) + { + scrollPos = 0; + scrolldirection = !scrolldirection; + } + } + + return tmp; + } + */ + + /** + * Ñледующий звук + */ + public void nextSound() + { + destroyPlayer(); + + playlist.nextElement(AudioOptions.shufflePlay && !paused); + main.FileSelect.executeFile(playlist, null, runpanel); + } + + /** + * предыдущий звук + */ + public void prevSound() + { + destroyPlayer(); + + playlist.prevElement(AudioOptions.shufflePlay && !paused); + main.FileSelect.executeFile(playlist, null, runpanel); + } + + public void nextVisual() + { + if(++AudioOptions.playerVisualVariant > (AudioOptions.playerVisualMode == 0 ? 3 : 6)) + { + AudioOptions.playerVisualVariant = 1; + } + } + + public void prevVisual() + { + if(--AudioOptions.playerVisualVariant < 1) + { + AudioOptions.playerVisualVariant = (AudioOptions.playerVisualMode == 0 ? 3 : 6); + } + } + + public void randomVisual() + { + AudioOptions.playerVisualVariant = AuxClass.randomFromRange(1, (AudioOptions.playerVisualMode == 0 ? 3 : 6)); + } + + private void visualSetTarget(int value) + { + vutarget = value; + + lai.setTarget(value); + rai.setTarget(value); + + lvu.setTarget(value); + rvu.setTarget(value); + + for(int i = 0; i < avu.length; i++) + { + avu[i].setTarget(value); + } + } + + private void visualSetValue(int value) + { + vutarget = value; + + lai.setValue(value); + rai.setValue(value); + + lvu.setValue(value); + rvu.setValue(value); + + for(int i = 0; i < avu.length; i++) + { + avu[i].setValue(value); + } + } + +// private static void out(String s) +// { +// System.out.println("[cvsPlayer] " + s); +// } +} \ No newline at end of file diff --git a/src/modules/color/ColorFileSource.java b/src/modules/color/ColorFileSource.java new file mode 100644 index 0000000..8203cee --- /dev/null +++ b/src/modules/color/ColorFileSource.java @@ -0,0 +1,34 @@ +package modules.color; + +import com.one.BufferedInputStream; +import com.one.FileSource; +import com.one.PlainPackage; +import com.one.file.Connector; +import com.one.file.FileConnection; +import filemanager.ColorScheme; +import filemanager.main; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class ColorFileSource implements FileSource +{ + public void createFile(String filename) throws IOException + { + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + + PlainPackage ppk = new PlainPackage(); + ppk.init(fc, true); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ColorScheme.saveColorScheme(baos); + + byte[] data = baos.toByteArray(); + baos.close(); + + ppk.addEntry(new BufferedInputStream(data), "scheme.ini", -1, true, null); + + ppk.close(); + + main.FileSelect.showWait(filename.substring(filename.lastIndexOf('/') + 1)); + } +} diff --git a/src/modules/color/ColorModule.java b/src/modules/color/ColorModule.java new file mode 100644 index 0000000..aff5671 --- /dev/null +++ b/src/modules/color/ColorModule.java @@ -0,0 +1,80 @@ +package modules.color; + +import com.one.Application; +import com.one.PlainPackage; +import com.one.PlayList; +import com.one.ProgressBar; +import com.one.TextProcessor; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.Locale; +import com.vmx.ProgressCallback; +import filemanager.ColorScheme; +import filemanager.main; +import filemanager.options; +import java.io.DataInputStream; +import java.io.IOException; + +public class ColorModule implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + options.colorScheme = ColorScheme.SCHEME_CUSTOM; + + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + DataInputStream dis = fc.openDataInputStream(); + + byte[] sig = new byte[3]; + dis.readFully(sig); + + String s = TextProcessor.byteArrayToString(sig); + + if(s.equals("MCS") || s.equals("Ths")) + { + ColorScheme.loadLegacyColorScheme(dis); + + dis.close(); + fc.close(); + + if(main.dsp.getCurrent() != main.FileSelect) + { + main.dsp.setCurrent(main.FileSelect); + } + + //main.FileSelect.updateGradients(); + main.FileSelect.repaint(); + } + else + { + dis.close(); + + ProgressCallback callback = ProgressBar.getProgressCallback(); + callback.setProgress(0); + callback.setText(Locale.getString(getClass().getName(), Locale.INSTALLING_COLOR_SCHEME)); + + PlainPackage ppk = new PlainPackage(); + ppk.init(fc, false); + + if(ColorScheme.loadModernColorScheme(ppk)) + { + //main.FileSelect.updateGradients(); + main.FileSelect.updateModuleList(); + main.FileSelect.showWait(main.currentFile); + } + else + { + if(main.dsp.getCurrent() != main.FileSelect) + { + main.dsp.setCurrent(main.FileSelect); + } + + //main.FileSelect.updateGradients(); + main.FileSelect.repaint(); + } + + ppk.close(); + } + } + + +} diff --git a/src/modules/id3Editor.java b/src/modules/id3Editor.java new file mode 100644 index 0000000..4adbb84 --- /dev/null +++ b/src/modules/id3Editor.java @@ -0,0 +1,219 @@ +package modules; + +import com.vmx.Locale; +import com.vmx.StringEncoder; +import javax.microedition.lcdui.*; +import com.one.file.*; +import java.io.*; +import com.one.*; +import com.vmx.InputStreamDecoder; +import filemanager.main; + +/** + * Форма-редактор ID3v1-тегов MP3 + */ +public class id3Editor implements Application, CommandListener +{ + public static String[] GENRES; + + protected Object parent; + protected FileConnection fc; + protected long tagpos; + + protected TextField tfTitle, + tfArtist, + tfAlbum, + tfYear, + tfComment, + tfTrackNumber; + + protected ChoiceGroup cgGenre; + + public void openFile(String filename, PlayList filelist) throws IOException + { + fc = (FileConnection)Connector.open("file:///" + filename); + tagpos = fc.fileSize(); + + byte[] tag = null; + int songnum = 1; + int genre = 0; + + if(tagpos > 128) + { + InputStream is = fc.openInputStream(); + tag = new byte[128]; + + tagpos -= 128; + + is.skip(tagpos); + is.read(tag); + is.close(); + + if(getFromTag(tag, 0, 3).equals("TAG")) + { + songnum = (int)tag[126] & 0xFF; + genre = (int)tag[127] & 0xFF; + } + else + { + tagpos += 128; + tag = null; + } + } + + int year = 0; + + try + { + year = Integer.parseInt(getFromTag(tag, 93, 4).trim()); + } + catch(NumberFormatException nfe) + { + } + + tfTitle = new TextField(Locale.getString(this, Locale.ID3_SONG), getFromTag(tag, 3, 30), 30, TextField.ANY); + tfArtist = new TextField(Locale.getString(this, Locale.ID3_ARTIST), getFromTag(tag, 33, 30), 30, TextField.ANY); + tfAlbum = new TextField(Locale.getString(this, Locale.ID3_ALBUM), getFromTag(tag, 63, 30), 30, TextField.ANY); + tfYear = new TextField(Locale.getString(this, Locale.ID3_YEAR), Integer.toString(year), 4, TextField.NUMERIC); + tfComment = new TextField(Locale.getString(this, Locale.ID3_COMMENT), getFromTag(tag, 97, 28), 28, TextField.ANY); + tfTrackNumber = new TextField(Locale.getString(this, Locale.ID3_TRACKNUM), Integer.toString(songnum), 3, TextField.NUMERIC); + + if(GENRES == null) + { + loadGenres(); + } + + if(cgGenre == null) + { + cgGenre = new ChoiceGroup(Locale.getString(this, Locale.ID3_GENRE), Choice.POPUP, GENRES, null); + } + + if(genre < 0 || genre >= GENRES.length) + { + genre = 0; + } + + cgGenre.setSelectedIndex(genre, true); + + Form form = new Form(Locale.getString(this, Locale.TAG_EDITOR)); + + form.append(tfTitle); + form.append(tfArtist); + form.append(tfAlbum); + form.append(tfYear); + form.append(tfComment); + form.append(tfTrackNumber); + form.append(cgGenre); + + form.addCommand(new Command(Locale.getString(this, Locale.SAVE_CMD), Command.OK, 1)); + form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.CANCEL, 2)); + form.setCommandListener(this); + + parent = main.dsp.getCurrent(); + main.dsp.setCurrent(form); + } + + /** + * Обработчик команд + */ + public void commandAction(Command c, Displayable d) + { + if(c.getCommandType() == Command.OK) + { + byte[] tag = new byte[128]; + + setToTag(tag, "TAG", 0, 3); + + setToTag(tag, tfTitle.getString(), 3, 30); + setToTag(tag, tfArtist.getString(), 33, 30); + setToTag(tag, tfAlbum.getString(), 63, 30); + setToTag(tag, tfYear.getString(), 93, 4); + setToTag(tag, tfComment.getString(), 97, 28); + + tag[125] = 0; + + try + { + tag[126] = (byte)Integer.parseInt(tfTrackNumber.getString().trim()); + } + catch(NumberFormatException nfe) + { + tag[126] = 1; + } + + tag[127] = (byte)cgGenre.getSelectedIndex(); + + try + { + OutputStream os = fc.openOutputStream(tagpos); + + os.write(tag); + os.close(); + + fc.close(); + } + catch(Exception x) + { + ErrScreen.showErrMsg(125, x); + } + } + + main.dsp.setCurrent(parent); + } + + /** + * ВзÑÑ‚ÑŒ куÑок тега и Ñделать Ñтрокой + */ + protected static String getFromTag(byte[] tag, int off, int len) + { + if(tag == null) + { + return ""; + } + + int end = off + len - 1; + for(; end >= off && (tag[end] == 0 || tag[end] == ' '); end--); + + return StringEncoder.decodeString(tag, off, end - off + 1, StringEncoder.ENC_DEFAULT); + } + + /** + * ЗапиÑать Ñтроку в куÑок тега + */ + protected static void setToTag(byte[] tag, String s, int off, int len) + { + byte[] bs = StringEncoder.encodeString(s, StringEncoder.ENC_DEFAULT); + + int pos = 0; + + for(; pos < bs.length && pos < len; pos++) + { + tag[off + pos] = bs[pos]; + } + + for(; pos < len; pos++) + { + tag[off + pos] = 0; + } + } + + public static void loadGenres() throws IOException + { + GENRES = new String[126]; + + InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/config/genres.ini"); + IniRecord record; + + while((record = IniRecord.getNextRecord(ini)) != null) + { + try + { + GENRES[Integer.parseInt(record.key)] = record.value; + } + catch(Exception e) + { + System.out.println(e.toString() + " because of " + record.key + ", " + record.value); + } + } + } +} diff --git a/src/modules/image/ImageContainer.java b/src/modules/image/ImageContainer.java new file mode 100644 index 0000000..1df7572 --- /dev/null +++ b/src/modules/image/ImageContainer.java @@ -0,0 +1,194 @@ +package modules.image; + +import com.one.ImageProcessor; +import com.one.vector.VectorImage; +import filemanager.images; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; + +public interface ImageContainer +{ + public int getWidth(); + public int getHeight(); + + public void scale(int width, int height); + public void paint(Graphics g, int x, int y, int transform); + + public long getFrameDelay(); + public int currentFrame(); + public void gotoFrame(int target); + public boolean nextFrame(); + public boolean prevFrame(); +} + +class TestImageContainer implements ImageContainer +{ + protected Image image; + + public TestImageContainer() + { + scale(768, 576); + } + + public int getWidth() + { + return image.getWidth(); + } + + public int getHeight() + { + return image.getHeight(); + } + + public void scale(int width, int height) + { + image = Image.createImage(width, height); + Graphics g = image.getGraphics(); + + g.setColor(0xFF000000); + g.fillRect(0, 0, width, height); + + images.drawVColorTest(g, 0, 0, width, height); + + g.setColor(0xFFFFFFFF); + g.drawRect(0, 0, width - 1, height - 1); + } + + public void paint(Graphics g, int x, int y, int transform) + { + g.drawRegion(image, 0, 0, image.getWidth(), image.getHeight(), transform, x, y, Graphics.LEFT | Graphics.TOP); + } + + public long getFrameDelay() + { + return 0; + } + + public int currentFrame() + { + return 0; + } + + public void gotoFrame(int target) + { + } + + public boolean nextFrame() + { + return false; + } + + public boolean prevFrame() + { + return false; + } +} + +class GenericImageContainer implements ImageContainer +{ + protected Image image; + + public GenericImageContainer(Image image) + { + this.image = image; + } + + public int getWidth() + { + return image.getWidth(); + } + + public int getHeight() + { + return image.getHeight(); + } + + public void scale(int width, int height) + { + image = ImageProcessor.scaleImage(image, width, height, false, true); + } + + public void paint(Graphics g, int x, int y, int transform) + { + g.drawRegion(image, 0, 0, image.getWidth(), image.getHeight(), transform, x, y, Graphics.LEFT | Graphics.TOP); + } + + public long getFrameDelay() + { + return 0; + } + + public int currentFrame() + { + return 0; + } + + public void gotoFrame(int target) + { + } + + public boolean nextFrame() + { + return false; + } + + public boolean prevFrame() + { + return false; + } +} + +class VectorImageContainer implements ImageContainer +{ + protected VectorImage image; + + public VectorImageContainer(VectorImage image) + { + this.image = image; + } + + public int getWidth() + { + return image.getWidth(); + } + + public int getHeight() + { + return image.getHeight(); + } + + public void scale(int width, int height) + { + image.scale(width, height); + } + + public void paint(Graphics g, int width, int height, int transform) + { + image.paint(g, width, height); + } + + public long getFrameDelay() + { + return image.getFrameDelay(); + } + + public int currentFrame() + { + return image.currentFrame(); + } + + public void gotoFrame(int target) + { + image.gotoFrame(target); + } + + public boolean nextFrame() + { + return image.nextFrame(); + } + + public boolean prevFrame() + { + return image.prevFrame(); + } +} diff --git a/src/modules/image/ImageModule.java b/src/modules/image/ImageModule.java new file mode 100644 index 0000000..251fd52 --- /dev/null +++ b/src/modules/image/ImageModule.java @@ -0,0 +1,19 @@ +package modules.image; + +import com.one.Application; +import com.one.PlayList; + +public class ImageModule implements Application +{ + public void openFile(String filename, PlayList filelist) + { + cvsImageView imageView = cvsImageView.getInstance(); + + if(filelist != null) + { + imageView.setPlayList(filelist); + } + + imageView.displayImage(filename); + } +} diff --git a/src/modules/image/ImageOptions.java b/src/modules/image/ImageOptions.java new file mode 100644 index 0000000..e4382fb --- /dev/null +++ b/src/modules/image/ImageOptions.java @@ -0,0 +1,120 @@ +package modules.image; + +import com.one.ModuleRegistry; +import com.one.OptionStorage; +import com.vmx.Locale; +import filemanager.main; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import javax.microedition.lcdui.Choice; +import javax.microedition.lcdui.ChoiceGroup; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; + +public class ImageOptions implements CommandListener, OptionStorage +{ + public static final int OPTIONS_VERSION = 1; + + public static int rotateMode = 0; + public static boolean scaleImages = true; + public static boolean useAccelerometer = false; + + protected Object parent; + + protected ChoiceGroup cgPlayer; + + public void showEditor(Object parent) + { + this.parent = parent; + + restoreOptions(); + + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + // *** ÐаÑтройки плеера *** + cgPlayer = new ChoiceGroup(null, Choice.MULTIPLE); + + // ИÑпользовать акÑелерометр + cgPlayer.append(Locale.getString(this, Locale.PREF_USE_ACCELEROMETER), null); + cgPlayer.setSelectedIndex(0, useAccelerometer); + + form.append(cgPlayer); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 2)); + + form.setCommandListener(this); + + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable d) + { + if(c.getCommandType() == Command.OK) + { + useAccelerometer = cgPlayer.isSelected(0); + + saveOptions(); + } + + main.dsp.setCurrent(parent); + } + + public void restoreOptions() + { + try + { + byte[] data = ModuleRegistry.getModuleData(getClass().getName()); + + if(data == null || data.length == 0) + { + return; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data)); + + if(dis.readInt() != OPTIONS_VERSION) + { + dis.close(); + return; + } + + rotateMode = dis.readInt(); + scaleImages = dis.readBoolean(); + useAccelerometer = dis.readBoolean(); + + dis.close(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + + public void saveOptions() + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(OPTIONS_VERSION); + dos.writeInt(rotateMode); + dos.writeBoolean(scaleImages); + dos.writeBoolean(useAccelerometer); + + byte[] data = baos.toByteArray(); + dos.close(); + + ModuleRegistry.setModuleData(getClass().getName(), data); + } + catch(Exception e) + { + e.printStackTrace(); + } + } +} diff --git a/src/modules/image/VectorModule.java b/src/modules/image/VectorModule.java new file mode 100644 index 0000000..f78acda --- /dev/null +++ b/src/modules/image/VectorModule.java @@ -0,0 +1,19 @@ +package modules.image; + +import com.one.Application; +import com.one.PlayList; + +public class VectorModule implements Application +{ + public void openFile(String filename, PlayList filelist) + { + cvsImageView imageView = cvsImageView.getInstance(); + + if(filelist != null) + { + imageView.setPlayList(filelist); + } + + imageView.displayVectorImage(filename); + } +} diff --git a/src/modules/image/cvsImageView.java b/src/modules/image/cvsImageView.java new file mode 100644 index 0000000..d9b5581 --- /dev/null +++ b/src/modules/image/cvsImageView.java @@ -0,0 +1,778 @@ +package modules.image; // переведен + +import javax.microedition.lcdui.*; +import javax.microedition.lcdui.game.*; +import java.util.Timer; +import java.io.*; +import com.vmx.*; +import com.one.*; +import com.one.vector.*; + +import com.one.file.*; +import filemanager.ColorScheme; +import filemanager.images; +import filemanager.main; +import java.util.Enumeration; +import java.util.TimerTask; + +/** + * КлаÑÑ - проÑмотрщик картинок + */ +public class cvsImageView extends gkcCanvas implements Runnable +{ + public static final int MODE_NULL = 0; + public static final int MODE_NORMAL = 1; + public static final int MODE_VECTOR = 2; + + private ImageContainer currentImage = null; + private int mode; + + private boolean rotate; + private int trans; + private boolean scaled; + + private boolean enableUI = true; + private int pictureWidth, pictureHeight; + private int currWidth, currHeight; + private double pictureAspect; + private int w, h; + private double aspect; + private int curposx, curposy; + private String OnlyFileName = ""; + private Font nameFont; + private int hstep, vstep; + private int navx, navy, navw, navh; // большой прÑмоугольник + private int navcx, navcy, navcw, navch; // малый примоугольник + private Timer timer = null; + private boolean isshown; + private int runpanel; + private PlayList playlist; + private boolean allowKeyRelease = true; + + protected static class AnimationTask extends TimerTask + { + protected ImageContainer image; + protected PaintableObject canvas; + + public AnimationTask(ImageContainer image, PaintableObject canvas) + { + this.image = image; + this.canvas = canvas; + } + + public void run() + { + synchronized(image) + { + image.nextFrame(); + } + + canvas.repaint(); + canvas.serviceRepaints(); + } + } + + private static cvsImageView instance; + + public static void loadInstance() + { + if(instance == null) + { + instance = new cvsImageView(); + } + } + + public static cvsImageView getInstance() + { + loadInstance(); + return instance; + } + + /** + * КонÑтруктор + */ + public cvsImageView() + { + setFullScreenMode(true); + + w = getWidth(); + h = getHeight(); + + aspect = (double)w / (double)h; + + nameFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); + + //fgimage = images.createUI(w, h); + + runpanel = -1; + } + + public void setPlayList(PlayList newlist) + { + playlist = newlist; + } + + public void setPlayList(Enumeration newlist) + { + playlist = new PlayList(newlist); + } + + protected void initPanels() + { + if(timer != null) + { + timer.cancel(); + timer = null; + } + + mode = MODE_NULL; + currentImage = null; + + if(runpanel < 0) + { + runpanel = main.manager.currentPanel(); + } + + main.manager.setCurrent(this, runpanel); + main.manager.updateAssociation(runpanel, playlist.getCurrentElement()); + main.manager.changePanel(runpanel); + } + + protected void initPlayList(String file) + { + OnlyFileName = file.substring(file.lastIndexOf('/') + 1); + + if(playlist == null) + { + playlist = new PlayList(file); + } + + playlist.selectElement(file); + } + + protected void initDisplay() + { + // ПрÑчем картинку за пределы Ñкрана на Ð²Ñ€ÐµÐ¼Ñ + curposx = w; + curposy = h; + + pictureWidth = currentImage.getWidth(); + pictureHeight = currentImage.getHeight(); + + switch(ImageOptions.rotateMode) + { + default: + case 0: + rotate = false; + trans = Sprite.TRANS_NONE; + break; + + case 1: + rotate = true; + trans = Sprite.TRANS_ROT90; + break; + + case 2: + rotate = false; + trans = Sprite.TRANS_ROT180; + break; + + case 3: + rotate = true; + trans = Sprite.TRANS_ROT270; + break; + + case 4: + if(pictureWidth > pictureHeight) + { + rotate = true; + trans = Sprite.TRANS_ROT90; + } + break; + + case 5: + if(pictureWidth > pictureHeight) + { + rotate = true; + trans = Sprite.TRANS_ROT270; + } + break; + } + + if(ImageOptions.scaleImages) + { + pictureAspect = (double)pictureWidth / (double)pictureHeight; + + if(rotate) //еÑли поворачиваем + { + /* Ñкран повернут, так что ширина Ñто h и выÑота Ñто w */ + + if(pictureAspect > (1 / aspect)) //впиÑываем по ширине + { + currentImage.scale(h, (int)(h / pictureAspect)); + } + else //впиÑываем по выÑоте + { + currentImage.scale((int)(w * pictureAspect), w); + } + } + else //еÑли не поворачиваем + { + if(pictureAspect > aspect) //впиÑываем по ширине + { + currentImage.scale(w, (int)(w / pictureAspect)); + } + else //впиÑываем по выÑоте + { + currentImage.scale((int)(h * pictureAspect), h); + } + } + + // SHIT! Что-то мне подÑказывает, что Ñто можно было Ñделать проще... + } + + currWidth = currentImage.getWidth(); + currHeight = currentImage.getHeight(); + + if(currWidth != pictureWidth || currHeight != pictureHeight) + { + scaled = true; + hstep = vstep = 0; + } + else + { + scaled = false; + hstep = vstep = (w + h) / 6; + } + + if(rotate) + { + currWidth ^= currHeight; + currHeight ^= currWidth; + currWidth ^= currHeight; + } + + if(currWidth > currHeight) // изображение горизонтальное + { + navw = w / 4; + navh = navw * currHeight / currWidth; + } + else + { + navh = w / 4; + navw = navh * currWidth / currHeight; + } + + navx = w - navw - 4; + navy = 3; + + curposx = (w - currWidth) / 2; + curposy = (h - currHeight) / 2; + } + + public void displayImageFromStream(InputStream is, String imgName) + { + initPanels(); + + mode = MODE_NORMAL; + + initPlayList(imgName); + + repaint(); + serviceRepaints(); + + try + { + currentImage = new GenericImageContainer(Image.createImage(is)); + is.close(); + } + catch(Exception x) + { + ErrScreen.showErrMsg(123, x); + +// x.printStackTrace(); +// +// currentImage = new TestImageContainer(); +// OnlyFileName = x.toString(); + } + + initDisplay(); + + repaint(); + } + + public void displayImage(String imgName) + { + try + { + displayImageFromStream(Connector.openInputStream("file:///" + imgName), imgName); + } + catch(Exception e) + { + } + } + + public void displayVectorImageFromStream(InputStream is, String imgName) + { + initPanels(); + + mode = MODE_VECTOR; + currentImage = null; + + initPlayList(imgName); + repaint(); + + try + { + is = new DataInputStream(is); + currentImage = new VectorImageContainer(new VectorImage((DataInputStream)is)); + is.close(); + } + catch(Exception x) + { + ErrScreen.showErrMsg(124, x); + +// x.printStackTrace(); +// +// currentImage = new TestImageContainer(); +// OnlyFileName = x.toString(); + } + + initDisplay(); + + repaint(); + } + + public void displayVectorImage(String imgName) + { + try + { + displayVectorImageFromStream(Connector.openInputStream("file:///" + imgName), imgName); + } + catch(Exception e) + { + } + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð¸Ñовки + */ + public void paint(Graphics g) + { + g.setColor(images.cImgBack); // 0x000000); + g.fillRect(0, 0, w, h); + + // фон + if(currentImage != null) + { + currentImage.paint(g, curposx, curposy, trans); + } + + if(enableUI) + { + if(currentImage != null && (currWidth > w || currHeight > h)) + { + // ----- прÑмоугольники в правом верхнем углу ----- + + g.setColor(ColorScheme.colors[ColorScheme.back1]); + g.fillRect(navx, navy, navw, navh); + + if(currWidth > w) + { + navcw = navw * w / currWidth; + navcx = navx - curposx * navw / currWidth; + } + else + { + navcw = navw; + navcx = navx; + } + + if(currHeight > h) + { + navch = navh * h / currHeight; + navcy = navy - curposy * navh / currHeight; + } + else + { + navch = navh; + navcy = navy; + } + + /* - такого не должно быть - Ñм. уÑÐ»Ð¾Ð²Ð¸Ñ Ð²Ñ‹ÑˆÐµ + if(navcw > navw) + { + navcw = navw; + } + + if(navch > navh) + { + navch = navh; + } + + if(navcx < navx) + { + navcx = navx; + } + else if(navcx + navcw > navx + navw) + { + navcx = navx + navw - navcw; + } + + if(navcy < navy) + { + navcy = navy; + } + else if(navcy + navch > navy + navh) + { + navcy = navy + navh - navch; + } + */ + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.fillRect(navcx + 1, navcy + 1, navcw, navch); + + g.setColor(ColorScheme.colors[ColorScheme.dkborder]); + g.drawRect(navx, navy, navw, navh); + + // ----- закончилиÑÑŒ прÑмоугольники ----- + } + + if(images.minUI != null) + { + g.drawImage(images.minUI, 0, h, Graphics.LEFT | Graphics.BOTTOM); + } + + g.setFont(nameFont); + + g.setColor(images.cPlayFore1); //0x800000); + g.drawString(OnlyFileName, w / 2, h - images.uiBottomHeight + images.uiBottomVSpace, Graphics.TOP | Graphics.HCENTER); + + if(currentImage != null) + { + String tmp = pictureWidth + " x " + pictureHeight + " ("; + + if(scaled) + { + tmp += Locale.getString(this, Locale.IMAGEVIEW_SCALED) + ", "; + } + + if(mode == MODE_VECTOR && currentImage != null) + { + tmp += Integer.toString(currentImage.currentFrame()); + } + else + { + switch(trans) + { + case Sprite.TRANS_NONE: + tmp += "0°"; + break; + + case Sprite.TRANS_ROT90: + tmp += "90°"; + break; + + case Sprite.TRANS_ROT180: + tmp += "180°"; + break; + + case Sprite.TRANS_ROT270: + tmp += "270°"; + break; + } + } + + tmp += ")"; + + g.setColor(images.cPlayFore2); //0x000080); + g.drawString(tmp, w / 2, h - images.uiBottomVSpace, Graphics.BOTTOM | Graphics.HCENTER); + } + } + } + + public void keyReleased(int keyCode) + { + if(allowKeyRelease) + { + handleKeyAction(keyCode); + } + else + { + allowKeyRelease = true; + } + } + + public void keyRepeated(int keyCode) + { + allowKeyRelease = false; + handleKeyAction(keyCode); + } + + /** + * Обработчик нажатий клавиш + */ + public void handleKeyAction(int keyCode) + { + keyCode = rotateKey(keyCode, trans); + + if(keyCode == KEY_POUND) + { + enableUI = !enableUI; + repaint(); + } + else if(keyCode == KEY_DOWN || keyCode == KEY_RIGHT) // Ð¡Ð»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + { + nextPicture(); + } + else if(keyCode == KEY_UP || keyCode == KEY_LEFT) // Предыдущ картинка + { + prevPicture(); + } + else if(keyCode == KEY_LSK) + { + if(mode == MODE_VECTOR) + { + if(timer != null) + { + timer.cancel(); + timer = null; + } + else + { + timer = new Timer(); + timer.scheduleAtFixedRate(new AnimationTask(currentImage, this), 0, currentImage.getFrameDelay()); + } + } + } + else if(keyCode == KEY_RSK) // Выход + { + if(timer != null) + { + timer.cancel(); + timer = null; + } + + mode = MODE_NULL; + + playlist.cancelSearch(); + playlist = null; + + main.manager.ret(); + runpanel = -1; + } + else if(keyCode == KEY_CANCEL) // ÑворачиваемÑÑ + { + main.manager.minimizePanel(); + } + else if(keyCode == KEY_NUM4) + { + curposx += hstep; + + if(curposx > 0) + { + curposx = 0; + } + + repaint(); + } + else if(keyCode == KEY_NUM6) + { + curposx -= hstep; + + if(curposx < w - currWidth) + { + curposx = w - currWidth; + } + + repaint(); + } + else if(keyCode == KEY_NUM2) + { + curposy += vstep; + + if(curposy > 0) + { + curposy = 0; + } + + repaint(); + } + else if(keyCode == KEY_NUM8) + { + curposy -= vstep; + + if(curposy < h - currHeight) + { + curposy = h - currHeight; + } + + repaint(); + } + else if(keyCode == KEY_NUM5) + { + curposx = (w - currWidth) / 2; + curposy = (h - currHeight) / 2; + + repaint(); + } + else if(keyCode == KEY_STAR) + { + if(++ImageOptions.rotateMode > 3) + { + ImageOptions.rotateMode = 0; + } + + redisplay(); + } + else if(keyCode == KEY_NUM0) + { + // еÑли не вышло маÑштабировать, + // то нечего и переключать + + boolean wasrunning = timer != null; + int prevframe = currentImage.currentFrame(); + + if(wasrunning) + { + timer.cancel(); + timer = null; + } + + ImageOptions.scaleImages = !scaled; + redisplay(); + + currentImage.gotoFrame(prevframe); + + if(wasrunning) + { + timer = new Timer(); + timer.scheduleAtFixedRate(new AnimationTask(currentImage, this), 0, currentImage.getFrameDelay()); + } + } + else if(keyCode == KEY_NUM1) + { + if(timer == null) + { + if(mode == MODE_VECTOR) + { + currentImage.prevFrame(); + repaint(); + } + } + } + else if(keyCode == KEY_NUM3) + { + if(timer == null) + { + if(mode == MODE_VECTOR) + { + currentImage.nextFrame(); + repaint(); + } + } + } + else if(keyCode == KEY_NUM7) + { + if(timer == null) + { + if(mode == MODE_VECTOR) + { + currentImage.gotoFrame(currentImage.currentFrame() - 10); + repaint(); + } + } + } + else if(keyCode == KEY_NUM9) + { + if(timer == null) + { + if(mode == MODE_VECTOR) + { + currentImage.gotoFrame(currentImage.currentFrame() + 10); + repaint(); + } + } + } + } + + /** + * ÑÐ»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + */ + public void nextPicture() + { + playlist.nextElement(false); + main.FileSelect.executeFile(playlist, null, runpanel); + } + + /** + * Ð¿Ñ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + */ + public void prevPicture() + { + playlist.prevElement(false); + main.FileSelect.executeFile(playlist, null, runpanel); + } + + private void redisplay() + { + if(mode == MODE_VECTOR) + { + currentImage.scale(-1, -1); + + initDisplay(); + + repaint(); + } + else + { + main.FileSelect.executeFile(playlist, null, runpanel); + } + } + + public void showNotify() + { + isshown = true; + + if(ImageOptions.useAccelerometer) + { + (new Thread(this, "ImageView/AccelEvent")).start(); + } + } + + public void hideNotify() + { + isshown = false; + } + + public void run() + { + while(isshown) + { + int delta = main.accelerometer.getDelta(0, 1200); + + if(currentImage != null || currentImage != null) + { + if(delta != 0) + { + if(delta > 0) + { + nextPicture(); + } + else + { + prevPicture(); + } + } + } + + try + { + Thread.sleep(300); + } + catch(InterruptedException ie) + { + } + } + } +} diff --git a/src/modules/langpack/StringPacker.java b/src/modules/langpack/StringPacker.java new file mode 100644 index 0000000..c6607cb --- /dev/null +++ b/src/modules/langpack/StringPacker.java @@ -0,0 +1,83 @@ +package modules.langpack; + +import com.one.Application; +import com.one.IniFile; +import com.one.PlayList; +import com.one.TextProcessor; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.InputStreamDecoder; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Enumeration; + +public class StringPacker implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + + String tempname = Connector.createTempFile(filename, true); + FileConnection temp = (FileConnection)Connector.open("file:///" + tempname); + temp.create(); + + InputStreamDecoder isd = InputStreamDecoder.getFileDecoder(fc); + IniFile ini = new IniFile(isd, false); + isd.close(); + + DataOutputStream dos = temp.openDataOutputStream(); + + Enumeration sections = ini.listSections(); + String section = null; + + int count = 0; + + while(sections.hasMoreElements()) + { + section = (String)sections.nextElement(); + + try + { + count = Integer.parseInt(section); + + if(count > 0) + { + break; + } + } + catch(NumberFormatException nfe) + { + } + } + + dos.writeInt(count); + + String text; + + for(int i = 0; i < count; i++) + { + text = ini.getRecord(section, Integer.toString(i)); + + if(text != null) + { + dos.writeUTF(TextProcessor.unescapeString(text)); + } + else + { + System.out.println("String " + Integer.toString(i) + " is missing!"); + dos.writeUTF(""); + } + } + + dos.close(); + + filename = fc.getName(); + fc.delete(); + fc.close(); + + temp.rename(filename); + temp.close(); + + Connector.releaseTempFile(tempname); + } +} diff --git a/src/modules/langpack/StringUnpacker.java b/src/modules/langpack/StringUnpacker.java new file mode 100644 index 0000000..eafba57 --- /dev/null +++ b/src/modules/langpack/StringUnpacker.java @@ -0,0 +1,50 @@ +package modules.langpack; + +import com.one.Application; +import com.one.IniFile; +import com.one.PlayList; +import com.one.TextProcessor; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.OutputStreamEncoder; +import com.vmx.StringEncoder; +import java.io.DataInputStream; +import java.io.IOException; + +public class StringUnpacker implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + + String tempname = Connector.createTempFile(filename, true); + FileConnection temp = (FileConnection)Connector.open("file:///" + tempname); + temp.create(); + + DataInputStream dis = fc.openDataInputStream(); + IniFile ini = new IniFile(false); + + int count = dis.readInt(); + String section = Integer.toString(count); + + for(int i = 0; i < count; i++) + { + ini.addRecord(section, Integer.toString(i), TextProcessor.escapeString(dis.readUTF(), StringEncoder.ENC_UTF8)); + } + + dis.close(); + + OutputStreamEncoder ose = new OutputStreamEncoder(temp.openOutputStream(), StringEncoder.ENC_UTF8); + ini.write(ose); + ose.close(); + + filename = fc.getName(); + fc.delete(); + fc.close(); + + temp.rename(filename); + temp.close(); + + Connector.releaseTempFile(tempname); + } +} diff --git a/src/modules/mascot/AnimationViewer.java b/src/modules/mascot/AnimationViewer.java new file mode 100644 index 0000000..3195c5c --- /dev/null +++ b/src/modules/mascot/AnimationViewer.java @@ -0,0 +1,30 @@ +/* + * aNNiMON 2010 + * For more info visit http://annimon.com/ + */ +package modules.mascot; + +import com.one.Application; +import com.one.ModuleRegistry; +import com.one.PlayList; +import com.vmx.AuxClass; +import java.io.IOException; + +/** + * + * @author aNNiMON + */ +public class AnimationViewer implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + Lib_mcv3 mc = Lib_mcv3.getInstance(); + + if(filelist != null) + { + mc.setPlayList(filelist); + } + + mc.init(Lib_mcv3.getFileData(filename.substring(0, filename.lastIndexOf('.')) + AuxClass.formatFileExtension(ModuleRegistry.getExtension(MascotViewer.class.getName()))), Lib_mcv3.getFileData(filename), filename); + } +} diff --git a/src/modules/mascot/Lib_mcv3.java b/src/modules/mascot/Lib_mcv3.java new file mode 100644 index 0000000..3da0fab --- /dev/null +++ b/src/modules/mascot/Lib_mcv3.java @@ -0,0 +1,686 @@ +package modules.mascot; + +import com.mascotcapsule.micro3d.v3.*; +import com.one.PlayList; +import com.one.SlidingNumber; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.AuxClass; +import com.vmx.Locale; +import com.vmx.gkcCanvas; +import filemanager.images; +import filemanager.main; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import javax.microedition.lcdui.*; + +/** + * + * @author aNNiMON + */ +public class Lib_mcv3 extends gkcCanvas implements Runnable +{ + /** + * Ðомера Ñтрок в локали. + * + * ЗдеÑÑŒ вÑе номера начинаютÑÑ Ñ 0 и модуль может Ñчитать, что он единÑтвенный, + * доÑтаточно указать необходимые ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð² файлах offsets.ini и strings.ini + */ + public static final int MODEL_INFO = 3; + + private Graphics3D g3 = null; + + private Figure figure; + private Texture mainTexture; + private Effect3D effect; + private AffineTrans viewTrans, modelTrans, tempTrans; + private ActionTable action; + private Vector3D Pos, Look, Up; + private Light light; //Свет + private Vector3D lightdir; // ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ Ð¸Ñточника Ñвета + private int dirIntensity; // ?нтенÑивноÑÑ‚ÑŒ Ñвета + private int ambIntensity; // ?нтенÑивноÑÑ‚ÑŒ амбиент Ñвета + private boolean lightEnabled; // иÑпользовать ли Ñвет? + private FigureLayout layout; + private int centerX, centerY;// центр вывода + private boolean persEnabled; //иÑпользовать перÑпективу? + private int persNear, persFar, persAngle; + private int spinx, spiny, spinz; + private int scalex, scaley, scalez; + private int modelx, modely, modelz; + private int numFrames, frameStep, frame = 0; + private int w, h; + private boolean allowKeyRelease = true; + private boolean moveMode = false; + private boolean enableUI = true; + private String OnlyFileName = ""; + private Font nameFont; + private boolean animationRunning = false; + private Thread t; + + private PlayList playlist; + private int runpanel; + + private static Lib_mcv3 instance; + + public static Lib_mcv3 getInstance() + { + if(instance == null) + { + instance = new Lib_mcv3(); + } + + return instance; + } + + public static byte[] getFileData(String filename) throws IOException + { + FileConnection fc = (FileConnection)Connector.open("file:///" + filename, Connector.READ); + byte[] bt = new byte[(int)fc.fileSize()]; + + InputStream is = fc.openInputStream(); + + int total = 0; + while((total += is.read(bt, total, bt.length - total)) < bt.length); + + is.close(); + fc.close(); + + return bt; + } + + private class ModelChanger implements Runnable + { + private Runnable runnable; + private int dir; + + public ModelChanger(Runnable runnable, int dir) + { + this.runnable = runnable; + this.dir = dir; + } + + public void run() + { + boolean flag = animationRunning; + animationRunning = false; + + if(t != null && t.isAlive()) + { + try + { + t.join(); + } + catch(InterruptedException ie) + { + } + } + + if(dir > 0) + { + playlist.nextElement(false); + } + else if(dir < 0) + { + playlist.prevElement(false); + } + + main.FileSelect.executeFile(playlist, null, runpanel); + + animationRunning = flag; + + if(animationRunning) + { + (t = new Thread(runnable)).start(); + } + } + } + + /* + * Загрузка + * */ + + //ТекÑтура + public void setBMP(byte[] texdata) + { + if(texdata != null) + { + mainTexture = new Texture(texdata, true); + } + else + { + mainTexture = null; + } + } + + public Lib_mcv3() + { + setFullScreenMode(true); + + resetView(); + + ambIntensity = 2048; + dirIntensity = 4096; + lightdir = new Vector3D(-3511, 731, 878); + + persNear = 1; + persFar = 4096; + persAngle = 682; + + Pos = new Vector3D(0, 120, 500); + Look = new Vector3D(0, 0, -2000); + Up = new Vector3D(0, 4096, 0); + + centerX = (w = getWidth()) / 2; + centerY = (h = getHeight()) / 2; + + nameFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); + } + + protected void resetView() + { + scalex = scaley = scalez = 4096; + modelx = modely = modelz = 0; + spinx = spiny = spinz = 0; + } + + /* + * Свет + * */ + // ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ Ð¸Ñточника Ñвета + /* public void setLightPos(int x, int y, int z) { + lightdir = new Vector3D(x, y, z); + } + //?нтенÑивноÑÑ‚ÑŒ Ñвета + public void setLightIntensity(int value) { + dirIntensity=value; + } + //?нтенÑивноÑÑ‚ÑŒ амбиент Ñвета + public void setAmbLightIntensity(int value) { + ambIntensity=value; + } + public void setLight(boolean light) { + lightEnabled=light; + }*/ + + /* + * FigureLayout + * */ + //центр FL +/* public void setFLCenter(int cx, int cy) { + centerX=cx; + centerY=cy; + } + //?Ñпользовать ли перÑпективу + public void setPerspective(boolean pers) { + persEnabled=pers; + } + // Параметры перÑпективы + public void setPersPos(int near, int far, int angle) { + persNear = near; //коÑфициент ближнего угла + persFar = far; // дальнего угла + persAngle = angle; // Ñам угол + } + // Параметры ÑƒÐ²ÐµÐ»Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð´ÐµÐ»Ð¸ + public void setScaleMDL(int x, int y, int z) { + scalex=x; + scaley=y; + scalez=z; + } + // Параметры транÑÑ„Ð¾Ñ€Ð¼Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð´ÐµÐ»Ð¸ + public void setTransMDL(int x, int y, int z) { + modelx=x; + modely=y; + modelz=z; + }*/ + + /* + * ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ + * */ + //Получить кол-во кадров анимации + protected void nextFrame() + { + frame += frameStep; + + if(frame > numFrames) + { + frame = numFrames; + } + } + + protected void prevFrame() + { + frame -= frameStep; + + if(frame < 0) + { + frame = 0; + } + } + + // ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ ÐºÐ°Ð¼ÐµÑ€Ñ‹ + /*public void setViewPos(int x, int y, int z) { + Pos = new Vector3D(x, y, z); + } + // ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ Ð¸Ñточника Ñвета + public void setViewLook(int x, int y, int z) { + Look = new Vector3D(x, y, z); + } + // ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ Ð¸Ñточника Ñвета + public void setViewUp(int x, int y, int z) { + Up = new Vector3D(x, y, z); + }*/ + + public void init(byte[] mbac, byte[] mtra, String modelName) + { + initPanels(); + + initPlayList(modelName); + + figure = new Figure(mbac); + + if(mainTexture != null) + { + figure.setTexture(mainTexture); + } + + effect = new Effect3D(null, Effect3D.NORMAL_SHADING, true, null); + layout = new FigureLayout(); + viewTrans = new AffineTrans(); + modelTrans = new AffineTrans(); + tempTrans = new AffineTrans(); + light = new Light(lightdir, dirIntensity, ambIntensity); + + if(mtra != null) + { + action = new ActionTable(mtra); + numFrames = action.getNumFrames(0); + } + else + { + action = null; + numFrames = 0; + } + + frameStep = numFrames / 100; + frame = 0; + + g3 = new Graphics3D(); + + repaint(); + } + + public void setPlayList(PlayList newlist) + { + playlist = newlist; + } + + public void setPlayList(Enumeration newlist) + { + playlist = new PlayList(newlist); + } + + protected void initPanels() + { + if(runpanel < 0) + { + runpanel = main.manager.currentPanel(); + } + + main.manager.setCurrent(this, runpanel); + main.manager.updateAssociation(runpanel, playlist.getCurrentElement()); + main.manager.changePanel(runpanel); + } + + protected void initPlayList(String file) + { + OnlyFileName = file.substring(file.lastIndexOf('/') + 1); + + if(playlist == null) + { + playlist = new PlayList(file); + } + + playlist.selectElement(file); + } + + /** + * ÑÐ»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + */ + public void nextModel() + { + (new Thread(new ModelChanger(this, 1))).start(); + } + + /** + * Ð¿Ñ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° + */ + public void prevModel() + { + (new Thread(new ModelChanger(this, -1))).start(); + } + + public void paint(Graphics g) + { + g.setColor(images.cImgBack); + g.fillRect(0, 0, w, h); + + drawModel(g); + + if(enableUI) + { + if(images.minUI != null) + { + g.drawImage(images.minUI, 0, h, Graphics.LEFT | Graphics.BOTTOM); + } + + g.setFont(nameFont); + + g.setColor(images.cPlayFore1); //0x800000); + g.drawString(OnlyFileName, w / 2, h - images.uiBottomHeight + images.uiBottomVSpace, Graphics.TOP | Graphics.HCENTER); + + String[] tokens = + { + AuxClass.doubleToString(scalex / 4096.0, 2), + AuxClass.doubleToString(scaley / 4096.0, 2), + AuxClass.doubleToString(scalez / 4096.0, 2), + AuxClass.doubleToString(spinx * 360.0 / 4096.0, 0), + AuxClass.doubleToString(spiny * 360.0 / 4096.0, 0), + AuxClass.doubleToString(spinz * 360.0 / 4096.0, 0), + AuxClass.doubleToString(modelx * 100 / 4096.0, 1), + AuxClass.doubleToString(modely * 100 / 4096.0, 1), + AuxClass.doubleToString(modelz * 100 / 4096.0, 1), + frameStep > 0 ? Integer.toString(frame / frameStep) : "0" + }; + + g.setColor(images.cPlayFore2); //0x000080); + g.drawString(Locale.getString(this, MODEL_INFO, tokens), w / 2, h - images.uiBottomVSpace, Graphics.BOTTOM | Graphics.HCENTER); + } + } + + /* + * ОтриÑовка модели + * */ + protected void drawModel(Graphics g) + { + if(g3 == null) + { + return; + } + + //3D рендеринг + g3.bind(g); + + if(lightEnabled) + { + effect.setLight(light); + } + else + { + effect.setLight(null); + } + + if(persEnabled) + { + layout.setPerspective(persNear, persFar, persAngle); + } + else + { + layout.setParallelSize(800, 800); + } + + layout.setCenter(centerX, centerY); + + modelTrans.setIdentity(); + modelTrans.rotationX(spinx); + + tempTrans.setIdentity(); + tempTrans.rotationY(spiny); + modelTrans.mul(tempTrans); + + tempTrans.set(scalex, 0, 0, 0, 0, scaley, 0, 0, 0, 0, scalez, 0); + modelTrans.mul(tempTrans); + + modelTrans.m03 = modelx; + modelTrans.m13 = modely; + modelTrans.m23 = modelz; + + viewTrans.lookAt(Pos, Look, Up); + viewTrans.mul(modelTrans); + + layout.setAffineTrans(viewTrans); + + if(action != null) + { + figure.setPosture(action, 0, frame); + } + + g3.renderFigure(figure, 0, 0, layout, effect); + g3.flush(); + + g3.release(g); + } + + public void keyReleased(int keyCode) + { + if(allowKeyRelease) + { + handleKeyAction(keyCode); + } + else + { + allowKeyRelease = true; + } + } + + public void keyRepeated(int keyCode) + { + allowKeyRelease = false; + handleKeyAction(keyCode); + } + + public void handleKeyAction(int key) + { + /* + * ЗдеÑÑŒ пришлоÑÑŒ вÑе-таки нагородить конÑтрукцию из if ... else if ... + * потому что switch требует иÑпользовать в case конÑтанты, + * а в gkcCanvas еÑÑ‚ÑŒ и проÑтые переменные вроде KEY_LSK + */ + + if(key == KEY_RSK) + { + animationRunning = false; + + playlist.cancelSearch(); + playlist = null; + + main.manager.ret(); + runpanel = -1; + } + else if(key == KEY_CANCEL) + { + animationRunning = false; + main.manager.minimizePanel(); + } + else if(key == KEY_LSK || key == KEY_FIRE) + { + if(animationRunning) + { + animationRunning = false; + } + else + { + animationRunning = true; + (t = new Thread(this)).start(); + } + } + else if(key == KEY_RIGHT || key == KEY_DOWN) + { + nextModel(); + } + else if(key == KEY_LEFT || key == KEY_UP) + { + prevModel(); + } + else + { + if(key == KEY_NUM4) + { + if(moveMode) + { + modelx += 20; + } + else + { + spiny -= 40; + + if(spiny < 0) + { + spiny += 4096; + } + } + } + else if(key == KEY_NUM6) + { + if(moveMode) + { + modelx -= 20; + } + else + { + spiny += 40; + + if(spiny >= 4096) + { + spiny -= 4096; + } + } + } + else if(key == KEY_NUM2) + { + if(moveMode) + { + modely -= 20; + } + else + { + spinx -= 40; + + if(spinx < 0) + { + spinx += 4096; + } + } + } + else if(key == KEY_NUM8) + { + if(moveMode) + { + modely += 20; + } + else + { + spinx += 40; + + if(spinx >= 4096) + { + spinx -= 4096; + } + } + } + else if(key == KEY_NUM5) + { + resetView(); + } + else if(key == KEY_STAR) + { + moveMode = !moveMode; + } + else if(key == KEY_POUND) + { + enableUI = !enableUI; + } + else if(key == KEY_NUM0) + { + lightEnabled = !lightEnabled; + } + else if(key == KEY_NUM1) + { + int delta = scalex >>> 3; + + if(delta < 1) + { + delta = 1; + } + + scalez = scaley = scalex -= delta; // 196; + } + else if(key == KEY_NUM3) + { + int delta = scalex >>> 3; + + if(delta < 1) + { + delta = 1; + } + + scalez = scaley = scalex += delta; // 196; + } + else if(key == KEY_NUM7) + { + prevFrame(); + } + else if(key == KEY_NUM9) + { + nextFrame(); + } + + repaint(); + } + } + + public void run() + { + if(action != null) + { + int frameStepSmall = frameStep / 2; + + if(frameStepSmall < 1) + { + frameStepSmall = 1; + } + + while(animationRunning) + { + frame += frameStepSmall; + + if(frame > numFrames) + { + frame = 0; + } + + repaint(); + serviceRepaints(); + + Thread.yield(); + } + } + else + { + SlidingNumber slidingSpinX = new SlidingNumber(0, 4096 << 1, spinx, 512, 4096); + SlidingNumber slidingSpinY = new SlidingNumber(0, 4096 << 1, spiny, 512, 4096); + + while(animationRunning) + { + spinx = slidingSpinX.nextValue(); + spiny = slidingSpinY.nextValue(); + + repaint(); + serviceRepaints(); + + Thread.yield(); + } + } + } +} diff --git a/src/modules/mascot/MascotViewer.java b/src/modules/mascot/MascotViewer.java new file mode 100644 index 0000000..4eb6974 --- /dev/null +++ b/src/modules/mascot/MascotViewer.java @@ -0,0 +1,28 @@ +/* + * aNNiMON 2010 + * For more info visit http://annimon.com/ + */ +package modules.mascot; + +import com.one.Application; +import com.one.PlayList; +import java.io.*; + +/** + * + * @author aNNiMON + */ +public class MascotViewer implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + Lib_mcv3 mc = Lib_mcv3.getInstance(); + + if(filelist != null) + { + mc.setPlayList(filelist); + } + + mc.init(Lib_mcv3.getFileData(filename), null, filename); + } +} diff --git a/src/modules/mascot/TextureLoader.java b/src/modules/mascot/TextureLoader.java new file mode 100644 index 0000000..7b68d48 --- /dev/null +++ b/src/modules/mascot/TextureLoader.java @@ -0,0 +1,25 @@ +/* + * aNNiMON 2010 + * For more info visit http://annimon.com/ + */ +package modules.mascot; + +import com.one.Application; +import com.one.PlayList; +import com.vmx.Locale; +import filemanager.main; +import java.io.IOException; +import javax.microedition.lcdui.AlertType; + +/** + * + * @author aNNiMON + */ +public class TextureLoader implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + Lib_mcv3.getInstance().setBMP(Lib_mcv3.getFileData(filename)); + main.showMessage(Locale.getString(null, Locale.DONE), Locale.getString(null, Locale.OPERATION_OK), AlertType.INFO, 1500, null); + } +} diff --git a/src/modules/mocha/Decompiler.java b/src/modules/mocha/Decompiler.java new file mode 100644 index 0000000..bab8d0f --- /dev/null +++ b/src/modules/mocha/Decompiler.java @@ -0,0 +1,45 @@ +package modules.mocha; + +import com.one.Application; +import com.one.PlayList; +import com.one.file.Connector; +import com.one.file.FileConnection; +import java.io.*; + +public class Decompiler implements Application { + + public static boolean m_debugZ; + public static boolean m_verboseZ; + + public void openFile(String filename, PlayList filelist) throws IOException { + boolean raw = false; + + FileConnection inputFile = (FileConnection)Connector.open("file:///" + filename); + String s = filename; + s = "file:///" + s.substring(0, s.length() - 6) + ".java"; + FileConnection outputFile = (FileConnection)Connector.open(s); + if (outputFile.exists()) { + outputFile.delete(); + } + outputFile.create(); + _cls0 _lcls0 = null; + try { + _cls3 _lcls3 = new _cls3(inputFile.openInputStream()); + _lcls0 = new _cls0(_lcls3, inputFile.getName()); + _lcls3.close(); + } catch (_cls128 _ex) { + _ex.printStackTrace(); + } catch (IOException _ex) { + } + if (!raw) { + _lcls0._39vV(); + } + try { + PrintStream printstream = new PrintStream(new _cls123(outputFile.openDataOutputStream())); + _lcls0._17PrintStreamV(printstream); + printstream.close(); + outputFile.close(); + } catch (IOException _ex) { + } + } +} diff --git a/src/modules/mocha/_cls0.java b/src/modules/mocha/_cls0.java new file mode 100644 index 0000000..40a92c3 --- /dev/null +++ b/src/modules/mocha/_cls0.java @@ -0,0 +1,547 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; +import java.util.*; + +// Referenced classes of package mocha: +// _cls3, _cls6, Obfuscator, _cls72, +// _cls2, _cls116, _cls1, _cls128, +// _cls7 + +public class _cls0 +{ + + String m_m_134StringString; + int m_m_137II; + int m_m_146II; + _cls2 m_m_118a2a2[]; + _cls6 m_m_066; + _cls2 m_m_14722; + String m_m_142StringString; + _cls2 m_m_13222; + _cls2 m_m_123a2a2[]; + _cls7 m_m_124a7a7[]; + _cls72 m_m_122a72a72[]; + _cls2 m_m_14922; + Vector m_m_129VectorVector; + Hashtable m_m_120HashtableHashtable; + Hashtable m_m_148HashtableHashtable; + Hashtable m_m_128HashtableHashtable; + Hashtable m_m_135HashtableHashtable; + Hashtable m_m_143HashtableHashtable; + Hashtable m_m_119HashtableHashtable; + Hashtable m_m_130HashtableHashtable; + String m_m_127aStringaString[]; + int m_m_144aIaI[]; + + public _cls0(_cls3 _pcls3, String s) + throws IOException, _cls128 + { + m_m_129VectorVector = new Vector(); + m_m_120HashtableHashtable = new Hashtable(); + m_m_148HashtableHashtable = new Hashtable(); + m_m_128HashtableHashtable = new Hashtable(); + m_m_134StringString = s; + if(_pcls3.readInt() != 0xcafebabe) + throw new _cls128("Not a valid Java class file"); + m_m_146II = _pcls3._14vI(); + m_m_137II = _pcls3._14vI(); + //if(m_m_137II != 45 || m_m_146II != 2 && m_m_146II != 3) + // throw new _cls128("Unsupported class file version " + m_m_137II + "." + m_m_146II); + int i = _pcls3._14vI(); + m_m_118a2a2 = new _cls2[i]; + for(int j = 1; j < i; j += m_m_118a2a2[j]._82vI()) + m_m_118a2a2[j] = _cls2._9532(_pcls3, this); + + m_m_066 = new _cls6(_pcls3); + m_m_14722 = m_m_118a2a2[_pcls3._14vI()]; + String s1 = m_m_14722.toString(); + int k = s1.lastIndexOf('.'); + if(k >= 0) + { + m_m_142StringString = s1.substring(0, k); + _139StringV(m_m_142StringString); + } + _139StringV("java.lang"); + _125vV(); + m_m_13222 = m_m_118a2a2[_pcls3._14vI()]; + int l = _pcls3._14vI(); + m_m_123a2a2 = new _cls2[l]; + for(int i1 = 0; i1 < l; i1++) + m_m_123a2a2[i1] = m_m_118a2a2[_pcls3._14vI()]; + + int j1 = _pcls3._14vI(); + m_m_124a7a7 = new _cls7[j1]; + for(int k1 = 0; k1 < j1; k1++) + m_m_124a7a7[k1] = new _cls7(_pcls3, this); + + int l1 = _pcls3._14vI(); + m_m_122a72a72 = new _cls72[l1]; + for(int i2 = 0; i2 < l1; i2++) + m_m_122a72a72[i2] = new _cls72(_pcls3, this); + + int j2 = _pcls3._14vI(); + for(int k2 = 0; k2 < j2; k2++) + { + String s2 = m_m_118a2a2[_pcls3._14vI()].toString(); + int l2 = _pcls3.readInt(); + if(s2.equals("SourceFile")) + { + m_m_14922 = m_m_118a2a2[_pcls3._14vI()]; + } else + { + err.println("Ignoring class attribute " + s2); + _pcls3.skip(l2); + } + } + + } + + public void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1.writeInt(0xcafebabe); + _pcls1._4IV(3); + _pcls1._4IV(45); + int i = m_m_118a2a2.length; + _pcls1._4IV(i); + for(int j = 1; j < i; j += m_m_118a2a2[j]._82vI()) + m_m_118a2a2[j]._61V(_pcls1); + + m_m_066._61V(_pcls1); + _121V(_pcls1, m_m_14722); + _121V(_pcls1, m_m_13222); + int k = m_m_123a2a2.length; + _pcls1._4IV(k); + for(int l = 0; l < k; l++) + _121V(_pcls1, m_m_123a2a2[l]); + + int i1 = m_m_124a7a7.length; + _pcls1._4IV(i1); + for(int j1 = 0; j1 < i1; j1++) + m_m_124a7a7[j1]._61V(_pcls1); + + int k1 = m_m_122a72a72.length; + _pcls1._4IV(k1); + for(int l1 = 0; l1 < k1; l1++) + m_m_122a72a72[l1]._61V(_pcls1); + + int i2 = 0; + if(m_m_14922 != null) + i2++; + _pcls1._4IV(i2); + if(m_m_14922 != null) + { + _121V(_pcls1, _8String2("SourceFile")); + _pcls1.writeInt(2); + _121V(_pcls1, m_m_14922); + } + _pcls1.close(); + } + + _cls2 _9I2(int i) + { + return m_m_118a2a2[i]; + } + + _cls2 _932(_cls3 _pcls3) + throws IOException + { + return _9I2(_pcls3._14vI()); + } + + void _139StringV(String s) + { + for(int i = 0; i < m_m_129VectorVector.size(); i++) + if(s.equals((String)m_m_129VectorVector.elementAt(i))) + return; + + m_m_129VectorVector.addElement(s); + } + + void _141StringV(String s) + { + s = s.replace('/', '.'); + if(s.lastIndexOf('.') < 0) + { + String s1 = (String)m_m_128HashtableHashtable.get(s); + if(s1 != null && !s1.equals("")) + m_m_148HashtableHashtable.remove(s1); + m_m_128HashtableHashtable.put(s, ""); + return; + } + s = _101StringString(s); + if(s.lastIndexOf('.') >= 0) + { + String s2 = s.substring(s.lastIndexOf('.') + 1); + String s3 = (String)m_m_128HashtableHashtable.get(s2); + if(s3 != null) + { + if(!s3.equals("")) + { + m_m_148HashtableHashtable.remove(s3); + m_m_128HashtableHashtable.put(s2, ""); + return; + } + } else + { + m_m_148HashtableHashtable.put(s, s2); + m_m_128HashtableHashtable.put(s2, s); + } + } + } + + void _102IV(int i) + { + m_m_120HashtableHashtable.put(new Integer(i), "C"); + } + + void _145IV(int i) + { + m_m_120HashtableHashtable.put(new Integer(i), "T"); + } + + void _125vV() + { + for(Enumeration enumeration = m_m_120HashtableHashtable.keys(); enumeration.hasMoreElements();) + { + Integer integer = (Integer)enumeration.nextElement(); + String s = (String)m_m_120HashtableHashtable.get(integer); + String s1 = _9I2(integer.intValue()).toString(); + if(s.equals("C")) + _141StringV(s1); + else + if(s1.startsWith("L")) + _141StringV(s1.substring(1, s1.length() - 1)); + } + + } + + String _101StringString(String s) + { + s = s.replace('/', '.'); + int i = s.lastIndexOf('.'); + if(i < 0) + return s; + String s1 = s.substring(0, i); + String s2 = s.substring(i + 1); + for(int j = 0; j < m_m_129VectorVector.size(); j++) + if(s1.equals((String)m_m_129VectorVector.elementAt(j))) + return s2; + + s2 = (String)m_m_148HashtableHashtable.get(s); + if(s2 != null) + return s2; + else + return s; + } + + _cls2 _76v2() + { + return m_m_14722; + } + + _cls7 _15027(_cls2 _pcls2) + { + if(_pcls2._56v2() != m_m_14722) + return null; + String s = _pcls2._18vString(); + String s1 = _pcls2._81vString(); + for(int i = 0; i < m_m_124a7a7.length; i++) + if(m_m_124a7a7[i]._18vString().equals(s) && m_m_124a7a7[i]._7vString().equals(s1)) + return m_m_124a7a7[i]; + + return null; + } + + public void _39vV() + { + for(int i = 0; i < m_m_122a72a72.length; i++) + m_m_122a72a72[i]._39vV(); + + } + + private void _133PrintStreamV(PrintStream printstream) + { + boolean flag = false; + Vector vector = new Vector(); + for(Enumeration enumeration = m_m_148HashtableHashtable.keys(); enumeration.hasMoreElements();) + { + String s = (String)enumeration.nextElement(); + int i; + for(i = 0; i < vector.size(); i++) + if(s.compareTo((String)vector.elementAt(i)) < 0) + break; + + if(i < vector.size()) + vector.insertElementAt(s, i); + else + vector.addElement(s); + } + + byte byte0 = 2; + String s1 = ""; + int j = 0; + for(int k = 0; k < vector.size(); k++) + { + String s2 = (String)vector.elementAt(k); + String s3 = s2.substring(0, s2.lastIndexOf('.')); + if(s3.equals(s1)) + { + if(++j > byte0) + { + if(j == byte0 + 1) + { + _139StringV(s3); + for(int j1 = 0; j1 < byte0; j1++) + vector.removeElementAt(k - byte0); + + k -= byte0; + } + vector.removeElementAt(k); + k--; + } + } else + { + s1 = s3; + j = 1; + } + } + + for(int l = 0; l < m_m_129VectorVector.size(); l++) + { + String s4 = (String)m_m_129VectorVector.elementAt(l); + if((m_m_142StringString == null || !s4.equals(m_m_142StringString)) && !s4.equals("java.lang")) + { + printstream.println("import " + s4 + ".*;"); + flag = true; + } + } + + for(int i1 = 0; i1 < vector.size(); i1++) + { + printstream.println("import " + vector.elementAt(i1) + ";"); + flag = true; + } + + if(flag) + printstream.println(); + } + + String _138StringString(String s) + { + String s1 = null; + if(s.indexOf('/') >= 0) + { + s1 = s.substring(0, s.lastIndexOf('/')); + s = s.substring(s.lastIndexOf('/') + 1, s.length()); + } + if((m_m_142StringString == null && s1 == null || m_m_142StringString != null && s1 != null && s1.replace('/', '.').equals(m_m_142StringString)) && !m_m_135HashtableHashtable.containsKey(s)) + { + String s2 = (String)m_m_119HashtableHashtable.get(s); + if(s2 == null) + { + s2 = String.valueOf(m_m_119HashtableHashtable.size()); + m_m_119HashtableHashtable.put(s, s2); + } + s = s2; + } + if(s1 != null) + s = s1 + '/' + s; + return s; + } + + String _136StringString(String s) + { + if(!m_m_143HashtableHashtable.containsKey(s)) + { + String s1 = (String)m_m_130HashtableHashtable.get(s); + if(s1 == null) + { + s1 = String.valueOf(m_m_130HashtableHashtable.size()); + m_m_130HashtableHashtable.put(s, s1); + } + s = s1; + } + return s; + } + + String _121StringString(String s) + { + StringBuffer stringbuffer = new StringBuffer(); + for(int i = 0; i < s.length(); i++) + if(s.charAt(i) == 'L') + { + int j; + for(j = i + 1; s.charAt(j) != ';'; j++); + stringbuffer.append("L" + _138StringString(s.substring(i + 1, j)) + ";"); + i = j; + } else + { + stringbuffer.append(s.charAt(i)); + } + + return stringbuffer.toString(); + } + + boolean _140StringZ(String s) + { + s = s.replace('/', '.'); + int i = s.lastIndexOf('.'); + if(i < 0) + return m_m_142StringString != null; + if(m_m_142StringString == null) + return true; + return !m_m_142StringString.equals(s.substring(0, i)); + } + + void _192V(_cls2 _pcls2, String s) + { + int i; + for(i = 1; i < m_m_118a2a2.length && m_m_118a2a2[i] != _pcls2; i += m_m_118a2a2[i]._82vI()); + if(_19IStringI(i, s) != i) + err.println("Conflicting usage of constant " + _pcls2.toString()); + } + + int _19IStringI(int i, String s) + { + if(m_m_127aStringaString[i] == null) + m_m_127aStringaString[i] = s; + if(m_m_127aStringaString[i].equals(s)) + return i; + if(m_m_144aIaI[i] != 0) + return _19IStringI(m_m_144aIaI[i], s); +// if(Obfuscator.m_m_debugZZ) +// System.out.println(m_m_118a2a2[i].getClass()._18vString() + " [" + i + "] " + m_m_118a2a2[i].toString() + " used as " + m_m_127aStringaString[i] + " as well as " + s + " -> new [" + m_m_118a2a2.length + "]"); + int j = m_m_118a2a2.length; + _cls2 a_lcls2[] = m_m_118a2a2; + m_m_118a2a2 = new _cls2[j + 1]; + for(int k = 0; k < j; k++) + m_m_118a2a2[k] = a_lcls2[k]; + + String as[] = m_m_127aStringaString; + m_m_127aStringaString = new String[j + 1]; + for(int l = 0; l < j; l++) + m_m_127aStringaString[l] = as[l]; + + int ai[] = m_m_144aIaI; + m_m_144aIaI = new int[j + 1]; + for(int i1 = 0; i1 < j; i1++) + m_m_144aIaI[i1] = ai[i1]; + + m_m_118a2a2[j] = ((_cls116)m_m_118a2a2[i])._131v116(); + m_m_127aStringaString[j] = s; + m_m_144aIaI[i] = j; + return j; + } + + public void _100HashtableHashtableV(Hashtable hashtable, Hashtable hashtable1, Hashtable hashtable2, Hashtable hashtable3) + { + m_m_135HashtableHashtable = hashtable; + m_m_143HashtableHashtable = hashtable1; + m_m_119HashtableHashtable = hashtable2; + m_m_130HashtableHashtable = hashtable3; +// if(Obfuscator.m_m_debugZZ) +// { +// for(int i = 1; i < m_m_118a2a2.length; i += m_m_118a2a2[i]._82vI()) +// System.out.println(i + ":" + m_m_118a2a2[i]._790String(this)); +// +// } + m_m_127aStringaString = new String[m_m_118a2a2.length]; + m_m_144aIaI = new int[m_m_118a2a2.length]; + _192V(m_m_14722, "class"); + _192V(m_m_13222, "class"); + _192V(_8String2("SourceFile"), "attribute"); + int j = m_m_124a7a7.length; + for(int k = 0; k < j; k++) + m_m_124a7a7[k]._19vV(); + + int l = m_m_122a72a72.length; + for(int i1 = 0; i1 < l; i1++) + m_m_122a72a72[i1]._19vV(); + + for(int j1 = 1; j1 < m_m_118a2a2.length; j1 += m_m_118a2a2[j1]._82vI()) + m_m_118a2a2[j1]._19vV(); + + for(int k1 = 1; k1 < m_m_118a2a2.length; k1 += m_m_118a2a2[k1]._82vI()) + m_m_118a2a2[k1]._1000V(this, m_m_127aStringaString[k1]); + + m_m_14922 = null; + } + + void _121V(_cls1 _pcls1, _cls2 _pcls2) + throws IOException + { + for(int i = 1; i < m_m_118a2a2.length; i += m_m_118a2a2[i]._82vI()) + if(m_m_118a2a2[i] == _pcls2) + { + _pcls1._4IV(i); + return; + } + + throw new IOException("Constant not found"); + } + + _cls2 _8String2(String s) + { + for(int i = 1; i < m_m_118a2a2.length; i += m_m_118a2a2[i]._82vI()) + if((m_m_118a2a2[i] instanceof _cls116) && m_m_118a2a2[i].toString().equals(s)) + return m_m_118a2a2[i]; + + return null; + } + + public void _17PrintStreamV(PrintStream printstream) + { + printstream.println("/* aNNiMON 2010 */"); + printstream.println("/* Decompiled by Mocha from " + m_m_134StringString + " */"); + if(m_m_14922 != null) + printstream.println("/* Originally compiled from " + m_m_14922 + " */"); + printstream.println(); + if(m_m_142StringString != null) + { + printstream.println("package " + m_m_142StringString + ";"); + printstream.println(); + } + _133PrintStreamV(printstream); + printstream.print(m_m_066); + if(m_m_066._126vZ()) + printstream.print("interface "); + else + printstream.print("class "); + printstream.print(m_m_14722); + String s = m_m_13222.toString(); + if(!s.equals("Object")) + printstream.print(" extends " + s); + if(m_m_123a2a2.length > 0) + { + printstream.print(" implements "); + for(int i = 0; i < m_m_123a2a2.length; i++) + { + if(i > 0) + printstream.print(", "); + printstream.print(m_m_123a2a2[i]); + } + + } + printstream.println(); + printstream.println("{"); + for(int j = 0; j < m_m_124a7a7.length; j++) + m_m_124a7a7[j]._17PrintStreamV(printstream); + + if(m_m_124a7a7.length > 0 && m_m_122a72a72.length > 0) + printstream.println(); + for(int k = 0; k < m_m_122a72a72.length; k++) + { + m_m_122a72a72[k]._17PrintStreamV(printstream); + if(k < m_m_122a72a72.length - 1 && !m_m_122a72a72[k]._40vZ()) + printstream.println(); + } + + printstream.println("}"); + } +} diff --git a/src/modules/mocha/_cls1.java b/src/modules/mocha/_cls1.java new file mode 100644 index 0000000..0d8e118 --- /dev/null +++ b/src/modules/mocha/_cls1.java @@ -0,0 +1,32 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +public class _cls1 extends DataOutputStream +{ + + public _cls1(OutputStream outputstream) + { + super(outputstream); + } + + public void _308IV(int i) + throws IOException + { + if(i > 127) + i -= 256; + writeByte(i); + } + + public void _4IV(int i) + throws IOException + { + if(i > 32767) + i -= 0x10000; + writeShort(i); + } +} diff --git a/src/modules/mocha/_cls10.java b/src/modules/mocha/_cls10.java new file mode 100644 index 0000000..1a494ef --- /dev/null +++ b/src/modules/mocha/_cls10.java @@ -0,0 +1,51 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls26, _cls25, +// _cls23, _cls27, _cls33, _cls35, +// _cls40, _cls19, _cls49, _cls47, +// _cls38, _cls30, _cls37, _cls54, +// _cls39, _cls48, _cls11, _cls46, +// _cls28, _cls12, _cls53, _cls50, +// _cls55, _cls8, _cls22, _cls17, +// _cls13, _cls51, _cls45, _cls21, +// _cls9, _cls18, _cls43, _cls69 + +class _cls10 extends _cls31 +{ + + _cls10(int i, int j) + { + super(i, j); + } + + public int _22vI() + { + return 1; + } + + public int _117vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + String s = "new(" + _pcls23._113v61().toString() + ")"; + return _pcls23._29v23()._716123(new _cls69("A", s)); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("new \"...\""); + } +} diff --git a/src/modules/mocha/_cls100.java b/src/modules/mocha/_cls100.java new file mode 100644 index 0000000..1c94407 --- /dev/null +++ b/src/modules/mocha/_cls100.java @@ -0,0 +1,142 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls78, _cls102, _cls95, _cls77, +// _cls98, _cls92, _cls75, _cls104, +// _cls87, _cls73, _cls96, _cls103, +// _cls105, _cls76, _cls91, _cls4, +// _cls84, _cls131, _cls88, _cls97, +// _cls80, _cls81, _cls83, _cls85, +// _cls90, _cls93, _cls79, _cls99, +// _cls106, _cls86, _cls74, _cls101, +// _cls82, _cls89, _cls94, _cls129 + +class _cls100 extends _cls78 +{ + + _cls78 m_8478; + _cls89 m_288a89[]; + _cls78 m_28678; + + _cls100(_cls78 _pcls78, _cls89 a_pcls89[], _cls78 _pcls78_1) + { + m_8478 = _pcls78; + m_288a89 = a_pcls89; + m_28678 = _pcls78_1; + _497475(_pcls78); + _527475(_pcls78); + } + + public void _197vV() + { + super.m_285I++; + m_8478._197vV(); + } + + public void _196vV() + { + super.m_285I--; + m_8478._196vV(); + } + + _cls78 _289v78() + { + return m_8478; + } + + _cls89[] _287va89() + { + return m_288a89; + } + + _cls78 _284v78() + { + return m_28678; + } + + public int _94vI() + { + return m_8478._94vI(); + } + + public int _48vI() + { + int i = m_8478._48vI(); + if(m_288a89 != null) + { + for(int j = 0; j < m_288a89.length; j++) + if(i < m_288a89[j]._48vI()) + i = m_288a89[j]._48vI(); + + } + if(m_28678 != null && i < m_28678._48vI()) + i = m_28678._48vI(); + return i; + } + + public void _152129V(_cls129 _pcls129) + { + _cls131 _lcls131 = new _cls131(_pcls129, _94vI(), _48vI()); + m_8478._152129V(_lcls131); + if(m_288a89 != null) + { + for(int i = 0; i < m_288a89.length; i++) + m_288a89[i]._152129V(_lcls131); + + } + if(m_28678 != null) + m_28678._152129V(_lcls131); + } + + public void _2vV() + { + m_8478._2vV(); + if(m_288a89 != null) + { + for(int i = 0; i < m_288a89.length; i++) + m_288a89[i]._2vV(); + + } + if(m_28678 != null) + m_28678._2vV(); + } + + public int _170vI() + { + int i = m_8478._170vI(); + if(m_288a89 != null) + { + for(int j = 0; j < m_288a89.length; j++) + i += m_288a89[j]._170vI(); + + } + if(m_28678 != null) + i += m_28678._170vI(); + return i; + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_cls75._50IString(i) + "try"); + printstream.println(_cls75._50IString(i) + "{"); + m_8478._17PrintStreamZV(printstream, i + 1, true); + printstream.println(_cls75._50IString(i) + "}"); + if(m_288a89 != null) + { + for(int j = 0; j < m_288a89.length; j++) + m_288a89[j]._17PrintStreamZV(printstream, i, true); + + } + if(m_28678 != null) + { + printstream.println(_cls75._50IString(i) + "finally"); + m_28678._17PrintStreamZV(printstream, i + 1, false); + } + } +} diff --git a/src/modules/mocha/_cls101.java b/src/modules/mocha/_cls101.java new file mode 100644 index 0000000..68cfb7a --- /dev/null +++ b/src/modules/mocha/_cls101.java @@ -0,0 +1,54 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls91, _cls77, _cls74, _cls79, +// _cls106, _cls76, _cls82, _cls93, +// _cls90, _cls80, _cls96, _cls84, +// _cls87, _cls85, _cls100, _cls75, +// _cls99, _cls103, _cls78, _cls4, +// _cls105, _cls98, _cls95, _cls97, +// _cls92, _cls104, _cls81, _cls86, +// _cls73, _cls83, _cls94, _cls102, +// _cls88, _cls89 + +class _cls101 extends _cls91 +{ + + _cls4 m_834; + + _cls101(_cls4 _pcls4, int i, int j) + { + int ai[] = { + i, j + }; + m_834 = _pcls4; + super.m_116aI = ai; + } + + public int _48vI() + { + return m_834._48vI(); + } + + public void _2vV() + { + m_834 = m_834._1String4("Z"); + m_834._2vV(); + } + + _cls4 _344v4() + { + return m_834; + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_cls75._50IString(i) + "if (" + m_834 + ") goto " + super.m_116aI[1] + " else " + super.m_116aI[0] + ";"); + } +} diff --git a/src/modules/mocha/_cls102.java b/src/modules/mocha/_cls102.java new file mode 100644 index 0000000..8c932e2 --- /dev/null +++ b/src/modules/mocha/_cls102.java @@ -0,0 +1,65 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls78, _cls95, _cls77, _cls98, +// _cls92, _cls75, _cls104, _cls87, +// _cls73, _cls96, _cls103, _cls105, +// _cls100, _cls76, _cls91, _cls4, +// _cls84, _cls88, _cls97, _cls80, +// _cls81, _cls83, _cls85, _cls90, +// _cls93, _cls79, _cls99, _cls106, +// _cls86, _cls74, _cls101, _cls82, +// _cls89, _cls94, _cls129 + +class _cls102 extends _cls78 +{ + + _cls4 m_1694; + _cls78 m_8478; + + _cls102(_cls4 _pcls4, _cls78 _pcls78) + { + m_1694 = _pcls4; + m_8478 = _pcls78; + _497475(_pcls4); + _527475(_pcls78); + } + + public int _94vI() + { + return m_1694._94vI(); + } + + public int _48vI() + { + return m_8478._48vI(); + } + + public void _152129V(_cls129 _pcls129) + { + m_8478._152129V(_pcls129); + } + + public void _2vV() + { + m_1694._2vV(); + m_8478._2vV(); + } + + public int _170vI() + { + return m_8478._170vI(); + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_cls75._50IString(i) + "synchronized (" + m_1694 + ")"); + m_8478._17PrintStreamZV(printstream, i + 1, false); + } +} diff --git a/src/modules/mocha/_cls103.java b/src/modules/mocha/_cls103.java new file mode 100644 index 0000000..4bfb1c5 --- /dev/null +++ b/src/modules/mocha/_cls103.java @@ -0,0 +1,238 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; +import java.util.Enumeration; +import java.util.Hashtable; + +// Referenced classes of package mocha: +// _cls102, _cls95, _cls77, _cls98, +// _cls92, _cls75, _cls104, _cls87, +// _cls73, _cls96, _cls105, _cls100, +// _cls76, _cls91, _cls4, _cls84, +// _cls88, _cls97, _cls80, _cls81, +// _cls83, _cls85, _cls122, Decompiler, +// _cls90, _cls93, _cls79, _cls99, +// _cls106, _cls86, _cls74, _cls101, +// _cls82, _cls89, _cls78, _cls94, +// _cls108, _cls71 + +class _cls103 +{ + + protected _cls74 m_246a74[]; + protected Hashtable m_244Hashtable; + protected Hashtable m_251Hashtable; + protected _cls108 m_41a108[]; + protected _cls71 m_11271; + + _cls103(int i, _cls71 _pcls71) + { + m_244Hashtable = new Hashtable(); + m_251Hashtable = new Hashtable(); + m_246a74 = new _cls74[i]; + m_11271 = _pcls71; + } + + void _253a108V(_cls108 a_pcls108[]) + { + m_41a108 = a_pcls108; + } + + _cls108[] _243va108() + { + return m_41a108; + } + + _cls71 _257v71() + { + return m_11271; + } + + _cls74 _254I74(int i) + { + return m_246a74[i]; + } + + _cls74 _2497474(_cls74 _pcls74) + { + if(_pcls74 != null) + m_246a74[_pcls74._155vI()] = _pcls74; + return _pcls74; + } + + void _242IV(int i) + { + m_246a74[i] = null; + } + + void _24274V(_cls74 _pcls74) + { + if(_pcls74 != null) + m_246a74[_pcls74._155vI()] = null; + } + + _cls82 _178v82() + { + return new _cls82(m_246a74); + } + + _cls74 _2487474(_cls74 _pcls74) + { + if(_pcls74._198vI() != 1) + return null; + int i = _pcls74._155vI(); + for(int j = i - 1; j >= 0; j--) + { + _cls74 _lcls74 = m_246a74[j]; + if(_lcls74 != null) + { + for(int l = 0; l < _lcls74._25vI(); l++) + if(_lcls74._26II(l) == i) + return _lcls74; + + } + } + + for(int k = i + 1; k < m_246a74.length; k++) + { + _cls74 _lcls74_1 = m_246a74[k]; + if(_lcls74_1 != null) + { + for(int i1 = 0; i1 < _lcls74_1._25vI(); i1++) + if(_lcls74_1._26II(i1) == i) + return _lcls74_1; + + } + } + + return null; + } + + _cls74 _2397474(_cls74 _pcls74) + { + if(_pcls74._25vI() != 1) + return null; + _cls74 _lcls74 = m_246a74[_pcls74._26II(0)]; + if(_lcls74 == null || _lcls74._198vI() != 1) + return null; + else + return _lcls74; + } + + int _258II(int i) + { + for(i++; i < m_246a74.length && m_246a74[i] == null; i++); + if(i < m_246a74.length) + return i; + else + return -1; + } + + void _250I122V(int i, _cls122 _pcls122) + { + m_244Hashtable.put(new Integer(i), _pcls122); + } + + _cls122 _238I122(int i) + { + return (_cls122)m_244Hashtable.get(new Integer(i)); + } + + _cls122 _252I122(int i) + { + for(Enumeration enumeration = m_244Hashtable.elements(); enumeration.hasMoreElements();) + { + _cls122 _lcls122 = (_cls122)enumeration.nextElement(); + if(_lcls122._255IZ(i)) + return _lcls122; + } + + return null; + } + + void _256I122V(int i, _cls122 _pcls122) + { + m_251Hashtable.put(new Integer(i), _pcls122); + } + + _cls122 _240I122(int i) + { + return (_cls122)m_251Hashtable.get(new Integer(i)); + } + + _cls122 _241I122(int i) + { + for(Enumeration enumeration = m_251Hashtable.elements(); enumeration.hasMoreElements();) + { + _cls122 _lcls122 = (_cls122)enumeration.nextElement(); + if(_lcls122._255IZ(i)) + return _lcls122; + } + + return null; + } + + int _247III(int i, int j) + { + if(j < 0) + j = m_246a74.length; + int k; + for(k = i + 1; k < j && m_246a74[k] != null; k--); + if(k >= j) + { + System.out.println("insertFragmentForward " + i + " - " + j + " in " + m_246a74.length + " failed"); + for(int l = i; l <= j; l++) + System.out.println(l + ": " + m_246a74[l].getClass().getName().substring(17)); + + } + if(k < j) + return k; + else + return -1; + } + + int _245III(int i, int j) + { + if(j < 0) + j = m_246a74.length; + int k; + for(k = j - 1; k > i && m_246a74[k] != null; k--); + if(k <= i) + { + System.out.println("insertFragmentBackward " + i + " - " + j + " in " + m_246a74.length + " failed"); + for(int l = i; l <= j; l++) + System.out.println(l + ": " + m_246a74[l].getClass().getName().substring(17)); + + } + if(k > i) + return k; + else + return -1; + } + + void _17PrintStreamvV(PrintStream printstream, int i) + { + int j = -1; + for(int k = 0; k < m_246a74.length; k++) + if(m_246a74[k] != null) + { + if(Decompiler.m_debugZ) + { + if(j != k) + printstream.println(" [goto " + j + "]"); + if(m_246a74[k]._25vI() == 1) + j = m_246a74[k]._26II(0); + else + j = -1; + } + m_246a74[k]._17PrintStreamZV(printstream, i, true); + } + + if(Decompiler.m_debugZ && j >= 0) + printstream.println(" [goto " + j + "]"); + } +} diff --git a/src/modules/mocha/_cls104.java b/src/modules/mocha/_cls104.java new file mode 100644 index 0000000..730d1ab --- /dev/null +++ b/src/modules/mocha/_cls104.java @@ -0,0 +1,41 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls76, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls82, +// _cls93, _cls90, _cls80, _cls96, +// _cls84, _cls87, _cls85, _cls100, +// _cls75, _cls99, _cls103, _cls78, +// _cls4, _cls105, _cls98, _cls95, +// _cls97, _cls92, _cls81, _cls86, +// _cls73, _cls83, _cls94, _cls102, +// _cls88, _cls89 + +class _cls104 extends _cls76 +{ + + String m_302String; + + _cls104(_cls4 _pcls4, String s) + { + super(_pcls4); + m_302String = s; + } + + public void _2vV() + { + super.m_724 = super.m_724._1String4(m_302String); + super.m_724._2vV(); + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_cls75._50IString(i) + "return " + this + ";"); + } +} diff --git a/src/modules/mocha/_cls105.java b/src/modules/mocha/_cls105.java new file mode 100644 index 0000000..a568fb4 --- /dev/null +++ b/src/modules/mocha/_cls105.java @@ -0,0 +1,119 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; +import java.util.Vector; + +// Referenced classes of package mocha: +// _cls73, _cls102, _cls95, _cls77, +// _cls98, _cls92, _cls75, _cls104, +// _cls87, _cls129, _cls96, _cls103, +// _cls100, _cls76, _cls91, _cls4, +// _cls84, _cls88, _cls97, _cls124, +// _cls80, _cls81, _cls83, _cls85, +// _cls90, _cls93, _cls79, _cls99, +// _cls106, _cls86, _cls74, _cls101, +// _cls82, _cls89, _cls78, _cls94, +// _cls122 + +class _cls105 extends _cls73 +{ + + _cls76 m_15776; + _cls76 m_15476; + _cls129 m_153129; + + _cls105(_cls76 _pcls76, _cls4 _pcls4, _cls76 _pcls76_1, _cls78 _pcls78, _cls122 _pcls122, _cls122 _pcls122_1) + { + super(_pcls4, _pcls78, _pcls122, _pcls122_1); + m_15776 = _pcls76; + m_15476 = _pcls76_1; + } + + public int _94vI() + { + if(m_15776 != null) + return m_15776._94vI(); + if(super.m_8478 != null) + return super.m_8478._94vI(); + else + return _155vI(); + } + + public void _152129V(_cls129 _pcls129) + { + m_153129 = new _cls129(_pcls129, _94vI(), _48vI()); + super._152129V(m_153129); + } + + public void _2vV() + { + if(m_15776 != null) + m_15776._2vV(); + if(m_15476 != null) + m_15476._2vV(); + super._2vV(); + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + _158vV(); + _85PrintStreamvV(printstream, i); + if(m_153129 != null) + m_153129._17PrintStreamStringV(printstream, i, "for"); + printstream.print(_cls75._50IString(i) + "for ("); + if(m_15776 != null) + printstream.print(m_15776); + printstream.print("; " + super.m_834 + "; "); + if(m_15476 != null) + printstream.print(m_15476); + printstream.print(")"); + if(super.m_8478 != null) + { + printstream.println(); + super.m_8478._17PrintStreamZV(printstream, i + 1, false); + return; + } else + { + printstream.println(" /* null body */ ;"); + return; + } + } + + void _158vV() + { + if(m_15776 != null) + { + Vector vector = m_153129._156vVector(); + for(int i = 0; i < vector.size();) + { + _cls124 _lcls124 = (_cls124)vector.elementAt(i); + int j = _lcls124._159vI(); + if(m_15776._48vI() == j - 1) + { + _cls4 _lcls4 = m_15776._78v4(); + if(_lcls4 instanceof _cls92) + { + _cls125 _lcls125 = _lcls124._111I125(j); + _cls4 _lcls4_1 = _lcls4._65I4(0); + _cls95 _lcls95 = new _cls95(_lcls125, _lcls4_1); + _lcls95._497475(m_15776); + _lcls95._527475(m_15776); + m_15776 = _lcls95; + _lcls124 = null; + } + } + if(_lcls124 == null) + vector.removeElementAt(i); + else + i++; + } + + } + if(m_153129._156vVector().size() > 0) + err.println("Declarators could not be incorporated in for statement"); + } +} diff --git a/src/modules/mocha/_cls106.java b/src/modules/mocha/_cls106.java new file mode 100644 index 0000000..81a27ca --- /dev/null +++ b/src/modules/mocha/_cls106.java @@ -0,0 +1,128 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls78, _cls102, _cls95, _cls77, +// _cls98, _cls92, _cls75, _cls104, +// _cls87, _cls73, _cls96, _cls103, +// _cls105, _cls100, _cls76, _cls91, +// _cls4, _cls84, _cls131, _cls88, +// _cls97, _cls80, _cls81, _cls83, +// _cls85, _cls90, _cls93, _cls79, +// _cls99, _cls86, _cls74, _cls101, +// _cls82, _cls89, _cls94, _cls129, +// _cls122 + +class _cls106 extends _cls78 +{ + + _cls4 m_202a4[]; + _cls78 m_201a78[]; + + _cls106(_cls4 _pcls4, _cls78 _pcls78) + { + m_202a4 = new _cls4[1]; + m_201a78 = new _cls78[2]; + m_202a4[0] = _pcls4; + m_201a78[0] = _pcls78; + m_201a78[1] = null; + } + + _cls106(_cls4 _pcls4, _cls78 _pcls78, _cls78 _pcls78_1) + { + if(_pcls78_1 != null && (_pcls78_1 instanceof _cls106)) + { + _cls106 _lcls106 = (_cls106)_pcls78_1; + int i = _lcls106.m_202a4.length; + m_202a4 = new _cls4[i + 1]; + m_201a78 = new _cls78[i + 2]; + for(int j = 0; j < i; j++) + m_202a4[j + 1] = _lcls106.m_202a4[j]; + + for(int k = 0; k <= i; k++) + m_201a78[k + 1] = _lcls106.m_201a78[k]; + + } else + { + m_202a4 = new _cls4[1]; + m_201a78 = new _cls78[2]; + m_201a78[1] = _pcls78_1; + } + m_202a4[0] = _pcls4; + m_201a78[0] = _pcls78; + } + + public int _48vI() + { + int i = _94vI(); + for(int j = 0; j < m_201a78.length; j++) + if(m_201a78[j] != null && i < m_201a78[j]._48vI()) + i = m_201a78[j]._48vI(); + + return i; + } + + public void _152129V(_cls129 _pcls129) + { + _cls131 _lcls131 = new _cls131(_pcls129, _94vI(), _48vI()); + for(int i = 0; i < m_201a78.length; i++) + if(m_201a78[i] != null) + m_201a78[i]._152129V(_lcls131); + + } + + public void _2vV() + { + for(int i = 0; i < m_202a4.length; i++) + { + m_202a4[i] = m_202a4[i]._1String4("Z"); + m_202a4[i]._2vV(); + } + + for(int j = 0; j < m_201a78.length; j++) + if(m_201a78[j] != null) + m_201a78[j]._2vV(); + + } + + boolean _193122vZ(_cls122 _pcls122, int i) + { + boolean flag = false; + for(int j = 0; j < m_201a78.length; j++) + if(m_201a78[j] != null && m_201a78[j]._193122vZ(_pcls122, i)) + flag = true; + + return flag; + } + + public int _170vI() + { + int i = 0; + for(int j = 0; j < m_201a78.length; j++) + if(m_201a78[j] != null) + i += m_201a78[j]._170vI(); + + return i; + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_cls75._50IString(i) + "if (" + m_202a4[0] + ")"); + m_201a78[0]._17PrintStreamZV(printstream, i + 1, false); + for(int j = 1; j < m_202a4.length; j++) + { + printstream.println(_cls75._50IString(i) + "else if (" + m_202a4[j] + ")"); + m_201a78[j]._17PrintStreamZV(printstream, i + 1, false); + } + if(m_201a78[m_202a4.length] != null) + { + printstream.println(_cls75._50IString(i) + "else"); + m_201a78[m_202a4.length]._17PrintStreamZV(printstream, i + 1, false); + } + } +} diff --git a/src/modules/mocha/_cls107.java b/src/modules/mocha/_cls107.java new file mode 100644 index 0000000..e9021d3 --- /dev/null +++ b/src/modules/mocha/_cls107.java @@ -0,0 +1,28 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls108 + +class _cls107 extends _cls108 +{ + + _cls107(int i, int j, int k) + { + super(i, j, k); + } + + String _61vString() + { + return ""; + } + + String _55vString() + { + return ""; + } +} diff --git a/src/modules/mocha/_cls108.java b/src/modules/mocha/_cls108.java new file mode 100644 index 0000000..ba14e46 --- /dev/null +++ b/src/modules/mocha/_cls108.java @@ -0,0 +1,90 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.IOException; + +// Referenced classes of package mocha: +// _cls107, _cls1, _cls3, _cls0, +// _cls2 + +class _cls108 +{ + + int m_60I; + int m_63I; + int m_58I; + _cls2 m_642; + + _cls108(int i, int j, int k) + { + m_60I = j; + m_63I = k; + m_58I = i; + } + + _cls108(_cls3 _pcls3, _cls0 _pcls0) + throws IOException + { + m_60I = _pcls3._14vI(); + m_63I = _pcls3._14vI(); + m_58I = _pcls3._14vI(); + m_642 = _pcls0._932(_pcls3); + } + + void _61V(_cls1 _pcls1, _cls0 _pcls0) + throws IOException + { + _pcls1._4IV(m_60I); + _pcls1._4IV(m_63I); + _pcls1._4IV(m_58I); + if(m_642 == null) + { + _pcls1._4IV(0); + return; + } else + { + _pcls0._121V(_pcls1, m_642); + return; + } + } + + void _190V(_cls0 _pcls0) + { + if(m_642 != null) + _pcls0._192V(m_642, "class"); + } + + int _57vI() + { + return m_58I; + } + + int _59vI() + { + return m_60I; + } + + int _62vI() + { + return m_63I; + } + + String _61vString() + { + if(m_642 == null) + return ""; + else + return "L" + m_642._56v2().toString() + ";"; + } + + String _55vString() + { + if(m_642 == null) + return ""; + else + return m_642.toString(); + } +} diff --git a/src/modules/mocha/_cls109.java b/src/modules/mocha/_cls109.java new file mode 100644 index 0000000..dc732b4 --- /dev/null +++ b/src/modules/mocha/_cls109.java @@ -0,0 +1,120 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// _cls2, _cls120, _cls111, _cls119, +// _cls112, _cls115, _cls114, _cls116, +// _cls121, _cls113, _cls118, _cls110, +// _cls117, _cls3, _cls1, _cls0 + +class _cls109 extends _cls2 +{ + + int m_80I; + String m_43String; + + _cls109(_cls3 _pcls3) + throws IOException + { + m_80I = _pcls3.readInt(); + m_43String = "I"; + } + + void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1.writeByte(3); + _pcls1.writeInt(m_80I); + } + + String _81vString() + { + return m_43String; + } + + void _1StringV(String s) + { + m_43String = s; + } + + public String toString() + { + if(m_43String.equals("Z")) + if(m_80I != 0) + return "true"; + else + return "false"; + if(m_43String.equals("C")) + { + StringBuffer stringbuffer = new StringBuffer(); + stringbuffer.append('\''); + switch(m_80I) + { + case 0: // '\0' + stringbuffer.append("\\0"); + break; + + case 8: // '\b' + stringbuffer.append("\\b"); + break; + + case 9: // '\t' + stringbuffer.append("\\t"); + break; + + case 10: // '\n' + stringbuffer.append("\\n"); + break; + + case 12: // '\f' + stringbuffer.append("\\f"); + break; + + case 13: // '\r' + stringbuffer.append("\\r"); + break; + + case 39: // '\'' + stringbuffer.append("\\'"); + break; + + case 92: // '\\' + stringbuffer.append("\\\\"); + break; + + default: + if(m_80I < 32) + { + String s; + for(s = Integer.toString(m_80I, 8); s.length() < 3; s = "0" + s); + stringbuffer.append("\\" + s); + break; + } + if(m_80I < 127) + { + stringbuffer.append((char)m_80I); + break; + } + String s1; + for(s1 = Integer.toString(m_80I, 16); s1.length() < 4; s1 = "0" + s1); + stringbuffer.append("\\u" + s1); + break; + } + stringbuffer.append('\''); + return stringbuffer.toString(); + } else + { + return String.valueOf(m_80I); + } + } + + String _790String(_cls0 _pcls0) + { + return "Integer " + m_80I; + } +} diff --git a/src/modules/mocha/_cls11.java b/src/modules/mocha/_cls11.java new file mode 100644 index 0000000..06e1982 --- /dev/null +++ b/src/modules/mocha/_cls11.java @@ -0,0 +1,45 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls19, _cls46, _cls27, _cls25, +// _cls31, _cls42, _cls18, _cls52, +// _cls35, _cls53, _cls43, _cls20, +// _cls14, _cls36, _cls26, _cls48, +// _cls45, _cls13, _cls54, _cls38, +// _cls50, _cls28, _cls41, _cls9, +// _cls16, _cls34, _cls44, _cls17, +// _cls37, _cls8, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls23, +// _cls29, _cls32, _cls10 + +class _cls11 extends _cls19 +{ + + _cls11(int i, int j) + { + super(i, j); + } + + public int _22vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._29v23(); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("throw"); + } +} diff --git a/src/modules/mocha/_cls110.java b/src/modules/mocha/_cls110.java new file mode 100644 index 0000000..1c81f18 --- /dev/null +++ b/src/modules/mocha/_cls110.java @@ -0,0 +1,37 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.DataOutputStream; +import java.io.IOException; + +// Referenced classes of package mocha: +// _cls121, _cls1, _cls111, _cls115, +// _cls113, _cls120, _cls0, _cls2, +// _cls114, _cls112, _cls119, _cls109, +// _cls116, _cls118, _cls117, _cls3 + +class _cls110 extends _cls121 +{ + + _cls110(_cls3 _pcls3, _cls0 _pcls0) + throws IOException + { + super(_pcls3, _pcls0); + } + + void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1.writeByte(11); + _pcls1._4IV(super.m_103I); + _pcls1._4IV(super.m_151I); + } + + String _790String(_cls0 _pcls0) + { + return "InterfaceMethodRef(" + super.m_103I + ":" + _pcls0._9I2(super.m_103I)._790String(_pcls0) + ", " + super.m_151I + ":" + _pcls0._9I2(super.m_151I)._790String(_pcls0) + ")"; + } +} diff --git a/src/modules/mocha/_cls111.java b/src/modules/mocha/_cls111.java new file mode 100644 index 0000000..0d5ad2a --- /dev/null +++ b/src/modules/mocha/_cls111.java @@ -0,0 +1,77 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.DataOutputStream; +import java.io.IOException; + +// Referenced classes of package mocha: +// _cls2, _cls1, _cls115, _cls3, +// _cls110, _cls113, _cls120, _cls0, +// _cls114, _cls112, _cls119, _cls109, +// _cls116, _cls118, _cls121, _cls117 + +class _cls111 extends _cls2 +{ + + _cls0 m_160; + int m_173I; + int m_172I; + + _cls111(_cls3 _pcls3, _cls0 _pcls0) + throws IOException + { + m_160 = _pcls0; + m_173I = _pcls3._14vI(); + m_172I = _pcls3._14vI(); + _pcls0._145IV(m_172I); + } + + void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1.writeByte(12); + _pcls1._4IV(m_173I); + _pcls1._4IV(m_172I); + } + + void _19vV() + { + m_172I = m_160._19IStringI(m_172I, "signature"); + } + + void _171IV(int i) + { + if(m_160._140StringZ(m_160._9I2(i)._56v2().toString())) + { + m_173I = m_160._19IStringI(m_173I, "external member"); + return; + } else + { + m_173I = m_160._19IStringI(m_173I, "internal member"); + return; + } + } + + void _1000V(_cls0 _pcls0, String s) + { + _104StringV(s, "none"); + } + + String _18vString() + { + return m_160._9I2(m_173I).toString(); + } + + String _81vString() + { + return m_160._9I2(m_172I).toString(); + } + + String _790String(_cls0 _pcls0) + { + return "NameAndType(" + m_173I + ":" + _pcls0._9I2(m_173I)._790String(_pcls0) + ", " + m_172I + ":" + _pcls0._9I2(m_172I)._790String(_pcls0) + ")"; + } +} diff --git a/src/modules/mocha/_cls112.java b/src/modules/mocha/_cls112.java new file mode 100644 index 0000000..d8795ab --- /dev/null +++ b/src/modules/mocha/_cls112.java @@ -0,0 +1,56 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.IOException; + +// Referenced classes of package mocha: +// _cls2, _cls111, _cls115, _cls3, +// _cls110, _cls113, _cls120, _cls0, +// _cls114, _cls119, _cls109, _cls116, +// _cls118, _cls121, _cls117 + +abstract class _cls112 extends _cls2 +{ + + _cls0 m_160; + int m_103I; + int m_151I; + + _cls112(_cls3 _pcls3, _cls0 _pcls0) + throws IOException + { + m_160 = _pcls0; + m_103I = _pcls3._14vI(); + m_151I = _pcls3._14vI(); + } + + void _19vV() + { + m_160._19IStringI(m_103I, "class"); + _cls111 _lcls111 = (_cls111)m_160._9I2(m_151I); + _lcls111._171IV(m_103I); + } + + void _1000V(_cls0 _pcls0, String s) + { + _104StringV(s, "member"); + } + + _cls2 _56v2() + { + return m_160._9I2(m_103I); + } + + String _18vString() + { + return m_160._9I2(m_151I)._18vString(); + } + + public String toString() + { + return _18vString(); + } +} diff --git a/src/modules/mocha/_cls113.java b/src/modules/mocha/_cls113.java new file mode 100644 index 0000000..48cdcc6 --- /dev/null +++ b/src/modules/mocha/_cls113.java @@ -0,0 +1,52 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// _cls2, _cls111, _cls115, _cls110, +// _cls120, _cls114, _cls112, _cls119, +// _cls109, _cls116, _cls118, _cls121, +// _cls117, _cls3, _cls1, _cls0 + +class _cls113 extends _cls2 +{ + + long m_80J; + + _cls113(_cls3 _pcls3) + throws IOException + { + m_80J = _pcls3.readLong(); + } + + void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1.writeByte(5); + _pcls1.writeLong(m_80J); + } + + int _82vI() + { + return 2; + } + + String _81vString() + { + return "J"; + } + + public String toString() + { + return String.valueOf(m_80J); + } + + String _790String(_cls0 _pcls0) + { + return "Long " + m_80J; + } +} diff --git a/src/modules/mocha/_cls114.java b/src/modules/mocha/_cls114.java new file mode 100644 index 0000000..2ff8a73 --- /dev/null +++ b/src/modules/mocha/_cls114.java @@ -0,0 +1,53 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// _cls2, _cls1, _cls111, _cls115, +// _cls3, _cls110, _cls113, _cls120, +// _cls112, _cls119, _cls109, _cls116, +// _cls118, _cls121, _cls117, _cls0 + +class _cls114 extends _cls2 +{ + + String m_301String; + + _cls114(_cls3 _pcls3) + throws IOException + { + int i = _pcls3._14vI(); + char ac[] = new char[i]; + for(int j = 0; j < i; j++) + ac[j] = _pcls3.readChar(); + + m_301String = new String(ac); + } + + void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1.writeByte(2); + _pcls1._4IV(m_301String.length()); + _pcls1.writeChars(m_301String); + } + + void _1000V(_cls0 _pcls0, String s) + { + _104StringV(s, "literal"); + } + + public String toString() + { + return m_301String; + } + + String _790String(_cls0 _pcls0) + { + return "Unicode '" + m_301String + "'"; + } +} diff --git a/src/modules/mocha/_cls115.java b/src/modules/mocha/_cls115.java new file mode 100644 index 0000000..9c00e66 --- /dev/null +++ b/src/modules/mocha/_cls115.java @@ -0,0 +1,52 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// _cls2, _cls111, _cls110, _cls113, +// _cls120, _cls114, _cls112, _cls119, +// _cls109, _cls116, _cls118, _cls121, +// _cls117, _cls3, _cls1, _cls0 + +class _cls115 extends _cls2 +{ + + double m_80D; + + _cls115(_cls3 _pcls3) + throws IOException + { + m_80D = _pcls3.readDouble(); + } + + void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1.writeByte(6); + _pcls1.writeDouble(m_80D); + } + + int _82vI() + { + return 2; + } + + String _81vString() + { + return "D"; + } + + public String toString() + { + return String.valueOf(m_80D); + } + + String _790String(_cls0 _pcls0) + { + return "Double " + m_80D; + } +} diff --git a/src/modules/mocha/_cls116.java b/src/modules/mocha/_cls116.java new file mode 100644 index 0000000..fad0e30 --- /dev/null +++ b/src/modules/mocha/_cls116.java @@ -0,0 +1,83 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// _cls2, _cls120, _cls111, _cls1, +// _cls119, _cls112, _cls115, _cls114, +// _cls121, _cls113, _cls109, _cls118, +// _cls3, _cls0, _cls110, Obfuscator, +// _cls117 + +class _cls116 extends _cls2 +{ + + String m_301String; + + _cls116(_cls3 _pcls3) + throws IOException + { + int i = _pcls3._14vI(); + byte abyte0[] = new byte[i]; + _pcls3.readFully(abyte0); + m_301String = new String(abyte0); + } + + void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1.writeByte(1); + _pcls1._4IV(m_301String.length()); + _pcls1.write(m_301String.getBytes()); + //_pcls1._writeBytesStringV(m_301String); + } + + void _1000V(_cls0 _pcls0, String s) + { + if(s == null) + { +// if(Obfuscator.m_debugZ) +// System.out.println("Discarding '" + m_301String + "'"); + m_301String = ""; + return; + } + if(s.equals("class")) + { + m_301String = _pcls0._138StringString(m_301String); + return; + } + if(s.equals("internal member")) + { + m_301String = _pcls0._136StringString(m_301String); + return; + } + if(s.equals("signature")) + m_301String = _pcls0._121StringString(m_301String); + } + + _cls116 _131v116() + { + try + { + return (_cls116)this; + } + catch(Exception _ex) + { + return null; + } + } + + public String toString() + { + return m_301String; + } + + String _790String(_cls0 _pcls0) + { + return "AsciiZ '" + m_301String + "'"; + } +} diff --git a/src/modules/mocha/_cls117.java b/src/modules/mocha/_cls117.java new file mode 100644 index 0000000..3b65d59 --- /dev/null +++ b/src/modules/mocha/_cls117.java @@ -0,0 +1,42 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.DataOutputStream; +import java.io.IOException; + +// Referenced classes of package mocha: +// _cls112, _cls1, _cls111, _cls115, +// _cls110, _cls113, _cls120, _cls0, +// _cls2, _cls114, _cls119, _cls109, +// _cls116, _cls118, _cls121, _cls3 + +class _cls117 extends _cls112 +{ + + _cls117(_cls3 _pcls3, _cls0 _pcls0) + throws IOException + { + super(_pcls3, _pcls0); + } + + void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1.writeByte(9); + _pcls1._4IV(super.m_103I); + _pcls1._4IV(super.m_151I); + } + + String _81vString() + { + return super.m_160._9I2(super.m_151I)._81vString(); + } + + String _790String(_cls0 _pcls0) + { + return "FieldRef(" + super.m_103I + ":" + _pcls0._9I2(super.m_103I)._790String(_pcls0) + ", " + super.m_151I + ":" + _pcls0._9I2(super.m_151I)._790String(_pcls0) + ")"; + } +} diff --git a/src/modules/mocha/_cls118.java b/src/modules/mocha/_cls118.java new file mode 100644 index 0000000..206bf2a --- /dev/null +++ b/src/modules/mocha/_cls118.java @@ -0,0 +1,47 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// _cls2, _cls111, _cls115, _cls110, +// _cls113, _cls120, _cls114, _cls112, +// _cls119, _cls109, _cls116, _cls121, +// _cls117, _cls3, _cls1, _cls0 + +class _cls118 extends _cls2 +{ + + float m_80F; + + _cls118(_cls3 _pcls3) + throws IOException + { + m_80F = _pcls3.readFloat(); + } + + void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1.writeByte(4); + _pcls1.writeFloat(m_80F); + } + + String _81vString() + { + return "F"; + } + + public String toString() + { + return String.valueOf(m_80F); + } + + String _790String(_cls0 _pcls0) + { + return "Float " + m_80F; + } +} diff --git a/src/modules/mocha/_cls119.java b/src/modules/mocha/_cls119.java new file mode 100644 index 0000000..80dd0ac --- /dev/null +++ b/src/modules/mocha/_cls119.java @@ -0,0 +1,133 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.IOException; + +// Referenced classes of package mocha: +// _cls2, _cls120, _cls111, _cls1, +// _cls112, _cls115, _cls114, _cls116, +// _cls121, _cls113, _cls109, _cls118, +// _cls3, _cls0, _cls110, _cls117 + +class _cls119 extends _cls2 +{ + + _cls0 m_160; + int m_86I; + + _cls119(_cls3 _pcls3, _cls0 _pcls0) + throws IOException + { + m_160 = _pcls0; + m_86I = _pcls3._14vI(); + } + + void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1.writeByte(8); + _pcls1._4IV(m_86I); + } + + void _19vV() + { + m_86I = m_160._19IStringI(m_86I, "literal"); + } + + String _81vString() + { + return "Ljava/lang/String;"; + } + + public String toString() + { + StringBuffer stringbuffer = new StringBuffer(); + stringbuffer.append('"'); + //String s = (m_160._9I2(m_86I)).toString(); + String s = String.valueOf(m_160._9I2(m_86I));//.toString(); + try { + stringbuffer.append(s);//StringEncoder.decodeWin1251(s.getBytes())); + }catch(Exception ex) {} + /*for(int i = 0; i < s.length();) + { + int j = s.charAt(i++); + if(j >= 128) + if(j < 224) + { + j &= 0x1f; + j <<= 6; + if(i= 0; + } + + void _192IV(int i) + { + m_191I = i; + } + + public String toString() + { + return "loop" + m_191I; + } +} diff --git a/src/modules/mocha/_cls123.java b/src/modules/mocha/_cls123.java new file mode 100644 index 0000000..75cba66 --- /dev/null +++ b/src/modules/mocha/_cls123.java @@ -0,0 +1,40 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// Decompiler + +class _cls123 extends DataOutputStream +{ + + private byte m_87aB[]; + + _cls123(OutputStream outputstream) + { + super(outputstream); + String s = "\n"; + m_87aB = new byte[s.length()]; + for(int i = 0; i < s.length(); i++) + m_87aB[i] = (byte)s.charAt(i); + + } + + public void write(int i) + throws IOException + { + if(i == 10) + { + super.out.write(m_87aB); + return; + } else + { + super.out.write(i); + return; + } + } +} diff --git a/src/modules/mocha/_cls124.java b/src/modules/mocha/_cls124.java new file mode 100644 index 0000000..dadbf13 --- /dev/null +++ b/src/modules/mocha/_cls124.java @@ -0,0 +1,216 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; +import java.util.Vector; + +// Referenced classes of package mocha: +// _cls129, _cls71, _cls5, _cls125, +// Decompiler, _cls126, _cls127, _cls0 + +class _cls124 +{ + + int m_89I; + Vector m_265Vector; + Vector m_273Vector; + boolean m_270Z; + + _cls124(int i) + { + m_89I = i; + m_265Vector = new Vector(); + m_273Vector = new Vector(); + m_270Z = false; + } + + void _262IStringV(int i, String s, char c) + { + _cls127 _lcls127 = new _cls127(i, s, c); + for(int j = 0; j < m_273Vector.size(); j++) + if(((_cls127)m_273Vector.elementAt(j)).m_110I > _lcls127.m_110I) + { + m_273Vector.insertElementAt(_lcls127, j); + return; + } + + m_273Vector.addElement(_lcls127); + } + + void _266124V(_cls124 _pcls124) + { + for(int i = 0; i < m_273Vector.size(); i++) + { + _cls127 _lcls127 = (_cls127)m_273Vector.elementAt(i); + _pcls124._262IStringV(_lcls127.m_110I, _lcls127.m_43String, _lcls127.m_195C); + } + + } + + int _159vI() + { + if(m_273Vector.size() > 0) + { + _cls127 _lcls127 = (_cls127)m_273Vector.elementAt(0); + return _lcls127.m_110I; + } else + { + return -1; + } + } + + int _271vI() + { + if(m_273Vector.size() > 0) + { + _cls127 _lcls127 = (_cls127)m_273Vector.elementAt(m_273Vector.size() - 1); + return _lcls127.m_110I; + } else + { + return -1; + } + } + + void _272vV() + { + m_270Z = true; + } + + boolean _264vZ() + { + return m_270Z; + } + + void _261125V(_cls125 _pcls125) + { + m_265Vector.addElement(_pcls125); + } + + _cls125 _111I125(int i) + { + _cls125 _lcls125 = null; + for(int j = 0; j < m_265Vector.size(); j++) + { + _cls125 _lcls125_1 = (_cls125)m_265Vector.elementAt(j); + if(_lcls125_1._96IZ(i)) + _lcls125 = _lcls125_1; + } + + return _lcls125; + } + + int _92vI() + { + return m_89I; + } + + Vector _267129Vector(_cls129 _pcls129) + { + Vector vector = new Vector(); + for(int i = 0; i < m_273Vector.size(); i++) + { + _cls127 _lcls127 = (_cls127)m_273Vector.elementAt(i); + _cls124 _lcls124 = _pcls129._274IIString124(m_89I, _lcls127.m_110I, _lcls127.m_43String, _lcls127.m_195C); + if(!vector.contains(_lcls124)) + vector.addElement(_lcls124); + } + + for(int j = 0; j < vector.size();) + { + _cls124 _lcls124_1 = (_cls124)vector.elementAt(j); + if(_lcls124_1 == null || _lcls124_1._264vZ()) + vector.removeElementAt(j); + else + j++; + } + + return vector; + } + + void _263129V(_cls129 _pcls129, _cls0 _pcls0, _cls71 _pcls71) + { + Vector vector = _267129Vector(_pcls129); + for(int i = 0; i < vector.size(); i++) + { + _cls124 _lcls124 = (_cls124)vector.elementAt(i); + _cls125 _lcls125 = _111I125(_lcls124._159vI()); + _lcls124._261125V(_lcls125); + } + + } + + void _269129V(_cls129 _pcls129, _cls0 _pcls0, _cls71 _pcls71) + { + m_265Vector = new Vector(); + Vector vector = _267129Vector(_pcls129); + for(int i = 0; i < vector.size(); i++) + { + _cls124 _lcls124 = (_cls124)vector.elementAt(i); + String s = _lcls124._268vString(); + _cls126 _lcls126 = _pcls71._98String126(s); + _cls125 _lcls125 = new _cls125(m_89I, _lcls126, s, _lcls124._159vI(), _lcls124._271vI(), _pcls0); + _lcls124._261125V(_lcls125); + _261125V(_lcls125); + } + + } + + String _268vString() + { + String s = null; + for(int i = 0; i < m_273Vector.size(); i++) + { + _cls127 _lcls127 = (_cls127)m_273Vector.elementAt(i); + if(_lcls127.m_195C != 'L') + if(s == null || _lcls127.m_195C == 'T') + s = _lcls127.m_43String; + else + s = _cls5._227StringString(s, _lcls127.m_43String); + } + + return s; + } + + public String toString() + { + String s = ""; + for(int i = 0; i < m_265Vector.size(); i++) + { + _cls125 _lcls125 = (_cls125)m_265Vector.elementAt(i); + _cls5 _lcls5 = null; + if(_lcls125 != null) + _lcls5 = _lcls125._90v5(); + if(_lcls5 != null) + { + if(s.length() > 0) + s += ", "; + s += _lcls5; + } + } + + return s; + } + + void _17PrintStreamvV(PrintStream printstream, int i) + { + for(int j = 0; j < m_265Vector.size(); j++) + { + _cls125 _lcls125 = (_cls125)m_265Vector.elementAt(j); + if(_lcls125 != null) + _lcls125._17PrintStreamvV(printstream, i); + } + + if(Decompiler.m_debugZ) + { + for(int k = 0; k < m_273Vector.size(); k++) + { + _cls127 _lcls127 = (_cls127)m_273Vector.elementAt(k); + _lcls127._17PrintStreamV(printstream); + } + + } + } +} diff --git a/src/modules/mocha/_cls125.java b/src/modules/mocha/_cls125.java new file mode 100644 index 0000000..141fa77 --- /dev/null +++ b/src/modules/mocha/_cls125.java @@ -0,0 +1,125 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.IOException; +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls71, _cls5, _cls124, _cls3, +// _cls0, Decompiler, _cls126, _cls127 + +class _cls125 +{ + + int m_89I; + Object m_97Object; + String m_43String; + int m_94I; + int m_48I; + _cls0 m_160; + + _cls125(int i, Object obj, String s, int j, int k, _cls0 _pcls0) + { + m_89I = i; + m_97Object = obj; + m_43String = s; + m_94I = j; + m_48I = k; + m_160 = _pcls0; + } + + _cls125(int i, Object obj, String s, _cls0 _pcls0) + { + this(i, obj, s, 0, 0x7fffffff, _pcls0); + } + + boolean _88vZ() + { + return m_48I == 0x7fffffff; + } + + Object _18vObject() + { + return m_97Object; + } + + void _9171V(_cls71 _pcls71) + { + if(m_97Object == null) + m_97Object = _pcls71._98String126(m_43String); + } + + String _81vString() + { + return m_43String; + } + + void _93StringV(String s) + { + m_43String = s; + } + + int _99vI() + { + String s = _81vString(); + return !s.equals("D") && !s.equals("J") ? 1 : 2; + } + + int _92vI() + { + return m_89I; + } + + public String toString() + { + return m_97Object.toString(); + } + + _cls5 _90v5() + { + if(m_43String.startsWith("<")) + return null; + else + return new _cls5(m_97Object.toString(), m_43String, m_160); + } + + static String _50IString(int i) + { + StringBuffer stringbuffer = new StringBuffer(4 * i); + for(int j = 0; j < i; j++) + stringbuffer.append(" "); + + return stringbuffer.toString(); + } + + void _17PrintStreamvV(PrintStream printstream, int i) + { + _cls5 _lcls5 = _90v5(); + if(_lcls5 != null) + { + printstream.print(_50IString(i) + _lcls5 + ";"); + if(Decompiler.m_debugZ && !_88vZ()) + printstream.print("\t// slot " + m_89I + ", scope " + m_94I + "-" + m_48I); + printstream.println(); + } + } + + boolean _96IZ(int i) + { + return m_94I <= i; + } + + static _cls125 _950125(_cls0 _pcls0, _cls3 _pcls3) + throws IOException + { + int i = _pcls3._14vI(); + int j = i + _pcls3._14vI(); + String s = _pcls0._932(_pcls3).toString(); + String s1 = _pcls0._932(_pcls3).toString(); + int k = _pcls3._14vI(); + return new _cls125(k, s, s1, i, j, _pcls0); + } +} diff --git a/src/modules/mocha/_cls126.java b/src/modules/mocha/_cls126.java new file mode 100644 index 0000000..e105303 --- /dev/null +++ b/src/modules/mocha/_cls126.java @@ -0,0 +1,32 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls124, _cls127, _cls71, _cls125 + +class _cls126 +{ + + String m_221String; + int m_220I; + _cls71 m_11271; + + _cls126(String s, int i, _cls71 _pcls71) + { + m_221String = s; + m_220I = i; + m_11271 = _pcls71; + } + + public String toString() + { + if(m_220I == 1 && m_11271._219StringI(m_221String) == 1) + return m_221String; + else + return m_221String + m_220I; + } +} diff --git a/src/modules/mocha/_cls127.java b/src/modules/mocha/_cls127.java new file mode 100644 index 0000000..38690d2 --- /dev/null +++ b/src/modules/mocha/_cls127.java @@ -0,0 +1,49 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls124, _cls126, _cls71, _cls125 + +class _cls127 +{ + + int m_110I; + String m_43String; + char m_195C; + + _cls127(int i, String s, char c) + { + m_110I = i; + m_43String = s; + m_195C = c; + } + + void _17PrintStreamV(PrintStream printstream) + { + String s = null; + switch(m_195C) + { + case 76: // 'L' + s = "Load"; + break; + + case 83: // 'S' + s = "Store"; + break; + + case 84: // 'T' + s = "Temporary"; + break; + + case 88: // 'X' + s = "Scalar"; + break; + } + printstream.println(" // " + m_110I + "\t" + m_43String + "\t" + s); + } +} diff --git a/src/modules/mocha/_cls128.java b/src/modules/mocha/_cls128.java new file mode 100644 index 0000000..08ad99f --- /dev/null +++ b/src/modules/mocha/_cls128.java @@ -0,0 +1,20 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.IOException; + +public class _cls128 extends IOException +{ + + _cls128() + { + } + + _cls128(String s) + { + super(s); + } +} diff --git a/src/modules/mocha/_cls129.java b/src/modules/mocha/_cls129.java new file mode 100644 index 0000000..a54a68a --- /dev/null +++ b/src/modules/mocha/_cls129.java @@ -0,0 +1,140 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; +import java.util.Vector; + +// Referenced classes of package mocha: +// _cls131, _cls124, Decompiler, _cls0 + +class _cls129 +{ + + int m_94I; + int m_48I; + Vector m_82Vector; + Vector m_296Vector; + _cls0 m_160; + + _cls129(_cls129 _pcls129, int i, int j) + { + m_94I = i; + m_48I = j; + m_82Vector = new Vector(); + m_296Vector = new Vector(); + if(_pcls129 != null) + _pcls129._297129V(this); + } + + void _297129V(_cls129 _pcls129) + { + m_296Vector.addElement(_pcls129); + } + + _cls124 _92I124(int i) + { + for(int j = 0; j < m_82Vector.size(); j++) + { + _cls124 _lcls124 = (_cls124)m_82Vector.elementAt(j); + if(_lcls124._92vI() == i) + return _lcls124; + } + + return null; + } + + Vector _156vVector() + { + return m_82Vector; + } + + _cls124 _274IIString124(int i, int j, String s, char c) + { + if(m_94I < j && j <= m_48I) + { + _cls124 _lcls124 = _92I124(i); + if(_lcls124 == null) + { + for(int k = 0; k < m_296Vector.size(); k++) + { + _cls129 _lcls129 = (_cls129)m_296Vector.elementAt(k); + _lcls124 = _lcls129._274IIString124(i, j, s, c); + if(_lcls124 != null) + return _lcls124; + } + + _lcls124 = new _cls124(i); + if(c != 'S') + { + boolean flag = false; + for(int l = m_296Vector.size() - 1; !flag && l >= 0; l--) + { + _cls129 _lcls129_1 = (_cls129)m_296Vector.elementAt(l); + if(_lcls129_1.m_48I < j) + flag = _lcls129_1._332124Z(_lcls124); + } + + if(!flag) + return null; + } + m_82Vector.addElement(_lcls124); + } + _lcls124._262IStringV(j, s, c); + return _lcls124; + } else + { + return null; + } + } + + boolean _332124Z(_cls124 _pcls124) + { + boolean flag = false; + _cls124 _lcls124 = _92I124(_pcls124._92vI()); + if(_lcls124 != null) + { + _lcls124._266124V(_pcls124); + m_82Vector.removeElement(_lcls124); + _lcls124._272vV(); + flag = true; + } + for(int i = 0; i < m_296Vector.size(); i++) + { + _cls129 _lcls129 = (_cls129)m_296Vector.elementAt(i); + flag |= _lcls129._332124Z(_pcls124); + } + + return flag; + } + + public String toString() + { + String s = ""; + for(int i = 0; i < m_82Vector.size(); i++) + { + if(s.length() > 0) + s += ", "; + _cls124 _lcls124 = (_cls124)m_82Vector.elementAt(i); + s += _lcls124; + } + + return s; + } + + void _17PrintStreamStringV(PrintStream printstream, int i, String s) + { + if(Decompiler.m_debugZ && m_82Vector.size() > 0) + printstream.println("---- start " + s + " scope ----"); + for(int j = 0; j < m_82Vector.size(); j++) + { + _cls124 _lcls124 = (_cls124)m_82Vector.elementAt(j); + _lcls124._17PrintStreamvV(printstream, i); + } + + if(Decompiler.m_debugZ && m_82Vector.size() > 0) + printstream.println("---- end " + s + " scope ----"); + } +} diff --git a/src/modules/mocha/_cls13.java b/src/modules/mocha/_cls13.java new file mode 100644 index 0000000..c280696 --- /dev/null +++ b/src/modules/mocha/_cls13.java @@ -0,0 +1,30 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls46, _cls27, _cls25, _cls31, +// _cls42, _cls18, _cls52, _cls35, +// _cls53, _cls43, _cls20, _cls14, +// _cls26, _cls36, _cls48, _cls45, +// _cls54, _cls38, _cls50, _cls28, +// _cls41, _cls9, _cls16, _cls34, +// _cls44, _cls17, _cls37, _cls19, +// _cls11, _cls8, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10 + +class _cls13 extends _cls46 +{ + + _cls13(int i, int j, int k) + { + super(i, j, k); + super.m_315I = 2; + } +} diff --git a/src/modules/mocha/_cls131.java b/src/modules/mocha/_cls131.java new file mode 100644 index 0000000..182a326 --- /dev/null +++ b/src/modules/mocha/_cls131.java @@ -0,0 +1,51 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; +import java.util.Vector; + +// Referenced classes of package mocha: +// _cls129, _cls124 + +class _cls131 extends _cls129 +{ + + _cls131(_cls129 _pcls129, int i, int j) + { + super(_pcls129, i, j); + super.m_82Vector = null; + } + + void _297129V(_cls129 _pcls129) + { + super.m_296Vector.addElement(_pcls129); + } + + _cls124 _92I124(int i) + { + return null; + } + + _cls124 _274IIString124(int i, int j, String s, char c) + { + if(super.m_94I < j && j <= super.m_48I) + { + for(int k = 0; k < super.m_296Vector.size(); k++) + { + _cls129 _lcls129 = (_cls129)super.m_296Vector.elementAt(k); + _cls124 _lcls124 = _lcls129._274IIString124(i, j, s, c); + if(_lcls124 != null) + return _lcls124; + } + + } + return null; + } + + void _17PrintStreamStringV(PrintStream printstream, int i, String s) + { + } +} diff --git a/src/modules/mocha/_cls132.java b/src/modules/mocha/_cls132.java new file mode 100644 index 0000000..3b0f5f2 --- /dev/null +++ b/src/modules/mocha/_cls132.java @@ -0,0 +1,198 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls166, _cls149, _cls75, +// _cls164, _cls167, _cls155, _cls103, +// _cls148, _cls153, _cls141, _cls140, +// _cls150, _cls4, _cls84, _cls142, +// _cls144, _cls137, _cls47, _cls143, +// _cls135, _cls156, _cls134, _cls169, +// _cls158, _cls139, _cls159, _cls154, +// _cls161, _cls147, _cls162, _cls157, +// _cls165, _cls79, _cls163, _cls171, +// _cls74, _cls170, _cls133, _cls78, +// _cls145, _cls151, _cls160 + +class _cls132 extends _cls138 +{ + + int _371a171II(_cls171 a_pcls171[], int i, int j) + { + int k; + if(a_pcls171[i].m_370I == j) + k = 0x7ffffffe; + else + if(a_pcls171[i].m_373I == -1) + k = a_pcls171[i].m_370I; + else + if(a_pcls171[i].m_373I == j) + k = a_pcls171[i].m_370I; + else + if(a_pcls171[i].m_369I >= 0) + k = _371a171II(a_pcls171, a_pcls171[i].m_369I, j) - 1; + else + k = -1; + if(k >= 0 && i == 0) + k = 0x7fffffff; + return k; + } + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + _cls74 _lcls74 = _pcls74; + if(!(_lcls74 instanceof _cls47)) + return null; + _cls47 _lcls47 = (_cls47)_lcls74; + _lcls74 = _pcls103._2487474(_pcls74); + if(!(_lcls74 instanceof _cls4)) + return null; + _cls4 _lcls4 = (_cls4)_lcls74; + _cls171 a_lcls171[] = new _cls171[_lcls47._25vI()]; + int i = 0; + for(int j = 0; j < a_lcls171.length; j++) + { + int k = _lcls47._26II(j); + int i1; + for(i1 = 0; i1 < i && a_lcls171[i1].m_370I != k; i1++); + if(i1 == i) + a_lcls171[i++] = new _cls171(k); + } + + int l = -1; + for(int j1 = 0; l < 0 && j1 < 2; j1++) + { + for(int k1 = 0; k1 < i; k1++) + { + _cls74 _lcls74_2 = _pcls103._254I74(a_lcls171[k1].m_370I); + if(!(_lcls74_2 instanceof _cls78)) + return null; + int j2 = -1; + switch(_lcls74_2._25vI()) + { + case 0: // '\0' + a_lcls171[k1].m_373I = -1; + break; + + case 1: // '\001' + a_lcls171[k1].m_373I = _lcls74_2._26II(0); + int l2; + for(l2 = 0; l2 < i && a_lcls171[l2].m_370I != a_lcls171[k1].m_373I; l2++); + if(l2 < i) + { + a_lcls171[k1].m_369I = l2; + a_lcls171[l2].m_372I++; + if(a_lcls171[l2].m_372I > 1) + j2 = a_lcls171[l2].m_370I; + } else + if(j1 > 0) + j2 = a_lcls171[k1].m_373I; + break; + + default: + j2 = a_lcls171[k1].m_370I; + break; + } + if(j2 >= 0) + if(l < 0) + l = j2; + else + if(j2 != l) + return null; + } + + } + + for(int l1 = 0; l1 < i; l1++) + { + a_lcls171[l1].m_371I = _371a171II(a_lcls171, l1, l); + if(a_lcls171[l1].m_371I < 0) + return null; + } + + super.m_368I++; + for(int i2 = 0; i2 < i - 1; i2++) + { + int k2 = i2; + for(int i3 = i2 + 1; i3 < i; i3++) + if(a_lcls171[i3].m_371I < a_lcls171[k2].m_371I) + k2 = i3; + + if(k2 != i2) + { + _cls171 _lcls171 = a_lcls171[i2]; + a_lcls171[i2] = a_lcls171[k2]; + a_lcls171[k2] = _lcls171; + } + } + + _cls79 _lcls79 = new _cls79(_lcls4); + _lcls79._21IIV(0, l); + _cls74 _lcls74_3 = null; + if(l >= 0) + { + _lcls74_3 = _pcls103._254I74(l); + _lcls74_3._197vV(); + } + for(int j3 = 0; j3 < i; j3++) + { + _cls74 _lcls74_1; + String s; + if(a_lcls171[j3].m_370I == l) + { + _lcls74_1 = null; + s = "B"; + if(_lcls74_3 != null) + { + for(int l3 = 0; l3 < _lcls47._25vI(); l3++) + if(_lcls47._26II(l3) == a_lcls171[j3].m_370I) + _lcls74_3._196vV(); + + } + if(j3 == i - 1) + break; + } else + { + _lcls74_1 = _pcls103._254I74(a_lcls171[j3].m_370I); + if(a_lcls171[j3].m_373I == -1) + s = "R"; + else + if(a_lcls171[j3].m_373I == l) + { + s = "B"; + if(_lcls74_3 != null) + _lcls74_3._196vV(); + } else + { + s = "F"; + } + } + _cls84 _lcls84 = new _cls84(s, (_cls78)_lcls74_1); + if(a_lcls171[j3].m_371I != 0x7fffffff) + { + for(int i4 = 1; i4 < _lcls47._25vI(); i4++) + if(_lcls47._26II(i4) == a_lcls171[j3].m_370I) + _lcls84._328IV(_lcls47._23II(i4)); + + } + _lcls79._23584V(_lcls84); + } + + _pcls103._24274V(_lcls4); + _pcls103._24274V(_lcls47); + for(int k3 = 0; k3 < i; k3++) + if(a_lcls171[k3].m_370I != l) + _pcls103._242IV(a_lcls171[k3].m_370I); + + return _pcls103._2497474(_lcls79); + } + + _cls132() + { + } +} diff --git a/src/modules/mocha/_cls133.java b/src/modules/mocha/_cls133.java new file mode 100644 index 0000000..c2bf215 --- /dev/null +++ b/src/modules/mocha/_cls133.java @@ -0,0 +1,70 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls34, _cls136, _cls42, +// _cls16, _cls146, _cls152, _cls168, +// _cls166, _cls149, _cls32, _cls75, +// _cls164, _cls167, _cls155, _cls103, +// _cls148, _cls153, _cls141, _cls140, +// _cls150, _cls4, _cls142, _cls144, +// _cls137, _cls61, _cls143, _cls135, +// _cls156, _cls31, _cls134, _cls169, +// _cls158, _cls139, _cls159, _cls154, +// _cls161, _cls147, _cls55, _cls162, +// _cls157, _cls165, _cls163, _cls171, +// _cls101, _cls170, _cls132, _cls145, +// _cls151, _cls160, _cls74 + +class _cls133 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls16)) + return null; + _cls55 _lcls55 = (_cls55)_pcls74; + _cls74 _lcls74 = _pcls103._2487474(_pcls74); + if(!(_lcls74 instanceof _cls4)) + return null; + _cls4 _lcls4 = (_cls4)_lcls74; + _cls74 _lcls74_1 = _lcls4._309v74(); + _cls4 _lcls4_1 = _lcls4; + if(_lcls74_1 instanceof _cls32) + { + _cls32 _lcls32 = (_cls32)_lcls74_1; + _lcls32._345StringV(_lcls55._259vString()); + } else + if(_lcls4._51v61()._43vString().equals("Z")) + { + if(_lcls55._259vString().equals("==")) + _lcls4_1 = _lcls4_1._311v4(); + else + if(!_lcls55._259vString().equals("!=")) + return null; + } else + { + _cls4 a_lcls4[] = new _cls4[2]; + a_lcls4[0] = _lcls4; + _cls42 _lcls42 = new _cls42(0, 0, "I", "0"); + _cls4 a_lcls4_1[] = new _cls4[0]; + a_lcls4[1] = new _cls4(_lcls42, a_lcls4_1); + _cls34 _lcls34 = new _cls34(_lcls55._155vI(), 0, "Z", _lcls55._259vString()); + _lcls4_1 = new _cls4(_lcls34, a_lcls4); + } + super.m_368I++; + Object obj = new _cls101(_lcls4_1, _lcls55._26II(0), _lcls55._26II(1)); + obj = ((_cls75) (obj))._497475(_lcls4); + _pcls103._24274V(_lcls4); + _pcls103._24274V(_lcls55); + return _pcls103._2497474(((_cls74) (obj))); + } + + _cls133() + { + } +} diff --git a/src/modules/mocha/_cls134.java b/src/modules/mocha/_cls134.java new file mode 100644 index 0000000..7d1866c --- /dev/null +++ b/src/modules/mocha/_cls134.java @@ -0,0 +1,68 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls34, _cls136, _cls42, +// _cls146, _cls152, _cls168, _cls166, +// _cls149, _cls75, _cls164, _cls167, +// _cls155, _cls103, _cls148, _cls153, +// _cls141, _cls140, _cls150, _cls4, +// _cls142, _cls144, _cls137, _cls143, +// _cls135, _cls156, _cls31, _cls169, +// _cls48, _cls158, _cls139, _cls159, +// _cls154, _cls161, _cls147, _cls55, +// _cls162, _cls157, _cls165, _cls163, +// _cls171, _cls101, _cls170, _cls133, +// _cls132, _cls145, _cls151, _cls43, +// _cls160, _cls74 + +class _cls134 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + byte byte0 = 0; + if(_pcls74 instanceof _cls48) + byte0 = 2; + else + if(_pcls74 instanceof _cls43) + byte0 = 1; + else + return null; + _cls55 _lcls55 = (_cls55)_pcls74; + _cls4 a_lcls4[] = new _cls4[2]; + _cls74 _lcls74 = _pcls74; + for(int i = 0; i < byte0; i++) + { + _lcls74 = _pcls103._2487474(_lcls74); + if(!(_lcls74 instanceof _cls4)) + return null; + a_lcls4[byte0 - i - 1] = (_cls4)_lcls74; + } + + super.m_368I++; + if(byte0 < 2) + { + _cls42 _lcls42 = new _cls42(0, 0, "A", "null"); + _cls4 a_lcls4_1[] = new _cls4[0]; + a_lcls4[1] = new _cls4(_lcls42, a_lcls4_1); + } + _cls34 _lcls34 = new _cls34(_lcls55._155vI(), 0, "Z", _lcls55._259vString()); + _cls4 _lcls4 = new _cls4(_lcls34, a_lcls4); + Object obj = new _cls101(_lcls4, _lcls55._26II(0), _lcls55._26II(1)); + obj = ((_cls75) (obj))._497475(a_lcls4[0]); + _pcls103._24274V(_lcls55); + for(int j = 0; j < byte0; j++) + _pcls103._24274V(a_lcls4[j]); + + return _pcls103._2497474(((_cls74) (obj))); + } + + _cls134() + { + } +} diff --git a/src/modules/mocha/_cls135.java b/src/modules/mocha/_cls135.java new file mode 100644 index 0000000..0902fef --- /dev/null +++ b/src/modules/mocha/_cls135.java @@ -0,0 +1,63 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls162, _cls159, +// _cls161, _cls160, _cls141, _cls76, +// _cls140, _cls147, _cls171, _cls169, +// _cls154, _cls146, _cls152, _cls143, +// _cls167, _cls149, _cls132, _cls139, +// _cls156, _cls34, _cls133, _cls168, +// _cls158, _cls165, _cls4, _cls142, +// _cls137, _cls157, _cls21, _cls166, +// _cls136, _cls150, _cls163, _cls170, +// _cls134, _cls153, _cls151, _cls74, +// _cls103 + +class _cls135 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + Object obj = _pcls74; + if(obj instanceof _cls76) + obj = ((_cls76)obj)._78v4(); + if(!(obj instanceof _cls4)) + return null; + _cls4 _lcls4 = (_cls4)obj; + _cls74 _lcls74 = _lcls4._309v74(); + if(!(_lcls74 instanceof _cls34)) + return null; + _cls21 _lcls21 = null; + for(int i = 0; i < 2 && _lcls21 == null; i++) + { + _cls4 _lcls4_1 = _lcls4._65I4(1); + _cls74 _lcls74_1 = _lcls4_1._309v74(); + if(_lcls74_1 instanceof _cls21) + { + _lcls21 = (_cls21)_lcls74_1; + if(_lcls21._182vZ()) + _lcls21 = null; + } + } + + if(_lcls21 == null || _lcls21._180vZ()) + { + return null; + } else + { + super.m_368I++; + _lcls21._183vV(); + return _pcls74; + } + } + + _cls135() + { + } +} diff --git a/src/modules/mocha/_cls136.java b/src/modules/mocha/_cls136.java new file mode 100644 index 0000000..4120c4b --- /dev/null +++ b/src/modules/mocha/_cls136.java @@ -0,0 +1,54 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls162, _cls159, +// _cls161, _cls160, _cls141, _cls76, +// _cls140, _cls147, _cls171, _cls169, +// _cls154, _cls146, _cls152, _cls143, +// _cls167, _cls149, _cls132, _cls139, +// _cls156, _cls133, _cls168, _cls158, +// _cls165, _cls4, _cls142, _cls135, +// _cls137, _cls92, _cls157, _cls21, +// _cls166, _cls150, _cls163, _cls170, +// _cls134, _cls153, _cls151, _cls74, +// _cls103 + +class _cls136 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + Object obj = _pcls74; + if(obj instanceof _cls76) + obj = ((_cls76)obj)._78v4(); + if(!(obj instanceof _cls92)) + return null; + _cls92 _lcls92 = (_cls92)obj; + _cls4 _lcls4 = _lcls92._65I4(0); + if(_lcls4 == null) + return null; + _cls74 _lcls74 = _lcls4._309v74(); + if(!(_lcls74 instanceof _cls21)) + return null; + _cls21 _lcls21 = (_cls21)_lcls74; + if(_lcls21._182vZ() || _lcls21._180vZ()) + { + return null; + } else + { + super.m_368I++; + _lcls21._183vV(); + return _pcls74; + } + } + + _cls136() + { + } +} diff --git a/src/modules/mocha/_cls137.java b/src/modules/mocha/_cls137.java new file mode 100644 index 0000000..9f79d29 --- /dev/null +++ b/src/modules/mocha/_cls137.java @@ -0,0 +1,46 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls74, _cls162, +// _cls159, _cls161, _cls160, _cls141, +// _cls140, _cls147, _cls171, _cls169, +// _cls154, _cls146, _cls152, _cls143, +// _cls167, _cls149, _cls132, _cls139, +// _cls156, _cls133, _cls168, _cls158, +// _cls165, _cls103, _cls142, _cls135, +// _cls97, _cls157, _cls83, _cls166, +// _cls136, _cls150, _cls163, _cls170, +// _cls134, _cls153, _cls151 + +class _cls137 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls97)) + return null; + if(_pcls74._155vI() != 0) + return null; + _cls97 _lcls97 = (_cls97)_pcls74; + if(!_lcls97.toString().equals("super()")) + { + return null; + } else + { + super.m_368I++; + _cls83 _lcls83 = new _cls83(_pcls74); + _pcls103._24274V(_pcls74); + return _pcls103._2497474(_lcls83); + } + } + + _cls137() + { + } +} diff --git a/src/modules/mocha/_cls138.java b/src/modules/mocha/_cls138.java new file mode 100644 index 0000000..c5b7dd0 --- /dev/null +++ b/src/modules/mocha/_cls138.java @@ -0,0 +1,37 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls145, _cls144, _cls148, _cls164, +// _cls155, _cls162, _cls159, _cls161, +// _cls160, _cls141, _cls140, _cls147, +// _cls171, _cls169, _cls154, _cls146, +// _cls152, _cls143, _cls167, _cls149, +// _cls132, _cls139, _cls156, _cls133, +// _cls168, _cls158, _cls165, _cls142, +// _cls135, _cls137, _cls157, _cls166, +// _cls136, _cls150, _cls163, _cls170, +// _cls134, _cls153, _cls151, _cls74, +// _cls103 + +abstract class _cls138 +{ + + int m_368I; + + abstract _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103); + + void _17PrintStreamV(PrintStream printstream) + { + printstream.println(getClass().getName() + " applied " + m_368I + " times"); + } + + _cls138() + { + } +} diff --git a/src/modules/mocha/_cls139.java b/src/modules/mocha/_cls139.java new file mode 100644 index 0000000..7279940 --- /dev/null +++ b/src/modules/mocha/_cls139.java @@ -0,0 +1,47 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls74, _cls162, +// _cls159, _cls161, _cls160, _cls141, +// _cls140, _cls147, _cls171, _cls169, +// _cls82, _cls154, _cls146, _cls152, +// _cls143, _cls167, _cls149, _cls132, +// _cls156, _cls133, _cls168, _cls158, +// _cls165, _cls103, _cls142, _cls135, +// _cls137, _cls51, _cls157, _cls166, +// _cls136, _cls150, _cls163, _cls170, +// _cls134, _cls153, _cls151 + +class _cls139 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls51)) + return null; + int i = _pcls74._155vI(); + int j = _pcls74._26II(0); + for(_cls82 _lcls82 = _pcls103._178v82(); _lcls82._174vZ();) + { + _cls74 _lcls74 = _lcls82._177v74(); + for(int k = 0; k < _lcls74._25vI(); k++) + if(_lcls74._26II(k) == i) + _lcls74._21IIV(k, j); + + } + + super.m_368I++; + _pcls103._24274V(_pcls74); + return _pcls74; + } + + _cls139() + { + } +} diff --git a/src/modules/mocha/_cls14.java b/src/modules/mocha/_cls14.java new file mode 100644 index 0000000..210b179 --- /dev/null +++ b/src/modules/mocha/_cls14.java @@ -0,0 +1,45 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls46, _cls27, _cls25, +// _cls42, _cls18, _cls52, _cls35, +// _cls53, _cls43, _cls20, _cls26, +// _cls36, _cls48, _cls45, _cls13, +// _cls54, _cls38, _cls50, _cls28, +// _cls41, _cls9, _cls16, _cls34, +// _cls44, _cls17, _cls37, _cls19, +// _cls11, _cls8, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls23, +// _cls29, _cls32, _cls10 + +class _cls14 extends _cls31 +{ + + _cls14(int i, int j) + { + super(i, j); + } + + public int _22vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._29v23(); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("drop"); + } +} diff --git a/src/modules/mocha/_cls140.java b/src/modules/mocha/_cls140.java new file mode 100644 index 0000000..a3a10f6 --- /dev/null +++ b/src/modules/mocha/_cls140.java @@ -0,0 +1,57 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls162, _cls159, +// _cls161, _cls160, _cls141, _cls76, +// _cls147, _cls171, _cls169, _cls154, +// _cls146, _cls152, _cls143, _cls167, +// _cls149, _cls132, _cls139, _cls156, +// _cls133, _cls168, _cls158, _cls165, +// _cls4, _cls142, _cls135, _cls137, +// _cls157, _cls21, _cls166, _cls136, +// _cls150, _cls163, _cls170, _cls134, +// _cls153, _cls151, _cls74, _cls103 + +class _cls140 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + Object obj = _pcls74; + if(obj instanceof _cls76) + obj = ((_cls76)obj)._78v4(); + if(!(obj instanceof _cls4)) + return null; + _cls4 _lcls4 = (_cls4)obj; + _cls74 _lcls74 = _lcls4._309v74(); + if(!(_lcls74 instanceof _cls21)) + return null; + _cls21 _lcls21 = (_cls21)_lcls74; + if(!_lcls21._182vZ()) + return null; + _cls4 _lcls4_1 = _lcls4._65I4(0); + _cls74 _lcls74_1 = _lcls4_1._309v74(); + if(!(_lcls74_1 instanceof _cls21)) + return null; + _cls21 _lcls21_1 = (_cls21)_lcls74_1; + if(!_lcls21_1._182vZ() || _lcls21_1._180vZ()) + { + return null; + } else + { + super.m_368I++; + _lcls21_1._183vV(); + return _pcls74; + } + } + + _cls140() + { + } +} diff --git a/src/modules/mocha/_cls141.java b/src/modules/mocha/_cls141.java new file mode 100644 index 0000000..b0cf1c8 --- /dev/null +++ b/src/modules/mocha/_cls141.java @@ -0,0 +1,77 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls34, _cls136, _cls146, +// _cls152, _cls168, _cls166, _cls149, +// _cls75, _cls164, _cls167, _cls155, +// _cls103, _cls148, _cls153, _cls140, +// _cls150, _cls4, _cls142, _cls144, +// _cls137, _cls143, _cls135, _cls156, +// _cls134, _cls169, _cls158, _cls139, +// _cls159, _cls154, _cls161, _cls147, +// _cls162, _cls157, _cls165, _cls163, +// _cls171, _cls74, _cls101, _cls170, +// _cls133, _cls132, _cls145, _cls151, +// _cls160 + +class _cls141 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + _cls74 _lcls74 = _pcls74; + if(!(_lcls74 instanceof _cls101)) + return null; + int j = _lcls74._26II(0); + int k = _lcls74._26II(1); + _cls74 _lcls74_1 = _pcls103._2487474(_lcls74); + if(!(_lcls74_1 instanceof _cls101)) + return null; + int i; + boolean flag; + if(_lcls74_1._26II(0) == _lcls74._155vI()) + { + flag = false; + i = _lcls74_1._26II(1); + } else + { + flag = true; + i = _lcls74_1._26II(0); + } + String s; + if(i == k) + s = "||"; + else + if(i == j) + { + s = "&&"; + flag = !flag; + } else + { + return null; + } + super.m_368I++; + _cls4 a_lcls4[] = new _cls4[2]; + a_lcls4[0] = ((_cls101)_lcls74_1)._344v4(); + if(flag) + a_lcls4[0] = a_lcls4[0]._311v4(); + a_lcls4[1] = ((_cls101)_lcls74)._344v4(); + _cls34 _lcls34 = new _cls34(0, 0, "Z", s); + _cls4 _lcls4 = new _cls4(_lcls34, a_lcls4); + Object obj = new _cls101(_lcls4, j, k); + obj = ((_cls75) (obj))._497475(_lcls74_1); + _pcls103._24274V(_lcls74_1); + _pcls103._24274V(_lcls74); + _pcls103._254I74(i)._196vV(); + return _pcls103._2497474(((_cls74) (obj))); + } + + _cls141() + { + } +} diff --git a/src/modules/mocha/_cls142.java b/src/modules/mocha/_cls142.java new file mode 100644 index 0000000..6c55990 --- /dev/null +++ b/src/modules/mocha/_cls142.java @@ -0,0 +1,153 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls34, _cls136, _cls146, +// _cls152, _cls168, _cls166, _cls149, +// _cls92, _cls75, _cls164, _cls167, +// _cls155, _cls103, _cls25, _cls76, +// _cls148, _cls153, _cls141, _cls140, +// _cls150, _cls4, _cls144, _cls137, +// _cls61, _cls143, _cls135, _cls156, +// _cls31, _cls134, _cls54, _cls169, +// _cls158, _cls46, _cls139, _cls159, +// _cls154, _cls161, _cls147, _cls162, +// _cls157, _cls165, _cls163, _cls171, +// _cls99, _cls86, _cls170, _cls9, +// _cls133, _cls132, _cls145, _cls151, +// _cls160, _cls74 + +class _cls142 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + boolean flag = false; + boolean flag1 = false; + String s = null; + _cls46 _lcls46 = null; + _cls46 _lcls46_1 = null; + _cls9 _lcls9 = null; + _cls34 _lcls34 = null; + _cls74 _lcls74_1 = _pcls74; + if(_lcls74_1 instanceof _cls34) + _lcls74_1 = _pcls103._2397474(_lcls74_1); + if(!(_lcls74_1 instanceof _cls54)) + return null; + _cls54 _lcls54 = (_cls54)_lcls74_1; + int i = _lcls54._22vI(); + _cls74 _lcls74; + _lcls74_1 = _pcls103._2487474(_lcls74 = _lcls74_1); + if(_lcls74_1 instanceof _cls46) + { + flag = true; + flag1 = true; + _lcls46 = (_cls46)_lcls74_1; + _lcls74_1 = _pcls103._2487474(_lcls74 = _lcls74_1); + } + if(_lcls74_1 instanceof _cls34) + { + _lcls34 = (_cls34)_lcls74_1; + s = _lcls34._299vString(); + _lcls74_1 = _pcls103._2487474(_lcls74 = _lcls74_1); + } + if(!(_lcls74_1 instanceof _cls4)) + return null; + _cls4 _lcls4 = (_cls4)_lcls74_1; + int j = _lcls4._51v61()._42vI(); + _lcls74_1 = _pcls103._2487474(_lcls74 = _lcls74_1); + if(!flag && (_lcls74_1 instanceof _cls46)) + { + flag = true; + _lcls46 = (_cls46)_lcls74_1; + _lcls74_1 = _pcls103._2487474(_lcls74 = _lcls74_1); + } + if(flag) + { + if(_lcls46._317vI() != i - 1) + return null; + if(j != _lcls46._22vI() - _lcls46._317vI()) + return null; + } + if(s != null) + { + _cls74 _lcls74_2 = _lcls74_1; + if(_lcls74_2 instanceof _cls4) + _lcls74_2 = ((_cls4)_lcls74_2)._309v74(); + if(!(_lcls74_2 instanceof _cls9)) + return null; + _lcls9 = (_cls9)_lcls74_2; + if(!_lcls9._11431Z(_lcls54)) + return null; + _lcls74_1 = _pcls103._2487474(_lcls74 = _lcls74_1); + if(i > 1) + { + if(!(_lcls74_1 instanceof _cls46)) + return null; + _lcls46_1 = (_cls46)_lcls74_1; + if(_lcls46_1._317vI() != 0) + return null; + if(i - 1 != _lcls46_1._22vI() - _lcls46_1._317vI()) + return null; + _lcls74_1 = _pcls103._2487474(_lcls74 = _lcls74_1); + } + } + _cls4 a_lcls4[] = new _cls4[i - 1]; + for(int k = 1; k < i; k++) + { + if(!(_lcls74_1 instanceof _cls4)) + return null; + a_lcls4[i - k - 1] = (_cls4)_lcls74_1; + _lcls74_1 = _pcls103._2487474(_lcls74 = _lcls74_1); + } + + super.m_368I++; + s = s != null ? s + "=" : "="; + boolean flag2 = false; + if(s.equals("+=") || s.equals("-=")) + { + String s1 = _lcls4.toString(); + if(s1.equals("1") || s1.equals("1L") || s1.equals("1.0") || s1.equals("1.0F")) + { + flag2 = true; + if(s.equals("+=")) + s = "++"; + else + s = "--"; + } + } + _cls61 _lcls61 = _lcls54._69a461(a_lcls4); + Object obj = null; + if(!flag2) + obj = new _cls92(_lcls61, _lcls54, s, _lcls4); + else + if(flag1) + obj = new _cls86(_lcls61, _lcls54, s); + else + obj = new _cls99(_lcls61, _lcls54, s); + Object obj1 = null; + if(flag) + obj1 = obj; + else + obj1 = new _cls76(((_cls4) (obj))); + ((_cls75) (obj1))._497475(_lcls74)._527475(_lcls54); + _pcls103._24274V(_lcls54); + _pcls103._24274V(_lcls46); + _pcls103._24274V(_lcls34); + _pcls103._24274V(_lcls4); + _pcls103._24274V(_lcls9); + _pcls103._24274V(_lcls46_1); + for(int l = 0; l < i - 1; l++) + _pcls103._24274V(a_lcls4[l]); + + return _pcls103._2497474(((_cls74) (obj1))); + } + + _cls142() + { + } +} diff --git a/src/modules/mocha/_cls143.java b/src/modules/mocha/_cls143.java new file mode 100644 index 0000000..a7c41c7 --- /dev/null +++ b/src/modules/mocha/_cls143.java @@ -0,0 +1,58 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls166, _cls149, _cls75, +// _cls164, _cls167, _cls155, _cls103, +// _cls148, _cls153, _cls141, _cls140, +// _cls150, _cls4, _cls142, _cls144, +// _cls137, _cls80, _cls135, _cls156, +// _cls134, _cls169, _cls158, _cls139, +// _cls159, _cls154, _cls161, _cls147, +// _cls162, _cls157, _cls165, _cls163, +// _cls171, _cls74, _cls101, _cls170, +// _cls133, _cls132, _cls145, _cls151, +// _cls160 + +class _cls143 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + _cls74 _lcls74 = _pcls74; + if(!(_lcls74 instanceof _cls101)) + return null; + _cls101 _lcls101 = (_cls101)_lcls74; + _lcls74 = _pcls103._254I74(_pcls74._26II(0)); + if(!(_lcls74 instanceof _cls4) || _lcls74._198vI() != 1) + return null; + _cls4 _lcls4 = (_cls4)_lcls74; + _lcls74 = _pcls103._254I74(_pcls74._26II(1)); + if(!(_lcls74 instanceof _cls4) || _lcls74._198vI() != 1) + return null; + _cls4 _lcls4_1 = (_cls4)_lcls74; + if(_lcls4._26II(0) != _lcls4_1._26II(0)) + { + return null; + } else + { + super.m_368I++; + Object obj = new _cls80(_lcls101._344v4(), _lcls4_1, _lcls4); + obj = ((_cls75) (obj))._497475(_lcls101)._527475(_lcls4); + _pcls103._24274V(_lcls101); + _pcls103._24274V(_lcls4_1); + _pcls103._24274V(_lcls4); + _pcls103._254I74(_lcls4_1._26II(0))._196vV(); + return _pcls103._2497474(((_cls74) (obj))); + } + } + + _cls143() + { + } +} diff --git a/src/modules/mocha/_cls144.java b/src/modules/mocha/_cls144.java new file mode 100644 index 0000000..f3f86ae --- /dev/null +++ b/src/modules/mocha/_cls144.java @@ -0,0 +1,178 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls34, _cls136, _cls146, +// _cls152, _cls168, _cls166, _cls149, +// _cls92, _cls52, _cls75, _cls164, +// _cls167, _cls2, _cls155, _cls103, +// _cls76, _cls148, _cls153, _cls141, +// _cls140, _cls150, _cls4, _cls142, +// _cls137, _cls143, _cls135, _cls156, +// _cls31, _cls134, _cls54, _cls169, +// _cls158, _cls46, _cls139, _cls159, +// _cls154, _cls161, _cls147, _cls162, +// _cls157, _cls165, _cls163, _cls171, +// _cls45, _cls170, _cls9, _cls133, +// _cls132, _cls145, _cls151, _cls160, +// _cls74 + +class _cls144 extends _cls138 +{ + + private boolean _37474SZ(_cls74 _pcls74, String s, String s1) + { + if(!(_pcls74 instanceof _cls52)) + return false; + _cls52 _lcls52 = (_cls52)_pcls74; + _cls2 _lcls2 = _lcls52._46v2(); + if(!_lcls2._56v2()._18vString().equals(s)) + return false; + else + return _lcls2._18vString().equals(s1); + } + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + boolean flag = false; + _cls46 _lcls46 = null; + _cls46 _lcls46_1 = null; + _cls9 _lcls9 = null; + Object obj1 = _pcls74; + if(!(obj1 instanceof _cls54)) + return null; + _cls54 _lcls54 = (_cls54)obj1; + int i = _lcls54._22vI(); + Object obj; + obj1 = _pcls103._2487474(((_cls74) (obj = obj1))); + if(obj1 instanceof _cls46) + { + flag = true; + _lcls46 = (_cls46)obj1; + if(_lcls46._317vI() != i - 1) + return null; + if(_lcls46._22vI() - _lcls46._317vI() != 1) + return null; + obj1 = _pcls103._2487474(((_cls74) (obj = obj1))); + } + if(!_37474SZ(((_cls74) (obj1)), "StringBuffer", "toString")) + return null; + _cls52 _lcls52 = (_cls52)obj1; + int j = 0; + do + { + obj1 = _pcls103._2487474(((_cls74) (obj1))); + if(!_37474SZ(((_cls74) (obj1)), "StringBuffer", "append")) + return null; + obj1 = _pcls103._2487474(((_cls74) (obj1))); + if(obj1 instanceof _cls4) + j++; + else + if(!(obj1 instanceof _cls45)) + return null; + } while(obj1 instanceof _cls4); + if(j < 1) + return null; + _cls52 a_lcls52[] = new _cls52[j + 1]; + _cls4 a_lcls4[] = new _cls4[j]; + obj1 = _lcls52; + for(int k = 0; k < j; k++) + { + obj1 = _pcls103._2487474(((_cls74) (obj1))); + a_lcls52[k] = (_cls52)obj1; + obj1 = _pcls103._2487474(((_cls74) (obj1))); + a_lcls4[k] = (_cls4)obj1; + } + + obj1 = _pcls103._2487474(((_cls74) (obj = obj1))); + a_lcls52[j] = (_cls52)obj1; + obj1 = _pcls103._2487474(((_cls74) (obj = obj1))); + if(!(obj1 instanceof _cls45)) + return null; + _cls45 _lcls45 = (_cls45)obj1; + obj1 = _pcls103._2487474(((_cls74) (obj = obj1))); + if(!(obj1 instanceof _cls4)) + return null; + _cls4 _lcls4 = (_cls4)obj1; + if(!_lcls4._51v61().toString().equals("new StringBuffer()")) + return null; + obj1 = _pcls103._2487474(((_cls74) (obj = obj1))); + _cls74 _lcls74 = ((_cls74) (obj1)); + if(_lcls74 instanceof _cls4) + _lcls74 = ((_cls4)_lcls74)._309v74(); + if(!(_lcls74 instanceof _cls9)) + return null; + _lcls9 = (_cls9)_lcls74; + if(!_lcls9._11431Z(_lcls54)) + return null; + obj1 = _pcls103._2487474(((_cls74) (obj = obj1))); + if(i > 1) + { + if(!(obj1 instanceof _cls46)) + return null; + _lcls46_1 = (_cls46)obj1; + if(_lcls46_1._317vI() != 0) + return null; + if(i - 1 != _lcls46_1._22vI() - _lcls46_1._317vI()) + return null; + obj1 = _pcls103._2487474(((_cls74) (obj = obj1))); + } + _cls4 a_lcls4_1[] = new _cls4[i - 1]; + for(int l = 1; l < i; l++) + { + if(!(obj1 instanceof _cls4)) + return null; + a_lcls4_1[i - l - 1] = (_cls4)obj1; + obj1 = _pcls103._2487474(((_cls74) (obj = obj1))); + } + + super.m_368I++; + _cls4 _lcls4_1 = null; + for(int i1 = j - 1; i1 >= 0; i1--) + if(_lcls4_1 == null) + { + _lcls4_1 = a_lcls4[i1]; + } else + { + _cls4 a_lcls4_2[] = { + _lcls4_1, a_lcls4[i1] + }; + _cls34 _lcls34 = new _cls34(0, 0, "Ljava/lang/String;", "+"); + _lcls4_1 = new _cls4(_lcls34, a_lcls4_2); + } + + _cls61 _lcls61 = _lcls54._69a461(a_lcls4_1); + _cls92 _lcls92 = new _cls92(_lcls61, _lcls54, "+=", _lcls4_1); + Object obj2; + if(flag) + obj2 = _lcls92; + else + obj2 = new _cls76(_lcls92); + ((_cls75) (obj2))._497475(((_cls74) (obj)))._527475(_lcls54); + _pcls103._24274V(_lcls54); + _pcls103._24274V(_lcls46); + _pcls103._24274V(_lcls52); + for(int j1 = 0; j1 < a_lcls52.length; j1++) + _pcls103._24274V(a_lcls52[j1]); + + for(int k1 = 0; k1 < a_lcls4.length; k1++) + _pcls103._24274V(a_lcls4[k1]); + + _pcls103._24274V(_lcls45); + _pcls103._24274V(_lcls4); + _pcls103._24274V(_lcls9); + _pcls103._24274V(_lcls46_1); + for(int l1 = 0; l1 < i - 1; l1++) + _pcls103._24274V(a_lcls4_1[l1]); + + return _pcls103._2497474(((_cls74) (obj2))); + } + + _cls144() + { + } +} diff --git a/src/modules/mocha/_cls145.java b/src/modules/mocha/_cls145.java new file mode 100644 index 0000000..6bf5083 --- /dev/null +++ b/src/modules/mocha/_cls145.java @@ -0,0 +1,79 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls36, _cls166, _cls149, +// _cls52, _cls164, _cls167, _cls155, +// _cls103, _cls76, _cls148, _cls153, +// _cls141, _cls140, _cls150, _cls4, +// _cls142, _cls144, _cls137, _cls143, +// _cls135, _cls156, _cls134, _cls81, +// _cls169, _cls158, _cls46, _cls139, +// _cls159, _cls154, _cls161, _cls147, +// _cls162, _cls157, _cls165, _cls163, +// _cls171, _cls74, _cls170, _cls133, +// _cls132, _cls151, _cls160 + +class _cls145 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls52)) + return null; + if(_pcls74._117vI() > 0) + return null; + _cls52 _lcls52 = (_cls52)_pcls74; + if(!_lcls52._74vZ()) + return null; + int i = _pcls74._22vI() - 1; + _cls4 a_lcls4[] = new _cls4[i]; + _cls74 _lcls74 = _pcls74; + for(int j = 0; j < i; j++) + { + _lcls74 = _pcls103._2487474(_lcls74); + if(!(_lcls74 instanceof _cls4)) + return null; + a_lcls4[i - j - 1] = (_cls4)_lcls74; + } + + _cls46 _lcls46 = null; + _lcls74 = _pcls103._2487474(_lcls74); + if(_lcls74 instanceof _cls46) + { + _lcls46 = (_cls46)_lcls74; + if(_lcls46._317vI() != 0) + return null; + _lcls74 = _pcls103._2487474(_lcls74); + } + if(!(_lcls74 instanceof _cls4)) + return null; + _cls4 _lcls4 = (_cls4)_lcls74; + _cls74 _lcls74_1 = _lcls4._309v74(); + if(!(_lcls74_1 instanceof _cls36)) + return null; + super.m_368I++; + _cls81 _lcls81 = new _cls81(_lcls4, a_lcls4, _lcls52); + Object obj; + if(_lcls46 == null) + obj = new _cls76(_lcls81); + else + obj = _lcls81; + _pcls103._24274V(_lcls4); + _pcls103._24274V(_lcls46); + for(int k = 0; k < i; k++) + _pcls103._24274V(a_lcls4[k]); + + _pcls103._24274V(_lcls52); + return _pcls103._2497474(((_cls74) (obj))); + } + + _cls145() + { + } +} diff --git a/src/modules/mocha/_cls146.java b/src/modules/mocha/_cls146.java new file mode 100644 index 0000000..22a6233 --- /dev/null +++ b/src/modules/mocha/_cls146.java @@ -0,0 +1,102 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls152, _cls168, +// _cls166, _cls149, _cls20, _cls75, +// _cls164, _cls167, _cls155, _cls103, +// _cls148, _cls153, _cls141, _cls140, +// _cls150, _cls4, _cls142, _cls144, +// _cls137, _cls143, _cls135, _cls156, +// _cls134, _cls169, _cls158, _cls46, +// _cls139, _cls159, _cls154, _cls161, +// _cls147, _cls50, _cls162, _cls157, +// _cls90, _cls165, _cls163, _cls171, +// _cls170, _cls133, _cls132, _cls145, +// _cls151, _cls160, _cls74 + +class _cls146 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls4)) + return null; + _cls4 _lcls4 = (_cls4)_pcls74; + _cls74 _lcls74 = _lcls4._309v74(); + if(!(_lcls74 instanceof _cls20)) + return null; + int i = 0; + if(_lcls4._22vI() != 1) + return null; + try + { + i = Integer.parseInt(_lcls4._65I4(0).toString()); + } + catch(NumberFormatException _ex) + { + return null; + } + if(i == 0) + return null; + _cls74 _lcls74_1 = null; + _cls74 _lcls74_2 = _pcls103._2397474(_pcls74); + _cls4 a_lcls4[] = new _cls4[i]; + for(int j = 0; j < i; j++) + { + if(!(_lcls74_2 instanceof _cls46)) + return null; + _cls46 _lcls46 = (_cls46)_lcls74_2; + if(_lcls46._317vI() != 0) + return null; + _lcls74_2 = _pcls103._2397474(_lcls74_2); + if(!(_lcls74_2 instanceof _cls4)) + return null; + _cls4 _lcls4_1 = (_cls4)_lcls74_2; + int l = 0; + try + { + l = Integer.parseInt(_lcls4_1.toString()); + } + catch(NumberFormatException _ex) + { + return null; + } + if(l != j) + return null; + _lcls74_2 = _pcls103._2397474(_lcls74_2); + if(!(_lcls74_2 instanceof _cls4)) + return null; + a_lcls4[j] = (_cls4)_lcls74_2; + _lcls74_2 = _pcls103._2397474(_lcls74_2); + if(!(_lcls74_2 instanceof _cls50)) + return null; + _lcls74_1 = _lcls74_2; + _lcls74_2 = _pcls103._2397474(_lcls74_2); + } + + super.m_368I++; + _cls75 _lcls75 = (new _cls90(a_lcls4))._497475(_lcls4)._527475(_lcls74_1); + _pcls103._24274V(_lcls4); + _lcls74_2 = _pcls103._2397474(_pcls74); + for(int k = 0; k < i; k++) + { + for(int i1 = 0; i1 < 4; i1++) + { + _pcls103._24274V(_lcls74_2); + _lcls74_2 = _pcls103._2397474(_lcls74_2); + } + + } + + return _pcls103._2497474(_lcls75); + } + + _cls146() + { + } +} diff --git a/src/modules/mocha/_cls147.java b/src/modules/mocha/_cls147.java new file mode 100644 index 0000000..927c2d0 --- /dev/null +++ b/src/modules/mocha/_cls147.java @@ -0,0 +1,50 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls162, _cls159, +// _cls161, _cls160, _cls141, _cls76, +// _cls140, _cls171, _cls169, _cls154, +// _cls146, _cls152, _cls143, _cls167, +// _cls149, _cls132, _cls139, _cls156, +// _cls133, _cls168, _cls158, _cls165, +// _cls103, _cls142, _cls135, _cls137, +// _cls92, _cls157, _cls7, _cls83, +// _cls166, _cls136, _cls150, _cls163, +// _cls170, _cls134, _cls153, _cls151, +// _cls74 + +class _cls147 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls76)) + return null; + _cls76 _lcls76 = (_cls76)_pcls74; + _cls4 _lcls4 = _lcls76._78v4(); + if(!(_lcls4 instanceof _cls92)) + return null; + _cls92 _lcls92 = (_cls92)_lcls4; + _cls7 _lcls7 = _lcls92._66v7(); + if(_lcls7 == null) + { + return null; + } else + { + super.m_368I++; + _lcls7._54V(_lcls92._65I4(0)); + _cls83 _lcls83 = new _cls83(_pcls74); + return _pcls103._2497474(_lcls83); + } + } + + _cls147() + { + } +} diff --git a/src/modules/mocha/_cls148.java b/src/modules/mocha/_cls148.java new file mode 100644 index 0000000..34016ba --- /dev/null +++ b/src/modules/mocha/_cls148.java @@ -0,0 +1,90 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls34, _cls136, _cls146, +// _cls152, _cls168, _cls166, _cls149, +// _cls52, _cls75, _cls164, _cls167, +// _cls2, _cls155, _cls103, _cls153, +// _cls141, _cls140, _cls150, _cls4, +// _cls142, _cls144, _cls137, _cls143, +// _cls135, _cls156, _cls134, _cls169, +// _cls158, _cls139, _cls159, _cls154, +// _cls161, _cls147, _cls162, _cls157, +// _cls165, _cls163, _cls171, _cls170, +// _cls133, _cls132, _cls145, _cls151, +// _cls160, _cls74 + +class _cls148 extends _cls138 +{ + + private boolean _37474SZ(_cls74 _pcls74, String s, String s1) + { + if(!(_pcls74 instanceof _cls4)) + return false; + _cls4 _lcls4 = (_cls4)_pcls74; + _cls74 _lcls74 = _lcls4._309v74(); + if(!(_lcls74 instanceof _cls52)) + return false; + _cls52 _lcls52 = (_cls52)_lcls74; + _cls2 _lcls2 = _lcls52._46v2(); + if(!_lcls2._56v2()._18vString().equals(s)) + return false; + else + return _lcls2._18vString().equals(s1); + } + + private int _3754I(_cls4 _pcls4) + { + if(_37474SZ(_pcls4, "StringBuffer", "")) + return 0; + if(_37474SZ(_pcls4, "StringBuffer", "append")) + return _3754I(_pcls4._65I4(0)) + 1; + else + return -1000; + } + + private _cls4 _37644(_cls4 _pcls4, _cls4 _pcls4_1, _cls4 _pcls4_2) + { + if(_37474SZ(_pcls4, "StringBuffer", "append")) + _pcls4_1 = _37644(_pcls4._65I4(0), _pcls4._65I4(1), _pcls4_1); + if(_pcls4_2 == null) + { + return _pcls4_1; + } else + { + _cls4 a_lcls4[] = { + _pcls4_1, _pcls4_2 + }; + _cls34 _lcls34 = new _cls34(0, 0, "Ljava/lang/String;", "+"); + return new _cls4(_lcls34, a_lcls4); + } + } + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!_37474SZ(_pcls74, "StringBuffer", "toString")) + return null; + _cls4 _lcls4 = (_cls4)_pcls74; + int i = _3754I(_lcls4._65I4(0)); + if(i < 2) + { + return null; + } else + { + super.m_368I++; + Object obj = _37644(_lcls4._65I4(0), null, null); + obj = ((_cls75) (obj))._497475(_pcls74)._527475(_pcls74); + _pcls103._24274V(_pcls74); + return _pcls103._2497474(((_cls74) (obj))); + } + } + + _cls148() + { + } +} diff --git a/src/modules/mocha/_cls149.java b/src/modules/mocha/_cls149.java new file mode 100644 index 0000000..0a89e10 --- /dev/null +++ b/src/modules/mocha/_cls149.java @@ -0,0 +1,60 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls166, _cls164, _cls167, +// _cls155, _cls103, _cls148, _cls153, +// _cls141, _cls140, _cls150, _cls142, +// _cls144, _cls137, _cls143, _cls135, +// _cls156, _cls134, _cls169, _cls158, +// _cls139, _cls159, _cls154, _cls161, +// _cls147, _cls122, _cls162, _cls157, +// _cls165, _cls163, _cls171, _cls74, +// _cls170, _cls133, _cls132, _cls145, +// _cls151, _cls94, _cls160 + +class _cls149 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + boolean flag = false; + int i = _pcls74._25vI(); + int j = _pcls74._155vI(); + for(int k = 0; k < i; k++) + { + int l = _pcls74._26II(k); + if(l != _pcls103._258II(j)) + { + _cls122 _lcls122 = _pcls103._240I122(l); + if(_lcls122 != null && _lcls122._352IZ(j)) + { + int i1 = _pcls103._247III(j, l); + _cls94 _lcls94 = new _cls94(i1, _lcls122); + _pcls103._2497474(_lcls94); + _pcls103._254I74(l)._196vV(); + _pcls74._21IIV(k, i1); + flag = true; + } + } + } + + if(!flag) + { + return null; + } else + { + super.m_368I++; + return _pcls103._254I74(0); + } + } + + _cls149() + { + } +} diff --git a/src/modules/mocha/_cls15.java b/src/modules/mocha/_cls15.java new file mode 100644 index 0000000..7fbdf3e --- /dev/null +++ b/src/modules/mocha/_cls15.java @@ -0,0 +1,61 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls34, _cls29, _cls42, +// _cls16, _cls44, _cls41, _cls36, +// _cls32, _cls24, _cls14, _cls20, +// _cls52, _cls2, _cls26, _cls25, +// _cls23, _cls27, _cls33, _cls35, +// _cls40, _cls19, _cls49, _cls47, +// _cls38, _cls30, _cls37, _cls54, +// _cls39, _cls48, _cls11, _cls46, +// _cls28, _cls12, _cls0, _cls53, +// _cls50, _cls10, _cls55, _cls8, +// _cls22, _cls17, _cls13, _cls51, +// _cls45, _cls21, _cls9, _cls18, +// _cls43, _cls69, _cls71 + +class _cls15 extends _cls31 +{ + + protected int m_260I; + protected _cls0 m_160; + + _cls15(int i, int j, int k) + { + super(i, j); + m_260I = k; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_160 = _pcls0; + } + + public int _117vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + _cls2 _lcls2 = m_160._9I2(m_260I); + return _pcls23._716123(new _cls69(_lcls2._81vString(), _lcls2.toString())); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("push " + m_160._9I2(m_260I)); + } + + public void _19vV() + { + m_260I = m_160._19IStringI(m_260I, "literal"); + } +} diff --git a/src/modules/mocha/_cls150.java b/src/modules/mocha/_cls150.java new file mode 100644 index 0000000..0603f24 --- /dev/null +++ b/src/modules/mocha/_cls150.java @@ -0,0 +1,51 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls74, _cls162, +// _cls159, _cls161, _cls160, _cls141, +// _cls140, _cls147, _cls171, _cls169, +// _cls154, _cls146, _cls152, _cls143, +// _cls167, _cls149, _cls132, _cls139, +// _cls156, _cls133, _cls168, _cls158, +// _cls165, _cls103, _cls4, _cls142, +// _cls135, _cls137, _cls157, _cls166, +// _cls136, _cls163, _cls170, _cls134, +// _cls153, _cls151 + +class _cls150 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(_pcls74._117vI() != 1) + return null; + int i = _pcls74._22vI(); + _cls4 a_lcls4[] = new _cls4[i]; + _cls74 _lcls74 = _pcls74; + for(int j = 0; j < i; j++) + { + _lcls74 = _pcls103._2487474(_lcls74); + if(!(_lcls74 instanceof _cls4)) + return null; + a_lcls4[i - j - 1] = (_cls4)_lcls74; + } + + super.m_368I++; + _cls4 _lcls4 = new _cls4(_pcls74, a_lcls4); + _pcls103._24274V(_pcls74); + for(int k = 0; k < i; k++) + _pcls103._24274V(a_lcls4[k]); + + return _pcls103._2497474(_lcls4); + } + + _cls150() + { + } +} diff --git a/src/modules/mocha/_cls151.java b/src/modules/mocha/_cls151.java new file mode 100644 index 0000000..727dbbd --- /dev/null +++ b/src/modules/mocha/_cls151.java @@ -0,0 +1,44 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls74, _cls162, +// _cls159, _cls161, _cls160, _cls141, +// _cls140, _cls147, _cls171, _cls169, +// _cls82, _cls154, _cls146, _cls152, +// _cls143, _cls167, _cls149, _cls132, +// _cls139, _cls156, _cls133, _cls85, +// _cls168, _cls158, _cls165, _cls103, +// _cls142, _cls135, _cls137, _cls157, +// _cls83, _cls166, _cls136, _cls150, +// _cls163, _cls170, _cls134, _cls153 + +class _cls151 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls85)) + return null; + _pcls74._155vI(); + for(_cls82 _lcls82 = _pcls103._178v82(); _lcls82._174vZ();) + if(_lcls82._177v74() == _pcls74 && !_lcls82._174vZ()) + { + super.m_368I++; + _cls83 _lcls83 = new _cls83(_pcls74); + _pcls103._24274V(_pcls74); + return _pcls103._2497474(_lcls83); + } + + return null; + } + + _cls151() + { + } +} diff --git a/src/modules/mocha/_cls152.java b/src/modules/mocha/_cls152.java new file mode 100644 index 0000000..8fb46a0 --- /dev/null +++ b/src/modules/mocha/_cls152.java @@ -0,0 +1,67 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls77, _cls164, _cls155, _cls162, +// _cls159, _cls161, _cls160, _cls141, +// _cls140, _cls147, _cls171, _cls169, +// _cls154, _cls146, _cls143, _cls167, +// _cls149, _cls132, _cls139, _cls156, +// _cls133, _cls168, _cls158, _cls165, +// _cls103, _cls78, _cls142, _cls135, +// _cls137, _cls157, _cls166, _cls136, +// _cls150, _cls163, _cls170, _cls134, +// _cls153, _cls151, _cls74 + +class _cls152 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + _cls78 _lcls78 = null; + _cls78 _lcls78_1 = null; + int i = 0; + for(_cls74 _lcls74 = _pcls74; _lcls74 instanceof _cls78; _lcls74 = _pcls103._2487474(_lcls78)) + { + _lcls78 = (_cls78)_lcls74; + i += _lcls78._291vI(); + } + + if(_lcls78 == null) + return null; + for(_cls74 _lcls74_1 = _pcls74; _lcls74_1 instanceof _cls78; _lcls74_1 = _pcls103._2397474(_lcls78_1)) + { + _lcls78_1 = (_cls78)_lcls74_1; + i += _lcls78_1._291vI(); + } + + if(_lcls78_1 == _lcls78) + return null; + super.m_368I++; + i -= ((_cls78)_pcls74)._291vI(); + _cls78 a_lcls78[] = new _cls78[i]; + Object obj = _lcls78; + for(int j = 0; j < i;) + { + _cls78 _lcls78_2 = (_cls78)obj; + for(int k = 0; k < _lcls78_2._291vI(); k++) + a_lcls78[j + k] = _lcls78_2._290I78(k); + + j += _lcls78_2._291vI(); + _pcls103._24274V(((_cls74) (obj))); + obj = _pcls103._2397474(((_cls74) (obj))); + } + + _cls77 _lcls77 = new _cls77(a_lcls78); + return _pcls103._2497474(_lcls77); + } + + _cls152() + { + } +} diff --git a/src/modules/mocha/_cls153.java b/src/modules/mocha/_cls153.java new file mode 100644 index 0000000..4e8106e --- /dev/null +++ b/src/modules/mocha/_cls153.java @@ -0,0 +1,93 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls166, _cls149, _cls75, +// _cls164, _cls167, _cls155, _cls103, +// _cls100, _cls148, _cls141, _cls33, +// _cls140, _cls150, _cls142, _cls144, +// _cls137, _cls143, _cls135, _cls156, +// _cls134, _cls169, _cls158, _cls139, +// _cls159, _cls154, _cls108, _cls161, +// _cls147, _cls162, _cls157, _cls165, +// _cls163, _cls171, _cls74, _cls170, +// _cls133, _cls132, _cls78, _cls145, +// _cls151, _cls18, _cls160 + +class _cls153 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(_pcls74._198vI() > 0) + return null; + _cls74 _lcls74 = _pcls74; + int i = _lcls74._155vI(); + if(_pcls74 instanceof _cls18) + _pcls74 = _pcls103._2397474(_pcls74); + if(!(_pcls74 instanceof _cls78)) + return null; + _cls78 _lcls78 = (_cls78)_pcls74; + _cls74 _lcls74_1 = _pcls74; + if(_lcls74 instanceof _cls18) + { + _lcls74_1 = _pcls103._2397474(_pcls74); + if(!(_lcls74_1 instanceof _cls33)) + return null; + } + _cls108 a_lcls108[] = _pcls103._243va108(); + int j = -1; + for(int k = 0; j < 0 && k < a_lcls108.length; k++) + if(a_lcls108[k]._57vI() == i && a_lcls108[k]._55vString().equals("")) + j = k; + + if(j < 0) + return null; + int l = a_lcls108[j]._59vI(); + _pcls74 = _pcls103._254I74(l); + if(!(_pcls74 instanceof _cls78)) + return null; + _cls78 _lcls78_1 = (_cls78)_pcls74; + int i1 = _lcls78_1._26II(0); + if(_lcls74 instanceof _cls18) + { + if(i1 >= 0 && i1 != a_lcls108[j]._62vI()) + return null; + } else + if(i1 != i || _lcls74_1._25vI() > 0) + return null; + super.m_368I++; + _lcls78_1._196vV(); + _pcls74 = _pcls103._254I74(a_lcls108[j]._62vI()); + if(_pcls74 != null) + _pcls74._196vV(); + _cls100 _lcls100; + if(_lcls78_1 instanceof _cls100) + { + _cls100 _lcls100_1 = (_cls100)_lcls78_1; + _lcls78_1 = _lcls100_1._289v78(); + _cls89 a_lcls89[] = _lcls100_1._287va89(); + _lcls100 = new _cls100(_lcls78_1, a_lcls89, _lcls78); + _pcls103._24274V(_lcls100_1); + } else + { + _lcls100 = new _cls100(_lcls78_1, null, _lcls78); + _pcls103._24274V(_lcls78_1); + } + if(!(_lcls74 instanceof _cls18)) + _lcls100._21IIV(0, -1); + _pcls103._24274V(_lcls74); + _pcls103._24274V(_lcls78); + _pcls103._24274V(_lcls74_1); + return _pcls103._2497474(_lcls100); + } + + _cls153() + { + } +} diff --git a/src/modules/mocha/_cls154.java b/src/modules/mocha/_cls154.java new file mode 100644 index 0000000..78174a8 --- /dev/null +++ b/src/modules/mocha/_cls154.java @@ -0,0 +1,53 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls74, _cls162, +// _cls159, _cls52, _cls161, _cls160, +// _cls141, _cls140, _cls147, _cls171, +// _cls169, _cls146, _cls152, _cls143, +// _cls167, _cls149, _cls132, _cls139, +// _cls156, _cls133, _cls168, _cls158, +// _cls165, _cls103, _cls4, _cls142, +// _cls135, _cls137, _cls97, _cls157, +// _cls166, _cls136, _cls150, _cls163, +// _cls170, _cls134, _cls153, _cls151 + +class _cls154 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls52)) + return null; + if(_pcls74._117vI() > 0) + return null; + int i = _pcls74._22vI(); + _cls4 a_lcls4[] = new _cls4[i]; + _cls74 _lcls74 = _pcls74; + for(int j = 0; j < i; j++) + { + _lcls74 = _pcls103._2487474(_lcls74); + if(!(_lcls74 instanceof _cls4)) + return null; + a_lcls4[i - j - 1] = (_cls4)_lcls74; + } + + super.m_368I++; + _cls97 _lcls97 = new _cls97((_cls52)_pcls74, a_lcls4); + _pcls103._24274V(_pcls74); + for(int k = 0; k < i; k++) + _pcls103._24274V(a_lcls4[k]); + + return _pcls103._2497474(_lcls97); + } + + _cls154() + { + } +} diff --git a/src/modules/mocha/_cls155.java b/src/modules/mocha/_cls155.java new file mode 100644 index 0000000..16bd57c --- /dev/null +++ b/src/modules/mocha/_cls155.java @@ -0,0 +1,119 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls42, _cls146, +// _cls152, _cls168, _cls166, _cls149, +// _cls92, _cls75, _cls164, _cls167, +// _cls103, _cls76, _cls148, _cls153, +// _cls141, _cls140, _cls150, _cls4, +// _cls142, _cls144, _cls137, _cls143, +// _cls135, _cls156, _cls134, _cls169, +// _cls158, _cls12, _cls139, _cls159, +// _cls154, _cls161, _cls147, _cls162, +// _cls157, _cls165, _cls163, _cls22, +// _cls171, _cls99, _cls86, _cls170, +// _cls133, _cls132, _cls145, _cls151, +// _cls160, _cls74 + +class _cls155 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + boolean flag = false; + boolean flag1 = false; + Object obj = null; + Object obj1 = _pcls74; + Object obj2 = _pcls74; + if(!(_pcls74 instanceof _cls22)) + return null; + _cls22 _lcls22 = (_cls22)_pcls74; + _cls74 _lcls74 = _pcls103._2487474(_pcls74); + if(_lcls74 instanceof _cls4) + _lcls74 = ((_cls4)_lcls74)._309v74(); + if(_lcls74 instanceof _cls12) + { + _cls12 _lcls12 = (_cls12)_lcls74; + if(_lcls12._11431Z(_lcls22)) + { + flag = true; + obj1 = _lcls12; + } + } + if(!flag) + { + _cls74 _lcls74_1 = _pcls103._2397474(_pcls74); + if(_lcls74_1 instanceof _cls4) + _lcls74_1 = ((_cls4)_lcls74_1)._309v74(); + if(_lcls74_1 instanceof _cls12) + { + _cls12 _lcls12_1 = (_cls12)_lcls74_1; + if(_lcls12_1._11431Z(_lcls22)) + { + flag = true; + flag1 = true; + obj2 = _lcls12_1; + } + } + } + int i = _lcls22._281vI(); + boolean flag2 = false; + String s = null; + switch(i) + { + case 1: // '\001' + s = "++"; + flag2 = true; + break; + + case -1: + s = "--"; + flag2 = true; + break; + + case 0: // '\0' + default: + if(i < 0) + { + s = "-="; + i = -i; + } else + { + s = "+="; + } + break; + } + super.m_368I++; + _cls61 _lcls61 = _lcls22._69a461(null); + Object obj3 = null; + if(!flag2) + { + _cls42 _lcls42 = new _cls42(0, 0, "I", String.valueOf(i)); + _cls4 a_lcls4[] = new _cls4[0]; + _cls4 _lcls4 = new _cls4(_lcls42, a_lcls4); + obj3 = new _cls92(_lcls61, ((_cls74) (obj2)), s, _lcls4); + } else + if(flag1) + obj3 = new _cls86(_lcls61, ((_cls74) (obj2)), s); + else + obj3 = new _cls99(_lcls61, ((_cls74) (obj2)), s); + Object obj4 = null; + if(flag) + obj4 = obj3; + else + obj4 = new _cls76(((_cls4) (obj3))); + ((_cls75) (obj4))._497475(((_cls74) (obj1)))._527475(((_cls74) (obj2))); + _pcls103._24274V(((_cls74) (obj1))); + _pcls103._24274V(((_cls74) (obj2))); + return _pcls103._2497474(((_cls74) (obj4))); + } + + _cls155() + { + } +} diff --git a/src/modules/mocha/_cls156.java b/src/modules/mocha/_cls156.java new file mode 100644 index 0000000..3cb4d5e --- /dev/null +++ b/src/modules/mocha/_cls156.java @@ -0,0 +1,41 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls74, _cls162, +// _cls159, _cls161, _cls160, _cls141, +// _cls140, _cls147, _cls171, _cls169, +// _cls154, _cls146, _cls152, _cls143, +// _cls167, _cls149, _cls132, _cls28, +// _cls139, _cls133, _cls168, _cls158, +// _cls165, _cls103, _cls142, _cls135, +// _cls137, _cls157, _cls83, _cls166, +// _cls136, _cls150, _cls163, _cls170, +// _cls134, _cls153, _cls151 + +class _cls156 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls28)) + { + return null; + } else + { + _pcls103._254I74(_pcls74._26II(1))._196vV(); + _pcls74._21IIV(1, -1); + _cls83 _lcls83 = new _cls83(_pcls74); + return _pcls103._2497474(_lcls83); + } + } + + _cls156() + { + } +} diff --git a/src/modules/mocha/_cls157.java b/src/modules/mocha/_cls157.java new file mode 100644 index 0000000..d85f95f --- /dev/null +++ b/src/modules/mocha/_cls157.java @@ -0,0 +1,48 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls162, _cls159, +// _cls161, _cls160, _cls141, _cls140, +// _cls147, _cls171, _cls169, _cls154, +// _cls146, _cls152, _cls143, _cls167, +// _cls149, _cls132, _cls139, _cls156, +// _cls133, _cls168, _cls158, _cls165, +// _cls75, _cls103, _cls4, _cls142, +// _cls135, _cls11, _cls137, _cls98, +// _cls166, _cls136, _cls150, _cls163, +// _cls170, _cls134, _cls153, _cls151, +// _cls74 + +class _cls157 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls11)) + return null; + _cls74 _lcls74 = _pcls103._2487474(_pcls74); + if(!(_lcls74 instanceof _cls4)) + { + return null; + } else + { + _cls4 _lcls4 = (_cls4)_lcls74; + super.m_368I++; + _cls98 _lcls98 = new _cls98(_lcls4); + _lcls98._527475(_pcls74); + _pcls103._24274V(_lcls4); + _pcls103._24274V(_pcls74); + return _pcls103._2497474(_lcls98); + } + } + + _cls157() + { + } +} diff --git a/src/modules/mocha/_cls158.java b/src/modules/mocha/_cls158.java new file mode 100644 index 0000000..9ce3e0e --- /dev/null +++ b/src/modules/mocha/_cls158.java @@ -0,0 +1,48 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls162, _cls159, +// _cls161, _cls160, _cls141, _cls76, +// _cls140, _cls147, _cls14, _cls171, +// _cls169, _cls154, _cls146, _cls152, +// _cls143, _cls167, _cls149, _cls132, +// _cls139, _cls156, _cls133, _cls168, +// _cls165, _cls75, _cls103, _cls4, +// _cls142, _cls135, _cls137, _cls157, +// _cls166, _cls136, _cls150, _cls163, +// _cls170, _cls134, _cls153, _cls151, +// _cls74 + +class _cls158 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls14)) + return null; + _cls74 _lcls74 = _pcls103._2487474(_pcls74); + if(!(_lcls74 instanceof _cls4)) + { + return null; + } else + { + _cls4 _lcls4 = (_cls4)_lcls74; + super.m_368I++; + _cls76 _lcls76 = new _cls76(_lcls4); + _lcls76._527475(_pcls74); + _pcls103._24274V(_lcls4); + _pcls103._24274V(_pcls74); + return _pcls103._2497474(_lcls76); + } + } + + _cls158() + { + } +} diff --git a/src/modules/mocha/_cls159.java b/src/modules/mocha/_cls159.java new file mode 100644 index 0000000..e5c55fe --- /dev/null +++ b/src/modules/mocha/_cls159.java @@ -0,0 +1,122 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls166, _cls149, _cls14, +// _cls75, _cls164, _cls167, _cls155, +// _cls103, _cls100, _cls148, _cls153, +// _cls141, _cls140, _cls150, _cls71, +// _cls142, _cls144, _cls137, _cls143, +// _cls135, _cls156, _cls134, _cls169, +// _cls158, _cls139, _cls154, _cls108, +// _cls161, _cls147, _cls162, _cls157, +// _cls165, _cls163, _cls171, _cls74, +// _cls170, _cls89, _cls133, _cls132, +// _cls78, _cls145, _cls151, _cls18, +// _cls160 + +class _cls159 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls78)) + return null; + if(_pcls74._198vI() < 2) + return null; + _cls78 _lcls78 = (_cls78)_pcls74; + int i = _pcls74._155vI(); + int j = _pcls74._26II(0); + _cls108 a_lcls108[] = _pcls103._243va108(); + int k = -1; + int l = 0; + for(int i1 = 0; i1 < a_lcls108.length; i1++) + if(a_lcls108[i1]._59vI() == i && !a_lcls108[i1]._55vString().equals("")) + { + if(k < 0) + k = a_lcls108[i1]._62vI(); + if(a_lcls108[i1]._62vI() == k) + { + _pcls74 = _pcls103._254I74(a_lcls108[i1]._57vI()); + if(!(_pcls74 instanceof _cls18) && !(_pcls74 instanceof _cls14)) + return null; + if((_pcls74 instanceof _cls18) || _pcls103._2397474(_pcls74) != null) + { + _pcls74 = _pcls103._2397474(_pcls74); + if(!(_pcls74 instanceof _cls78)) + return null; + } + if(j < 0) + j = _pcls74._26II(0); + if(_pcls74._26II(0) >= 0 && _pcls74._26II(0) != j) + return null; + l++; + } + } + + if(l == 0) + return null; + super.m_368I++; + _cls89 a_lcls89[] = new _cls89[l]; + _cls108 a_lcls108_1[] = new _cls108[a_lcls108.length - l]; + int j1 = 0; + int k1 = 0; + for(int l1 = 0; l1 < a_lcls108.length; l1++) + { + _cls108 _lcls108 = a_lcls108[l1]; + if(_lcls108._59vI() == i && _lcls108._62vI() == k) + { + _pcls74 = _pcls103._254I74(a_lcls108[l1]._57vI()); + _pcls103._24274V(_pcls74); + _cls78 _lcls78_1 = null; + _cls74 _lcls74 = _pcls103._2397474(_pcls74); + if(_lcls74 == null) + { + _lcls74 = _pcls74; + } else + { + _pcls103._24274V(_lcls74); + _lcls78_1 = (_cls78)_lcls74; + } + _cls89 _lcls89; + if(_pcls74 instanceof _cls18) + { + _lcls89 = new _cls89(_lcls78_1); + } else + { + _cls71 _lcls71 = _pcls103._257v71(); + _cls126 _lcls126 = _lcls71._98String126(_lcls108._61vString()); + _lcls89 = new _cls89(_lcls78_1, _lcls108._55vString(), _lcls126); + } + _lcls89._497475(_pcls74); + a_lcls89[j1++] = _lcls89; + _lcls78._196vV(); + _pcls74 = _pcls103._254I74(a_lcls108[l1]._62vI()); + if(_pcls74 != null) + _pcls74._196vV(); + if(_lcls74._26II(0) >= 0) + _pcls103._254I74(_lcls74._26II(0))._196vV(); + } else + { + a_lcls108_1[k1++] = _lcls108; + } + } + + if(j >= 0 && _lcls78._26II(0) != j) + _pcls103._254I74(j)._197vV(); + _cls100 _lcls100 = new _cls100(_lcls78, a_lcls89, null); + _lcls100._21IIV(0, j); + _pcls103._253a108V(a_lcls108_1); + _pcls103._24274V(_lcls78); + return _pcls103._2497474(_lcls100); + } + + _cls159() + { + } +} diff --git a/src/modules/mocha/_cls16.java b/src/modules/mocha/_cls16.java new file mode 100644 index 0000000..1bb64c4 --- /dev/null +++ b/src/modules/mocha/_cls16.java @@ -0,0 +1,56 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls55, _cls15, _cls34, _cls29, +// _cls42, _cls44, _cls41, _cls36, +// _cls32, _cls24, _cls14, _cls20, +// _cls52, _cls26, _cls25, _cls23, +// _cls27, _cls33, _cls35, _cls40, +// _cls19, _cls71, _cls49, _cls47, +// _cls38, _cls31, _cls30, _cls37, +// _cls54, _cls39, _cls48, _cls11, +// _cls46, _cls28, _cls12, _cls53, +// _cls50, _cls10, _cls8, _cls22, +// _cls17, _cls13, _cls51, _cls45, +// _cls21, _cls9, _cls18, _cls43, +// _cls103 + +class _cls16 extends _cls55 +{ + + _cls16(int i, int j, String s, int k) + { + super(i, j, s, k); + } + + public int _22vI() + { + return 1; + } + + public void _10723V(_cls23 _pcls23, _cls103 _pcls103) + { + if(super.m_10523 == null) + { + if(!super.m_32String.equals("==") && !super.m_32String.equals("!=")) + super.m_11271._18661vV(_pcls23._113v61(), super.m_110I); + super._10723V(_pcls23, _pcls103); + } + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._29v23(); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("if " + super.m_32String + " goto " + super.m_27I); + } +} diff --git a/src/modules/mocha/_cls160.java b/src/modules/mocha/_cls160.java new file mode 100644 index 0000000..5a5add6 --- /dev/null +++ b/src/modules/mocha/_cls160.java @@ -0,0 +1,190 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls77, _cls168, _cls166, _cls149, +// _cls92, _cls75, _cls164, _cls167, +// _cls155, _cls103, _cls105, _cls76, +// _cls148, _cls153, _cls141, _cls140, +// _cls150, _cls91, _cls4, _cls142, +// _cls144, _cls137, _cls143, _cls135, +// _cls156, _cls134, _cls169, _cls158, +// _cls139, _cls159, _cls154, _cls161, +// _cls147, _cls122, _cls162, _cls157, +// _cls165, _cls163, _cls171, _cls74, +// _cls101, _cls82, _cls170, _cls133, +// _cls132, _cls78, _cls145, _cls151 + +class _cls160 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls101)) + return null; + _cls101 _lcls101 = (_cls101)_pcls74; + _cls74 _lcls74; + int i; + boolean flag; + if(flag = _lcls101._26II(0) < _lcls101._26II(1)) + { + _lcls74 = _pcls103._254I74(_lcls101._26II(0)); + i = _lcls101._26II(1); + } else + { + _lcls74 = _pcls103._254I74(_lcls101._26II(1)); + i = _lcls101._26II(0); + } + _cls78 _lcls78; + if(_lcls74._155vI() == _lcls101._155vI()) + _lcls78 = null; + else + if((_lcls74 instanceof _cls78) && _lcls74._198vI() == 1) + { + if(_lcls74._25vI() == 0) + _lcls78 = (_cls78)_lcls74; + else + if(_lcls74._26II(0) == _lcls101._155vI()) + _lcls78 = (_cls78)_lcls74; + else + return null; + } else + { + return null; + } + _cls122 _lcls122 = _pcls103._241I122(_lcls101._155vI()); + _cls76 _lcls76 = null; + _cls61 _lcls61 = null; + boolean flag1 = true; + if(_lcls122 != null) + { + if(_lcls78 == null) + return null; + if(_lcls78._193122vZ(_lcls122, 1000)) + if(_lcls122._351StringZ("for")) + flag1 = false; + else + return null; + } + Object obj1 = _lcls78; + if(_lcls78 != null && _lcls78._25vI() == 0) + { + for(_cls82 _lcls82 = _pcls103._178v82(); _lcls82._174vZ() && _lcls76 == null;) + { + _pcls74 = _lcls82._177v74(); + if((_pcls74 instanceof _cls76) && _pcls74._198vI() == 0 && _pcls74._26II(0) == _lcls101._155vI()) + _lcls76 = (_cls76)_pcls74; + } + + if(_lcls76 == null) + return null; + } else + if(_lcls78 != null && _lcls78._25vI() == 1) + { + int j = _lcls78._291vI() - 1; + _pcls74 = _lcls78._290I78(j); + if(_pcls74 instanceof _cls76) + { + _lcls76 = (_cls76)_pcls74; + _lcls61 = _lcls76._78v4()._69v61(); + if(j == 0) + { + obj1 = null; + } else + { + _cls78 a_lcls78[] = new _cls78[j]; + for(int k = 0; k < j; k++) + a_lcls78[k] = _lcls78._290I78(k); + + obj1 = new _cls77(a_lcls78); + } + } + } + Object obj2 = null; + _cls76 _lcls76_1 = null; + _cls61 _lcls61_1 = null; + for(_cls82 _lcls82_1 = _pcls103._178v82(); _lcls82_1._174vZ();) + { + _pcls74 = _lcls82_1._177v74(); + if(_pcls74._25vI() == 1 && _pcls74._26II(0) == _lcls101._155vI()) + { + if(_pcls74 instanceof _cls78) + { + if(_pcls74 instanceof _cls77) + { + obj2 = (_cls78)_pcls74; + _cls77 _lcls77 = (_cls77)_pcls74; + _pcls74 = _lcls77._290I78(_lcls77._291vI() - 1); + } + if(_pcls74 instanceof _cls76) + { + _cls4 _lcls4 = ((_cls76)_pcls74)._78v4(); + if(_lcls4 instanceof _cls92) + { + _lcls76_1 = (_cls76)_pcls74; + _lcls61_1 = _lcls76_1._78v4()._69v61(); + } + } + } + break; + } + } + + _cls4 _lcls4_1 = _lcls101._344v4(); + if(_lcls61_1 != null && _lcls61_1 != _lcls61 && !_lcls4_1._6861Z(_lcls61_1)) + { + _lcls61_1 = null; + _lcls76_1 = null; + obj2 = null; + } + if(_lcls76 != null && flag1 && (_lcls61 == null || _lcls61 != _lcls61_1) && (_lcls61 == null || !_lcls4_1._6861Z(_lcls61))) + { + Object obj = null; + _lcls76 = null; + obj1 = _lcls78; + } + if(_lcls76 == null && _lcls76_1 == null) + return null; + super.m_368I++; + if(flag) + _lcls4_1 = _lcls4_1._311v4(); + _cls122 _lcls122_1 = _pcls103._252I122(_lcls101._155vI()); + _cls105 _lcls105 = new _cls105(_lcls76_1, _lcls4_1, _lcls76, ((_cls78) (obj1)), _lcls122, _lcls122_1); + _lcls105._21IIV(0, i); + _lcls101._196vV(); + if(_lcls76_1 != null) + { + _lcls105._497475(_lcls76_1); + if(obj2 != null) + { + int l = ((_cls78) (obj2))._291vI() - 1; + _cls78 a_lcls78_1[] = new _cls78[l]; + for(int i1 = 0; i1 < l; i1++) + a_lcls78_1[i1] = ((_cls78) (obj2))._290I78(i1); + + obj2 = new _cls77(a_lcls78_1); + _pcls103._2497474(((_cls74) (obj2))); + } else + { + _pcls103._24274V(_lcls76_1); + } + } else + { + _lcls105._497475(_lcls101); + } + _pcls103._24274V(_lcls101); + _pcls103._24274V(_lcls78); + if(_lcls78 != null && _lcls78._25vI() == 0) + _pcls103._24274V(_lcls76); + return _pcls103._2497474(_lcls105); + } + + _cls160() + { + } +} diff --git a/src/modules/mocha/_cls161.java b/src/modules/mocha/_cls161.java new file mode 100644 index 0000000..b2206a0 --- /dev/null +++ b/src/modules/mocha/_cls161.java @@ -0,0 +1,77 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls166, _cls149, _cls75, +// _cls164, _cls167, _cls155, _cls96, +// _cls103, _cls148, _cls153, _cls141, +// _cls140, _cls150, _cls91, _cls4, +// _cls142, _cls144, _cls137, _cls143, +// _cls135, _cls156, _cls134, _cls169, +// _cls158, _cls139, _cls159, _cls154, +// _cls147, _cls162, _cls157, _cls165, +// _cls163, _cls171, _cls74, _cls101, +// _cls170, _cls133, _cls132, _cls78, +// _cls145, _cls151, _cls160 + +class _cls161 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls101)) + return null; + _cls101 _lcls101 = (_cls101)_pcls74; + _cls74 _lcls74 = _pcls103._254I74(_lcls101._26II(0)); + _cls74 _lcls74_1 = _pcls103._254I74(_lcls101._26II(1)); + _cls4 _lcls4; + _cls78 _lcls78; + int i; + if(_lcls101._26II(0) == _lcls101._155vI()) + { + _lcls4 = _lcls101._344v4()._311v4(); + _lcls78 = null; + i = _lcls101._26II(1); + } else + if(_lcls101._26II(1) == _lcls101._155vI()) + { + _lcls4 = _lcls101._344v4(); + _lcls78 = null; + i = _lcls101._26II(0); + } else + if((_lcls74 instanceof _cls78) && _lcls74._198vI() == 1 && _lcls74._26II(0) == _lcls101._155vI()) + { + _lcls4 = _lcls101._344v4()._311v4(); + _lcls78 = (_cls78)_lcls74; + i = _lcls101._26II(1); + } else + if((_lcls74_1 instanceof _cls78) && _lcls74_1._198vI() == 1 && _lcls74_1._26II(0) == _lcls101._155vI()) + { + _lcls4 = _lcls101._344v4(); + _lcls78 = (_cls78)_lcls74_1; + i = _lcls101._26II(0); + } else + { + return null; + } + super.m_368I++; + _cls122 _lcls122 = _pcls103._241I122(_lcls101._155vI()); + _cls122 _lcls122_1 = _pcls103._252I122(_lcls101._155vI()); + Object obj = new _cls96(_lcls4, _lcls78, _lcls122, _lcls122_1); + _lcls101._196vV(); + obj = ((_cls75) (obj))._497475(_lcls101); + ((_cls75) (obj))._21IIV(0, i); + _pcls103._24274V(_lcls101); + _pcls103._24274V(_lcls78); + return _pcls103._2497474(((_cls74) (obj))); + } + + _cls161() + { + } +} diff --git a/src/modules/mocha/_cls162.java b/src/modules/mocha/_cls162.java new file mode 100644 index 0000000..c092a48 --- /dev/null +++ b/src/modules/mocha/_cls162.java @@ -0,0 +1,63 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls166, _cls149, _cls75, +// _cls164, _cls167, _cls155, _cls103, +// _cls148, _cls153, _cls141, _cls140, +// _cls150, _cls91, _cls4, _cls142, +// _cls144, _cls137, _cls143, _cls135, +// _cls156, _cls134, _cls169, _cls158, +// _cls139, _cls159, _cls154, _cls161, +// _cls147, _cls157, _cls93, _cls165, +// _cls163, _cls171, _cls74, _cls101, +// _cls170, _cls133, _cls132, _cls78, +// _cls145, _cls151, _cls160 + +class _cls162 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls101)) + return null; + _cls101 _lcls101 = (_cls101)_pcls74; + _cls74 _lcls74 = _pcls103._2487474(_lcls101); + if(!(_lcls74 instanceof _cls78)) + return null; + _cls4 _lcls4; + int i; + if(_lcls101._26II(0) == _lcls74._155vI()) + { + _lcls4 = _lcls101._344v4()._311v4(); + i = _lcls101._26II(1); + } else + if(_lcls101._26II(1) == _lcls74._155vI()) + { + _lcls4 = _lcls101._344v4(); + i = _lcls101._26II(0); + } else + { + return null; + } + super.m_368I++; + _cls122 _lcls122 = _pcls103._241I122(_lcls101._155vI()); + _cls122 _lcls122_1 = _pcls103._252I122(_lcls101._155vI()); + Object obj = new _cls93(_lcls4, (_cls78)_lcls74, _lcls122, _lcls122_1); + _lcls74._196vV(); + obj = ((_cls75) (obj))._497475(_lcls74); + ((_cls75) (obj))._21IIV(0, i); + _pcls103._24274V(_lcls101); + _pcls103._24274V(_lcls74); + return _pcls103._2497474(((_cls74) (obj))); + } + + _cls162() + { + } +} diff --git a/src/modules/mocha/_cls163.java b/src/modules/mocha/_cls163.java new file mode 100644 index 0000000..40c2894 --- /dev/null +++ b/src/modules/mocha/_cls163.java @@ -0,0 +1,110 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls166, _cls149, _cls75, +// _cls164, _cls167, _cls155, _cls103, +// _cls76, _cls148, _cls153, _cls141, +// _cls140, _cls150, _cls142, _cls144, +// _cls137, _cls143, _cls135, _cls156, +// _cls134, _cls169, _cls158, _cls139, +// _cls159, _cls154, _cls161, _cls147, +// _cls122, _cls162, _cls157, _cls165, +// _cls171, _cls74, _cls101, _cls82, +// _cls170, _cls133, _cls132, _cls78, +// _cls145, _cls151, _cls160 + +class _cls163 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls101)) + return null; + int i = _pcls74._155vI(); + int j; + int k; + int l; + if(_pcls74._26II(0) <= i) + { + j = _pcls74._26II(0); + k = i; + l = _pcls74._26II(1); + } else + if(_pcls74._26II(1) <= i) + { + j = _pcls74._26II(1); + k = i; + l = _pcls74._26II(0); + } else + { + return null; + } + if(_pcls103._238I122(l) != null) + return null; + int j1 = 0; + int k1 = 0; + int l1 = 0; + _cls74 _lcls74 = null; + for(_cls82 _lcls82 = _pcls103._178v82(); _lcls82._174vZ();) + { + _cls74 _lcls74_1 = _lcls82._177v74(); + for(int i2 = 0; i2 < _lcls74_1._25vI(); i2++) + if(_lcls74_1._26II(i2) == i) + if(_lcls74_1._155vI() < j) + j1++; + else + if(_lcls74_1._155vI() < k) + { + k1++; + _lcls74 = _lcls74_1; + } else + { + l1++; + } + + } + + String s = "do/while"; + int i1; + if(l1 > 0) + i1 = -1; + else + if(j1 == 0) + i1 = i; + else + if(k1 > 2) + i1 = i; + else + if(_lcls74 instanceof _cls78) + { + _cls78 _lcls78 = (_cls78)_lcls74; + _lcls78 = _lcls78._290I78(_lcls78._291vI() - 1); + if(_lcls78 instanceof _cls76) + { + i1 = _lcls78._155vI(); + s = "for"; + } else + { + i1 = i; + } + } else + { + i1 = -1; + } + super.m_368I++; + _pcls103._250I122V(l, new _cls122(i, j, k, "for/do/while")); + if(i1 >= 0) + _pcls103._256I122V(i1, new _cls122(i, j + 1, i1, s)); + return _pcls74; + } + + _cls163() + { + } +} diff --git a/src/modules/mocha/_cls164.java b/src/modules/mocha/_cls164.java new file mode 100644 index 0000000..0646e9b --- /dev/null +++ b/src/modules/mocha/_cls164.java @@ -0,0 +1,80 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls166, _cls149, _cls98, +// _cls14, _cls167, _cls155, _cls103, +// _cls107, _cls148, _cls153, _cls141, +// _cls140, _cls150, _cls142, _cls144, +// _cls137, _cls143, _cls135, _cls156, +// _cls134, _cls169, _cls158, _cls28, +// _cls139, _cls159, _cls154, _cls108, +// _cls161, _cls147, _cls162, _cls157, +// _cls165, _cls163, _cls171, _cls74, +// _cls170, _cls133, _cls132, _cls145, +// _cls151, _cls18, _cls160 + +class _cls164 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(_pcls74 instanceof _cls28) + _pcls74 = _pcls103._2487474(_pcls74); + if(!(_pcls74 instanceof _cls18) && !(_pcls74 instanceof _cls14)) + return null; + if(_pcls74._198vI() != 1) + return null; + _cls74 _lcls74 = _pcls74; + int i = _lcls74._155vI(); + _cls108 a_lcls108[] = _pcls103._243va108(); + int j = -1; + for(int k = 0; j < 0 && k < a_lcls108.length; k++) + if(a_lcls108[k]._57vI() == i && a_lcls108[k]._55vString().equals("")) + j = k; + + if(j < 0) + return null; + if(_lcls74 instanceof _cls18) + { + _pcls74 = _pcls103._2397474(_pcls74); + if(!(_pcls74 instanceof _cls28)) + return null; + _pcls74 = _pcls103._254I74(_pcls74._26II(0)); + if(!(_pcls74 instanceof _cls98)) + return null; + } + super.m_368I++; + int l = a_lcls108[j]._59vI(); + int i1 = a_lcls108[j]._62vI(); + int j1 = -1; + _pcls74 = _lcls74; + _pcls103._24274V(_pcls74); + if(_lcls74 instanceof _cls18) + { + _pcls74 = _pcls103._2397474(_pcls74); + _pcls103._24274V(_pcls74); + j1 = _pcls74._26II(1); + _pcls74 = _pcls103._254I74(_pcls74._26II(0)); + _pcls103._24274V(_pcls74); + } else + { + j1 = _lcls74._26II(0); + _pcls103._254I74(j1)._196vV(); + } + a_lcls108[j] = new _cls107(j1, l, i1); + _pcls103._253a108V(a_lcls108); + _pcls74 = _pcls103._254I74(j1); + _pcls74._196vV(); + return _pcls74; + } + + _cls164() + { + } +} diff --git a/src/modules/mocha/_cls165.java b/src/modules/mocha/_cls165.java new file mode 100644 index 0000000..affa260 --- /dev/null +++ b/src/modules/mocha/_cls165.java @@ -0,0 +1,158 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls102, _cls146, +// _cls152, _cls77, _cls168, _cls166, +// _cls149, _cls92, _cls75, _cls164, +// _cls167, _cls155, _cls103, _cls76, +// _cls148, _cls153, _cls141, _cls27, +// _cls33, _cls140, _cls150, _cls4, +// _cls71, _cls142, _cls144, _cls137, +// _cls143, _cls135, _cls156, _cls31, +// _cls134, _cls169, _cls158, _cls11, +// _cls139, _cls159, _cls154, _cls108, +// _cls161, _cls147, _cls162, _cls157, +// _cls8, _cls163, _cls171, _cls74, +// _cls170, _cls133, _cls132, _cls78, +// _cls145, _cls151, _cls18, _cls160 + +class _cls165 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls27)) + return null; + _cls27 _lcls27 = (_cls27)_pcls74; + _pcls74 = _pcls103._2487474(_lcls27); + if(!(_pcls74 instanceof _cls4)) + return null; + _cls4 _lcls4 = (_cls4)_pcls74; + String s = _lcls4._51v61().toString(); + _pcls74 = _pcls103._2487474(_lcls4); + _cls77 _lcls77 = null; + if(_pcls74 instanceof _cls77) + { + _lcls77 = (_cls77)_pcls74; + _pcls74 = _lcls77._290I78(_lcls77._291vI() - 1); + } + if(!(_pcls74 instanceof _cls76)) + return null; + _cls76 _lcls76 = (_cls76)_pcls74; + if(!(_lcls76._78v4() instanceof _cls92)) + return null; + _cls92 _lcls92 = (_cls92)_lcls76._78v4(); + if(!_lcls92._69v61().toString().equals(s)) + return null; + _cls4 _lcls4_1 = _lcls92._65I4(0); + if(_lcls4_1 == null) + return null; + _pcls74 = _pcls103._254I74(_lcls27._26II(0)); + if(!(_pcls74 instanceof _cls78)) + return null; + _cls78 _lcls78 = (_cls78)_pcls74; + int i = _lcls78._155vI(); + _cls108 a_lcls108[] = _pcls103._243va108(); + int j = -1; + for(int k = 0; j < 0 && k < a_lcls108.length; k++) + if(a_lcls108[k]._59vI() == i && a_lcls108[k]._55vString().equals("")) + j = k; + + if(j < 0) + return null; + _pcls74 = _pcls103._254I74(a_lcls108[j]._57vI()); + if(!(_pcls74 instanceof _cls4)) + return null; + _cls4 _lcls4_2 = (_cls4)_pcls74; + if(!_lcls4_2._51v61().toString().equals(s)) + return null; + _pcls74 = _pcls103._2397474(_lcls4_2); + if(!(_pcls74 instanceof _cls8)) + return null; + _cls8 _lcls8 = (_cls8)_pcls74; + _pcls74 = _pcls103._2397474(_lcls8); + if(!(_pcls74 instanceof _cls11)) + return null; + _cls11 _lcls11 = (_cls11)_pcls74; + _cls18 _lcls18 = null; + _cls4 _lcls4_3 = null; + _cls8 _lcls8_1 = null; + _cls33 _lcls33 = null; + if(_lcls78._26II(0) < 0) + { + int l = _pcls103._258II(_lcls11._155vI()); + if(l < 0) + return null; + _pcls74 = _pcls103._254I74(l); + if(!(_pcls74 instanceof _cls18)) + return null; + _lcls18 = (_cls18)_pcls74; + _pcls74 = _pcls103._2397474(_lcls18); + if(!(_pcls74 instanceof _cls4)) + return null; + _lcls4_3 = (_cls4)_pcls74; + if(!_lcls4_3._51v61().toString().equals(s)) + return null; + _pcls74 = _pcls103._2397474(_lcls4_3); + if(!(_pcls74 instanceof _cls8)) + return null; + _lcls8_1 = (_cls8)_pcls74; + _pcls74 = _pcls103._2397474(_lcls8_1); + if(!(_pcls74 instanceof _cls33)) + return null; + _lcls33 = (_cls33)_pcls74; + } else + { + _pcls74 = _pcls103._254I74(_lcls78._26II(0)); + if(!(_pcls74 instanceof _cls4)) + return null; + _lcls4_3 = (_cls4)_pcls74; + if(!_lcls4_3._51v61().toString().equals(s)) + return null; + _pcls74 = _pcls103._2397474(_lcls4_3); + if(!(_pcls74 instanceof _cls8)) + return null; + _lcls8_1 = (_cls8)_pcls74; + } + super.m_368I++; + _pcls103._257v71()._34261vV(_lcls4._51v61(), _lcls27._155vI()); + _lcls78._196vV(); + _pcls74 = _pcls103._254I74(a_lcls108[j]._62vI()); + if(_pcls74 != null) + _pcls74._196vV(); + _cls102 _lcls102 = new _cls102(_lcls4_1, _lcls78); + _lcls102._527475(_lcls8_1); + if(_lcls77 != null) + { + _cls78 a_lcls78[] = new _cls78[_lcls77._291vI() - 1]; + for(int i1 = 0; i1 < a_lcls78.length; i1++) + a_lcls78[i1] = _lcls77._290I78(i1); + + _pcls103._24274V(_lcls77); + _pcls103._2497474(new _cls77(a_lcls78)); + } else + { + _pcls103._24274V(_lcls76); + } + _pcls103._24274V(_lcls4); + _pcls103._24274V(_lcls27); + _pcls103._24274V(_lcls78); + _pcls103._24274V(_lcls4_3); + _pcls103._24274V(_lcls8_1); + _pcls103._24274V(_lcls4_2); + _pcls103._24274V(_lcls8); + _pcls103._24274V(_lcls11); + _pcls103._24274V(_lcls18); + _pcls103._24274V(_lcls33); + return _pcls103._2497474(_lcls102); + } + + _cls165() + { + } +} diff --git a/src/modules/mocha/_cls166.java b/src/modules/mocha/_cls166.java new file mode 100644 index 0000000..389094d --- /dev/null +++ b/src/modules/mocha/_cls166.java @@ -0,0 +1,71 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls42, _cls146, +// _cls152, _cls168, _cls149, _cls75, +// _cls164, _cls167, _cls155, _cls103, +// _cls148, _cls153, _cls141, _cls140, +// _cls150, _cls4, _cls142, _cls144, +// _cls137, _cls143, _cls135, _cls156, +// _cls134, _cls83, _cls169, _cls158, +// _cls139, _cls159, _cls154, _cls161, +// _cls147, _cls162, _cls157, _cls165, +// _cls163, _cls171, _cls74, _cls101, +// _cls82, _cls170, _cls133, _cls132, +// _cls78, _cls145, _cls151, _cls160 + +class _cls166 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls78) || _pcls74._26II(0) != _pcls74._155vI()) + return null; + _cls78 _lcls78 = (_cls78)_pcls74; + super.m_368I++; + int i = _lcls78._155vI(); + int j = _pcls103._258II(i); + if(j < 0) + { + j = _pcls103._245III(i, -1); + _cls75 _lcls75 = (new _cls83(null))._346I75(j); + _pcls103._2497474(_lcls75); + } + int k = _pcls103._245III(i, j); + _cls42 _lcls42 = new _cls42(_lcls78._48vI(), 0, "Z", "true"); + _cls4 a_lcls4[] = new _cls4[0]; + _cls4 _lcls4 = new _cls4(_lcls42, a_lcls4); + _cls75 _lcls75_1 = (new _cls101(_lcls4, j, i))._346I75(k); + _lcls78._21IIV(0, k); + _lcls75_1._197vV(); + _pcls103._254I74(j)._197vV(); + for(_cls82 _lcls82 = _pcls103._178v82(); _lcls82._174vZ();) + { + _pcls74 = _lcls82._177v74(); + for(int l = 0; l < _pcls74._25vI(); l++) + if(_pcls74._26II(l) == i) + { + _pcls74._21IIV(l, k); + _lcls78._196vV(); + _lcls75_1._197vV(); + } + + } + + if(i == 0) + { + _lcls78._196vV(); + _lcls75_1._197vV(); + } + return _pcls103._2497474(_lcls75_1); + } + + _cls166() + { + } +} diff --git a/src/modules/mocha/_cls167.java b/src/modules/mocha/_cls167.java new file mode 100644 index 0000000..adf03d9 --- /dev/null +++ b/src/modules/mocha/_cls167.java @@ -0,0 +1,95 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls166, _cls149, _cls75, +// _cls164, _cls155, _cls103, _cls148, +// _cls153, _cls141, _cls140, _cls150, +// _cls91, _cls4, _cls142, _cls144, +// _cls137, _cls143, _cls135, _cls156, +// _cls134, _cls169, _cls158, _cls139, +// _cls159, _cls154, _cls161, _cls147, +// _cls162, _cls157, _cls165, _cls163, +// _cls171, _cls106, _cls74, _cls101, +// _cls170, _cls133, _cls132, _cls78, +// _cls145, _cls151, _cls160 + +class _cls167 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + _cls74 _lcls74 = _pcls74; + if(!(_lcls74 instanceof _cls101)) + return null; + _cls101 _lcls101 = (_cls101)_lcls74; + if(_lcls101._26II(0) <= _lcls101._155vI() || _lcls101._26II(1) <= _lcls101._155vI()) + return null; + _cls78 _lcls78 = null; + int i = _lcls101._26II(0); + _lcls74 = _pcls103._254I74(i); + if((_lcls74 instanceof _cls78) && _lcls74._198vI() == 1) + { + _lcls78 = (_cls78)_lcls74; + i = _lcls78._26II(0); + } + _cls78 _lcls78_1 = null; + int j = _lcls101._26II(1); + _lcls74 = _pcls103._254I74(j); + if((_lcls74 instanceof _cls78) && _lcls74._198vI() == 1) + { + _lcls78_1 = (_cls78)_lcls74; + j = _lcls78_1._26II(0); + } + if(i >= 0 && j >= 0 && i != j) + return null; + if(i < 0 && j >= 0) + { + _lcls78_1 = null; + j = _lcls101._26II(1); + } else + if(j < 0 && i >= 0) + { + _lcls78 = null; + i = _lcls101._26II(0); + } + _cls106 _lcls106; + if(_lcls78 != null && _lcls78_1 != null) + { + boolean flag = false; + if((_lcls78_1 instanceof _cls106) && !(_lcls78 instanceof _cls106)) + flag = true; + else + if((_lcls78 instanceof _cls106) && !(_lcls78_1 instanceof _cls106)) + flag = false; + else + flag = true; + if(flag) + _lcls106 = new _cls106(_lcls101._344v4()._311v4(), _lcls78, _lcls78_1); + else + _lcls106 = new _cls106(_lcls101._344v4(), _lcls78_1, _lcls78); + } else + if(_lcls78 != null) + _lcls106 = new _cls106(_lcls101._344v4()._311v4(), _lcls78); + else + _lcls106 = new _cls106(_lcls101._344v4(), _lcls78_1); + super.m_368I++; + _lcls106._497475(_lcls101); + _lcls106._21IIV(0, i < 0 ? j : i); + if(i >= 0 && j >= 0) + _pcls103._254I74(i)._196vV(); + _pcls103._24274V(_lcls101); + _pcls103._24274V(_lcls78_1); + _pcls103._24274V(_lcls78); + return _pcls103._2497474(_lcls106); + } + + _cls167() + { + } +} diff --git a/src/modules/mocha/_cls168.java b/src/modules/mocha/_cls168.java new file mode 100644 index 0000000..c589a78 --- /dev/null +++ b/src/modules/mocha/_cls168.java @@ -0,0 +1,51 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls29, _cls136, _cls146, +// _cls152, _cls166, _cls149, _cls75, +// _cls164, _cls104, _cls167, _cls155, +// _cls103, _cls148, _cls153, _cls141, +// _cls140, _cls150, _cls4, _cls71, +// _cls142, _cls144, _cls137, _cls143, +// _cls135, _cls156, _cls134, _cls169, +// _cls158, _cls139, _cls159, _cls154, +// _cls161, _cls147, _cls162, _cls157, +// _cls165, _cls163, _cls171, _cls74, +// _cls170, _cls133, _cls132, _cls145, +// _cls151, _cls160 + +class _cls168 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls29)) + return null; + if(_pcls74._22vI() == 0) + return null; + _cls74 _lcls74 = _pcls103._2487474(_pcls74); + if(!(_lcls74 instanceof _cls4)) + { + return null; + } else + { + _cls4 _lcls4 = (_cls4)_lcls74; + super.m_368I++; + String s = _pcls103._257v71()._334vString(); + _cls104 _lcls104 = new _cls104(_lcls4, s); + _lcls104._527475(_pcls74); + _pcls103._24274V(_lcls4); + _pcls103._24274V(_pcls74); + return _pcls103._2497474(_lcls104); + } + } + + _cls168() + { + } +} diff --git a/src/modules/mocha/_cls169.java b/src/modules/mocha/_cls169.java new file mode 100644 index 0000000..00d32f3 --- /dev/null +++ b/src/modules/mocha/_cls169.java @@ -0,0 +1,44 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls145, _cls144, _cls148, +// _cls164, _cls155, _cls74, _cls162, +// _cls159, _cls161, _cls160, _cls141, +// _cls140, _cls147, _cls171, _cls154, +// _cls146, _cls152, _cls143, _cls167, +// _cls149, _cls132, _cls139, _cls156, +// _cls133, _cls85, _cls168, _cls158, +// _cls165, _cls75, _cls103, _cls142, +// _cls135, _cls137, _cls157, _cls166, +// _cls136, _cls150, _cls29, _cls163, +// _cls170, _cls134, _cls153, _cls151 + +class _cls169 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + if(!(_pcls74 instanceof _cls29)) + return null; + if(_pcls74._22vI() > 0) + { + return null; + } else + { + super.m_368I++; + _cls85 _lcls85 = new _cls85(); + _lcls85._497475(_pcls74)._527475(_pcls74); + _pcls103._24274V(_pcls74); + return _pcls103._2497474(_lcls85); + } + } + + _cls169() + { + } +} diff --git a/src/modules/mocha/_cls17.java b/src/modules/mocha/_cls17.java new file mode 100644 index 0000000..128d224 --- /dev/null +++ b/src/modules/mocha/_cls17.java @@ -0,0 +1,69 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls56, +// _cls14, _cls20, _cls52, _cls2, +// _cls26, _cls25, _cls23, _cls27, +// _cls33, _cls35, _cls40, _cls19, +// _cls49, _cls47, _cls38, _cls30, +// _cls37, _cls54, _cls39, _cls48, +// _cls11, _cls46, _cls28, _cls12, +// _cls0, _cls53, _cls50, _cls10, +// _cls55, _cls8, _cls22, _cls13, +// _cls51, _cls45, _cls21, _cls9, +// _cls18, _cls43, _cls71 + +class _cls17 extends _cls31 +{ + + protected int m_187I; + protected _cls0 m_160; + + _cls17(int i, int j, int k) + { + super(i, j); + m_187I = k; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_160 = _pcls0; + } + + public int _22vI() + { + return 1; + } + + public int _117vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + String s = m_160._9I2(m_187I)._56v2().toString(); + String s1 = "(" + m_160._101StringString(s) + ")"; + String s2 = "L" + s + ";"; + _cls61 _lcls61 = _pcls23._113v61(); + return _pcls23._29v23()._716123(new _cls56(s2, _lcls61, s1, 23)); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("cast to " + m_160._9I2(m_187I)); + } + + public void _19vV() + { + m_187I = m_160._19IStringI(m_187I, "class"); + } +} diff --git a/src/modules/mocha/_cls170.java b/src/modules/mocha/_cls170.java new file mode 100644 index 0000000..1673935 --- /dev/null +++ b/src/modules/mocha/_cls170.java @@ -0,0 +1,60 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls138, _cls136, _cls146, _cls152, +// _cls168, _cls166, _cls149, _cls164, +// _cls87, _cls167, _cls155, _cls103, +// _cls148, _cls153, _cls141, _cls140, +// _cls150, _cls142, _cls144, _cls137, +// _cls143, _cls135, _cls156, _cls134, +// _cls169, _cls158, _cls139, _cls159, +// _cls154, _cls161, _cls147, _cls122, +// _cls162, _cls157, _cls165, _cls163, +// _cls171, _cls74, _cls133, _cls132, +// _cls145, _cls151, _cls160 + +class _cls170 extends _cls138 +{ + + _cls74 _3587474(_cls74 _pcls74, _cls103 _pcls103) + { + boolean flag = false; + int i = _pcls74._25vI(); + int j = _pcls74._155vI(); + for(int k = 0; k < i; k++) + { + int l = _pcls74._26II(k); + if(l != _pcls103._258II(j)) + { + _cls122 _lcls122 = _pcls103._238I122(l); + if(_lcls122 != null && _lcls122._352IZ(j)) + { + int i1 = _pcls103._247III(j, l); + _cls87 _lcls87 = new _cls87(i1, _lcls122); + _pcls103._2497474(_lcls87); + _pcls103._254I74(l)._196vV(); + _pcls74._21IIV(k, i1); + flag = true; + } + } + } + + if(!flag) + { + return null; + } else + { + super.m_368I++; + return _pcls103._254I74(0); + } + } + + _cls170() + { + } +} diff --git a/src/modules/mocha/_cls171.java b/src/modules/mocha/_cls171.java new file mode 100644 index 0000000..e45e1f7 --- /dev/null +++ b/src/modules/mocha/_cls171.java @@ -0,0 +1,35 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls145, _cls144, _cls148, _cls164, +// _cls155, _cls162, _cls159, _cls161, +// _cls160, _cls141, _cls138, _cls140, +// _cls147, _cls169, _cls154, _cls146, +// _cls152, _cls143, _cls167, _cls149, +// _cls132, _cls139, _cls156, _cls133, +// _cls168, _cls158, _cls165, _cls142, +// _cls135, _cls137, _cls157, _cls166, +// _cls136, _cls150, _cls163, _cls170, +// _cls134, _cls153, _cls151 + +class _cls171 +{ + + int m_370I; + int m_373I; + int m_372I; + int m_369I; + int m_371I; + + _cls171(int i) + { + m_370I = i; + m_372I = 0; + m_369I = -1; + } +} diff --git a/src/modules/mocha/_cls18.java b/src/modules/mocha/_cls18.java new file mode 100644 index 0000000..86a7be0 --- /dev/null +++ b/src/modules/mocha/_cls18.java @@ -0,0 +1,72 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls54, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls26, _cls25, +// _cls23, _cls27, _cls33, _cls35, +// _cls40, _cls19, _cls71, _cls49, +// _cls47, _cls61, _cls38, _cls31, +// _cls30, _cls37, _cls39, _cls48, +// _cls11, _cls46, _cls28, _cls12, +// _cls53, _cls50, _cls10, _cls55, +// _cls8, _cls22, _cls17, _cls13, +// _cls51, _cls58, _cls45, _cls21, +// _cls9, _cls43, _cls0, _cls103, +// _cls4 + +class _cls18 extends _cls54 +{ + + protected String m_44String; + protected int m_106I; + protected _cls71 m_11271; + + _cls18(int i, int j, String s, int k) + { + super(i, j); + m_44String = s; + m_106I = k; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_11271 = _pcls71; + } + + public int _22vI() + { + return 1; + } + + public void _10723V(_cls23 _pcls23, _cls103 _pcls103) + { + if(super.m_10523 == null) + { + m_11271._283IIV(m_106I, super.m_110I + super.m_226I, _pcls23._113v61()._43vString()); + super._10723V(_pcls23, _pcls103); + } + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._29v23(); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("pop " + m_11271._111II125(m_106I, super.m_110I + super.m_226I)); + } + + _cls61 _69a461(_cls4 a_pcls4[]) + { + return new _cls58(m_11271, m_106I, super.m_110I + super.m_226I); + } +} diff --git a/src/modules/mocha/_cls19.java b/src/modules/mocha/_cls19.java new file mode 100644 index 0000000..7909f26 --- /dev/null +++ b/src/modules/mocha/_cls19.java @@ -0,0 +1,34 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls31, _cls46, _cls27, _cls25, +// _cls42, _cls18, _cls52, _cls35, +// _cls53, _cls43, _cls20, _cls14, +// _cls26, _cls36, _cls48, _cls45, +// _cls13, _cls54, _cls38, _cls50, +// _cls28, _cls41, _cls9, _cls16, +// _cls34, _cls44, _cls17, _cls37, +// _cls11, _cls8, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10 + +abstract class _cls19 extends _cls31 +{ + + _cls19(int i, int j) + { + super(i, j); + } + + public int _25vI() + { + return 0; + } +} diff --git a/src/modules/mocha/_cls2.java b/src/modules/mocha/_cls2.java new file mode 100644 index 0000000..c24daf9 --- /dev/null +++ b/src/modules/mocha/_cls2.java @@ -0,0 +1,129 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// _cls120, _cls111, _cls119, _cls112, +// _cls115, _cls114, _cls116, _cls121, +// _cls113, _cls109, _cls118, _cls128, +// _cls110, _cls117, _cls3, _cls0, +// _cls1 + +abstract class _cls2 +{ + + static final byte m_m_208BB = 1; + static final byte m_m_204BB = 2; + static final byte m_m_209BB = 3; + static final byte m_m_214BB = 4; + static final byte m_m_212BB = 5; + static final byte m_m_210BB = 6; + static final byte m_m_213BB = 7; + static final byte m_m_211BB = 8; + static final byte m_m_206BB = 9; + static final byte m_m_205BB = 10; + static final byte m_m_207BB = 11; + static final byte m_m_203BB = 12; + + int _82vI() + { + return 1; + } + + _cls2 _56v2() + { + return null; + } + + String _18vString() + { + return "name?"; + } + + String _81vString() + { + return "type?"; + } + + String _7vString() + { + return "sig?"; + } + + void _1StringV(String s) + { + } + + static _cls2 _9532(_cls3 _pcls3, _cls0 _pcls0) + throws IOException, _cls128 + { + byte byte0 = _pcls3.readByte(); + switch(byte0) + { + case 1: // '\001' + return new _cls116(_pcls3); + + case 2: // '\002' + return new _cls114(_pcls3); + + case 3: // '\003' + return new _cls109(_pcls3); + + case 4: // '\004' + return new _cls118(_pcls3); + + case 5: // '\005' + return new _cls113(_pcls3); + + case 6: // '\006' + return new _cls115(_pcls3); + + case 7: // '\007' + return new _cls120(_pcls3, _pcls0); + + case 8: // '\b' + return new _cls119(_pcls3, _pcls0); + + case 9: // '\t' + return new _cls117(_pcls3, _pcls0); + + case 10: // '\n' + return new _cls121(_pcls3, _pcls0); + + case 11: // '\013' + return new _cls110(_pcls3, _pcls0); + + case 12: // '\f' + return new _cls111(_pcls3, _pcls0); + } + throw new _cls128("Invalid constant tag " + byte0); + } + + abstract void _61V(_cls1 _pcls1) + throws IOException; + + void _19vV() + { + } + + void _1000V(_cls0 _pcls0, String s) + { + _104StringV(s, "literal"); + } + + void _104StringV(String s, String s1) + { + if(s != null && !s.equals(s1)) + err.println(getClass().getName() + " used as " + s + " instead of " + s1); + } + + abstract String _790String(_cls0 _pcls0); + + _cls2() + { + } +} diff --git a/src/modules/mocha/_cls20.java b/src/modules/mocha/_cls20.java new file mode 100644 index 0000000..130e7c0 --- /dev/null +++ b/src/modules/mocha/_cls20.java @@ -0,0 +1,144 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls52, _cls2, _cls26, _cls25, +// _cls23, _cls27, _cls33, _cls35, +// _cls40, _cls19, _cls49, _cls47, +// _cls38, _cls30, _cls37, _cls54, +// _cls39, _cls48, _cls11, _cls46, +// _cls28, _cls12, _cls0, _cls53, +// _cls50, _cls10, _cls55, _cls8, +// _cls22, _cls17, _cls13, _cls51, +// _cls45, _cls21, _cls9, _cls18, +// _cls69, _cls43, _cls71 + +class _cls20 extends _cls31 +{ + + protected int m_187I; + protected String m_44String; + protected int m_314I; + protected boolean m_313Z; + protected _cls0 m_160; + + _cls20(int i, int j, int k) + { + super(i, j); + m_187I = k; + m_314I = 1; + m_313Z = false; + } + + _cls20(int i, int j, String s) + { + super(i, j); + m_44String = s; + m_314I = 1; + m_313Z = true; + } + + _cls20(int i, int j, int k, int l) + { + super(i, j); + m_187I = k; + m_314I = l; + m_313Z = true; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_160 = _pcls0; + } + + public int _22vI() + { + return m_314I; + } + + public int _117vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + if(m_44String == null) + { + m_44String = m_160._9I2(m_187I)._56v2().toString(); + if(!m_313Z) + { + if(m_44String.startsWith("[")) + m_44String = "[" + m_44String; + else + m_44String = "[L" + m_44String + ";"; + m_313Z = true; + } + } + int i = 0; + String s; + for(s = m_44String; s.charAt(0) == '['; s = s.substring(1)) + i++; + + if(s.startsWith("L")) + s = m_160._101StringString(s.substring(1, s.length() - 1)); + else + if(s.equals("B")) + s = "byte"; + else + if(s.equals("C")) + s = "char"; + else + if(s.equals("D")) + s = "double"; + else + if(s.equals("F")) + s = "float"; + else + if(s.equals("I")) + s = "int"; + else + if(s.equals("J")) + s = "long"; + else + if(s.equals("S")) + s = "short"; + else + if(s.equals("Z")) + s = "boolean"; + String s1 = "new " + s; + for(int j = m_314I; j > 0; j--) + s1 = s1 + "[" + _pcls23._113I61(j - 1) + "]"; + + for(int k = m_314I; k < i; k++) + s1 = s1 + "[]"; + + return _pcls23._29I23(m_314I)._716123(new _cls69(m_44String, s1)); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.print("new "); + if(m_44String == null) + printstream.print(m_160._9I2(m_187I)); + else + printstream.print(m_44String); + for(int i = 0; i < m_314I; i++) + printstream.print("[]"); + + printstream.println(); + } + + public void _19vV() + { + m_187I = m_160._19IStringI(m_187I, "class"); + } +} diff --git a/src/modules/mocha/_cls21.java b/src/modules/mocha/_cls21.java new file mode 100644 index 0000000..b2fdc44 --- /dev/null +++ b/src/modules/mocha/_cls21.java @@ -0,0 +1,125 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls56, +// _cls14, _cls20, _cls52, _cls26, +// _cls25, _cls23, _cls27, _cls33, +// _cls35, _cls40, _cls19, _cls49, +// _cls47, _cls61, _cls38, _cls30, +// _cls37, _cls54, _cls39, _cls48, +// _cls11, _cls46, _cls28, _cls12, +// _cls53, _cls50, _cls10, _cls55, +// _cls8, _cls22, _cls17, _cls13, +// _cls51, _cls45, _cls9, _cls18, +// _cls43 + +class _cls21 extends _cls31 +{ + + protected String m_179String; + protected String m_185String; + boolean m_181Z; + + _cls21(int i, int j, String s, String s1) + { + super(i, j); + m_179String = s; + m_185String = s1; + m_181Z = false; + } + + public int _22vI() + { + return 1; + } + + public int _117vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + if(m_181Z) + return _pcls23; + String s = null; + if(m_185String.equals("B")) + s = "(byte)"; + else + if(m_185String.equals("C")) + s = "(char)"; + else + if(m_185String.equals("D")) + s = "(double)"; + else + if(m_185String.equals("F")) + s = "(float)"; + else + if(m_185String.equals("I")) + s = "(int)"; + else + if(m_185String.equals("J")) + s = "(long)"; + else + if(m_185String.equals("S")) + s = "(short)"; + else + if(m_185String.equals("W")) + s = "(int)"; + _cls61 _lcls61 = _pcls23._113v61(); + return _pcls23._29v23()._716123(new _cls56(m_185String, _lcls61, s, 23)); + } + + private int _184StringI(String s) + { + if(s.equals("B")) + return 1; + if(s.equals("C")) + return 2; + if(s.equals("D")) + return 6; + if(s.equals("F")) + return 5; + if(s.equals("I")) + return 3; + if(s.equals("J")) + return 4; + if(s.equals("S")) + return 2; + return !s.equals("W") ? 3 : 3; + } + + boolean _182vZ() + { + if(m_179String.equals("W") && super.m_10523 != null) + { + _cls61 _lcls61 = super.m_10523._113v61(); + if(_lcls61 != null) + return _184StringI(_lcls61._43vString()) >= _184StringI(m_185String); + } + return _184StringI(m_179String) >= _184StringI(m_185String); + } + + boolean _180vZ() + { + return m_181Z; + } + + void _183vV() + { + m_181Z = true; + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("convert " + m_179String + " to " + m_185String); + } +} diff --git a/src/modules/mocha/_cls22.java b/src/modules/mocha/_cls22.java new file mode 100644 index 0000000..4040a70 --- /dev/null +++ b/src/modules/mocha/_cls22.java @@ -0,0 +1,81 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls26, _cls25, +// _cls27, _cls33, _cls35, _cls40, +// _cls19, _cls71, _cls49, _cls47, +// _cls38, _cls30, _cls37, _cls54, +// _cls39, _cls48, _cls11, _cls46, +// _cls28, _cls12, _cls53, _cls50, +// _cls10, _cls55, _cls8, _cls17, +// _cls13, _cls51, _cls58, _cls45, +// _cls21, _cls9, _cls18, _cls43, +// _cls0, _cls23, _cls103, _cls4, +// _cls61 + +class _cls22 extends _cls31 +{ + + protected int m_106I; + protected int m_282I; + protected _cls71 m_11271; + + _cls22(int i, int j, int k, int l) + { + super(i, j); + m_106I = k; + m_282I = l; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_11271 = _pcls71; + } + + public void _10723V(_cls23 _pcls23, _cls103 _pcls103) + { + if(super.m_10523 == null) + { + m_11271._109IIV(m_106I, super.m_110I, "I"); + m_11271._283IIV(m_106I, super.m_110I + super.m_226I, "I"); + super._10723V(_pcls23, _pcls103); + } + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23; + } + + int _281vI() + { + return m_282I; + } + + _cls61 _69a461(_cls4 a_pcls4[]) + { + return new _cls58(m_11271, m_106I, super.m_110I + super.m_226I); + } + + void _20PrintStreamV(PrintStream printstream) + { + if(m_282I >= 0) + { + printstream.println("increment " + m_11271._111II125(m_106I, super.m_110I) + " by " + m_282I); + return; + } else + { + printstream.println("decrement " + m_11271._111II125(m_106I, super.m_110I) + " by " + -m_282I); + return; + } + } +} diff --git a/src/modules/mocha/_cls23.java b/src/modules/mocha/_cls23.java new file mode 100644 index 0000000..a62b96a --- /dev/null +++ b/src/modules/mocha/_cls23.java @@ -0,0 +1,96 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls60, _cls69, _cls65, _cls56, +// _cls62, _cls68, _cls64, _cls57, +// _cls59, _cls58, _cls66, _cls67, +// _cls63, _cls61 + +class _cls23 +{ + + protected _cls23 m_31923; + protected _cls61 m_32061; + + _cls23() + { + m_31923 = null; + m_32061 = null; + } + + _cls23(_cls23 _pcls23, _cls61 _pcls61) + { + m_31923 = _pcls23; + m_32061 = _pcls61; + } + + _cls61 _113v61() + { + return m_32061; + } + + _cls61 _113I61(int i) + { + if(i == 0) + return m_32061; + else + return m_31923._113I61(i - 1); + } + + _cls23 _716123(_cls61 _pcls61) + { + if(_pcls61 == null) + return this; + else + return new _cls23(this, _pcls61); + } + + _cls23 _29v23() + { + return m_31923; + } + + _cls23 _29I23(int i) + { + if(i == 0) + return this; + else + return m_31923._29I23(i - 1); + } + + int _318vI() + { + if(m_32061 == null) + return 0; + else + return m_31923._318vI() + 1; + } + + public String toString(int i) + { + String s = ""; + if(m_32061 != null) + if(i == 0) + { + s = "..."; + } else + { + s = m_31923.toString(i - 1); + if(s.length() > 0) + s = s + ", " + m_32061; + else + s = m_32061.toString(); + } + return s; + } + + public String toString() + { + return toString(3); + } +} diff --git a/src/modules/mocha/_cls24.java b/src/modules/mocha/_cls24.java new file mode 100644 index 0000000..a45e593 --- /dev/null +++ b/src/modules/mocha/_cls24.java @@ -0,0 +1,80 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls9, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls14, _cls20, +// _cls52, _cls2, _cls67, _cls26, +// _cls25, _cls23, _cls27, _cls33, +// _cls63, _cls35, _cls40, _cls19, +// _cls49, _cls47, _cls38, _cls31, +// _cls30, _cls37, _cls54, _cls39, +// _cls48, _cls11, _cls46, _cls28, +// _cls12, _cls0, _cls53, _cls50, +// _cls10, _cls55, _cls8, _cls22, +// _cls17, _cls13, _cls51, _cls45, +// _cls21, _cls18, _cls43, _cls69, +// _cls71 + +class _cls24 extends _cls9 +{ + + protected int m_115I; + protected boolean m_34Z; + protected _cls0 m_160; + protected _cls71 m_11271; + + _cls24(int i, int j, int k, boolean flag) + { + super(i, j); + m_115I = k; + m_34Z = flag; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_160 = _pcls0; + m_11271 = _pcls71; + } + + public int _22vI() + { + return !m_34Z ? 1 : 0; + } + + public _cls23 _242323(_cls23 _pcls23) + { + _cls2 _lcls2 = m_160._9I2(m_115I); + _cls69 _lcls69 = new _cls69(_lcls2._81vString(), _lcls2._18vString()); + Object obj; + if(m_34Z) + obj = new _cls63(_lcls2._56v2(), _lcls69, m_160, m_11271, super.m_110I); + else + obj = new _cls67(_pcls23._113v61(), _lcls69, m_11271, super.m_110I); + return _pcls23._29I23(m_34Z ? 0 : 1)._716123(((_cls61) (obj))); + } + + boolean _11431Z(_cls31 _pcls31) + { + if(!(_pcls31 instanceof _cls49)) + return false; + _cls49 _lcls49 = (_cls49)_pcls31; + return m_115I == _lcls49.m_115I && m_34Z == _lcls49.m_34Z; + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("push " + m_160._9I2(m_115I)); + } + + public void _19vV() + { + m_115I = m_160._19IStringI(m_115I, "member"); + } +} diff --git a/src/modules/mocha/_cls25.java b/src/modules/mocha/_cls25.java new file mode 100644 index 0000000..ad16fdc --- /dev/null +++ b/src/modules/mocha/_cls25.java @@ -0,0 +1,44 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls31, _cls46, _cls27, _cls42, +// _cls18, _cls52, _cls35, _cls53, +// _cls43, _cls20, _cls14, _cls26, +// _cls36, _cls48, _cls45, _cls13, +// _cls54, _cls38, _cls50, _cls28, +// _cls41, _cls9, _cls16, _cls34, +// _cls44, _cls17, _cls37, _cls19, +// _cls11, _cls8, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10 + +abstract class _cls25 extends _cls31 +{ + + protected String m_44String; + protected String m_32String; + + _cls25(int i, int j, String s, String s1) + { + super(i, j); + m_44String = s; + m_32String = s1; + } + + public int _117vI() + { + return 1; + } + + String _299vString() + { + return m_32String; + } +} diff --git a/src/modules/mocha/_cls26.java b/src/modules/mocha/_cls26.java new file mode 100644 index 0000000..759e8a0 --- /dev/null +++ b/src/modules/mocha/_cls26.java @@ -0,0 +1,51 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls46, _cls27, _cls25, +// _cls42, _cls18, _cls52, _cls35, +// _cls53, _cls43, _cls20, _cls14, +// _cls36, _cls62, _cls48, _cls45, +// _cls13, _cls54, _cls38, _cls50, +// _cls28, _cls41, _cls9, _cls16, +// _cls34, _cls44, _cls17, _cls37, +// _cls19, _cls11, _cls8, _cls51, +// _cls40, _cls22, _cls33, _cls30, +// _cls49, _cls24, _cls47, _cls55, +// _cls15, _cls39, _cls21, _cls12, +// _cls23, _cls29, _cls32, _cls10 + +class _cls26 extends _cls31 +{ + + _cls26(int i, int j) + { + super(i, j); + } + + public int _22vI() + { + return 1; + } + + public int _117vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + _cls61 _lcls61 = _pcls23._113v61(); + return _pcls23._29v23()._716123(new _cls62("I", _lcls61, ".length", 26)); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println(".length"); + } +} diff --git a/src/modules/mocha/_cls27.java b/src/modules/mocha/_cls27.java new file mode 100644 index 0000000..a568f30 --- /dev/null +++ b/src/modules/mocha/_cls27.java @@ -0,0 +1,45 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls46, _cls25, _cls42, +// _cls18, _cls52, _cls35, _cls53, +// _cls43, _cls20, _cls14, _cls36, +// _cls26, _cls48, _cls45, _cls13, +// _cls54, _cls38, _cls50, _cls28, +// _cls41, _cls9, _cls16, _cls34, +// _cls44, _cls17, _cls37, _cls19, +// _cls11, _cls8, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls23, +// _cls29, _cls32, _cls10 + +class _cls27 extends _cls31 +{ + + _cls27(int i, int j) + { + super(i, j); + } + + public int _22vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._29v23(); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("lock"); + } +} diff --git a/src/modules/mocha/_cls28.java b/src/modules/mocha/_cls28.java new file mode 100644 index 0000000..b530e44 --- /dev/null +++ b/src/modules/mocha/_cls28.java @@ -0,0 +1,66 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls38, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls26, _cls25, +// _cls23, _cls27, _cls33, _cls35, +// _cls40, _cls19, _cls49, _cls47, +// _cls31, _cls30, _cls37, _cls54, +// _cls39, _cls48, _cls11, _cls46, +// _cls12, _cls53, _cls50, _cls10, +// _cls55, _cls8, _cls22, _cls17, +// _cls13, _cls51, _cls45, _cls21, +// _cls9, _cls18, _cls43, _cls69 + +class _cls28 extends _cls38 +{ + + _cls28(int i, int j, int k) + { + super(i, j, k); + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._716123(new _cls69("", "@")); + } + + public int _25vI() + { + return super.m_27I >= 0 ? 2 : 1; + } + + public int _26II(int i) + { + if(i == 0) + return super._26II(i); + else + return super.m_27I; + } + + public void _21IIV(int i, int j) + { + if(i == 0) + { + super._21IIV(i, j); + return; + } else + { + super.m_27I = j; + return; + } + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("finalize " + super.m_27I); + } +} diff --git a/src/modules/mocha/_cls29.java b/src/modules/mocha/_cls29.java new file mode 100644 index 0000000..75827a2 --- /dev/null +++ b/src/modules/mocha/_cls29.java @@ -0,0 +1,59 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls19, _cls46, _cls27, _cls25, +// _cls31, _cls42, _cls18, _cls52, +// _cls35, _cls53, _cls43, _cls20, +// _cls14, _cls26, _cls36, _cls48, +// _cls45, _cls13, _cls54, _cls38, +// _cls50, _cls28, _cls41, _cls9, +// _cls16, _cls34, _cls44, _cls17, +// _cls37, _cls11, _cls8, _cls51, +// _cls40, _cls22, _cls33, _cls30, +// _cls49, _cls24, _cls47, _cls55, +// _cls15, _cls39, _cls21, _cls12, +// _cls23, _cls32, _cls10 + +class _cls29 extends _cls19 +{ + + protected String m_44String; + + _cls29(int i, int j, String s) + { + super(i, j); + m_44String = s; + } + + public int _22vI() + { + return !m_44String.equals("V") ? 1 : 0; + } + + public _cls23 _242323(_cls23 _pcls23) + { + if(m_44String.equals("V")) + return _pcls23; + else + return _pcls23._29v23(); + } + + void _20PrintStreamV(PrintStream printstream) + { + if(m_44String.equals("V")) + { + printstream.println("return void"); + return; + } else + { + printstream.println("return"); + return; + } + } +} diff --git a/src/modules/mocha/_cls3.java b/src/modules/mocha/_cls3.java new file mode 100644 index 0000000..c83b806 --- /dev/null +++ b/src/modules/mocha/_cls3.java @@ -0,0 +1,34 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +public class _cls3 extends DataInputStream +{ + + public _cls3(InputStream inputstream) + { + super(inputstream); + } + + public int _300vI() + throws IOException + { + int i = readByte(); + if(i < 0) + i += 256; + return i; + } + + public int _14vI() + throws IOException + { + int i = readShort(); + if(i < 0) + i += 0x10000; + return i; + } +} diff --git a/src/modules/mocha/_cls30.java b/src/modules/mocha/_cls30.java new file mode 100644 index 0000000..8c934f5 --- /dev/null +++ b/src/modules/mocha/_cls30.java @@ -0,0 +1,54 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.DataInputStream; +import java.io.IOException; + +// Referenced classes of package mocha: +// _cls47, _cls46, _cls27, _cls25, +// _cls31, _cls42, _cls18, _cls52, +// _cls35, _cls53, _cls43, _cls20, +// _cls14, _cls36, _cls26, _cls48, +// _cls45, _cls13, _cls54, _cls38, +// _cls50, _cls28, _cls41, _cls9, +// _cls16, _cls34, _cls44, _cls17, +// _cls37, _cls19, _cls11, _cls8, +// _cls51, _cls40, _cls22, _cls33, +// _cls49, _cls24, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10, _cls3 + +class _cls30 extends _cls47 +{ + + protected int m_225aI[]; + + _cls30(int i, int j, _cls3 _pcls3) + throws IOException + { + super(i, j); + super.m_28I = i + _pcls3.readInt(); + int k = _pcls3.readInt(); + m_225aI = new int[k]; + super.m_27aI = new int[k]; + for(int l = 0; l < k; l++) + { + m_225aI[l] = _pcls3.readInt(); + super.m_27aI[l] = i + _pcls3.readInt(); + } + + } + + public int _200vI() + { + return super.m_226I + 8 * (super.m_27aI.length + 1); + } + + int _23II(int i) + { + return m_225aI[i - 1]; + } +} diff --git a/src/modules/mocha/_cls31.java b/src/modules/mocha/_cls31.java new file mode 100644 index 0000000..53d7ce3 --- /dev/null +++ b/src/modules/mocha/_cls31.java @@ -0,0 +1,923 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// _cls28, _cls41, _cls51, _cls3, +// _cls37, _cls11, _cls74, _cls32, +// _cls30, _cls9, _cls103, _cls38, +// _cls15, _cls39, _cls18, _cls36, +// _cls13, _cls45, _cls24, _cls40, +// _cls34, _cls27, _cls25, _cls49, +// _cls47, _cls43, _cls54, _cls12, +// _cls16, _cls10, _cls26, _cls29, +// _cls8, _cls50, _cls46, _cls53, +// _cls22, Decompiler, _cls52, _cls44, +// _cls42, _cls19, _cls20, _cls35, +// _cls128, _cls33, _cls48, _cls55, +// _cls17, _cls21, _cls14, _cls23, +// _cls0, _cls71, _cls129 + +abstract class _cls31 + implements _cls74 +{ + + protected int m_110I; + protected int m_226I; + protected int m_312I; + protected int m_285I; + protected _cls23 m_10523; + + _cls31(int i, int j) + { + m_110I = i; + m_226I = j; + m_312I = i + j; + m_285I = 0; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + } + + public int _200vI() + { + return m_226I; + } + + public int _155vI() + { + return m_110I; + } + + public int _94vI() + { + return m_110I; + } + + public int _48vI() + { + return (m_110I + m_226I) - 1; + } + + public void _152129V(_cls129 _pcls129) + { + } + + public void _197vV() + { + m_285I++; + } + + public void _196vV() + { + m_285I--; + } + + public int _198vI() + { + return m_285I; + } + + public int _25vI() + { + return 1; + } + + public int _26II(int i) + { + return m_312I; + } + + public void _21IIV(int i, int j) + { + m_312I = j; + } + + public void _10723V(_cls23 _pcls23, _cls103 _pcls103) + { + if(m_10523 == null) + { + m_10523 = _pcls23; + _cls23 _lcls23 = _242323(_pcls23); + for(int i = 0; i < _25vI(); i++) + _pcls103._254I74(_26II(i))._10723V(_lcls23, _pcls103); + + } + } + + public void _2vV() + { + } + + public _cls23 _199v23() + { + return m_10523; + } + + public int _22vI() + { + return 0; + } + + public int _117vI() + { + return 0; + } + + public int _170vI() + { + return 1; + } + + public void _17PrintStreamZV(PrintStream printstream, int i, boolean flag) + { + if(Decompiler.m_debugZ) + { + for(int j = 0; j < i - 2; j++) + printstream.print(" "); + + printstream.println(_94vI() + "-" + _48vI() + ":" + _198vI() + ">"); + } + for(int k = 0; k < i; k++) + printstream.print(" "); + + _20PrintStreamV(printstream); + } + + abstract void _20PrintStreamV(PrintStream printstream); + + public void _19vV() + { + } + + static _cls74 _953v74(_cls3 _pcls3, int i) + throws IOException, _cls128 + { + int l11 = _pcls3._300vI(); + switch(l11) + { + case 0: // '\0' + return new _cls40(i, 1); + + case 1: // '\001' + return new _cls42(i, 1, "A", "null"); + + case 2: // '\002' + return new _cls42(i, 1, "B", "-1"); + + case 3: // '\003' + return new _cls42(i, 1, "Z", "0"); + + case 4: // '\004' + return new _cls42(i, 1, "Z", "1"); + + case 5: // '\005' + return new _cls42(i, 1, "B", "2"); + + case 6: // '\006' + return new _cls42(i, 1, "B", "3"); + + case 7: // '\007' + return new _cls42(i, 1, "B", "4"); + + case 8: // '\b' + return new _cls42(i, 1, "B", "5"); + + case 9: // '\t' + return new _cls42(i, 1, "J", "0L"); + + case 10: // '\n' + return new _cls42(i, 1, "J", "1L"); + + case 11: // '\013' + return new _cls42(i, 1, "F", "0.0F"); + + case 12: // '\f' + return new _cls42(i, 1, "F", "1.0F"); + + case 13: // '\r' + return new _cls42(i, 1, "F", "2.0F"); + + case 14: // '\016' + return new _cls42(i, 1, "D", "0.0"); + + case 15: // '\017' + return new _cls42(i, 1, "D", "1.0"); + + case 16: // '\020' + byte byte0 = _pcls3.readByte(); + return new _cls42(i, 2, "B", String.valueOf(byte0)); + + case 17: // '\021' + short word0 = _pcls3.readShort(); + return new _cls42(i, 3, "S", String.valueOf(word0)); + + case 18: // '\022' + int j = _pcls3._300vI(); + return new _cls15(i, 2, j); + + case 19: // '\023' + case 20: // '\024' + int k = _pcls3._14vI(); + return new _cls15(i, 3, k); + + case 21: // '\025' + int l = _pcls3._300vI(); + return new _cls12(i, 2, "W", l); + + case 22: // '\026' + int i1 = _pcls3._300vI(); + return new _cls12(i, 2, "J", i1); + + case 23: // '\027' + int j1 = _pcls3._300vI(); + return new _cls12(i, 2, "F", j1); + + case 24: // '\030' + int k1 = _pcls3._300vI(); + return new _cls12(i, 2, "D", k1); + + case 25: // '\031' + int l1 = _pcls3._300vI(); + return new _cls12(i, 2, "A", l1); + + case 26: // '\032' + return new _cls12(i, 1, "W", 0); + + case 27: // '\033' + return new _cls12(i, 1, "W", 1); + + case 28: // '\034' + return new _cls12(i, 1, "W", 2); + + case 29: // '\035' + return new _cls12(i, 1, "W", 3); + + case 30: // '\036' + return new _cls12(i, 1, "J", 0); + + case 31: // '\037' + return new _cls12(i, 1, "J", 1); + + case 32: // ' ' + return new _cls12(i, 1, "J", 2); + + case 33: // '!' + return new _cls12(i, 1, "J", 3); + + case 34: // '"' + return new _cls12(i, 1, "F", 0); + + case 35: // '#' + return new _cls12(i, 1, "F", 1); + + case 36: // '$' + return new _cls12(i, 1, "F", 2); + + case 37: // '%' + return new _cls12(i, 1, "F", 3); + + case 38: // '&' + return new _cls12(i, 1, "D", 0); + + case 39: // '\'' + return new _cls12(i, 1, "D", 1); + + case 40: // '(' + return new _cls12(i, 1, "D", 2); + + case 41: // ')' + return new _cls12(i, 1, "D", 3); + + case 42: // '*' + return new _cls12(i, 1, "A", 0); + + case 43: // '+' + return new _cls12(i, 1, "A", 1); + + case 44: // ',' + return new _cls12(i, 1, "A", 2); + + case 45: // '-' + return new _cls12(i, 1, "A", 3); + + case 46: // '.' + return new _cls37(i, 1, "I"); + + case 47: // '/' + return new _cls37(i, 1, "J"); + + case 48: // '0' + return new _cls37(i, 1, "F"); + + case 49: // '1' + return new _cls37(i, 1, "D"); + + case 50: // '2' + return new _cls37(i, 1, "A"); + + case 51: // '3' + return new _cls37(i, 1, "B"); + + case 52: // '4' + return new _cls37(i, 1, "C"); + + case 53: // '5' + return new _cls37(i, 1, "S"); + + case 54: // '6' + int i2 = _pcls3._300vI(); + return new _cls18(i, 2, "W", i2); + + case 55: // '7' + int j2 = _pcls3._300vI(); + return new _cls18(i, 2, "J", j2); + + case 56: // '8' + int k2 = _pcls3._300vI(); + return new _cls18(i, 2, "F", k2); + + case 57: // '9' + int l2 = _pcls3._300vI(); + return new _cls18(i, 2, "D", l2); + + case 58: // ':' + int i3 = _pcls3._300vI(); + return new _cls18(i, 2, "A", i3); + + case 59: // ';' + return new _cls18(i, 1, "W", 0); + + case 60: // '<' + return new _cls18(i, 1, "W", 1); + + case 61: // '=' + return new _cls18(i, 1, "W", 2); + + case 62: // '>' + return new _cls18(i, 1, "W", 3); + + case 63: // '?' + return new _cls18(i, 1, "J", 0); + + case 64: // '@' + return new _cls18(i, 1, "J", 1); + + case 65: // 'A' + return new _cls18(i, 1, "J", 2); + + case 66: // 'B' + return new _cls18(i, 1, "J", 3); + + case 67: // 'C' + return new _cls18(i, 1, "F", 0); + + case 68: // 'D' + return new _cls18(i, 1, "F", 1); + + case 69: // 'E' + return new _cls18(i, 1, "F", 2); + + case 70: // 'F' + return new _cls18(i, 1, "F", 3); + + case 71: // 'G' + return new _cls18(i, 1, "D", 0); + + case 72: // 'H' + return new _cls18(i, 1, "D", 1); + + case 73: // 'I' + return new _cls18(i, 1, "D", 2); + + case 74: // 'J' + return new _cls18(i, 1, "D", 3); + + case 75: // 'K' + return new _cls18(i, 1, "A", 0); + + case 76: // 'L' + return new _cls18(i, 1, "A", 1); + + case 77: // 'M' + return new _cls18(i, 1, "A", 2); + + case 78: // 'N' + return new _cls18(i, 1, "A", 3); + + case 79: // 'O' + return new _cls50(i, 1, "I"); + + case 80: // 'P' + return new _cls50(i, 1, "J"); + + case 81: // 'Q' + return new _cls50(i, 1, "F"); + + case 82: // 'R' + return new _cls50(i, 1, "D"); + + case 83: // 'S' + return new _cls50(i, 1, "A"); + + case 84: // 'T' + return new _cls50(i, 1, "B"); + + case 85: // 'U' + return new _cls50(i, 1, "C"); + + case 86: // 'V' + return new _cls50(i, 1, "S"); + + case 87: // 'W' + case 88: // 'X' + return new _cls14(i, 1); + + case 89: // 'Y' + return new _cls46(i, 1, 0); + + case 90: // 'Z' + return new _cls46(i, 1, 1); + + case 91: // '[' + return new _cls46(i, 1, 2); + + case 92: // '\\' + return new _cls13(i, 1, 0); + + case 93: // ']' + return new _cls13(i, 1, 1); + + case 94: // '^' + return new _cls13(i, 1, 2); + + case 95: // '_' + return new _cls45(i, 1); + + case 96: // '`' + return new _cls34(i, 1, "I", "+"); + + case 97: // 'a' + return new _cls34(i, 1, "J", "+"); + + case 98: // 'b' + return new _cls34(i, 1, "F", "+"); + + case 99: // 'c' + return new _cls34(i, 1, "D", "+"); + + case 100: // 'd' + return new _cls34(i, 1, "I", "-"); + + case 101: // 'e' + return new _cls34(i, 1, "J", "-"); + + case 102: // 'f' + return new _cls34(i, 1, "F", "-"); + + case 103: // 'g' + return new _cls34(i, 1, "D", "-"); + + case 104: // 'h' + return new _cls34(i, 1, "I", "*"); + + case 105: // 'i' + return new _cls34(i, 1, "J", "*"); + + case 106: // 'j' + return new _cls34(i, 1, "F", "*"); + + case 107: // 'k' + return new _cls34(i, 1, "D", "*"); + + case 108: // 'l' + return new _cls34(i, 1, "I", "/"); + + case 109: // 'm' + return new _cls34(i, 1, "J", "/"); + + case 110: // 'n' + return new _cls34(i, 1, "F", "/"); + + case 111: // 'o' + return new _cls34(i, 1, "D", "/"); + + case 112: // 'p' + return new _cls34(i, 1, "I", "%"); + + case 113: // 'q' + return new _cls34(i, 1, "J", "%"); + + case 114: // 'r' + return new _cls34(i, 1, "F", "%"); + + case 115: // 's' + return new _cls34(i, 1, "D", "%"); + + case 116: // 't' + return new _cls41(i, 1, "I", "-"); + + case 117: // 'u' + return new _cls41(i, 1, "J", "-"); + + case 118: // 'v' + return new _cls41(i, 1, "F", "-"); + + case 119: // 'w' + return new _cls41(i, 1, "D", "-"); + + case 120: // 'x' + return new _cls34(i, 1, "I", "<<"); + + case 121: // 'y' + return new _cls34(i, 1, "J", "<<"); + + case 122: // 'z' + return new _cls34(i, 1, "I", ">>"); + + case 123: // '{' + return new _cls34(i, 1, "J", ">>"); + + case 124: // '|' + return new _cls34(i, 1, "I", ">>>"); + + case 125: // '}' + return new _cls34(i, 1, "J", ">>>"); + + case 126: // '~' + return new _cls34(i, 1, "I", "&"); + + case 127: // '\177' + return new _cls34(i, 1, "J", "&"); + + case 128: + return new _cls34(i, 1, "I", "|"); + + case 129: + return new _cls34(i, 1, "J", "|"); + + case 130: + return new _cls34(i, 1, "I", "^"); + + case 131: + return new _cls34(i, 1, "J", "^"); + + case 132: + int j3 = _pcls3._300vI(); + byte byte1 = _pcls3.readByte(); + return new _cls22(i, 3, j3, byte1); + + case 133: + return new _cls21(i, 1, "W", "J"); + + case 134: + return new _cls21(i, 1, "W", "F"); + + case 135: + return new _cls21(i, 1, "W", "D"); + + case 136: + return new _cls21(i, 1, "J", "I"); + + case 137: + return new _cls21(i, 1, "J", "F"); + + case 138: + return new _cls21(i, 1, "J", "D"); + + case 139: + return new _cls21(i, 1, "F", "I"); + + case 140: + return new _cls21(i, 1, "F", "J"); + + case 141: + return new _cls21(i, 1, "F", "D"); + + case 142: + return new _cls21(i, 1, "D", "I"); + + case 143: + return new _cls21(i, 1, "D", "J"); + + case 144: + return new _cls21(i, 1, "D", "F"); + + case 145: + return new _cls21(i, 1, "W", "B"); + + case 146: + return new _cls21(i, 1, "W", "C"); + + case 147: + return new _cls21(i, 1, "W", "S"); + + case 148: + return new _cls32(i, 1, "J"); + + case 149: + case 150: + return new _cls32(i, 1, "F"); + + case 151: + case 152: + return new _cls32(i, 1, "D"); + + case 153: + short word1 = _pcls3.readShort(); + return new _cls16(i, 3, "==", word1); + + case 154: + short word2 = _pcls3.readShort(); + return new _cls16(i, 3, "!=", word2); + + case 155: + short word3 = _pcls3.readShort(); + return new _cls16(i, 3, "<", word3); + + case 156: + short word4 = _pcls3.readShort(); + return new _cls16(i, 3, ">=", word4); + + case 157: + short word5 = _pcls3.readShort(); + return new _cls16(i, 3, ">", word5); + + case 158: + short word6 = _pcls3.readShort(); + return new _cls16(i, 3, "<=", word6); + + case 159: + short word7 = _pcls3.readShort(); + return new _cls48(i, 3, "W", "==", word7); + + case 160: + short word8 = _pcls3.readShort(); + return new _cls48(i, 3, "W", "!=", word8); + + case 161: + short word9 = _pcls3.readShort(); + return new _cls48(i, 3, "W", "<", word9); + + case 162: + short word10 = _pcls3.readShort(); + return new _cls48(i, 3, "W", ">=", word10); + + case 163: + short word11 = _pcls3.readShort(); + return new _cls48(i, 3, "W", ">", word11); + + case 164: + short word12 = _pcls3.readShort(); + return new _cls48(i, 3, "W", "<=", word12); + + case 165: + short word13 = _pcls3.readShort(); + return new _cls48(i, 3, "A", "==", word13); + + case 166: + short word14 = _pcls3.readShort(); + return new _cls48(i, 3, "A", "!=", word14); + + case 167: + short word15 = _pcls3.readShort(); + return new _cls51(i, 3, word15); + + case 168: + short word16 = _pcls3.readShort(); + return new _cls28(i, 3, word16); + + case 169: + int k3 = _pcls3._300vI(); + return new _cls33(i, 2, k3); + + case 170: + int l3 = -i - 1 & 3; + _pcls3.skip(l3); + return new _cls53(i, l3 + 1, _pcls3); + + case 171: + int i4 = -i - 1 & 3; + _pcls3.skip(i4); + return new _cls30(i, i4 + 1, _pcls3); + + case 172: + return new _cls29(i, 1, "W"); + + case 173: + return new _cls29(i, 1, "J"); + + case 174: + return new _cls29(i, 1, "F"); + + case 175: + return new _cls29(i, 1, "D"); + + case 176: + return new _cls29(i, 1, "A"); + + case 177: + return new _cls29(i, 1, "V"); + + case 178: + int j4 = _pcls3._14vI(); + return new _cls24(i, 3, j4, true); + + case 179: + int k4 = _pcls3._14vI(); + return new _cls49(i, 3, k4, true); + + case 180: + int l4 = _pcls3._14vI(); + return new _cls24(i, 3, l4, false); + + case 181: + int i5 = _pcls3._14vI(); + return new _cls49(i, 3, i5, false); + + case 182: + int j5 = _pcls3._14vI(); + return new _cls52(i, 3, j5); + + case 183: + int k5 = _pcls3._14vI(); + return new _cls35(i, 3, k5); + + case 184: + int l5 = _pcls3._14vI(); + return new _cls44(i, 3, l5); + + case 185: + int i6 = _pcls3._14vI(); + int j11 = _pcls3.readByte(); + j11 = _pcls3._300vI(); + return new _cls52(i, 5, i6); + + case 186: + return new _cls10(i, 1); + + case 187: + int j6 = _pcls3._14vI(); + return new _cls36(i, 3, j6); + + case 188: + int k6 = _pcls3._300vI(); + String s; + switch(k6) + { + case 1: // '\001' + s = "[[?"; + break; + + case 4: // '\004' + s = "[Z"; + break; + + case 5: // '\005' + s = "[C"; + break; + + case 6: // '\006' + s = "[F"; + break; + + case 7: // '\007' + s = "[D"; + break; + + case 8: // '\b' + s = "[B"; + break; + + case 9: // '\t' + s = "[S"; + break; + + case 10: // '\n' + s = "[I"; + break; + + case 11: // '\013' + s = "[J"; + break; + + case 2: // '\002' + case 3: // '\003' + default: + throw new _cls128("Invalid newarray operand " + k6); + } + return new _cls20(i, 2, s); + + case 189: + int l6 = _pcls3._14vI(); + return new _cls20(i, 3, l6); + + case 190: + return new _cls26(i, 1); + + case 191: + return new _cls11(i, 1); + + case 192: + int i7 = _pcls3._14vI(); + return new _cls17(i, 3, i7); + + case 193: + int j7 = _pcls3._14vI(); + return new _cls39(i, 3, j7); + + case 194: + return new _cls27(i, 1); + + case 195: + return new _cls8(i, 1); + + case 196: + l11 = _pcls3._300vI(); + switch(l11) + { + case 21: // '\025' + int k7 = _pcls3._14vI(); + return new _cls12(i, 4, "W", k7); + + case 22: // '\026' + int l7 = _pcls3._14vI(); + return new _cls12(i, 4, "J", l7); + + case 23: // '\027' + int i8 = _pcls3._14vI(); + return new _cls12(i, 4, "F", i8); + + case 24: // '\030' + int j8 = _pcls3._14vI(); + return new _cls12(i, 4, "D", j8); + + case 25: // '\031' + int k8 = _pcls3._14vI(); + return new _cls12(i, 4, "A", k8); + + case 54: // '6' + int l8 = _pcls3._14vI(); + return new _cls18(i, 4, "W", l8); + + case 55: // '7' + int i9 = _pcls3._14vI(); + return new _cls18(i, 4, "J", i9); + + case 56: // '8' + int j9 = _pcls3._14vI(); + return new _cls18(i, 4, "F", j9); + + case 57: // '9' + int k9 = _pcls3._14vI(); + return new _cls18(i, 4, "D", k9); + + case 58: // ':' + int l9 = _pcls3._14vI(); + return new _cls18(i, 4, "A", l9); + + case 132: + int i10 = _pcls3._14vI(); + short word19 = _pcls3.readShort(); + return new _cls22(i, 6, i10, word19); + + case 169: + int j10 = _pcls3._14vI(); + return new _cls33(i, 4, j10); + } + throw new _cls128("Invalid wide opcode " + l11); + + case 197: + int k10 = _pcls3._14vI(); + int k11 = _pcls3._300vI(); + return new _cls20(i, 4, k10, k11); + + case 198: + short word17 = _pcls3.readShort(); + return new _cls43(i, 3, "==", word17); + + case 199: + short word18 = _pcls3.readShort(); + return new _cls43(i, 3, "!=", word18); + + case 200: + int l10 = _pcls3.readInt(); + return new _cls51(i, 5, l10); + + case 201: + int i11 = _pcls3.readInt(); + return new _cls28(i, 5, i11); + + case 202: + return new _cls40(i, 1); + } + throw new _cls128("Invalid opcode " + l11); + } + + public abstract _cls23 _242323(_cls23 _pcls23); +} diff --git a/src/modules/mocha/_cls32.java b/src/modules/mocha/_cls32.java new file mode 100644 index 0000000..d04fd1c --- /dev/null +++ b/src/modules/mocha/_cls32.java @@ -0,0 +1,34 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls34, _cls46, _cls27, _cls25, +// _cls31, _cls42, _cls18, _cls52, +// _cls35, _cls53, _cls43, _cls20, +// _cls14, _cls26, _cls36, _cls48, +// _cls45, _cls13, _cls54, _cls38, +// _cls50, _cls28, _cls41, _cls9, +// _cls16, _cls44, _cls17, _cls37, +// _cls19, _cls11, _cls8, _cls51, +// _cls40, _cls22, _cls33, _cls30, +// _cls49, _cls24, _cls47, _cls55, +// _cls15, _cls39, _cls21, _cls12, +// _cls29, _cls10 + +class _cls32 extends _cls34 +{ + + _cls32(int i, int j, String s) + { + super(i, j, s, "<>"); + } + + void _345StringV(String s) + { + super.m_32String = s; + } +} diff --git a/src/modules/mocha/_cls33.java b/src/modules/mocha/_cls33.java new file mode 100644 index 0000000..7a3a02d --- /dev/null +++ b/src/modules/mocha/_cls33.java @@ -0,0 +1,59 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls19, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls26, _cls25, +// _cls27, _cls35, _cls40, _cls71, +// _cls49, _cls47, _cls38, _cls31, +// _cls30, _cls37, _cls54, _cls39, +// _cls48, _cls11, _cls46, _cls28, +// _cls12, _cls53, _cls50, _cls10, +// _cls55, _cls8, _cls22, _cls17, +// _cls13, _cls51, _cls45, _cls21, +// _cls9, _cls18, _cls43, _cls0, +// _cls23, _cls103 + +class _cls33 extends _cls19 +{ + + protected int m_106I; + protected _cls71 m_11271; + + _cls33(int i, int j, int k) + { + super(i, j); + m_106I = k; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_11271 = _pcls71; + } + + public void _10723V(_cls23 _pcls23, _cls103 _pcls103) + { + if(super.m_10523 == null) + { + m_11271._109IIV(m_106I, super.m_110I, ""); + super._10723V(_pcls23, _pcls103); + } + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23; + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("endfinalize " + m_11271._111II125(m_106I, super.m_110I)); + } +} diff --git a/src/modules/mocha/_cls34.java b/src/modules/mocha/_cls34.java new file mode 100644 index 0000000..20363a8 --- /dev/null +++ b/src/modules/mocha/_cls34.java @@ -0,0 +1,159 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls25, _cls15, _cls29, _cls42, +// _cls16, _cls44, _cls41, _cls36, +// _cls32, _cls24, _cls14, _cls20, +// _cls52, _cls26, _cls23, _cls27, +// _cls33, _cls35, _cls40, _cls19, +// _cls71, _cls49, _cls47, _cls61, +// _cls38, _cls66, _cls31, _cls30, +// _cls37, _cls54, _cls39, _cls48, +// _cls11, _cls46, _cls28, _cls12, +// _cls53, _cls50, _cls10, _cls55, +// _cls8, _cls57, _cls22, _cls17, +// _cls13, _cls51, _cls45, _cls21, +// _cls9, _cls18, _cls43, _cls0, +// _cls103 + +class _cls34 extends _cls25 +{ + + protected _cls71 m_11271; + private static final byte m_321aB[] = { + 0, 13, 14, 15, 16, 17, 18, 18, 19, 19, + 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, + 22 + }; + private static final byte m_324aB[] = { + 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1 + }; + private static final String m_322aString[] = { + "", "Z", "Z", "", "", "", "Z", "Z", "Z", "Z", + "Z", "Z", "Z", "", "", "", "", "", "", "", + "" + }; + private static final byte m_323aB[] = { + 0, 2, 2, 1, 1, 1, 2, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0 + }; + + _cls34(int i, int j, String s, String s1) + { + super(i, j, s, s1); + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_11271 = _pcls71; + } + + public int _22vI() + { + return 2; + } + + private int _325vI() + { + if(super.m_32String.equals("||")) + return 1; + if(super.m_32String.equals("&&")) + return 2; + if(super.m_32String.equals("|")) + return 3; + if(super.m_32String.equals("^")) + return 4; + if(super.m_32String.equals("&")) + return 5; + if(super.m_32String.equals("==")) + return 6; + if(super.m_32String.equals("!=")) + return 7; + if(super.m_32String.equals("<>")) + return 8; + if(super.m_32String.equals("<")) + return 9; + if(super.m_32String.equals("<=")) + return 10; + if(super.m_32String.equals(">")) + return 11; + if(super.m_32String.equals(">=")) + return 12; + if(super.m_32String.equals("<<")) + return 13; + if(super.m_32String.equals(">>")) + return 14; + if(super.m_32String.equals(">>>")) + return 15; + if(super.m_32String.equals("+")) + return 16; + if(super.m_32String.equals("-")) + return 17; + if(super.m_32String.equals("*")) + return 18; + if(super.m_32String.equals("/")) + return 19; + return !super.m_32String.equals("%") ? 0 : 20; + } + + public void _10723V(_cls23 _pcls23, _cls103 _pcls103) + { + if(super.m_10523 == null) + { + switch(m_323aB[_325vI()]) + { + default: + break; + + case 0: // '\0' + m_11271._18661vV(_pcls23._113I61(0), super.m_110I); + m_11271._18661vV(_pcls23._113I61(1), super.m_110I); + break; + + case 1: // '\001' + String s = _pcls23._113I61(0)._43vString(); + String s1 = _pcls23._113I61(1)._43vString(); + if(!s.equals("Z") && s1.equals("Z")) + { + m_11271._18661vV(_pcls23._113I61(1), super.m_110I); + break; + } + if(s.equals("Z") && !s1.equals("Z")) + m_11271._18661vV(_pcls23._113I61(0), super.m_110I); + break; + } + super._10723V(_pcls23, _pcls103); + } + } + + public _cls23 _242323(_cls23 _pcls23) + { + _cls61 _lcls61 = _pcls23._113I61(1); + _cls61 _lcls61_1 = _pcls23._113I61(0); + int i = _325vI(); + byte byte0 = m_321aB[i]; + byte byte1 = m_324aB[i]; + String s = m_322aString[i]; + if(s.length() == 0) + s = super.m_44String; + if(byte1 == 0) + return _pcls23._29I23(2)._716123(new _cls66(s, _lcls61, _lcls61_1, super.m_32String, byte0)); + else + return _pcls23._29I23(2)._716123(new _cls57(s, _lcls61, _lcls61_1, super.m_32String, byte0)); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("" + super.m_32String); + } + +} diff --git a/src/modules/mocha/_cls35.java b/src/modules/mocha/_cls35.java new file mode 100644 index 0000000..7af8eea --- /dev/null +++ b/src/modules/mocha/_cls35.java @@ -0,0 +1,62 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls52, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls2, _cls26, _cls25, +// _cls27, _cls33, _cls40, _cls19, +// _cls49, _cls47, _cls38, _cls31, +// _cls30, _cls37, _cls54, _cls39, +// _cls48, _cls11, _cls46, _cls28, +// _cls12, _cls0, _cls53, _cls50, +// _cls10, _cls55, _cls8, _cls22, +// _cls17, _cls13, _cls51, _cls45, +// _cls21, _cls9, _cls18, _cls43, +// _cls61 + +class _cls35 extends _cls52 +{ + + _cls35(int i, int j, int k) + { + super(i, j, k); + } + + boolean _74vZ() + { + _cls2 _lcls2 = super.m_160._9I2(super.m_75I); + return _lcls2._18vString().equals(""); + } + + boolean _7361Z(_cls61 _pcls61) + { + if(!_pcls61.toString().equals("this")) + return false; + _cls2 _lcls2 = super.m_160._9I2(super.m_75I); + _cls2 _lcls2_1 = _lcls2._56v2(); + return _lcls2_1 != super.m_160._76v2(); + } + + boolean _7761Z(_cls61 _pcls61) + { + if(!_pcls61.toString().equals("this")) + return false; + _cls2 _lcls2 = super.m_160._9I2(super.m_75I); + _cls2 _lcls2_1 = _lcls2._56v2(); + return _lcls2_1 == super.m_160._76v2(); + } + + void _20PrintStreamV(PrintStream printstream) + { + _cls2 _lcls2 = super.m_160._9I2(super.m_75I); + _cls2 _lcls2_1 = _lcls2._56v2(); + printstream.println("invoke " + _lcls2_1 + "." + _lcls2); + } +} diff --git a/src/modules/mocha/_cls36.java b/src/modules/mocha/_cls36.java new file mode 100644 index 0000000..0c8ca91 --- /dev/null +++ b/src/modules/mocha/_cls36.java @@ -0,0 +1,63 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls32, _cls24, _cls14, _cls20, +// _cls52, _cls2, _cls26, _cls25, +// _cls23, _cls27, _cls33, _cls35, +// _cls40, _cls19, _cls49, _cls47, +// _cls38, _cls30, _cls37, _cls54, +// _cls39, _cls48, _cls11, _cls46, +// _cls28, _cls12, _cls0, _cls53, +// _cls50, _cls10, _cls55, _cls8, +// _cls22, _cls17, _cls13, _cls51, +// _cls45, _cls21, _cls9, _cls18, +// _cls69, _cls43, _cls71 + +class _cls36 extends _cls31 +{ + + protected int m_187I; + protected _cls0 m_160; + + _cls36(int i, int j, int k) + { + super(i, j); + m_187I = k; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_160 = _pcls0; + } + + public int _117vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + String s = m_160._9I2(m_187I)._56v2().toString(); + String s1 = "new " + m_160._101StringString(s); + String s2 = "L" + s + ";"; + return _pcls23._716123(new _cls69(s2, s1)); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("new " + m_160._9I2(m_187I)); + } + + public void _19vV() + { + m_187I = m_160._19IStringI(m_187I, "class"); + } +} diff --git a/src/modules/mocha/_cls37.java b/src/modules/mocha/_cls37.java new file mode 100644 index 0000000..8e5e53c --- /dev/null +++ b/src/modules/mocha/_cls37.java @@ -0,0 +1,65 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls9, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls26, _cls65, +// _cls25, _cls23, _cls27, _cls33, +// _cls35, _cls40, _cls19, _cls49, +// _cls47, _cls61, _cls38, _cls31, +// _cls30, _cls54, _cls39, _cls48, +// _cls11, _cls46, _cls28, _cls12, +// _cls53, _cls50, _cls10, _cls55, +// _cls8, _cls22, _cls17, _cls13, +// _cls51, _cls45, _cls21, _cls18, +// _cls43 + +class _cls37 extends _cls9 +{ + + protected String m_44String; + + _cls37(int i, int j, String s) + { + super(i, j); + m_44String = s; + } + + public int _22vI() + { + return 2; + } + + public _cls23 _242323(_cls23 _pcls23) + { + _cls61 _lcls61 = _pcls23._113I61(1); + _cls61 _lcls61_1 = _pcls23._113I61(0); + String s = _lcls61._43vString(); + s = s.length() <= 1 ? "?" : s.substring(1); + return _pcls23._29I23(2)._716123(new _cls65(s, _lcls61, _lcls61_1)); + } + + boolean _11431Z(_cls31 _pcls31) + { + if(!(_pcls31 instanceof _cls50)) + { + return false; + } else + { + _cls50 _lcls50 = (_cls50)_pcls31; + return m_44String.equals(_lcls50.m_44String); + } + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("push []"); + } +} diff --git a/src/modules/mocha/_cls38.java b/src/modules/mocha/_cls38.java new file mode 100644 index 0000000..bbb1ad6 --- /dev/null +++ b/src/modules/mocha/_cls38.java @@ -0,0 +1,32 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls31, _cls46, _cls27, _cls25, +// _cls42, _cls18, _cls52, _cls35, +// _cls53, _cls43, _cls20, _cls14, +// _cls26, _cls36, _cls48, _cls45, +// _cls13, _cls54, _cls50, _cls28, +// _cls41, _cls9, _cls16, _cls34, +// _cls44, _cls17, _cls37, _cls19, +// _cls11, _cls8, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10 + +abstract class _cls38 extends _cls31 +{ + + protected int m_27I; + + _cls38(int i, int j, int k) + { + super(i, j); + m_27I = i + k; + } +} diff --git a/src/modules/mocha/_cls39.java b/src/modules/mocha/_cls39.java new file mode 100644 index 0000000..5a35cec --- /dev/null +++ b/src/modules/mocha/_cls39.java @@ -0,0 +1,68 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls2, _cls26, +// _cls25, _cls23, _cls27, _cls33, +// _cls35, _cls40, _cls19, _cls49, +// _cls47, _cls38, _cls66, _cls30, +// _cls37, _cls54, _cls48, _cls11, +// _cls46, _cls28, _cls12, _cls0, +// _cls53, _cls50, _cls10, _cls55, +// _cls8, _cls22, _cls17, _cls13, +// _cls51, _cls45, _cls21, _cls9, +// _cls18, _cls43, _cls69, _cls71 + +class _cls39 extends _cls31 +{ + + protected int m_187I; + protected _cls0 m_160; + + _cls39(int i, int j, int k) + { + super(i, j); + m_187I = k; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_160 = _pcls0; + } + + public int _22vI() + { + return 1; + } + + public int _117vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + String s = m_160._9I2(m_187I)._18vString(); + _cls69 _lcls69 = new _cls69("?", s); + _cls61 _lcls61 = _pcls23._113v61(); + return _pcls23._29v23()._716123(new _cls66("Z", _lcls61, _lcls69, "instanceof", 19)); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("instanceof " + m_160._9I2(m_187I)); + } + + public void _19vV() + { + m_187I = m_160._19IStringI(m_187I, "class"); + } +} diff --git a/src/modules/mocha/_cls4.java b/src/modules/mocha/_cls4.java new file mode 100644 index 0000000..ad4071f --- /dev/null +++ b/src/modules/mocha/_cls4.java @@ -0,0 +1,193 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls75, _cls34, _cls102, _cls42, +// _cls95, _cls41, _cls77, _cls98, +// _cls92, _cls52, _cls104, _cls87, +// _cls73, _cls2, _cls96, _cls103, +// _cls25, _cls105, _cls23, _cls100, +// _cls76, _cls91, _cls84, _cls88, +// _cls97, _cls80, _cls81, _cls83, +// _cls85, _cls90, _cls93, _cls79, +// _cls99, _cls106, _cls86, _cls74, +// _cls101, _cls82, _cls89, _cls78, +// _cls94, _cls61 + +class _cls4 extends _cls75 +{ + + _cls74 m_31074; + _cls4 m_54a4[]; + + _cls4() + { + } + + _cls4(_cls74 _pcls74, _cls4 a_pcls4[]) + { + _497475(((_cls74) (a_pcls4.length <= 0 ? _pcls74 : ((_cls74) (a_pcls4[0]))))); + _527475(_pcls74); + m_31074 = _pcls74; + m_54a4 = a_pcls4; + } + + public int _22vI() + { + return m_54a4.length; + } + + public int _117vI() + { + return -1; + } + + public int _48vI() + { + return m_31074._48vI(); + } + + public _cls23 _242323(_cls23 _pcls23) + { + for(int i = 0; i < m_54a4.length; i++) + _pcls23 = m_54a4[i]._242323(_pcls23); + + return m_31074._242323(_pcls23); + } + + public _cls61 _51v61() + { + return _242323(new _cls23())._113v61(); + } + + public String toString() + { + return _51v61().toString(); + } + + _cls74 _309v74() + { + return m_31074; + } + + _cls4 _65I4(int i) + { + return m_54a4[i]; + } + + void _67I4V(int i, _cls4 _pcls4) + { + m_54a4[i] = _pcls4; + } + + public void _2vV() + { + if(m_31074 instanceof _cls52) + { + _cls52 _lcls52 = (_cls52)m_31074; + _cls2 _lcls2 = _lcls52._46v2(); + String s = _lcls2._7vString(); + int j = _lcls52._34vZ() ? 0 : 1; + for(int k = j; k < m_54a4.length; k++) + m_54a4[k] = m_54a4[k]._1String4(_53StringvString(s, k - j)); + + } + for(int i = 0; i < m_54a4.length; i++) + m_54a4[i]._2vV(); + + } + + _cls4 _1String4(String s) + { + if(m_31074 instanceof _cls42) + { + _cls42 _lcls42 = (_cls42)m_31074; + _lcls42._1StringV(s); + } + return this; + } + + _cls4 _311v4() + { + String s; + if(m_31074 instanceof _cls25) + { + String s1 = ((_cls25)m_31074)._299vString(); + if(s1.equals("==")) + s = "!="; + else + if(s1.equals("!=")) + s = "=="; + else + if(s1.equals("<")) + s = ">="; + else + if(s1.equals(">")) + s = "<="; + else + if(s1.equals("<=")) + s = ">"; + else + if(s1.equals(">=")) + s = "<"; + else + if(s1.equals("&&")) + s = "||"; + else + if(s1.equals("||")) + s = "&&"; + else + if(s1.equals("!")) + s = null; + else + s = "!"; + } else + { + s = "!"; + } + if(s == null) + return m_54a4[0]; + if(s.equals("!")) + { + _cls41 _lcls41 = new _cls41(_155vI(), 0, "Z", "!"); + _cls4 a_lcls4[] = { + this + }; + return new _cls4(_lcls41, a_lcls4); + } + m_31074 = new _cls34(0, 0, "Z", s); + if(s.equals("&&") || s.equals("||")) + { + for(int i = 0; i < m_54a4.length; i++) + m_54a4[i] = m_54a4[i]._311v4(); + + } + return this; + } + + _cls61 _69v61() + { + return null; + } + + boolean _6861Z(_cls61 _pcls61) + { + if(toString().equals(_pcls61.toString())) + return true; + for(int i = 0; i < m_54a4.length; i++) + if(m_54a4[i]._6861Z(_pcls61)) + return true; + + return false; + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_cls75._50IString(i) + "expression " + this); + } +} diff --git a/src/modules/mocha/_cls40.java b/src/modules/mocha/_cls40.java new file mode 100644 index 0000000..918406c --- /dev/null +++ b/src/modules/mocha/_cls40.java @@ -0,0 +1,40 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls46, _cls27, _cls25, +// _cls42, _cls18, _cls52, _cls35, +// _cls53, _cls43, _cls20, _cls14, +// _cls26, _cls36, _cls48, _cls45, +// _cls13, _cls54, _cls38, _cls50, +// _cls28, _cls41, _cls9, _cls16, +// _cls34, _cls44, _cls17, _cls37, +// _cls19, _cls11, _cls8, _cls51, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10, _cls23 + +class _cls40 extends _cls31 +{ + + _cls40(int i, int j) + { + super(i, j); + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23; + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("nop"); + } +} diff --git a/src/modules/mocha/_cls41.java b/src/modules/mocha/_cls41.java new file mode 100644 index 0000000..dfb9b0d --- /dev/null +++ b/src/modules/mocha/_cls41.java @@ -0,0 +1,46 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls25, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls36, +// _cls32, _cls24, _cls14, _cls56, +// _cls20, _cls52, _cls26, _cls23, +// _cls27, _cls33, _cls35, _cls40, +// _cls19, _cls49, _cls47, _cls38, +// _cls31, _cls30, _cls37, _cls54, +// _cls39, _cls48, _cls11, _cls46, +// _cls28, _cls12, _cls53, _cls50, +// _cls10, _cls55, _cls8, _cls22, +// _cls17, _cls13, _cls51, _cls45, +// _cls21, _cls9, _cls18, _cls43 + +class _cls41 extends _cls25 +{ + + _cls41(int i, int j, String s, String s1) + { + super(i, j, s, s1); + } + + public int _22vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + _cls61 _lcls61 = _pcls23._113v61(); + return _pcls23._29v23()._716123(new _cls56(super.m_44String, _lcls61, super.m_32String, 24)); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("unary " + super.m_32String); + } +} diff --git a/src/modules/mocha/_cls42.java b/src/modules/mocha/_cls42.java new file mode 100644 index 0000000..cfc6967 --- /dev/null +++ b/src/modules/mocha/_cls42.java @@ -0,0 +1,133 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls15, _cls34, _cls29, +// _cls16, _cls44, _cls41, _cls36, +// _cls32, _cls24, _cls14, _cls20, +// _cls52, _cls26, _cls25, _cls23, +// _cls27, _cls33, _cls35, _cls40, +// _cls19, _cls49, _cls47, _cls38, +// _cls30, _cls37, _cls54, _cls39, +// _cls48, _cls11, _cls46, _cls28, +// _cls12, _cls53, _cls50, _cls10, +// _cls55, _cls8, _cls22, _cls17, +// _cls13, _cls51, _cls45, _cls21, +// _cls9, _cls18, _cls43, _cls69 + +class _cls42 extends _cls31 +{ + + protected String m_44String; + protected String m_275String; + + _cls42(int i, int j, String s, String s1) + { + super(i, j); + m_44String = s; + m_275String = s1; + } + + public int _117vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._716123(new _cls69(m_44String, m_275String)); + } + + public void _1StringV(String s) + { + if(s.equals("Z")) + { + if(m_275String.equals("0")) + { + m_275String = "false"; + return; + } + if(m_275String.equals("1")) + { + m_275String = "true"; + return; + } + } else + if(s.equals("C")) + try + { + StringBuffer stringbuffer = new StringBuffer(); + stringbuffer.append('\''); + int i = Integer.parseInt(m_275String); + switch(i) + { + case 0: // '\0' + stringbuffer.append("\\0"); + break; + + case 8: // '\b' + stringbuffer.append("\\b"); + break; + + case 9: // '\t' + stringbuffer.append("\\t"); + break; + + case 10: // '\n' + stringbuffer.append("\\n"); + break; + + case 12: // '\f' + stringbuffer.append("\\f"); + break; + + case 13: // '\r' + stringbuffer.append("\\r"); + break; + + case 39: // '\'' + stringbuffer.append("\\'"); + break; + + case 92: // '\\' + stringbuffer.append("\\\\"); + break; + + default: + if(i < 32) + { + String s1; + for(s1 = Integer.toString(i, 8); s1.length() < 3; s1 = "0" + s1); + stringbuffer.append("\\" + s1); + break; + } + if(i < 127) + { + stringbuffer.append((char)i); + break; + } + String s2; + for(s2 = Integer.toString(i, 16); s2.length() < 4; s2 = "0" + s2); + stringbuffer.append("\\u" + s2); + break; + } + stringbuffer.append('\''); + m_275String = stringbuffer.toString(); + return; + } + catch(NumberFormatException _ex) + { + return; + } + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("push " + m_275String); + } +} diff --git a/src/modules/mocha/_cls43.java b/src/modules/mocha/_cls43.java new file mode 100644 index 0000000..ec818d1 --- /dev/null +++ b/src/modules/mocha/_cls43.java @@ -0,0 +1,45 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls55, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls26, _cls25, +// _cls23, _cls27, _cls33, _cls35, +// _cls40, _cls19, _cls49, _cls47, +// _cls38, _cls31, _cls30, _cls37, +// _cls54, _cls39, _cls48, _cls11, +// _cls46, _cls28, _cls12, _cls53, +// _cls50, _cls10, _cls8, _cls22, +// _cls17, _cls13, _cls51, _cls45, +// _cls21, _cls9, _cls18 + +class _cls43 extends _cls55 +{ + + _cls43(int i, int j, String s, int k) + { + super(i, j, s, k); + } + + public int _22vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._29v23(); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("if " + super.m_32String + " null goto " + super.m_27I); + } +} diff --git a/src/modules/mocha/_cls44.java b/src/modules/mocha/_cls44.java new file mode 100644 index 0000000..d6cf16d --- /dev/null +++ b/src/modules/mocha/_cls44.java @@ -0,0 +1,34 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls52, _cls46, _cls27, _cls25, +// _cls31, _cls42, _cls18, _cls35, +// _cls53, _cls43, _cls20, _cls14, +// _cls26, _cls36, _cls48, _cls45, +// _cls13, _cls54, _cls38, _cls50, +// _cls28, _cls41, _cls9, _cls16, +// _cls34, _cls17, _cls37, _cls19, +// _cls11, _cls8, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10 + +class _cls44 extends _cls52 +{ + + _cls44(int i, int j, int k) + { + super(i, j, k); + } + + boolean _34vZ() + { + return true; + } +} diff --git a/src/modules/mocha/_cls45.java b/src/modules/mocha/_cls45.java new file mode 100644 index 0000000..c181962 --- /dev/null +++ b/src/modules/mocha/_cls45.java @@ -0,0 +1,52 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls46, _cls27, _cls25, +// _cls42, _cls18, _cls52, _cls35, +// _cls53, _cls43, _cls20, _cls14, +// _cls26, _cls36, _cls48, _cls13, +// _cls54, _cls38, _cls50, _cls28, +// _cls41, _cls9, _cls16, _cls34, +// _cls44, _cls17, _cls37, _cls19, +// _cls11, _cls8, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls23, +// _cls29, _cls32, _cls10 + +class _cls45 extends _cls31 +{ + + _cls45(int i, int j) + { + super(i, j); + } + + public int _22vI() + { + return 2; + } + + public int _117vI() + { + return 2; + } + + public _cls23 _242323(_cls23 _pcls23) + { + _cls61 _lcls61 = _pcls23._113I61(0); + _cls61 _lcls61_1 = _pcls23._113I61(1); + return _pcls23._29I23(2)._716123(_lcls61)._716123(_lcls61_1); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("swap"); + } +} diff --git a/src/modules/mocha/_cls46.java b/src/modules/mocha/_cls46.java new file mode 100644 index 0000000..3cd34b9 --- /dev/null +++ b/src/modules/mocha/_cls46.java @@ -0,0 +1,90 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls26, _cls25, +// _cls23, _cls27, _cls33, _cls35, +// _cls40, _cls19, _cls49, _cls47, +// _cls61, _cls38, _cls30, _cls37, +// _cls54, _cls39, _cls48, _cls11, +// _cls28, _cls12, _cls53, _cls50, +// _cls10, _cls55, _cls8, _cls22, +// _cls17, _cls13, _cls51, _cls45, +// _cls21, _cls9, _cls18, _cls43 + +class _cls46 extends _cls31 +{ + + protected int m_316I; + protected int m_315I; + + _cls46(int i, int j, int k) + { + super(i, j); + m_316I = k; + m_315I = 1; + } + + public int _22vI() + { + return m_316I + m_315I; + } + + public int _117vI() + { + return m_316I + 2 * m_315I; + } + + int _317vI() + { + return m_316I; + } + + public _cls23 _242323(_cls23 _pcls23) + { + _cls23 _lcls23 = _pcls23; + _cls61 a_lcls61[] = new _cls61[m_315I]; + int i; + int j; + for(i = j = 0; j < m_315I; i++) + { + a_lcls61[i] = _lcls23._113v61(); + j += a_lcls61[i]._42vI(); + _lcls23 = _lcls23._29v23(); + } + + _cls61 a_lcls61_1[] = new _cls61[m_316I]; + int k; + int l; + for(k = l = 0; l < m_316I; k++) + { + a_lcls61_1[k] = _lcls23._113v61(); + l += a_lcls61_1[k]._42vI(); + _lcls23 = _lcls23._29v23(); + } + + for(int i1 = i; i1 > 0;) + _lcls23 = _lcls23._716123(a_lcls61[--i1]); + + for(int j1 = k; j1 > 0;) + _lcls23 = _lcls23._716123(a_lcls61_1[--j1]); + + for(int k1 = i; k1 > 0;) + _lcls23 = _lcls23._716123(a_lcls61[--k1]); + + return _lcls23; + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("dup " + m_315I + " over " + m_316I); + } +} diff --git a/src/modules/mocha/_cls47.java b/src/modules/mocha/_cls47.java new file mode 100644 index 0000000..a3db20f --- /dev/null +++ b/src/modules/mocha/_cls47.java @@ -0,0 +1,80 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls26, _cls25, +// _cls23, _cls27, _cls33, _cls35, +// _cls40, _cls19, _cls49, _cls38, +// _cls30, _cls37, _cls54, _cls39, +// _cls48, _cls11, _cls46, _cls28, +// _cls12, _cls53, _cls50, _cls10, +// _cls55, _cls8, _cls22, _cls17, +// _cls13, _cls51, _cls45, _cls21, +// _cls9, _cls18, _cls43 + +abstract class _cls47 extends _cls31 +{ + + protected int m_28I; + protected int m_27aI[]; + + _cls47(int i, int j) + { + super(i, j); + } + + public int _25vI() + { + return 1 + m_27aI.length; + } + + public int _26II(int i) + { + if(i == 0) + return m_28I; + else + return m_27aI[i - 1]; + } + + public void _21IIV(int i, int j) + { + if(i == 0) + { + m_28I = j; + return; + } else + { + m_27aI[i - 1] = j; + return; + } + } + + public int _22vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._29v23(); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("switch"); + for(int i = 0; i < m_27aI.length; i++) + printstream.println("case " + _23II(i + 1) + ": goto " + m_27aI[i]); + + printstream.println("default: goto " + m_28I); + } + + abstract int _23II(int i); +} diff --git a/src/modules/mocha/_cls48.java b/src/modules/mocha/_cls48.java new file mode 100644 index 0000000..136dffa --- /dev/null +++ b/src/modules/mocha/_cls48.java @@ -0,0 +1,71 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls55, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls26, _cls25, +// _cls23, _cls27, _cls33, _cls35, +// _cls40, _cls19, _cls71, _cls49, +// _cls47, _cls61, _cls38, _cls31, +// _cls30, _cls37, _cls54, _cls39, +// _cls11, _cls46, _cls28, _cls12, +// _cls53, _cls50, _cls10, _cls8, +// _cls22, _cls17, _cls13, _cls51, +// _cls45, _cls21, _cls9, _cls18, +// _cls43, _cls103 + +class _cls48 extends _cls55 +{ + + protected String m_44String; + + _cls48(int i, int j, String s, String s1, int k) + { + super(i, j, s1, k); + m_44String = s; + } + + public int _22vI() + { + return 2; + } + + public void _10723V(_cls23 _pcls23, _cls103 _pcls103) + { + if(super.m_10523 == null) + { + if(super.m_32String.equals("==") || super.m_32String.equals("!=")) + { + String s = _pcls23._113I61(0)._43vString(); + String s1 = _pcls23._113I61(1)._43vString(); + if(!s.equals("Z") && s1.equals("Z")) + super.m_11271._18661vV(_pcls23._113I61(1), super.m_110I); + else + if(s.equals("Z") && !s1.equals("Z")) + super.m_11271._18661vV(_pcls23._113I61(0), super.m_110I); + } else + { + super.m_11271._18661vV(_pcls23._113I61(0), super.m_110I); + super.m_11271._18661vV(_pcls23._113I61(1), super.m_110I); + } + super._10723V(_pcls23, _pcls103); + } + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._29I23(2); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("compare and if " + super.m_32String + " goto " + super.m_27I); + } +} diff --git a/src/modules/mocha/_cls49.java b/src/modules/mocha/_cls49.java new file mode 100644 index 0000000..a13ec0f --- /dev/null +++ b/src/modules/mocha/_cls49.java @@ -0,0 +1,85 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls54, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls2, _cls67, +// _cls26, _cls25, _cls23, _cls27, +// _cls33, _cls63, _cls4, _cls35, +// _cls40, _cls19, _cls47, _cls38, +// _cls31, _cls30, _cls37, _cls39, +// _cls7, _cls48, _cls11, _cls46, +// _cls28, _cls12, _cls0, _cls53, +// _cls50, _cls10, _cls55, _cls8, +// _cls22, _cls17, _cls13, _cls51, +// _cls45, _cls21, _cls9, _cls18, +// _cls69, _cls43, _cls71, _cls61 + +class _cls49 extends _cls54 +{ + + protected int m_115I; + protected boolean m_34Z; + protected _cls0 m_160; + protected _cls71 m_11271; + + _cls49(int i, int j, int k, boolean flag) + { + super(i, j); + m_115I = k; + m_34Z = flag; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_160 = _pcls0; + m_11271 = _pcls71; + } + + public int _22vI() + { + return !m_34Z ? 2 : 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._29I23(m_34Z ? 1 : 2); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("pop " + m_160._9I2(m_115I)); + } + + _cls7 _66v7() + { + _cls2 _lcls2 = m_160._9I2(m_115I); + _cls7 _lcls7 = m_160._15027(_lcls2); + if(_lcls7 != null && _lcls7._3vZ()) + return _lcls7; + else + return null; + } + + _cls61 _69a461(_cls4 a_pcls4[]) + { + _cls2 _lcls2 = m_160._9I2(m_115I); + _cls69 _lcls69 = new _cls69(_lcls2._81vString(), _lcls2._18vString()); + if(m_34Z) + return new _cls63(_lcls2._56v2(), _lcls69, m_160, m_11271, super.m_110I); + else + return new _cls67(a_pcls4[0]._51v61(), _lcls69, m_11271, super.m_110I); + } + + public void _19vV() + { + m_115I = m_160._19IStringI(m_115I, "member"); + } +} diff --git a/src/modules/mocha/_cls5.java b/src/modules/mocha/_cls5.java new file mode 100644 index 0000000..b41ad35 --- /dev/null +++ b/src/modules/mocha/_cls5.java @@ -0,0 +1,259 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls71, _cls0, _cls125, _cls128, +// _cls2 + +class _cls5 +{ + + _cls0 m_160; + _cls71 m_23271; + String m_97String; + String m_230String; + int m_234I; + private static final String m_233aString[] = { + "W", "Z", "Y", "B", "C", "S", "I", "J", "F", "D" + }; + private static final int m_228aaI[][] = { + { + 0 + }, { + 1, 1 + }, { + 2, 2, 2 + }, { + 3, 3, 3, 3 + }, { + 4, 4, 4, 4, 4 + }, { + 5, 5, 5, 5, 6, 5 + }, { + 6, 6, 6, 6, 6, 6, 6 + }, { + 7, 7, 7, 7, 7, 7, 7, 7 + }, { + 8, 8, 8, 8, 8, 8, 8, 8, 8 + }, { + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 + } + }; + + _cls5(String s, String s1, _cls0 _pcls0) + { + m_160 = _pcls0; + m_97String = s; + m_230String = s1; + } + + _cls5(_cls2 _pcls2, _cls2 _pcls2_1, _cls0 _pcls0, _cls71 _pcls71) + { + this(_pcls2.toString(), _pcls2_1.toString(), _pcls0); + m_23271 = _pcls71; + } + + _cls5(_cls2 _pcls2, _cls2 _pcls2_1, _cls0 _pcls0) + { + this(_pcls2, _pcls2_1, _pcls0, null); + } + + String _229StringString(String s) + throws _cls128 + { + String s1 = ""; + StringBuffer stringbuffer = new StringBuffer(); + String s2 = ""; + switch(m_230String.charAt(m_234I++)) + { + case 66: // 'B' + s1 = "byte"; + break; + + case 67: // 'C' + s1 = "char"; + break; + + case 68: // 'D' + s1 = "double"; + break; + + case 70: // 'F' + s1 = "float"; + break; + + case 73: // 'I' + s1 = "int"; + break; + + case 74: // 'J' + s1 = "long"; + break; + + case 83: // 'S' + s1 = "short"; + break; + + case 86: // 'V' + s1 = "void"; + break; + + case 87: // 'W' + s1 = "int?"; + break; + + case 89: // 'Y' + s1 = "int?"; + break; + + case 90: // 'Z' + s1 = "boolean"; + break; + + case 76: // 'L' + int i; + for(i = m_234I; m_230String.charAt(i) != ';'; i++); + s1 = m_230String.substring(m_234I, i); + s1 = m_160._101StringString(s1); + m_234I = i + 1; + break; + + case 91: // '[' + m_234I--; + do + { + int j; + for(j = ++m_234I; m_230String.charAt(j) >= '0' && m_230String.charAt(j) <= '9'; j++); + s2 = s2 + "[" + m_230String.substring(m_234I, j) + "]"; + m_234I = j; + } while(m_230String.charAt(m_234I) == '['); + s1 = _229StringString(null); + break; + + case 40: // '(' + stringbuffer.append("("); + int k = 0; + String s3; + for(; m_230String.charAt(m_234I) != ')'; stringbuffer.append(_229StringString(s3))) + { + if(stringbuffer.length() > 1) + stringbuffer.append(", "); + s3 = null; + if(m_23271 != null) + s3 = m_23271._231I125(k++).toString(); + } + + stringbuffer.append(")"); + m_234I++; + s1 = _229StringString(null); + break; + + case 60: // '<' + s1 = ""; + break; + + default: + throw new _cls128("Invalid signature " + m_230String); + } + if(s != null) + { + if(s.equals("")) + s1 = m_160._76v2().toString() + stringbuffer; + else + if(s.equals("")) + s1 = ""; + else + if(stringbuffer.length() > 0) + s1 = s1 + s2 + " " + s + stringbuffer; + else + s1 = s1 + " " + s + s2; + } else + { + s1 = s1 + s2; + } + return s1; + } + + public String toString() + { + try + { + m_234I = 0; + return _229StringString(m_97String); + } + catch(_cls128 _ex) + { + return ""; + } + } + + static String _227StringString(String s, String s1) + { + String s2 = s; + String s3 = s1; + int i; + for(i = 0; s2.charAt(0) == '['; i++) + s2 = s2.substring(1); + + int j; + for(j = 0; s3.charAt(0) == '['; j++) + s3 = s3.substring(1); + + if(s2.equals("A") && j > 0) + return s1; + if(s3.equals("A") && i > 0) + return s; + if(i != j) + return ""; + if(s2.equals(s3)) + return s; + if(s2.startsWith("<")) + return s1; + if(s3.startsWith("<")) + return s; + int k = -1; + for(int l = 0; k < 0 && l < m_233aString.length; l++) + if(m_233aString[l].equals(s2)) + k = l; + + int i1 = -1; + for(int j1 = 0; i1 < 0 && j1 < m_233aString.length; j1++) + if(m_233aString[j1].equals(s3)) + i1 = j1; + + if(k < i1) + { + int k1 = k; + k = i1; + i1 = k1; + } + if(i1 >= 0) + { + if(i > 0) + return ""; + int l1 = m_228aaI[k][i1]; + String s4 = l1 >= 0 ? m_233aString[l1] : ""; + for(int i2 = 0; i2 < i; i2++) + s4 = "[" + s4; + + return s4; + } + if(k >= 0) + return ""; + if(!s2.equals("A") && !s2.startsWith("L")) + return ""; + if(!s3.equals("A") && !s3.startsWith("L")) + return ""; + if(s2.equals("A")) + return s1; + if(s3.equals("A")) + return s; + else + return "Ljava/lang/Object;"; + } + +} diff --git a/src/modules/mocha/_cls50.java b/src/modules/mocha/_cls50.java new file mode 100644 index 0000000..82f936a --- /dev/null +++ b/src/modules/mocha/_cls50.java @@ -0,0 +1,56 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls54, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls52, _cls26, _cls65, +// _cls25, _cls23, _cls27, _cls33, +// _cls4, _cls35, _cls40, _cls19, +// _cls49, _cls47, _cls38, _cls31, +// _cls30, _cls37, _cls39, _cls48, +// _cls11, _cls46, _cls28, _cls12, +// _cls53, _cls10, _cls55, _cls8, +// _cls22, _cls17, _cls13, _cls51, +// _cls45, _cls21, _cls9, _cls18, +// _cls43, _cls61 + +class _cls50 extends _cls54 +{ + + protected String m_44String; + + _cls50(int i, int j, String s) + { + super(i, j); + m_44String = s; + } + + public int _22vI() + { + return 3; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._29I23(3); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("pop []"); + } + + _cls61 _69a461(_cls4 a_pcls4[]) + { + _cls61 _lcls61 = a_pcls4[0]._51v61(); + _cls61 _lcls61_1 = a_pcls4[1]._51v61(); + return new _cls65(m_44String, _lcls61, _lcls61_1); + } +} diff --git a/src/modules/mocha/_cls51.java b/src/modules/mocha/_cls51.java new file mode 100644 index 0000000..2c025e2 --- /dev/null +++ b/src/modules/mocha/_cls51.java @@ -0,0 +1,50 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls38, _cls46, _cls27, _cls25, +// _cls31, _cls42, _cls18, _cls52, +// _cls35, _cls53, _cls43, _cls20, +// _cls14, _cls26, _cls36, _cls48, +// _cls45, _cls13, _cls54, _cls50, +// _cls28, _cls41, _cls9, _cls16, +// _cls34, _cls44, _cls17, _cls37, +// _cls19, _cls11, _cls8, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10, _cls23 + +class _cls51 extends _cls38 +{ + + _cls51(int i, int j, int k) + { + super(i, j, k); + } + + public int _26II(int i) + { + return super.m_27I; + } + + public void _21IIV(int i, int j) + { + super.m_27I = j; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23; + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("goto " + super.m_27I); + } +} diff --git a/src/modules/mocha/_cls52.java b/src/modules/mocha/_cls52.java new file mode 100644 index 0000000..c5dc9c6 --- /dev/null +++ b/src/modules/mocha/_cls52.java @@ -0,0 +1,162 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls15, _cls34, _cls29, +// _cls42, _cls16, _cls44, _cls41, +// _cls36, _cls32, _cls24, _cls14, +// _cls20, _cls2, _cls67, _cls26, +// _cls25, _cls23, _cls27, _cls33, +// _cls63, _cls35, _cls40, _cls19, +// _cls49, _cls47, _cls61, _cls38, +// _cls30, _cls37, _cls54, _cls39, +// _cls48, _cls11, _cls46, _cls68, +// _cls28, _cls12, _cls59, _cls0, +// _cls53, _cls50, _cls10, _cls55, +// _cls8, _cls22, _cls17, _cls13, +// _cls51, _cls45, _cls21, _cls9, +// _cls18, _cls43, _cls71 + +class _cls52 extends _cls31 +{ + + protected int m_75I; + protected _cls0 m_160; + protected _cls71 m_11271; + + _cls52(int i, int j, int k) + { + super(i, j); + m_75I = k; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_160 = _pcls0; + m_11271 = _pcls71; + } + + public int _22vI() + { + _cls2 _lcls2 = m_160._9I2(m_75I); + String s = _lcls2._7vString(); + int i = 0; + int j = 0; + for(char c = s.charAt(++j); c != ')'; c = s.charAt(++j)) + { + if(c != '[') + i++; + if(c == 'L') + for(c = s.charAt(++j); c != ';'; c = s.charAt(++j)); + } + + if(!_34vZ()) + i++; + return i; + } + + public int _117vI() + { + return !_302vString().equals("V") ? 1 : 0; + } + + private String _302vString() + { + _cls2 _lcls2 = m_160._9I2(m_75I); + String s = _lcls2._7vString(); + return s.substring(s.indexOf(')') + 1); + } + + public _cls23 _242323(_cls23 _pcls23) + { + Object obj = null; + if(_117vI() > 0) + { + int i = _34vZ() ? _22vI() : _22vI() - 1; + _cls61 a_lcls61[] = new _cls61[i]; + for(int j = 0; j < i; j++) + a_lcls61[j] = _pcls23._113I61(i - 1 - j); + + _cls2 _lcls2 = m_160._9I2(m_75I); + _cls68 _lcls68 = new _cls68(_302vString(), _lcls2._18vString(), a_lcls61); + if(_34vZ()) + obj = new _cls63(_lcls2._56v2(), _lcls68, m_160, m_11271, super.m_110I); + else + if(_7361Z(_pcls23._113I61(i))) + obj = new _cls59(_lcls68); + else + obj = new _cls67(_pcls23._113I61(i), _lcls68, m_11271, super.m_110I); + } + return _pcls23._29I23(_22vI())._716123(((_cls61) (obj))); + } + + _cls61 _452361(_cls23 _pcls23) + { + if(_117vI() > 0) + return null; + int i = _34vZ() ? _22vI() : _22vI() - 1; + _cls61 a_lcls61[] = new _cls61[i]; + for(int j = 0; j < i; j++) + a_lcls61[j] = _pcls23._113I61(i - 1 - j); + + _cls2 _lcls2 = m_160._9I2(m_75I); + String s = _lcls2._18vString(); + boolean flag = _7361Z(_pcls23._113I61(i)); + if(_74vZ()) + { + if(_7761Z(_pcls23._113I61(i))) + s = "this"; + else + if(flag) + s = "super"; + flag = false; + } + _cls68 _lcls68 = new _cls68(_302vString(), s, a_lcls61); + if(_34vZ()) + return new _cls63(_lcls2._56v2(), _lcls68, m_160, m_11271, super.m_110I); + if(flag) + return new _cls59(_lcls68); + else + return new _cls67(_pcls23._113I61(i), _lcls68, m_11271, super.m_110I); + } + + boolean _74vZ() + { + return false; + } + + boolean _7361Z(_cls61 _pcls61) + { + return false; + } + + boolean _7761Z(_cls61 _pcls61) + { + return false; + } + + boolean _34vZ() + { + return false; + } + + _cls2 _46v2() + { + return m_160._9I2(m_75I); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("invoke " + m_160._9I2(m_75I)); + } + + public void _19vV() + { + m_75I = m_160._19IStringI(m_75I, "member"); + } +} diff --git a/src/modules/mocha/_cls53.java b/src/modules/mocha/_cls53.java new file mode 100644 index 0000000..c1bc4d0 --- /dev/null +++ b/src/modules/mocha/_cls53.java @@ -0,0 +1,52 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.DataInputStream; +import java.io.IOException; + +// Referenced classes of package mocha: +// _cls47, _cls46, _cls27, _cls25, +// _cls31, _cls42, _cls18, _cls52, +// _cls35, _cls43, _cls20, _cls14, +// _cls36, _cls26, _cls48, _cls45, +// _cls13, _cls54, _cls38, _cls50, +// _cls28, _cls41, _cls9, _cls16, +// _cls34, _cls44, _cls17, _cls37, +// _cls19, _cls11, _cls8, _cls51, +// _cls40, _cls22, _cls33, _cls30, +// _cls49, _cls24, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10, _cls3 + +class _cls53 extends _cls47 +{ + + protected int m_280I; + protected int m_279I; + + _cls53(int i, int j, _cls3 _pcls3) + throws IOException + { + super(i, j); + super.m_28I = i + _pcls3.readInt(); + m_280I = _pcls3.readInt(); + m_279I = _pcls3.readInt(); + super.m_27aI = new int[(m_279I - m_280I) + 1]; + for(int k = 0; k < super.m_27aI.length; k++) + super.m_27aI[k] = i + _pcls3.readInt(); + + } + + public int _200vI() + { + return super.m_226I + 4 * (super.m_27aI.length + 3); + } + + int _23II(int i) + { + return (m_280I + i) - 1; + } +} diff --git a/src/modules/mocha/_cls54.java b/src/modules/mocha/_cls54.java new file mode 100644 index 0000000..8dd9347 --- /dev/null +++ b/src/modules/mocha/_cls54.java @@ -0,0 +1,37 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls31, _cls46, _cls27, _cls25, +// _cls42, _cls18, _cls52, _cls35, +// _cls53, _cls43, _cls20, _cls14, +// _cls26, _cls36, _cls48, _cls45, +// _cls13, _cls38, _cls50, _cls28, +// _cls41, _cls9, _cls16, _cls34, +// _cls44, _cls17, _cls37, _cls19, +// _cls11, _cls8, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10, _cls7, _cls4, +// _cls61 + +abstract class _cls54 extends _cls31 +{ + + _cls54(int i, int j) + { + super(i, j); + } + + _cls7 _66v7() + { + return null; + } + + abstract _cls61 _69a461(_cls4 a_pcls4[]); +} diff --git a/src/modules/mocha/_cls55.java b/src/modules/mocha/_cls55.java new file mode 100644 index 0000000..0333327 --- /dev/null +++ b/src/modules/mocha/_cls55.java @@ -0,0 +1,69 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls38, _cls46, _cls27, _cls25, +// _cls31, _cls42, _cls18, _cls52, +// _cls35, _cls53, _cls43, _cls20, +// _cls14, _cls26, _cls36, _cls48, +// _cls45, _cls13, _cls54, _cls50, +// _cls28, _cls41, _cls9, _cls16, +// _cls34, _cls44, _cls17, _cls37, +// _cls19, _cls11, _cls8, _cls51, +// _cls40, _cls22, _cls33, _cls30, +// _cls49, _cls24, _cls47, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10, _cls71, _cls0 + +abstract class _cls55 extends _cls38 +{ + + protected _cls71 m_11271; + protected String m_32String; + + _cls55(int i, int j, String s, int k) + { + super(i, j, k); + m_32String = s; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + m_11271 = _pcls71; + } + + public int _25vI() + { + return 2; + } + + public int _26II(int i) + { + if(i == 0) + return super._26II(i); + else + return super.m_27I; + } + + public void _21IIV(int i, int j) + { + if(i == 0) + { + super._21IIV(i, j); + return; + } else + { + super.m_27I = j; + return; + } + } + + String _259vString() + { + return m_32String; + } +} diff --git a/src/modules/mocha/_cls56.java b/src/modules/mocha/_cls56.java new file mode 100644 index 0000000..73d6fa0 --- /dev/null +++ b/src/modules/mocha/_cls56.java @@ -0,0 +1,31 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls61, _cls68, _cls60, _cls62, +// _cls23, _cls57, _cls69, _cls66, +// _cls65, _cls67, _cls58, _cls59, +// _cls64, _cls63 + +class _cls56 extends _cls61 +{ + + _cls61 m_3161; + String m_32String; + + _cls56(String s, _cls61 _pcls61, String s1, int i) + { + super(s, i); + m_3161 = _pcls61; + m_32String = s1; + } + + public String toString() + { + return m_32String + m_3161._30IString(super.m_33I); + } +} diff --git a/src/modules/mocha/_cls57.java b/src/modules/mocha/_cls57.java new file mode 100644 index 0000000..8fae088 --- /dev/null +++ b/src/modules/mocha/_cls57.java @@ -0,0 +1,26 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls66, _cls60, _cls69, _cls65, +// _cls56, _cls62, _cls68, _cls64, +// _cls59, _cls58, _cls67, _cls23, +// _cls63, _cls61 + +class _cls57 extends _cls66 +{ + + _cls57(String s, _cls61 _pcls61, _cls61 _pcls61_1, String s1, int i) + { + super(s, _pcls61, _pcls61_1, s1, i); + } + + public String toString() + { + return super.m_29461._30IString(super.m_33I) + " " + super.m_32String + " " + super.m_29561._30IString(super.m_33I + 1); + } +} diff --git a/src/modules/mocha/_cls58.java b/src/modules/mocha/_cls58.java new file mode 100644 index 0000000..ae974ce --- /dev/null +++ b/src/modules/mocha/_cls58.java @@ -0,0 +1,39 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls61, _cls60, _cls69, _cls65, +// _cls56, _cls62, _cls68, _cls64, +// _cls57, _cls71, _cls59, _cls66, +// _cls125, _cls67, _cls23, _cls63 + +class _cls58 extends _cls61 +{ + + _cls71 m_11271; + int m_106I; + int m_110I; + + _cls58(_cls71 _pcls71, int i, int j) + { + super("?", 100); + m_11271 = _pcls71; + m_106I = i; + m_110I = j; + super.m_44String = _pcls71._111II125(i, j)._81vString(); + } + + int _92vI() + { + return m_106I; + } + + public String toString() + { + return m_11271._111II125(m_106I, m_110I).toString(); + } +} diff --git a/src/modules/mocha/_cls59.java b/src/modules/mocha/_cls59.java new file mode 100644 index 0000000..0044639 --- /dev/null +++ b/src/modules/mocha/_cls59.java @@ -0,0 +1,29 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls61, _cls68, _cls56, _cls60, +// _cls62, _cls23, _cls57, _cls69, +// _cls66, _cls65, _cls67, _cls58, +// _cls64, _cls63 + +class _cls59 extends _cls61 +{ + + _cls61 m_21561; + + _cls59(_cls61 _pcls61) + { + super(_pcls61._43vString(), 26); + m_21561 = _pcls61; + } + + public String toString() + { + return "super." + m_21561; + } +} diff --git a/src/modules/mocha/_cls6.java b/src/modules/mocha/_cls6.java new file mode 100644 index 0000000..14a3f8f --- /dev/null +++ b/src/modules/mocha/_cls6.java @@ -0,0 +1,109 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.IOException; + +// Referenced classes of package mocha: +// _cls1, _cls3 + +class _cls6 +{ + + int m_165I; + + _cls6(_cls3 _pcls3) + throws IOException + { + m_165I = _pcls3._14vI(); + } + + void _61V(_cls1 _pcls1) + throws IOException + { + _pcls1._4IV(m_165I); + } + + boolean _160vZ() + { + return (m_165I & 1) != 0; + } + + boolean _168vZ() + { + return (m_165I & 2) != 0; + } + + boolean _164vZ() + { + return (m_165I & 4) != 0; + } + + boolean _34vZ() + { + return (m_165I & 8) != 0; + } + + boolean _3vZ() + { + return (m_165I & 0x10) != 0; + } + + boolean _167vZ() + { + return (m_165I & 0x20) != 0; + } + + boolean _162vZ() + { + return (m_165I & 0x40) != 0; + } + + boolean _163vZ() + { + return (m_165I & 0x80) != 0; + } + + boolean _166vZ() + { + return (m_165I & 0x100) != 0; + } + + boolean _126vZ() + { + return (m_165I & 0x200) != 0; + } + + boolean _161vZ() + { + return (m_165I & 0x400) != 0; + } + + public String toString() + { + String s = ""; + if(_160vZ()) + s = s + "public "; + if(_168vZ()) + s = s + "private "; + if(_164vZ()) + s = s + "protected "; + if(_34vZ()) + s = s + "static "; + if(_3vZ()) + s = s + "final "; + if(_167vZ()) + s = s + "synchronized "; + if(_162vZ()) + s = s + "volatile "; + if(_163vZ()) + s = s + "transient "; + if(_166vZ()) + s = s + "native "; + if(_161vZ()) + s = s + "abstract "; + return s; + } +} diff --git a/src/modules/mocha/_cls60.java b/src/modules/mocha/_cls60.java new file mode 100644 index 0000000..9fe1c73 --- /dev/null +++ b/src/modules/mocha/_cls60.java @@ -0,0 +1,26 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls66, _cls69, _cls65, _cls56, +// _cls62, _cls68, _cls64, _cls57, +// _cls59, _cls58, _cls67, _cls23, +// _cls63, _cls61 + +class _cls60 extends _cls66 +{ + + _cls60(String s, _cls61 _pcls61, _cls61 _pcls61_1, String s1, int i) + { + super(s, _pcls61, _pcls61_1, s1, i); + } + + public String toString() + { + return super.m_29461._30IString(super.m_33I + 1) + " " + super.m_32String + " " + super.m_29561._30IString(super.m_33I); + } +} diff --git a/src/modules/mocha/_cls61.java b/src/modules/mocha/_cls61.java new file mode 100644 index 0000000..acf7962 --- /dev/null +++ b/src/modules/mocha/_cls61.java @@ -0,0 +1,45 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls60, _cls69, _cls65, _cls56, +// _cls62, _cls68, _cls64, _cls57, +// _cls59, _cls58, _cls66, _cls67, +// _cls23, _cls63 + +class _cls61 +{ + + protected String m_44String; + protected int m_33I; + + _cls61(String s, int i) + { + m_44String = s; + m_33I = i; + } + + String _43vString() + { + return m_44String; + } + + int _42vI() + { + if(m_44String.equals("J")) + return 2; + return !m_44String.equals("D") ? 1 : 2; + } + + String _30IString(int i) + { + if(i > m_33I) + return "(" + toString() + ")"; + else + return toString(); + } +} diff --git a/src/modules/mocha/_cls62.java b/src/modules/mocha/_cls62.java new file mode 100644 index 0000000..18b25ed --- /dev/null +++ b/src/modules/mocha/_cls62.java @@ -0,0 +1,31 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls61, _cls68, _cls56, _cls60, +// _cls23, _cls57, _cls69, _cls66, +// _cls65, _cls67, _cls58, _cls59, +// _cls64, _cls63 + +class _cls62 extends _cls61 +{ + + _cls61 m_3161; + String m_32String; + + _cls62(String s, _cls61 _pcls61, String s1, int i) + { + super(s, i); + m_3161 = _pcls61; + m_32String = s1; + } + + public String toString() + { + return m_3161._30IString(super.m_33I) + m_32String; + } +} diff --git a/src/modules/mocha/_cls63.java b/src/modules/mocha/_cls63.java new file mode 100644 index 0000000..184ee30 --- /dev/null +++ b/src/modules/mocha/_cls63.java @@ -0,0 +1,65 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.util.Enumeration; + +// Referenced classes of package mocha: +// _cls61, _cls60, _cls69, _cls65, +// _cls56, _cls62, _cls68, _cls64, +// _cls57, _cls0, _cls71, _cls59, +// _cls58, _cls66, _cls125, _cls67, +// _cls23, _cls2 + +class _cls63 extends _cls61 +{ + + _cls2 m_1532; + _cls61 m_21561; + _cls0 m_160; + _cls71 m_11271; + int m_110I; + + _cls63(_cls2 _pcls2, _cls61 _pcls61, _cls0 _pcls0, _cls71 _pcls71, int i) + { + super(_pcls61._43vString(), 26); + m_1532 = _pcls2; + m_21561 = _pcls61; + m_160 = _pcls0; + m_11271 = _pcls71; + m_110I = i; + if(_216vZ()) + super.m_33I = 100; + } + + boolean _216vZ() + { + boolean flag = false; + if(m_1532 == m_160._76v2()) + { + flag = true; + if(m_11271 != null) + { + String s = m_21561.toString(); + for(Enumeration enumeration = m_11271._35IEnumeration(m_110I); enumeration.hasMoreElements() && flag;) + { + _cls125 _lcls125 = (_cls125)enumeration.nextElement(); + if(_lcls125._96IZ(m_110I) && _lcls125._18vObject().equals(s)) + flag = false; + } + + } + } + return flag; + } + + public String toString() + { + if(_216vZ()) + return m_21561.toString(); + else + return m_160._101StringString(m_1532.toString()) + "." + m_21561; + } +} diff --git a/src/modules/mocha/_cls64.java b/src/modules/mocha/_cls64.java new file mode 100644 index 0000000..71ef87d --- /dev/null +++ b/src/modules/mocha/_cls64.java @@ -0,0 +1,37 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls61, _cls60, _cls69, _cls65, +// _cls56, _cls62, _cls68, _cls57, +// _cls59, _cls58, _cls66, _cls67, +// _cls23, _cls63 + +class _cls64 extends _cls61 +{ + + _cls61 m_29461; + _cls61 m_34761; + _cls61 m_29561; + String m_349String; + String m_348String; + + _cls64(String s, _cls61 _pcls61, _cls61 _pcls61_1, _cls61 _pcls61_2, String s1, String s2, int i) + { + super(s, i); + m_29461 = _pcls61; + m_34761 = _pcls61_1; + m_29561 = _pcls61_2; + m_349String = s1; + m_348String = s2; + } + + public String toString() + { + return m_29461._30IString(23) + " " + m_349String + " " + m_34761._30IString(23) + " " + m_348String + " " + m_29561._30IString(23); + } +} diff --git a/src/modules/mocha/_cls65.java b/src/modules/mocha/_cls65.java new file mode 100644 index 0000000..5be9f47 --- /dev/null +++ b/src/modules/mocha/_cls65.java @@ -0,0 +1,31 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls61, _cls60, _cls69, _cls56, +// _cls62, _cls68, _cls64, _cls57, +// _cls59, _cls58, _cls66, _cls67, +// _cls23, _cls63 + +class _cls65 extends _cls61 +{ + + _cls61 m_29861; + _cls61 m_22061; + + _cls65(String s, _cls61 _pcls61, _cls61 _pcls61_1) + { + super(s, 26); + m_29861 = _pcls61; + m_22061 = _pcls61_1; + } + + public String toString() + { + return m_29861._30IString(super.m_33I) + "[" + m_22061 + "]"; + } +} diff --git a/src/modules/mocha/_cls66.java b/src/modules/mocha/_cls66.java new file mode 100644 index 0000000..f8f360e --- /dev/null +++ b/src/modules/mocha/_cls66.java @@ -0,0 +1,33 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls61, _cls60, _cls69, _cls65, +// _cls56, _cls62, _cls68, _cls64, +// _cls57, _cls59, _cls58, _cls67, +// _cls23, _cls63 + +class _cls66 extends _cls61 +{ + + _cls61 m_29461; + _cls61 m_29561; + String m_32String; + + _cls66(String s, _cls61 _pcls61, _cls61 _pcls61_1, String s1, int i) + { + super(s, i); + m_29461 = _pcls61; + m_29561 = _pcls61_1; + m_32String = s1; + } + + public String toString() + { + return m_29461._30IString(super.m_33I) + " " + m_32String + " " + m_29561._30IString(super.m_33I); + } +} diff --git a/src/modules/mocha/_cls67.java b/src/modules/mocha/_cls67.java new file mode 100644 index 0000000..4837703 --- /dev/null +++ b/src/modules/mocha/_cls67.java @@ -0,0 +1,62 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.util.Enumeration; + +// Referenced classes of package mocha: +// _cls61, _cls60, _cls69, _cls65, +// _cls56, _cls62, _cls68, _cls64, +// _cls57, _cls71, _cls59, _cls58, +// _cls66, _cls125, _cls23, _cls63 + +class _cls67 extends _cls61 +{ + + _cls61 m_21761; + _cls61 m_21561; + _cls71 m_11271; + int m_110I; + + _cls67(_cls61 _pcls61, _cls61 _pcls61_1, _cls71 _pcls71, int i) + { + super(_pcls61_1._43vString(), 26); + m_21761 = _pcls61; + m_21561 = _pcls61_1; + m_11271 = _pcls71; + m_110I = i; + if(_216vZ()) + super.m_33I = 100; + } + + boolean _216vZ() + { + boolean flag = false; + if(m_21761.toString().equals("this")) + { + flag = true; + if(m_11271 != null) + { + String s = m_21561.toString(); + for(Enumeration enumeration = m_11271._35IEnumeration(m_110I); enumeration.hasMoreElements() && flag;) + { + _cls125 _lcls125 = (_cls125)enumeration.nextElement(); + if(_lcls125._18vObject().toString().equals(s)) + flag = false; + } + + } + } + return flag; + } + + public String toString() + { + if(_216vZ()) + return m_21561.toString(); + else + return m_21761._30IString(super.m_33I) + "." + m_21561; + } +} diff --git a/src/modules/mocha/_cls68.java b/src/modules/mocha/_cls68.java new file mode 100644 index 0000000..f585107 --- /dev/null +++ b/src/modules/mocha/_cls68.java @@ -0,0 +1,40 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls61, _cls60, _cls69, _cls65, +// _cls56, _cls62, _cls64, _cls57, +// _cls59, _cls58, _cls66, _cls67, +// _cls23, _cls63 + +class _cls68 extends _cls61 +{ + + String m_292String; + _cls61 m_293a61[]; + + _cls68(String s, String s1, _cls61 a_pcls61[]) + { + super(s, 90); + m_292String = s1; + m_293a61 = a_pcls61; + } + + public String toString() + { + String s = m_292String + "("; + for(int i = 0; i < m_293a61.length; i++) + { + if(i > 0) + s = s + ", "; + s = s + m_293a61[i]; + } + + s = s + ")"; + return s; + } +} diff --git a/src/modules/mocha/_cls69.java b/src/modules/mocha/_cls69.java new file mode 100644 index 0000000..69931b3 --- /dev/null +++ b/src/modules/mocha/_cls69.java @@ -0,0 +1,29 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls61, _cls68, _cls56, _cls60, +// _cls62, _cls23, _cls57, _cls66, +// _cls65, _cls67, _cls58, _cls59, +// _cls64, _cls63 + +class _cls69 extends _cls61 +{ + + String m_326String; + + _cls69(String s, String s1) + { + super(s, 100); + m_326String = s1; + } + + public String toString() + { + return m_326String; + } +} diff --git a/src/modules/mocha/_cls7.java b/src/modules/mocha/_cls7.java new file mode 100644 index 0000000..d5af8b9 --- /dev/null +++ b/src/modules/mocha/_cls7.java @@ -0,0 +1,117 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// _cls1, _cls2, _cls4, _cls5, +// _cls6, _cls3, _cls0 + +class _cls7 +{ + + _cls0 m_160; + _cls6 m_06; + _cls2 m_132; + _cls2 m_102; + _cls2 m_152; + _cls4 m_114; + + _cls7(_cls3 _pcls3, _cls0 _pcls0) + throws IOException + { + m_160 = _pcls0; + m_06 = new _cls6(_pcls3); + m_132 = _pcls0._932(_pcls3); + m_102 = _pcls0._932(_pcls3); + int i = _pcls3._14vI(); + for(int j = 0; j < i; j++) + { + String s = _pcls0._932(_pcls3).toString(); + int k = _pcls3.readInt(); + if(s.equals("ConstantValue")) + { + m_152 = _pcls0._932(_pcls3); + } else + { + err.println("Ignoring field attribute " + s); + _pcls3.skip(k); + } + } + + } + + void _61V(_cls1 _pcls1) + throws IOException + { + m_06._61V(_pcls1); + m_160._121V(_pcls1, m_132); + m_160._121V(_pcls1, m_102); + int i = 0; + if(m_152 != null) + i++; + _pcls1._4IV(i); + if(m_152 != null) + { + m_160._121V(_pcls1, m_160._8String2("ConstantValue")); + _pcls1.writeInt(2); + m_160._121V(_pcls1, m_152); + } + } + + void _19vV() + { + m_160._192V(m_132, "internal member"); + m_160._192V(m_102, "signature"); + if(m_152 != null) + { + m_160._192V(m_160._8String2("ConstantValue"), "attribute"); + m_160._192V(m_152, "literal"); + } + } + + String _18vString() + { + return m_132.toString(); + } + + String _7vString() + { + return m_102.toString(); + } + + boolean _3vZ() + { + return m_06._3vZ(); + } + + void _54V(_cls4 _pcls4) + { + m_114 = _pcls4; + } + + void _17PrintStreamV(PrintStream printstream) + { + _cls5 _lcls5 = new _cls5(m_132, m_102, m_160); + printstream.print(" "); + printstream.print(m_06); + printstream.print(_lcls5); + if(m_152 != null) + { + m_152._1StringV(m_102.toString()); + printstream.print(" = "); + printstream.print(m_152); + } else + if(m_114 != null) + { + m_114 = m_114._1String4(m_102.toString()); + m_114._2vV(); + printstream.print(" = "); + printstream.print(m_114); + } + printstream.println(";"); + } +} diff --git a/src/modules/mocha/_cls70.java b/src/modules/mocha/_cls70.java new file mode 100644 index 0000000..ea1397a --- /dev/null +++ b/src/modules/mocha/_cls70.java @@ -0,0 +1,261 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// _cls144, _cls23, _cls128, _cls143, +// _cls150, _cls145, _cls152, _cls136, +// _cls1, _cls146, _cls69, _cls166, +// _cls154, _cls31, _cls157, _cls169, +// _cls82, _cls129, _cls137, _cls135, +// _cls147, _cls74, _cls142, _cls140, +// _cls165, _cls108, _cls158, _cls141, +// _cls168, _cls160, _cls138, _cls133, +// _cls161, _cls103, _cls156, _cls159, +// _cls151, Decompiler, _cls139, _cls162, +// _cls153, _cls132, _cls155, _cls134, +// _cls149, _cls164, _cls3, _cls71, +// _cls170, _cls0, _cls167, _cls148, +// _cls163 + +class _cls70 +{ + + _cls0 m_160; + int m_365I; + int m_359I; + int m_226I; + byte m_362aB[]; + _cls108 m_361a108[]; + _cls71 m_3571; + _cls103 m_357103; + _cls138 m_366a138[] = { + new _cls145(), new _cls142(), new _cls150(), new _cls136(), new _cls135(), new _cls140(), new _cls148(), new _cls144(), new _cls147(), new _cls146(), + new _cls155(), new _cls158(), new _cls154(), new _cls137(), new _cls157(), new _cls168(), new _cls169(), new _cls151(), new _cls134(), new _cls133(), + new _cls139(), new _cls141(), new _cls143() + }; + _cls138 m_360a138[] = { + new _cls152(), new _cls160(), new _cls161(), new _cls162(), new _cls166(), new _cls167(), new _cls132(), new _cls163(), new _cls170(), new _cls149(), + new _cls164(), new _cls156(), new _cls159(), new _cls153(), new _cls165() + }; + + _cls70(_cls3 _pcls3, _cls0 _pcls0, _cls71 _pcls71) + throws IOException, _cls128 + { + m_160 = _pcls0; + m_3571 = _pcls71; + if(_pcls0.m_m_146II == 2) + { + m_365I = _pcls3._300vI(); + m_359I = _pcls3._300vI(); + m_226I = _pcls3._14vI(); + } else + { + m_365I = _pcls3._14vI(); + m_359I = _pcls3._14vI(); + m_226I = _pcls3.readInt(); + } + _pcls3.mark(m_226I); + m_362aB = new byte[m_226I]; + _pcls3.readFully(m_362aB); + _pcls3.reset(); + m_357103 = new _cls103(m_226I, _pcls71); + _cls74 _lcls74; + for(int i = 0; i < m_226I; i += _lcls74._200vI()) + { + _lcls74 = _cls31._953v74(_pcls3, i); + _lcls74._1080V(_pcls0, _pcls71); + m_357103._2497474(_lcls74); + } + + int j = _pcls3._14vI(); + m_361a108 = new _cls108[j]; + for(int k = 0; k < j; k++) + m_361a108[k] = new _cls108(_pcls3, _pcls0); + + m_357103._253a108V(m_361a108); + int l = _pcls3._14vI(); + for(int i1 = 0; i1 < l; i1++) + { + String s = _pcls0._932(_pcls3).toString(); + int j1 = _pcls3.readInt(); + if(s.equals("LineNumberTable")) + _pcls3.skip(j1); + else + if(s.equals("LocalVariableTable")) + { + _pcls71._953V(_pcls3); + } else + { + err.println("Ignoring code attribute " + s); + _pcls3.skip(j1); + } + } + + } + + void _61V(_cls1 _pcls1) + throws IOException + { + int i = 0; + i += 2; + i += 2; + i = (i += 4) + m_226I; + int j = m_361a108.length; + i = (i += 2) + j * 8; + int k = 0; + i += 2; + _pcls1.writeInt(i); + _pcls1._4IV(m_365I); + _pcls1._4IV(m_359I); + _pcls1.writeInt(m_226I); + _pcls1.write(m_362aB, 0, m_226I); + _pcls1._4IV(j); + for(int l = 0; l < j; l++) + m_361a108[l]._61V(_pcls1, m_160); + + _pcls1._4IV(k); + } + + void _19vV() + { + for(_cls82 _lcls82 = m_357103._178v82(); _lcls82._174vZ(); _lcls82._177v74()._19vV()); + for(int i = 0; i < m_361a108.length; i++) + m_361a108[i]._190V(m_160); + + } + + void _363vV() + { + m_357103._254I74(0)._197vV(); + for(_cls82 _lcls82 = m_357103._178v82(); _lcls82._174vZ();) + { + _cls74 _lcls74 = _lcls82._177v74(); + for(int j = 0; j < _lcls74._25vI(); j++) + m_357103._254I74(_lcls74._26II(j))._197vV(); + + } + + for(int i = 0; i < m_361a108.length; i++) + { + m_357103._254I74(m_361a108[i]._57vI())._197vV(); + m_357103._254I74(m_361a108[i]._59vI())._197vV(); + m_357103._254I74(m_361a108[i]._62vI())._197vV(); + } + + } + + void _107vV() + { + _cls23 _lcls23 = new _cls23(); + m_357103._254I74(0)._10723V(_lcls23, m_357103); + for(int i = 0; i < m_361a108.length; i++) + { + String s = m_361a108[i]._61vString(); + _cls23 _lcls23_1 = _lcls23._716123(new _cls69(s, "e")); + m_357103._254I74(m_361a108[i]._57vI())._10723V(_lcls23_1, m_357103); + } + + } + + int _356a138vI(_cls138 a_pcls138[], boolean flag) + { + int j = 0; + int i; + do + { + i = j; + for(_cls82 _lcls82 = m_357103._178v82(); _lcls82._174vZ();) + { + _cls74 _lcls74 = _lcls82._177v74(); + for(int k = 0; k < a_pcls138.length; k++) + { + _cls74 _lcls74_1 = a_pcls138[k]._3587474(_lcls74, m_357103); + if(_lcls74_1 != null) + { + _lcls74 = _lcls74_1; + i++; + if(Decompiler.m_debugZ) + System.out.println("Applied " + a_pcls138[k].getClass().getName()); + else + if(Decompiler.m_verboseZ) + { + System.out.print("."); + System.out.flush(); + } + if(flag) + _lcls82._17574V(null); + else + _lcls82._17574V(_lcls74_1); + } + } + + } + + } while(i != j); + return i; + } + + void _364vV() + { + _cls129 _lcls129 = new _cls129(null, 0, 0x7fffffff); + _cls74 _lcls74; + for(_cls82 _lcls82 = m_357103._178v82(); _lcls82._174vZ(); _lcls74._152129V(_lcls129)) + _lcls74 = _lcls82._177v74(); + + m_3571._39129V(_lcls129); + } + + void _2vV() + { + _cls74 _lcls74; + for(_cls82 _lcls82 = m_357103._178v82(); _lcls82._174vZ(); _lcls74._2vV()) + _lcls74 = _lcls82._177v74(); + + } + + String _367vString() + { + int i = 0; + for(_cls82 _lcls82 = m_357103._178v82(); _lcls82._174vZ();) + { + _lcls82._177v74(); + i++; + } + + if(i > 1) + return "Flow analysis could not complete"; + else + return null; + } + + String _39vString() + { + _363vV(); + _107vV(); + _356a138vI(m_366a138, false); + _356a138vI(m_360a138, true); + _364vV(); + _2vV(); + return _367vString(); + } + + void _17PrintStreamV(PrintStream printstream) + { + if(Decompiler.m_debugZ) + { + for(int i = 0; i < m_361a108.length; i++) + { + _cls108 _lcls108 = m_361a108[i]; + printstream.println("// handle " + _lcls108._55vString() + " in " + _lcls108._59vI() + "-" + _lcls108._62vI() + " at " + _lcls108._57vI()); + } + + } + m_3571._17PrintStreamvV(printstream, 2); + m_357103._17PrintStreamvV(printstream, 2); + } +} diff --git a/src/modules/mocha/_cls71.java b/src/modules/mocha/_cls71.java new file mode 100644 index 0000000..41314d6 --- /dev/null +++ b/src/modules/mocha/_cls71.java @@ -0,0 +1,358 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.*; + +// Referenced classes of package mocha: +// _cls129, _cls3, _cls125, _cls58, +// _cls124, _cls5, _cls2, Decompiler, +// _cls126, _cls127, _cls0, _cls61 + +class _cls71 +{ + + _cls0 m_160; + String m_230String; + int m_343I; + int m_336I; + Vector m_82Vector; + boolean m_341Z; + _cls129 m_339129; + Hashtable m_338Hashtable; + + _cls71(_cls0 _pcls0, boolean flag, String s) + { + m_160 = _pcls0; + m_230String = s; + m_343I = flag ? 0 : 1; + m_336I = _53StringI(s); + m_82Vector = new Vector(); + m_341Z = false; + m_338Hashtable = new Hashtable(); + } + + void _953V(_cls3 _pcls3) + throws IOException + { + int i = _pcls3._14vI(); + for(int j = 0; j < i; j++) + { + _cls125 _lcls125 = _cls125._950125(m_160, _pcls3); + _cls124 _lcls124 = _92I124(_lcls125._92vI()); + _lcls124._261125V(_lcls125); + } + + m_341Z = true; + } + + _cls124 _92I124(int i) + { + if(i >= m_82Vector.size()) + m_82Vector.setSize(i + 1); + _cls124 _lcls124 = (_cls124)m_82Vector.elementAt(i); + if(_lcls124 == null) + { + _lcls124 = new _cls124(i); + m_82Vector.setElementAt(_lcls124, i); + } + return _lcls124; + } + + _cls125 _111II125(int i, int j) + { + _cls124 _lcls124 = _92I124(i); + _cls125 _lcls125 = _lcls124._111I125(j); + if(_lcls125 == null) + { + _lcls125 = new _cls125(i, "local" + ((i - m_343I - m_336I) + 1), "", m_160); + _lcls124._261125V(_lcls125); + } + return _lcls125; + } + + _cls125 _231I125(int i) + { + int j = m_343I; + for(int k = 0; k < i; k++) + j += _111II125(j, 0)._99vI(); + + return _111II125(j, 0); + } + + Enumeration _35IEnumeration(int i) + { + Vector vector = new Vector(); + for(int j = 0; j < m_82Vector.size(); j++) + { + _cls124 _lcls124 = (_cls124)m_82Vector.elementAt(j); + if(_lcls124 != null) + { + _cls125 _lcls125 = _lcls124._111I125(i); + if(_lcls125 != null) + vector.addElement(_lcls125); + } + } + + return vector.elements(); + } + + boolean _38vZ() + { + return !m_341Z; + } + + private void _340vV() + { + if(m_343I > 0) + { + String s = "L" + m_160._76v2()._56v2().toString() + ";"; + _cls125 _lcls125 = new _cls125(0, "this", s, m_160); + _92I124(0)._261125V(_lcls125); + } + } + + private void _337vV() + { + int i = m_343I; + int j = 0; + int l; + for(int k = 1; m_230String.charAt(k) != ')'; k = l + 1) + { + for(l = k; m_230String.charAt(l) == '['; l++); + if(m_230String.charAt(l) == 'L') + for(; m_230String.charAt(l) != ';'; l++); + String s = m_230String.substring(k, l + 1); + j++; + _cls126 _lcls126 = _98String126(s); + _cls125 _lcls125 = new _cls125(i, _lcls126, s, m_160); + _92I124(i)._261125V(_lcls125); + i += _lcls125._99vI(); + } + + } + + void _37vV() + { + if(!m_341Z) + { + _340vV(); + _337vV(); + } + } + + void _333IIStringV(int i, int j, String s, char c) + { + if(i >= m_343I + m_336I) + { + _cls124 _lcls124 = _92I124(i); + _lcls124._262IStringV(j, s, c); + if(!m_341Z) + { + _cls125 _lcls125 = _111II125(i, j); + if(c != 'S') + s = _cls5._227StringString(_lcls125._81vString(), s); + s.equals(""); + _lcls125._93StringV(s); + } + } + } + + void _109IIV(int i, int j, String s) + { + _333IIStringV(i, j, s, 'L'); + } + + void _283IIV(int i, int j, String s) + { + _333IIStringV(i, j, s, 'S'); + } + + void _18661vV(_cls61 _pcls61, int i) + { + if(!m_341Z && (_pcls61 instanceof _cls58)) + { + _cls58 _lcls58 = (_cls58)_pcls61; + _333IIStringV(_lcls58._92vI(), i, "Y", 'X'); + } + } + + void _34261vV(_cls61 _pcls61, int i) + { + if(!m_341Z && (_pcls61 instanceof _cls58)) + { + _cls58 _lcls58 = (_cls58)_pcls61; + _333IIStringV(_lcls58._92vI(), i, "", 'T'); + } + } + + void _39129V(_cls129 _pcls129) + { + m_339129 = _pcls129; + for(int i = m_343I + m_336I; i < m_82Vector.size(); i++) + { + _cls124 _lcls124 = (_cls124)m_82Vector.elementAt(i); + if(_lcls124 != null) + if(m_341Z) + _lcls124._263129V(_pcls129, m_160, this); + else + _lcls124._269129V(_pcls129, m_160, this); + } + + } + + int _219StringI(String s) + { + Integer integer = (Integer)m_338Hashtable.get(s); + if(integer == null) + return 0; + else + return integer.intValue(); + } + + _cls126 _335String126(String s) + { + Integer integer = (Integer)m_338Hashtable.get(s); + int i = integer != null ? integer.intValue() + 1 : 1; + m_338Hashtable.put(s, new Integer(i)); + if(s.equals("n")) + { + switch((i - 1) % 3) + { + case 0: // '\0' + s = "i"; + break; + + case 1: // '\001' + s = "j"; + break; + + case 2: // '\002' + s = "k"; + break; + } + return _335String126(s); + } else + { + return new _cls126(s, i, this); + } + } + + _cls126 _98String126(String s) + { + StringBuffer stringbuffer = new StringBuffer(); + for(; s.startsWith("["); s = s.substring(1)) + stringbuffer.append("a"); + + if(s.equals("Z")) + stringbuffer.append("flag"); + else + if(s.equals("B")) + stringbuffer.append("b"); + else + if(s.equals("C")) + stringbuffer.append("ch"); + else + if(s.equals("S")) + stringbuffer.append("s"); + else + if(s.equals("I")) + stringbuffer.append("n"); + else + if(s.equals("J")) + stringbuffer.append("n"); + else + if(s.equals("F")) + stringbuffer.append("f"); + else + if(s.equals("D")) + stringbuffer.append("d"); + else + if(s.equals("W")) + stringbuffer.append("n"); + else + if(s.equals("Y")) + stringbuffer.append("n"); + else + if(s.startsWith("L")) + { + s = s.replace('/', '.').substring(1, s.length() - 1); + if(s.endsWith("Exception") || s.endsWith("Error")) + stringbuffer.append("e"); + else + if(s.equals("java.awt.Graphics")) + { + stringbuffer.append("g"); + } else + { + s = s.substring(s.lastIndexOf('.') + 1, s.length()); + char c = s.charAt(0); + c = Character.isUpperCase(c) ? Character.toLowerCase(c) : Character.toUpperCase(c); + stringbuffer.append(c); + stringbuffer.append(s.substring(1)); + } + } else + { + stringbuffer.append("local"); + } + return _335String126(stringbuffer.toString()); + } + + void _17PrintStreamvV(PrintStream printstream, int i) + { + if(Decompiler.m_debugZ) + { + for(int j = 0; j < m_82Vector.size(); j++) + { + _cls124 _lcls124 = (_cls124)m_82Vector.elementAt(j); + _lcls124._17PrintStreamvV(printstream, i); + } + + } + if(m_339129 != null) + m_339129._17PrintStreamStringV(printstream, i, "method"); + } + + private int _53StringI(String s) + { + int i = 0; + boolean flag = false; + for(int k = 0; k < s.length() && s.charAt(k) != ')'; k++) + switch(s.charAt(k)) + { + case 40: // '(' + case 91: // '[' + break; + + case 76: // 'L' + i++; + int j = k; + for(k++; s.charAt(k) != ';'; k++); + m_160._141StringV(s.substring(j + 1, k)); + break; + + case 68: // 'D' + case 74: // 'J' + i += 2; + break; + + default: + i++; + break; + } + + String s1 = s.substring(s.lastIndexOf(')') + 1); + if(s1.startsWith("L")) + m_160._141StringV(s1.substring(1, s1.length() - 1)); + return i; + } + + String _334vString() + { + return m_230String.substring(m_230String.lastIndexOf(')') + 1); + } +} diff --git a/src/modules/mocha/_cls72.java b/src/modules/mocha/_cls72.java new file mode 100644 index 0000000..1eec2fc --- /dev/null +++ b/src/modules/mocha/_cls72.java @@ -0,0 +1,155 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.*; + +// Referenced classes of package mocha: +// Decompiler, _cls1, _cls6, _cls70, +// _cls5, _cls71, _cls3, _cls2, +// _cls0 + +class _cls72 +{ + + _cls0 m_160; + _cls6 m_06; + _cls2 m_132; + _cls2 m_102; + _cls70 m_3670; + _cls71 m_3571; + _cls2 m_41a2[]; + + _cls72(_cls3 _pcls3, _cls0 _pcls0) + throws IOException + { + m_160 = _pcls0; + m_06 = new _cls6(_pcls3); + m_132 = _pcls0._932(_pcls3); + m_102 = _pcls0._932(_pcls3); + m_3571 = new _cls71(_pcls0, m_06._34vZ(), m_102.toString()); + int i = _pcls3._14vI(); + for(int j = 0; j < i; j++) + { + String s = _pcls0._932(_pcls3).toString(); + int k = _pcls3.readInt(); + if(s.equals("Code")) + m_3670 = new _cls70(_pcls3, _pcls0, m_3571); + else + if(s.equals("Exceptions")) + { + int l = _pcls3._14vI(); + m_41a2 = new _cls2[l]; + for(int i1 = 0; i1 < l; i1++) + m_41a2[i1] = _pcls0._932(_pcls3); + + } else + { + err.println("Ignoring method attribute " + s); + _pcls3.skip(k); + } + } + + if(m_3571._38vZ()) + m_3571._37vV(); + } + + void _61V(_cls1 _pcls1) + throws IOException + { + m_06._61V(_pcls1); + m_160._121V(_pcls1, m_132); + m_160._121V(_pcls1, m_102); + int i = 0; + if(m_3670 != null) + i++; + if(m_41a2 != null) + i++; + _pcls1._4IV(i); + if(m_3670 != null) + { + m_160._121V(_pcls1, m_160._8String2("Code")); + m_3670._61V(_pcls1); + } + if(m_41a2 != null) + { + m_160._121V(_pcls1, m_160._8String2("Exceptions")); + _pcls1.writeInt(2 * m_41a2.length + 2); + _pcls1._4IV(m_41a2.length); + for(int j = 0; j < m_41a2.length; j++) + m_160._121V(_pcls1, m_41a2[j]); + + } + } + + void _19vV() + { + m_160._192V(m_132, "internal member"); + m_160._192V(m_102, "signature"); + if(m_3670 != null) + { + m_160._192V(m_160._8String2("Code"), "attribute"); + m_3670._19vV(); + } + if(m_41a2 != null) + { + m_160._192V(m_160._8String2("Exceptions"), "attribute"); + for(int i = 0; i < m_41a2.length; i++) + m_160._192V(m_41a2[i], "class"); + + } + } + + void _39vV() + { + if(m_3670 != null) + { + if(Decompiler.m_verboseZ) + System.out.print(" Method " + m_132); + String s = m_3670._39vString(); + if(Decompiler.m_verboseZ) + System.out.println(); + if(s != null) + err.println("Method " + m_132 + ": " + s); + } + } + + boolean _40vZ() + { + return m_3670 == null; + } + + void _17PrintStreamV(PrintStream printstream) + { + _cls5 _lcls5 = new _cls5(m_132, m_102, m_160, m_3571); + printstream.print(" "); + printstream.print(m_06); + printstream.print(_lcls5); + if(m_41a2 != null) + { + printstream.println(); + printstream.print(" throws "); + for(int i = 0; i < m_41a2.length; i++) + { + if(i != 0) + printstream.print(", "); + printstream.print(m_41a2[i]); + } + + } + if(m_3670 == null) + { + printstream.println(";"); + return; + } else + { + printstream.println(); + printstream.println(" {"); + m_3670._17PrintStreamV(printstream); + printstream.println(" }"); + return; + } + } +} diff --git a/src/modules/mocha/_cls73.java b/src/modules/mocha/_cls73.java new file mode 100644 index 0000000..2d47194 --- /dev/null +++ b/src/modules/mocha/_cls73.java @@ -0,0 +1,97 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls78, _cls102, _cls95, _cls77, +// _cls98, _cls92, _cls75, _cls104, +// _cls87, _cls96, _cls103, _cls105, +// _cls100, _cls76, _cls91, _cls4, +// _cls84, _cls88, _cls97, _cls80, +// _cls81, _cls83, _cls85, _cls122, +// _cls90, _cls93, _cls79, _cls99, +// _cls106, _cls86, _cls74, _cls101, +// _cls82, _cls89, _cls94, _cls129 + +class _cls73 extends _cls78 +{ + + _cls4 m_834; + _cls78 m_8478; + _cls122 m_194122; + _cls122 m_190122; + static int m_191I; + + _cls73(_cls4 _pcls4, _cls78 _pcls78, _cls122 _pcls122, _cls122 _pcls122_1) + { + m_834 = _pcls4; + m_8478 = _pcls78; + m_194122 = _pcls122; + m_190122 = _pcls122_1; + } + + public int _94vI() + { + if(m_8478 != null) + return m_8478._94vI(); + else + return _155vI(); + } + + public int _48vI() + { + return m_834._48vI() + 1; + } + + public void _152129V(_cls129 _pcls129) + { + if(m_8478 != null) + m_8478._152129V(_pcls129); + } + + public void _2vV() + { + m_834 = m_834._1String4("Z"); + m_834._2vV(); + if(m_8478 != null) + m_8478._2vV(); + } + + public int _170vI() + { + if(m_8478 == null) + return 0; + else + return m_8478._170vI(); + } + + boolean _193122vZ(_cls122 _pcls122, int i) + { + if(m_8478 != null) + return m_8478._193122vZ(_pcls122, i + 1); + else + return false; + } + + void _85PrintStreamvV(PrintStream printstream, int i) + { + boolean flag = false; + if(m_194122 != null && _193122vZ(m_194122, 0)) + flag = true; + if(m_190122 != null && _193122vZ(m_190122, 0)) + flag = true; + if(flag) + { + m_191I++; + if(m_194122 != null) + m_194122._192IV(m_191I); + if(m_190122 != null) + m_190122._192IV(m_191I); + printstream.println(_cls75._50IString(i - 1) + "loop" + m_191I + ":"); + } + } +} diff --git a/src/modules/mocha/_cls74.java b/src/modules/mocha/_cls74.java new file mode 100644 index 0000000..1545811 --- /dev/null +++ b/src/modules/mocha/_cls74.java @@ -0,0 +1,65 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls101, _cls77, _cls91, _cls79, +// _cls106, _cls76, _cls82, _cls93, +// _cls90, _cls80, _cls96, _cls84, +// _cls87, _cls85, _cls100, _cls75, +// _cls99, _cls103, _cls78, _cls4, +// _cls105, _cls98, _cls95, _cls97, +// _cls92, _cls104, _cls81, _cls86, +// _cls73, _cls83, _cls94, _cls102, +// _cls88, _cls89, _cls129, _cls0, +// _cls71, _cls23 + +interface _cls74 +{ + + public abstract void _197vV(); + + public abstract void _196vV(); + + public abstract int _198vI(); + + public abstract int _25vI(); + + public abstract int _26II(int i); + + public abstract void _21IIV(int i, int j); + + public abstract int _200vI(); + + public abstract int _155vI(); + + public abstract int _94vI(); + + public abstract int _48vI(); + + public abstract void _152129V(_cls129 _pcls129); + + public abstract void _1080V(_cls0 _pcls0, _cls71 _pcls71); + + public abstract int _22vI(); + + public abstract int _117vI(); + + public abstract _cls23 _242323(_cls23 _pcls23); + + public abstract void _10723V(_cls23 _pcls23, _cls103 _pcls103); + + public abstract void _2vV(); + + public abstract _cls23 _199v23(); + + public abstract int _170vI(); + + public abstract void _17PrintStreamZV(PrintStream printstream, int i, boolean flag); + + public abstract void _19vV(); +} diff --git a/src/modules/mocha/_cls75.java b/src/modules/mocha/_cls75.java new file mode 100644 index 0000000..b4f622d --- /dev/null +++ b/src/modules/mocha/_cls75.java @@ -0,0 +1,224 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls102, _cls95, _cls77, _cls98, +// _cls92, _cls104, _cls87, _cls73, +// _cls96, _cls103, _cls105, _cls23, +// _cls100, _cls76, _cls91, _cls4, +// _cls84, _cls88, _cls97, _cls80, +// _cls81, _cls83, _cls85, Decompiler, +// _cls90, _cls93, _cls79, _cls99, +// _cls106, _cls86, _cls74, _cls101, +// _cls82, _cls89, _cls78, _cls94, +// _cls129, _cls0, _cls71, _cls122 + +abstract class _cls75 + implements _cls74 +{ + + protected int m_285I; + protected int m_306I; + protected int m_312I; + + _cls75() + { + m_285I = 0; + m_306I = -1; + m_312I = -1; + } + + _cls75 _497475(_cls74 _pcls74) + { + m_285I = _pcls74._198vI(); + m_306I = _pcls74._155vI(); + return this; + } + + _cls75 _527475(_cls74 _pcls74) + { + switch(_pcls74._25vI()) + { + case 0: // '\0' + m_312I = -1; + break; + + case 1: // '\001' + m_312I = _pcls74._26II(0); + break; + + default: + throw new IllegalArgumentException("StructuredFragment has split tail"); + } + return this; + } + + public void _197vV() + { + m_285I++; + } + + public void _196vV() + { + m_285I--; + } + + public int _198vI() + { + return m_285I; + } + + public int _155vI() + { + return m_306I; + } + + public int _94vI() + { + return _155vI(); + } + + public int _48vI() + { + return _94vI(); + } + + public void _152129V(_cls129 _pcls129) + { + } + + public int _25vI() + { + return m_312I >= 0 ? 1 : 0; + } + + public int _26II(int i) + { + return m_312I; + } + + public void _21IIV(int i, int j) + { + m_312I = j; + } + + public void _1080V(_cls0 _pcls0, _cls71 _pcls71) + { + } + + public void _10723V(_cls23 _pcls23, _cls103 _pcls103) + { + } + + public void _2vV() + { + } + + public _cls23 _199v23() + { + return new _cls23(); + } + + public int _200vI() + { + return 0; + } + + _cls75 _346I75(int i) + { + m_306I = i; + return this; + } + + boolean _193122vZ(_cls122 _pcls122, int i) + { + return false; + } + + static String _50IString(int i) + { + StringBuffer stringbuffer = new StringBuffer(4 * i); + for(int j = 0; j < i; j++) + stringbuffer.append(" "); + + return stringbuffer.toString(); + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_50IString(i) + getClass().getName()); + } + + public int _170vI() + { + return 1; + } + + public void _17PrintStreamZV(PrintStream printstream, int i, boolean flag) + { + if(Decompiler.m_debugZ) + printstream.println(_50IString(i - 2) + _94vI() + "-" + _48vI() + ":" + _198vI() + ">" + "\t\t\t\t\t\t\t\t" + getClass().getName().substring(6)); + if(!flag && _170vI() <= 1) + flag = true; + if(!flag) + printstream.println(_50IString(i - 1) + "{"); + _20PrintStreamvV(printstream, i); + if(!flag) + printstream.println(_50IString(i - 1) + "}"); + } + + protected String _53StringvString(String s, int i) + { + StringBuffer stringbuffer = new StringBuffer(); + if(s.charAt(0) == '(') + { + int j = 1; + while(i >= 0) + { + char c = s.charAt(j++); + if(i == 0) + stringbuffer.append(c); + switch(c) + { + case 41: // ')' + i = -1; + break; + + case 91: // '[' + break; + + case 76: // 'L' + char c1; + do + { + c1 = s.charAt(j++); + if(i == 0) + stringbuffer.append(c1); + } while(c1 != ';'); + i--; + break; + + default: + i--; + break; + } + } + } + return stringbuffer.toString(); + } + + public void _19vV() + { + } + + public abstract int _22vI(); + + public abstract int _117vI(); + + public abstract _cls23 _242323(_cls23 _pcls23); +} diff --git a/src/modules/mocha/_cls76.java b/src/modules/mocha/_cls76.java new file mode 100644 index 0000000..371941d --- /dev/null +++ b/src/modules/mocha/_cls76.java @@ -0,0 +1,61 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls78, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls82, +// _cls93, _cls90, _cls80, _cls96, +// _cls84, _cls87, _cls85, _cls100, +// _cls75, _cls99, _cls103, _cls4, +// _cls105, _cls98, _cls95, _cls97, +// _cls92, _cls104, _cls81, _cls86, +// _cls73, _cls83, _cls94, _cls102, +// _cls88, _cls89, _cls61 + +class _cls76 extends _cls78 +{ + + _cls4 m_724; + + _cls76(_cls4 _pcls4) + { + _497475(_pcls4); + _527475(_pcls4); + m_724 = _pcls4; + } + + public int _48vI() + { + return m_724._48vI(); + } + + _cls4 _78v4() + { + return m_724; + } + + public void _2vV() + { + m_724._2vV(); + } + + public _cls61 _51v61() + { + return m_724._51v61(); + } + + public String toString() + { + return _51v61().toString(); + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_cls75._50IString(i) + this + ";"); + } +} diff --git a/src/modules/mocha/_cls77.java b/src/modules/mocha/_cls77.java new file mode 100644 index 0000000..a8edac1 --- /dev/null +++ b/src/modules/mocha/_cls77.java @@ -0,0 +1,145 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; +import java.util.Vector; + +// Referenced classes of package mocha: +// _cls78, _cls102, _cls95, _cls98, +// _cls92, _cls75, _cls104, _cls87, +// _cls73, _cls129, _cls96, _cls103, +// _cls105, _cls100, _cls76, _cls91, +// _cls4, _cls84, _cls88, _cls97, +// _cls124, _cls80, _cls81, _cls83, +// _cls85, _cls90, _cls93, _cls79, +// _cls99, _cls106, _cls86, _cls74, +// _cls101, _cls82, _cls89, _cls94, +// _cls122 + +class _cls77 extends _cls78 +{ + + _cls78 m_307a78[]; + _cls129 m_153129; + + _cls77(_cls78 a_pcls78[]) + { + _497475(a_pcls78[0]); + _527475(a_pcls78[a_pcls78.length - 1]); + m_307a78 = a_pcls78; + } + + public void _197vV() + { + super.m_285I++; + if(m_307a78.length > 0) + m_307a78[0]._197vV(); + } + + public void _196vV() + { + super.m_285I--; + if(m_307a78.length > 0) + m_307a78[0]._196vV(); + } + + public int _48vI() + { + if(m_307a78.length > 0) + return m_307a78[m_307a78.length - 1]._48vI(); + else + return _94vI(); + } + + public void _152129V(_cls129 _pcls129) + { + m_153129 = new _cls129(_pcls129, _94vI(), _48vI()); + for(int i = 0; i < m_307a78.length; i++) + m_307a78[i]._152129V(m_153129); + + } + + public void _2vV() + { + for(int i = 0; i < m_307a78.length; i++) + m_307a78[i]._2vV(); + + } + + boolean _193122vZ(_cls122 _pcls122, int i) + { + boolean flag = false; + for(int j = 0; j < m_307a78.length; j++) + if(m_307a78[j]._193122vZ(_pcls122, i)) + flag = true; + + return flag; + } + + int _291vI() + { + return m_307a78.length; + } + + _cls78 _290I78(int i) + { + return m_307a78[i]; + } + + public int _170vI() + { + int i = 0; + for(int j = 0; j < m_307a78.length; j++) + i += m_307a78[j]._170vI(); + + return i; + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + _158vV(); + if(m_153129 != null) + m_153129._17PrintStreamStringV(printstream, i, "sequence"); + for(int j = 0; j < m_307a78.length; j++) + m_307a78[j]._17PrintStreamZV(printstream, i, true); + + } + + void _158vV() + { + Vector vector = m_153129._156vVector(); + for(int i = 0; i < vector.size();) + { + _cls124 _lcls124 = (_cls124)vector.elementAt(i); + int j = _lcls124._159vI(); + for(int k = 0; _lcls124 != null && k < m_307a78.length; k++) + { + _cls78 _lcls78 = m_307a78[k]; + if(_lcls78._48vI() == j - 1 && (_lcls78 instanceof _cls76)) + { + _cls76 _lcls76 = (_cls76)_lcls78; + _cls4 _lcls4 = _lcls76._78v4(); + if(_lcls4 instanceof _cls92) + { + _cls125 _lcls125 = _lcls124._111I125(j); + _cls4 _lcls4_1 = _lcls4._65I4(0); + _cls95 _lcls95 = new _cls95(_lcls125, _lcls4_1); + _lcls95._497475(m_307a78[k]); + _lcls95._527475(m_307a78[k]); + m_307a78[k] = _lcls95; + _lcls124 = null; + } + } + } + + if(_lcls124 == null) + vector.removeElementAt(i); + else + i++; + } + + } +} diff --git a/src/modules/mocha/_cls78.java b/src/modules/mocha/_cls78.java new file mode 100644 index 0000000..97cc5c3 --- /dev/null +++ b/src/modules/mocha/_cls78.java @@ -0,0 +1,50 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls75, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls76, +// _cls82, _cls93, _cls90, _cls80, +// _cls96, _cls84, _cls87, _cls85, +// _cls100, _cls99, _cls103, _cls4, +// _cls105, _cls98, _cls95, _cls97, +// _cls92, _cls104, _cls81, _cls86, +// _cls73, _cls83, _cls94, _cls102, +// _cls88, _cls89, _cls23 + +class _cls78 extends _cls75 +{ + + public int _22vI() + { + return 0; + } + + public int _117vI() + { + return 0; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23; + } + + int _291vI() + { + return 1; + } + + _cls78 _290I78(int i) + { + return this; + } + + _cls78() + { + } +} diff --git a/src/modules/mocha/_cls79.java b/src/modules/mocha/_cls79.java new file mode 100644 index 0000000..23073a4 --- /dev/null +++ b/src/modules/mocha/_cls79.java @@ -0,0 +1,98 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls78, _cls102, _cls95, _cls77, +// _cls98, _cls92, _cls75, _cls104, +// _cls87, _cls73, _cls96, _cls103, +// _cls105, _cls100, _cls76, _cls91, +// _cls4, _cls84, _cls131, _cls88, +// _cls97, _cls80, _cls81, _cls83, +// _cls85, _cls90, _cls93, _cls99, +// _cls106, _cls86, _cls74, _cls101, +// _cls82, _cls89, _cls94, _cls129, +// _cls122 + +class _cls79 extends _cls78 +{ + + _cls4 m_2374; + _cls84 m_236a84[]; + + _cls79(_cls4 _pcls4) + { + m_2374 = _pcls4; + _497475(_pcls4); + } + + public int _48vI() + { + int i = _94vI(); + for(int j = 0; j < m_236a84.length; j++) + if(i < m_236a84[j]._48vI()) + i = m_236a84[j]._48vI(); + + return i; + } + + public void _152129V(_cls129 _pcls129) + { + _cls131 _lcls131 = new _cls131(_pcls129, _94vI(), _48vI()); + for(int i = 0; i < m_236a84.length; i++) + m_236a84[i]._152129V(_lcls131); + + } + + public void _2vV() + { + m_2374._2vV(); + for(int i = 0; i < m_236a84.length; i++) + m_236a84[i]._2vV(); + + } + + boolean _193122vZ(_cls122 _pcls122, int i) + { + boolean flag = false; + for(int j = 0; j < m_236a84.length; j++) + if(m_236a84[j]._193122vZ(_pcls122, i + 1)) + flag = true; + + return flag; + } + + void _23584V(_cls84 _pcls84) + { + int i = m_236a84 != null ? m_236a84.length : 0; + _cls84 a_lcls84[] = new _cls84[i + 1]; + for(int j = 0; j < i; j++) + a_lcls84[j] = m_236a84[j]; + + a_lcls84[i] = _pcls84; + m_236a84 = a_lcls84; + } + + public int _170vI() + { + return m_236a84.length + 3; + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_cls75._50IString(i) + "switch (" + m_2374 + ")"); + printstream.println(_cls75._50IString(i) + "{"); + for(int j = 0; j < m_236a84.length; j++) + { + if(j > 0) + printstream.println(); + m_236a84[j]._17PrintStreamZV(printstream, i, true); + } + + printstream.println(_cls75._50IString(i) + "}"); + } +} diff --git a/src/modules/mocha/_cls8.java b/src/modules/mocha/_cls8.java new file mode 100644 index 0000000..26373de --- /dev/null +++ b/src/modules/mocha/_cls8.java @@ -0,0 +1,45 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls31, _cls46, _cls27, _cls25, +// _cls42, _cls18, _cls52, _cls35, +// _cls53, _cls43, _cls20, _cls14, +// _cls36, _cls26, _cls48, _cls45, +// _cls13, _cls54, _cls38, _cls50, +// _cls28, _cls41, _cls9, _cls16, +// _cls34, _cls44, _cls17, _cls37, +// _cls19, _cls11, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls23, +// _cls29, _cls32, _cls10 + +class _cls8 extends _cls31 +{ + + _cls8(int i, int j) + { + super(i, j); + } + + public int _22vI() + { + return 1; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._29v23(); + } + + void _20PrintStreamV(PrintStream printstream) + { + printstream.println("unlock"); + } +} diff --git a/src/modules/mocha/_cls80.java b/src/modules/mocha/_cls80.java new file mode 100644 index 0000000..e62a0f6 --- /dev/null +++ b/src/modules/mocha/_cls80.java @@ -0,0 +1,85 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls4, _cls102, _cls95, _cls77, +// _cls98, _cls92, _cls75, _cls104, +// _cls87, _cls73, _cls96, _cls103, +// _cls105, _cls23, _cls100, _cls76, +// _cls91, _cls84, _cls88, _cls97, +// _cls61, _cls81, _cls83, _cls85, +// _cls90, _cls93, _cls79, _cls99, +// _cls106, _cls86, _cls74, _cls101, +// _cls82, _cls89, _cls64, _cls78, +// _cls94 + +class _cls80 extends _cls4 +{ + + _cls4 m_834; + + _cls80(_cls4 _pcls4, _cls4 _pcls4_1, _cls4 _pcls4_2) + { + m_834 = _pcls4._311v4(); + _cls4 a_lcls4[] = { + _pcls4_2, _pcls4_1 + }; + super.m_54a4 = a_lcls4; + } + + public int _48vI() + { + if(super.m_54a4[0]._48vI() > super.m_54a4[1]._48vI()) + return super.m_54a4[0]._48vI(); + else + return super.m_54a4[1]._48vI(); + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._716123(_51v61()); + } + + public _cls61 _51v61() + { + _cls61 _lcls61 = m_834._51v61(); + _cls61 _lcls61_1 = super.m_54a4[0]._51v61(); + _cls61 _lcls61_2 = super.m_54a4[1]._51v61(); + return new _cls64(_lcls61_1._43vString(), _lcls61, _lcls61_1, _lcls61_2, "?", ":", 12); + } + + boolean _6861Z(_cls61 _pcls61) + { + if(super._6861Z(_pcls61)) + return true; + else + return m_834._6861Z(_pcls61); + } + + public void _2vV() + { + m_834 = m_834._1String4("Z"); + m_834._2vV(); + super._2vV(); + } + + _cls4 _1String4(String s) + { + super.m_54a4[0] = super.m_54a4[0]._1String4(s); + super.m_54a4[1] = super.m_54a4[1]._1String4(s); + if(s.equals("Z")) + { + String s1 = super.m_54a4[0].toString(); + String s2 = super.m_54a4[1].toString(); + if(s1.equals("true") && s2.equals("false")) + return m_834; + if(s1.equals("false") && s2.equals("true")) + return m_834._311v4(); + } + return this; + } +} diff --git a/src/modules/mocha/_cls81.java b/src/modules/mocha/_cls81.java new file mode 100644 index 0000000..45c8a16 --- /dev/null +++ b/src/modules/mocha/_cls81.java @@ -0,0 +1,52 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls4, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls76, +// _cls82, _cls93, _cls68, _cls90, +// _cls80, _cls96, _cls84, _cls87, +// _cls85, _cls100, _cls75, _cls99, +// _cls103, _cls78, _cls105, _cls98, +// _cls95, _cls97, _cls92, _cls104, +// _cls86, _cls73, _cls83, _cls94, +// _cls102, _cls23, _cls88, _cls61, +// _cls89, _cls52 + +class _cls81 extends _cls4 +{ + + _cls4 m_3304; + + _cls81(_cls4 _pcls4, _cls4 a_pcls4[], _cls52 _pcls52) + { + super(_pcls52, a_pcls4); + _497475(_pcls4); + _527475(_pcls52); + m_3304 = _pcls4; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._716123(_51v61()); + } + + public _cls61 _51v61() + { + String s = m_3304.toString(); + _cls61 a_lcls61[] = new _cls61[super.m_54a4.length]; + for(int i = 0; i < super.m_54a4.length; i++) + a_lcls61[i] = super.m_54a4[i]._51v61(); + + return new _cls68("A", s, a_lcls61); + } + + public int _22vI() + { + return 0; + } +} diff --git a/src/modules/mocha/_cls82.java b/src/modules/mocha/_cls82.java new file mode 100644 index 0000000..f8bffec --- /dev/null +++ b/src/modules/mocha/_cls82.java @@ -0,0 +1,60 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls101, _cls77, _cls74, _cls91, +// _cls79, _cls106, _cls76, _cls93, +// _cls90, _cls80, _cls96, _cls84, +// _cls87, _cls85, _cls100, _cls75, +// _cls99, _cls103, _cls78, _cls4, +// _cls105, _cls98, _cls95, _cls97, +// _cls92, _cls104, _cls81, _cls86, +// _cls73, _cls83, _cls94, _cls102, +// _cls88, _cls89 + +class _cls82 +{ + + protected _cls74 m_178a74[]; + protected int m_176I; + + _cls82(_cls74 a_pcls74[]) + { + m_178a74 = a_pcls74; + m_176I = 0; + } + + boolean _174vZ() + { + for(int i = m_176I; i < m_178a74.length; i++) + if(m_178a74[i] != null) + return true; + + return false; + } + + _cls74 _177v74() + { + while(m_176I < m_178a74.length) + if(m_178a74[m_176I++] != null) + return m_178a74[m_176I - 1]; + return null; + } + + void _17574V(_cls74 _pcls74) + { + if(_pcls74 == null) + { + m_176I = 0; + return; + } else + { + m_176I = _pcls74._155vI() + 1; + return; + } + } +} diff --git a/src/modules/mocha/_cls83.java b/src/modules/mocha/_cls83.java new file mode 100644 index 0000000..66df57e --- /dev/null +++ b/src/modules/mocha/_cls83.java @@ -0,0 +1,79 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls78, _cls101, _cls77, _cls74, +// _cls91, _cls79, Decompiler, _cls106, +// _cls76, _cls82, _cls93, _cls90, +// _cls80, _cls96, _cls84, _cls87, +// _cls85, _cls100, _cls75, _cls99, +// _cls103, _cls4, _cls105, _cls98, +// _cls95, _cls97, _cls92, _cls104, +// _cls81, _cls86, _cls73, _cls94, +// _cls102, _cls88, _cls89, _cls129, +// _cls23 + +class _cls83 extends _cls78 +{ + + _cls74 m_33174; + + _cls83(_cls74 _pcls74) + { + m_33174 = _pcls74; + if(_pcls74 != null) + { + _497475(_pcls74); + _527475(_pcls74); + } + } + + public int _22vI() + { + return 0; + } + + public int _117vI() + { + return 0; + } + + public int _48vI() + { + if(m_33174 != null) + return m_33174._48vI(); + else + return _94vI(); + } + + public void _152129V(_cls129 _pcls129) + { + if(m_33174 != null) + m_33174._152129V(_pcls129); + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23; + } + + public int _170vI() + { + return m_33174 == null || !Decompiler.m_debugZ ? 0 : 2; + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + if(m_33174 != null && Decompiler.m_debugZ) + { + printstream.println("/*"); + m_33174._17PrintStreamZV(printstream, i, true); + printstream.println("*/"); + } + } +} diff --git a/src/modules/mocha/_cls84.java b/src/modules/mocha/_cls84.java new file mode 100644 index 0000000..12b8160 --- /dev/null +++ b/src/modules/mocha/_cls84.java @@ -0,0 +1,114 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls75, _cls102, _cls95, _cls77, +// _cls98, _cls92, _cls104, _cls87, +// _cls73, _cls96, _cls103, _cls105, +// _cls100, _cls76, _cls91, _cls4, +// _cls88, _cls97, _cls80, _cls81, +// _cls83, _cls85, _cls90, _cls93, +// _cls79, _cls99, _cls106, _cls86, +// _cls74, _cls101, _cls82, _cls89, +// _cls78, _cls94, _cls129, _cls122, +// _cls23 + +class _cls84 extends _cls75 +{ + + int m_327aI[]; + String m_329String; + _cls78 m_8478; + + _cls84(String s, _cls78 _pcls78) + { + m_329String = s; + m_8478 = _pcls78; + } + + public int _48vI() + { + if(m_8478 != null) + return m_8478._48vI(); + else + return _94vI(); + } + + public void _152129V(_cls129 _pcls129) + { + if(m_8478 != null) + m_8478._152129V(_pcls129); + } + + public void _2vV() + { + if(m_8478 != null) + m_8478._2vV(); + } + + boolean _193122vZ(_cls122 _pcls122, int i) + { + if(m_8478 != null) + return m_8478._193122vZ(_pcls122, i); + else + return false; + } + + void _328IV(int i) + { + int j = m_327aI != null ? m_327aI.length : 0; + int ai[] = new int[j + 1]; + for(int k = 0; k < j; k++) + ai[k] = m_327aI[k]; + + ai[j] = i; + m_327aI = ai; + } + + public int _22vI() + { + return 0; + } + + public int _117vI() + { + return 0; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23; + } + + public int _170vI() + { + return 0; + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + if(m_327aI == null) + { + printstream.println(_cls75._50IString(i) + "default:"); + } else + { + for(int j = 0; j < m_327aI.length; j++) + printstream.println(_cls75._50IString(i) + "case " + m_327aI[j] + ":"); + + } + if(m_8478 != null) + m_8478._17PrintStreamZV(printstream, i + 1, true); + if(m_329String.equals("B")) + { + printstream.println(_cls75._50IString(i + 1) + "break;"); + return; + } + if(m_329String.equals("F")) + printstream.println("\n" + _cls75._50IString(i + 1) + "// fall thru"); + } +} diff --git a/src/modules/mocha/_cls85.java b/src/modules/mocha/_cls85.java new file mode 100644 index 0000000..26b2913 --- /dev/null +++ b/src/modules/mocha/_cls85.java @@ -0,0 +1,31 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls78, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls76, +// _cls82, _cls93, _cls90, _cls80, +// _cls96, _cls84, _cls87, _cls100, +// _cls75, _cls99, _cls103, _cls4, +// _cls105, _cls98, _cls95, _cls97, +// _cls92, _cls104, _cls81, _cls86, +// _cls73, _cls83, _cls94, _cls102, +// _cls88, _cls89 + +class _cls85 extends _cls78 +{ + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_cls75._50IString(i) + "return;"); + } + + _cls85() + { + } +} diff --git a/src/modules/mocha/_cls86.java b/src/modules/mocha/_cls86.java new file mode 100644 index 0000000..c5eff4b --- /dev/null +++ b/src/modules/mocha/_cls86.java @@ -0,0 +1,36 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls92, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls56, _cls106, +// _cls76, _cls82, _cls93, _cls90, +// _cls80, _cls96, _cls84, _cls87, +// _cls85, _cls100, _cls75, _cls99, +// _cls103, _cls78, _cls4, _cls105, +// _cls98, _cls95, _cls97, _cls104, +// _cls81, _cls73, _cls83, _cls94, +// _cls102, _cls88, _cls61, _cls89 + +class _cls86 extends _cls92 +{ + + _cls86(_cls61 _pcls61, _cls74 _pcls74, String s) + { + super(_pcls61, _pcls74, s, null); + } + + public _cls61 _51v61() + { + return new _cls56(super.m_7061._43vString(), super.m_7061, super.m_32String, 24); + } + + public int _22vI() + { + return 0; + } +} diff --git a/src/modules/mocha/_cls87.java b/src/modules/mocha/_cls87.java new file mode 100644 index 0000000..4f21af1 --- /dev/null +++ b/src/modules/mocha/_cls87.java @@ -0,0 +1,26 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls88, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls76, +// _cls82, _cls93, _cls90, _cls80, +// _cls96, _cls84, _cls85, _cls100, +// _cls75, _cls99, _cls103, _cls78, +// _cls4, _cls105, _cls98, _cls95, +// _cls97, _cls92, _cls104, _cls81, +// _cls86, _cls73, _cls83, _cls94, +// _cls102, _cls89, _cls122 + +class _cls87 extends _cls88 +{ + + _cls87(int i, _cls122 _pcls122) + { + super(i, _pcls122, "break"); + } +} diff --git a/src/modules/mocha/_cls88.java b/src/modules/mocha/_cls88.java new file mode 100644 index 0000000..fd45163 --- /dev/null +++ b/src/modules/mocha/_cls88.java @@ -0,0 +1,52 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls78, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls76, +// _cls82, _cls93, _cls90, _cls80, +// _cls96, _cls84, _cls87, _cls85, +// _cls100, _cls75, _cls99, _cls103, +// _cls4, _cls105, _cls98, _cls95, +// _cls97, _cls92, _cls104, _cls81, +// _cls86, _cls73, _cls83, _cls94, +// _cls102, _cls89, _cls122 + +class _cls88 extends _cls78 +{ + + _cls122 m_304122; + boolean m_303Z; + String m_305String; + + _cls88(int i, _cls122 _pcls122, String s) + { + m_303Z = false; + super.m_306I = i; + super.m_285I = 1; + m_304122 = _pcls122; + m_305String = s; + } + + boolean _193122vZ(_cls122 _pcls122, int i) + { + if(_pcls122 != m_304122 || i <= 1) + return false; + if(i < 1000) + m_303Z = true; + return true; + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.print(_cls75._50IString(i) + m_305String); + if(m_303Z) + printstream.print(" " + m_304122); + printstream.println(";"); + } +} diff --git a/src/modules/mocha/_cls89.java b/src/modules/mocha/_cls89.java new file mode 100644 index 0000000..4ce479a --- /dev/null +++ b/src/modules/mocha/_cls89.java @@ -0,0 +1,82 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls78, _cls102, _cls95, _cls77, +// _cls98, _cls92, _cls75, _cls104, +// _cls87, _cls73, _cls129, _cls96, +// _cls103, _cls105, _cls100, _cls76, +// _cls91, _cls4, _cls84, _cls88, +// _cls97, _cls80, _cls81, _cls83, +// _cls85, _cls90, _cls93, _cls79, +// _cls99, _cls106, _cls86, _cls74, +// _cls101, _cls82, _cls94, _cls126 + +class _cls89 extends _cls78 +{ + + _cls78 m_22278; + String m_224String; + _cls126 m_223126; + _cls129 m_153129; + + _cls89(_cls78 _pcls78) + { + m_22278 = _pcls78; + } + + _cls89(_cls78 _pcls78, String s, _cls126 _pcls126) + { + m_22278 = _pcls78; + m_224String = s; + m_223126 = _pcls126; + } + + public int _48vI() + { + if(m_22278 != null) + return m_22278._48vI(); + else + return _155vI(); + } + + public void _152129V(_cls129 _pcls129) + { + m_153129 = new _cls129(_pcls129, _94vI(), _48vI()); + if(m_22278 != null) + m_22278._152129V(m_153129); + } + + public void _2vV() + { + if(m_22278 != null) + m_22278._2vV(); + } + + public int _170vI() + { + if(m_22278 == null) + return 1; + else + return m_22278._170vI(); + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.print(_cls75._50IString(i) + "catch ("); + if(m_224String == null) + printstream.print(m_153129); + else + printstream.print(m_224String + " " + m_223126); + printstream.println(")"); + printstream.println(_cls75._50IString(i) + "{"); + if(m_22278 != null) + m_22278._17PrintStreamZV(printstream, i + 1, true); + printstream.println(_cls75._50IString(i) + "}"); + } +} diff --git a/src/modules/mocha/_cls9.java b/src/modules/mocha/_cls9.java new file mode 100644 index 0000000..77230f3 --- /dev/null +++ b/src/modules/mocha/_cls9.java @@ -0,0 +1,36 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls31, _cls46, _cls27, _cls25, +// _cls42, _cls18, _cls52, _cls35, +// _cls53, _cls43, _cls20, _cls14, +// _cls26, _cls36, _cls48, _cls45, +// _cls13, _cls54, _cls38, _cls50, +// _cls28, _cls41, _cls16, _cls34, +// _cls44, _cls17, _cls37, _cls19, +// _cls11, _cls8, _cls51, _cls40, +// _cls22, _cls33, _cls30, _cls49, +// _cls24, _cls47, _cls55, _cls15, +// _cls39, _cls21, _cls12, _cls29, +// _cls32, _cls10 + +abstract class _cls9 extends _cls31 +{ + + _cls9(int i, int j) + { + super(i, j); + } + + public int _117vI() + { + return 1; + } + + abstract boolean _11431Z(_cls31 _pcls31); +} diff --git a/src/modules/mocha/_cls90.java b/src/modules/mocha/_cls90.java new file mode 100644 index 0000000..7efccb3 --- /dev/null +++ b/src/modules/mocha/_cls90.java @@ -0,0 +1,52 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls4, _cls101, _cls77, _cls69, +// _cls74, _cls91, _cls79, _cls106, +// _cls76, _cls82, _cls93, _cls80, +// _cls96, _cls84, _cls87, _cls85, +// _cls100, _cls75, _cls99, _cls103, +// _cls78, _cls105, _cls98, _cls95, +// _cls97, _cls92, _cls104, _cls81, +// _cls86, _cls73, _cls83, _cls94, +// _cls102, _cls23, _cls88, _cls61, +// _cls89 + +class _cls90 extends _cls4 +{ + + _cls90(_cls4 a_pcls4[]) + { + super.m_54a4 = a_pcls4; + } + + public int _48vI() + { + return super.m_54a4[super.m_54a4.length - 1]._48vI(); + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._716123(_51v61()); + } + + public _cls61 _51v61() + { + StringBuffer stringbuffer = new StringBuffer("{ "); + for(int i = 0; i < super.m_54a4.length; i++) + { + if(i != 0) + stringbuffer.append(", "); + stringbuffer.append(super.m_54a4[i]); + } + + stringbuffer.append(" }"); + String s = "[" + super.m_54a4[0]._51v61()._43vString(); + return new _cls69(s, stringbuffer.toString()); + } +} diff --git a/src/modules/mocha/_cls91.java b/src/modules/mocha/_cls91.java new file mode 100644 index 0000000..a07cc31 --- /dev/null +++ b/src/modules/mocha/_cls91.java @@ -0,0 +1,66 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls75, _cls101, _cls77, _cls74, +// _cls79, _cls106, _cls76, _cls82, +// _cls93, _cls90, _cls80, _cls96, +// _cls84, _cls87, _cls85, _cls100, +// _cls99, _cls103, _cls78, _cls4, +// _cls105, _cls98, _cls95, _cls97, +// _cls92, _cls104, _cls81, _cls86, +// _cls73, _cls83, _cls94, _cls102, +// _cls88, _cls89, _cls23 + +class _cls91 extends _cls75 +{ + + protected int m_116aI[]; + + _cls75 _527475(_cls74 _pcls74) + { + m_116aI = new int[_pcls74._25vI()]; + for(int i = 0; i < m_116aI.length; i++) + m_116aI[i] = _pcls74._26II(i); + + return this; + } + + public int _25vI() + { + return m_116aI.length; + } + + public int _26II(int i) + { + return m_116aI[i]; + } + + public void _21IIV(int i, int j) + { + m_116aI[i] = j; + } + + public int _22vI() + { + return 0; + } + + public int _117vI() + { + return 0; + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23; + } + + _cls91() + { + } +} diff --git a/src/modules/mocha/_cls92.java b/src/modules/mocha/_cls92.java new file mode 100644 index 0000000..63e5e40 --- /dev/null +++ b/src/modules/mocha/_cls92.java @@ -0,0 +1,100 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls4, _cls102, _cls95, _cls77, +// _cls98, _cls75, _cls104, _cls87, +// _cls73, _cls96, _cls103, _cls105, +// _cls23, _cls100, _cls76, _cls91, +// _cls84, _cls88, _cls97, _cls61, +// _cls80, _cls81, _cls54, _cls83, +// _cls60, _cls85, _cls90, _cls93, +// _cls79, _cls99, _cls106, _cls86, +// _cls74, _cls101, _cls82, _cls89, +// _cls78, _cls94, _cls7 + +class _cls92 extends _cls4 +{ + + _cls61 m_7061; + _cls74 m_2974; + String m_32String; + _cls4 m_724; + + _cls92(_cls61 _pcls61, _cls74 _pcls74, String s, _cls4 _pcls4) + { + m_7061 = _pcls61; + m_2974 = _pcls74; + m_32String = s; + m_724 = _pcls4; + } + + public int _48vI() + { + return m_2974._48vI(); + } + + public _cls23 _242323(_cls23 _pcls23) + { + return _pcls23._716123(_51v61()); + } + + public _cls61 _51v61() + { + _cls61 _lcls61 = m_724._51v61(); + return new _cls60(_lcls61._43vString(), m_7061, _lcls61, m_32String, 11); + } + + boolean _6861Z(_cls61 _pcls61) + { + if(toString().equals(_pcls61.toString())) + return true; + if(m_7061.toString().equals(_pcls61.toString())) + return true; + if(m_724 != null) + return m_724._6861Z(_pcls61); + else + return false; + } + + public int _22vI() + { + return 1; + } + + _cls4 _65I4(int i) + { + return m_724; + } + + void _67I4V(int i, _cls4 _pcls4) + { + m_724 = _pcls4; + } + + public void _2vV() + { + if(m_724 != null) + { + m_724 = m_724._1String4(m_7061._43vString()); + m_724._2vV(); + } + } + + _cls61 _69v61() + { + return m_7061; + } + + _cls7 _66v7() + { + if(m_2974 instanceof _cls54) + return ((_cls54)m_2974)._66v7(); + else + return null; + } +} diff --git a/src/modules/mocha/_cls93.java b/src/modules/mocha/_cls93.java new file mode 100644 index 0000000..5051a4c --- /dev/null +++ b/src/modules/mocha/_cls93.java @@ -0,0 +1,40 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls73, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls76, +// _cls82, _cls90, _cls80, _cls96, +// _cls84, _cls87, _cls85, _cls100, +// _cls75, _cls99, _cls103, _cls78, +// _cls4, _cls105, _cls98, _cls95, +// _cls97, _cls92, _cls104, _cls81, +// _cls86, _cls83, _cls94, _cls102, +// _cls88, _cls89, _cls122 + +class _cls93 extends _cls73 +{ + + _cls93(_cls4 _pcls4, _cls78 _pcls78, _cls122 _pcls122, _cls122 _pcls122_1) + { + super(_pcls4, _pcls78, _pcls122, _pcls122_1); + } + + public int _170vI() + { + return super.m_8478._170vI() + 1; + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + _85PrintStreamvV(printstream, i); + printstream.println(_cls75._50IString(i) + "do"); + super.m_8478._17PrintStreamZV(printstream, i + 1, false); + printstream.println(_cls75._50IString(i) + "while (" + super.m_834 + ");"); + } +} diff --git a/src/modules/mocha/_cls94.java b/src/modules/mocha/_cls94.java new file mode 100644 index 0000000..40e58c9 --- /dev/null +++ b/src/modules/mocha/_cls94.java @@ -0,0 +1,26 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls88, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls76, +// _cls82, _cls93, _cls90, _cls80, +// _cls96, _cls84, _cls87, _cls85, +// _cls100, _cls75, _cls99, _cls103, +// _cls78, _cls4, _cls105, _cls98, +// _cls95, _cls97, _cls92, _cls104, +// _cls81, _cls86, _cls73, _cls83, +// _cls102, _cls89, _cls122 + +class _cls94 extends _cls88 +{ + + _cls94(int i, _cls122 _pcls122) + { + super(i, _pcls122, "continue"); + } +} diff --git a/src/modules/mocha/_cls95.java b/src/modules/mocha/_cls95.java new file mode 100644 index 0000000..db4262c --- /dev/null +++ b/src/modules/mocha/_cls95.java @@ -0,0 +1,43 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls76, _cls60, _cls101, _cls77, +// _cls69, _cls74, _cls91, _cls79, +// _cls5, _cls106, _cls82, _cls93, +// _cls90, _cls80, _cls96, _cls84, +// _cls87, _cls85, _cls100, _cls75, +// _cls99, _cls103, _cls78, _cls4, +// _cls105, _cls98, _cls97, _cls92, +// _cls104, _cls81, _cls86, _cls73, +// _cls83, _cls125, _cls94, _cls102, +// _cls88, _cls61, _cls89 + +class _cls95 extends _cls76 +{ + + _cls125 m_218125; + + _cls95(_cls125 _pcls125, _cls4 _pcls4) + { + super(_pcls4); + m_218125 = _pcls125; + } + + public void _2vV() + { + super.m_724 = super.m_724._1String4(m_218125._81vString()); + super.m_724._2vV(); + } + + public _cls61 _51v61() + { + _cls69 _lcls69 = new _cls69(m_218125._81vString(), m_218125._90v5().toString()); + _cls61 _lcls61 = super.m_724._51v61(); + return new _cls60(_lcls69._43vString(), _lcls69, _lcls61, "=", 11); + } +} diff --git a/src/modules/mocha/_cls96.java b/src/modules/mocha/_cls96.java new file mode 100644 index 0000000..49b1099 --- /dev/null +++ b/src/modules/mocha/_cls96.java @@ -0,0 +1,43 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls73, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls76, +// _cls82, _cls93, _cls90, _cls80, +// _cls84, _cls87, _cls85, _cls100, +// _cls75, _cls99, _cls103, _cls78, +// _cls4, _cls105, _cls98, _cls95, +// _cls97, _cls92, _cls104, _cls81, +// _cls86, _cls83, _cls94, _cls102, +// _cls88, _cls89, _cls122 + +class _cls96 extends _cls73 +{ + + _cls96(_cls4 _pcls4, _cls78 _pcls78, _cls122 _pcls122, _cls122 _pcls122_1) + { + super(_pcls4, _pcls78, _pcls122, _pcls122_1); + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + _85PrintStreamvV(printstream, i); + printstream.print(_cls75._50IString(i) + "while (" + super.m_834 + ")"); + if(super.m_8478 != null) + { + printstream.println(); + super.m_8478._17PrintStreamZV(printstream, i + 1, false); + return; + } else + { + printstream.println(" /* null body */ ;"); + return; + } + } +} diff --git a/src/modules/mocha/_cls97.java b/src/modules/mocha/_cls97.java new file mode 100644 index 0000000..274ab52 --- /dev/null +++ b/src/modules/mocha/_cls97.java @@ -0,0 +1,71 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls78, _cls102, _cls95, _cls77, +// _cls98, _cls92, _cls52, _cls75, +// _cls104, _cls87, _cls73, _cls2, +// _cls96, _cls103, _cls105, _cls23, +// _cls100, _cls76, _cls91, _cls4, +// _cls84, _cls88, _cls80, _cls31, +// _cls81, _cls83, _cls85, _cls90, +// _cls93, _cls79, _cls99, _cls106, +// _cls86, _cls74, _cls101, _cls82, +// _cls89, _cls94, _cls61 + +class _cls97 extends _cls78 +{ + + _cls52 m_4752; + _cls4 m_54a4[]; + + _cls97(_cls52 _pcls52, _cls4 a_pcls4[]) + { + _497475(((_cls74) (a_pcls4.length <= 0 ? ((_cls74) (_pcls52)) : ((_cls74) (a_pcls4[0]))))); + _527475(_pcls52); + m_4752 = _pcls52; + m_54a4 = a_pcls4; + } + + public int _48vI() + { + return m_4752._48vI(); + } + + public void _2vV() + { + _cls2 _lcls2 = m_4752._46v2(); + String s = _lcls2._7vString(); + int i = m_4752._34vZ() ? 0 : 1; + for(int j = i; j < m_54a4.length; j++) + m_54a4[j] = m_54a4[j]._1String4(_53StringvString(s, j - i)); + + for(int k = 0; k < m_54a4.length; k++) + m_54a4[k]._2vV(); + + } + + _cls61 _51v61() + { + _cls23 _lcls23 = new _cls23(); + for(int i = 0; i < m_54a4.length; i++) + _lcls23 = m_54a4[i]._242323(_lcls23); + + return m_4752._452361(_lcls23); + } + + public String toString() + { + return _51v61().toString(); + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_cls75._50IString(i) + this + ";"); + } +} diff --git a/src/modules/mocha/_cls98.java b/src/modules/mocha/_cls98.java new file mode 100644 index 0000000..2bd6886 --- /dev/null +++ b/src/modules/mocha/_cls98.java @@ -0,0 +1,32 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + +import java.io.PrintStream; + +// Referenced classes of package mocha: +// _cls76, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls82, +// _cls93, _cls90, _cls80, _cls96, +// _cls84, _cls87, _cls85, _cls100, +// _cls75, _cls99, _cls103, _cls78, +// _cls4, _cls105, _cls95, _cls97, +// _cls92, _cls104, _cls81, _cls86, +// _cls73, _cls83, _cls94, _cls102, +// _cls88, _cls89 + +class _cls98 extends _cls76 +{ + + _cls98(_cls4 _pcls4) + { + super(_pcls4); + } + + public void _20PrintStreamvV(PrintStream printstream, int i) + { + printstream.println(_cls75._50IString(i) + "throw " + this + ";"); + } +} diff --git a/src/modules/mocha/_cls99.java b/src/modules/mocha/_cls99.java new file mode 100644 index 0000000..74f1691 --- /dev/null +++ b/src/modules/mocha/_cls99.java @@ -0,0 +1,36 @@ +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +package modules.mocha; + + +// Referenced classes of package mocha: +// _cls92, _cls101, _cls77, _cls74, +// _cls91, _cls79, _cls106, _cls76, +// _cls82, _cls62, _cls93, _cls90, +// _cls80, _cls96, _cls84, _cls87, +// _cls85, _cls100, _cls75, _cls103, +// _cls78, _cls4, _cls105, _cls98, +// _cls95, _cls97, _cls104, _cls81, +// _cls86, _cls73, _cls83, _cls94, +// _cls102, _cls88, _cls61, _cls89 + +class _cls99 extends _cls92 +{ + + _cls99(_cls61 _pcls61, _cls74 _pcls74, String s) + { + super(_pcls61, _pcls74, s, null); + } + + public _cls61 _51v61() + { + return new _cls62(super.m_7061._43vString(), super.m_7061, super.m_32String, 26); + } + + public int _22vI() + { + return 0; + } +} diff --git a/src/modules/mocha/err.java b/src/modules/mocha/err.java new file mode 100644 index 0000000..30cd70a --- /dev/null +++ b/src/modules/mocha/err.java @@ -0,0 +1,21 @@ +/* + * aNNiMON 2010 + * For more info visit http://annimon.com/ + */ + +package modules.mocha; + +/** + * + * @author aNNiMON + */ +public class err { + + public static String error = "", last = ""; + + public static void println(String s) { + if(!last.equals(s)) error = error + s + "\n"; + System.out.println(s); + last = s; + } +} diff --git a/src/modules/playlist/M3UFileSource.java b/src/modules/playlist/M3UFileSource.java new file mode 100644 index 0000000..6edca23 --- /dev/null +++ b/src/modules/playlist/M3UFileSource.java @@ -0,0 +1,151 @@ +package modules.playlist; + +import com.one.ErrScreen; +import com.one.FileSource; +import com.one.ModuleRegistry; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.AuxClass; +import com.vmx.Locale; +import com.vmx.OutputStreamEncoder; +import com.vmx.StringEncoder; +import filemanager.Buffer; +import filemanager.main; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; +import javax.microedition.lcdui.AlertType; +import javax.microedition.lcdui.Choice; +import javax.microedition.lcdui.ChoiceGroup; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; + +public class M3UFileSource implements FileSource, CommandListener +{ + protected Object parent; + protected String filename; + + protected ChoiceGroup cgType; + + public void createFile(String filename) throws IOException + { + this.filename = filename; + + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + cgType = new ChoiceGroup(/* Locale.getString(this, Locale.FILE_TYPE) */ null, Choice.EXCLUSIVE); + + Enumeration groups = ModuleRegistry.listSimalarityGroups(); + String group; + + while(groups.hasMoreElements()) + { + group = (String)groups.nextElement(); + cgType.append(group, ModuleRegistry.getIcon((String)ModuleRegistry.listSimilars(group).nextElement())); + } + + cgType.setSelectedIndex(0, true); + + form.append(cgType); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.CANCEL, 2)); + form.setCommandListener(this); + + parent = main.dsp.getCurrent(); + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable dp) + { + if(c.getCommandType() == Command.OK) + { + try + { + if(Buffer.getSize() == 0) + { + main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.BUFFER_EMPTY), AlertType.WARNING, 3000, main.dsp.getCurrent()); + return; + } + + Vector group = AuxClass.enumerationToVector(ModuleRegistry.listSimilars(cgType.getString(cgType.getSelectedIndex())), null); + + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + + if(fc.exists()) + { + fc.truncate(0); + } + else + { + fc.create(); + } + + OutputStreamEncoder ose = new OutputStreamEncoder(fc.openOutputStream(), StringEncoder.ENC_DEFAULT); + + ose.writeBOM(); + + String disk = filename.substring(0, filename.indexOf('/')); + String path = filename.substring(0, filename.lastIndexOf('/') + 1); + + int dlen = disk.length(); + int plen = path.length(); + + Buffer.flattenBuffer(); + //Buffer.sortBuffer(); + + Enumeration buf = Buffer.getBuffer(); + String s, module; + int index; + + while(buf.hasMoreElements()) + { + s = (String)buf.nextElement(); + + index = s.lastIndexOf('.'); + + if(index >= 0) + { + module = ModuleRegistry.getModule(s.substring(index + 1)); + + if(module != null && group.contains(module)) + { + if(s.startsWith(path)) + { + ose.writeString(s.substring(plen).replace('/', '\\')); + } + else if(s.startsWith(disk)) + { + ose.writeString(s.substring(dlen).replace('/', '\\')); + } + else + { + ose.writeString(s.replace('/', '\\')); + } + + ose.writeChar('\r'); + ose.writeChar('\n'); + } + } + } + + ose.close(); + fc.close(); + + Buffer.clear(); + + main.FileSelect.showWait(filename.substring(filename.lastIndexOf('/') + 1)); + } + catch(Exception e) + { + ErrScreen.showErrMsg(ModuleRegistry.getErrCode(getClass().getName()) * 100 + 1, e); + } + } + else + { + main.dsp.setCurrent(parent); + } + } +} diff --git a/src/modules/playlist/M3UModule.java b/src/modules/playlist/M3UModule.java new file mode 100644 index 0000000..bb7143e --- /dev/null +++ b/src/modules/playlist/M3UModule.java @@ -0,0 +1,54 @@ +package modules.playlist; + +import com.one.Application; +import com.one.IniFile; +import com.one.file.Connector; +import com.one.file.FileConnection; +import com.vmx.InputStreamDecoder; +import com.one.PlayList; +import filemanager.main; +import java.io.IOException; +import java.util.Vector; + +public class M3UModule implements Application +{ + public void openFile(String filename, PlayList filelist) throws IOException + { + FileConnection fc = (FileConnection)Connector.open("file:///" + filename); + InputStreamDecoder isd = InputStreamDecoder.getFileDecoder(fc); + + String disk = filename.substring(0, filename.indexOf('/')); + String path = filename.substring(0, filename.lastIndexOf('/') + 1); + + Vector files = new Vector(); + String s; + + while((s = IniFile.readIniLine(isd)) != null) + { + if(s.startsWith("#")) + { + continue; + } + + s = s.replace('\\', '/'); + + if(s.indexOf(':') >= 0) + { + files.addElement(s); + } + else if(s.startsWith("/")) + { + files.addElement(disk + s); + } + else + { + files.addElement(path + s); + } + } + + isd.close(); + fc.close(); + + main.FileSelect.executeFile(new PlayList(files.elements()), null, main.manager.currentPanel()); + } +} diff --git a/src/modules/tbTmoEdit.java b/src/modules/tbTmoEdit.java new file mode 100644 index 0000000..0279512 --- /dev/null +++ b/src/modules/tbTmoEdit.java @@ -0,0 +1,185 @@ +package modules; // Ñ Ð´Ð¸Ñком 3 не работает! + +import com.vmx.Locale; +import com.one.file.Connector; +import filemanager.GraphicAlert; +import filemanager.cvsWait; +import filemanager.filesystem; +import filemanager.images; +import filemanager.main; +import java.io.*; +import javax.microedition.lcdui.*; + +// клаÑÑ Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ð¸ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ TMO файлов +public class tbTmoEdit + extends TextBox + implements CommandListener +{ + String filename; + String savedText = ""; + boolean newfile; + boolean readOnly; + int runpanel = -1; + + Command cmdCancel = new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 2); + Command cmdNo = new Command(Locale.getString(this, Locale.NO_CMD), Command.BACK, 1); + Command cmdYes = new Command(Locale.getString(this, Locale.YES_CMD), Command.ITEM, 2); + Command cmdSave = new Command(Locale.getString(this, Locale.SAVE_CMD), Command.ITEM, 1); + Command cmdClear = new Command(Locale.getString(this, Locale.CLEAR_CMD), Command.ITEM, 3); + + public tbTmoEdit(String filename, boolean newfile, boolean ReadOnly) + { + super(filename.substring(filename.lastIndexOf('/') + 1), "", 400, TextField.ANY); + + runpanel = main.manager.currentPanel(); + + this.newfile = newfile; + this.readOnly = ReadOnly; + this.filename = filename; + + if(!newfile) // еÑли файл не новый, читаем его + { + savedText = readTMO_UTF(filename); + this.setString(savedText); + } + + this.addCommand(cmdCancel); + this.addCommand(cmdSave); + this.addCommand(cmdClear); + this.setCommandListener(this); + } + + /** + * + * @param command Command + * @param displayable Displayable + */ + public void commandAction(Command command, Displayable displayable) + { + if(command == cmdCancel) + { + if(this.getString().compareTo(savedText) == 0 || readOnly) // не изменÑлоÑÑŒ или readonly + back(); + else + { + GraphicAlert al = new GraphicAlert(Locale.getString(this, Locale.CONFIRMATION), Locale.getString(this, Locale.FILE_NOT_SAVED_EXIT), images.getAlertIcon(AlertType.CONFIRMATION), AlertType.CONFIRMATION); + al.addCommand(cmdYes); + al.addCommand(cmdNo); + al.setCommandListener(this); + main.dsp.setCurrent(al, this); + } + } + else if(command == cmdSave) + { + if(!readOnly) + { + // запиÑÑŒ + saveTMO_UTF(filename, this.getString()); + savedText = this.getString(); + GraphicAlert al = new GraphicAlert(Locale.getString(this, Locale.DONE), Locale.getString(this, Locale.SAVED), images.getAlertIcon(AlertType.INFO), AlertType.INFO); + al.setTimeout(1500); + main.dsp.setCurrent(al, this); + } + else + { + // только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ + GraphicAlert al = new GraphicAlert(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.FILE_NOT_SAVED), images.getAlertIcon(AlertType.ERROR), AlertType.ERROR); + al.setTimeout(1500); + main.dsp.setCurrent(al, this); + } + } + // очиÑтка + else if(command == cmdClear) + this.setString(""); + // выход + else if(command == cmdYes) + back(); + // отмена + else if(command == cmdNo) + main.dsp.setCurrent(this); + } + + private void back() + { + if(newfile) // новый файл перечитываем ФС + { + cvsWait.start(null, runpanel); + } + else + { + main.manager.setCurrent(main.FileSelect, runpanel); + } + + runpanel = -1; + } + + /** + * ЗапиÑÑŒ TMO файла + * @param filename String + */ + public static void saveTMO_UTF(String filename, String str) + { + int length = str.length(); + int ksum = length; + char curr_ch; + byte byte_1, byte_2; + filesystem.deleteFile(filename, false, null); + filesystem.makeNewFile(filename, ""); + try + { + DataOutputStream dos = Connector.openDataOutputStream("file:///" + filename); + dos.writeByte(length); + dos.writeByte(length >> 8); + for(int i = 0; i < length; i++) + { + curr_ch = str.charAt(i); // ÑохранÑем как тмо файл + byte_1 = (byte)(curr_ch); + byte_2 = (byte)(curr_ch >> 8); + ksum = ksum ^ curr_ch; + dos.writeByte(byte_1); + dos.writeByte(byte_2); + } + dos.writeByte(ksum); + dos.flush(); + dos.close(); + } + catch(IOException ioe) + { + //System.out.println ("Error save tmo file"); + } + } + + /** + * Чтение TMO файла + * + * @param filename String + * @return String + */ + public static String readTMO_UTF(String filename) + { + StringBuffer str = new StringBuffer(); + char ch; + byte byte_1, byte_2; + try + { + DataInputStream dis = Connector.openDataInputStream("file:///" + filename); + int length = (dis.readUnsignedByte() + dis.readUnsignedByte() * 256) * 2; + for(int i = 0; i < length; i = i + 2) + { + byte_1 = dis.readByte(); + byte_2 = dis.readByte(); + ch = (char)((char)(byte_1) | (char)(byte_2 << 8)); + str.append(ch); + } + dis.close(); + } + catch(IOException ioe) + { + //System.out.println ("Error read tmo file"); + } + finally + { + return str.toString(); + } + } +} diff --git a/src/modules/text/TextFileSource.java b/src/modules/text/TextFileSource.java new file mode 100644 index 0000000..105c33a --- /dev/null +++ b/src/modules/text/TextFileSource.java @@ -0,0 +1,14 @@ +package modules.text; + +import com.one.FileSource; +import com.vmx.StringEncoder; +import filemanager.main; + +public class TextFileSource implements FileSource +{ + public void createFile(String filename) + { + main.dsp.setCurrent(cvsTextView.getInstance()); + cvsTextView.getInstance().openNewFile(filename, null, StringEncoder.ENC_UTF8); + } +} \ No newline at end of file diff --git a/src/modules/text/TextForms.java b/src/modules/text/TextForms.java new file mode 100644 index 0000000..795221e --- /dev/null +++ b/src/modules/text/TextForms.java @@ -0,0 +1,524 @@ +package modules.text; + +import com.vmx.Locale; +import com.vmx.StringEncoder; +import filemanager.options; +import javax.microedition.lcdui.Choice; +import javax.microedition.lcdui.ChoiceGroup; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Font; +import javax.microedition.lcdui.Form; +import javax.microedition.lcdui.Gauge; +import javax.microedition.lcdui.Item; +import javax.microedition.lcdui.ItemStateListener; +import javax.microedition.lcdui.StringItem; +import javax.microedition.lcdui.TextField; + +/** + * Форма перехода на позицию в текÑте + */ +class frmSeek extends Form implements ItemStateListener +{ + protected Gauge gSeek; + protected TextField tfLineNum; + + public frmSeek(CommandListener cl) + { + super(""); + setTitle(Locale.getString(this, Locale.GOTO_CMD)); + + gSeek = new Gauge("0%", true, 100, 0); + + tfLineNum = new TextField(Locale.getString(this, Locale.LINE_NUMBER), "", 20, TextField.NUMERIC); + + append(gSeek); + append(tfLineNum); + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 2)); + + setCommandListener(cl); + setItemStateListener(this); + } + + public int getValue() + { + return gSeek.getValue(); + } + + public int getLineNum() + { + try + { + return Integer.parseInt(tfLineNum.getString()); + } + catch(NumberFormatException nfe) + { + return 0; + } + } + + public void setValue(int value) + { + gSeek.setValue(value); + gSeek.setLabel(Integer.toString(value) + "%"); // Integer.toString(scrStart) + "/" + Integer.toString(bdis.getCapacity()); + + tfLineNum.setString(""); + } + + public void itemStateChanged(Item item) + { + gSeek.setLabel(Integer.toString(gSeek.getValue()) + "%"); + } +} + +/** + * Форма Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð² шрифта + */ +class frmFont extends Form +{ + protected ChoiceGroup cgSize, cgFace, cgStyle; + + public frmFont(CommandListener cl) + { + super(""); + setTitle(Locale.getString(this, Locale.FONT_CMD)); + + cgSize = new ChoiceGroup(Locale.getString(this, Locale.SIZE), ChoiceGroup.EXCLUSIVE); + + cgSize.append(Locale.getString(this, Locale.SIZE_SMALL), null); + cgSize.append(Locale.getString(this, Locale.SIZE_MEDIUM), null); + cgSize.append(Locale.getString(this, Locale.SIZE_LARGE), null); + + cgFace = new ChoiceGroup(Locale.getString(this, Locale.FONT_FACE), ChoiceGroup.EXCLUSIVE); + + cgFace.append(Locale.getString(this, Locale.FONT_MONOSPACE), null); + cgFace.append(Locale.getString(this, Locale.FONT_PROPORTIONAL), null); + cgFace.append(Locale.getString(this, Locale.FONT_SYSTEM), null); + + cgStyle = new ChoiceGroup(Locale.getString(this, Locale.FONT_STYLE), ChoiceGroup.MULTIPLE); + + cgStyle.append(Locale.getString(this, Locale.FONT_BOLD), null); + cgStyle.append(Locale.getString(this, Locale.FONT_ITALIC), null); + cgStyle.append(Locale.getString(this, Locale.FONT_UNDERLINED), null); + + append(cgSize); + append(cgFace); + append(cgStyle); + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 2)); + + setCommandListener(cl); + } + + public void setFont(Font f) + { + switch(f.getSize()) + { + case Font.SIZE_SMALL: + cgSize.setSelectedIndex(0, true); + break; + + case Font.SIZE_MEDIUM: + cgSize.setSelectedIndex(1, true); + break; + + case Font.SIZE_LARGE: + cgSize.setSelectedIndex(2, true); + break; + } + + switch(f.getFace()) + { + case Font.FACE_MONOSPACE: + cgFace.setSelectedIndex(0, true); + break; + + case Font.FACE_PROPORTIONAL: + cgFace.setSelectedIndex(1, true); + break; + + case Font.FACE_SYSTEM: + cgFace.setSelectedIndex(2, true); + break; + } + + cgStyle.setSelectedIndex(0, f.isBold()); + cgStyle.setSelectedIndex(1, f.isItalic()); + cgStyle.setSelectedIndex(2, f.isUnderlined()); + } + + public Font getFont() + { + int face = 0; + + switch(cgFace.getSelectedIndex()) + { + case 0: + face = Font.FACE_MONOSPACE; + break; + + case 1: + face = Font.FACE_PROPORTIONAL; + break; + + case 2: + face = Font.FACE_SYSTEM; + break; + } + + int style = 0; + + if(cgStyle.isSelected(0)) + { + style |= Font.STYLE_BOLD; + } + + if(cgStyle.isSelected(1)) + { + style |= Font.STYLE_ITALIC; + } + + if(cgStyle.isSelected(2)) + { + style |= Font.STYLE_UNDERLINED; + } + + int size = 0; + + switch(cgSize.getSelectedIndex()) + { + case 0: + size = Font.SIZE_SMALL; + break; + + case 1: + size = Font.SIZE_MEDIUM; + break; + + case 2: + size = Font.SIZE_LARGE; + break; + } + + return Font.getFont(face, style, size); + } +} + +/** + * Форма Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° кодировки текÑта + */ +class frmEnc extends Form +{ + protected ChoiceGroup cgEnc; + + public frmEnc(CommandListener cl) + { + super(""); + setTitle(Locale.getString(this, Locale.ENCODING_CMD)); + + cgEnc = new ChoiceGroup(null, ChoiceGroup.EXCLUSIVE); + + cgEnc.append(StringEncoder.ENC_NAME_UTF8, null); + cgEnc.append(StringEncoder.ENC_NAME_UTF16N, null); + cgEnc.append(StringEncoder.ENC_NAME_UTF16L, null); + + for(int i = 0; i < StringEncoder.encnames.length; i++) + { + cgEnc.append(StringEncoder.encnames[i], null); + } + + append(cgEnc); + + addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 2)); + + setCommandListener(cl); + } + + public void setEncoding(int enc) + { + switch(enc) + { + case StringEncoder.ENC_UTF8: + cgEnc.setSelectedIndex(0, true); + break; + + case StringEncoder.ENC_UTF16N: + cgEnc.setSelectedIndex(1, true); + break; + + case StringEncoder.ENC_UTF16L: + cgEnc.setSelectedIndex(2, true); + break; + + default: + cgEnc.setSelectedIndex(enc + 3, true); + } + } + + public int getEncoding() + { + switch(cgEnc.getSelectedIndex()) + { + case 0: + return StringEncoder.ENC_UTF8; + + case 1: + return StringEncoder.ENC_UTF16N; + + case 2: + return StringEncoder.ENC_UTF16L; + + default: + return cgEnc.getSelectedIndex() - 3; + } + } +} + +/** + * Форма ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñ‚ÐµÐºÑта. + * ОтображаетÑÑ Ð¿Ñ€Ð¸ выборе пункта меню "Сохранить как". + */ +class frmSave extends Form +{ + protected TextField tfFileName; + protected ChoiceGroup cgEnc; + protected ChoiceGroup cgBOM; + + public frmSave(CommandListener cl) + { + super(""); + setTitle(Locale.getString(this, Locale.SAVE_AS_CMD)); + + tfFileName = new TextField(Locale.getString(this, Locale.NAME), "", 256, TextField.ANY); + + cgEnc = new ChoiceGroup(Locale.getString(this, Locale.ENCODING_CMD), ChoiceGroup.EXCLUSIVE); + + cgEnc.append(StringEncoder.ENC_NAME_UTF8, null); + cgEnc.append(StringEncoder.ENC_NAME_UTF16N, null); + cgEnc.append(StringEncoder.ENC_NAME_UTF16L, null); + + for(int i = 0; i < StringEncoder.encnames.length; i++) + { + cgEnc.append(StringEncoder.encnames[i], null); + } + + cgBOM = new ChoiceGroup(null, ChoiceGroup.MULTIPLE); + cgBOM.append(Locale.getString(this, Locale.USE_UTF_BOM), null); + + append(tfFileName); + append(cgEnc); + append(cgBOM); + + addCommand(new Command(Locale.getString(this, Locale.SAVE_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 2)); + + setCommandListener(cl); + } + + /** + * УÑтановка имени файла. + */ + public void setFileName(String fname) + { + tfFileName.setString(fname); + } + + /** + * Получение имени файла. + */ + public String getFileName() + { + return tfFileName.getString(); + } + + public void setEncoding(int enc) + { + switch(enc) + { + case StringEncoder.ENC_UTF8: + cgEnc.setSelectedIndex(0, true); + break; + + case StringEncoder.ENC_UTF16N: + cgEnc.setSelectedIndex(1, true); + break; + + case StringEncoder.ENC_UTF16L: + cgEnc.setSelectedIndex(2, true); + break; + + default: + cgEnc.setSelectedIndex(enc + 3, true); + } + } + + public int getEncoding() + { + switch(cgEnc.getSelectedIndex()) + { + case 0: + return StringEncoder.ENC_UTF8; + + case 1: + return StringEncoder.ENC_UTF16N; + + case 2: + return StringEncoder.ENC_UTF16L; + + default: + return cgEnc.getSelectedIndex() - 3; + } + } + + public void setUseBOM(boolean value) + { + cgBOM.setSelectedIndex(0, value); + } + + public boolean getUseBOM() + { + return cgBOM.isSelected(0); + } +} + +class frmFind extends Form +{ + protected TextField tfText; + protected TextField tfReplace; + protected ChoiceGroup cgIgnoreCase; + protected StringItem siMatches; + + public frmFind(CommandListener cl) + { + super(""); + setTitle(Locale.getString(this, Locale.MENU_SEARCH)); + + tfText = new TextField(Locale.getString(this, Locale.FIND_CMD), "", TextOptions.textBufSize, TextField.ANY); + tfReplace = new TextField(Locale.getString(this, Locale.REPLACE_WITH), "", TextOptions.textBufSize, TextField.ANY); + + cgIgnoreCase = new ChoiceGroup(null, Choice.MULTIPLE); + cgIgnoreCase.append(Locale.getString(this, Locale.IGNORE_CASE), null); + + siMatches = new StringItem(null, ""); + + append(tfText); + append(tfReplace); + append(cgIgnoreCase); + append(siMatches); + + addCommand(new Command(Locale.getString(this, Locale.FIND_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.REPLACE_CMD), Command.OK, 2)); + addCommand(new Command(Locale.getString(this, Locale.REPLACE_ALL_CMD), Command.OK, 3)); + addCommand(new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 4)); + + setCommandListener(cl); + } + + public void setText(String text) + { + tfText.setString(text); + } + + public String getText() + { + return tfText.getString(); + } + + public void setReplace(String replace) + { + tfReplace.setString(replace); + } + + public String getReplace() + { + return tfReplace.getString(); + } + + public void setIgnoreCase(boolean ignoreCase) + { + cgIgnoreCase.setSelectedIndex(0, ignoreCase); + } + + public boolean getIgnoreCase() + { + return cgIgnoreCase.isSelected(0); + } + + public void setMatchesCount(int matches) + { + if(matches > 0) + { + siMatches.setText(Integer.toString(matches) + " " + Locale.getString(this, Locale.SEARCH_MATCHES)); + } + else + { + siMatches.setText(""); + } + } +} + +class frmRegExp extends Form +{ + protected TextField tfText; + protected TextField tfReplace; + protected ChoiceGroup cgFlags; + + public frmRegExp(CommandListener cl) + { + super(""); + setTitle(Locale.getString(this, Locale.REG_EXP_CMD)); + + tfText = new TextField(Locale.getString(this, Locale.FIND_CMD), "", TextOptions.textBufSize, TextField.ANY); + tfReplace = new TextField(Locale.getString(this, Locale.REPLACE_WITH), "", TextOptions.textBufSize, TextField.ANY); + + cgFlags = new ChoiceGroup(null, Choice.MULTIPLE); + + cgFlags.append(Locale.getString(this, Locale.IGNORE_CASE), null); + cgFlags.append(Locale.getString(this, Locale.RE_MATCH_MULTILINE), null); + cgFlags.append(Locale.getString(this, Locale.RE_REPLACE_BACKREF), null); + + append(tfText); + append(tfReplace); + append(cgFlags); + + //addCommand(new Command(Locale.getString(this, Locale.REPLACE_CMD), Command.OK, 1)); + addCommand(new Command(Locale.getString(this, Locale.REPLACE_ALL_CMD), Command.OK, 2)); + addCommand(new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 3)); + + setCommandListener(cl); + } + + public void setText(String text) + { + tfText.setString(text); + } + + public String getText() + { + return tfText.getString(); + } + + public void setReplace(String replace) + { + tfReplace.setString(replace); + } + + public String getReplace() + { + return tfReplace.getString(); + } + + public void setFlags(int index, boolean ignoreCase) + { + cgFlags.setSelectedIndex(index, ignoreCase); + } + + public boolean getFlags(int index) + { + return cgFlags.isSelected(index); + } +} \ No newline at end of file diff --git a/src/modules/text/TextModule.java b/src/modules/text/TextModule.java new file mode 100644 index 0000000..e08c0da --- /dev/null +++ b/src/modules/text/TextModule.java @@ -0,0 +1,12 @@ +package modules.text; + +import com.one.Application; +import com.one.PlayList; + +public class TextModule implements Application +{ + public void openFile(String filename, PlayList filelist) + { + cvsTextView.getInstance().openFile(filename); + } +} diff --git a/src/modules/text/TextOptions.java b/src/modules/text/TextOptions.java new file mode 100644 index 0000000..9315551 --- /dev/null +++ b/src/modules/text/TextOptions.java @@ -0,0 +1,189 @@ +package modules.text; + +import com.one.ModuleRegistry; +import com.one.OptionStorage; +import com.vmx.Locale; +import filemanager.cvsContextMenu; +import filemanager.main; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import javax.microedition.lcdui.Choice; +import javax.microedition.lcdui.ChoiceGroup; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Font; +import javax.microedition.lcdui.Form; +import javax.microedition.lcdui.TextField; + +public class TextOptions implements CommandListener, OptionStorage +{ + public static final int OPTIONS_VERSION = 1; + + public static int textFontFace = Font.FACE_SYSTEM; + public static int textFontSize = Font.SIZE_SMALL; + public static int textFontStyle = Font.STYLE_PLAIN; + public static boolean showCR = false; + public static boolean showLF = false; + public static boolean substTAB = true; + public static int textBoxTitle = 0; + public static int textBufSize = 8192; + public static boolean useUTFBOM = true; + public static boolean textPageScroll = false; + + protected Object parent; + + protected ChoiceGroup cgText; + protected ChoiceGroup cgTextBoxTitle; + + protected TextField tfTextBufSize; + + public void showEditor(Object parent) + { + this.parent = parent; + + restoreOptions(); + + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + // *** ÐаÑтройки текÑтового редактора *** + cgText = new ChoiceGroup(Locale.getString(this, Locale.PREF_TEXT_SETUP), Choice.MULTIPLE); + + // Показывать CR + cgText.append(Locale.getString(this, Locale.PREF_SHOW_CR), null); + cgText.setSelectedIndex(0, showCR); + + // Показывать LF + cgText.append(Locale.getString(this, Locale.PREF_SHOW_LF), null); + cgText.setSelectedIndex(1, showLF); + + // ЗаменÑÑ‚ÑŒ табулÑцию пробелами + cgText.append(Locale.getString(this, Locale.PREF_SUBST_TAB), null); + cgText.setSelectedIndex(2, substTAB); + + // ПоÑÑ‚Ñ€Ð¾Ñ‡Ð½Ð°Ñ / поÑÑ‚Ñ€Ð°Ð½Ð¸Ñ‡Ð½Ð°Ñ Ð¿Ñ€Ð¾ÐºÑ€ÑƒÑ‚ÐºÐ° + cgText.append(Locale.getString(this, Locale.PREF_PAGE_SCROLL), null); + cgText.setSelectedIndex(3, textPageScroll); + + // *** Заколовок текÑтового окна *** + cgTextBoxTitle = new ChoiceGroup(Locale.getString(this, Locale.PREF_TEXTBOX_TITLE), Choice.EXCLUSIVE); + + cgTextBoxTitle.append(Locale.getString(this, Locale.NORMAL), null); + cgTextBoxTitle.append(Locale.getString(this, Locale.TICKER), null); + cgTextBoxTitle.append(Locale.getString(this, Locale.DISABLED), null); + + cgTextBoxTitle.setSelectedIndex(textBoxTitle, true); + + // Размер текÑтового буфера + tfTextBufSize = new TextField(Locale.getString(this, Locale.PREF_TEXT_BUFFER_SIZE), Integer.toString(textBufSize), 20, TextField.NUMERIC); + + form.append(cgText); + form.append(cgTextBoxTitle); + form.append(tfTextBufSize); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 2)); + + form.setCommandListener(this); + + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable d) + { + if(c.getCommandType() == Command.OK) + { + showCR = cgText.isSelected(0); + showLF = cgText.isSelected(1); + substTAB = cgText.isSelected(2); + textPageScroll = cgText.isSelected(3); + + textBoxTitle = cgTextBoxTitle.getSelectedIndex(); + + textBufSize = Integer.parseInt(tfTextBufSize.getString()); + + if(textBufSize < 1024) + { + textBufSize = 1024; + } + + saveOptions(); + } + + main.dsp.setCurrent(parent); + } + + public void restoreOptions() + { + try + { + byte[] data = ModuleRegistry.getModuleData(getClass().getName()); + + if(data == null || data.length == 0) + { + return; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data)); + + if(dis.readInt() != OPTIONS_VERSION) + { + dis.close(); + return; + } + + textFontFace = dis.readInt(); + textFontSize = dis.readInt(); + textFontStyle = dis.readInt(); + showCR = dis.readBoolean(); + showLF = dis.readBoolean(); + substTAB = dis.readBoolean(); + textBoxTitle = dis.readInt(); + textBufSize = dis.readInt(); + useUTFBOM = dis.readBoolean(); + textPageScroll = dis.readBoolean(); + + cvsContextMenu.readKeyConfig(cvsTextView.menuKeyConfig, dis); + + dis.close(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + + public void saveOptions() + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(OPTIONS_VERSION); + dos.writeInt(textFontFace); + dos.writeInt(textFontSize); + dos.writeInt(textFontStyle); + dos.writeBoolean(showCR); + dos.writeBoolean(showLF); + dos.writeBoolean(substTAB); + dos.writeInt(textBoxTitle); + dos.writeInt(textBufSize); + dos.writeBoolean(useUTFBOM); + dos.writeBoolean(textPageScroll); + + cvsContextMenu.writeKeyConfig(cvsTextView.menuKeyConfig, dos); + + byte[] data = baos.toByteArray(); + dos.close(); + + ModuleRegistry.setModuleData(getClass().getName(), data); + } + catch(Exception e) + { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/modules/text/cvsTextView.java b/src/modules/text/cvsTextView.java new file mode 100644 index 0000000..6db4127 --- /dev/null +++ b/src/modules/text/cvsTextView.java @@ -0,0 +1,2617 @@ +package modules.text; + +import javax.microedition.lcdui.*; +import java.io.*; +import com.vmx.*; +import com.one.*; +import java.util.Vector; + +import com.one.file.*; +import filemanager.ColorScheme; +import filemanager.GraphicAlert; +import filemanager.MenuListener; +import filemanager.TemplateManager; +import filemanager.cvsContextMenu; +import filemanager.cvsWait; +import filemanager.filesystem; +import filemanager.images; +import filemanager.main; +import filemanager.options; +import javax.microedition.io.file.IllegalModeException; +import org.apache.regexp.RE; + +/** + * КлаÑÑ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра и Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑта + */ +public class cvsTextView extends gkcCanvas implements CommandListener, MenuListener +{ + // Чтение и запиÑÑŒ текÑта + private RandomAccessInputStream rais = null; + private BufDataInputStream bdis = null; + private InputStreamDecoder isd = null; + + /** + * ИÑÑ‚Ð¾Ñ€Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹, вноÑимых в текÑÑ‚. + * Вектор хранит потоки, из которых производитÑÑ Ñ‡Ñ‚ÐµÐ½Ð¸Ðµ текÑта. + * Первый поток - оригинальный, Ñледующие - потоки Ñ Ð¿Ð¾Ð´Ñтановкой, + * где ÐºÐ°Ð¶Ð´Ð°Ñ Ð¿Ð¾Ð´Ñтановка ÑоответÑтвует изменениÑм в текÑте. + * Каждый Ñледующий поток в векторе ÑоздаетÑÑ Ð½Ð° оÑнове предыдущего, + * таким образом хранитÑÑ Ð¸ÑÑ‚Ð¾Ñ€Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñтью Ð¿ÐµÑ€ÐµÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾ ней. + */ + private Vector editHistory = null; + private int editIndex = -1; + + private int offset; + + private int enc; + + private int scrStart, scrEnd; + + // ОтриÑовка текÑта и заголовок + private String caption = ""; + private int clockw, captionw, captionx; + private Image icon; + + private int linesPerScreen; + + private int w, h; + + private Font fntText; + private int fntTextHeight; + private FontWidthCache fwc; + + private String lines[]; + private int lineposes[]; + + private int maxStrWidth; + + // ПолноÑкранный режим + private boolean fsmode; + private int header, footer; + + // Правка текÑта + private int selStart; + private int editStart, editEnd; + + private TextBox tb; + private String edittext; + private int esclevel; + + private List lstTextCommands; + + //private FileConnection fc; + private boolean fileUsed, newFile; + private boolean rescanAfterExit; + private boolean closing; + private String fname; + + /* показывать Ñамую нижнюю, возможно + не полноÑтью видимую Ñтроку */ + public static final boolean showLastLine = false; + + private final Command cmdYes = new Command(Locale.getString(this, Locale.YES_CMD), Command.OK, 1); + private final Command cmdNo = new Command(Locale.getString(this, Locale.NO_CMD), Command.BACK, 2); + + private final Command cmdOK = new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1); + private final Command cmdOptions = new Command(Locale.getString(this, Locale.OPTIONS_CMD), Command.OK, 2); + + private final Command cmdTemplate = new Command(Locale.getString(this, Locale.TEMPLATES_CMD), Command.OK, 2); + private final Command cmdClear = new Command(Locale.getString(this, Locale.CLEAR_CMD), Command.OK, 3); + private final Command cmdEscape = new Command(Locale.getString(this, Locale.ESCAPE_CMD), Command.OK, 4); + private final Command cmdUnescape = new Command(Locale.getString(this, Locale.UNESCAPE_CMD), Command.OK, 5); + private final Command cmdRegExp = new Command(Locale.getString(this, Locale.REG_EXP_CMD), Command.OK, 6); + private final Command cmdBack = new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 7); + private final Command cmdCancel = new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.CANCEL, 8); + + private int runpanel; + + private int keyHeld; + private boolean keyReleaseAllowed = false; + + private frmSeek seekForm; + private frmFont fontForm; + private frmEnc encForm; + private frmSave saveForm; + private frmFind findForm; + private frmRegExp regExpForm; + + private GraphicAlert alConfirmSave, + alSearchEOF; + + private String searchText = ""; + private boolean searchIgnoreCase = true; + + private String searchReplaceText = ""; + private boolean searchReplace = false; + + private cvsContextMenu mn; + + private List lstTemplates; + private List lstEncodings; + + private static cvsTextView instance; + + public static void loadInstance() + { + if(instance == null) + { + instance = new cvsTextView(); + } + } + + public static cvsTextView getInstance() + { + loadInstance(); + return instance; + } + + /** + * КонÑтруктор + */ + public cvsTextView() + { + rescanAfterExit = false; + closing = false; + + setFullScreenMode(true); + w = getWidth(); + h = getHeight(); + + setFont(Font.getFont(TextOptions.textFontFace, TextOptions.textFontStyle, TextOptions.textFontSize)); + + selStart = -1; + + // Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ñ‹Ñ… i/o + rais = null; + bdis = null; + isd = null; + + seekForm = new frmSeek(this); + fontForm = new frmFont(this); + encForm = new frmEnc(this); + saveForm = new frmSave(this); + findForm = new frmFind(this); + regExpForm = new frmRegExp(this); + + alConfirmSave = new GraphicAlert(Locale.getString(this, Locale.CONFIRMATION), Locale.getString(this, Locale.CONFIRM_SAVE), images.getAlertIcon(AlertType.CONFIRMATION), AlertType.CONFIRMATION); + alConfirmSave.setTimeout(Alert.FOREVER); + alConfirmSave.addCommand(cmdYes); + alConfirmSave.addCommand(cmdNo); + alConfirmSave.addCommand(cmdBack); + alConfirmSave.setCommandListener(this); + + alSearchEOF = new GraphicAlert(Locale.getString(this, Locale.MENU_SEARCH), Locale.getString(this, Locale.SEARCH_EOF_QUESTION), images.getAlertIcon(AlertType.CONFIRMATION), AlertType.CONFIRMATION); + alSearchEOF.setTimeout(Alert.FOREVER); + alSearchEOF.addCommand(cmdYes); + alSearchEOF.addCommand(cmdNo); + alSearchEOF.setCommandListener(this); + + mn = new cvsContextMenu(menuData, menuKeyConfig, menuKeyAllowed); + mn.setListener(this); + + runpanel = -1; + } + + /** + * УÑтановить шрифт Ð´Ð»Ñ Ñ‚ÐµÐºÑта + */ + public void setFont(Font font) + { + TextOptions.textFontFace = font.getFace(); + TextOptions.textFontSize = font.getSize(); + TextOptions.textFontStyle = font.getStyle(); + + fntText = font; + fntTextHeight = fntText.getHeight() + 1; + fwc = FontWidthCache.getCache(fntText); + + clockw = fwc.stringWidth(AuxClass.getCurrentTime()); + captionw = w - images.iconWidth - clockw - 10; + + setFSMode(fsmode); + } + + /** + * УÑтановить полноÑкранный / не полноÑкранный режим + */ + public void setFSMode(boolean nm) + { + fsmode = nm; + + if(fsmode) + { + header = footer = 0; + linesPerScreen = h / fntTextHeight; + + maxStrWidth = w - 4; + } + else + { + header = Math.max(images.iconHeight + 4, fntTextHeight + 1); + footer = 8; + + linesPerScreen = (h - header - footer - 2) / fntTextHeight; + + maxStrWidth = w - 7; + } + + //linesPerScreen = (h - header - footer) / fntTextHeight; + + /* выÑота полоÑÑ‹ прокрутки */ + slall = h - header - footer; + + if(showLastLine) + { + linesPerScreen += 1; + } + + lines = new String[linesPerScreen]; + lineposes = new int[linesPerScreen + 1]; + + if(isd != null) + { + try + { + bdis.setPosition(scrStart); + readScreen(true); + } + catch(IOException ioe) + { + ErrScreen.showErrMsg(18, ioe); + } + } + + repaint(); + } + + protected void initPanels() + { + if(runpanel < 0) + { + runpanel = main.manager.currentPanel(); + } + + main.manager.setCurrent(this, runpanel); + main.manager.updateAssociation(runpanel, fname); + main.manager.changePanel(runpanel); + } + + /** + * Открыть входной поток + */ + public boolean openStream(InputStream is, String caption) + { + closeStream(); + + fileUsed = false; + newFile = false; + rescanAfterExit = false; + + selStart = -1; + clearScreen(); + + if(caption != null) + { + this.caption = caption; + } + else + { + this.caption = ""; + } + + icon = ModuleRegistry.getIcon(caption.substring(caption.lastIndexOf('.') + 1)); + + if(icon == null) + { + icon = ModuleRegistry.getIcon("txt"); + } + + initPanels(); + + int bmpos = options.getBookMark(this.caption); + + try + { + rais = new BufferedInputStream(is); + + enc = InputStreamDecoder.detectEncoding(rais, options.textEnc); + offset = rais.getPosition(); + rais.reset(); // Ñигнатуру потом пропуÑкаем отдельно (еÑли она еÑÑ‚ÑŒ) + + editHistory = new Vector(); + editHistory.addElement(rais); + editIndex = 0; + + bdis = new BufDataInputStream(rais); + isd = new InputStreamDecoder(bdis, enc); + + if(bmpos < offset) + { + bmpos = offset; + } + + bdis.setPosition(bmpos); + readScreen(true); + repaint(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(19, e); + return false; + } + + return true; + } + + /** + * ОÑознать, в какой кодировке is, запиÑать кодировку в enc, + * позиционировать is на начало текÑта и вернуть Ñто Ñмещение + */ + /* + public int detectEncoding(InputStream is) throws IOException + { + enc = "windows-1251"; + + int off = 0; + + is.mark(10); + + if(is.available() >= 3 && is.read() == 0xEF && is.read() == 0xBB && is.read() == 0xBF) // UTF-8 BOM signature + { + enc = "UTF-8"; + off = 3; + } + else + { + is.reset(); + } + + return off; + } + */ + + /** + * Открыть файл через FileConnection + */ + public boolean openFile(String filename) + { + closeStream(); + + fileUsed = true; + newFile = false; + rescanAfterExit = false; + + selStart = -1; + clearScreen(); + + this.fname = filename; + caption = fname.substring(fname.lastIndexOf('/') + 1); + + icon = ModuleRegistry.getIcon(caption.substring(caption.lastIndexOf('.') + 1)); + + if(icon == null) + { + icon = images.getIcon(images.iFile); + } + + initPanels(); + + int bmpos = options.getBookMark(caption); + + try + { + FileConnection fc = (FileConnection)Connector.open("file:///" + fname, Connector.READ); + + rais = new FileInputStream(fc); // BufferedInputStream(fc.openInputStream()); + //RandomAccessInputStream is = new BufferedInputStream(fc.openInputStream()); + + enc = InputStreamDecoder.detectEncoding(rais, options.textEnc); + offset = rais.getPosition(); + rais.reset(); // Ñигнатуру потом пропуÑкаем отдельно (еÑли она еÑÑ‚ÑŒ) + + editHistory = new Vector(); + editHistory.addElement(rais); + editIndex = 0; + + bdis = new BufDataInputStream(rais); + isd = new InputStreamDecoder(bdis, enc); + + if(bmpos < offset) + { + bmpos = offset; + } + + bdis.setPosition(bmpos); + readScreen(true); + repaint(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(116, e); + fileUsed = false; + + return false; + } + + return true; + } + + /** + * Редактировать новый файл. + * ОткрываетÑÑ Ð²Ñ…Ð¾Ð´Ð½Ð¾Ð¹ поток из маÑÑива, на оÑнове которого + * впоÑледÑтвие могут ÑоздаватьÑÑ Ð¿Ð¾Ñ‚Ð¾ÐºÐ¸ Ñ Ð·Ð°Ð¼ÐµÐ½Ð¾Ð¹. + * МаÑÑив может Ñодержать BOM Ñигнатуру (Ð´Ð»Ñ Ð®Ð½Ð¸ÐºÐ¾Ð´Ð°), + * а также некоторый начальный текÑÑ‚ в заданной кодировке. + * Ð’ Ñтом режиме пункты "Сохранить" и "Сохранить как" Ñквивалентны. + */ + public boolean openNewFile(String filename, String text, int newEnc) + { + closeStream(); + + fileUsed = true; + newFile = true; + rescanAfterExit = true; + + selStart = -1; + clearScreen(); + + this.fname = filename; + caption = fname.substring(fname.lastIndexOf('/') + 1); + + icon = ModuleRegistry.getIcon(caption.substring(caption.lastIndexOf('.') + 1)); + + if(icon == null) + { + icon = images.getIcon(images.iFile); + } + + initPanels(); + + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStreamEncoder ose = new OutputStreamEncoder(baos, newEnc); + + if(text != null) + { + for(int i = 0; i < text.length(); i++) + { + ose.writeChar(text.charAt(i)); + } + } + + baos.flush(); + + rais = new BufferedInputStream(baos.toByteArray()); + + ose.close(); + ose = null; + baos = null; + + enc = newEnc; + offset = 0; + + editHistory = new Vector(); + editHistory.addElement(rais); + editIndex = 0; + + bdis = new BufDataInputStream(rais); + isd = new InputStreamDecoder(bdis, enc); + + bdis.setPosition(offset); + readScreen(true); + + editText(); + } + catch(Exception e) + { + ErrScreen.showErrMsg(117, e); + fileUsed = false; + + return false; + } + + return true; + } + + /** + * Закрыть входной поток + */ + public void closeStream() + { + try + { + if(isd != null) + { + options.setBookMark(caption, scrStart); + + rais = (RandomAccessInputStream)editHistory.elementAt(0); + FileConnection fc = null; + + if(rais instanceof FileInputStream) + { + fc = ((FileInputStream)rais).getBaseConnection(); + } + + isd.close(); + isd = null; + bdis = null; + rais = null; + + if(fc != null) + { + fc.close(); + } + + editHistory = null; + editIndex = -1; + } + } + catch(Exception e) + { + ErrScreen.showErrMsg(20, e); + } + } + + /** + * Прочитать Ñтроку из потока + */ + public String readString(boolean wordwrap) + { + StringBuffer s = new StringBuffer(); + String res; + + int afterspace = -1; + int cut = 0; + int strwidth = 0; + char c; + + try + { + if(bdis == null || bdis.available() <= 0) + { + return null; + } + + if(bdis.getPosition() < offset) + { + bdis.setPosition(offset); + } + + try + { + do + { + /* Ñчитываем Ñимвол */ + c = isd.readChar(); + + /* еÑли Ñто не Ñимвол конца Ñтроки и не конец файла, + то добавлÑем его к Ñтроке и обновлÑем ее длину. + Ð’ противном Ñлучае Ñообщаем, что Ð¿ÐµÑ€ÐµÐ½Ð¾Ñ Ñлов не требуетÑÑ Ð¸ выходим из цикла */ + if(c == '\n') + { + if(TextOptions.showLF) + { + s.append('\n'); + strwidth += fwc.charWidth('\n'); + } + + wordwrap = false; + break; + } + else if(c == '\r') + { + if(TextOptions.showCR) + { + s.append('\r'); + strwidth += fwc.charWidth('\r'); + } + } + else if(c == '\t') + { + s.append('\t'); + + if(TextOptions.substTAB) + { + strwidth += fwc.stringWidth(AuxClass.TAB_AS_SPACES); + c = ' '; + } + else + { + strwidth += fwc.charWidth(c); + } + } + else + { + s.append(c); + strwidth += fwc.charWidth(c); + } + + if(AuxClass.SEPARATOR_CHARS.indexOf(c) >= 0) + { + afterspace = 0; + } + else if(afterspace >= 0) + { + afterspace++; + } + } + while(strwidth < maxStrWidth); + } + catch(EOFException eof) + { + wordwrap = false; + } + + res = s.toString(); + + if(wordwrap && afterspace >= 0) + { + cut = afterspace; + } + else if(strwidth > maxStrWidth) + { + cut = 1; + } + + if(cut > 0) + { + res = res.substring(0, res.length() - cut); + + if(enc >= 0) // однобайтовые кодировки + { + bdis.setPosition(bdis.getPosition() - cut); + } + else + { + for(int i = 0; i < cut; i++) + { + isd.readCharBack(); + } + } + } + } + catch(IOException ioe) + { + ErrScreen.showErrMsg(21, ioe); + return null; + } + + if(TextOptions.substTAB) + { + int index = 0; + + while((index = res.indexOf('\t')) >= 0) + { + res = res.substring(0, index) + AuxClass.TAB_AS_SPACES + res.substring(index + 1); + } + } + + return res.toString(); + } + + /** + * Прочитать Ñтроку из потока ÐÐЗÐД + */ + public String readStringBack(boolean wordwrap) + { + StringBuffer s = new StringBuffer(); + String res; + + int afterspace = -1; + int cut = 0; + int strwidth = 0; + char c = (char)-1; + + try + { + if(bdis == null || bdis.getPosition() <= offset) + { + return null; + } + + try + { + do + { + if(bdis.getPosition() <= offset) + { + wordwrap = false; + break; + } + + /* Ñчитываем Ñимвол */ + c = isd.readCharBack(); + + /* еÑли Ñто не Ñимвол конца Ñтроки и не конец файла, + то добавлÑем его к Ñтроке и обновлÑем ее длину. + Ð’ противном Ñлучае Ñообщаем, что Ð¿ÐµÑ€ÐµÐ½Ð¾Ñ Ñлов не требуетÑÑ Ð¸ выходим из цикла */ + if(c == '\n') + { + if(s.length() > 0 || afterspace >= 0) + { + /* + * Ð’ Ñтроке уже еÑÑ‚ÑŒ Ñимволы, + * то еÑÑ‚ÑŒ Ñто не конец Ñтроки. + * ЗдеÑÑŒ Ñимвол LF не показываем в любом Ñлучае, + * так как Ñто конец предыдущей Ñтроки. + * + * Тем не менее в буфер нужно что-то воткнуть, + * чтобы было потом что отброÑить, когда будем + * читать Ñимвол назад. + */ + + s.insert(0, '\n'); + strwidth += fwc.charWidth('\n'); + + wordwrap = false; + break; + } + else + { + /* + * Строка пока пуÑтаÑ, так что Ñто может быть + * конец Ñтой Ñтроки. + * Пихаем Ñимвол LF в Ñтроку на уÑмотрение пользователÑ. + */ + + if(TextOptions.showLF) + { + s.insert(0, '\n'); + strwidth += fwc.charWidth('\n'); + } + // else + // { + // s.insert(0, ' '); + // strwidth += fwc.charWidth(' '); + // } + } + } + else if(c == '\r') + { + if(TextOptions.showCR) + { + s.insert(0, '\r'); + strwidth += fwc.charWidth('\r'); + } + } + else if(c == '\t') + { + s.insert(0, '\t'); + + if(TextOptions.substTAB) + { + strwidth += fwc.stringWidth(AuxClass.TAB_AS_SPACES); + c = ' '; + } + else + { + strwidth += fwc.charWidth('\t'); + } + } + else + { + s.insert(0, c); + strwidth += fwc.charWidth(c); + } + + if(AuxClass.SEPARATOR_CHARS.indexOf(c) >= 0) + { + afterspace = 1; + } + else if(c == '\n') + { + afterspace = 0; + } + else if(afterspace >= 0) + { + afterspace++; + } + } + while(strwidth < maxStrWidth); + } + catch(EOFException eof) + { + wordwrap = false; + } + + res = s.toString(); + + if(wordwrap && afterspace >= 0 && res.length() > afterspace) + { + cut = afterspace; + } + else if((strwidth > maxStrWidth) || (c == '\n' && res.length() > 0)) + { + cut = 1; + } + + if(cut > 0) + { + res = res.substring(cut); + + if(enc >= 0) // однобайтовые кодировки + { + bdis.setPosition(bdis.getPosition() + cut); + } + else + { + for(int i = 0; i < cut; i++) + { + isd.readChar(); + } + } + } + } + catch(Exception ioe) + { + ErrScreen.showErrMsg(22, ioe); + return null; + } + + if(TextOptions.substTAB) + { + int index = 0; + + while((index = res.indexOf('\t')) >= 0) + { + res = res.substring(0, index) + AuxClass.TAB_AS_SPACES + res.substring(index + 1); + } + } + + return res.toString(); + } + + /* + // ÐžÑ‚Ð»Ð°Ð´Ð¾Ñ‡Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ + void printposes () + { + System.out.print ("lineposes:"); + for (int i = 0; i < linesPerScreen+1; i++) + System.out.print (" " + lineposes [i]); + System.out.println (); + }*/ + + /** + * Прочитать Ñкран из потока + */ + public void readScreen(boolean wordWrap) + { + try + { + for(int i = 0; i < linesPerScreen; i++) + { + lineposes[i] = bdis.getPosition(); + lines[i] = readString(wordWrap); + } + + lineposes[linesPerScreen] = bdis.getPosition(); + + scrStart = lineposes[0]; + scrEnd = lineposes[linesPerScreen]; + } + catch(Exception ioe) + { + ErrScreen.showErrMsg(23, ioe); + } + } + + /** + * ОчиÑтить Ñкран + */ + public void clearScreen() + { + for(int i = 0; i < linesPerScreen; i++) + { + lineposes[i] = 0; + lines[i] = null; + } + + lineposes[linesPerScreen] = 0; + } + + /** + * Перейти Ñтрочкой выше + */ + public void lineUp(boolean repaints) + { + try + { + if(scrStart > offset) + { + bdis.setPosition(scrStart); + + scrEnd = lineposes[linesPerScreen] = lineposes[linesPerScreen - 1]; + + for(int i = linesPerScreen - 1; i > 0; i--) + { + lines[i] = lines[i - 1]; + lineposes[i] = lineposes[i - 1]; + } + + lines[0] = readStringBack(true); + + scrStart = lineposes[0] = bdis.getPosition(); + + bdis.setPosition(scrEnd); + } + } + catch(IOException ioe) + { + ErrScreen.showErrMsg(24, ioe); + } + + if(repaints) + { + repaint(); + } + } + + /** + * Перейти Ñтрочкой ниже + */ + public void lineDown(boolean repaints) + { + if(scrEnd < bdis.getCapacity()) + { + scrStart = lineposes[1]; + + for(int i = 0; i < linesPerScreen - 1; i++) + { + lines[i] = lines[i + 1]; + lineposes[i] = lineposes[i + 1]; + } + + lineposes[linesPerScreen - 1] = lineposes[linesPerScreen]; + + lines[linesPerScreen - 1] = readString(true); + + lineposes[linesPerScreen] = scrEnd = bdis.getPosition(); + } + + if(repaints) + { + repaint(); + } + } + + /** + * Перейти Ñкраном выше + */ + public void screenUp() + { + try + { + bdis.setPosition(scrStart); + + for(int i = 0; i < linesPerScreen; i++) + { + readStringBack(true); + } + + readScreen(true); + } + catch(Exception e) + { + ErrScreen.showErrMsg(26, e); + } + + repaint(); + } + + /** + * Перейти Ñкраном ниже + */ + public void screenDown() + { + try + { + if(scrEnd < bdis.getCapacity()) + { + readScreen(true); + } + } + catch(Exception e) + { + ErrScreen.showErrMsg(27, e); + } + + repaint(); + } + + /** + * Проверка возможноÑти Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑта. + * Редактировать можно только текÑÑ‚, открытый из файла. + */ + public boolean editPossible() + { + return fileUsed; + } + + /** + * Проверка возможноÑти непоÑредÑтвенного ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñ‚ÐµÐºÑта. + * Это возможно только еÑли в текÑÑ‚ внеÑены изменениÑ. + * Что, в Ñвою очередь, возможно только еÑли текÑÑ‚ открыт из файла. + */ + public boolean savePossible() + { + return editIndex > 0; + } + + /** + * Ðачать редактирование выделенного текÑта или текущего Ñкрана + */ + public void editText() + { + if(!editPossible()) + { + return; + } + + if(selStart < 0) + { + editText(scrStart, scrEnd); + } + else + { + start = selStart; + end = scrEnd; + + selStart = -1; + + if(end < start) + { + start ^= end; + end ^= start; + start ^= end; + } + + if(end > start) + { + editText(start, end); + } + else + { + repaint(); + } + } + } + + /** + * Редактировать куÑок текÑта Ñ start до end + */ + public void editText(int start, int end) + { + editStart = start; + editEnd = end; + + edittext = ""; + + // Читаем то, что будем редактировать + try + { + bdis.setPosition(editStart); + + byte[] bs = new byte[editEnd - editStart]; + + int rl = bdis.read(bs); + + if(rl > 0) + { + edittext = StringEncoder.decodeString(bs, 0, rl, enc); + } + +// if(TextViewOptions.escapedStrings) +// { +// edittext = TextProcessor.escapeString(edittext); +// } + } + catch(Exception e) + { + ErrScreen.showErrMsg(29, e); + edittext = null; + return; + } + + // Запихиваем Ñто в TextBox + + tb = new TextBox(TextOptions.textBoxTitle == 0 ? caption : null, "", edittext.length() + TextOptions.textBufSize, TextField.ANY); + int maxsize = tb.getMaxSize(); + + if(edittext.length() > maxsize) + { + edittext = edittext.substring(0, maxsize); + editEnd = editStart + StringEncoder.getEncodedLength(edittext, enc); + } + + tb.setString(edittext); + + tb.addCommand(cmdOK); + tb.addCommand(cmdOptions); + +// tb.addCommand(cmdTemplate); +// tb.addCommand(cmdClear); +// tb.addCommand(cmdEscape); +// tb.addCommand(cmdUnescape); +// tb.addCommand(cmdRegExp); +// tb.addCommand(cmdCancel); + + tb.setCommandListener(this); + + if(TextOptions.textBoxTitle == 1) + { + tb.setTicker(new Ticker(caption)); + } + + lstTextCommands = new List(cmdOptions.getLabel(), Choice.IMPLICIT); + + lstTextCommands.append(cmdTemplate.getLabel(), null); + lstTextCommands.append(cmdClear.getLabel(), null); + lstTextCommands.append(cmdEscape.getLabel(), null); + lstTextCommands.append(cmdUnescape.getLabel(), null); + lstTextCommands.append(cmdRegExp.getLabel(), null); + //lstTextCommands.append(cmdBack.getLabel(), null); + + lstTextCommands.addCommand(cmdBack); + lstTextCommands.addCommand(cmdCancel); + lstTextCommands.setCommandListener(this); + + // Ð TextBox - на Ñкран + main.dsp.setCurrent(tb); + } + + /* + * Завершение Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑта, пока без ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ + */ + public void returnFromEditing() + { + if(tb == null) + { + return; + } + + main.dsp.setCurrent(this); + + edittext = tb.getString(); + + if(esclevel > 0) + { + edittext = TextProcessor.unescapeString(edittext); + } + + replaceText(edittext, editStart, editEnd); + + readScreen(true); + repaint(); + } + + public void replaceText(String newtext, int start, int end) + { + try + { + ReplaceableInputStream ris = new ReplaceableInputStream(rais); + ris.setReplace(StringEncoder.encodeString(newtext, enc), start, end); + + if(editHistory.size() <= ++editIndex) + { + // мы в конце ÑпиÑка изменений - добавлÑем новый Ñлемент + editHistory.addElement(ris); + } + else + { + // мы в Ñередине ÑпиÑка - обновлÑем текущий Ñлемент + // и удалÑем вÑе, что поÑле него + editHistory.setSize(editIndex + 1); + editHistory.setElementAt(ris, editIndex); + } + + rais = ris; + bdis.setInputStream(rais); + bdis.setPosition(scrStart); + } + catch(Exception e) + { + ErrScreen.showErrMsg(79, e); + } + } + + public boolean undoPossible() + { + return editIndex > 0; + } + + public boolean redoPossible() + { + return editIndex < editHistory.size() - 1; + } + + public void undo() + { + if(undoPossible()) + { + try + { + rais = (RandomAccessInputStream)editHistory.elementAt(--editIndex); + + bdis.setInputStream(rais); + bdis.setPosition(scrStart); + } + catch(Exception e) + { + ErrScreen.showErrMsg(80, e); + } + + readScreen(true); + + repaint(); + } + } + + public void redo() + { + if(redoPossible()) + { + try + { + rais = (RandomAccessInputStream)editHistory.elementAt(++editIndex); + + bdis.setInputStream(rais); + bdis.setPosition(scrStart); + } + catch(Exception e) + { + ErrScreen.showErrMsg(81, e); + } + + readScreen(true); + + repaint(); + } + } + + public void showSave() + { + if(fileUsed) + { + saveForm.setFileName(fname); + } + else + { + saveForm.setFileName(main.currentPath + caption); + } + + saveForm.setEncoding(enc); + saveForm.setUseBOM(TextOptions.useUTFBOM); + + main.dsp.setCurrent(saveForm); + } + + public void saveFile(String newFileName, int newEnc, boolean useBOM) + { + if(!newFile && newFileName.equals(fname)) // ÑохранÑем в Ñтарый файл + { + saveEditText(); + + /* + * Перекодирование в пределах одного файла. + * Из-за проверки выше оно будет возможно только еÑли + * иÑÑ…Ð¾Ð´Ð½Ð°Ñ Ð¸ ÐºÐ¾Ð½ÐµÑ‡Ð½Ð°Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²ÐºÐ¸ - однобайтовые + * (что ÑоответÑтвует требованиÑм transcode()) + */ + if(newEnc != enc) + { + options.textEnc = newEnc; + + try + { + rais = (RandomAccessInputStream)editHistory.elementAt(0); + + FileConnection src; + + if(rais instanceof FileInputStream) + { + src = ((FileInputStream)rais).getBaseConnection(); + } + else + { + src = (FileConnection)Connector.open("file:///" + fname); + } + + closeStream(); + + // еÑли менÑетÑÑ Ñ‡Ñ‚Ð¾-то, ÑвÑзанное Ñ ÑŽÐ½Ð¸ÐºÐ¾Ð´Ð¾Ð¼... + if(enc < 0 || newEnc < 0 || (offset != 0) != useBOM) + { + String tempname = Connector.createTempFile(fname, false); + + FileConnection dst = (FileConnection)Connector.open("file:///" + tempname); + dst.create(); + + StringEncoder.transcode(src, dst, enc, newEnc, useBOM); + + String name = src.getName(); + src.delete(); + src.close(); + + dst.rename(name); + dst.close(); + + Connector.releaseTempFile(tempname); + } + else + { + StringEncoder.transcode(src, src, enc, newEnc, useBOM); + + src.close(); + } + + // открываем заново + openFile(fname); + } + catch(Exception e) + { + ErrScreen.showErrMsg(66, e); + return; + } + } + } + else // ÑохранÑем в новый файл + { + try + { + int index = newFileName.lastIndexOf('/') + 1; + + if(index > 0) + { + String path = newFileName.substring(0, index); + + if(!filesystem.isFileExist(path)) + { + filesystem.makeNewDir(path); + } + } + + FileConnection fc = (FileConnection)Connector.open("file:///" + newFileName); + + if(fc.exists()) + { + fc.truncate(0); + } + else + { + fc.create(); + } + + OutputStream os = fc.openOutputStream(); + OutputStreamEncoder ose = new OutputStreamEncoder(os, newEnc); + + TextOptions.useUTFBOM = useBOM; + + if(useBOM) + { + ose.writeBOM(); + } + + if(newEnc >= 0 || !useBOM) + { + options.textEnc = newEnc; + } + + bdis.setPosition(offset); + + while(isd.available() > 0) + { + ose.writeChar(isd.readChar()); + } + + os.flush(); + ose.close(); + fc.close(); + + // возвращаемÑÑ Ð½Ð° offset назад, чтобы не пропуÑтить потом + // первые offset байт из-за Ñохраненной закладки + if(scrStart >= offset) + { + scrStart -= offset; + } + + // еÑли Ñохранили в UTF-16, то уÑтанавливаем + // поток на четную позицию + if((newEnc == StringEncoder.ENC_UTF16N || newEnc == StringEncoder.ENC_UTF16L) && scrStart % 2 != 0) + { + scrStart--; + } + + openFile(newFileName); + + rescanAfterExit = true; + } + catch(Exception e) + { + ErrScreen.showErrMsg(82, e); + return; + } + } + + if(closing) + { + close(); + } + else + { + main.dsp.setCurrent(this); + } + } + + /** + * Сохранить изменениÑ, внеÑенные в текÑÑ‚. + * ТекÑÑ‚ ÑохранÑетÑÑ Ð² том виде, в котором он отображаетÑÑ. + * Отмененные Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ðµ запиÑываютÑÑ Ð² файл, + * и поÑле ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ них терÑетÑÑ. + */ + public void saveEditText() + { + if(editIndex <= 0) // нечего ÑохранÑÑ‚ÑŒ + { + return; + } + + // еÑли редактировали новый файл, то + // в файловой ÑиÑтеме он еще не ÑущеÑтвует + if(newFile) + { + showSave(); + return; + } + + // уÑтанавливаем закладку, + // чтобы потом текÑÑ‚ открылÑÑ Ð½Ð° том же меÑте, + // где он был открыт до Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + options.setBookMark(caption, scrStart); + + try + { + rais = (RandomAccessInputStream)editHistory.elementAt(0); + + FileConnection fc; + + if(rais instanceof FileInputStream) + { + fc = ((FileInputStream)rais).getBaseConnection(); + + try + { + OutputStream os = fc.openOutputStream(); + os.close(); + } + catch(IllegalModeException ime) + { + rais.close(); + fc.close(); + + fc = (FileConnection)Connector.open("file:///" + fname); + ((FileInputStream)rais).setFileConnection(fc); + } + } + else + { + fc = (FileConnection)Connector.open("file:///" + fname); + } + + // берем поÑледний поток Ñ Ð¿Ð¾Ð´Ñтановкой + ReplaceableInputStream ris = (ReplaceableInputStream)editHistory.elementAt(editIndex); + + // запиÑываем подÑтановки в файл, так или иначе + // иÑходный поток закрываетÑÑ Ñ‚Ð°Ð¼ же автоматичеÑки + fc = AuxClass.updateFileData(fc, ris); + +// // поÑледовательно запиÑываем в файл данные замены +// for(int i = 1; i <= editIndex; i++) +// { +// ris = (ReplaceableInputStream)editHistory.elementAt(i); +// AuxClass.updateFileData(fc, ris.getReplace(), ris.getReplaceStart(), ris.getReplaceEnd()); +// } + + fc.close(); + + // открываем заново + int oldstart = editStart; + + openFile(fname); + + bdis.setPosition(oldstart); + } + catch(Exception e) + { + ErrScreen.showErrMsg(30, e); + } + + if(!closing) + { + main.showMessage(Locale.getString(this, Locale.DONE), Locale.getString(this, Locale.SAVED), AlertType.INFO, 1500, this); + } + + readScreen(true); + repaint(); + } + + /** + * Прервать редактирование, еÑли оно идёт + */ + public void breakEditing() + { + if(tb == null) + { + return; + } + + main.dsp.setCurrent(this); + + repaint(); + + tb = null; + lstTextCommands = null; + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð¸Ñовки + */ + + private int slall, slpos, slend; + private int start, end; + + public void paint(Graphics g) + { + images.drawVGradient(g, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, w, h, options.ditherGradients, options.alphaGradients); + + // РиÑуем Ñам текÑÑ‚ + + //g.setColor(Colors.colors[Colors.hlfore]); + //g.drawLine(maxStrWidth + 2, header, maxStrWidth + 2, h - footer); + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.setFont(fntText); + + for(int i = 0; i < linesPerScreen; i++) + { + if(lines[i] != null) + { + g.drawString(lines[i], 2, header + 2 + i * fntTextHeight, Graphics.LEFT | Graphics.TOP); + //g.drawLine(2 + fwc.stringWidth(lines[i]), header + 2 + i * fntTextHeight, 2 + fwc.stringWidth(lines[i]), header + 2 + (i + 1) * fntTextHeight); + } + } + + if(!fsmode) + { + // РиÑуем заголовок + //g.setColor (Colors.back); + //g.fillRect (0, 0, w, header); + + /* значек текÑта */ + //images.drawIcon(g, images.iText, 2, (header - images.iconHeight) / 2); + + if(icon != null) + { + g.drawImage(icon, 2, (header - images.iconHeight) / 2, Graphics.LEFT | Graphics.TOP); + } + + /* заголовок */ + captionx = options.alterClockPos ? (images.iconWidth + clockw + 8) : (images.iconWidth + 4); + + g.setColor(ColorScheme.colors[ColorScheme.fore]); + g.setClip(captionx, 0, captionw, header); + g.drawString(caption, captionx, (header - fntTextHeight) / 2, Graphics.LEFT | Graphics.TOP); + + /* чаÑÑ‹ */ + g.setColor(ColorScheme.colors[ColorScheme.altfore]); + g.setClip(0, 0, w, h); + + if(options.alterClockPos) + { + g.drawString(AuxClass.getCurrentTime(), images.iconWidth + 4, (header - fntTextHeight) / 2, Graphics.LEFT | Graphics.TOP); + } + else + { + g.drawString(AuxClass.getCurrentTime(), w - 2, (header - fntTextHeight) / 2, Graphics.RIGHT | Graphics.TOP); + } + + /* линии */ + g.setColor(ColorScheme.colors[ColorScheme.mdborder]); + g.drawLine(0, header - 1, w, header - 1); // header = 20; footer = 8; + g.drawLine(0, h - footer, w, h - footer); + + // РиÑуем "подпиÑи" к Ñофт-кнопкам (креÑтик и "...") + g.setColor(ColorScheme.colors[ColorScheme.fore]); + + g.drawLine(w - footer + 2, h - footer + 2, w - footer + 6, h - footer + 6); + g.drawLine(w - footer + 6, h - footer + 2, w - footer + 2, h - footer + 6); + + //g.drawString("...", 3, h - fntTextHeight - 1, Graphics.LEFT | Graphics.TOP); + g.drawLine(3, h - footer / 2 - 1, 3, h - footer / 2 - 1); + g.drawLine(5, h - footer / 2 - 1, 5, h - footer / 2 - 1); + g.drawLine(7, h - footer / 2 - 1, 7, h - footer / 2 - 1); + + g.setClip(w - 3, header, 3, h - header - footer); + g.setColor(ColorScheme.colors[ColorScheme.sbline]); + + // РиÑуем полоÑу прокрутки + g.drawLine(w - 2, header, w - 2, h - footer); + + if(selStart >= 0) + { + start = selStart; + end = scrEnd; + + if(end < start) + { + start ^= end; + end ^= start; + start ^= end; + } + + try + { + slpos = header + slall * start / bdis.getCapacity(); + slend = header + slall * end / bdis.getCapacity(); + } + catch(Exception e) + { + slpos = header; + slend = header + slall; + } + + if(slend > h - footer) + { + slend = h - footer; + } + + g.setColor(ColorScheme.colors[ColorScheme.hlfore]); + } + else + { + try + { + slpos = header + slall * scrStart / bdis.getCapacity(); + slend = header + slall * scrEnd / bdis.getCapacity(); + } + catch(Exception e) + { + slpos = header; + slend = header + slall; + } + + if(slend > h - footer) + { + slend = h - footer; + } + + g.setColor(ColorScheme.colors[ColorScheme.sbfore]); + } + + /* ползунок на полоÑе прокрутки */ + g.drawLine(w - 1, slpos, w - 1, slend); + g.drawLine(w - 3, slpos, w - 3, slend); + g.drawLine(w - 2, slpos - 1, w - 2, slend + 1); + } + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ команд + */ + public void commandAction(Command c, Displayable d) + { + if(d == tb) + { + if(c == cmdOK) // учет изменений и выход из редактора + { + returnFromEditing(); + } + else if(c == cmdBack) // выход из редактора без ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ + { + breakEditing(); + } + else if(c == cmdOptions) + { + main.dsp.setCurrent(lstTextCommands); + } + else if(c == cmdClear) // очиÑтка + { + tb.setString(""); + } + else if(c == cmdTemplate) + { + lstTemplates = new List(Locale.getString(this, Locale.TEMPLATES_CMD), List.IMPLICIT, TemplateManager.tempnames, null); + + lstTemplates.addCommand(cmdBack); + lstTemplates.setCommandListener(this); + + main.dsp.setCurrent(lstTemplates); + } + else if(c == cmdEscape) + { + //tb.setString(TextProcessor.escapeString(tb.getString())); + + lstEncodings = new List(Locale.getString(this, Locale.ENCODING_CMD), List.IMPLICIT, StringEncoder.encnames, null); + lstEncodings.insert(0, StringEncoder.ENC_NAME_UTF8, null); + lstEncodings.setSelectedIndex(enc >= 0 ? enc + 1 : 0, true); + + lstEncodings.addCommand(cmdBack); + lstEncodings.setCommandListener(this); + + main.dsp.setCurrent(lstEncodings); + } + else if(c == cmdUnescape) + { + edittext = TextProcessor.unescapeString(tb.getString()); + tb.setString(edittext); + + if(esclevel > 0) + { + esclevel--; + } + } + else if(c == cmdRegExp) + { + main.dsp.setCurrent(regExpForm); + } + } + else if(d == lstTextCommands) + { + main.dsp.setCurrent(tb); + + if(c == List.SELECT_COMMAND) + { + switch(lstTextCommands.getSelectedIndex()) + { + case 0: + commandAction(cmdTemplate, tb); + break; + + case 1: + commandAction(cmdClear, tb); + break; + + case 2: + commandAction(cmdEscape, tb); + break; + + case 3: + commandAction(cmdUnescape, tb); + break; + + case 4: + commandAction(cmdRegExp, tb); + break; + + case 5: + commandAction(cmdCancel, tb); + break; + } + } + else if(c == cmdCancel) + { + commandAction(cmdBack, tb); + } + } + else if(d == seekForm) + { + if(c.getCommandType() == Command.OK) + { + try + { + int n = seekForm.getLineNum(); + + if(n > 0) + { + isd.gotoLineNum(n); + } + else + { + n = seekForm.getValue() * bdis.getCapacity() / 100; + + if(n < offset) + { + n = offset; + } + + bdis.setPosition(n); + } + + readScreen(true); + } + catch(IOException ioe) + { + ErrScreen.showErrMsg(33, ioe); + } + } + + main.dsp.setCurrent(this); + } + else if(d == fontForm) + { + if(c.getCommandType() == Command.OK) + { + setFont(fontForm.getFont()); + } + + main.dsp.setCurrent(this); + } + else if(d == encForm) + { + if(c.getCommandType() == Command.OK) + { + int newEnc = encForm.getEncoding(); + + if(newEnc >= 0 || !TextOptions.useUTFBOM) + { + options.textEnc = newEnc; + } + + setEncoding(newEnc); + } + + main.dsp.setCurrent(this); + } + else if(d == saveForm) + { + switch(c.getCommandType()) + { + case Command.OK: + saveFile(saveForm.getFileName(), saveForm.getEncoding(), saveForm.getUseBOM()); + break; + + case Command.BACK: + main.dsp.setCurrent(this); + } + } + else if(d == findForm) + { + if(c.getCommandType() == Command.OK) + { + searchText = findForm.getText(); + searchReplaceText = findForm.getReplace(); + searchIgnoreCase = findForm.getIgnoreCase(); + + switch(c.getPriority()) + { + case 1: + main.dsp.setCurrent(this); + searchReplace = false; + findNext(false); + break; + + case 2: + main.dsp.setCurrent(this); + searchReplace = true; + findNext(false); + break; + + case 3: + searchReplace = true; + findReplaceAll(); + break; + } + } + else + { + main.dsp.setCurrent(this); + } + } + else if(d == regExpForm) + { + if(c.getCommandType() == Command.OK) + { + int flags = RE.MATCH_NORMAL; + + if(regExpForm.getFlags(0)) + { + flags |= RE.MATCH_CASEINDEPENDENT; + } + + if(regExpForm.getFlags(1)) + { + flags |= RE.MATCH_MULTILINE; + } + + RE re = new RE(regExpForm.getText(), flags); + + flags = RE.REPLACE_ALL; + + if(c.getPriority() == 1) + { + flags |= RE.REPLACE_FIRSTONLY; + } + + if(regExpForm.getFlags(2)) + { + flags |= RE.REPLACE_BACKREFERENCES; + } + + tb.setString(re.subst(tb.getString(), regExpForm.getReplace(), flags)); + } + + main.dsp.setCurrent(tb); + } + else if(d == lstTemplates) + { + if(tb == null) + { + return; + } + + if(c == List.SELECT_COMMAND) + { + try + { + InputStreamDecoder tempDecoder = InputStreamDecoder.getResourceDecoder("/temp/" + TemplateManager.templates[lstTemplates.getSelectedIndex()] + ".tpl"); + String temp = ""; + + while(tempDecoder.available() > 0) + { + temp += tempDecoder.readChar(); + } + + tb.setString(tb.getString() + temp); + } + catch(Exception e) + { + ErrScreen.showErrMsg(90, e); + } + } + + main.dsp.setCurrent(tb); + } + else if(d == lstEncodings) + { + if(tb == null) + { + return; + } + + if(c == List.SELECT_COMMAND) + { + edittext = TextProcessor.escapeString(esclevel++ == 0 ? edittext : tb.getString(), lstEncodings.getSelectedIndex() - 1); + tb.setString(edittext); + } + + main.dsp.setCurrent(tb); + } + else if(d instanceof Renderer) + { + PaintableObject po = ((Renderer)d).getCurrent(); + + if(po == alConfirmSave) + { + if(c == cmdYes) + { + saveEditText(); + + if(!newFile) + { + close(); + } + } + else if(c == cmdNo) + { + close(); + } + else + { + main.dsp.setCurrent(this); + } + } + else if(po == alSearchEOF) + { + if(c == cmdYes) + { + findNext(true); + } + + main.dsp.setCurrent(this); + } + } + } + + public void menuAction(int string) + { + mn.ret(); + + switch(string) + { + case Locale.SAVE_CMD: + if(savePossible()) + { + saveEditText(); + } + break; + + case Locale.SAVE_AS_CMD: + showSave(); + break; + + case Locale.EDIT_CMD: + if(editPossible()) + { + editText(); + } + break; + + case Locale.UNDO_CMD: + if(undoPossible()) + { + undo(); + } + break; + + case Locale.REDO_CMD: + if(redoPossible()) + { + redo(); + } + break; + + case Locale.GOTO_CMD: + showGoto(); + break; + + case Locale.GOTO_START_CMD: + gotoStart(); + break; + + case Locale.GOTO_END_CMD: + gotoEnd(); + break; + + case Locale.FIND_CMD: + showFind(); + break; + + case Locale.FIND_NEXT_CMD: + findNext(false); + break; + + case Locale.FONT_CMD: + showFont(); + break; + + case Locale.ENCODING_CMD: + if(encPossible()) + { + showEncoding(); + } + break; + + case Locale.MINIMIZE_CMD: + try + { + main.dsp.setCurrent(null); + } + catch(Exception e) + { + } + break; + } + } + + public void showNotify() + { + keyReleaseAllowed = false; + main.startLightControl(true); + } + + public void hideNotify() + { + main.startLightControl(true); + } + + /** + * Обработчик Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸ÑˆÐ¸ + */ + public void keyPressed(int keyCode) + { + keyReleaseAllowed = true; + + if(keyCode == KEY_UP || keyCode == KEY_NUM2) + { + if(TextOptions.textPageScroll) + { + screenUp(); + } + else + { + lineUp(true); + } + } + else if(keyCode == KEY_DOWN || keyCode == KEY_NUM8) + { + if(TextOptions.textPageScroll) + { + screenDown(); + } + else + { + lineDown(true); + } + } + else if(keyCode == KEY_RIGHT || keyCode == KEY_NUM6) + { + if(TextOptions.textPageScroll) + { + lineDown(true); + } + else + { + screenDown(); + } + } + else if(keyCode == KEY_LEFT || keyCode == KEY_NUM4) + { + if(TextOptions.textPageScroll) + { + lineUp(true); + } + else + { + screenUp(); + } + } + else if(keyCode == KEY_DIAL) + { + if(selStart < 0) + { + selStart = scrStart; + } + else + { + selStart = -1; + } + + repaint(); + } + else if(keyCode == KEY_POUND) + { + setFSMode(!fsmode); + } + else if(keyCode == KEY_LSK) // редактирование + { + showMenu(); + } + else if(keyCode == KEY_RSK) // выход + { + closing = true; + + if(savePossible()) + { + main.dsp.setCurrent(alConfirmSave, this); + } + else + { + close(); + } + } + else if(keyCode == KEY_CANCEL) + { + main.manager.minimizePanel(); + } + } + + public void keyRepeated(int keyCode) + { + if(mn.isKeyAllowed(keyCode)) + { + if(++keyHeld == 3) + { + keyHeld = 0; + keyReleaseAllowed = false; + + mn.keyAction(keyCode | KEY_HELD); + } + } + else + { + keyPressed(translateKey(keyCode)); + } + } + + public void keyReleased(int keyCode) + { + if(!keyReleaseAllowed) + { + return; + } + + if(keyHeld < 3 && isKeyNum(keyCode)) + { + mn.keyAction(keyCode); + } + + keyHeld = 0; + } + + public void close() + { + clearScreen(); + closeStream(); + + main.manager.ret(); + + if(rescanAfterExit) // еÑли новый файл правили + { + cvsWait.start(this, runpanel, caption); + rescanAfterExit = false; + } + + runpanel = -1; + closing = false; + } + + /** + * Перейти в начало файла. + */ + public void gotoStart() + { + try + { + bdis.setPosition(offset); + readScreen(true); + } + catch(Exception e) + { + ErrScreen.showErrMsg(91, e); + } + + repaint(); + } + + /** + * Перейти в конец файла. + */ + public void gotoEnd() + { + try + { + bdis.setPosition(bdis.getCapacity()); + + for(int i = 0; i < linesPerScreen; i++) + { + readStringBack(false); + } + + readScreen(true); + + while(scrEnd < bdis.getCapacity()) + { + lineDown(false); + } + } + catch(Exception e) + { + ErrScreen.showErrMsg(92, e); + } + + repaint(); + } + + /** + * Показать форму перехода на произвольную позицию + */ + public void showGoto() + { + seekForm.setValue(scrStart * 100 / bdis.getCapacity()); + main.dsp.setCurrent(seekForm); + } + + /** + * Показать форму поиÑка + */ + public void showFind() + { + findForm.setText(searchText); + findForm.setReplace(searchReplaceText); + findForm.setIgnoreCase(searchIgnoreCase); + findForm.setMatchesCount(-1); + + main.dsp.setCurrent(findForm); + } + + public void findNext(boolean fromStart) + { + if(searchText.length() == 0) + { + showFind(); + return; + } + + try + { + int index = -1; + int searchTextLen = StringEncoder.getEncodedLength(searchText, enc); + + if(fromStart) + { + index = isd.indexOf(searchText, offset, scrStart, searchIgnoreCase); + } + else + { + index = isd.indexOf(searchText, scrStart + searchTextLen, -1, searchIgnoreCase); + + if(index < 0 && scrStart >= offset + searchTextLen) + { + main.dsp.setCurrent(alSearchEOF, this); + return; + } + } + + if(index >= offset) + { + if(searchReplace) + { + replaceText(searchReplaceText, index, index + searchTextLen); + } + + bdis.setPosition(index); + readScreen(true); + repaint(); + } + } + catch(Exception e) + { + ErrScreen.showErrMsg(88, e); + } + } + + public void findReplaceAll() + { + if(searchText.length() == 0) + { + showFind(); + return; + } + + try + { + int index = -1; + int searchStart = offset; + int searchTextLen = StringEncoder.getEncodedLength(searchText, enc); + int replaceTextLen = StringEncoder.getEncodedLength(searchReplaceText, enc); + int matchesCount = 0; + + IntVector indices = new IntVector(); + + while(searchStart + searchTextLen < bdis.getCapacity()) + { + index = isd.indexOf(searchText, searchStart, -1, searchIgnoreCase); + + if(index < offset) + { + break; + } + + //replaceText(searchReplaceText, index, index + searchTextLen); + //searchStart = index + replaceTextLen + 1; + + indices.add(index); + searchStart = index + searchTextLen + 1; + + findForm.setMatchesCount(matchesCount++); + } + + if(indices.size() > 0) + { + StringBuffer repbuf = new StringBuffer(); + int replen = 0; + int repstart = -1; + int nextindex; + int i = 0; + + while(true) + { + index = indices.get(i); + + if(repstart < 0) + { + repstart = index; + } + + repbuf.append(searchReplaceText); + replen += replaceTextLen; + + if(++i < indices.size()) + { + nextindex = indices.get(i); + + if(replen + nextindex - index - searchTextLen + replaceTextLen <= TextOptions.textBufSize) + { + bdis.setPosition(index + searchTextLen); + + while(bdis.getPosition() < nextindex) + { + repbuf.append(isd.readChar()); + } + + replen += nextindex - index - searchTextLen; + } + else + { + replaceText(repbuf.toString(), repstart, index + searchTextLen); + + repbuf.delete(0, repbuf.length()); + replen = 0; + repstart = -1; + } + } + else + { + replaceText(repbuf.toString(), repstart, index + searchTextLen); + break; + } + } + } + + bdis.setPosition(scrStart); + readScreen(true); + main.dsp.setCurrent(this); + } + catch(Exception e) + { + ErrScreen.showErrMsg(95, e); + } + } + + /** + * Показать форму Ñмены шрифта + */ + public void showFont() + { + fontForm.setFont(fntText); + main.dsp.setCurrent(fontForm); + } + + /** + * Показать форму Ñмены кодировки + */ + public void showEncoding() + { + encForm.setEncoding(enc); + main.dsp.setCurrent(encForm); + } + + /** + * Переоткрыть поток в новой кодировке + */ + public void setEncoding(int encoding) + { + // UTF открываетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ как UTF, + // поÑтому здеÑÑŒ проверка + + if(encPossible()) + { + try + { + enc = encoding; + + if(enc < 0) + { + rais.setPosition(0); + + InputStreamDecoder.detectEncoding(rais, enc); + offset = rais.getPosition(); + } + else + { + offset = 0; + } + + isd = new InputStreamDecoder(bdis, enc); + setFSMode(fsmode); + } + catch(Exception e) + { + ErrScreen.showErrMsg(36, e); + } + } + } + + public boolean encPossible() + { + return true; // enc >= 0; + } + + public void showMenu() + { + menuEnabled[0][1] = savePossible(); + menuEnabled[1][1] = editPossible(); + menuEnabled[1][2] = undoPossible(); + menuEnabled[1][3] = redoPossible(); + menuEnabled[3][2] = encPossible(); + + mn.setEnabledFlags(menuEnabled); + mn.show(this); + } + + /** + * Данные меню. + */ + public static final int[][] menuData = + { + { + Locale.MENU_FILE, + Locale.SAVE_CMD, + Locale.SAVE_AS_CMD, + Locale.MINIMIZE_CMD + }, + { + Locale.MENU_EDIT, + Locale.EDIT_CMD, + Locale.UNDO_CMD, + Locale.REDO_CMD + }, + { + Locale.MENU_SEARCH, + Locale.FIND_CMD, + Locale.FIND_NEXT_CMD, + Locale.GOTO_CMD, + Locale.GOTO_START_CMD, + Locale.GOTO_END_CMD + }, + { + Locale.MENU_TEXT, + Locale.FONT_CMD, + Locale.ENCODING_CMD + } + }; + + /** + * Данные enabled режимов меню. + */ + public static final boolean[][] menuEnabled = + { + { false, false, true, true }, + { false, false, false, false }, + { false, true, true, true, true, true }, + { false, true, false } + }; + + /** + * Кнопки, аÑÑоциированные Ñ Ð¿ÑƒÐ½ÐºÑ‚Ð°Ð¼Ð¸ меню. + * Может быть Ñ†Ð¸Ñ„Ñ€Ð¾Ð²Ð°Ñ ÐºÐ½Ð¾Ð¿ÐºÐ°, *, # или KEY_INVALID. + */ + public static int[][] menuKeyConfig = + { + { + KEY_STAR, + KEY_STAR | KEY_HELD, + KEY_NUM0 | KEY_HELD + }, + { + KEY_NUM5, + KEY_NUM3 | KEY_HELD, + KEY_NUM9 | KEY_HELD + }, + { + KEY_NUM3, + KEY_NUM9, + KEY_NUM0, + KEY_NUM1 | KEY_HELD, + KEY_NUM7 | KEY_HELD + }, + { + KEY_NUM1, + KEY_NUM7 + } + }; + + /** + * Какие горÑчие клавиши разрешено назначать Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ типа меню. + * Идет *, #, потом цифровые. + */ + public static final boolean[] menuKeyAllowed = + { + true, false, true, true, false, true, false, true, false, true, false, true + }; + +// private static void out(String s) +// { +// System.out.println("[cvsTextView] " + s); +// } +} \ No newline at end of file diff --git a/src/modules/video/VideoModule.java b/src/modules/video/VideoModule.java new file mode 100644 index 0000000..558bd87 --- /dev/null +++ b/src/modules/video/VideoModule.java @@ -0,0 +1,19 @@ +package modules.video; + +import com.one.Application; +import com.one.PlayList; + +public class VideoModule implements Application +{ + public void openFile(String filename, PlayList filelist) + { + cvsVideoPlayer videoPlayer = cvsVideoPlayer.getInstance(); + + if(filelist != null) + { + videoPlayer.setPlayList(filelist); + } + + videoPlayer.playVideo(filename); + } +} diff --git a/src/modules/video/VideoOptions.java b/src/modules/video/VideoOptions.java new file mode 100644 index 0000000..36cb18e --- /dev/null +++ b/src/modules/video/VideoOptions.java @@ -0,0 +1,134 @@ +package modules.video; + +import com.one.ModuleRegistry; +import com.one.OptionStorage; +import com.vmx.Locale; +import filemanager.main; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import javax.microedition.lcdui.Choice; +import javax.microedition.lcdui.ChoiceGroup; +import javax.microedition.lcdui.Command; +import javax.microedition.lcdui.CommandListener; +import javax.microedition.lcdui.Displayable; +import javax.microedition.lcdui.Form; + +public class VideoOptions implements CommandListener, OptionStorage +{ + public static final int OPTIONS_VERSION = 1; + + public static int rotateMode = 0; + public static int volume = 100; // громкоÑÑ‚ÑŒ аудио плейера + public static boolean muted = false; // отключен звук в аудиоплейере? + public static boolean useAccelerometer = false; + public static boolean shufflePlay = false; + public static boolean showPlayProgress = true; + + protected Object parent; + + protected ChoiceGroup cgPlayer; + + public void showEditor(Object parent) + { + this.parent = parent; + + restoreOptions(); + + Form form = new Form(ModuleRegistry.getModuleName(getClass().getName())); + + // *** ÐаÑтройки плеера *** + cgPlayer = new ChoiceGroup(null, Choice.MULTIPLE); + + // Показывать прогреÑÑ-бар при воÑпроизведении + cgPlayer.append(Locale.getString(this, Locale.PREF_SHOW_PLAY_PROGRESS), null); + cgPlayer.setSelectedIndex(0, showPlayProgress); + + // ИÑпользовать акÑелерометр + cgPlayer.append(Locale.getString(this, Locale.PREF_USE_ACCELEROMETER), null); + cgPlayer.setSelectedIndex(1, useAccelerometer); + + form.append(cgPlayer); + + form.addCommand(new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1)); + form.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 2)); + + form.setCommandListener(this); + + main.dsp.setCurrent(form); + } + + public void commandAction(Command c, Displayable d) + { + if(c.getCommandType() == Command.OK) + { + showPlayProgress = cgPlayer.isSelected(0); + useAccelerometer = cgPlayer.isSelected(1); + + saveOptions(); + } + + main.dsp.setCurrent(parent); + } + + public void restoreOptions() + { + try + { + byte[] data = ModuleRegistry.getModuleData(getClass().getName()); + + if(data == null || data.length == 0) + { + return; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data)); + + if(dis.readInt() != OPTIONS_VERSION) + { + dis.close(); + return; + } + + rotateMode = dis.readInt(); + volume = dis.readInt(); + muted = dis.readBoolean(); + useAccelerometer = dis.readBoolean(); + shufflePlay = dis.readBoolean(); + showPlayProgress = dis.readBoolean(); + + dis.close(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + + public void saveOptions() + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + dos.writeInt(OPTIONS_VERSION); + dos.writeInt(rotateMode); + dos.writeInt(volume); + dos.writeBoolean(muted); + dos.writeBoolean(useAccelerometer); + dos.writeBoolean(shufflePlay); + dos.writeBoolean(showPlayProgress); + + byte[] data = baos.toByteArray(); + dos.close(); + + ModuleRegistry.setModuleData(getClass().getName(), data); + } + catch(Exception e) + { + e.printStackTrace(); + } + } +} diff --git a/src/modules/video/cvsVideoPlayer.java b/src/modules/video/cvsVideoPlayer.java new file mode 100644 index 0000000..90af726 --- /dev/null +++ b/src/modules/video/cvsVideoPlayer.java @@ -0,0 +1,1097 @@ +package modules.video; // переведен + +import javax.microedition.lcdui.*; +import javax.microedition.lcdui.game.*; +import javax.microedition.media.*; +import javax.microedition.media.control.*; +import java.io.*; +import com.vmx.*; +import com.one.*; +import com.one.file.*; +import filemanager.filesystem; +import filemanager.images; +import filemanager.main; +import java.util.Enumeration; + +/** + * Проигрыватель видео + */ +public class cvsVideoPlayer extends gkcCanvas implements PlayerListener, Runnable +{ + public static final String SHUFFLE_PLAY_MARK = "±"; // "°"; + + private static Player player; + private VolumeControl volumeControl; + private VideoControl videoControl; + private InputStream is; + private int trans; + private boolean running; + private boolean paused; + private Thread t = null; + private String currentFile, OnlyFileName; + private int w, h, w2, h2; + private Font infoFont; + private int ofnw, ofnx, ofnstep, ofndelay; // прокрутка Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ + private static final int OFN_DEF_DELAY = 1; + private boolean keyFlag = false; + private boolean wasPaused = false; + private long duration, time, tstep; + private int pbx, pby, pbw, pbh; // прогреÑÑ + private PlayList playlist; + private boolean enableUI = true; + private boolean overlay; + private boolean paintflag; + private boolean update; + private boolean isshown; + + private int runpanel; + + private static cvsVideoPlayer instance; + + public static void loadInstance() + { + if(instance == null) + { + instance = new cvsVideoPlayer(); + } + } + + public static cvsVideoPlayer getInstance() + { + loadInstance(); + return instance; + } + + private Runnable videoRedisplayTask = new Runnable() + { + public void run() + { + Thread.yield(); + + update = true; + + repaint(); + serviceRepaints(); + + if(videoControl != null) + { + videoControl.setVisible(!isshown); + videoControl.setVisible(isshown); + } + } + }; + + /** + * КонÑтруктор + */ + public cvsVideoPlayer() + { + setFullScreenMode(true); + + w = getWidth(); + h = getHeight(); + + w2 = w / 2; + h2 = h / 2; + + infoFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL); + + //bgimage = images.createFullUI(w, h); + + pbw = w * 9 / 16; + pbh = infoFont.getHeight() * 3 / 4; + pbx = (w - pbw) / 2; + pby = images.uiTopHeight + (h - images.uiTopHeight - images.uiBottomHeight - infoFont.getHeight()) / 2; + + runpanel = -1; + } + + /** + * Обновление данных в ÑоответÑтвии Ñ ÑоÑтоÑнием плеера + */ + public void playerUpdate(Player player, String event, Object data) + { + //System.out.println ("EVENT =" + event); + + if(event.equals(PlayerListener.VOLUME_CHANGED)) + { + if(volumeControl != null) + { + VideoOptions.volume = volumeControl.getLevel(); + //System.out.println ( "Volume =" + VideoOptions.volume ); + } + + repaint(); + } + else if(event.equals(PlayerListener.END_OF_MEDIA)) + { + nextClip(); + } + } + + public void setPlayList(PlayList newlist) + { + playlist = newlist; + } + + public void setPlayList(Enumeration newlist) + { + playlist = new PlayList(newlist); + } + + protected void initScroll() + { + // только Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐºÑ€ÑƒÑ‚ÐºÐ¸ + OnlyFileName = currentFile.substring(currentFile.lastIndexOf('/') + 1); + + ofnw = infoFont.stringWidth(OnlyFileName); + ofnx = images.uiTopHSpace; + ofndelay = OFN_DEF_DELAY; + + if(ofnw > w - images.uiTopHSpace * 2) + { + ofnstep = -(ofnw / OnlyFileName.length()); + } + else + { + ofnstep = 0; + } + } + + protected void initDuration() + { + duration = player.getDuration(); + tstep = duration / 100; + } + + protected void initPanels() + { + if(runpanel < 0) + { + runpanel = main.manager.currentPanel(); + } + + main.manager.setCurrent(this, runpanel); + main.manager.updateAssociation(runpanel, playlist.getCurrentElement()); + } + + protected void initPlayList(String file) + { + currentFile = file; + + if(playlist == null) + { + playlist = new PlayList(file); + } + + playlist.selectElement(file); + } + + /** + * Играть файл videoFile + */ + public void playVideo(String videoFile) + { + destroyPlayer(); + + initPanels(); + + player = null; + running = true; + + initPlayList(videoFile); + + initScroll(); + + try + { + player = Manager.createPlayer("file:///" + videoFile); + player.realize(); + player.prefetch(); + + player.addPlayerListener(this); + player.setLoopCount(1); + + initDuration(); + + videoControl = (VideoControl)player.getControl("VideoControl"); + setDisplay(true); + + volumeControl = (VolumeControl)player.getControl("VolumeControl"); + + if(volumeControl != null) + { + volumeControl.setLevel(VideoOptions.volume); + volumeControl.setMute(VideoOptions.muted); + } + } + catch(Exception e) + { + try + { + playVideoFromStream(Connector.openInputStream("file:///" + videoFile), videoFile.substring(videoFile.lastIndexOf('/') + 1)); + return; + } + catch(IOException ioe) + { + ErrScreen.showErrMsg(16, ioe); + } + } + + if(t == null) + { + t = new Thread(this, "VideoPlayer/Update"); + t.start(); + } + } + + public void playVideoFromStream(InputStream is, String videoFile) + { + destroyPlayer(); + + initPanels(); + + player = null; + running = true; + + initPlayList(videoFile); + + initScroll(); + + try + { + this.is = is; + + try + { + player = Manager.createPlayer(is, filesystem.mimeType(videoFile)); + player.realize(); + player.prefetch(); + } + catch(Exception stupidEmulatorException) + { + player = Manager.createPlayer(is, "video/3gpp"); + player.realize(); + player.prefetch(); + } + + player.addPlayerListener(this); + player.setLoopCount(1); + + initDuration(); + + videoControl = (VideoControl)player.getControl("VideoControl"); + setDisplay(true); + + volumeControl = (VolumeControl)player.getControl("VolumeControl"); + + if(volumeControl != null) + { + volumeControl.setLevel(VideoOptions.volume); + volumeControl.setMute(VideoOptions.muted); + } + } + catch(Exception e) + { + ErrScreen.showErrMsg(16, e); + } + + if(t == null) + { + t = new Thread(this, "VideoPlayer/Update"); + t.start(); + } + } + + public void hideNotify() + { + if(videoControl != null) + { + try + { + videoControl.setVisible(false); + } + catch(Exception e) + { + } + } + + isshown = false; + } + + public void showNotify() + { + if(videoControl != null) + { + try + { + videoControl.setVisible(true); + } + catch(Exception e) + { + } + } + + isshown = true; + update = true; + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð¸Ñовки + */ + public void paint(Graphics g) + { + boolean needupdate = update; + update = false; + + //System.out.println("[" + AuxClass.timeToString(-1, true) + "]"); + + //boolean playing = player != null && player.getState() == Player.STARTED; + + if(!needupdate && !overlay) + { + if(player == null || player.getState() != Player.STARTED) + { + return; + } + +// paintflag = !paintflag; +// +// if(!paintflag) +// { +// return; +// } + } + + if(!enableUI) + { + g.setClip(0, 0, w, h); + + if(needupdate) + { + g.setColor(0xFF000000); + g.fillRect(0, 0, w, h); + } + + return; + } + + // БÑкграунд + if(images.playerUI != null) + { + if(!needupdate && player != null) + { + g.setClip(0, 0, w, images.uiTopHeight); + g.drawImage(images.playerUI, 0, 0, Graphics.LEFT | Graphics.TOP); + + g.setClip(0, h - images.uiBottomHeight, w, images.uiBottomHeight); + g.drawImage(images.playerUI, 0, 0, Graphics.LEFT | Graphics.TOP); + + g.setClip(0, 0, w, h); + } + else + { + g.setClip(0, 0, w, h); + g.drawImage(images.playerUI, 0, 0, Graphics.LEFT | Graphics.TOP); + } + } + + if(images.buttons != null) + { + // Кнопка PLAY + g.drawRegion(images.buttons, 0, 0, images.btnWidth, images.btnHeight, Sprite.TRANS_NONE, images.uiBottomHOffset, h - images.uiBottomHeight + images.uiBottomVOffset, Graphics.LEFT | Graphics.TOP); + + // Кнопка STOP + g.drawRegion(images.buttons, images.btnWidth * 2, 0, images.btnWidth, images.btnHeight, Sprite.TRANS_NONE, w - images.btnWidth - images.uiBottomHOffset, h - images.uiBottomHeight + images.uiBottomVOffset, Graphics.LEFT | Graphics.TOP); + } + + g.setColor(images.cPlayFore2); + + int y = h - images.uiBottomHeight / 2; + + if(VideoOptions.volume == 0) // вывод значка громкоÑти + { + images.drawIcon(g, images.iMute, w2 - images.iconWidth, y - images.iconHeight / 2); + g.fillRect(w2 + 4, y + 4, 10, 1); + } + else + { + if(!VideoOptions.muted) + { + images.drawIcon(g, images.iNoMute, w2 - images.iconWidth, y - images.iconHeight / 2); + } + else + { + images.drawIcon(g, images.iMute, w2 - images.iconWidth, y - images.iconHeight / 2); + } + + for(int i = 0; i < VideoOptions.volume; i += 25) + { + g.fillRect(w2 + 4, y + 3 - (i / 25) * 3, 10, 2); + } + } + + g.setFont(infoFont); + g.setColor(images.cPlayFore1); //0x800000); + + if(VideoOptions.shufflePlay) + { + g.drawString(SHUFFLE_PLAY_MARK, w - 1, images.uiTopHeight, Graphics.RIGHT | Graphics.TOP); + } + + if(player != null) + { + if(player.getState() == Player.STARTED && images.buttons != null) + { + g.drawRegion(images.buttons, images.btnWidth, 0, images.btnWidth, images.btnHeight, Sprite.TRANS_NONE, images.uiBottomHOffset, h - images.uiBottomHeight + images.uiBottomVOffset, Graphics.LEFT | Graphics.TOP); + } + else + { + if(duration > 0 && time >= 0 && VideoOptions.showPlayProgress) + { + g.drawRect(pbx, pby, pbw, pbh); + g.fillRect(pbx + 2, pby + 2, (int)((pbw - 3) * time / duration), pbh - 3); + } + else + { + g.drawString(AuxClass.mediaTimeToString(time), w2, pby, Graphics.TOP | Graphics.HCENTER); + } + } + } + + g.setColor(images.cPlayTitle); // 0xFFFFFF); + g.setClip(images.uiTopHSpace, images.uiTopVSpace, w - images.uiTopHSpace * 2, images.uiTopHeight - images.uiTopVSpace); + + if(OnlyFileName != null) + { + g.drawString(OnlyFileName, ofnx, images.uiTopVSpace, Graphics.LEFT | Graphics.TOP); + } + + g.setClip(0, images.uiTopHeight, w, h - images.uiTopHeight - images.uiBottomHeight); + } + + /** + * УÑтановить параметры меÑта Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð²Ð¸Ð´ÐµÐ¾ + */ + private void setDisplay(boolean init) + { + if(videoControl == null) + { + return; + } + + int dw, dh, maxh, y; + + maxh = h; // enableUI ? h - images.uiTopHeight - images.uiBottomHeight : h; + y = 0; // enableUI ? images.uiTopHeight : 0; + + double aspect = (double)w / (double)maxh; + + int vw = videoControl.getSourceWidth(); + int vh = videoControl.getSourceHeight(); + + boolean rotate = false; + trans = Sprite.TRANS_NONE; + + switch(VideoOptions.rotateMode) + { + case 1: + rotate = true; + trans = Sprite.TRANS_ROT90; + break; + + case 2: + rotate = false; + trans = Sprite.TRANS_ROT180; + break; + + case 3: + rotate = true; + trans = Sprite.TRANS_ROT270; + break; + + case 4: + if(vw > vh) + { + rotate = true; + trans = Sprite.TRANS_ROT90; + } + break; + + case 5: + if(vw > vh) + { + rotate = true; + trans = Sprite.TRANS_ROT270; + } + break; + } + + if(init) + { + overlay = true; + + try + { + videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO | (trans << 4) | (1 << 8), getRenderer()); + } + catch(Exception e) + { + try + { + videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO | (trans << 4), getRenderer()); + overlay = false; + } + catch(Exception e1) + { + try + { + videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO | (1 << 8), getRenderer()); + } + catch(Exception e2) + { + videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO, getRenderer()); + overlay = false; + } + + rotate = false; + trans = Sprite.TRANS_NONE; + } + } + } + + if(true) // VideoOptions.scaleImages) + { + double pictureAspect = (double)vw / (double)vh; + + if(rotate) + { + if(pictureAspect > (1 / aspect)) + { + dw = maxh; + dh = (int)(maxh / pictureAspect); + } + else + { + dw = (int)(w * pictureAspect); + dh = w; + } + } + else + { + if(pictureAspect > aspect) + { + dw = w; + dh = (int)(w / pictureAspect); + } + else + { + dw = (int)(maxh * pictureAspect); + dh = maxh; + } + } + } + + //System.out.println("Video rescaled from " + vw + "x" + vh + " to " + dw + "x" + dh); + + if(rotate) + { + dw ^= dh; + dh ^= dw; + dw ^= dh; + } + + videoControl.setDisplayLocation((w - dw) / 2, y + (maxh - dh) / 2); + + try + { + videoControl.setDisplaySize(dw, dh); + } + catch(Exception e) + { + //ErrScreen.showErrMsg(62, e); + } + + videoControl.setVisible(isshown); + } + + private void replayVideo() + { + long prevtime = player.getMediaTime(); + + main.FileSelect.executeFile(playlist, null, runpanel); + + try + { + playerPause(); + player.setMediaTime(prevtime); + playerStart(); + } + catch(MediaException me) + { + } + } + + /** + * Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿Ð¾Ñ‚Ð¾ÐºÐ° + */ + public void run() + { + if(wasPaused) + { + paused = true; + } + else + { + playerStart(); + } + + long prevtime = System.currentTimeMillis(); + boolean repaints; + + while(running) // цикл + { + repaints = false; + + if(System.currentTimeMillis() - prevtime > 300) + { + prevtime = System.currentTimeMillis(); + + if(ofndelay > 0) + { + ofndelay--; + } + else + { + ofnx += ofnstep; + } + + if(ofnstep > 0) + { + if(ofnx > images.uiTopHSpace) + { + ofnx = images.uiTopHSpace; + ofnstep = -ofnstep; + ofndelay = OFN_DEF_DELAY; + } + } + else if(ofnstep < 0) + { + if(ofnx < w - images.uiTopHSpace - ofnw) + { + ofnx = w - images.uiTopHSpace - ofnw; + ofnstep = -ofnstep; + ofndelay = OFN_DEF_DELAY; + } + } + + if(VideoOptions.useAccelerometer) + { + final int delta = main.accelerometer.getDelta(0, 1200); + + if(delta != 0) + { + Runnable runnable = new Runnable() + { + public void run() + { + if(delta > 0) + { + nextClip(); + } + else if(delta < 0) + { + prevClip(); + } + } + }; + + (new Thread(runnable, "VideoPlayer/AccelEvent")).start(); + } + } + + repaints = enableUI; + } + + if(repaints || keyFlag) + { + repaint(); + //serviceRepaints(); + } + + try + { + Thread.sleep(60); + } + catch(InterruptedException ie) + { + } + } + } + + /** + * Обработчик Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ ÐºÐ½Ð¾Ð¿Ð¾Ðº + * + * @param key int + */ + public void keyPressed(int key) + { + key = rotateKey(translateKey(key), trans); + + if(key == KEY_RSK) // краÑÐ½Ð°Ñ - выход + { + destroyPlayer(); + wasPaused = false; + + // Возврат + //main.manager.setCurrent(main.FileSelect, runpanel); + main.manager.ret(); + + playlist.cancelSearch(); + playlist = null; + + runpanel = -1; + } + else if(key == KEY_CANCEL) // назад или краÑÐ½Ð°Ñ - ÑворачиваемÑÑ + { + main.manager.minimizePanel(); + } + else if(player != null) + { + if(key == KEY_LSK || key == KEY_FIRE) // Ð»ÐµÐ²Ð°Ñ Ñофт или Ð·ÐµÐ»ÐµÐ½Ð°Ñ - пауза/воÑпроизведение + { + if(player.getState() == Player.STARTED) + { + playerPause(); + wasPaused = true; + } + else if(player.getState() == Player.PREFETCHED) + { + playerStart(); + wasPaused = false; + } + } + else if(key == KEY_UP) // Volume up + { + if(!VideoOptions.muted) + { + VideoOptions.volume += 5; + + if(VideoOptions.volume > 100) + { + VideoOptions.volume = 100; + } + + if(volumeControl != null) + { + volumeControl.setLevel(VideoOptions.volume); + } + } + } + else if(key == KEY_DOWN) // Volume down + { + if(!VideoOptions.muted) + { + VideoOptions.volume -= 5; + + if(VideoOptions.volume < 0) + { + VideoOptions.volume = 0; + } + + if(volumeControl != null) + { + volumeControl.setLevel(VideoOptions.volume); + } + } + } + else if(key == KEY_DIAL) // Mute + { + VideoOptions.muted = !VideoOptions.muted; + + if(volumeControl != null) + { + volumeControl.setMute(VideoOptions.muted); + } + } + else if(key == KEY_NUM0) + { + VideoOptions.shufflePlay = !VideoOptions.shufflePlay; + (new Thread(videoRedisplayTask, "VideoPlayer/VideoRedisplay")).start(); + } + else if(key == KEY_POUND) + { + enableUI = !enableUI; + (new Thread(videoRedisplayTask, "VideoPlayer/VideoRedisplay")).start(); + } + else if(key == KEY_STAR) + { + if(true) // rotation) + { + if(++VideoOptions.rotateMode > 3) + { + VideoOptions.rotateMode = 0; + } + + replayVideo(); + } + } + } + } + + public void keyReleased(int key) + { + key = rotateKey(translateKey(key), trans); + + if(keyFlag) + { + try + { + player.setMediaTime(time); + } + catch(MediaException me) + { + } + + if(!wasPaused) + { + playerStart(); + } + + keyFlag = false; + } + else + { + if(key == KEY_RIGHT) // Ñледующий звук + { + nextClip(); + } + else if(key == KEY_LEFT) // предыдущий звук + { + prevClip(); + } + } + } + + public void keyRepeated(int keyCode) + { + int key = rotateKey(translateKey(keyCode), trans); + + if(key == KEY_RIGHT) // перемотка вперед + { + if(!keyFlag) + { + if(!wasPaused) + { + playerPause(); + } + + keyFlag = true; + } + + time += tstep; + + if(time > duration) + { + time = duration; + } + } + else if(key == KEY_LEFT) // перемотка назад + { + if(!keyFlag) + { + playerPause(); + keyFlag = true; + } + + time -= tstep; + + if(time < 0) + { + time = 0; + } + } + else + { + keyPressed(keyCode); + } + } + + /** + * Уничтожение плеера Ñ Ð¿Ñ€ÐµÐ´Ð²Ð°Ñ€Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ñ‹Ð¼ оÑтановом + */ + private void destroyPlayer() + { + OnlyFileName = Locale.getString(this, Locale.WAIT_PLEASE); + ofnw = 0; + ofnx = images.uiTopHSpace; + ofnstep = 0; + + time = 0; + + running = false; + + if(t != null) + { + if(t.isAlive()) + { + try + { + t.join(); + } + catch(InterruptedException ie) + { + } + } + + t = null; + } + + if(player != null) + { + try + { + player.stop(); + player.close(); + } + catch(Exception e) + { + //System.out.println("Cannot stop and exit player"); + //ErrScreen.showErrMsg(100, e); + } + + player = null; + } + + if(is != null) + { + try + { + is.close(); + } + catch(Exception e) + { + } + + is = null; + } + + main.startLightControl(false); + } + + /** + * Пауза плеера + */ + private void playerPause() + { + if(player == null) + { + return; + } + + try + { + time = player.getMediaTime(); + player.stop(); + paused = true; + repaint(); + } + catch(Exception e) + { + //System.out.println ("Cannot pause player"); + //e.printStackTrace (); + } + + main.startLightControl(false); + } + + /** + * ЗапуÑк плеера + */ + private void playerStart() + { + if(player == null) + { + return; + } + + try + { + player.start(); + + if(player.getState() == Player.STARTED) + { + paused = false; + repaint(); + + main.startLightControl(true); + } + } + catch(Exception e) + { + ErrScreen.showErrMsg(63, e); + } + } + + /** + * Перейти к Ñледующему видеофайлу + */ + private void nextClip() + { + destroyPlayer(); + + playlist.nextElement(VideoOptions.shufflePlay && !paused); + main.FileSelect.executeFile(playlist, null, runpanel); + } + + /** + * Перейти к предыдущему видеофайлу + */ + private void prevClip() + { + destroyPlayer(); + + playlist.prevElement(VideoOptions.shufflePlay && !paused); + main.FileSelect.executeFile(playlist, null, runpanel); + } + + /** + * Скроллинг текÑта TEXT (кол-во Ñимволов COUNT) + * + * @param text String + * @param count int + * @return String + */ + /* + private String scrollText(String text, int count) + { + String tmp = text; + int len = text.length(); + int scr = len - count; + if(len > count) + { + tmp = text.substring(scrollPos, scrollPos + count); + if(scrolldirection) + scrollPos--; + else + scrollPos++; + if(scrollPos > scr) + { + scrollPos--; + scrolldirection = !scrolldirection; + } + else if(scrollPos < 0) + { + scrollPos = 0; + scrolldirection = !scrolldirection; + } + } + return tmp; + } + */ + +// private static void out(String s) +// { +// System.out.println("[cvsVideoPlayer] " + s); +// } +} \ No newline at end of file diff --git a/src/org/apache/regexp/CharacterArrayCharacterIterator.java b/src/org/apache/regexp/CharacterArrayCharacterIterator.java new file mode 100644 index 0000000..9ed8352 --- /dev/null +++ b/src/org/apache/regexp/CharacterArrayCharacterIterator.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.regexp; + +/** + * Encapsulates char[] as CharacterIterator + * + * @author Ales Novak + * @version CVS $Id: CharacterArrayCharacterIterator.java 518156 2007-03-14 14:31:26Z vgritsenko $ + */ +public final class CharacterArrayCharacterIterator implements CharacterIterator +{ + /** encapsulated */ + private final char[] src; + /** offset in the char array */ + private final int off; + /** used portion of the array */ + private final int len; + + /** @param src - encapsulated String */ + public CharacterArrayCharacterIterator(char[] src, int off, int len) + { + this.src = src; + this.off = off; + this.len = len; + } + + /** @return a substring */ + public String substring(int beginIndex, int endIndex) + { + if (endIndex > len) { + throw new IndexOutOfBoundsException("endIndex=" + endIndex + + "; sequence size=" + len); + } + if (beginIndex < 0 || beginIndex > endIndex) { + throw new IndexOutOfBoundsException("beginIndex=" + beginIndex + + "; endIndex=" + endIndex); + } + return new String(src, off + beginIndex, endIndex - beginIndex); + } + + /** @return a substring */ + public String substring(int beginIndex) + { + return substring(beginIndex, len); + } + + /** @return a character at the specified position. */ + public char charAt(int pos) + { + return src[off + pos]; + } + + /** @return true iff if the specified index is after the end of the character stream */ + public boolean isEnd(int pos) + { + return (pos >= len); + } +} diff --git a/src/org/apache/regexp/CharacterIterator.java b/src/org/apache/regexp/CharacterIterator.java new file mode 100644 index 0000000..557ef6c --- /dev/null +++ b/src/org/apache/regexp/CharacterIterator.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.regexp; + +/** + * Encapsulates different types of character sources - String, InputStream, ... + * Defines a set of common methods + * + * @author Ales Novak + * @version CVS $Id: CharacterIterator.java 518156 2007-03-14 14:31:26Z vgritsenko $ + */ +public interface CharacterIterator +{ + /** @return a substring */ + String substring(int beginIndex, int endIndex); + + /** @return a substring */ + String substring(int beginIndex); + + /** @return a character at the specified position. */ + char charAt(int pos); + + /** @return true iff if the specified index is after the end of the character stream */ + boolean isEnd(int pos); +} diff --git a/src/org/apache/regexp/RE.java b/src/org/apache/regexp/RE.java new file mode 100644 index 0000000..1c87b03 --- /dev/null +++ b/src/org/apache/regexp/RE.java @@ -0,0 +1,1803 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.regexp; + +import com.classpath.util.Characters; +import java.util.Vector; + +/** + * RE is an efficient, lightweight regular expression evaluator/matcher + * class. Regular expressions are pattern descriptions which enable + * sophisticated matching of strings. In addition to being able to + * match a string against a pattern, you can also extract parts of the + * match. This is especially useful in text parsing! Details on the + * syntax of regular expression patterns are given below. + * + *

+ * To compile a regular expression (RE), you can simply construct an RE + * matcher object from the string specification of the pattern, like this: + * + *

+ *  RE r = new RE("a*b");
+ * 
+ * + *

+ * Once you have done this, you can call either of the RE.match methods to + * perform matching on a String. For example: + * + *

+ *  boolean matched = r.match("aaaab");
+ * 
+ * + * will cause the boolean matched to be set to true because the + * pattern "a*b" matches the string "aaaab". + * + *

+ * If you were interested in the number of a's which matched the + * first part of our example expression, you could change the expression to + * "(a*)b". Then when you compiled the expression and matched it against + * something like "xaaaab", you would get results like this: + * + *

+ *  RE r = new RE("(a*)b");                  // Compile expression
+ *  boolean matched = r.match("xaaaab");     // Match against "xaaaab"
+ *
+ *  String wholeExpr = r.getParen(0);        // wholeExpr will be 'aaaab'
+ *  String insideParens = r.getParen(1);     // insideParens will be 'aaaa'
+ *
+ *  int startWholeExpr = r.getParenStart(0); // startWholeExpr will be index 1
+ *  int endWholeExpr = r.getParenEnd(0);     // endWholeExpr will be index 6
+ *  int lenWholeExpr = r.getParenLength(0);  // lenWholeExpr will be 5
+ *
+ *  int startInside = r.getParenStart(1);    // startInside will be index 1
+ *  int endInside = r.getParenEnd(1);        // endInside will be index 5
+ *  int lenInside = r.getParenLength(1);     // lenInside will be 4
+ * 
+ * + * You can also refer to the contents of a parenthesized expression + * within a regular expression itself. This is called a + * 'backreference'. The first backreference in a regular expression is + * denoted by \1, the second by \2 and so on. So the expression: + * + *
+ *  ([0-9]+)=\1
+ * 
+ * + * will match any string of the form n=n (like 0=0 or 2=2). + * + *

+ * The full regular expression syntax accepted by RE is described here: + * + *

+ *
+ *  Characters
+ *
+ *    unicodeChar   Matches any identical unicode character
+ *    \                    Used to quote a meta-character (like '*')
+ *    \\                   Matches a single '\' character
+ *    \0nnn                Matches a given octal character
+ *    \xhh                 Matches a given 8-bit hexadecimal character
+ *    \\uhhhh              Matches a given 16-bit hexadecimal character
+ *    \t                   Matches an ASCII tab character
+ *    \n                   Matches an ASCII newline character
+ *    \r                   Matches an ASCII return character
+ *    \f                   Matches an ASCII form feed character
+ *
+ *
+ *  Character Classes
+ *
+ *    [abc]                Simple character class
+ *    [a-zA-Z]             Character class with ranges
+ *    [^abc]               Negated character class
+ * 
+ * + * NOTE: Incomplete ranges will be interpreted as "starts + * from zero" or "ends with last character". + *
+ * I.e. [-a] is the same as [\\u0000-a], and [a-] is the same as [a-\\uFFFF], + * [-] means "all characters". + * + *
+ *
+ *  Standard POSIX Character Classes
+ *
+ *    [:alnum:]            Alphanumeric characters.
+ *    [:alpha:]            Alphabetic characters.
+ *    [:blank:]            Space and tab characters.
+ *    [:cntrl:]            Control characters.
+ *    [:digit:]            Numeric characters.
+ *    [:graph:]            Characters that are printable and are also visible.
+ *                         (A space is printable, but not visible, while an
+ *                         `a' is both.)
+ *    [:lower:]            Lower-case alphabetic characters.
+ *    [:print:]            Printable characters (characters that are not
+ *                         control characters.)
+ *    [:punct:]            Punctuation characters (characters that are not letter,
+ *                         digits, control characters, or space characters).
+ *    [:space:]            Space characters (such as space, tab, and formfeed,
+ *                         to name a few).
+ *    [:upper:]            Upper-case alphabetic characters.
+ *    [:xdigit:]           Characters that are hexadecimal digits.
+ *
+ *
+ *  Non-standard POSIX-style Character Classes
+ *
+ *    [:javastart:]        Start of a Java identifier
+ *    [:javapart:]         Part of a Java identifier
+ *
+ *
+ *  Predefined Classes
+ *
+ *    .         Matches any character other than newline
+ *    \w        Matches a "word" character (alphanumeric plus "_")
+ *    \W        Matches a non-word character
+ *    \s        Matches a whitespace character
+ *    \S        Matches a non-whitespace character
+ *    \d        Matches a digit character
+ *    \D        Matches a non-digit character
+ *
+ *
+ *  Boundary Matchers
+ *
+ *    ^         Matches only at the beginning of a line
+ *    $         Matches only at the end of a line
+ *    \b        Matches only at a word boundary
+ *    \B        Matches only at a non-word boundary
+ *
+ *
+ *  Greedy Closures
+ *
+ *    A*        Matches A 0 or more times (greedy)
+ *    A+        Matches A 1 or more times (greedy)
+ *    A?        Matches A 1 or 0 times (greedy)
+ *    A{n}      Matches A exactly n times (greedy)
+ *    A{n,}     Matches A at least n times (greedy)
+ *    A{n,m}    Matches A at least n but not more than m times (greedy)
+ *
+ *
+ *  Reluctant Closures
+ *
+ *    A*?       Matches A 0 or more times (reluctant)
+ *    A+?       Matches A 1 or more times (reluctant)
+ *    A??       Matches A 0 or 1 times (reluctant)
+ *
+ *
+ *  Logical Operators
+ *
+ *    AB        Matches A followed by B
+ *    A|B       Matches either A or B
+ *    (A)       Used for subexpression grouping
+ *   (?:A)      Used for subexpression clustering (just like grouping but
+ *              no backrefs)
+ *
+ *
+ *  Backreferences
+ *
+ *    \1    Backreference to 1st parenthesized subexpression
+ *    \2    Backreference to 2nd parenthesized subexpression
+ *    \3    Backreference to 3rd parenthesized subexpression
+ *    \4    Backreference to 4th parenthesized subexpression
+ *    \5    Backreference to 5th parenthesized subexpression
+ *    \6    Backreference to 6th parenthesized subexpression
+ *    \7    Backreference to 7th parenthesized subexpression
+ *    \8    Backreference to 8th parenthesized subexpression
+ *    \9    Backreference to 9th parenthesized subexpression
+ * 
+ * + *

+ * All closure operators (+, *, ?, {m,n}) are greedy by default, meaning + * that they match as many elements of the string as possible without + * causing the overall match to fail. If you want a closure to be + * reluctant (non-greedy), you can simply follow it with a '?'. A + * reluctant closure will match as few elements of the string as + * possible when finding matches. {m,n} closures don't currently + * support reluctancy. + * + *

+ * Line terminators + *
+ * A line terminator is a one- or two-character sequence that marks + * the end of a line of the input character sequence. The following + * are recognized as line terminators: + *

    + *
  • A newline (line feed) character ('\n'),
  • + *
  • A carriage-return character followed immediately by a newline character ("\r\n"),
  • + *
  • A standalone carriage-return character ('\r'),
  • + *
  • A next-line character ('\u0085'),
  • + *
  • A line-separator character ('\u2028'), or
  • + *
  • A paragraph-separator character ('\u2029).
  • + *
+ * + *

+ * RE runs programs compiled by the RECompiler class. But the RE + * matcher class does not include the actual regular expression compiler + * for reasons of efficiency. In fact, if you want to pre-compile one + * or more regular expressions, the 'recompile' class can be invoked + * from the command line to produce compiled output like this: + * + *

+ *    // Pre-compiled regular expression "a*b"
+ *    char[] re1Instructions =
+ *    {
+ *        0x007c, 0x0000, 0x001a, 0x007c, 0x0000, 0x000d, 0x0041,
+ *        0x0001, 0x0004, 0x0061, 0x007c, 0x0000, 0x0003, 0x0047,
+ *        0x0000, 0xfff6, 0x007c, 0x0000, 0x0003, 0x004e, 0x0000,
+ *        0x0003, 0x0041, 0x0001, 0x0004, 0x0062, 0x0045, 0x0000,
+ *        0x0000,
+ *    };
+ *
+ *
+ *    REProgram re1 = new REProgram(re1Instructions);
+ * 
+ * + * You can then construct a regular expression matcher (RE) object from + * the pre-compiled expression re1 and thus avoid the overhead of + * compiling the expression at runtime. If you require more dynamic + * regular expressions, you can construct a single RECompiler object and + * re-use it to compile each expression. Similarly, you can change the + * program run by a given matcher object at any time. However, RE and + * RECompiler are not threadsafe (for efficiency reasons, and because + * requiring thread safety in this class is deemed to be a rare + * requirement), so you will need to construct a separate compiler or + * matcher object for each thread (unless you do thread synchronization + * yourself). Once expression compiled into the REProgram object, REProgram + * can be safely shared across multiple threads and RE objects. + * + *


+ * + * + * ISSUES: + * + *

    + *
  • com.weusours.util.re is not currently compatible with all + * standard POSIX regcomp flags
  • + *
  • com.weusours.util.re does not support POSIX equivalence classes + * ([=foo=] syntax) (I18N/locale issue)
  • + *
  • com.weusours.util.re does not support nested POSIX character + * classes (definitely should, but not completely trivial)
  • + *
  • com.weusours.util.re Does not support POSIX character collation + * concepts ([.foo.] syntax) (I18N/locale issue)
  • + *
  • Should there be different matching styles (simple, POSIX, Perl etc?)
  • + *
  • Should RE support character iterators (for backwards RE matching!)?
  • + *
  • Should RE support reluctant {m,n} closures (does anyone care)?
  • + *
  • Not *all* possibilities are considered for greediness when backreferences + * are involved (as POSIX suggests should be the case). The POSIX RE + * "(ac*)c*d[ac]*\1", when matched against "acdacaa" should yield a match + * of acdacaa where \1 is "a". This is not the case in this RE package, + * and actually Perl doesn't go to this extent either! Until someone + * actually complains about this, I'm not sure it's worth "fixing". + * If it ever is fixed, test #137 in RETest.txt should be updated.
  • + *
+ * + * + * + * @see recompile + * @see RECompiler + * + * @author Jonathan Locke + * @author Tobias Schäfer + * @version $Id: RE.java 518156 2007-03-14 14:31:26Z vgritsenko $ + */ +public class RE +{ + /** + * Specifies normal, case-sensitive matching behaviour. + */ + public static final int MATCH_NORMAL = 0x0000; + + /** + * Flag to indicate that matching should be case-independent (folded) + */ + public static final int MATCH_CASEINDEPENDENT = 0x0001; + + /** + * Newlines should match as BOL/EOL (^ and $) + */ + public static final int MATCH_MULTILINE = 0x0002; + + /** + * Consider all input a single body of text - newlines are matched by . + */ + public static final int MATCH_SINGLELINE = 0x0004; + + /************************************************ + * * + * The format of a node in a program is: * + * * + * [ OPCODE ] [ OPDATA ] [ OPNEXT ] [ OPERAND ] * + * * + * char OPCODE - instruction * + * char OPDATA - modifying data * + * char OPNEXT - next node (relative offset) * + * * + ************************************************/ + + // Opcode Char Opdata/Operand Meaning + // ---------- ---------- --------------- -------------------------------------------------- + static final char OP_END = 'E'; // end of program + static final char OP_BOL = '^'; // match only if at beginning of line + static final char OP_EOL = '$'; // match only if at end of line + static final char OP_ANY = '.'; // match any single character except newline + static final char OP_ANYOF = '['; // count/ranges match any char in the list of ranges + static final char OP_BRANCH = '|'; // node match this alternative or the next one + static final char OP_ATOM = 'A'; // length/string length of string followed by string itself + static final char OP_STAR = '*'; // node kleene closure + static final char OP_PLUS = '+'; // node positive closure + static final char OP_MAYBE = '?'; // node optional closure + static final char OP_ESCAPE = '\\'; // escape special escape code char class (escape is E_* code) + static final char OP_OPEN = '('; // number nth opening paren + static final char OP_OPEN_CLUSTER = '<'; // opening cluster + static final char OP_CLOSE = ')'; // number nth closing paren + static final char OP_CLOSE_CLUSTER = '>'; // closing cluster + static final char OP_BACKREF = '#'; // number reference nth already matched parenthesized string + static final char OP_GOTO = 'G'; // nothing but a (back-)pointer + static final char OP_NOTHING = 'N'; // match null string such as in '(a|)' + static final char OP_CONTINUE = 'C'; // continue to the following command (ignore next) + static final char OP_RELUCTANTSTAR = '8'; // none/expr reluctant '*' (mnemonic for char is unshifted '*') + static final char OP_RELUCTANTPLUS = '='; // none/expr reluctant '+' (mnemonic for char is unshifted '+') + static final char OP_RELUCTANTMAYBE = '/'; // none/expr reluctant '?' (mnemonic for char is unshifted '?') + static final char OP_POSIXCLASS = 'P'; // classid one of the posix character classes + + // Escape codes + static final char E_ALNUM = 'w'; // Alphanumeric + static final char E_NALNUM = 'W'; // Non-alphanumeric + static final char E_BOUND = 'b'; // Word boundary + static final char E_NBOUND = 'B'; // Non-word boundary + static final char E_SPACE = 's'; // Whitespace + static final char E_NSPACE = 'S'; // Non-whitespace + static final char E_DIGIT = 'd'; // Digit + static final char E_NDIGIT = 'D'; // Non-digit + + // Posix character classes + static final char POSIX_CLASS_ALNUM = 'w'; // Alphanumerics + static final char POSIX_CLASS_ALPHA = 'a'; // Alphabetics + static final char POSIX_CLASS_BLANK = 'b'; // Blanks + static final char POSIX_CLASS_CNTRL = 'c'; // Control characters + static final char POSIX_CLASS_DIGIT = 'd'; // Digits + static final char POSIX_CLASS_GRAPH = 'g'; // Graphic characters + static final char POSIX_CLASS_LOWER = 'l'; // Lowercase characters + static final char POSIX_CLASS_PRINT = 'p'; // Printable characters + static final char POSIX_CLASS_PUNCT = '!'; // Punctuation + static final char POSIX_CLASS_SPACE = 's'; // Spaces + static final char POSIX_CLASS_UPPER = 'u'; // Uppercase characters + static final char POSIX_CLASS_XDIGIT = 'x'; // Hexadecimal digits + static final char POSIX_CLASS_JSTART = 'j'; // Java identifier start + static final char POSIX_CLASS_JPART = 'k'; // Java identifier part + + // Limits + static final int maxNode = 65536; // Maximum number of nodes in a program + static final int MAX_PAREN = 16; // Number of paren pairs (only 9 can be backrefs) + + // Node layout constants + static final int offsetOpcode = 0; // Opcode offset (first character) + static final int offsetOpdata = 1; // Opdata offset (second char) + static final int offsetNext = 2; // Next index offset (third char) + static final int nodeSize = 3; // Node size (in chars) + + // State of current program + REProgram program; // Compiled regular expression 'program' + transient CharacterIterator search; // The string being matched against + int matchFlags; // Match behaviour flags + int maxParen = MAX_PAREN; + + // Parenthesized subexpressions + transient int parenCount; // Number of subexpressions matched (num open parens + 1) + transient int start0; // Cache of start[0] + transient int end0; // Cache of start[0] + transient int start1; // Cache of start[1] + transient int end1; // Cache of start[1] + transient int start2; // Cache of start[2] + transient int end2; // Cache of start[2] + transient int[] startn; // Lazy-alloced array of sub-expression starts + transient int[] endn; // Lazy-alloced array of sub-expression ends + + // Backreferences + transient int[] startBackref; // Lazy-alloced array of backref starts + transient int[] endBackref; // Lazy-alloced array of backref ends + + /** + * Constructs a regular expression matcher from a String by compiling it + * using a new instance of RECompiler. If you will be compiling many + * expressions, you may prefer to use a single RECompiler object instead. + * + * @param pattern The regular expression pattern to compile. + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + * @see RECompiler + * @see recompile + */ + public RE(String pattern) throws RESyntaxException + { + this(pattern, MATCH_NORMAL); + } + + /** + * Constructs a regular expression matcher from a String by compiling it + * using a new instance of RECompiler. If you will be compiling many + * expressions, you may prefer to use a single RECompiler object instead. + * + * @param pattern The regular expression pattern to compile. + * @param matchFlags The matching style + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + * @see RECompiler + * @see recompile + */ + public RE(String pattern, int matchFlags) throws RESyntaxException + { + this(new RECompiler().compile(pattern), matchFlags); + } + + /** + * Construct a matcher for a pre-compiled regular expression from program + * (bytecode) data. Permits special flags to be passed in to modify matching + * behaviour. + * + * @param program Compiled regular expression program (see RECompiler and/or recompile) + * @param matchFlags One or more of the RE match behaviour flags (RE.MATCH_*): + * + *
+     *   MATCH_NORMAL              // Normal (case-sensitive) matching
+     *   MATCH_CASEINDEPENDENT     // Case folded comparisons
+     *   MATCH_MULTILINE           // Newline matches as BOL/EOL
+     * 
+ * + * @see RECompiler + * @see REProgram + * @see recompile + */ + public RE(REProgram program, int matchFlags) + { + setProgram(program); + setMatchFlags(matchFlags); + } + + /** + * Construct a matcher for a pre-compiled regular expression from program + * (bytecode) data. + * + * @param program Compiled regular expression program + * @see RECompiler + * @see recompile + */ + public RE(REProgram program) + { + this(program, MATCH_NORMAL); + } + + /** + * Constructs a regular expression matcher with no initial program. + * This is likely to be an uncommon practice, but is still supported. + */ + public RE() + { + this((REProgram) null, MATCH_NORMAL); + } + + /** + * Converts a 'simplified' regular expression to a full regular expression + * + * @param pattern The pattern to convert + * @return The full regular expression + */ + public static String simplePatternToFullRegularExpression(String pattern) + { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < pattern.length(); i++) + { + char c = pattern.charAt(i); + switch (c) + { + case '*': + buf.append(".*"); + break; + + case '.': + case '[': + case ']': + case '\\': + case '+': + case '?': + case '{': + case '}': + case '$': + case '^': + case '|': + case '(': + case ')': + buf.append('\\'); + default: + buf.append(c); + break; + } + } + return buf.toString(); + } + + /** + * Sets match behaviour flags which alter the way RE does matching. + * @param matchFlags One or more of the RE match behaviour flags (RE.MATCH_*): + * + *
+     *   MATCH_NORMAL              // Normal (case-sensitive) matching
+     *   MATCH_CASEINDEPENDENT     // Case folded comparisons
+     *   MATCH_MULTILINE           // Newline matches as BOL/EOL
+     * 
+ */ + public void setMatchFlags(int matchFlags) + { + this.matchFlags = matchFlags; + } + + /** + * Returns the current match behaviour flags. + * @return Current match behaviour flags (RE.MATCH_*). + * + *
+     *   MATCH_NORMAL              // Normal (case-sensitive) matching
+     *   MATCH_CASEINDEPENDENT     // Case folded comparisons
+     *   MATCH_MULTILINE           // Newline matches as BOL/EOL
+     * 
+ * + * @see #setMatchFlags + */ + public int getMatchFlags() + { + return matchFlags; + } + + /** + * Sets the current regular expression program used by this matcher object. + * + * @param program Regular expression program compiled by RECompiler. + * @see RECompiler + * @see REProgram + * @see recompile + */ + public void setProgram(REProgram program) + { + this.program = program; + if (program != null && program.maxParens != -1) { + this.maxParen = program.maxParens; + } else { + this.maxParen = MAX_PAREN; + } + } + + /** + * Returns the current regular expression program in use by this matcher object. + * + * @return Regular expression program + * @see #setProgram + */ + public REProgram getProgram() + { + return program; + } + + /** + * Returns the number of parenthesized subexpressions available after a successful match. + * + * @return Number of available parenthesized subexpressions + */ + public int getParenCount() + { + return parenCount; + } + + /** + * Gets the contents of a parenthesized subexpression after a successful match. + * + * @param which Nesting level of subexpression + * @return String + */ + public String getParen(int which) + { + int start; + if (which < parenCount && (start = getParenStart(which)) >= 0) + { + return search.substring(start, getParenEnd(which)); + } + return null; + } + + /** + * Returns the start index of a given paren level. + * + * @param which Nesting level of subexpression + * @return String index + */ + public final int getParenStart(int which) + { + if (which < parenCount) + { + switch (which) + { + case 0: + return start0; + + case 1: + return start1; + + case 2: + return start2; + + default: + if (startn == null) + { + allocParens(); + } + return startn[which]; + } + } + return -1; + } + + /** + * Returns the end index of a given paren level. + * + * @param which Nesting level of subexpression + * @return String index + */ + public final int getParenEnd(int which) + { + if (which < parenCount) + { + switch (which) + { + case 0: + return end0; + + case 1: + return end1; + + case 2: + return end2; + + default: + if (endn == null) + { + allocParens(); + } + return endn[which]; + } + } + return -1; + } + + /** + * Returns the length of a given paren level. + * + * @param which Nesting level of subexpression + * @return Number of characters in the parenthesized subexpression + */ + public final int getParenLength(int which) + { + if (which < parenCount) + { + return getParenEnd(which) - getParenStart(which); + } + return -1; + } + + /** + * Sets the start of a paren level + * + * @param which Which paren level + * @param i Index in input array + */ + protected final void setParenStart(int which, int i) + { + if (which < parenCount) + { + switch (which) + { + case 0: + start0 = i; + break; + + case 1: + start1 = i; + break; + + case 2: + start2 = i; + break; + + default: + if (startn == null) + { + allocParens(); + } + startn[which] = i; + break; + } + } + } + + /** + * Sets the end of a paren level + * + * @param which Which paren level + * @param i Index in input array + */ + protected final void setParenEnd(int which, int i) + { + if (which < parenCount) + { + switch (which) + { + case 0: + end0 = i; + break; + + case 1: + end1 = i; + break; + + case 2: + end2 = i; + break; + + default: + if (endn == null) + { + allocParens(); + } + endn[which] = i; + break; + } + } + } + + /** + * Throws an Error representing an internal error condition probably resulting + * from a bug in the regular expression compiler (or possibly data corruption). + * In practice, this should be very rare. + * + * @param s Error description + */ + protected void internalError(String s) throws Error + { + throw new Error("RE internal error: " + s); + } + + /** + * Performs lazy allocation of subexpression arrays + */ + private void allocParens() + { + // Allocate arrays for subexpressions + startn = new int[maxParen]; + endn = new int[maxParen]; + + // Set sub-expression pointers to invalid values + for (int i = 0; i < maxParen; i++) + { + startn[i] = -1; + endn[i] = -1; + } + } + + /** + * Try to match a string against a subset of nodes in the program + * + * @param firstNode Node to start at in program + * @param lastNode Last valid node (used for matching a subexpression without + * matching the rest of the program as well). + * @param idxStart Starting position in character array + * @return Final input array index if match succeeded. -1 if not. + */ + protected int matchNodes(int firstNode, int lastNode, int idxStart) + { + // Our current place in the string + int idx = idxStart; + + // Loop while node is valid + int next, opcode, opdata; + int idxNew; + char[] instruction = program.instruction; + for (int node = firstNode; node < lastNode; ) + { + opcode = instruction[node /* + offsetOpcode */]; + next = node + (short) instruction[node + offsetNext]; + opdata = instruction[node + offsetOpdata]; + + switch (opcode) + { + case OP_MAYBE: + case OP_STAR: + { + // Try to match the following subexpr. If it matches: + // MAYBE: Continues matching rest of the expression + // STAR: Points back here to repeat subexpr matching + if ((idxNew = matchNodes(node + nodeSize, maxNode, idx)) != -1) + { + return idxNew; + } + + // If failed, just continue with the rest of expression + break; + } + + case OP_PLUS: + { + // Try to match the subexpr again (and again (and ... + if ((idxNew = matchNodes(next, maxNode, idx)) != -1) + { + return idxNew; + } + + // If failed, just continue with the rest of expression + // Rest is located at the next pointer of the next instruction + // (which must be OP_CONTINUE) + node = next + (short) instruction[next + offsetNext]; + continue; + } + + case OP_RELUCTANTMAYBE: + case OP_RELUCTANTSTAR: + { + // Try to match the rest without using the reluctant subexpr + if ((idxNew = matchNodes(next, maxNode, idx)) != -1) + { + return idxNew; + } + + // Try reluctant subexpr. If it matches: + // RELUCTANTMAYBE: Continues matching rest of the expression + // RELUCTANTSTAR: Points back here to repeat reluctant star matching + return matchNodes(node + nodeSize, next, idx); + } + + case OP_RELUCTANTPLUS: + { + // Continue matching the rest without using the reluctant subexpr + if ((idxNew = matchNodes(next + (short) instruction[next + offsetNext], maxNode, idx)) != -1) + { + return idxNew; + } + + // Try to match subexpression again + break; + } + + case OP_OPEN: + + // Match subexpression + if ((program.flags & REProgram.OPT_HASBACKREFS) != 0) + { + startBackref[opdata] = idx; + } + if ((idxNew = matchNodes(next, maxNode, idx)) != -1) + { + // Increase valid paren count + if (opdata >= parenCount) + { + parenCount = opdata + 1; + } + + // Don't set paren if already set later on + if (getParenStart(opdata) == -1) + { + setParenStart(opdata, idx); + } + } + return idxNew; + + case OP_CLOSE: + + // Done matching subexpression + if ((program.flags & REProgram.OPT_HASBACKREFS) != 0) + { + endBackref[opdata] = idx; + } + if ((idxNew = matchNodes(next, maxNode, idx)) != -1) + { + // Increase valid paren count + if (opdata >= parenCount) + { + parenCount = opdata + 1; + } + + // Don't set paren if already set later on + if (getParenEnd(opdata) == -1) + { + setParenEnd(opdata, idx); + } + } + return idxNew; + + case OP_BACKREF: + { + // Get the start and end of the backref + int s = startBackref[opdata]; + int e = endBackref[opdata]; + + // We don't know the backref yet + if (s == -1 || e == -1) + { + return -1; + } + + // The backref is empty size + if (s == e) + { + break; + } + + // Get the length of the backref + int l = e - s; + + // If there's not enough input left, give up. + if (search.isEnd(idx + l - 1)) + { + return -1; + } + + // Case fold the backref? + final boolean caseFold = + ((matchFlags & MATCH_CASEINDEPENDENT) != 0); + // Compare backref to input + for (int i = 0; i < l; i++) + { + if (compareChars(search.charAt(idx++), search.charAt(s + i), caseFold) != 0) + { + return -1; + } + } + } + break; + + case OP_BOL: + + // Fail if we're not at the start of the string + if (idx != 0) + { + // If we're multiline matching, we could still be at the start of a line + if ((matchFlags & MATCH_MULTILINE) == MATCH_MULTILINE) + { + // Continue if at the start of a line + if (isNewline(idx - 1)) + { + break; + } + } + return -1; + } + break; + + case OP_EOL: + + // If we're not at the end of string + if (!search.isEnd(0) && !search.isEnd(idx)) + { + // If we're multi-line matching + if ((matchFlags & MATCH_MULTILINE) == MATCH_MULTILINE) + { + // Continue if we're at the end of a line + if (isNewline(idx)) + { + break; + } + } + return -1; + } + break; + + case OP_ESCAPE: + + // Which escape? + switch (opdata) + { + // Word boundary match + case E_NBOUND: + case E_BOUND: + { + char cLast = ((idx == 0) ? '\n' : search.charAt(idx - 1)); + char cNext = ((search.isEnd(idx)) ? '\n' : search.charAt(idx)); + if ((Characters.isLetterOrDigit(cLast) == Characters.isLetterOrDigit(cNext)) == (opdata == E_BOUND)) + { + return -1; + } + } + break; + + // Alpha-numeric, digit, space, javaLetter, javaLetterOrDigit + case E_ALNUM: + case E_NALNUM: + case E_DIGIT: + case E_NDIGIT: + case E_SPACE: + case E_NSPACE: + + // Give up if out of input + if (search.isEnd(idx)) + { + return -1; + } + + char c = search.charAt(idx); + + // Switch on escape + switch (opdata) + { + case E_ALNUM: + case E_NALNUM: + if (!((Characters.isLetterOrDigit(c) || c == '_') == (opdata == E_ALNUM))) + { + return -1; + } + break; + + case E_DIGIT: + case E_NDIGIT: + if (!(Characters.isDigit(c) == (opdata == E_DIGIT))) + { + return -1; + } + break; + + case E_SPACE: + case E_NSPACE: + if (!(Characters.isWhitespace(c) == (opdata == E_SPACE))) + { + return -1; + } + break; + } + idx++; + break; + + default: + internalError("Unrecognized escape '" + opdata + "'"); + } + break; + + case OP_ANY: + + if ((matchFlags & MATCH_SINGLELINE) == MATCH_SINGLELINE) { + // Match anything + if (search.isEnd(idx)) + { + return -1; + } + } + else + { + // Match anything but a newline + if (search.isEnd(idx) || isNewline(idx)) + { + return -1; + } + } + idx++; + break; + + case OP_ATOM: + { + // Match an atom value + if (search.isEnd(idx)) + { + return -1; + } + + // Get length of atom and starting index + // int lenAtom = opdata; + int startAtom = node + nodeSize; + + // Give up if not enough input remains to have a match + if (search.isEnd(opdata + idx - 1)) + { + return -1; + } + + // Match atom differently depending on casefolding flag + final boolean caseFold = + ((matchFlags & MATCH_CASEINDEPENDENT) != 0); + + for (int i = 0; i < opdata; i++) + { + if (compareChars(search.charAt(idx++), instruction[startAtom + i], caseFold) != 0) + { + return -1; + } + } + } + break; + + case OP_POSIXCLASS: + { + // Out of input? + if (search.isEnd(idx)) + { + return -1; + } + + switch (opdata) + { + case POSIX_CLASS_ALNUM: + if (!Characters.isLetterOrDigit(search.charAt(idx))) + { + return -1; + } + break; + + case POSIX_CLASS_ALPHA: + if (!Characters.isLetter(search.charAt(idx))) + { + return -1; + } + break; + + case POSIX_CLASS_DIGIT: + if (!Characters.isDigit(search.charAt(idx))) + { + return -1; + } + break; + + case POSIX_CLASS_BLANK: // JWL - bugbug: is this right?? + if (!Characters.isSpaceChar(search.charAt(idx))) + { + return -1; + } + break; + + case POSIX_CLASS_SPACE: + if (!Characters.isWhitespace(search.charAt(idx))) + { + return -1; + } + break; + + case POSIX_CLASS_CNTRL: + if (Characters.getType(search.charAt(idx)) != Characters.CONTROL) + { + return -1; + } + break; + + case POSIX_CLASS_GRAPH: // JWL - bugbug??? + switch (Characters.getType(search.charAt(idx))) + { + case Characters.MATH_SYMBOL: + case Characters.CURRENCY_SYMBOL: + case Characters.MODIFIER_SYMBOL: + case Characters.OTHER_SYMBOL: + break; + + default: + return -1; + } + break; + + case POSIX_CLASS_LOWER: + if (Characters.getType(search.charAt(idx)) != Characters.LOWERCASE_LETTER) + { + return -1; + } + break; + + case POSIX_CLASS_UPPER: + if (Characters.getType(search.charAt(idx)) != Characters.UPPERCASE_LETTER) + { + return -1; + } + break; + + case POSIX_CLASS_PRINT: + if (Characters.getType(search.charAt(idx)) == Characters.CONTROL) + { + return -1; + } + break; + + case POSIX_CLASS_PUNCT: + { + int type = Characters.getType(search.charAt(idx)); + switch(type) + { + case Characters.DASH_PUNCTUATION: + case Characters.START_PUNCTUATION: + case Characters.END_PUNCTUATION: + case Characters.CONNECTOR_PUNCTUATION: + case Characters.OTHER_PUNCTUATION: + break; + + default: + return -1; + } + } + break; + + case POSIX_CLASS_XDIGIT: // JWL - bugbug?? + { + boolean isXDigit = ((search.charAt(idx) >= '0' && search.charAt(idx) <= '9') || + (search.charAt(idx) >= 'a' && search.charAt(idx) <= 'f') || + (search.charAt(idx) >= 'A' && search.charAt(idx) <= 'F')); + if (!isXDigit) + { + return -1; + } + } + break; + + case POSIX_CLASS_JSTART: + if (!Characters.isJavaIdentifierStart(search.charAt(idx))) + { + return -1; + } + break; + + case POSIX_CLASS_JPART: + if (!Characters.isJavaIdentifierPart(search.charAt(idx))) + { + return -1; + } + break; + + default: + internalError("Bad posix class"); + break; + } + + // Matched. + idx++; + } + break; + + case OP_ANYOF: + { + // Out of input? + if (search.isEnd(idx)) + { + return -1; + } + + // Get character to match against character class and maybe casefold + char c = search.charAt(idx); + boolean caseFold = (matchFlags & MATCH_CASEINDEPENDENT) != 0; + // Loop through character class checking our match character + int idxRange = node + nodeSize; + int idxEnd = idxRange + (opdata * 2); + boolean match = false; + for (int i = idxRange; !match && i < idxEnd; ) + { + // Get start, end and match characters + char s = instruction[i++]; + char e = instruction[i++]; + + match = ((compareChars(c, s, caseFold) >= 0) + && (compareChars(c, e, caseFold) <= 0)); + } + + // Fail if we didn't match the character class + if (!match) + { + return -1; + } + idx++; + } + break; + + case OP_BRANCH: + { + // Check for choices + // FIXME Dead code - only reason to keep is backward compat with pre-compiled exprs. Remove? + if (instruction[next /* + offsetOpcode */] != OP_BRANCH) + { + // If there aren't any other choices, just evaluate this branch. + node += nodeSize; + continue; + } + + // Try all available branches + int nextBranch; + do + { + // Try matching the branch against the string + if ((idxNew = matchNodes(node + nodeSize, maxNode, idx)) != -1) + { + return idxNew; + } + + // Go to next branch (if any) + nextBranch = (short) instruction[node + offsetNext]; + node += nextBranch; + } + while (nextBranch != 0 && (instruction[node /* + offsetOpcode */] == OP_BRANCH)); + + // Failed to match any branch! + return -1; + } + + case OP_OPEN_CLUSTER: + case OP_CLOSE_CLUSTER: + // starting or ending the matching of a subexpression which has no backref. + + case OP_NOTHING: + case OP_GOTO: + + // Just advance to the next node without doing anything + break; + + case OP_CONTINUE: + + // Advance to the following node + node += nodeSize; + continue; + + case OP_END: + + // Match has succeeded! + setParenEnd(0, idx); + return idx; + + default: + + // Corrupt program + internalError("Invalid opcode '" + opcode + "'"); + } + + // Advance to the next node in the program + node = next; + } + + // We "should" never end up here + internalError("Corrupt program"); + return -1; + } + + /** + * Match the current regular expression program against the current + * input string, starting at index i of the input string. This method + * is only meant for internal use. + * + * @param i The input string index to start matching at + * @return True if the input matched the expression + */ + protected boolean matchAt(int i) + { + // Initialize start pointer, paren cache and paren count + start0 = -1; + end0 = -1; + start1 = -1; + end1 = -1; + start2 = -1; + end2 = -1; + startn = null; + endn = null; + parenCount = 1; + setParenStart(0, i); + + // Allocate backref arrays (unless optimizations indicate otherwise) + if ((program.flags & REProgram.OPT_HASBACKREFS) != 0) + { + startBackref = new int[maxParen]; + endBackref = new int[maxParen]; + } + + // Match against string + int idx; + if ((idx = matchNodes(0, maxNode, i)) != -1) + { + setParenEnd(0, idx); + return true; + } + + // Didn't match + parenCount = 0; + return false; + } + + /** + * Matches the current regular expression program against a character array, + * starting at a given index. + * + * @param search String to match against + * @param i Index to start searching at + * @return True if string matched + */ + public boolean match(String search, int i) + { + return match(new StringCharacterIterator(search), i); + } + + /** + * Matches the current regular expression program against a character array, + * starting at a given index. + * + * @param search String to match against + * @param i Index to start searching at + * @return True if string matched + */ + public boolean match(CharacterIterator search, int i) + { + // There is no compiled program to search with! + if (program == null) + { + // This should be uncommon enough to be an error case rather + // than an exception (which would have to be handled everywhere) + internalError("No RE program to run!"); + } + + // Save string to search + this.search = search; + + // Can we optimize the search by looking for new lines? + if ((program.flags & REProgram.OPT_HASBOL) == REProgram.OPT_HASBOL) + { + // Non multi-line matching with BOL: Must match at '0' index + if ((matchFlags & MATCH_MULTILINE) == 0) + { + return i == 0 && matchAt(i); + } + + // Multi-line matching with BOL: Seek to next line + for ( ;! search.isEnd(i); i++) + { + // Skip if we are at the beginning of the line + if (isNewline(i)) + { + continue; + } + + // Match at the beginning of the line + if (matchAt(i)) + { + return true; + } + + // Skip to the end of line + for ( ;! search.isEnd(i); i++) + { + if (isNewline(i)) + { + break; + } + } + } + + return false; + } + + // Can we optimize the search by looking for a prefix string? + if (program.prefix == null) + { + // Unprefixed matching must try for a match at each character + for ( ;! search.isEnd(i - 1); i++) + { + // Try a match at index i + if (matchAt(i)) + { + return true; + } + } + return false; + } + else + { + // Prefix-anchored matching is possible + boolean caseIndependent = (matchFlags & MATCH_CASEINDEPENDENT) != 0; + char[] prefix = program.prefix; + for ( ; !search.isEnd(i + prefix.length - 1); i++) + { + int j = i; + int k = 0; + + boolean match; + do { + // If there's a mismatch of any character in the prefix, give up + match = (compareChars(search.charAt(j++), prefix[k++], caseIndependent) == 0); + } while (match && k < prefix.length); + + // See if the whole prefix string matched + if (k == prefix.length) + { + // We matched the full prefix at firstChar, so try it + if (matchAt(i)) + { + return true; + } + } + } + return false; + } + } + + /** + * Matches the current regular expression program against a String. + * + * @param search String to match against + * @return True if string matched + */ + public boolean match(String search) + { + return match(search, 0); + } + + /** + * Splits a string into an array of strings on regular expression boundaries. + * This function works the same way as the Perl function of the same name. + * Given a regular expression of "[ab]+" and a string to split of + * "xyzzyababbayyzabbbab123", the result would be the array of Strings + * "[xyzzy, yyz, 123]". + * + *

Please note that the first string in the resulting array may be an empty + * string. This happens when the very first character of input string is + * matched by the pattern. + * + * @param s String to split on this regular exression + * @return Array of strings + */ + public String[] split(String s) + { + // Create new vector + Vector v = new Vector(); + + // Start at position 0 and search the whole string + int pos = 0; + int len = s.length(); + + // Try a match at each position + while (pos < len && match(s, pos)) + { + // Get start of match + int start = getParenStart(0); + + // Get end of match + int newpos = getParenEnd(0); + + // Check if no progress was made + if (newpos == pos) + { + v.addElement(s.substring(pos, start + 1)); + newpos++; + } + else + { + v.addElement(s.substring(pos, start)); + } + + // Move to new position + pos = newpos; + } + + // Push remainder if it's not empty + String remainder = s.substring(pos); + if (remainder.length() != 0) + { + v.addElement(remainder); + } + + // Return vector as an array of strings + String[] ret = new String[v.size()]; + v.copyInto(ret); + return ret; + } + + /** + * Flag bit that indicates that subst should replace all occurrences of this + * regular expression. + */ + public static final int REPLACE_ALL = 0x0000; + + /** + * Flag bit that indicates that subst should only replace the first occurrence + * of this regular expression. + */ + public static final int REPLACE_FIRSTONLY = 0x0001; + + /** + * Flag bit that indicates that subst should replace backreferences + */ + public static final int REPLACE_BACKREFERENCES = 0x0002; + + /** + * Substitutes a string for this regular expression in another string. + * This method works like the Perl function of the same name. + * Given a regular expression of "a*b", a String to substituteIn of + * "aaaabfooaaabgarplyaaabwackyb" and the substitution String "-", the + * resulting String returned by subst would be "-foo-garply-wacky-". + * + * @param substituteIn String to substitute within + * @param substitution String to substitute for all matches of this regular expression. + * @return The string substituteIn with zero or more occurrences of the current + * regular expression replaced with the substitution String (if this regular + * expression object doesn't match at any position, the original String is returned + * unchanged). + */ + public String subst(String substituteIn, String substitution) + { + return subst(substituteIn, substitution, REPLACE_ALL); + } + + /** + * Substitutes a string for this regular expression in another string. + * This method works like the Perl function of the same name. + * Given a regular expression of "a*b", a String to substituteIn of + * "aaaabfooaaabgarplyaaabwackyb" and the substitution String "-", the + * resulting String returned by subst would be "-foo-garply-wacky-". + *

+ * It is also possible to reference the contents of a parenthesized expression + * with $0, $1, ... $9. A regular expression of "http://[\\.\\w\\-\\?/~_@&=%]+", + * a String to substituteIn of "visit us: http://www.apache.org!" and the + * substitution String "<a href=\"$0\">$0</a>", the resulting String + * returned by subst would be + * "visit us: <a href=\"http://www.apache.org\">http://www.apache.org</a>!". + *

+ * Note: $0 represents the whole match. + * + * @param substituteIn String to substitute within + * @param substitution String to substitute for matches of this regular expression + * @param flags One or more bitwise flags from REPLACE_*. If the REPLACE_FIRSTONLY + * flag bit is set, only the first occurrence of this regular expression is replaced. + * If the bit is not set (REPLACE_ALL), all occurrences of this pattern will be + * replaced. If the flag REPLACE_BACKREFERENCES is set, all backreferences will + * be processed. + * @return The string substituteIn with zero or more occurrences of the current + * regular expression replaced with the substitution String (if this regular + * expression object doesn't match at any position, the original String is returned + * unchanged). + */ + public String subst(String substituteIn, String substitution, int flags) + { + // String to return + StringBuffer ret = new StringBuffer(); + + // Start at position 0 and search the whole string + int pos = 0; + int len = substituteIn.length(); + + // Try a match at each position + while (pos < len && match(substituteIn, pos)) + { + // Append string before match + ret.append(substituteIn.substring(pos, getParenStart(0))); + + if ((flags & REPLACE_BACKREFERENCES) != 0) + { + // Process backreferences + int lCurrentPosition = 0; + int lLastPosition = -2; + int lLength = substitution.length(); + + while ((lCurrentPosition = substitution.indexOf("$", lCurrentPosition)) >= 0) + { + if ((lCurrentPosition == 0 || substitution.charAt(lCurrentPosition - 1) != '\\') + && lCurrentPosition + 1 < lLength) + { + char c = substitution.charAt(lCurrentPosition + 1); + if (c >= '0' && c <= '9') + { + // Append everything between the last and the current $ sign + ret.append(substitution.substring(lLastPosition + 2, lCurrentPosition)); + + // Append the parenthesized expression, if present + String val = getParen(c - '0'); + if (val != null) { + ret.append(val); + } + lLastPosition = lCurrentPosition; + } + } + + // Move forward, skipping past match + lCurrentPosition++; + } + + // Append everything after the last $ sign + ret.append(substitution.substring(lLastPosition + 2, lLength)); + } + else + { + // Append substitution without processing backreferences + ret.append(substitution); + } + + // Move forward, skipping past match + int newpos = getParenEnd(0); + + // We always want to make progress! + if (newpos == pos) + { + newpos++; + } + + // Try new position + pos = newpos; + + // Break out if we're only supposed to replace one occurrence + if ((flags & REPLACE_FIRSTONLY) != 0) + { + break; + } + } + + // If there's remaining input, append it + if (pos < len) + { + ret.append(substituteIn.substring(pos)); + } + + // Return string buffer as string + return ret.toString(); + } + + /** + * Returns an array of Strings, whose toString representation matches a regular + * expression. This method works like the Perl function of the same name. Given + * a regular expression of "a*b" and an array of String objects of [foo, aab, zzz, + * aaaab], the array of Strings returned by grep would be [aab, aaaab]. + * + * @param search Array of Objects to search + * @return Array of Strings whose toString() value matches this regular expression. + */ + public String[] grep(Object[] search) + { + // Create new vector to hold return items + Vector v = new Vector(); + + // Traverse array of objects + for (int i = 0; i < search.length; i++) + { + // Get next object as a string + String s = search[i].toString(); + + // If it matches this regexp, add it to the list + if (match(s)) + { + v.addElement(s); + } + } + + // Return vector as an array of strings + String[] ret = new String[v.size()]; + v.copyInto(ret); + return ret; + } + + /** + * @return true if character at i-th position in the search string is a newline + */ + private boolean isNewline(int i) + { + char nextChar = search.charAt(i); + + return nextChar == '\n' || nextChar == '\r' || nextChar == '\u0085' || + nextChar == '\u2028' || nextChar == '\u2029'; + } + + /** + * Compares two characters. + * + * @param c1 first character to compare. + * @param c2 second character to compare. + * @param caseIndependent whether comparision is case insensitive or not. + * @return negative, 0, or positive integer as the first character + * less than, equal to, or greater then the second. + */ + private int compareChars(char c1, char c2, boolean caseIndependent) + { + if (caseIndependent) + { + c1 = Character.toLowerCase(c1); + c2 = Character.toLowerCase(c2); + } + return ((int)c1 - (int)c2); + } +} diff --git a/src/org/apache/regexp/RECompiler.java b/src/org/apache/regexp/RECompiler.java new file mode 100644 index 0000000..26afde3 --- /dev/null +++ b/src/org/apache/regexp/RECompiler.java @@ -0,0 +1,1469 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.regexp; + +import com.classpath.util.Characters; +import java.util.Hashtable; + +/** + * A regular expression compiler class. This class compiles a pattern string into a + * regular expression program interpretable by the RE evaluator class. The 'recompile' + * command line tool uses this compiler to pre-compile regular expressions for use + * with RE. For a description of the syntax accepted by RECompiler and what you can + * do with regular expressions, see the documentation for the RE matcher class. + * + * @see RE + * @see recompile + * + * @author Jonathan Locke + * @author Michael McCallum + * @version $Id: RECompiler.java 518156 2007-03-14 14:31:26Z vgritsenko $ + */ +public class RECompiler +{ + // The compiled program + char[] instruction; // The compiled RE 'program' instruction buffer + int lenInstruction; // The amount of the program buffer currently in use + + // Input state for compiling regular expression + String pattern; // Input string + int len; // Length of the pattern string + int idx; // Current input index into ac + int parens; // Total number of paren pairs + + // Node flags + static final int NODE_NORMAL = 0; // No flags (nothing special) + static final int NODE_NULLABLE = 1; // True if node is potentially null + static final int NODE_TOPLEVEL = 2; // True if top level expr + + // Special types of 'escapes' + static final int ESC_MASK = 0xffff0; // Escape complexity mask + static final int ESC_BACKREF = 0xfffff; // Escape is really a backreference + static final int ESC_COMPLEX = 0xffffe; // Escape isn't really a true character + static final int ESC_CLASS = 0xffffd; // Escape represents a whole class of characters + + // {m,n} stacks + static final int bracketUnbounded = -1; // Unbounded value + int bracketMin; // Minimum number of matches + int bracketOpt; // Additional optional matches + + // Lookup table for POSIX character class names + static final Hashtable hashPOSIX = new Hashtable(); + static + { + hashPOSIX.put("alnum", new Character(RE.POSIX_CLASS_ALNUM)); + hashPOSIX.put("alpha", new Character(RE.POSIX_CLASS_ALPHA)); + hashPOSIX.put("blank", new Character(RE.POSIX_CLASS_BLANK)); + hashPOSIX.put("cntrl", new Character(RE.POSIX_CLASS_CNTRL)); + hashPOSIX.put("digit", new Character(RE.POSIX_CLASS_DIGIT)); + hashPOSIX.put("graph", new Character(RE.POSIX_CLASS_GRAPH)); + hashPOSIX.put("lower", new Character(RE.POSIX_CLASS_LOWER)); + hashPOSIX.put("print", new Character(RE.POSIX_CLASS_PRINT)); + hashPOSIX.put("punct", new Character(RE.POSIX_CLASS_PUNCT)); + hashPOSIX.put("space", new Character(RE.POSIX_CLASS_SPACE)); + hashPOSIX.put("upper", new Character(RE.POSIX_CLASS_UPPER)); + hashPOSIX.put("xdigit", new Character(RE.POSIX_CLASS_XDIGIT)); + hashPOSIX.put("javastart", new Character(RE.POSIX_CLASS_JSTART)); + hashPOSIX.put("javapart", new Character(RE.POSIX_CLASS_JPART)); + } + + /** + * Constructor. Creates (initially empty) storage for a regular expression program. + */ + public RECompiler() + { + // Start off with a generous, yet reasonable, initial size + instruction = new char[128]; + lenInstruction = 0; + } + + /** + * Ensures that n more characters can fit in the program buffer. + * If n more can't fit, then the size is doubled until it can. + * @param n Number of additional characters to ensure will fit. + */ + void ensure(int n) + { + // Get current program length + int curlen = instruction.length; + + // If the current length + n more is too much + if (lenInstruction + n >= curlen) + { + // Double the size of the program array until n more will fit + while (lenInstruction + n >= curlen) + { + curlen *= 2; + } + + // Allocate new program array and move data into it + char[] newInstruction = new char[curlen]; + System.arraycopy(instruction, 0, newInstruction, 0, lenInstruction); + instruction = newInstruction; + } + } + + /** + * Emit a single character into the program stream. + * @param c Character to add + */ + void emit(char c) + { + // Make room for character + ensure(1); + + // Add character + instruction[lenInstruction++] = c; + } + + /** + * Inserts a node with a given opcode and opdata at insertAt. The node relative next + * pointer is initialized to 0. + * @param opcode Opcode for new node + * @param opdata Opdata for new node (only the low 16 bits are currently used) + * @param insertAt Index at which to insert the new node in the program + */ + void nodeInsert(char opcode, int opdata, int insertAt) + { + // Make room for a new node + ensure(RE.nodeSize); + + // Move everything from insertAt to the end down nodeSize elements + System.arraycopy(instruction, insertAt, instruction, insertAt + RE.nodeSize, lenInstruction - insertAt); + instruction[insertAt /* + RE.offsetOpcode */] = opcode; + instruction[insertAt + RE.offsetOpdata ] = (char) opdata; + instruction[insertAt + RE.offsetNext ] = 0; + lenInstruction += RE.nodeSize; + } + + /** + * Appends a node to the end of a node chain + * @param node Start of node chain to traverse + * @param pointTo Node to have the tail of the chain point to + */ + void setNextOfEnd(int node, int pointTo) + { + // Traverse the chain until the next offset is 0 + int next = instruction[node + RE.offsetNext]; + // while the 'node' is not the last in the chain + // and the 'node' is not the last in the program. + while ( next != 0 && node < lenInstruction ) + { + // if the node we are supposed to point to is in the chain then + // point to the end of the program instead. + // Michael McCallum + // FIXME: This is a _hack_ to stop infinite programs. + // I believe that the implementation of the reluctant matches is wrong but + // have not worked out a better way yet. + if (node == pointTo) { + pointTo = lenInstruction; + } + node += next; + next = instruction[node + RE.offsetNext]; + } + + // if we have reached the end of the program then dont set the pointTo. + // im not sure if this will break any thing but passes all the tests. + if ( node < lenInstruction ) { + // Some patterns result in very large programs which exceed + // capacity of the short used for specifying signed offset of the + // next instruction. Example: a{1638} + int offset = pointTo - node; + if (offset != (short) offset) { + throw new RESyntaxException("Exceeded short jump range."); + } + + // Point the last node in the chain to pointTo. + instruction[node + RE.offsetNext] = (char) (short) offset; + } + } + + /** + * Adds a new node + * @param opcode Opcode for node + * @param opdata Opdata for node (only the low 16 bits are currently used) + * @return Index of new node in program + */ + int node(char opcode, int opdata) + { + // Make room for a new node + ensure(RE.nodeSize); + + // Add new node at end + instruction[lenInstruction /* + RE.offsetOpcode */] = opcode; + instruction[lenInstruction + RE.offsetOpdata ] = (char) opdata; + instruction[lenInstruction + RE.offsetNext ] = 0; + lenInstruction += RE.nodeSize; + + // Return index of new node + return lenInstruction - RE.nodeSize; + } + + + /** + * Throws a new internal error exception + * @exception Error Thrown in the event of an internal error. + */ + void internalError() throws Error + { + throw new Error("Internal error!"); + } + + /** + * Throws a new syntax error exception + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + */ + void syntaxError(String s) throws RESyntaxException + { + throw new RESyntaxException(s); + } + + /** + * Match bracket {m,n} expression put results in bracket member variables + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + */ + void bracket() throws RESyntaxException + { + // Current character must be a '{' + if (idx >= len || pattern.charAt(idx++) != '{') + { + internalError(); + } + + // Next char must be a digit + if (idx >= len || !Characters.isDigit(pattern.charAt(idx))) + { + syntaxError("Expected digit"); + } + + // Get min ('m' of {m,n}) number + StringBuffer number = new StringBuffer(); + while (idx < len && Characters.isDigit(pattern.charAt(idx))) + { + number.append(pattern.charAt(idx++)); + } + try + { + bracketMin = Integer.parseInt(number.toString()); + } + catch (NumberFormatException e) + { + syntaxError("Expected valid number"); + } + + // If out of input, fail + if (idx >= len) + { + syntaxError("Expected comma or right bracket"); + } + + // If end of expr, optional limit is 0 + if (pattern.charAt(idx) == '}') + { + idx++; + bracketOpt = 0; + return; + } + + // Must have at least {m,} and maybe {m,n}. + if (idx >= len || pattern.charAt(idx++) != ',') + { + syntaxError("Expected comma"); + } + + // If out of input, fail + if (idx >= len) + { + syntaxError("Expected comma or right bracket"); + } + + // If {m,} max is unlimited + if (pattern.charAt(idx) == '}') + { + idx++; + bracketOpt = bracketUnbounded; + return; + } + + // Next char must be a digit + if (idx >= len || !Characters.isDigit(pattern.charAt(idx))) + { + syntaxError("Expected digit"); + } + + // Get max number + number.setLength(0); + while (idx < len && Characters.isDigit(pattern.charAt(idx))) + { + number.append(pattern.charAt(idx++)); + } + try + { + bracketOpt = Integer.parseInt(number.toString()) - bracketMin; + } + catch (NumberFormatException e) + { + syntaxError("Expected valid number"); + } + + // Optional repetitions must be >= 0 + if (bracketOpt < 0) + { + syntaxError("Bad range"); + } + + // Must have close brace + if (idx >= len || pattern.charAt(idx++) != '}') + { + syntaxError("Missing close brace"); + } + } + + /** + * Match an escape sequence. Handles quoted chars and octal escapes as well + * as normal escape characters. Always advances the input stream by the + * right amount. This code "understands" the subtle difference between an + * octal escape and a backref. You can access the type of ESC_CLASS or + * ESC_COMPLEX or ESC_BACKREF by looking at pattern[idx - 1]. + * @return ESC_* code or character if simple escape + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + */ + int escape() throws RESyntaxException + { + // "Shouldn't" happen + if (pattern.charAt(idx) != '\\') + { + internalError(); + } + + // Escape shouldn't occur as last character in string! + if (idx + 1 == len) + { + syntaxError("Escape terminates string"); + } + + // Switch on character after backslash + idx += 2; + char escapeChar = pattern.charAt(idx - 1); + switch (escapeChar) + { + case RE.E_BOUND: + case RE.E_NBOUND: + return ESC_COMPLEX; + + case RE.E_ALNUM: + case RE.E_NALNUM: + case RE.E_SPACE: + case RE.E_NSPACE: + case RE.E_DIGIT: + case RE.E_NDIGIT: + return ESC_CLASS; + + case 'u': + case 'x': + { + // Exact required hex digits for escape type + int hexDigits = (escapeChar == 'u' ? 4 : 2); + + // Parse up to hexDigits characters from input + int val = 0; + for ( ; idx < len && hexDigits-- > 0; idx++) + { + // Get char + char c = pattern.charAt(idx); + + // If it's a hexadecimal digit (0-9) + if (c >= '0' && c <= '9') + { + // Compute new value + val = (val << 4) + c - '0'; + } + else + { + // If it's a hexadecimal letter (a-f) + c = Character.toLowerCase(c); + if (c >= 'a' && c <= 'f') + { + // Compute new value + val = (val << 4) + (c - 'a') + 10; + } + else + { + // If it's not a valid digit or hex letter, the escape must be invalid + // because hexDigits of input have not been absorbed yet. + syntaxError("Expected " + hexDigits + " hexadecimal digits after \\" + escapeChar); + } + } + } + return val; + } + + case 't': + return '\t'; + + case 'n': + return '\n'; + + case 'r': + return '\r'; + + case 'f': + return '\f'; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + + // An octal escape starts with a 0 or has two digits in a row + if ((idx < len && Characters.isDigit(pattern.charAt(idx))) || escapeChar == '0') + { + // Handle \nnn octal escapes + int val = escapeChar - '0'; + if (idx < len && Characters.isDigit(pattern.charAt(idx))) + { + val = ((val << 3) + (pattern.charAt(idx++) - '0')); + if (idx < len && Characters.isDigit(pattern.charAt(idx))) + { + val = ((val << 3) + (pattern.charAt(idx++) - '0')); + } + } + return val; + } + + // It's actually a backreference (\[1-9]), not an escape + return ESC_BACKREF; + + default: + + // Simple quoting of a character + return escapeChar; + } + } + + /** + * Compile a character class + * @return Index of class node + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + */ + int characterClass() throws RESyntaxException + { + // Check for bad calling or empty class + if (pattern.charAt(idx) != '[') + { + internalError(); + } + + // Check for unterminated or empty class + if ((idx + 1) >= len || pattern.charAt(++idx) == ']') + { + syntaxError("Empty or unterminated class"); + } + + // Check for POSIX character class + if (idx < len && pattern.charAt(idx) == ':') + { + // Skip colon + idx++; + + // POSIX character classes are denoted with lowercase ASCII strings + int idxStart = idx; + while (idx < len && pattern.charAt(idx) >= 'a' && pattern.charAt(idx) <= 'z') + { + idx++; + } + + // Should be a ":]" to terminate the POSIX character class + if ((idx + 1) < len && pattern.charAt(idx) == ':' && pattern.charAt(idx + 1) == ']') + { + // Get character class + String charClass = pattern.substring(idxStart, idx); + + // Select the POSIX class id + Character i = (Character)hashPOSIX.get(charClass); + if (i != null) + { + // Move past colon and right bracket + idx += 2; + + // Return new POSIX character class node + return node(RE.OP_POSIXCLASS, i.charValue()); + } + syntaxError("Invalid POSIX character class '" + charClass + "'"); + } + syntaxError("Invalid POSIX character class syntax"); + } + + // Try to build a class. Create OP_ANYOF node + int ret = node(RE.OP_ANYOF, 0); + + // Parse class declaration + char CHAR_INVALID = Characters.MAX_VALUE; + char last = CHAR_INVALID; + char simpleChar; + boolean include = true; + boolean definingRange = false; + int idxFirst = idx; + char rangeStart = Characters.MIN_VALUE; + char rangeEnd; + RERange range = new RERange(); + while (idx < len && pattern.charAt(idx) != ']') + { + + switchOnCharacter: + + // Switch on character + switch (pattern.charAt(idx)) + { + case '^': + include = !include; + if (idx == idxFirst) + { + range.include(Characters.MIN_VALUE, Characters.MAX_VALUE, true); + } + idx++; + continue; + + case '\\': + { + // Escape always advances the stream + int c; + switch (c = escape ()) + { + case ESC_COMPLEX: + case ESC_BACKREF: + + // Word boundaries and backrefs not allowed in a character class! + syntaxError("Bad character class"); + + case ESC_CLASS: + + // Classes can't be an endpoint of a range + if (definingRange) + { + syntaxError("Bad character class"); + } + + // Handle specific type of class (some are ok) + switch (pattern.charAt(idx - 1)) + { + case RE.E_NSPACE: + range.include(Characters.MIN_VALUE, 7, include); // [Min - \b ) + range.include((char) 11, include); // ( \n - \f ) + range.include(14, 31, include); // ( \r - ' ') + range.include(33, Characters.MAX_VALUE, include); // (' ' - Max] + break; + + case RE.E_NALNUM: + range.include(Characters.MIN_VALUE, '/', include); // [Min - '0') + range.include(':', '@', include); // ('9' - 'A') + range.include('[', '^', include); // ('Z' - '_') + range.include('`', include); // ('_' - 'a') + range.include('{', Characters.MAX_VALUE, include); // ('z' - Max] + break; + + case RE.E_NDIGIT: + range.include(Characters.MIN_VALUE, '/', include); // [Min - '0') + range.include(':', Characters.MAX_VALUE, include); // ('9' - Max] + break; + + case RE.E_SPACE: + range.include('\t', include); + range.include('\r', include); + range.include('\f', include); + range.include('\n', include); + range.include('\b', include); + range.include(' ', include); + break; + + case RE.E_ALNUM: + range.include('a', 'z', include); + range.include('A', 'Z', include); + range.include('_', include); + + // Fall through! + + case RE.E_DIGIT: + range.include('0', '9', include); + break; + } + + // Make last char invalid (can't be a range start) + last = CHAR_INVALID; + break; + + default: + + // Escape is simple so treat as a simple char + simpleChar = (char) c; + break switchOnCharacter; + } + } + continue; + + case '-': + + // Start a range if one isn't already started + if (definingRange) + { + syntaxError("Bad class range"); + } + definingRange = true; + + // If no last character, start of range is 0 + rangeStart = (last == CHAR_INVALID ? 0 : last); + + // Premature end of range. define up to Characters.MAX_VALUE + if ((idx + 1) < len && pattern.charAt(++idx) == ']') + { + simpleChar = Characters.MAX_VALUE; + break; + } + continue; + + default: + simpleChar = pattern.charAt(idx++); + break; + } + + // Handle simple character simpleChar + if (definingRange) + { + // if we are defining a range make it now + rangeEnd = simpleChar; + + // Actually create a range if the range is ok + if (rangeStart >= rangeEnd) + { + syntaxError("Bad character class"); + } + range.include(rangeStart, rangeEnd, include); + + // We are done defining the range + last = CHAR_INVALID; + definingRange = false; + } + else + { + // If simple character and not start of range, include it + if (idx >= len || pattern.charAt(idx) != '-') + { + range.include(simpleChar, include); + } + last = simpleChar; + } + } + + // Shouldn't be out of input + if (idx == len) + { + syntaxError("Unterminated character class"); + } + + // Absorb the ']' end of class marker + idx++; + + // Emit character class definition + instruction[ret + RE.offsetOpdata] = (char)range.num; + for (int i = 0; i < range.num; i++) + { + emit((char)range.minRange[i]); + emit((char)range.maxRange[i]); + } + return ret; + } + + /** + * Absorb an atomic character string. This method is a little tricky because + * it can un-include the last character of string if a closure operator follows. + * This is correct because *+? have higher precedence than concatentation (thus + * ABC* means AB(C*) and NOT (ABC)*). + * @return Index of new atom node + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + */ + int atom() throws RESyntaxException + { + // Create a string node + int ret = node(RE.OP_ATOM, 0); + + // Length of atom + int lenAtom = 0; + + // Loop while we've got input + + atomLoop: + + while (idx < len) + { + // Is there a next char? + if ((idx + 1) < len) + { + char c = pattern.charAt(idx + 1); + + // If the next 'char' is an escape, look past the whole escape + if (pattern.charAt(idx) == '\\') + { + int idxEscape = idx; + escape(); + if (idx < len) + { + c = pattern.charAt(idx); + } + idx = idxEscape; + } + + // Switch on next char + switch (c) + { + case '{': + case '?': + case '*': + case '+': + + // If the next character is a closure operator and our atom is non-empty, the + // current character should bind to the closure operator rather than the atom + if (lenAtom != 0) + { + break atomLoop; + } + } + } + + // Switch on current char + switch (pattern.charAt(idx)) + { + case ']': + case '^': + case '$': + case '.': + case '[': + case '(': + case ')': + case '|': + break atomLoop; + + case '{': + case '?': + case '*': + case '+': + + // We should have an atom by now + if (lenAtom == 0) + { + // No atom before closure + syntaxError("Missing operand to closure"); + } + break atomLoop; + + case '\\': + + { + // Get the escaped character (advances input automatically) + int idxBeforeEscape = idx; + int c = escape(); + + // Check if it's a simple escape (as opposed to, say, a backreference) + if ((c & ESC_MASK) == ESC_MASK) + { + // Not a simple escape, so backup to where we were before the escape. + idx = idxBeforeEscape; + break atomLoop; + } + + // Add escaped char to atom + emit((char) c); + lenAtom++; + } + break; + + default: + + // Add normal character to atom + emit(pattern.charAt(idx++)); + lenAtom++; + break; + } + } + + // This "shouldn't" happen + if (lenAtom == 0) + { + internalError(); + } + + // Emit the atom length into the program + instruction[ret + RE.offsetOpdata] = (char)lenAtom; + return ret; + } + + /** + * Match a terminal node. + * @param flags Flags + * @return Index of terminal node (closeable) + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + */ + int terminal(int[] flags) throws RESyntaxException + { + switch (pattern.charAt(idx)) + { + case RE.OP_EOL: + case RE.OP_BOL: + case RE.OP_ANY: + return node(pattern.charAt(idx++), 0); + + case '[': + return characterClass(); + + case '(': + return expr(flags); + + case ')': + syntaxError("Unexpected close paren"); + + case '|': + internalError(); + + case ']': + syntaxError("Mismatched class"); + + case 0: + syntaxError("Unexpected end of input"); + + case '?': + case '+': + case '{': + case '*': + syntaxError("Missing operand to closure"); + + case '\\': + { + // Don't forget, escape() advances the input stream! + int idxBeforeEscape = idx; + + // Switch on escaped character + switch (escape()) + { + case ESC_CLASS: + case ESC_COMPLEX: + flags[0] &= ~NODE_NULLABLE; + return node(RE.OP_ESCAPE, pattern.charAt(idx - 1)); + + case ESC_BACKREF: + { + char backreference = (char)(pattern.charAt(idx - 1) - '0'); + if (parens <= backreference) + { + syntaxError("Bad backreference"); + } + flags[0] |= NODE_NULLABLE; + return node(RE.OP_BACKREF, backreference); + } + + default: + + // We had a simple escape and we want to have it end up in + // an atom, so we back up and fall though to the default handling + idx = idxBeforeEscape; + flags[0] &= ~NODE_NULLABLE; + break; + } + } + } + + // Everything above either fails or returns. + // If it wasn't one of the above, it must be the start of an atom. + flags[0] &= ~NODE_NULLABLE; + return atom(); + } + + /** + * Compile a possibly closured terminal + * @param flags Flags passed by reference + * @return Index of closured node + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + */ + int closure(int[] flags) throws RESyntaxException + { + // Before terminal + int idxBeforeTerminal = idx; + + // Values to pass by reference to terminal() + int[] terminalFlags = { NODE_NORMAL }; + + // Get terminal symbol + int ret = terminal(terminalFlags); + + // Or in flags from terminal symbol + flags[0] |= terminalFlags[0]; + + // Advance input, set NODE_NULLABLE flag and do sanity checks + if (idx >= len) + { + return ret; + } + + boolean greedy = true; + char closureType = pattern.charAt(idx); + switch (closureType) + { + case '?': + case '*': + + // The current node can be null + flags[0] |= NODE_NULLABLE; + + // Drop through + + case '+': + + // Eat closure character + idx++; + + // Drop through + + case '{': + + // Don't allow blantant stupidity + int opcode = instruction[ret /* + RE.offsetOpcode */]; + if (opcode == RE.OP_BOL || opcode == RE.OP_EOL) + { + syntaxError("Bad closure operand"); + } + if ((terminalFlags[0] & NODE_NULLABLE) != 0) + { + syntaxError("Closure operand can't be nullable"); + } + } + + // If the next character is a '?', make the closure non-greedy (reluctant) + if (idx < len && pattern.charAt(idx) == '?') + { + idx++; + greedy = false; + } + + if (greedy) + { + // Actually do the closure now + switch (closureType) + { + case '{': + { + bracket(); + int bracketEnd = idx; + int bracketMin = this.bracketMin; + int bracketOpt = this.bracketOpt; + + // Pointer to the last terminal + int pos = ret; + + // Process min first + for (int c = 0; c < bracketMin; c++) + { + // Rewind stream and run it through again - more matchers coming + idx = idxBeforeTerminal; + setNextOfEnd(pos, pos = terminal(terminalFlags)); + } + + // Do the right thing for maximum ({m,}) + if (bracketOpt == bracketUnbounded) + { + // Drop through now and closure expression. + // We are done with the {m,} expr, so skip rest + idx = bracketEnd; + nodeInsert(RE.OP_STAR, 0, pos); + setNextOfEnd(pos + RE.nodeSize, pos); + break; + } + else if (bracketOpt > 0) + { + int opt[] = new int[bracketOpt + 1]; + // Surround first optional terminal with MAYBE + nodeInsert(RE.OP_MAYBE, 0, pos); + opt[0] = pos; + + // Add all the rest optional terminals with preceeding MAYBEs + for (int c = 1; c < bracketOpt; c++) + { + opt[c] = node(RE.OP_MAYBE, 0); + // Rewind stream and run it through again - more matchers coming + idx = idxBeforeTerminal; + terminal(terminalFlags); + } + + // Tie ends together + int end = opt[bracketOpt] = node(RE.OP_NOTHING, 0); + for (int c = 0; c < bracketOpt; c++) + { + setNextOfEnd(opt[c], end); + setNextOfEnd(opt[c] + RE.nodeSize, opt[c + 1]); + } + } + else + { + // Rollback terminal - no opt matchers present + lenInstruction = pos; + node(RE.OP_NOTHING, 0); + } + + // We are done. skip the reminder of {m,n} expr + idx = bracketEnd; + break; + } + + case '?': + { + nodeInsert(RE.OP_MAYBE, 0, ret); + int n = node(RE.OP_NOTHING, 0); + setNextOfEnd(ret, n); + setNextOfEnd(ret + RE.nodeSize, n); + break; + } + + case '*': + { + nodeInsert(RE.OP_STAR, 0, ret); + setNextOfEnd(ret + RE.nodeSize, ret); + break; + } + + case '+': + { + nodeInsert(RE.OP_CONTINUE, 0, ret); + int n = node(RE.OP_PLUS, 0); + setNextOfEnd(ret + RE.nodeSize, n); + setNextOfEnd(n, ret); + break; + } + } + } + else + { + // Actually do the closure now + switch (closureType) + { + case '?': + { + nodeInsert(RE.OP_RELUCTANTMAYBE, 0, ret); + int n = node(RE.OP_NOTHING, 0); + setNextOfEnd(ret, n); + setNextOfEnd(ret + RE.nodeSize, n); + break; + } + + case '*': + { + nodeInsert(RE.OP_RELUCTANTSTAR, 0, ret); + setNextOfEnd(ret + RE.nodeSize, ret); + break; + } + + case '+': + { + nodeInsert(RE.OP_CONTINUE, 0, ret); + int n = node(RE.OP_RELUCTANTPLUS, 0); + setNextOfEnd(n, ret); + setNextOfEnd(ret + RE.nodeSize, n); + break; + } + } + } + + return ret; + } + + /** + * Compile body of one branch of an or operator (implements concatenation) + * + * @param flags Flags passed by reference + * @return Pointer to first node in the branch + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + */ + int branch(int[] flags) throws RESyntaxException + { + // Get each possibly closured piece and concat + int node; + int ret = -1; + int chain = -1; + int[] closureFlags = new int[1]; + boolean nullable = true; + while (idx < len && pattern.charAt(idx) != '|' && pattern.charAt(idx) != ')') + { + // Get new node + closureFlags[0] = NODE_NORMAL; + node = closure(closureFlags); + if (closureFlags[0] == NODE_NORMAL) + { + nullable = false; + } + + // If there's a chain, append to the end + if (chain != -1) + { + setNextOfEnd(chain, node); + } + + // Chain starts at current + chain = node; + if (ret == -1) { + ret = node; + } + } + + // If we don't run loop, make a nothing node + if (ret == -1) + { + ret = node(RE.OP_NOTHING, 0); + } + + // Set nullable flag for this branch + if (nullable) + { + flags[0] |= NODE_NULLABLE; + } + + return ret; + } + + /** + * Compile an expression with possible parens around it. Paren matching + * is done at this level so we can tie the branch tails together. + * + * @param flags Flag value passed by reference + * @return Node index of expression in instruction array + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + */ + int expr(int[] flags) throws RESyntaxException + { + // Create open paren node unless we were called from the top level (which has no parens) + int paren = -1; + int ret = -1; + int closeParens = parens; + if ((flags[0] & NODE_TOPLEVEL) == 0 && pattern.charAt(idx) == '(') + { + // if its a cluster ( rather than a proper subexpression ie with backrefs ) + if (idx + 2 < len && pattern.charAt(idx + 1) == '?' && pattern.charAt(idx + 2) == ':') + { + paren = 2; + idx += 3; + ret = node(RE.OP_OPEN_CLUSTER, 0); + } + else + { + paren = 1; + idx++; + ret = node(RE.OP_OPEN, parens++); + } + } + flags[0] &= ~NODE_TOPLEVEL; + + // Process contents of first branch node + boolean open = false; + int branch = branch(flags); + if (ret == -1) + { + ret = branch; + } + else + { + setNextOfEnd(ret, branch); + } + + // Loop through branches + while (idx < len && pattern.charAt(idx) == '|') + { + // Now open the first branch since there are more than one + if (!open) { + nodeInsert(RE.OP_BRANCH, 0, branch); + open = true; + } + + idx++; + setNextOfEnd(branch, branch = node(RE.OP_BRANCH, 0)); + branch(flags); + } + + // Create an ending node (either a close paren or an OP_END) + int end; + if (paren > 0) + { + if (idx < len && pattern.charAt(idx) == ')') + { + idx++; + } + else + { + syntaxError("Missing close paren"); + } + if (paren == 1) + { + end = node(RE.OP_CLOSE, closeParens); + } + else + { + end = node(RE.OP_CLOSE_CLUSTER, 0); + } + } + else + { + end = node(RE.OP_END, 0); + } + + // Append the ending node to the ret nodelist + setNextOfEnd(ret, end); + + // Hook the ends of each branch to the end node + int currentNode = ret; + int nextNodeOffset = instruction[currentNode + RE.offsetNext]; + // while the next node o + while (nextNodeOffset != 0 && currentNode < lenInstruction) + { + // If branch, make the end of the branch's operand chain point to the end node. + if (instruction[currentNode /* + RE.offsetOpcode */] == RE.OP_BRANCH) + { + setNextOfEnd(currentNode + RE.nodeSize, end); + } + nextNodeOffset = instruction[currentNode + RE.offsetNext]; + currentNode += nextNodeOffset; + } + + // Return the node list + return ret; + } + + /** + * Compiles a regular expression pattern into a program runnable by the pattern + * matcher class 'RE'. + * @param pattern Regular expression pattern to compile (see RECompiler class + * for details). + * @return A compiled regular expression program. + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + * @see RECompiler + * @see RE + */ + public REProgram compile(String pattern) throws RESyntaxException + { + // Initialize variables for compilation + this.pattern = pattern; // Save pattern in instance variable + len = pattern.length(); // Precompute pattern length for speed + idx = 0; // Set parsing index to the first character + lenInstruction = 0; // Set emitted instruction count to zero + parens = 1; // Set paren level to 1 (the implicit outer parens) + + // Initialize pass by reference flags value + int[] flags = { NODE_TOPLEVEL }; + + // Parse expression + expr(flags); + + // Should be at end of input + if (idx != len) + { + if (pattern.charAt(idx) == ')') + { + syntaxError("Unmatched close paren"); + } + syntaxError("Unexpected input remains"); + } + + // Return the result + char[] ins = new char[lenInstruction]; + System.arraycopy(instruction, 0, ins, 0, lenInstruction); + return new REProgram(parens, ins); + } + + /** + * Local, nested class for maintaining character ranges for character classes. + */ + class RERange + { + int size = 16; // Capacity of current range arrays + int[] minRange = new int[size]; // Range minima + int[] maxRange = new int[size]; // Range maxima + int num = 0; // Number of range array elements in use + + /** + * Deletes the range at a given index from the range lists + * @param index Index of range to delete from minRange and maxRange arrays. + */ + void delete(int index) + { + // Return if no elements left or index is out of range + if (num == 0 || index >= num) + { + return; + } + + // Move elements down + while (++index < num) + { + if (index - 1 >= 0) + { + minRange[index-1] = minRange[index]; + maxRange[index-1] = maxRange[index]; + } + } + + // One less element now + num--; + } + + /** + * Merges a range into the range list, coalescing ranges if possible. + * @param min Minimum end of range + * @param max Maximum end of range + */ + void merge(int min, int max) + { + // Loop through ranges + for (int i = 0; i < num; i++) + { + // Min-max is subsumed by minRange[i]-maxRange[i] + if (min >= minRange[i] && max <= maxRange[i]) + { + return; + } + + // Min-max subsumes minRange[i]-maxRange[i] + else if (min <= minRange[i] && max >= maxRange[i]) + { + delete(i); + merge(min, max); + return; + } + + // Min is in the range, but max is outside + else if (min >= minRange[i] && min <= maxRange[i]) + { + min = minRange[i]; + delete(i); + merge(min, max); + return; + } + + // Max is in the range, but min is outside + else if (max >= minRange[i] && max <= maxRange[i]) + { + max = maxRange[i]; + delete(i); + merge(min, max); + return; + } + } + + // Must not overlap any other ranges + if (num >= size) + { + size *= 2; + int[] newMin = new int[size]; + int[] newMax = new int[size]; + System.arraycopy(minRange, 0, newMin, 0, num); + System.arraycopy(maxRange, 0, newMax, 0, num); + minRange = newMin; + maxRange = newMax; + } + minRange[num] = min; + maxRange[num] = max; + num++; + } + + /** + * Removes a range by deleting or shrinking all other ranges + * @param min Minimum end of range + * @param max Maximum end of range + */ + void remove(int min, int max) + { + // Loop through ranges + for (int i = 0; i < num; i++) + { + // minRange[i]-maxRange[i] is subsumed by min-max + if (minRange[i] >= min && maxRange[i] <= max) + { + delete(i); + return; + } + + // min-max is subsumed by minRange[i]-maxRange[i] + else if (min >= minRange[i] && max <= maxRange[i]) + { + int minr = minRange[i]; + int maxr = maxRange[i]; + delete(i); + if (minr < min) + { + merge(minr, min - 1); + } + if (max < maxr) + { + merge(max + 1, maxr); + } + return; + } + + // minRange is in the range, but maxRange is outside + else if (minRange[i] >= min && minRange[i] <= max) + { + minRange[i] = max + 1; + return; + } + + // maxRange is in the range, but minRange is outside + else if (maxRange[i] >= min && maxRange[i] <= max) + { + maxRange[i] = min - 1; + return; + } + } + } + + /** + * Includes (or excludes) the range from min to max, inclusive. + * @param min Minimum end of range + * @param max Maximum end of range + * @param include True if range should be included. False otherwise. + */ + void include(int min, int max, boolean include) + { + if (include) + { + merge(min, max); + } + else + { + remove(min, max); + } + } + + /** + * Includes a range with the same min and max + * @param minmax Minimum and maximum end of range (inclusive) + * @param include True if range should be included. False otherwise. + */ + void include(char minmax, boolean include) + { + include(minmax, minmax, include); + } + } +} diff --git a/src/org/apache/regexp/REDebugCompiler.java b/src/org/apache/regexp/REDebugCompiler.java new file mode 100644 index 0000000..7a044c5 --- /dev/null +++ b/src/org/apache/regexp/REDebugCompiler.java @@ -0,0 +1,263 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.regexp; + +import java.io.PrintStream; +import java.util.Hashtable; + +/** + * A subclass of RECompiler which can dump a regular expression program + * for debugging purposes. + * + * @author Jonathan Locke + * @version $Id: REDebugCompiler.java 518169 2007-03-14 15:03:35Z vgritsenko $ + */ +public class REDebugCompiler extends RECompiler +{ + /** + * Mapping from opcodes to descriptive strings + */ + static Hashtable hashOpcode = new Hashtable(); + static + { + hashOpcode.put(new Integer(RE.OP_RELUCTANTSTAR), "OP_RELUCTANTSTAR"); + hashOpcode.put(new Integer(RE.OP_RELUCTANTPLUS), "OP_RELUCTANTPLUS"); + hashOpcode.put(new Integer(RE.OP_RELUCTANTMAYBE), "OP_RELUCTANTMAYBE"); + hashOpcode.put(new Integer(RE.OP_END), "OP_END"); + hashOpcode.put(new Integer(RE.OP_BOL), "OP_BOL"); + hashOpcode.put(new Integer(RE.OP_EOL), "OP_EOL"); + hashOpcode.put(new Integer(RE.OP_ANY), "OP_ANY"); + hashOpcode.put(new Integer(RE.OP_ANYOF), "OP_ANYOF"); + hashOpcode.put(new Integer(RE.OP_BRANCH), "OP_BRANCH"); + hashOpcode.put(new Integer(RE.OP_ATOM), "OP_ATOM"); + hashOpcode.put(new Integer(RE.OP_STAR), "OP_STAR"); + hashOpcode.put(new Integer(RE.OP_PLUS), "OP_PLUS"); + hashOpcode.put(new Integer(RE.OP_MAYBE), "OP_MAYBE"); + hashOpcode.put(new Integer(RE.OP_NOTHING), "OP_NOTHING"); + hashOpcode.put(new Integer(RE.OP_GOTO), "OP_GOTO"); + hashOpcode.put(new Integer(RE.OP_CONTINUE), "OP_CONTINUE"); + hashOpcode.put(new Integer(RE.OP_ESCAPE), "OP_ESCAPE"); + hashOpcode.put(new Integer(RE.OP_OPEN), "OP_OPEN"); + hashOpcode.put(new Integer(RE.OP_CLOSE), "OP_CLOSE"); + hashOpcode.put(new Integer(RE.OP_BACKREF), "OP_BACKREF"); + hashOpcode.put(new Integer(RE.OP_POSIXCLASS), "OP_POSIXCLASS"); + hashOpcode.put(new Integer(RE.OP_OPEN_CLUSTER), "OP_OPEN_CLUSTER"); + hashOpcode.put(new Integer(RE.OP_CLOSE_CLUSTER), "OP_CLOSE_CLUSTER"); + } + + /** + * Returns a descriptive string for an opcode. + * + * @param opcode Opcode to convert to a string + * @return Description of opcode + */ + String opcodeToString(char opcode) + { + // Get string for opcode + String ret = (String) hashOpcode.get(new Integer(opcode)); + + // Just in case we have a corrupt program + if (ret == null) + { + ret = "OP_????"; + } + return ret; + } + + /** + * Return a string describing a (possibly unprintable) character. + * + * @param c Character to convert to a printable representation + * @return String representation of character + */ + String charToString(char c) + { + // If it's unprintable, convert to '\###' + if (c < ' ' || c > 127) + { + return "\\" + (int) c; + } + + // Return the character as a string + return String.valueOf(c); + } + + /** + * Returns a descriptive string for a node in a regular expression program. + * @param node Node to describe + * @return Description of node + */ + String nodeToString(int node) + { + // Get opcode and opdata for node + char opcode = instruction[node /* + RE.offsetOpcode */]; + int opdata = (int) instruction[node + RE.offsetOpdata ]; + + // Return opcode as a string and opdata value + return opcodeToString(opcode) + ", opdata = " + opdata; + } + + /** + * Adds a new node + * + * @param opcode Opcode for node + * @param opdata Opdata for node (only the low 16 bits are currently used) + * @return Index of new node in program + * / + int node(char opcode, int opdata) + { + System.out.println("====> Add " + opcode + " " + opdata); + PrintWriter writer = new PrintWriter(System.out); + dumpProgram(writer); + writer.flush(); + int r = super.node(opcode, opdata); + System.out.println("====< "); + dumpProgram(writer); + writer.flush(); + return r; + }/**/ + + /** + * Inserts a node with a given opcode and opdata at insertAt. The node relative next + * pointer is initialized to 0. + * + * @param opcode Opcode for new node + * @param opdata Opdata for new node (only the low 16 bits are currently used) + * @param insertAt Index at which to insert the new node in the program + * / + void nodeInsert(char opcode, int opdata, int insertAt) + { + System.out.println("====> Ins " + opcode + " " + opdata + " " + insertAt); + PrintWriter writer = new PrintWriter(System.out); + dumpProgram(writer); + writer.flush(); + super.nodeInsert(opcode, opdata, insertAt); + System.out.println("====< "); + dumpProgram(writer); + writer.flush(); + }/**/ + + + /** + * Appends a node to the end of a node chain + * + * @param node Start of node chain to traverse + * @param pointTo Node to have the tail of the chain point to + * / + void setNextOfEnd(int node, int pointTo) + { + System.out.println("====> Link " + node + " " + pointTo); + PrintWriter writer = new PrintWriter(System.out); + dumpProgram(writer); + writer.flush(); + super.setNextOfEnd(node, pointTo); + System.out.println("====< "); + dumpProgram(writer); + writer.flush(); + }/**/ + + + /** + * Dumps the current program to a {@link PrintWriter}. + * + * @param p PrintWriter for program dump output + */ + public void dumpProgram(PrintStream p) + { + // Loop through the whole program + for (int i = 0; i < lenInstruction; ) + { + // Get opcode, opdata and next fields of current program node + char opcode = instruction[i /* + RE.offsetOpcode */]; + char opdata = instruction[i + RE.offsetOpdata ]; + int next = (short) instruction[i + RE.offsetNext ]; + + // Display the current program node + p.print(i + ". " + nodeToString(i) + ", next = "); + + // If there's no next, say 'none', otherwise give absolute index of next node + if (next == 0) + { + p.print("none"); + } + else + { + p.print(i + next); + } + + // Move past node + i += RE.nodeSize; + + // If character class + if (opcode == RE.OP_ANYOF) + { + // Opening bracket for start of char class + p.print(", ["); + + // Show each range in the char class + // int rangeCount = opdata; + for (int r = 0; r < opdata; r++) + { + // Get first and last chars in range + char charFirst = instruction[i++]; + char charLast = instruction[i++]; + + // Print range as X-Y, unless range encompasses only one char + if (charFirst == charLast) + { + p.print(charToString(charFirst)); + } + else + { + p.print(charToString(charFirst) + "-" + charToString(charLast)); + } + } + + // Annotate the end of the char class + p.print("]"); + } + + // If atom + if (opcode == RE.OP_ATOM) + { + // Open quote + p.print(", \""); + + // Print each character in the atom + for (int len = opdata; len-- != 0; ) + { + p.print(charToString(instruction[i++])); + } + + // Close quote + p.print("\""); + } + + // Print a newline + p.println(""); + } + } + + /** + * Dumps the current program to a System.out. + */ + public void dumpProgram() + { + dumpProgram(System.out); + } +} diff --git a/src/org/apache/regexp/REProgram.java b/src/org/apache/regexp/REProgram.java new file mode 100644 index 0000000..0ea665c --- /dev/null +++ b/src/org/apache/regexp/REProgram.java @@ -0,0 +1,180 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.regexp; + +/** + * A class that holds compiled regular expressions. This is exposed mainly + * for use by the recompile utility (which helps you produce precompiled + * REProgram objects). You should not otherwise need to work directly with + * this class. + * + * @see RE + * @see RECompiler + * + * @author Jonathan Locke + * @version $Id: REProgram.java 518156 2007-03-14 14:31:26Z vgritsenko $ + */ +public class REProgram +{ + static final int OPT_HASBACKREFS = 1; + static final int OPT_HASBOL = 2; + + char[] instruction; // The compiled regular expression 'program' + int lenInstruction; // The amount of the instruction buffer in use + char[] prefix; // Prefix string optimization + int flags; // Optimization flags (REProgram.OPT_*) + int maxParens = -1; + + /** + * Constructs a program object from a character array + * @param instruction Character array with RE opcode instructions in it + */ + public REProgram(char[] instruction) + { + this(instruction, instruction.length); + } + + /** + * Constructs a program object from a character array + * @param parens Count of parens in the program + * @param instruction Character array with RE opcode instructions in it + */ + public REProgram(int parens, char[] instruction) + { + this(instruction, instruction.length); + this.maxParens = parens; + } + + /** + * Constructs a program object from a character array + * @param instruction Character array with RE opcode instructions in it + * @param lenInstruction Amount of instruction array in use + */ + public REProgram(char[] instruction, int lenInstruction) + { + setInstructions(instruction, lenInstruction); + } + + /** + * Returns a copy of the current regular expression program in a character + * array that is exactly the right length to hold the program. If there is + * no program compiled yet, getInstructions() will return null. + * @return A copy of the current compiled RE program + */ + public char[] getInstructions() + { + // Ensure program has been compiled! + if (lenInstruction != 0) + { + // Return copy of program + char[] ret = new char[lenInstruction]; + System.arraycopy(instruction, 0, ret, 0, lenInstruction); + return ret; + } + return null; + } + + /** + * Sets a new regular expression program to run. It is this method which + * performs any special compile-time search optimizations. Currently only + * two optimizations are in place - one which checks for backreferences + * (so that they can be lazily allocated) and another which attempts to + * find an prefix anchor string so that substantial amounts of input can + * potentially be skipped without running the actual program. + * @param instruction Program instruction buffer + * @param lenInstruction Length of instruction buffer in use + */ + public void setInstructions(char[] instruction, int lenInstruction) + { + // Save reference to instruction array + this.instruction = instruction; + this.lenInstruction = lenInstruction; + + // Initialize other program-related variables + this.flags = 0; + this.prefix = null; + + // Try various compile-time optimizations if there's a program + if (instruction != null && lenInstruction != 0) + { + // If the first node is a branch + if (lenInstruction >= RE.nodeSize && instruction[0 + RE.offsetOpcode] == RE.OP_BRANCH) + { + // to the end node + int next = (short) instruction[0 + RE.offsetNext]; + if (instruction[next + RE.offsetOpcode] == RE.OP_END && lenInstruction >= (RE.nodeSize * 2)) + { + final char nextOp = instruction[RE.nodeSize + RE.offsetOpcode]; + // the branch starts with an atom + if (nextOp == RE.OP_ATOM) + { + // then get that atom as an prefix because there's no other choice + int lenAtom = instruction[RE.nodeSize + RE.offsetOpdata]; + this.prefix = new char[lenAtom]; + System.arraycopy(instruction, RE.nodeSize * 2, prefix, 0, lenAtom); + } + // the branch starts with a BOL + else if (nextOp == RE.OP_BOL) + { + // then set the flag indicating that BOL is present + this.flags |= OPT_HASBOL; + } + } + } + + BackrefScanLoop: + + // Check for backreferences + for (int i = 0; i < lenInstruction; i += RE.nodeSize) + { + switch (instruction[i + RE.offsetOpcode]) + { + case RE.OP_ANYOF: + i += (instruction[i + RE.offsetOpdata] * 2); + break; + + case RE.OP_ATOM: + i += instruction[i + RE.offsetOpdata]; + break; + + case RE.OP_BACKREF: + flags |= OPT_HASBACKREFS; + break BackrefScanLoop; + } + } + } + } + + /** + * Returns a copy of the prefix of current regular expression program + * in a character array. If there is no prefix, or there is no program + * compiled yet, getPrefix will return null. + * @return A copy of the prefix of current compiled RE program + */ + public char[] getPrefix() + { + if (prefix != null) + { + // Return copy of prefix + char[] ret = new char[prefix.length]; + System.arraycopy(prefix, 0, ret, 0, prefix.length); + return ret; + } + return null; + } +} diff --git a/src/org/apache/regexp/RESyntaxException.java b/src/org/apache/regexp/RESyntaxException.java new file mode 100644 index 0000000..3fabd27 --- /dev/null +++ b/src/org/apache/regexp/RESyntaxException.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.regexp; + +/** + * Exception thrown to indicate a syntax error in a regular expression. + * This is a non-checked exception because you should only have problems compiling + * a regular expression during development. + * If you are making regular expresion programs dynamically then you can catch it + * if you wish. But should not be forced to. + * + * @author Jonathan Locke + * @author Jonathan Locke + * @version $Id: REUtil.java 518156 2007-03-14 14:31:26Z vgritsenko $ + */ +public class REUtil +{ + /** complex: */ + private static final String complexPrefix = "complex:"; + + /** + * Creates a regular expression, permitting simple or complex syntax + * @param expression The expression, beginning with a prefix if it's complex or + * having no prefix if it's simple + * @param matchFlags Matching style flags + * @return The regular expression object + * @exception RESyntaxException thrown in case of error + */ + public static RE createRE(String expression, int matchFlags) throws RESyntaxException + { + if (expression.startsWith(complexPrefix)) + { + return new RE(expression.substring(complexPrefix.length()), matchFlags); + } + return new RE(RE.simplePatternToFullRegularExpression(expression), matchFlags); + } + + /** + * Creates a regular expression, permitting simple or complex syntax + * @param expression The expression, beginning with a prefix if it's complex or + * having no prefix if it's simple + * @return The regular expression object + * @exception RESyntaxException thrown in case of error + */ + public static RE createRE(String expression) throws RESyntaxException + { + return createRE(expression, RE.MATCH_NORMAL); + } +} diff --git a/src/org/apache/regexp/ReaderCharacterIterator.java b/src/org/apache/regexp/ReaderCharacterIterator.java new file mode 100644 index 0000000..c18fa7c --- /dev/null +++ b/src/org/apache/regexp/ReaderCharacterIterator.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.regexp; + +import java.io.Reader; +import java.io.IOException; + +/** + * Encapsulates java.io.Reader as CharacterIterator + * + * @author Ales Novak + * @version CVS $Id: ReaderCharacterIterator.java 518156 2007-03-14 14:31:26Z vgritsenko $ + */ +public final class ReaderCharacterIterator implements CharacterIterator +{ + /** Underlying reader */ + private final Reader reader; + + /** Buffer of read chars */ + private final StringBuffer buff; + + /** read end? */ + private boolean closed; + + /** @param reader a Reader, which is parsed */ + public ReaderCharacterIterator(Reader reader) + { + this.reader = reader; + this.buff = new StringBuffer(512); + this.closed = false; + } + + /** @return a substring */ + public String substring(int beginIndex, int endIndex) + { + try + { + ensure(endIndex); + return buff.toString().substring(beginIndex, endIndex); + } + catch (IOException e) + { + throw new StringIndexOutOfBoundsException(e.getMessage()); + } + } + + /** @return a substring */ + public String substring(int beginIndex) + { + try + { + readAll(); + return buff.toString().substring(beginIndex); + } + catch (IOException e) + { + throw new StringIndexOutOfBoundsException(e.getMessage()); + } + } + + /** @return a character at the specified position. */ + public char charAt(int pos) + { + try + { + ensure(pos); + return buff.charAt(pos); + } + catch (IOException e) + { + throw new StringIndexOutOfBoundsException(e.getMessage()); + } + } + + /** @return true iff if the specified index is after the end of the character stream */ + public boolean isEnd(int pos) + { + if (buff.length() > pos) + { + return false; + } + else + { + try + { + ensure(pos); + return (buff.length() <= pos); + } + catch (IOException e) + { + throw new StringIndexOutOfBoundsException(e.getMessage()); + } + } + } + + /** Reads n characters from the stream and appends them to the buffer */ + private int read(int n) throws IOException + { + if (closed) + { + return 0; + } + + char[] c = new char[n]; + int count = 0; + int read = 0; + + do + { + read = reader.read(c); + if (read < 0) // EOF + { + closed = true; + break; + } + count += read; + buff.append(c, 0, read); + } + while (count < n); + + return count; + } + + /** Reads rest of the stream. */ + private void readAll() throws IOException + { + while(! closed) + { + read(1000); + } + } + + /** Reads chars up to the idx */ + private void ensure(int idx) throws IOException + { + if (closed) + { + return; + } + + if (idx < buff.length()) + { + return; + } + read(idx + 1 - buff.length()); + } +} diff --git a/src/org/apache/regexp/StreamCharacterIterator.java b/src/org/apache/regexp/StreamCharacterIterator.java new file mode 100644 index 0000000..3bc0ffa --- /dev/null +++ b/src/org/apache/regexp/StreamCharacterIterator.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.regexp; + +import java.io.InputStream; +import java.io.IOException; + +/** + * Encapsulates java.io.InputStream as CharacterIterator. + * + * @author Ales Novak + * @version CVS $Id: StreamCharacterIterator.java 518156 2007-03-14 14:31:26Z vgritsenko $ + */ +public final class StreamCharacterIterator implements CharacterIterator +{ + /** Underlying is */ + private final InputStream is; + + /** Buffer of read chars */ + private final StringBuffer buff; + + /** read end? */ + private boolean closed; + + /** @param is an InputStream, which is parsed */ + public StreamCharacterIterator(InputStream is) + { + this.is = is; + this.buff = new StringBuffer(512); + this.closed = false; + } + + /** @return a substring */ + public String substring(int beginIndex, int endIndex) + { + try + { + ensure(endIndex); + return buff.toString().substring(beginIndex, endIndex); + } + catch (IOException e) + { + throw new StringIndexOutOfBoundsException(e.getMessage()); + } + } + + /** @return a substring */ + public String substring(int beginIndex) + { + try + { + readAll(); + return buff.toString().substring(beginIndex); + } + catch (IOException e) + { + throw new StringIndexOutOfBoundsException(e.getMessage()); + } + } + + + /** @return a character at the specified position. */ + public char charAt(int pos) + { + try + { + ensure(pos); + return buff.charAt(pos); + } + catch (IOException e) + { + throw new StringIndexOutOfBoundsException(e.getMessage()); + } + } + + /** @return true iff if the specified index is after the end of the character stream */ + public boolean isEnd(int pos) + { + if (buff.length() > pos) + { + return false; + } + else + { + try + { + ensure(pos); + return (buff.length() <= pos); + } + catch (IOException e) + { + throw new StringIndexOutOfBoundsException(e.getMessage()); + } + } + } + + /** Reads n characters from the stream and appends them to the buffer */ + private int read(int n) throws IOException + { + if (closed) + { + return 0; + } + + int c; + int i = n; + while (--i >= 0) + { + c = is.read(); + if (c < 0) // EOF + { + closed = true; + break; + } + buff.append((char) c); + } + return n - i; + } + + /** Reads rest of the stream. */ + private void readAll() throws IOException + { + while(! closed) + { + read(1000); + } + } + + /** Reads chars up to the idx */ + private void ensure(int idx) throws IOException + { + if (closed) + { + return; + } + + if (idx < buff.length()) + { + return; + } + + read(idx + 1 - buff.length()); + } +} diff --git a/src/org/apache/regexp/StringCharacterIterator.java b/src/org/apache/regexp/StringCharacterIterator.java new file mode 100644 index 0000000..34f52ad --- /dev/null +++ b/src/org/apache/regexp/StringCharacterIterator.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.regexp; + +/** + * Encapsulates String as CharacterIterator. + * + * @author Ales Novak + * @version CVS $Id: StringCharacterIterator.java 518156 2007-03-14 14:31:26Z vgritsenko $ + */ +public final class StringCharacterIterator implements CharacterIterator +{ + /** encapsulated */ + private final String src; + + /** @param src - encapsulated String */ + public StringCharacterIterator(String src) + { + this.src = src; + } + + /** @return a substring */ + public String substring(int beginIndex, int endIndex) + { + return src.substring(beginIndex, endIndex); + } + + /** @return a substring */ + public String substring(int beginIndex) + { + return src.substring(beginIndex); + } + + /** @return a character at the specified position. */ + public char charAt(int pos) + { + return src.charAt(pos); + } + + /** @return true iff if the specified index is after the end of the character stream */ + public boolean isEnd(int pos) + { + return (pos >= src.length()); + } +}