This commit is contained in:
Victor 2018-11-15 12:22:04 +02:00
commit bae38c0001
178 changed files with 39766 additions and 0 deletions

83
build.xml Normal file
View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<project name="SieFM" default="jar" basedir=".">
<description>Builds, tests, and runs the project .</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
pre-init: called before initialization of project properties
post-init: called after initialization of project properties
pre-preprocess: called before text preprocessing of sources
post-preprocess: called after text preprocessing of sources
pre-compile: called before source compilation
post-compile: called after source compilation
pre-obfuscate: called before obfuscation
post-obfuscate: called after obfuscation
pre-preverify: called before preverification
post-preverify: called after preverification
pre-jar: called before jar building
post-jar: called after jar building
pre-build: called before final distribution building
post-build: called after final distribution building
pre-clean: called before cleaning build products
post-clean: called after cleaning build products
Example of pluging a my-special-task after the compilation could look like
<target name="post-compile">
<my-special-task>
<fileset dir="${build.classes.dir}"/>
</my-special-task>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Other way how to customize the build is by overriding existing main targets.
The target of interest are:
preprocess: preprocessing
extract-libs: extraction of libraries and resources
compile: compilation
create-jad: construction of jad and jar manifest source
obfuscate: obfuscation
preverify: preverification
jar: jar archive building
run: execution
debug: execution in debug mode
build: building of the final distribution
javadoc: javadoc generation
Example of overriding the target for project execution could look like
<target name="run" depends="init,jar">
<my-special-exec jadfile="${dist.dir}/${dist.jad}"/>
</target>
Be careful about correct dependencies when overriding original target.
Again, for list of available properties which you can use check the target
you are overriding in nbproject/build-impl.xml file.
A special target for-all-configs can be used to run some specific targets for
all project configurations in a sequence. File nbproject/build-impl.xml
already contains some "for-all" targets:
jar-all
javadoc-all
clean-all
Example of definition of target iterating over all project configurations:
<target name="jar-all">
<property name="target.to.call" value="jar"/>
<antcall target="for-all-configs"/>
</target>
-->
</project>

1368
nbproject/build-impl.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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=535663c6
build.xml.script.CRC32=94c8884a
build.xml.stylesheet.CRC32=03eab09b
nbproject/build-impl.xml.data.CRC32=535663c6
nbproject/build-impl.xml.script.CRC32=0915c3e7
nbproject/build-impl.xml.stylesheet.CRC32=d670562e

View File

@ -0,0 +1,7 @@
#Tue Dec 01 01:16:58 EET 2009
netbeans.user=C\:\\Users\\aNNiMON\\.netbeans\\6.7
javadoc.preview=true
config.active=
deployment.counter=8
app-version.autoincrement=true
deployment.number=0.0.7

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/>
</project-private>

View File

@ -0,0 +1,140 @@
abilities=MMAPI=1.1,SATSAJCRMI=1.0,SATSACRYPTO=1.0,JSR82=1.1,NOKIAUI=1.0,JSR226=1.0,MIDP=2.1,JSR229=1.1.0,SATSAAPDU=1.0,CLDC=1.1,JSR177=1.0,JSR179=1.0.1,J2MEWS=1.0,VSCL=2.1,WMA=2.0,JSR172=1.0,SEMC_EXT_JP8=1.0,ColorScreen,OBEX=1.0,NokiaUI=1.0,JSR238=1.0,JSR239=1.0,JSR211=1.0,JSR234=1.0,ScreenWidth=240,lib/semc_ext_jp8.jar=1.0,MascotV3=1.0,JSR75=1.0,JSR184=1.1,SATSAPKI=1.0,ScreenHeight=321,ScreenColorDepth=8,JSR180=1.0.1,J2MEXMLRPC=1.0,
all.configurations=\
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
debug.level=debug
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=SieFM.jad
dist.jar=SieFM.jar
dist.javadoc.dir=${dist.dir}/doc
dist.root.dir=dist
extra.classpath=
filter.exclude.tests=false
filter.excludes=
filter.more.excludes=**/overview.html,**/package.html
filter.use.standard=true
jar.compress=true
javac.debug=true
javac.deprecation=false
javac.encoding=windows-1251
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=
main.class=
main.class.class=applet
manifest.apipermissions=
manifest.file=manifest.mf
manifest.jad=
manifest.manifest=
manifest.midlets=MIDlet-1: SieFM,/img/icon32.png,ftpmid.FtpMid\n
manifest.others=MIDlet-Vendor: SilentKnight, VMX, DiHLoS\nMIDlet-Name: SieFM\nMIDlet-Version: 3.41\n
manifest.pushregistry=
name=SieFM
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=-keep public class * extends javax.microedition.midlet.MIDlet \n-dontusemixedcaseclassnames
obfuscation.level=1
obfuscator.destjar=${build.dir}/obfuscated.jar
obfuscator.srcjar=${build.dir}/before-obfuscation.jar
platform.active=Sony_Ericsson_SDK_2_5_0_4_for_the_Java_TM__ME_Platform_Emulator_
platform.active.description=Sony Ericsson SDK 2.5.0.4 for the Java(TM) ME Platform(Emulator)
platform.apis=JSR234-1.0,SATSA-APDU-1.0,JSR211-1.0,JSR75-1.0,J2ME-WS-1.0,J2ME-XMLRPC-1.0,JSR82-1.1,SATSA-JCRMI-1.0,SATSA-CRYPTO-1.0,JSR239-1.0,JSR179-1.0.1,MascotV3-1.0,JSR184-1.1,JSR238-1.0,MMAPI-1.1,NokiaUI-1.0,JSR229-1.1.0,SATSA-PKI-1.0,JSR180-1.0.1,JSR226-1.0,JSR177-1.0,SEMC_EXT_JP8-1.0,VSCL-2.0,VSCL-2.1,WMA-2.0,lib/semc_ext_jp8.jar
platform.bootclasspath=${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/jsr239.jar:${platform.home}/lib/jsr75.jar:${platform.home}/lib/jsr179.jar:${platform.home}/lib/satsa-pki.jar:${platform.home}/lib/jsr180.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=72821905
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=trusted
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=E4534009
semc.certificate.path=
semc.private.key.password=
semc.private.key.path=
sign.alias=
sign.enabled=false
sign.keystore=
src.dir=src
use.emptyapis=true
use.preprocessor=true

10
nbproject/project.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.kjava.j2meproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2me-project">
<name>SieFM</name>
<minimum-ant-version>1.6</minimum-ant-version>
</data>
</configuration>
</project>

View File

@ -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.
*<p>
* The specification for Adler32 may be found in RFC 1950.
* (ZLIB Compressed Data Format Specification version 3.3)
*<p>
*<p>
* From that document:
*<p>
* "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.
*<p>
* 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."
*<p>
* "8.2. The Adler-32 algorithm
*<p>
* The Adler-32 algorithm is much faster than the CRC32 algorithm yet
* still provides an extremely low probability of undetected errors.
*<p>
* 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.)
*<p>
* 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 <code>Adler32</code> 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;
}
}

View File

@ -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); }
}

View File

@ -0,0 +1,64 @@
package com.classpath.zip;
import java.io.*;
class CentralDirectoryEndRecord implements ZipConstants
{
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(ZipFile.readLeInt(is) != ENDSIG)
{
return false;
}
is.skip(6);
numEntries = ZipFile.readLeShort(is);
centralSize = ZipFile.readLeInt(is);
centralOffset = ZipFile.readLeInt(is);
int commentLen = ZipFile.readLeShort(is);
if(commentLen > 0)
{
comment = ZipFile.readString(is, commentLen);
}
else
{
comment = "";
}
return true;
}
public void write(OutputStream os) throws IOException
{
ZipFile.writeLeInt(os, ENDSIG);
ZipFile.writeLeShort(os, 0); /* disk number */
ZipFile.writeLeShort(os, 0); /* disk with start of central dir */
ZipFile.writeLeShort(os, numEntries);
ZipFile.writeLeShort(os, numEntries);
ZipFile.writeLeInt(os, centralSize);
ZipFile.writeLeInt(os, centralOffset);
byte[] zipComment = ZipFile.encodeString(comment);
ZipFile.writeLeShort(os, zipComment.length);
os.write(zipComment);
}
}

View File

@ -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 <code>getChecksum.getValue()</code>.
*/
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;
}

View File

@ -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 <code>getChecksum.getValue()</code>.
*/
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;
}

View File

@ -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
* <code>getValue</code>. 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);
}

View File

@ -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);
}
}

View File

@ -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 <i>not</i> 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
* <i>undefined</i>.
* @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(). <br>
*
* <em>NOTE</em>: 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 <code>setInput(input, 0, input.length)</code>.
* @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 <code>setDictionary(dict, 0,
* dict.length)</code>.
* @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);
}
}

View File

@ -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;
interface 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 };
}

View File

@ -0,0 +1,706 @@
/* 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 implements DeflaterConstants
{
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*WSIZE];
head = new short[HASH_SIZE];
prev = new short[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 = MIN_MATCH - 1;
for (int i = 0; i < HASH_SIZE; i++)
head[i] = 0;
for (int i = 0; i < 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 DEFLATE_STORED:
if (strstart > blockStart)
{
huffman.flushStoredBlock (window, blockStart,
strstart - blockStart, false);
blockStart = strstart;
}
updateHash ();
break;
case DEFLATE_FAST:
if (strstart > blockStart)
{
huffman.flushBlock (window, blockStart, strstart - blockStart,
false);
blockStart = strstart;
}
break;
case 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 = MIN_MATCH - 1;
break;
}
comprFunc = COMPR_FUNC[lvl];
}
}
private final void updateHash ()
{
if (DEBUGGING)
System.err.println ("updateHash: "+strstart);
ins_h = (window[strstart] << 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 << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)])
& 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 & WMASK] = match = head[hash];
head[hash] = (short) strstart;
ins_h = hash;
return match & 0xffff;
}
private void slideWindow ()
{
System.arraycopy (window, WSIZE, window, 0, WSIZE);
matchStart -= WSIZE;
strstart -= WSIZE;
blockStart -= WSIZE;
/* Slide the hash table (could be avoided with 32 bit values
* at the expense of memory usage).
*/
for (int i = 0; i < HASH_SIZE; i++)
{
int m = head[i] & 0xffff;
head[i] = m >= WSIZE ? (short) (m - WSIZE) : 0;
}
/* Slide the prev table.
*/
for (int i = 0; i < WSIZE; i++)
{
int m = prev[i] & 0xffff;
prev[i] = m >= WSIZE ? (short) (m - 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 >= WSIZE + 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*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 >= 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, MIN_MATCH - 1);
int limit = Math.max (strstart - MAX_DIST, 0);
int strend = scan + 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 & WMASK] & 0xffff)) > limit
&& --chainLength != 0);
matchLen = Math.min (best_len, lookahead);
return matchLen >= 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 < MIN_MATCH)
return;
if (length > MAX_DIST)
{
offset += length - MAX_DIST;
length = 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 < WSIZE && storedLen >= 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 < MIN_LOOKAHEAD && !flush)
return false;
while (lookahead >= MIN_LOOKAHEAD || flush)
{
if (lookahead == 0)
{
/* We are flushing everything */
huffman.flushBlock (window, blockStart, strstart - blockStart,
finish);
blockStart = strstart;
return false;
}
if (strstart > 2 * WSIZE - 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 >= MIN_MATCH
&& (hashHead = insertString ()) != 0
&& strategy != Deflater.HUFFMAN_ONLY
&& strstart - hashHead <= 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 >= MIN_MATCH)
{
while (--matchLen > 0)
{
strstart++;
insertString ();
}
strstart++;
}
else
{
strstart += matchLen;
if (lookahead >= MIN_MATCH - 1)
updateHash ();
}
matchLen = 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 < MIN_LOOKAHEAD && !flush)
return false;
while (lookahead >= 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 * WSIZE - 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 >= MIN_MATCH)
{
int hashHead = insertString ();
if (strategy != Deflater.HUFFMAN_ONLY
&& hashHead != 0 && strstart - hashHead <= 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 == MIN_MATCH
&& strstart - matchStart > TOO_FAR)))
{
matchLen = MIN_MATCH - 1;
}
}
}
/* previous match was better */
if (prevLen >= 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 >= MIN_MATCH)
insertString ();
}
while (--prevLen > 0);
strstart ++;
lookahead--;
prevAvailable = false;
matchLen = 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 DEFLATE_STORED:
progress = deflateStored (canFlush, finish);
break;
case DEFLATE_FAST:
progress = deflateFast (canFlush, finish);
break;
case 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;
}
}

View File

@ -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 <i>not</i> 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;
}
}

View File

@ -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
* <code>def.deflate()</code> 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();
}
}

View File

@ -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);
}
}

View File

@ -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 <code>size</code>
* 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 <code>buf</code>
* 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;
}
}

View File

@ -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 )");
}
}

View File

@ -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
* <code>setInput()</code>, then inflate() it. If inflate doesn't
* inflate any bytes there may be three reasons:
* <ul>
* <li>needsInput() returns true because the input buffer is empty.
* You have to provide more input with <code>setInput()</code>.
* NOTE: needsInput() also returns true when, the stream is finished.
* </li>
* <li>needsDictionary() returns true, you have to provide a preset
* dictionary with <code>setDictionary()</code>.</li>
* <li>finished() returns true, the inflater has finished.</li>
* </ul>
* 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. <br>
*
* 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
* <i>undefined</i>.
*/
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(). <br>
*
* <em>NOTE</em>: 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();
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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 <code>GZIPInputStream</code>.
*
* @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");
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,160 @@
package com.classpath.zip;
import java.io.*;
import com.one.*;
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.seek(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
{
if(len > available() + dummyByteCount)
{
len = available() + dummyByteCount;
}
is.seek(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 seek(int pos) throws IOException
{
if(pos == currpos)
{
return;
}
if(pos < start)
{
pos = start;
}
else if(pos > end)
{
pos = end;
}
currpos = pos;
}
public int tell()
{
return currpos - start;
}
public int getCapacity()
{
return end - start;
}
public void update() throws IOException
{
is.update();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
interface ZipConstants
{
/* The local file header */
int LOCHDR = 30;
int LOCSIG = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);
int LOCVER = 4;
int LOCFLG = 6;
int LOCHOW = 8;
int LOCTIM = 10;
int LOCCRC = 14;
int LOCSIZ = 18;
int LOCLEN = 22;
int LOCNAM = 26;
int LOCEXT = 28;
/* The Data descriptor */
int EXTSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
int EXTHDR = 16;
int EXTCRC = 4;
int EXTSIZ = 8;
int EXTLEN = 12;
/* The central directory file header */
int CENSIG = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);
int CENHDR = 46;
int CENVEM = 4;
int CENVER = 6;
int CENFLG = 8;
int CENHOW = 10;
int CENTIM = 12;
int CENCRC = 16;
int CENSIZ = 20;
int CENLEN = 24;
int CENNAM = 28;
int CENEXT = 30;
int CENCOM = 32;
int CENDSK = 34;
int CENATT = 36;
int CENATX = 38;
int CENOFF = 42;
/* The entries in the end of central directory */
int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);
int ENDHDR = 22;
/* The following two fields are missing in SUN JDK */
int ENDNRD = 4;
int ENDDCD = 6;
int ENDSUB = 8;
int ENDTOT = 10;
int ENDSIZ = 12;
int ENDOFF = 16;
int ENDCOM = 20;
}

View File

@ -0,0 +1,631 @@
/* 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 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 implements ZipConstants
{
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 String name;
private int size;
private int compressedSize;
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 */
public int offset; /* used by ZipFile and 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 = LOCHDR + compressedSize;
if(name != null)
{
localSize += ZipFile.getEncodedLength(name);
}
if(extra != null)
{
localSize += extra.length;
}
if((flags & 8) != 0)
{
localSize += 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(ZipFile.readLeInt(is) != CENSIG)
{
return false;
}
is.skip(4);
flags = ZipFile.readLeShort(is);
setMethod(ZipFile.readLeShort(is));
setDOSTime(ZipFile.readLeInt(is));
setCRC(ZipFile.readLeInt(is));
setCompressedSize(ZipFile.readLeInt(is));
setSize(ZipFile.readLeInt(is));
int nameLen = ZipFile.readLeShort(is);
int extraLen = ZipFile.readLeShort(is);
int commentLen = ZipFile.readLeShort(is);
is.skip(8);
offset = ZipFile.readLeInt(is);
if(nameLen > 0)
{
setName(ZipFile.readString(is, nameLen));
}
if(extraLen > 0)
{
byte[] b = new byte[extraLen];
is.read(b, 0, extraLen);
setExtra(b);
}
if(commentLen > 0)
{
setComment(ZipFile.readString(is, commentLen));
}
return true;
}
/**
* Write central file header for this entry,
* return number of bytes written.
*/
public int writeCentralHeader(OutputStream os) throws IOException
{
ZipFile.writeLeInt(os, CENSIG);
int method = getMethod();
ZipFile.writeLeShort(os, method == ZipFile.STORED ? ZipFile.ZIP_STORED_VERSION : ZipFile.ZIP_DEFLATED_VERSION);
ZipFile.writeLeShort(os, method == ZipFile.STORED ? ZipFile.ZIP_STORED_VERSION : ZipFile.ZIP_DEFLATED_VERSION);
ZipFile.writeLeShort(os, flags);
ZipFile.writeLeShort(os, method);
ZipFile.writeLeInt(os, getDOSTime());
ZipFile.writeLeInt(os, getCRC());
ZipFile.writeLeInt(os, getCompressedSize());
ZipFile.writeLeInt(os, getSize());
byte[] name = ZipFile.encodeString(getName());
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 ? ZipFile.encodeString(strComment) : new byte[0];
if(comment.length > 0xFFFF)
{
throw new ZipException("Comment too long.");
}
ZipFile.writeLeShort(os, name.length);
ZipFile.writeLeShort(os, extra.length);
ZipFile.writeLeShort(os, comment.length);
ZipFile.writeLeShort(os, 0); /* disk number */
ZipFile.writeLeShort(os, 0); /* internal file attr */
ZipFile.writeLeInt(os, 0); /* external file attr */
ZipFile.writeLeInt(os, offset);
os.write(name);
os.write(extra);
os.write(comment);
return 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(ZipFile.readLeInt(is) != LOCSIG)
{
return false;
}
is.skip(2);
flags = ZipFile.readLeShort(is);
setMethod(ZipFile.readLeShort(is));
setDOSTime(ZipFile.readLeInt(is));
setCRC(ZipFile.readLeInt(is));
setCompressedSize(ZipFile.readLeInt(is));
setSize(ZipFile.readLeInt(is));
int nameLen = ZipFile.readLeShort(is);
int extraLen = ZipFile.readLeShort(is);
if(nameLen > 0)
{
setName(ZipFile.readString(is, nameLen));
}
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
{
ZipFile.writeLeInt(os, LOCSIG);
int method = getMethod();
ZipFile.writeLeShort(os, method == ZipFile.STORED ? ZipFile.ZIP_STORED_VERSION : ZipFile.ZIP_DEFLATED_VERSION);
ZipFile.writeLeShort(os, flags);
ZipFile.writeLeShort(os, method);
ZipFile.writeLeInt(os, getDOSTime());
if((flags & 8) == 0)
{
ZipFile.writeLeInt(os, getCRC());
ZipFile.writeLeInt(os, getCompressedSize());
ZipFile.writeLeInt(os, getSize());
}
else
{
ZipFile.writeLeInt(os, 0);
ZipFile.writeLeInt(os, 0);
ZipFile.writeLeInt(os, 0);
}
byte[] name = ZipFile.encodeString(getName());
if(name.length > 0xFFFF)
{
throw new ZipException("Name too long.");
}
byte[] extra = getExtra();
if(extra == null)
{
extra = new byte[0];
}
ZipFile.writeLeShort(os, name.length);
ZipFile.writeLeShort(os, extra.length);
os.write(name);
os.write(extra);
return 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 setTime(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 getTime()
{
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);
setTime(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();
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,753 @@
/* 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 javax.microedition.io.file.*;
import javax.microedition.io.*;
import com.vmx.*;
import com.one.*;
import filemanager.*;
/**
* 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 implements ZipConstants
{
/**
* 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;
// File from which zip entries are read.
private FileConnection fc = null;
private RandomAccessInputStream rais;
private boolean closed = false;
private boolean finished = true;
private CentralDirectoryEndRecord cder = new CentralDirectoryEndRecord();
// The entries of this zip file when initialized and not yet closed.
private Hashtable entries;
public ZipFile(InputStream is) throws IOException
{
if(is instanceof RandomAccessInputStream)
{
rais = (RandomAccessInputStream)is;
}
else
{
rais = new BufferedInputStream(is);
}
checkZipFile();
}
public ZipFile(String fileName, boolean create) throws IOException
{
fc = (FileConnection)Connector.open("file:///" + fileName);
if(fc.isDirectory())
{
fc.close();
throw new IOException("Not a file: " + fileName);
}
else if(!fc.exists())
{
if(create)
{
fc.create();
}
else
{
fc.close();
throw new IOException("File does not exist: " + fileName);
}
}
rais = new FileInputStream(fc);
if(rais.getCapacity() == 0)
{
entries = new Hashtable();
finished = false;
}
else
{
checkZipFile();
}
}
private void checkZipFile() throws ZipException
{
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");
}
}
public boolean isReadOnly()
{
return fc == null;
}
private void checkReadOnly() throws IOException
{
if(isReadOnly())
{
throw new IOException("ZipFile is read only");
}
}
/**
* Checks if file is closed and throws an exception.
*/
private void checkClosed()
{
if(closed)
{
throw new IllegalStateException("ZipFile is closed");
}
}
private void checkEntries()
{
if(entries == null)
{
try
{
readEntries();
}
catch(Exception e)
{
System.err.println("*** " + e.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 <code>rais</code>.
*
* @exception IOException if a i/o error occured.
* @exception ZipException if the central directory is malformed
*/
private void readEntries() 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.seek(0);
BufDataInputStream inp = new BufDataInputStream(rais);
int pos = rais.getCapacity() - ENDHDR;
int top = Math.max(0, pos - 0xFFFF);
/* -- VERY slow with current implementation
do
{
if(pos < top)
{
throw new ZipException("Central Directory not found, probably not a zip file");
}
inp.seek(pos--);
} while(!cder.read(inp));
*/
inp.seek(pos);
if(!cder.read(inp))
{
byte[] sig = new byte[4];
sig[0] = (byte)(ENDSIG & 0xFF);
sig[1] = (byte)((ENDSIG >> 8) & 0xFF);
sig[2] = (byte)((ENDSIG >> 16) & 0xFF);
sig[3] = (byte)((ENDSIG >> 24) & 0xFF);
pos = inp.indexOf(sig, 0, 4, top, pos);
if(pos >= 0)
{
inp.seek(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);
ZipEntry entry;
inp.seek(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);
}
}
/**
* 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(InputStream source, String name, long time, int level, boolean replace, ProgressCallback callback) throws IOException
{
if(replace)
{
deleteEntry(name);
}
else
{
checkReadOnly();
if(getEntry(name) != null)
{
return false;
}
}
if(callback != null)
{
int index = name.lastIndexOf('/');
if(index >= 0 && index < name.length())
{
callback.setText(name.substring(index + 1));
}
else
{
callback.setText(name);
}
}
ZipEntry entry = new ZipEntry(name);
if(time < 0)
{
time = System.currentTimeMillis();
}
entry.setTime(time);
entry.setMethod(DEFLATED);
entry.flags = 8;
entry.offset = cder.centralOffset;
OutputStream os = fc.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(level, true));
int size = 0;
if(source != null)
{
byte[] buf = new byte[main.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)
{
writeLeInt(os, EXTSIG);
writeLeInt(os, entry.getCRC());
writeLeInt(os, entry.getCompressedSize());
writeLeInt(os, entry.getSize());
cder.centralOffset += EXTHDR;
}
dos.close();
entries.put(name, entry);
rais.update();
return true;
}
/**
* Delete an entry with specified name 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(String name) throws IOException
{
checkReadOnly();
ZipEntry entry = getEntry(name);
if(entry == null)
{
return false;
}
finished = false;
rais.close();
int delta = filesystem.updateFileData(fc, new byte[0], entry.offset, entry.offset + entry.getLocalSize());
cder.centralOffset += delta;
fc.truncate(cder.centralOffset);
rais = new FileInputStream(fc);
updateOffset(entry.offset, delta);
entries.remove(entry.getName());
return true;
}
/**
* Rename specified entry.
*/
public boolean renameEntry(String name, String newName) throws IOException
{
checkReadOnly();
ZipEntry entry = getEntry(name);
if(entry == null)
{
return false;
}
byte[] b = encodeString(newName);
finished = false;
rais.close();
int delta = filesystem.updateFileData(fc, b, entry.offset + LOCHDR, entry.offset + LOCHDR + getEncodedLength(entry.getName()));
cder.centralOffset += delta;
fc.truncate(cder.centralOffset);
int len = b.length;
b = new byte[2];
b[0] = (byte)(len & 0xFF);
b[1] = (byte)((len & 0xFF) >> 8);
filesystem.updateFileData(fc, b, entry.offset + LOCNAM, entry.offset + LOCNAM + 2);
rais = new FileInputStream(fc);
updateOffset(entry.offset, delta);
entries.remove(entry.getName());
entry.setName(newName);
entries.put(entry.getName(), entry);
return true;
}
/**
* Update offsets of entries in hashtable.
*/
private void updateOffset(int base, int delta) throws IOException
{
if(finished)
{
return;
}
checkReadOnly();
Enumeration e = entries();
ZipEntry entry;
while(e.hasMoreElements())
{
entry = (ZipEntry)e.nextElement();
if(entry.offset > base)
{
entry.offset += delta;
}
}
}
/**
* Write central directory at the end of file.
*/
public void finish() throws IOException
{
if(finished)
{
return;
}
checkReadOnly();
Enumeration enm = entries();
ZipEntry entry;
cder.centralSize = 0;
cder.numEntries = 0;
OutputStream os = fc.openOutputStream(cder.centralOffset);
while(enm.hasMoreElements())
{
entry = (ZipEntry)enm.nextElement();
cder.centralSize += entry.writeCentralHeader(os);
cder.numEntries++;
}
cder.write(os);
os.flush();
os.close();
finished = true;
}
/**
* Closes the ZipFile. This also closes all input streams given by
* this class. After this is called, no further method should be called.
*
* @exception IOException if a i/o error occured.
*/
public void close() throws IOException
{
if(!finished)
{
finish();
}
closed = true;
entries = null;
if(rais != null)
{
rais.close();
rais = null;
}
if(fc != null)
{
fc.close();
fc = null;
}
}
/**
* Returns an enumeration of all Zip entries in this Zip file.
*
* @exception IllegalStateException when the ZipFile has already been closed
*/
public Enumeration entries()
{
checkClosed();
checkEntries();
return entries.elements();
}
/**
* Searches for a zip entry in this archive with the given name.
*
* @param name the name. May contain directory components separated by
* slashes ('/').
* @return the zip entry, or null if no entry with that name exists.
*
* @exception IllegalStateException when the ZipFile has already been closed
*/
public ZipEntry getEntry(String name)
{
checkClosed();
checkEntries();
ZipEntry entry = (ZipEntry)entries.get(name);
// If we didn't find it, maybe it's a directory.
// -- Such behaviour can cause promlems when adding
// an entry with replacement of existing one
// (we might replace a folder with a file in particular).
/*
if(entry == null && !name.endsWith("/"))
{
entry = (ZipEntry)entries.get(name + '/');
}
*/
return entry;
}
/**
* 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(String name) throws IOException
{
ZipEntry entry = getEntry(name);
if(entry == null)
{
return null;
}
ZipEntry readEntry = new ZipEntry();
rais.seek(entry.offset);
if(!readEntry.readLocalHeader(rais))
{
throw new ZipException("Wrong Local Header signature");
}
PartialInputStream inp = new PartialInputStream(rais, rais.tell(), entry.getCompressedSize());
switch(entry.getMethod())
{
case STORED:
return inp;
case DEFLATED:
inp.addDummyByte();
final Inflater inf = new Inflater(true);
final int sz = entry.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 " + entry.getMethod());
}
}
/**
* Returns the number of entries in this zip file.
*
* @exception IllegalStateException when the ZipFile has already been closed
*/
public int size()
{
checkClosed();
checkEntries();
return entries.size();
}
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 String readString(InputStream is, int len) throws IOException
{
byte[] b = new byte[len];
len = is.read(b, 0, len);
return StringEncoder.decodeString(b, 0, len, options.arcEnc);
}
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);
}
public static byte[] encodeString(String value)
{
return StringEncoder.encodeString(value, options.arcEnc);
}
public static int getEncodedLength(String value)
{
return StringEncoder.getEncodedLength(value, options.arcEnc);
}
// private static void out(String s)
// {
// System.out.println("[ZipFile] " + s);
// }
}

View File

@ -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 implements ZipConstants
{
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 == CENSIG)
{
/* Central Header reached. */
close();
return null;
}
if(header != 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() != 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);
}
}

View File

@ -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 implements ZipConstants
{
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.getTime() < 0)
{
entry.setTime(System.currentTimeMillis());
}
entry.flags = flags;
entry.offset = offset;
entry.setMethod(method);
curMethod = method;
/* Write the local file header */
writeLeInt(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 += 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(EXTSIG);
writeLeInt((int)curEntry.getCRC());
writeLeInt((int)curEntry.getCompressedSize());
writeLeInt((int)curEntry.getSize());
offset += 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(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 += CENHDR + name.length + extra.length + comment.length;
}
writeLeInt(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;
}
}

947
src/com/ibxm/Channel.java Normal file
View File

@ -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 );
}
}

112
src/com/ibxm/Envelope.java Normal file
View File

@ -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 ) + ", " );
}
}
}

View File

@ -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;
}
}

416
src/com/ibxm/IBXM.java Normal file
View File

@ -0,0 +1,416 @@
//package ibxm;
package com.ibxm;
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(int sample_rate)
{
//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(new Module());
set_resampling_quality(1);
}
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 void get_audio(byte[] output_buffer, int frames)
{
int output_idx, mix_idx, mix_end, count, amplitude;
output_idx = 0;
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;
}
}
}
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;
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

171
src/com/ibxm/Module.java Normal file
View File

@ -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;
}
}
}

62
src/com/ibxm/Pattern.java Normal file
View File

@ -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;
}
}

View File

@ -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;
}
}

240
src/com/ibxm/Sample.java Normal file
View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,102 @@
package com.ibxm.util;
/*
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.
<Samples>
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<Samples>
^(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;
/**
* <p>Write a WAV header for the specified format.</p>
* <p>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.</p>
*
* @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);
}
}

View File

@ -0,0 +1,10 @@
package com.one;
/**
* Èíòåðôåéñ, ïðèíèìàþùèé ñîîáùåíèÿ îò ArraySearchThread
* î íàéäåííûõ ýëåìåíòàõ
*/
public interface ArraySearchListener
{
public void elementFound(Object[] array, Object element, int index);
}

View File

@ -0,0 +1,59 @@
package com.one;
/**
* Ïîòîê äëÿ ïîèñêà ýëåìåíòîâ â ìàññèâå
*/
public class ArraySearchThread implements Runnable
{
protected Object[] array;
protected Object element;
protected ArraySearchListener listener;
protected boolean running;
protected Thread t;
public ArraySearchThread(Object[] array, Object element, ArraySearchListener listener)
{
this.array = array;
this.element = element;
this.listener = listener;
}
public void start()
{
running = true;
t = new Thread(this);
t.start();
}
public void stop()
{
running = false;
}
public boolean isAlive()
{
return running;
}
public void join() throws InterruptedException
{
if(running && t != null)
{
t.join();
}
}
public void run()
{
for(int i = 0; (i < array.length) && running; i++)
{
if(array[i].equals(element))
{
listener.elementFound(array, element, i);
break;
}
}
running = false;
}
}

View File

@ -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();
}

View File

@ -0,0 +1,175 @@
package com.one;
import java.io.*;
import filemanager.main;
/**
* Âõîäíîé ïîòîê ñ ïîëíîé áóôåðèçàöèåé.
* Ïðèçâàí ðàáîòàòü òàì, ãäå òðåáóåòñÿ ïîääåðæêà 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
{
System.gc();
this.is = is;
buf = new byte[is.available()];
currpos = 0;
readpos = 0;
markedpos = 0;
}
public BufferedInputStream(byte[] data)
{
this.is = null;
buf = data;
currpos = 0;
readpos = data.length;
markedpos = 0;
}
protected BufferedInputStream()
{
}
// public byte[] getBuffer()
// {
// bufferize(buf.length - 1);
// return buf;
// }
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
{
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 seek(int pos)
{
if(pos == currpos)
{
return;
}
if(pos < 0)
{
currpos = 0;
}
else if(pos > getCapacity())
{
currpos = getCapacity();
}
else
{
currpos = pos;
}
}
public int tell()
{
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();
}
}
}
}

View File

@ -0,0 +1,112 @@
package com.one;
import com.vmx.*;
import java.util.*;
import java.io.*;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import filemanager.filesystem;
/**
* Ïîòîê øèôðîâàíèÿ ôàéëîâ
*/
public class CryptThread implements Runnable
{
protected RTEF rtef;
protected Vector files;
protected ProgressCallback callback;
public String error;
public boolean interrupt;
public CryptThread(String password, Vector filelist, ProgressCallback cb)
{
rtef = new RTEF(password);
files = filelist;
callback = cb;
error = null;
interrupt = false;
}
/**
* Ôóíêöèÿ, îñóùåñòâëÿþùàÿ ñîáñòâåííî øèôðîâàíèå
*/
public void run()
{
FileConnection fc = null;
InputStream is = null;
OutputStream os = null;
boolean usecb = callback != null;
try
{
if(usecb)
{
int max = 0;
for(int i = 0; i < files.size(); i++)
{
max += filesystem.getSize((String)files.elementAt(i));
}
callback.setMax(max);
callback.setProgress(0);
}
int cp;
String fname;
for(int i = 0; i < files.size() && !interrupt; i++)
{
fname = (String)files.elementAt(i);
if(usecb)
{
callback.setText(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(usecb)
{
callback.progress(cp);
}
}
}
catch(Exception x)
{
error = x.toString(); // x.getClass().getName() + ": " + x.getMessage();
if(fc != null)
{
try
{
fc.close();
}
catch(Exception xx)
{
}
}
}
}
// private static void out(String s)
// {
// System.out.println("[CryptThread] " + s);
// }
}

View File

@ -0,0 +1,146 @@
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();
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 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)).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);
}
}

View File

@ -0,0 +1,191 @@
package com.one;
import java.io.*;
import javax.microedition.io.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
{
this.fc = fc;
is = fc.openInputStream();
if(marksupp = is.markSupported())
{
is.mark(is.available() + 0x100);
}
currpos = 0;
markedpos = 0;
}
public int available() throws IOException
{
return is.available();
}
public void close() throws IOException
{
is.close();
is = null;
fc = null;
}
public void mark(int readLimit)
{
markedpos = currpos;
}
public int read() throws IOException
{
if(is.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
{
if(len > is.available()) // íåëüçÿ ñ÷èòàòü áîëüøå, ÷åì åùå îñòàëîñü
{
len = is.available();
}
is.read(b, off, len);
currpos += len;
return len;
}
public void reset() throws IOException
{
seek(markedpos);
}
public long skip(long n) throws IOException
{
if(n > is.available())
{
n = is.available();
}
is.skip(n);
currpos += n;
return n;
}
public void seek(int pos) throws IOException
{
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 tell()
{
return currpos;
}
public int getCapacity() throws IOException
{
return is.available() + currpos;
}
public void update() throws IOException
{
int pos = currpos;
currpos = 0;
is.close();
is = fc.openInputStream();
if(marksupp = is.markSupported())
{
is.mark(is.available() + 0x100);
}
seek(pos);
}
// private static void out(String s)
// {
// System.out.println("[FileInputStream] " + s);
// }
}

View File

@ -0,0 +1,228 @@
package com.one;
import javax.microedition.lcdui.*;
import java.io.*;
import filemanager.main;
/**
* Êëàññ äëÿ îáðàáîòêè èçîáðàæåíèé
*/
public class ImageProcessor
{
/** ïîëîæåíèå ôèêñèðîâàííîé òî÷êè */
private static final int SHIFT = 16;
/**
* Ôóíêöèÿ ìàñøòàáèðîâàíèÿ èçîáðàæåíèé
*/
public static Image scaleImage(Image source, int destw, int desth)
{
if(source == null)
{
return null;
}
int srcw, srch;
int[] srcPixels;
int[] destPixels;
int wscan, hscan, scancount;
int x, y, sx, sy, cx, cy;
int r, g, b;
int idx;
int rx, ry;
try
{
/* ðàçìåðû èñõîäíîãî èçîáðàæåíèÿ */
srcw = source.getWidth();
srch = source.getHeight();
/* êîýôôèöèåíò ìàñøòàáèðîâàíèÿ */
rx = (srcw << SHIFT) / destw;
ry = (srch << SHIFT) / desth;
System.gc();
srcPixels = new int[srcw * srch];
source.getRGB(srcPixels, 0, srcw, 0, 0, srcw, srch);
source = null;
System.gc();
destPixels = new int[destw * desth];
/* ñêîëüêî òî÷åê ó÷àñòâóþò â óñðåäíåíèè */
wscan = rx >>> SHIFT;
hscan = ry >>> SHIFT;
if(wscan == 0)
{
wscan = 1;
}
if(hscan == 0)
{
hscan = 1;
}
scancount = wscan * hscan;
for(x = 0; x < destw; x++)
{
for(y = 0; y < desth; y++)
{
/* íà÷àëüíûå êîîðäèíàòû äëÿ óñðåäíåíèÿ */
sx = (x * rx) >>> SHIFT ;
sy = (y * ry) >>> 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 + destw * y] = (r << 16) | (g << 8) | (b);
}
}
srcPixels = null;
System.gc();
source = Image.createRGBImage(destPixels, destw, desth, false);
destPixels = null;
System.gc();
}
catch(OutOfMemoryError ome)
{
// óâû, íè÷åãî íå ïîäåëàåøü,
// âîçâðàùàåì îðèãèíàëüíóþ êàðòèíêó
}
catch(Throwable e)
{
// à âîò ýòî íå ïðåäóñìîòðåíî,
// íàäî ïîêàçàòü ñîîáùåíèå ñ îøèáêîé
main.showErrMsg(38, e);
}
return source;
}
/**
* Êà÷åñòâåííî óâåëè÷èòü êàðòèíêó.
* Ñíà÷àëà óâåëè÷èâàåì â öåëîå ÷èñëî ðàç,
* çàòåì óìåíüøàåì äî íåîáõîäèìûõ ðàçìåðîâ.
* Òàêèì îáðàçîì îñóùåñòâëÿåòñÿ ñãëàæèâàíèå.
*/
public static Image scaleImageHQ(Image source, int destw, int desth)
{
int origw = source.getWidth();
int origh = source.getHeight();
if(destw <= origw && desth <= origh)
{
return scaleImage(source, destw, desth);
}
else
{
int tempw = origw;
int temph = origh;
while(tempw < destw || temph < desth)
{
tempw += origw;
temph += origh;
}
return scaleImage(scaleImage(source, tempw, temph), destw, desth);
}
}
/**
* Ïðåîáîðàçîâàíèå èçîáðàæåíèÿ source â ïðîçðà÷íîå
* ñ çàäàííîé ïðîçðà÷íîñòüþ
*/
public static Image transImage(Image source, int newtrans)
{
if(source == null)
{
return null;
}
int[] rgbdata;
try
{
rgbdata = new int[source.getWidth() * source.getHeight()];
source.getRGB(rgbdata, 0, source.getWidth(), 0, 0, source.getWidth(), source.getHeight());
int alpha;
for(int i = 0; i < rgbdata.length; i++)
{
alpha = rgbdata[i] >>> 24;
if(alpha > newtrans)
{
alpha = newtrans;
}
rgbdata[i] = (rgbdata[i] & 0x00FFFFFF) | (alpha << 24);
}
return Image.createRGBImage(rgbdata, source.getWidth(), source.getHeight(), true);
}
catch(OutOfMemoryError oome)
{
return source;
}
}
/**
* Ïðåîáîðàçîâàíèå â èçîáðàæåíèè source öâåòà color â newcolor
*/
public static Image transColor(Image source, int color, int newcolor)
{
if(source == null)
{
return null;
}
int[] rgbdata;
try
{
rgbdata = new int[source.getWidth() * source.getHeight()];
source.getRGB(rgbdata, 0, source.getWidth(), 0, 0, source.getWidth(), source.getHeight());
for(int i = 0; i < rgbdata.length; i++)
{
if(rgbdata[i] == color)
{
rgbdata[i] = newcolor;
}
}
return Image.createRGBImage(rgbdata, source.getWidth(), source.getHeight(), true);
}
catch(OutOfMemoryError oome)
{
return source;
}
}
}

109
src/com/one/IniFile.java Normal file
View File

@ -0,0 +1,109 @@
package com.one;
import java.io.*;
import com.vmx.*;
/**
* Ïàðñåð INI ôàéëîâ.
* Ñåêöèè íå ïîäåðæèâàþòñÿ.
*/
public class IniFile
{
protected InputStreamDecoder isd;
/**
* Îòêðûòèå ðåñóðñà êàê INI ôàéëà
*/
public IniFile(String resname) throws IOException
{
isd = InputStreamDecoder.getResourceDecoder(resname);
}
/**
* Îòêðûòèå INI ôàéëà
*/
public IniFile(InputStreamDecoder isd)
{
this.isd = isd;
}
public void close() throws IOException
{
isd.close();
}
/**
* Ïðî÷èòàòü èç ôàéëà ñëåäóþùóþ ñòðîêó
* è ïðåîáðàçîâàòü åå â IniRecord
*/
public IniRecord getNextRecord() 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)
{
// åñëè ñòðîêà íå ïóñòàÿ, òî âîçâðàùàåì ñîîòâåòñòâóþùóþ IniRecord
IniRecord record = new IniRecord();
index = s.indexOf('=');
if(index >= 0)
{
record.key = s.substring(0, index).trim();
record.value = s.substring(index + 1).trim();
}
else
{
record.key = record.value = s;
}
return record;
}
}
return null;
}
}

View File

@ -0,0 +1,13 @@
package com.one;
/**
* Çàïèñü INI
*/
public class IniRecord
{
/** Êëþ÷ */
public String key;
/** Çíà÷åíèå */
public String value;
}

380
src/com/one/MD5.java Normal file
View File

@ -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 <i>blockSize</i> 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;
}
}

View File

@ -0,0 +1,146 @@
package com.one;
import javax.microedition.lcdui.*;
public 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();
}
protected void showNotify()
{
}
protected void hideNotify()
{
}
protected void keyPressed(int keyCode)
{
}
protected void keyReleased(int keyCode)
{
}
protected void keyRepeated(int keyCode)
{
}
protected void paint(Graphics g)
{
}
protected void pointerDragged(int x, int y)
{
}
protected void pointerPressed(int x, int y)
{
}
protected void pointerReleased(int x, int y)
{
}
protected void sizeChanged(int w, int h)
{
}
}

234
src/com/one/PakFile.java Normal file
View File

@ -0,0 +1,234 @@
package com.one;
import java.io.*;
import java.util.Hashtable;
import com.vmx.*;
import filemanager.main;
/**
* Êëàññ äëÿ ðàáîòû ñ 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(2048, 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[main.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 RandomAccessInputStream.getPartialInputStream(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);
// }
}

115
src/com/one/PakThread.java Normal file
View File

@ -0,0 +1,115 @@
package com.one;
import com.vmx.*;
import java.util.*;
import java.io.*;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import filemanager.filesystem;
import javax.microedition.lcdui.Gauge;
/**
* Ïîòîê ñîçäàíèÿ PAK àðõèâà
*/
public class PakThread implements Runnable
{
protected String filename;
protected Vector files;
protected ProgressCallback callback;
public String error;
public boolean interrupt;
protected boolean usecb;
public PakThread(String fn, Vector filelist, ProgressCallback cb)
{
filename = fn;
files = filelist;
callback = cb;
error = null;
interrupt = false;
usecb = callback != null;
}
protected void addToPak(PakFile pf, String file) throws IOException, IllegalStateException
{
if(usecb)
{
callback.setText(file.substring(file.lastIndexOf('/') + 1));
}
InputStream is = Connector.openInputStream("file:///" + file);
int cp = is.available();
pf.addElement(file.substring(file.lastIndexOf('/') + 1), is, callback);
is.close();
}
/**
* Ôóíêöèÿ, îñóùåñòâëÿþùàÿ ñîáñòâåííî ñîçäàíèå PAK ôàéëà
*/
public void run()
{
FileConnection fc = null;
try
{
fc = (FileConnection)Connector.open("file:///" + filename);
if(fc.exists() && fc.isDirectory())
{
fc.delete();
}
if(!fc.exists())
{
fc.create();
}
PakFile pf = new PakFile(files.size());
if(usecb)
{
int max = 0;
for(int i = 0; i < files.size(); i++)
{
max += filesystem.getSize((String)files.elementAt(i));
}
callback.setMax(max);
callback.setProgress(0);
}
for(int i = 0; i < files.size() && !interrupt; i++)
{
addToPak(pf, (String)files.elementAt(i));
}
if(usecb)
{
callback.setMax(Gauge.INDEFINITE);
callback.setProgress(Gauge.CONTINUOUS_RUNNING);
}
OutputStream os = fc.openOutputStream();
pf.write(os);
os.close();
fc.close();
}
catch(Exception x)
{
error = x.toString(); // x.getClass().getName() + ": " + x.getMessage();
if(fc != null)
{
try
{
fc.close();
}
catch(Exception xx)
{
}
}
}
}
}

View File

@ -0,0 +1,106 @@
package com.one;
import java.io.*;
import javax.microedition.io.*;
import com.vmx.*;
import java.util.Vector;
import java.util.Enumeration;
/**
* Êëàññ äëÿ ðàáîòû ñî ñïèñêàìè âîñïðîèçâåäåíèÿ
*/
public class PlayListFile
{
/*
public static void writePlayList(String[] pl, OutputStream os) throws IOException
{
DataOutputStream dos = new DataOutputStream(os);
dos.writeShort((short)pl.length);
for(int i = 0; i < pl.length; i++)
{
dos.writeUTF(pl[i]);
}
}
*/
public static void writePlayList(Vector vpl, String path, boolean allowRelPath, OutputStream os) throws IOException
{
DataOutputStream dos = new DataOutputStream(os);
dos.writeShort((short)vpl.size());
dos.writeBoolean(allowRelPath);
Enumeration e = vpl.elements();
if(e == null)
{
return;
}
if(allowRelPath)
{
int newstart = path.length();
String s;
while(e.hasMoreElements())
{
s = (String)e.nextElement();
if(s.startsWith(path))
{
dos.writeUTF(s.substring(newstart));
}
}
}
else
{
while(e.hasMoreElements())
{
dos.writeUTF((String)e.nextElement());
}
}
}
public static String[] readPlayList(String fname) throws IOException
{
String s = null;
int index = fname.lastIndexOf('/');
if(index > 0)
{
s = fname.substring(0, index + 1);
}
else
{
s = fname;
}
return readPlayList(Connector.openInputStream("file:///" + fname), s);
}
public static String[] readPlayList(InputStream is, String path) throws IOException
{
DataInputStream dis = new DataInputStream(is);
String[] pl = new String[dis.readShort()];
if(dis.readBoolean())
{
for(int i = 0; i < pl.length; i++)
{
pl[i] = path + dis.readUTF();
}
}
else
{
for(int i = 0; i < pl.length; i++)
{
pl[i] = dis.readUTF();
}
}
return pl;
}
}

View File

@ -0,0 +1,101 @@
package com.one;
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.io.file.*;
import java.util.Vector;
import java.util.Enumeration;
import com.vmx.*;
import filemanager.filesystem;
import javax.microedition.lcdui.Gauge;
/**
* Ïîòîê ñîçäàíèÿ ñïèñêà âîñïðîèçâåäåíèÿ
*/
public class PlayListGenerator implements Runnable
{
public String error;
public boolean interrupt;
protected String name;
protected Vector files;
protected int type;
protected boolean relPath;
protected ProgressCallback callback;
public PlayListGenerator(String listname, int listtype, boolean allowRelPath, Vector filelist, ProgressCallback cb)
{
error = null;
interrupt = false;
name = listname;
type = listtype;
relPath = allowRelPath;
files = filelist;
callback = cb;
}
public void run()
{
boolean usecb = callback != null;
if(usecb)
{
callback.setMax(files.size());
callback.setProgress(0);
}
Vector v = new Vector();
Enumeration e = files.elements();
String s = null;
if(e == null)
{
return;
}
while(e.hasMoreElements())
{
s = (String)e.nextElement();
if(filesystem.fileType(s) == type)
{
v.addElement(s);
}
if(usecb)
{
callback.progress(1);
}
}
if(usecb)
{
callback.setMax(Gauge.INDEFINITE);
callback.setProgress(Gauge.CONTINUOUS_RUNNING);
}
try
{
FileConnection fc = (FileConnection)Connector.open("file:///" + name);
if(fc.exists() && fc.isDirectory())
{
fc.delete();
}
if(!fc.exists())
{
fc.create();
}
PlayListFile.writePlayList(v, name.substring(0, name.lastIndexOf('/') + 1), relPath, fc.openOutputStream());
fc.close();
}
catch(Exception x)
{
error = x.toString();
}
}
}

115
src/com/one/RTEF.java Normal file
View File

@ -0,0 +1,115 @@
package com.one;
import java.io.*;
import com.vmx.ProgressCallback;
import filemanager.main;
/**
* Øèôðàòîð.
* Äëÿ øèôðîâàíèÿ èñïîëüçóåòñÿ ìåòîä ãàììèðîâàíèÿ ñ ïñåâäîñëó÷àéíûì êëþ÷îì.
*/
public class RTEF
{
private static final int MAX_SHIFT = 64;
private static final int SHIFT_STEP = 8;
protected Random 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 Random(((long)hash[0] << 32 | (long)hash[2]) ^ ((long)hash[1] << 16));
int offset = (hash[3] ^ hash[4]) % 0xFFFF;
for(int i = 0; i < offset; i++)
{
rnd.nextLong();
}
rnd.mark();
}
/**
* Ñîçäàíèå øèôðàòîðà ñ ïàðîëåì â âèäå ïàðàìåòðîâ ÃÑ×
*/
public RTEF(long key, int offset)
{
rnd = new Random(key);
for(int i = 0; i < offset; i++)
{
rnd.nextLong();
}
rnd.mark();
}
/**
* Øèôðîâàíèå ïîòîêà.
* Äëÿ êàæäîé îïåðàöèè øèôðîâàíèÿ èñïîëüçóåòñÿ îäèíàêîâàÿ ãàììà.
*/
public void crypt(InputStream is, OutputStream os, ProgressCallback callback) throws IOException
{
rnd.reset();
long k = rnd.nextLong();
int shift = 0;
byte[] buf = new byte[main.COPYBUFSIZE];
int buflen, i;
boolean usecb = callback != null;
while(is.available() > 0)
{
buflen = is.read(buf);
for(i = 0; i < buflen; i++)
{
buf[i] ^= (byte)((k >> shift) & 0xFF);
shift += SHIFT_STEP;
if(shift >= MAX_SHIFT)
{
k = rnd.nextLong();
shift = 0;
}
}
os.write(buf, 0, buflen);
if(usecb)
{
callback.progress(buflen);
}
}
}
}

94
src/com/one/Random.java Normal file
View File

@ -0,0 +1,94 @@
package com.one;
/**
* Ãåíåðàòîð ïñåâäîñëó÷àéíûõ ÷èñåë.
* Èñïîëüçóåò àëãîðèòì Äæîðäæà Ìàðñàãëèè - "Xorshift 128".
* Ïî ôóíêöèîíàëüíîñòè èäåíòè÷åí ñòàíäàðòíîìó ãåíåðàòîðó,
* íî ïðåâîñõîäèò åãî ïî êà÷åñòâó ïîëó÷àåìûõ ïîñëåäîâàòåëüíîñòåé.
*/
public class Random
{
protected static final long L253 = 1L << 53;
protected static final double D253 = (double)L253;
protected static final long L224 = 1L << 24;
protected static final float F224 = (float)L224;
protected static final long SEED1 = 362436069L;
protected static final long SEED2 = 521288629L;
protected static final long SEED3 = 88675123L;
protected long t, x, y, z, w;
protected long x1, y1, z1, w1;
public Random()
{
this(System.currentTimeMillis());
}
public Random(long seed)
{
setSeed(seed);
}
protected long next()
{
t = (x ^ (x << 11));
x = y;
y = z;
z = w;
w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
return w;
}
public double nextDouble()
{
return (next() & L253) / D253;
}
public float nextFloat()
{
return (next() & L224) / F224;
}
public int nextInt()
{
return (int)(next() % 0xFFFFFFFFL);
}
public int nextInt(int n)
{
return nextInt() % n;
}
public long nextLong()
{
return next();
}
public void setSeed(long seed)
{
x = seed;
y = SEED1;
z = SEED2;
w = SEED3;
mark();
}
public void mark()
{
x1 = x;
y1 = y;
z1 = z;
w1 = w;
}
public void reset()
{
x = x1;
y = y1;
z = z1;
w = w1;
}
}

View File

@ -0,0 +1,123 @@
package com.one;
import java.io.*;
/**
* Âõîäíîé ïîòîê ñ ïðîèçâîëüíûì äîñòóïîì.
*/
public abstract class RandomAccessInputStream extends InputStream
{
/**
* Ïåðåõîä íà ïðîèçâîëüíóþ ïîçèöèþ
*/
public abstract void seek(int pos) throws IOException;
/**
* Òåêóùàÿ ïîçèöèÿ â ïîòîêå
*/
public abstract int tell() 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 = tell();
if(startIndex >= 0)
{
seek(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 = tell() - 1;
}
if(++i >= end)
{
break;
}
}
else if(b == data[off])
{
index = tell() - 1;
i = off;
}
else
{
index = -1;
i = off;
}
if(endIndex >= 0 && tell() >= endIndex)
{
break;
}
}
seek(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);
}
}

114
src/com/one/Renderer.java Normal file
View File

@ -0,0 +1,114 @@
package com.one;
import javax.microedition.lcdui.*;
public class Renderer extends Canvas
{
protected PaintableObject current;
protected boolean shown;
public Renderer()
{
setFullScreenMode(true);
current = new PaintableObject();
shown = false;
}
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)
{
if(current == po)
{
setFullScreenMode(mode);
}
}
public void paint(Graphics g)
{
current.paint(g);
}
public void showNotify()
{
current.showNotify();
shown = true;
}
public void hideNotify()
{
current.hideNotify();
shown = false;
}
public void keyPressed(int keyCode)
{
current.keyPressed(keyCode);
}
public void keyRepeated(int keyCode)
{
current.keyRepeated(keyCode);
}
public void keyReleased(int keyCode)
{
current.keyReleased(keyCode);
}
public void pointerPressed(int x, int y)
{
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);
}
}

View File

@ -0,0 +1,265 @@
package com.one;
import java.io.*;
/**
* Ïîòîê ñ âîçìîæíîñòüþ çàìåíû ïðîèçâîëüíîãî ó÷àñòêà.
*/
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();
}
/**
* Óñòàíîâêà çàìåíû.
* Äàííûå â ïîòîêå ñî 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 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.seek(currpos);
currpos++;
return is.read();
}
else if(currpos < repbufend)
{
return ((int)repbuf[currpos++ - repstart]) & 0xFF;
}
else
{
is.seek(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.seek(currpos);
read = is.read(b, off, len);
currpos += read;
return read;
}
if(len > available())
{
len = available();
}
int temp;
while(len > 0)
{
if(currpos < repstart)
{
is.seek(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.seek(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 seek(int pos) throws IOException
{
if(pos == currpos)
{
return;
}
if(pos < 0)
{
pos = 0;
}
else if(pos > getCapacity())
{
pos = getCapacity();
}
currpos = pos;
}
public int tell()
{
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);
// }
}

206
src/com/one/SHA1.java Normal file
View File

@ -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 <i>blockSize</i> 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;
}
}

View File

@ -0,0 +1,53 @@
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 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));
}
}

View File

@ -0,0 +1,80 @@
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);
repaint();
serviceRepaints();
}
public void showNotify()
{
flag = true;
(new Thread(this)).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();
}
}
}

View File

@ -0,0 +1,679 @@
/**************************************\
* Áóôåðèçîâàííûé ââîä/âûâîä *
** **
* Áóôåðèçîâàííûé ïîòîê ââîäà *
* (c) 2005+, Vitali Filippov [VMX] *
* *
* BufDataInputStream.java *
* Created on 24 Oct 2005, 13:25 *
\**************************************/
package com.vmx;
import java.io.*;
import javax.microedition.io.*;
import com.one.RandomAccessInputStream;
/**
* Class for buffered data input.
* For documentation, see java.io.DataInput.
*/
public class BufDataInputStream extends RandomAccessInputStream implements DataInput
{
protected byte buffer[];
protected int bmax, blen, bpos;
protected int bstreampos;
protected int markedPos;
protected int capacity, is_available;
protected RandomAccessInputStream is;
/**
* Êîíñòðóêòîð.
* Èñïîëüçóåòñÿ áóôåð ñòàíäàðòíîãî ðàçìåðà (4 ÊÁ).
*/
public BufDataInputStream(RandomAccessInputStream iis) throws IOException
{
this(4096, iis);
}
/**
* Êîíñòðóêòîð.
* Èñïîëüçóåòñÿ áóôåð çàäàííîãî ðàçìåðà.
*/
public BufDataInputStream(int bufsize, RandomAccessInputStream iis) throws IOException
{
if(bufsize <= 0)
{
throw new IOException("Buffer size must be greater than 0");
}
bmax = bufsize;
bpos = blen = 0;
bstreampos = 0;
buffer = new byte[bmax];
is = iis;
capacity = is.getCapacity();
is_available = is.available();
is.mark(capacity + 0x100);
markedPos = -1;
}
/**
* Óñòàíîâèòü íîâûé áàçîâûé ïîòîê äëÿ ýòîãî áóôåðèçîâàííîãî ïîòîêà.
* Ïðè ýòîì áóôåð àâòîìàòè÷åñêè îáíîâëÿåòñÿ.
*/
public void setInputStream(RandomAccessInputStream iis) throws IOException
{
is = iis;
capacity = is.getCapacity();
is.seek(bstreampos);
bufferize();
}
/**
* Çàêðûòèå áóôåðèçîâàííîãî ïîòîêà âìåñòå ñ òåì, íà êîòîðîì
* îí îñíîâàí.
*/
public void close() throws IOException
{
is.close();
}
/**
* Âîçâðàùàåò êîëè÷åñòâî áàéò, êîòîðûå åù¸ âîçìîæíî ïðî÷åñòü èç
* ýòîãî áóôåðèçîâàííîãî ïîòîêà.
*/
public int available()
{
return blen - bpos + is_available;
}
/**
* Ïîëó÷èòü îáú¸ì ïîòîêà
*/
public int getCapacity()
{
return capacity;
}
/**
* Ïåðåéòè ê ïîëîæåíèþ pos
*/
public void seek(int pos) throws IOException
{
//out(bstreampos + " <= " + pos + " < " + (bstreampos + blen));
if(pos >= bstreampos && pos < bstreampos + blen)
{
bpos = pos - bstreampos;
}
else
{
is.seek(pos);
bufferize();
}
}
/**
* Âîçâðàùàåò òåêóùóþ ïîçèöèþ â áóôåðèçîâàííîì ïîòîêå.
*/
public int tell()
{
return capacity - available();
}
/**
* Ñòàâèò ìåòêó, íà êîòîðóþ âîçâðàùàòüñÿ ïîòîì ìîæíî ïî reset.
*/
public void mark(int readlimit)
{
markedPos = tell();
}
/**
* Âîçâðàùàåò, äîñòóïíû ëè ôóíêöèè mark() è reset()?
*/
/*
public boolean markSupported()
{
return markSupp; // <- ìîæåò âåðíóòü false, õîòÿ ïî ëîãèêå çäåñü ó íàñ true
//return true;
}
*/
/**
* Ïåðåéòè íà ïîñëåäíþþ çàäàííóþ mark'îì ïîçèöèþ.
*/
public void reset() throws IOException
{
if(markedPos >= 0)
{
seek(markedPos);
}
else
{
throw new IOException("call mark() before reset()");
}
}
/**
* ïðîïóñòèòü n áàéò
*/
public long skip(long n) throws IOException
{
if(n < blen - bpos)
{
bpos += n;
return n;
}
else
{
long act = blen - bpos;
n -= blen - bpos;
act += is.skip(n);
bufferize();
return act;
}
}
/**
* Ïðî÷èòàòü ìàññèâ èç ïîòîêà: ïðî÷èòàòü è çàïèñàòü ìàêñèìóì len áàéò,
* çàïèñàòü èõ â b[], íà÷èíàÿ ñî ñìåùåíèÿ off, è âåðíóòü êîëè÷åñòâî
* ñ÷èòàííûõ áàéò.
*/
public int read(byte[] b, int off, int len) throws IOException
{
int rest = len, pos = off, n;
while(rest > 0)
{
if(bpos >= blen && bufferize() <= 0) // äàííûå êîí÷èëèñü?
{
blen = 0;
break;
}
// åñëè áóôåð êîí÷èëñÿ, à bufferize çàïîëíèëî åãî ÷åì-òî - áóäåò îê
n = rest;
if(n > blen - bpos)
{
n = blen - bpos;
}
System.arraycopy(buffer, bpos, b, pos, n);
pos += n;
bpos += n;
rest -= n;
}
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(bpos >= blen && bufferize() <= 0) // äàííûå êîí÷èëèñü?
{
return -1;
}
return ((int)buffer[bpos++]) & 0xFF;
}
/**
* Ïðî÷èòàòü 1 áàéò èç ïîòîêà íàçàä, åñëè íà÷àëî ôàéëà - âåðíóòü -1.
* Äëÿ ðàáîòû òðåáóåòñÿ ïîääåðæêà mark() è reset()
*/
public int readBack() throws IOException
{
if(bpos == 0)
{
if(available() == capacity)
{
return -1;
}
int old = tell();
bstreampos -= bmax;
if(bstreampos < 0)
{
bstreampos = 0;
}
is.seek(bstreampos);
bufferize();
bpos = old - bstreampos;
}
return ((int)buffer[--bpos]) & 0xFF;
}
/**
* Åñëè áóôåð íå ïîëîí, äî÷èòàòü è äîïîëíèòü åãî.
*/
public void flush() throws IOException
{
if(is_available > 0)
{
if(bpos != 0 && bpos != blen)
{
System.arraycopy(buffer, bpos, buffer, 0, blen - bpos);
}
blen -= bpos;
bstreampos += bpos;
bpos = 0;
int blenp = is.read(buffer, blen, bmax - blen);
blen += blenp;
is_available -= blenp;
}
}
/**
* Óáèâàåò òåêóùèé áóôåð è áóôåðèçóåò ñ òåêóùåãî ïîëîæåíèÿ InputStream'à
*/
protected int bufferize() throws IOException
{
is_available = is.available();
bstreampos = capacity - is_available;
blen = bpos = 0;
if(is_available > 0)
{
blen = is.read(buffer, 0, bmax);
is_available -= blen;
}
return blen;
}
/**
* Îáíîâèòü ñîäåðæèìîå áóôåðà â ñîîòâåòñòâèè ñ ïîòîêîì
*/
protected void updateBuffer() throws IOException
{
capacity = is.getCapacity(); // ïîòîê ìîæåò áûòü ïåðåìåííîé äëèíû
is.seek(bstreampos);
bufferize();
}
/**
* Îáùåå îáíîâëåíèå ïîòîêà.
*/
public void update() throws IOException
{
int pos = tell();
is.update();
updateBuffer();
seek(pos);
}
/**
* Ïðî÷èòàòü áóëåâî çíà÷åíèå èç ïîòîêà (ñì. 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
{
String s = "";
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
{
String s = "";
for(int i = 0; i < count && available() > 0; i++)
{
s += readCharUTF();
}
return s;
}
/**
* Ïðîïóñòèòü â ïîòîêå ìàêñèìóì 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);
// }
}

View File

@ -0,0 +1,163 @@
/*
* BufDataOutputStream.java
*
* Created on 24 Îêòÿáðü 2005 ã., 14:26
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package com.vmx;
import java.io.*;
import javax.microedition.io.*;
/**
*
* @author Âèòàëèé
*/
public class BufDataOutputStream implements DataOutput
{
final byte [] buffer;
int bmax, bpos;
OutputStream os;
/** Creates a new instance of BufDataOutputStream */
public BufDataOutputStream (int bufsize, OutputStream oos) throws IOException
{
if (bufsize <= 0)
throw new IOException ("Buffer size must be greater than 0");
bmax = bufsize;
bpos = 0;
buffer = new byte [bmax];
os = oos;
}
public void close () throws IOException
{
flush ();
os.close ();
}
public void flush () throws IOException
{
os.write (buffer, 0, bpos);
bpos = 0;
}
public void write (byte [] b, int off, int len) throws IOException
{
int rest = len, n, pos = off;
while (rest > 0)
{
if (bpos >= bmax)
flush ();
n = rest;
if (n > bmax-bpos)
n = bmax-bpos;
System.arraycopy (b, pos, buffer, bpos, n);
pos += n;
bpos += n;
rest -= n;
}
}
public void write (byte [] b) throws IOException
{
write (b, 0, b.length);
}
public void write (int b) throws IOException
{
if (bpos >= bmax)
flush ();
buffer [bpos++] = (byte)b;
}
public void writeBoolean (boolean b) throws IOException
{
byte bb = 0;
if (b)
bb = 1;
write (bb);
}
public void writeByte (int v) throws IOException
{
write (v);
}
public void writeChar (int c) throws IOException
{
write ((c >> 8) & 0xFF);
write (c & 0xFF);
}
public void writeChars (String s) throws IOException
{
for (int i = 0; i < s.length (); i++)
writeChar (s.charAt (i));
}
public void writeDouble (double d) throws IOException
{
writeLong (Double.doubleToLongBits (d));
}
public void writeFloat (float f) throws IOException
{
writeInt (Float.floatToIntBits (f));
}
public void writeInt (int i) throws IOException
{
write ((i >> 24)&0xFF);
write ((i >> 16)&0xFF);
write ((i >> 8)&0xFF);
write ((i )&0xFF);
}
public void writeLong (long l) throws IOException
{
write ((int)((l >> 56)&0xFF));
write ((int)((l >> 48)&0xFF));
write ((int)((l >> 40)&0xFF));
write ((int)((l >> 32)&0xFF));
write ((int)((l >> 24)&0xFF));
write ((int)((l >> 16)&0xFF));
write ((int)((l >> 8)&0xFF));
write ((int)((l )&0xFF));
}
public void writeShort (int s) throws IOException
{
write ((s >> 8) & 0xFF);
write (s & 0xFF);
}
public void writeUTF (String s, boolean writeLength) throws IOException
{
flush ();
if (!writeLength)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream ();
DataOutputStream dos = new DataOutputStream (baos);
dos.writeUTF (s);
dos.flush ();
byte [] bytes = baos.toByteArray ();
os.write (bytes, 2, bytes.length-2);
dos.close ();
}
else
{
DataOutputStream dos = new DataOutputStream (os);
dos.writeUTF (s);
dos.flush ();
}
}
public void writeUTF (String s) throws IOException
{
writeUTF (s, true);
}
}

View File

@ -0,0 +1,209 @@
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[] splitString(String text, int maxStrWidth)
{
int afterspace;
int cut;
int strwidth;
int strstart, strend;
boolean wordWrap;
int i;
char c = 0;
Vector v = new Vector();
strstart = 0;
i = 0;
while(i < text.length())
{
afterspace = -1;
cut = 0;
strwidth = 0;
wordWrap = true;
while(strwidth < maxStrWidth)
{
/* áåðåì ñèìâîë */
if(i < text.length())
{
c = text.charAt(i++);
}
else
{
wordWrap = false;
break;
}
/* åñëè ýòî íå ñèìâîë êîíöà ñòðîêè è íå êîíåö ôàéëà,
òî äîáàâëÿåì åãî ê ñòðîêå è îáíîâëÿåì åå äëèíó.
 ïðîòèâíîì ñëó÷àå ñîîáùàåì, ÷òî ïåðåíîñ ñëîâ íå òðåáóåòñÿ è âûõîäèì èç öèêëà */
if(c == '\n')
{
wordWrap = false;
break;
}
else
{
strwidth += charWidth(c);
}
if(c == ' ')
{
afterspace = 0;
}
else if(afterspace >= 0)
{
afterspace++;
}
}
if(wordWrap && afterspace >= 0)
{
cut += afterspace;
}
else if(strwidth > maxStrWidth && c != ' ')
{
cut = 1;
}
if(cut > 0)
{
i -= cut;
}
v.addElement(text.substring(strstart, i));
strstart = i;
}
if(strstart < i)
{
v.addElement(text.substring(strstart, i));
}
String[] res = new String[v.size()];
v.copyInto(res);
return res;
}
// private static void out(String s)
// {
// System.out.println("[FontWidthCache] " + s);
// }
}

View File

@ -0,0 +1,9 @@
package com.vmx;
import java.io.*;
public interface GenericFileConnection
{
public InputStream openInputStream () throws IOException;
public void close ();
}

View File

@ -0,0 +1,257 @@
package com.vmx;
import java.io.*;
import com.one.*;
import filemanager.main;
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(main.loader.getResourceAsStream(resname));
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();
}
}
return (char)-1;
}
/**
* Ñ÷èòàòü ñèìâîë íàçàä
*/
public char readCharBack() throws IOException
{
if(bdis.tell() > 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();
}
}
return (char)-1;
}
public int gotoLineNum(int linenum) throws IOException
{
bdis.seek(0);
detectEncoding(bdis, enc);
int currline = 1;
while(bdis.available() > 0 && currline < linenum)
{
if(readChar() == '\n')
{
currline++;
}
}
return bdis.tell();
}
/**
* Ïîèñê òåêñòà â ïîòîêå.
* Åñëè startIndex >= 0, òî ïîèñê âåäåòñÿ ñî startIndex, èíà÷å ñ òåêóùåé ïîçèöèè.
* Åñëè endIndex >= 0, òî ïîèñê èäåò ìàêñèìóì äî endIndex, èíà÷å äî êîíöà ïîòîêà.
* Åñëè ignoreCase = true, òî ïîèñê âåäåòñÿ áåç ó÷åòà ðåãèñòðà.
* Ïîñëå ïîèñêà ïîòîê âîçâðàùàåòñÿ íà ïðåæíþþ ïîçèöèþ.
*/
public int indexOf(String text, int startIndex, int endIndex, boolean ignoreCase) throws IOException
{
int prevpos = bdis.tell();
if(startIndex >= 0)
{
bdis.seek(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.tell() - 1;
}
if(++i >= end)
{
break;
}
}
else if(c == data[0])
{
index = bdis.tell() - 1;
i = 0;
}
else
{
index = -1;
i = 0;
}
if(endIndex >= 0 && bdis.tell() >= endIndex)
{
break;
}
}
bdis.seek(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);
// }
}

112
src/com/vmx/IntVector.java Normal file
View File

@ -0,0 +1,112 @@
package com.vmx;
public class IntVector
{
protected int[] array;
protected int count;
public final int arrplus;
public IntVector()
{
array = new int[0];
count = 0;
arrplus = 32;
}
public IntVector(int capacity)
{
array = new int[capacity];
count = 0;
arrplus = 32;
}
/**
* Óäàëèòü ýëåìåíòû ñ 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];
}
}
}
/**
* Äîáàâèòü â array çíà÷åíèå n
*/
public void add(int el)
{
if(count >= array.length)
{
int[] newarray = new int[array.length + arrplus];
System.arraycopy(array, 0, newarray, 0, array.length);
array = newarray;
}
array[count++] = el;
}
/**
* Ïîëó÷èòü ýëåìåíò íîìåð 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);
}
}

View File

@ -0,0 +1,95 @@
package com.vmx;
import java.io.*;
import com.one.*;
import filemanager.main;
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 close() throws IOException
{
os.close();
}
// private static void out(String s)
// {
// System.out.println("[OutputStreamEncoder] " + s);
// }
}

View File

@ -0,0 +1,9 @@
package com.vmx;
public interface ProgressCallback
{
public void setMax(int max);
public void setProgress(int progress);
public void progress(int plus);
public void setText(String text);
}

View File

@ -0,0 +1,337 @@
package com.vmx;
import java.io.*;
import java.util.Vector;
import filemanager.main;
import com.one.*;
public class StringEncoder
{
/** Òàáëèöû êîäèðîâîê */
protected static char[][] codepage;
/** Íàçâàíèÿ êîäèðîâîê */
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 StringEncoder()
{
}
/**
* Çàãðóçèòü êîäîâûå òàáëèöû
*/
public static void loadCodePages() throws IOException
{
Vector v = new Vector();
String defenc = null;
RandomAccessInputStream is = new BufferedInputStream(main.loader.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);
IniFile ini = new IniFile(isd);
IniRecord record = null;
while((record = ini.getNextRecord()) != null)
{
if(defenc == null && record.key.equals("DEFAULT"))
{
defenc = record.value;
}
else
{
v.addElement(record);
}
}
ini.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
{
dis = new DataInputStream(main.loader.getResourceAsStream("/enc/" + encodings[i] + ".enc"));
for(int j = 0; j < 128; j++)
{
codepage[i][j] = dis.readChar();
}
dis.close();
}
catch(Exception e)
{
main.showErrMsg(39, e);
}
}
if(defenc != null)
{
ENC_DEFAULT = findEncoding(defenc);
}
}
/**
* Êîäèðîâàòü ñòðîêó s â êîäèðîâêó enc
*/
public static byte[] encodeString(String s, int enc)
{
if(enc >= 0)
{
byte[] bs = new byte[s.length()];
for(int i = 0; i < s.length(); i++)
{
bs[i] = (byte)encodeChar(s.charAt(i), enc);
}
return bs;
}
else if(enc == ENC_UTF8)
{
try
{
return s.getBytes("UTF-8");
}
catch(UnsupportedEncodingException x)
{
main.showErrMsg(40, x);
return null;
}
}
else if(enc == ENC_UTF16N)
{
byte[] bs = new byte[s.length() * 2];
char c;
for(int i = 0; i < s.length(); i++)
{
c = s.charAt(i);
bs[i * 2] = (byte)(c >>> 8);
bs[i * 2 + 1] = (byte)(c & 0xFF);
}
return bs;
}
else if(enc == ENC_UTF16L)
{
byte[] bs = new byte[s.length() * 2];
char c;
for(int i = 0; i < s.length(); i++)
{
c = s.charAt(i);
bs[i * 2] = (byte)(c & 0xFF);
bs[i * 2 + 1] = (byte)(c >>> 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)
{
main.showErrMsg(41, x);
return -1;
}
}
else if(enc == ENC_UTF16N || enc == ENC_UTF16L)
{
return s.length() * 2;
}
return -1;
}
/**
* Äåêîäèðîâàòü ó÷àñòîê ìàññèâà b äëèíîé len ñî ñìåùåíèÿ off èç êîäèðîâêè enc
*/
public static String decodeString(byte[] bs, int off, int len, int enc)
{
if(enc >= 0)
{
String s = "";
for(int i = 0; i < len; i++)
{
s += decodeChar(bs[off + i], enc);
}
return s;
}
else if(enc == ENC_UTF8)
{
try
{
return new String(bs, off, len, "UTF-8");
}
catch(UnsupportedEncodingException x)
{
main.showErrMsg(42, x);
return null;
}
}
else if(enc == ENC_UTF16N)
{
String s = "";
if(len % 2 != 0)
{
len--;
}
for(int i = off; i < off + len; i += 2)
{
s += (char)(((char)bs[i] << 8) | bs[i + 1]);
}
return s;
}
else if(enc == ENC_UTF16L)
{
String s = "";
if(len % 2 != 0)
{
len--;
}
for(int i = off; i < off + len; i += 2)
{
s += (char)(((char)bs[i + 1] << 8) | bs[i]);
}
return s;
}
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
{
for(int i = 0; i < 128; i++)
{
if(ch == codepage[enc][i])
{
return i + 128;
}
}
return (int)' '; //0x3F; // '?' - íåèçâåñòíûé ñèìâîë
}
}
/**
* Ïåðåêîäèðîâàòü äàííûå èç ïîòîêà is èç êîäèðîâêè srcenc
* â ïîòîê os â êîäèðîâêó dstenc
*/
public static void transcode(InputStream is, OutputStream os, int srcenc, int dstenc) throws IOException
{
if(srcenc >= 0 && dstenc >= 0)
{
while(is.available() > 0)
{
os.write(encodeChar(decodeChar(is.read(), srcenc), dstenc));
}
}
}
/**
* Ïîëó÷èòü íîìåð êîäèðîâêè enc
*/
public static int findEncoding(String enc)
{
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);
// }
}

177
src/com/vmx/gkcCanvas.java Normal file
View File

@ -0,0 +1,177 @@
/*
* gkcCanvas.java
*
* Get Key Codes canvas
* (c) 2006, Âèòàëèé Ôèëèïïîâ [VMX]
*/
package com.vmx;
import filemanager.main;
import java.util.Vector;
import com.one.*;
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_BACK, KEY_CLEAR, KEY_DIAL, KEY_CANCEL;
public static final int KEY_INVALID = 0;
public static final int KEY_HELD = 0x80000000;
public static String[] platforms;
public static int[][] keycodes;
public static final int KEYS_COUNT = 11;
public static int getDisplayWidth()
{
return getRenderer().getWidth();
}
public static int getDisplayHeight()
{
return getRenderer().getHeight();
}
// public Canvas getRenderer()
// {
// return this;
// }
public gkcCanvas()
{
}
public static void readKeyMapList()
{
Vector vplatform = new Vector();
Vector vcode = new Vector();
try
{
IniFile ini = new IniFile("/config/keymap.ini");
IniRecord record = null;
int[] array;
String s;
int index;
while((record = ini.getNextRecord()) != null)
{
try
{
vplatform.addElement(record.key);
s = record.value;
array = new int[KEYS_COUNT];
for(int i = 0; i < KEYS_COUNT; i++)
{
index = s.indexOf(',');
if(index > 0)
{
array[i] = Integer.parseInt(s.substring(0, index).trim());
s = s.substring(index + 1);
}
else
{
array[i] = Integer.parseInt(s.trim());
}
}
vcode.addElement(array);
}
catch(Exception e)
{
}
}
ini.close();
}
catch(Exception e)
{
main.showErrMsg(0, e);
}
platforms = new String[vplatform.size()];
vplatform.copyInto(platforms);
keycodes = new int[vcode.size()][];
vcode.copyInto(keycodes);
}
public static void setKeyMap(int plindex)
{
if(plindex < 0 || plindex >= keycodes.length)
{
return;
}
/* ïëàòôîðìî - íåçàâèñèìûå êîäû */
//KEY_LEFT = tc.getKeyCode(LEFT);
//KEY_RIGHT = tc.getKeyCode(RIGHT);
//KEY_UP = tc.getKeyCode(UP);
//KEY_DOWN = tc.getKeyCode(DOWN);
//KEY_FIRE = tc.getKeyCode(FIRE);
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];
/* ïëàòôîðìî - çàâèñèìûå êîäû */
KEY_LSK = keycodes[plindex][5];
KEY_RSK = keycodes[plindex][6];
KEY_DIAL = keycodes[plindex][7];
KEY_CANCEL = keycodes[plindex][8];
KEY_BACK = keycodes[plindex][9];
KEY_CLEAR = keycodes[plindex][10];
}
/**
* Óñòàíàâëèâàåì âåçäå àâòîìàòè÷åñêóþ
* îáðàáîòêó ïîâòîðåíèé êàê íàæàòèé.
*/
protected void keyRepeated(int keyCode)
{
keyPressed(keyCode);
}
/**
* Ïðîâåðêà, ÿâëÿåòñÿ ëè íàæàòàÿ êëàâèøà öèôðîâîé.
*/
public static boolean isKeyNum(int keyCode)
{
keyCode &= ~KEY_HELD;
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;
}
}
}

14
src/config/ext.ini Normal file
View File

@ -0,0 +1,14 @@
0 = .mid .amr .wav .aac .mp3 .imy .m4a .xmf .awb .midi .wma ; SOUND
1 = .jpg .jpe .gif .png .bmx .jpeg .wbmp .ico .bmp ; PICTURE
2 = .3gp .mp4 .m4v .wmv .rm ; VIDEO
3 = .j .txt .jad .log .ini .inf .cdf .xml .col .java .jcc ; TEXT
4 = .zip .jar .sdt .scs .nth ; ZIP
5 = .tmo .vcs .vnt ; TMO
6 = .mod .xm .s3m ; SOUND_MODULE
7 = .pak .res ; PAK
8 = .gz .gzip ; GZIP
9 = .apl ; AUDIO_PLAYLIST
10 = .vpl ; VIDEO_PLAYLIST
11 = .mcs .ths ; COLOR_SCHEME
12 = .tpl ; TEMPLATE
13 = .mvi ; VECTOR_PICTURE

3
src/config/keymap.ini Normal file
View File

@ -0,0 +1,3 @@
Siemens = -59, -60, -61, -62, -26, -1, -4, -11, -12, 0, 0
Sony Ericsson = -1, -2, -3, -4, -5, -6, -7, 0, 0, -10, -8
Motorola = -1, -6, -2, -5, -20, -21, -22, -10, 0, 0, 0

19
src/config/mime.ini Normal file
View File

@ -0,0 +1,19 @@
; 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

BIN
src/enc/cp1251.enc Normal file

Binary file not shown.

BIN
src/enc/cp1252.enc Normal file

Binary file not shown.

BIN
src/enc/cp437.enc Normal file

Binary file not shown.

BIN
src/enc/cp866.enc Normal file

Binary file not shown.

9
src/enc/enc.ini Normal file
View File

@ -0,0 +1,9 @@
Windows Latin = cp1252
Windows Cyrillic = cp1251
DOS Latin = cp437
DOS Cyrillic = cp866
KOI-8 Russian = koi8r
; Internal resource encoding
; If not present, first one will be used
DEFAULT = cp1251

BIN
src/enc/koi8r.enc Normal file

Binary file not shown.

View File

@ -0,0 +1,78 @@
package filemanager;
import javax.microedition.sensor.*;
import javax.microedition.io.Connector;
import java.io.IOException;
public class Accelerometer
{
protected int[] channels = new int[3];
protected String[] channelNames = new String[3];
protected SensorConnection sensor;
public Accelerometer() throws ClassNotFoundException, IOException
{
Class asclass = null;
try
{
asclass = Class.forName("javax.microedition.sensor.SensorManager");
}
catch(Throwable t)
{
}
if(asclass == null)
{
throw new ClassNotFoundException();
}
SensorInfo[] info = SensorManager.findSensors("acceleration", null);
if(info == null || info.length == 0)
{
throw new ClassNotFoundException();
}
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());
}
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;
}
}

691
src/filemanager/Buffer.java Normal file
View File

@ -0,0 +1,691 @@
package filemanager;
import javax.microedition.lcdui.*;
import java.util.*;
import com.vmx.*;
import com.one.*;
class CopyMoveThread implements Runnable
{
public boolean interrupt = false;
protected ProgressCallback callback;
protected boolean usecb;
public CopyMoveThread(ProgressCallback cb)
{
interrupt = false;
callback = cb;
usecb = callback != null;
}
/**
* Ôóíêöèÿ ïîòîêà êîïèðîâàíèÿ/ïåðåìåùåíèÿ
*/
public void run()
{
if(usecb)
{
String[] files = Buffer.getBuffer();
long size = 0;
for(int i = 0; i < files.length; i++)
{
size += filesystem.getSize(files[i]);
}
callback.setMax((int)size);
}
// ïàïêà, êóäà êîïèðóåì/ïåðåìåùàåì
String targetPath = main.currentPath;
// ôàéë äëÿ îïåðàöèè
String sourceFileFullName;
String sourceOnlyName;
boolean mustMove;
boolean forAll = false, yes = false, fileExists = false;
while(Buffer.buf.size() > 0 && !interrupt)
{
mustMove = (Buffer.flags.get(Buffer.buf.size() - 1) & Buffer.FLAG_MOVE) != 0; // true, åñëè íàäî ïåðåìåùàòü!
sourceFileFullName = noLastSlash((String)Buffer.buf.elementAt(Buffer.buf.size() - 1)); // ïîñë ôàéë èç áóôåðà
sourceOnlyName = sourceFileFullName.substring(sourceFileFullName.lastIndexOf('/') + 1);
if(usecb)
{
callback.setText(sourceOnlyName);
}
fileExists = filesystem.isFileExist(targetPath + sourceOnlyName);
if(fileExists && !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;
main.dsp.setCurrent(Buffer.waitScreen);
}
if(!fileExists || yes)
{
if(!mustMove) // êîïèðîâàíèå
{
if(!filesystem.copyFile(sourceFileFullName, targetPath + sourceOnlyName, callback))
{
Buffer.errors += Locale.Strings[Locale.FILE] + " " + sourceOnlyName + " " + Locale.Strings[Locale.FILE_NOT_COPIED] + "\n\n";
}
}
else // ïåðåìåùåíèå
{
if(filesystem.copyFile(sourceFileFullName, targetPath + sourceOnlyName, callback)) // ñêîïèðîâàí?
{
if(filesystem.isReadOnly(sourceFileFullName)) // èñòî÷íèê readonly
{
Buffer.errors += sourceOnlyName + " " + Locale.Strings[Locale.SOURCE_FILE_READONLY_BE_COPIED] + "\n\n";
}
else
{
filesystem.deleteFile(sourceFileFullName, true, callback); // óäàëÿåì èñõîäíûé ôàéë
}
}
else // íå ïåðåìåùåí
{
Buffer.errors += Locale.Strings[Locale.FILE] + " " + sourceOnlyName + " " + Locale.Strings[Locale.FILE_NOT_MOVED] + "\n\n";
}
}
}
// óäàëèòü ïîñëåäíèé èç áóôåðà
Buffer.remove(Buffer.buf.size() - 1);
}
Buffer.waitScreen = null;
main.dsp.setCurrent(new alMessage(Buffer.errors));
}
/** Îáðåçàíèå ïîñëåäíåãî ñëýøà ó s */
public static String noLastSlash(String s)
{
if(s.charAt(s.length() - 1) == '/')
{
return s.substring(0, s.length() - 1);
}
return s;
}
}
/*
class GaugeCallback implements ProgressCallback
{
protected Gauge gg;
//protected StringItem si;
public GaugeCallback(Gauge assoc) // , StringItem text)
{
gg = assoc;
//si = text;
}
public void setMax(int max)
{
gg.setMaxValue(max);
}
public void setProgress(int progress)
{
gg.setValue(progress);
}
public void progress(int plus)
{
gg.setValue(gg.getValue() + plus);
}
public void setText(String text)
{
//si.setText(text + "\n");
}
}
*/
class WaitComLis implements CommandListener
{
public void commandAction(Command c, Displayable d)
{
Buffer.stopThread();
main.dsp.setCurrent(main.FileSelect);
}
}
class AfterburnThread implements Runnable
{
protected Thread t;
public AfterburnThread(Thread wait)
{
t = wait;
}
public void run()
{
if(t.isAlive())
{
try
{
t.join();
}
catch(Exception xx)
{
}
}
Buffer.clear();
if(Buffer.zz != null)
{
main.dsp.setCurrent(new alMessage(Buffer.zz.error));
Buffer.zz = null;
}
if(Buffer.gz != null)
{
if(Buffer.gzipTempFile != null)
{
filesystem.deleteFile(Buffer.gzipTempFile + Buffer.TEMP_EXT, false, null);
Buffer.gzipTempFile = null;
}
main.dsp.setCurrent(new alMessage(Buffer.gz.error));
Buffer.gz = null;
}
if(Buffer.pt != null)
{
main.dsp.setCurrent(new alMessage(Buffer.pt.error));
Buffer.pt = null;
}
if(Buffer.ct != null)
{
main.dsp.setCurrent(new alMessage(Buffer.ct.error));
Buffer.ct = null;
}
if(Buffer.plg != null)
{
main.dsp.setCurrent(new alMessage(Buffer.plg.error));
Buffer.plg = null;
}
if(Buffer.rr != null)
{
main.dsp.setCurrent(new alMessage(Buffer.rr.error));
Buffer.rr = null;
}
}
}
class MultiGZipThread implements Runnable
{
protected Thread t;
protected String s;
public MultiGZipThread(Thread wait)
{
t = wait;
}
public void run()
{
if(t.isAlive())
{
try
{
t.join();
}
catch(Exception e)
{
}
}
if(Buffer.pt != null)
{
Buffer.pt = null;
Buffer.clear();
Buffer.add(Buffer.gzipTempFile + Buffer.TEMP_EXT, Buffer.FLAG_NORMAL);
Buffer.gzipFiles(Buffer.gzipTempFile);
}
}
}
public class Buffer
{
public static final int FLAG_NORMAL = 0;
public static final int FLAG_MOVE = 1;
public static final int FLAG_INZIP = 2;
protected static Thread t = null;
public static String errors = "";
public static Object waitScreen = null;
public static ProgressCallback callback = null;
protected static WaitComLis wcl = null;
public static Vector buf = new Vector();
public static IntVector flags = new IntVector();
protected static IntVector hbuf = new IntVector();
public static Zipper zz = null;
public static GZipper gz = null;
public static PakThread pt = null;
public static CryptThread ct = null;
public static CopyMoveThread cmt = null;
public static PlayListGenerator plg = null;
public static Renamer rr = null;
public static String gzipTempFile = null;
public static final String TEMP_EXT = ".tmp";
/**
* Äîáàâèòü â áóôåð
*/
public static void add(String file, int flag)
{
add(file, flag, false);
}
/**
* Äîáàâèòü â áóôåð
* Åñëè flatten = true, òî ñòðóêòóðà ôàéëîâ
* èç äîáàâëÿåìûõ ïàïîê ðàçâîðà÷èâàåòñÿ
*/
private static void add(String file, int flag, boolean flatten)
{
if(flatten && filesystem.isDir(file))
{
String[] files = new String[0];
try
{
files = filesystem.listNoArchives(file, options.showHidden);
}
catch(Exception e)
{
}
for(int i = 0; i < files.length; i++)
{
add(file + files[i], flag, flatten);
}
}
else
{
int hash = file.hashCode();
int index = hbuf.find(hash);
if(index < 0)
{
buf.addElement(file);
hbuf.add(hash);
flags.add(flag);
}
else
{
flags.set(index, flag);
}
}
}
/**
* Ðàçâåðíóòü ôàéëîâóþ ñòðóêòóðó â áóôåðå,
* ÷òîáû òàì îñòàëèñü òîëüêî ôàéëû
*/
public static void flattenBuffer()
{
String[] tbuf = new String[buf.size()];
buf.copyInto(tbuf);
int[] tflags = new int[flags.size()];
flags.copyInto(tflags);
clear();
for(int i = 0; i < tbuf.length; i++)
{
add(tbuf[i], tflags[i], true);
}
}
/**
* Óäàëèòü èç áóôåðà
*/
public static void remove(int index)
{
buf.removeElementAt(index);
hbuf.remove(index, 1);
flags.remove(index, 1);
}
/**
* Î÷èñòèòü áóôåð
*/
public static void clear()
{
buf.removeAllElements();
hbuf.remove(0, hbuf.size());
flags.remove(0, flags.size());
}
/**
* Âåðíóòü áóôåð êàê ìàññèâ ñòðîê
*/
public static String[] getBuffer()
{
String bufs[] = new String[buf.size()];
buf.copyInto(bufs);
return bufs;
}
/**
* Çàïóñòèòü ïîòîê êîïèðîâàíèÿ/ïåðåìåùåíèÿ
*/
public static void copyMoveFiles()
{
errors = "";
if(buf.size() > 0)
{
createWait();
//Gauge gg = new Gauge(null, false, 1, 0);
//waitAlert.setIndicator(gg);
//waitForm.append(gg);
//GaugeCallback callback = new GaugeCallback(gg);
main.dsp.setCurrent(waitScreen);
stopThread();
cmt = new CopyMoveThread(callback);
t = new Thread(cmt);
t.start();
}
}
public static void renameFiles(String template)
{
errors = "";
if(buf.size() > 0)
{
createWait();
main.dsp.setCurrent(waitScreen);
callback.setMax(Gauge.INDEFINITE);
callback.setProgress(Gauge.CONTINUOUS_RUNNING);
flattenBuffer();
stopThread();
rr = new Renamer(template, buf, callback);
t = new Thread(rr);
t.start();
Thread t2 = new Thread(new AfterburnThread(t));
t2.start();
}
}
public static void createPlayList(String name, int type, boolean allowRelPath)
{
errors = "";
if(buf.size() > 0)
{
createWait();
main.dsp.setCurrent(waitScreen);
callback.setMax(Gauge.INDEFINITE);
callback.setProgress(Gauge.CONTINUOUS_RUNNING);
flattenBuffer();
stopThread();
plg = new PlayListGenerator(name, type, allowRelPath, buf, callback);
t = new Thread(plg);
t.start();
Thread t2 = new Thread(new AfterburnThread(t));
t2.start();
}
}
/**
* Çàïóñòèòü ïîòîê ñæàòèÿ ôàéëîâ
*/
public static void zipFiles(String zipfile, String path, int zipLevel)
{
errors = "";
if(buf.size() > 0)
{
createWait();
main.dsp.setCurrent(waitScreen);
stopThread();
zz = new Zipper(zipfile, zipLevel, buf, path, callback);
t = new Thread(zz);
t.start();
Thread t2 = new Thread(new AfterburnThread(t));
t2.start();
}
}
/**
* Çàïóñòèòü ïîòîê ñîçäàíèÿ PAK ôàéëà
*/
public static void pakFiles(String pakName)
{
errors = "";
if(buf.size() > 0)
{
createWait();
main.dsp.setCurrent(waitScreen);
callback.setMax(Gauge.INDEFINITE);
callback.setProgress(Gauge.CONTINUOUS_RUNNING);
flattenBuffer();
stopThread();
pt = new PakThread(pakName, buf, callback);
t = new Thread(pt);
t.start();
Thread t2 = new Thread(new AfterburnThread(t));
t2.start();
}
}
public static void gzipFiles(String gzipName)
{
errors = "";
if(buf.size() == 0)
{
return;
}
createWait();
main.dsp.setCurrent(waitScreen);
callback.setMax(Gauge.INDEFINITE);
callback.setProgress(Gauge.CONTINUOUS_RUNNING);
flattenBuffer();
stopThread();
if(buf.size() > 1)
{
// â GZIP áîëüøå 1 ôàéëà íå âëåçåò,
// òàê ÷òî ñíà÷àëà óïàêîâûâàåì â PAK
gzipTempFile = gzipName;
pt = new PakThread(gzipName + TEMP_EXT, buf, callback);
t = new Thread(pt);
t.start();
Thread t2 = new Thread(new MultiGZipThread(t));
t2.start();
}
else
{
gz = new GZipper(gzipName, (String)buf.elementAt(0), callback);
t = new Thread(gz);
t.start();
Thread t2 = new Thread(new AfterburnThread(t));
t2.start();
}
}
/**
* Çàïóñòèòü ïîòîê øèôðîâàíèÿ ôàéëîâ
*/
public static void cryptFiles(String password)
{
errors = "";
if(buf.size() > 0)
{
createWait();
main.dsp.setCurrent(waitScreen);
callback.setMax(Gauge.INDEFINITE);
callback.setProgress(Gauge.CONTINUOUS_RUNNING);
flattenBuffer();
stopThread();
ct = new CryptThread(password, buf, callback);
t = new Thread(ct);
t.start();
Thread t2 = new Thread(new AfterburnThread(t));
t2.start();
}
}
/**
* Ñîçäàòü waitAlert
*/
public static void createWait()
{
/*
waitScreen = new frmProgress(Locale.Strings[Locale.WAIT]);
waitScreen.addCommand(new Command(Locale.Strings[Locale.CANCEL_CMD], Command.CANCEL, 1));
waitScreen.setCommandListener(wcl = new WaitComLis());
callback = (ProgressCallback)waitScreen;
callback.setText(Locale.Strings[Locale.WAIT_PLEASE]);
*/
waitScreen = new cvsAlert(Locale.Strings[Locale.WAIT]);
((cvsAlert)waitScreen).setType(AlertType.WARNING);
((cvsAlert)waitScreen).setIndicator(true);
((cvsAlert)waitScreen).addCommand(new Command(Locale.Strings[Locale.CANCEL_CMD], Command.CANCEL, 1));
((cvsAlert)waitScreen).setCommandListener(wcl = new WaitComLis());
callback = (ProgressCallback)waitScreen;
callback.setText(Locale.Strings[Locale.WAIT_PLEASE]);
}
/**
* Îñòàíîâèòü ïðîöåññ
*/
public static void stopThread()
{
if(t != null)
{
if(zz != null)
{
zz.interrupt = true;
}
if(pt != null)
{
pt.interrupt = true;
}
if(gz != null)
{
gz.interrupt = true;
}
if(cmt != null)
{
cmt.interrupt = true;
}
if(t.isAlive())
{
try
{
t.join();
}
catch(Exception x)
{
}
}
t = null;
}
}
}

207
src/filemanager/Colors.java Normal file
View File

@ -0,0 +1,207 @@
package filemanager;
import java.io.*;
import com.one.*;
import com.vmx.*;
import java.util.Vector;
import javax.microedition.io.*;
import javax.microedition.lcdui.Image;
/**
* Êëàññ ñîäåðæèò öâåòîâóþ ñõåìó
*/
public class Colors
{
public static final byte BLOCK_BACK_IMAGE = 1,
BLOCK_CURSOR_MODE = 2,
BLOCK_CURSOR_IMAGE = 3,
BLOCK_ICONS_MODE = 4,
BLOCK_ICONS_PARAM = 5,
BLOCK_ICONS_IMAGE = 6,
BLOCK_SUBST_ICONS = 7,
BLOCK_WAIT_PARAM = 8,
BLOCK_WAIT_IMAGE = 9,
BLOCK_PLAYER_COLORS = 10,
BLOCK_PLAYER_BACK_IMAGE = 11,
BLOCK_PLAYER_UI_PARAM = 12,
BLOCK_PLAYER_UI_IMAGE = 13,
BLOCK_PLAYER_BUTTON_PARAM = 14,
BLOCK_PLAYER_BUTTON_IMAGE = 15,
BLOCK_PLAYER_ANIM_PARAM = 16,
BLOCK_PLAYER_ANIM_IMAGE = 17;
public static final int SCHEME_EDIT = -1;
public static final int SCHEME_EXTERNAL = -2;
public static String[] schemes;
public static int fore = 0xFF000080,
fore1 = 0xFF008000,
fore2 = 0xFFFF0000,
border = 0xFF000000,
disabled = 0xFF808080,
back1 = 0xFFD0D0D0,
back2 = 0xFFD0D0D0,
selfore = 0xFFFFFFFF,
selback1 = 0xFF000080,
selback2 = 0xFF000080;
public static Image backImage = null;
public static void readSchemeList()
{
Vector v = new Vector();
try
{
IniFile ini = new IniFile("/style/style.ini");
IniRecord record = null;
while((record = ini.getNextRecord()) != null)
{
v.addElement(record.value);
}
ini.close();
}
catch(Exception e)
{
main.showErrMsg(43, e);
}
schemes = new String[v.size()];
v.copyInto(schemes);
}
public static void loadColorScheme(int scheme) throws IOException
{
if(scheme < 0 || scheme >= schemes.length)
{
return;
}
readSchemeData(main.loader.getResourceAsStream("/style/" + schemes[scheme] + ".mcs"));
}
public static void loadExtColorScheme(String fname) throws IOException
{
readSchemeData(Connector.openInputStream("file:///" + fname));
}
public static void readSchemeData(InputStream is) throws IOException
{
DataInputStream dis = new DataInputStream(is);
byte[] sig = new byte[3];
dis.readFully(sig);
boolean mcsext = (sig[0] == (byte)0x4D) && (sig[1] == (byte)0x43) && (sig[2] == (byte)0x53); // MCS ñèãíàòóðà
fore = dis.readInt();
fore1 = dis.readInt();
fore2 = dis.readInt();
border = dis.readInt();
disabled = dis.readInt();
back1 = dis.readInt();
back2 = dis.readInt();
selfore = dis.readInt();
selback1 = dis.readInt();
selback2 = dis.readInt();
backImage = null;
if(mcsext)
{
int count = dis.readUnsignedShort();
for(int i = 0; i < count; i++)
{
switch(dis.readUnsignedByte())
{
case BLOCK_BACK_IMAGE:
int len = dis.readInt();
if(len > 0)
{
byte[] b = new byte[len];
dis.readFully(b);
backImage = ImageProcessor.scaleImage(Image.createImage(b, 0, b.length), gkcCanvas.getDisplayWidth(), gkcCanvas.getDisplayHeight());
}
break;
case BLOCK_CURSOR_MODE:
options.frameCursor = dis.readBoolean();
break;
case BLOCK_CURSOR_IMAGE:
dis.skip(dis.readInt());
break;
case BLOCK_ICONS_MODE:
options.iconsVista = dis.readBoolean();
images.loadIcons();
break;
case BLOCK_ICONS_PARAM:
dis.skip(4);
break;
case BLOCK_ICONS_IMAGE:
dis.skip(dis.readInt());
break;
case BLOCK_SUBST_ICONS:
dis.skip(dis.readShort() * 4);
break;
case BLOCK_WAIT_PARAM:
dis.skip(4);
break;
case BLOCK_WAIT_IMAGE:
dis.skip(dis.readInt());
case BLOCK_PLAYER_COLORS:
dis.skip(16);
break;
case BLOCK_PLAYER_BACK_IMAGE:
dis.skip(dis.readInt());
break;
case BLOCK_PLAYER_UI_PARAM:
dis.skip(14);
break;
case BLOCK_PLAYER_UI_IMAGE:
dis.skip(dis.readInt());
break;
case BLOCK_PLAYER_BUTTON_PARAM:
dis.skip(4);
break;
case BLOCK_PLAYER_BUTTON_IMAGE:
dis.skip(dis.readInt());
break;
case BLOCK_PLAYER_ANIM_PARAM:
dis.skip(4);
break;
case BLOCK_PLAYER_ANIM_IMAGE:
dis.skip(dis.readInt());
break;
default:
count = 0;
}
}
}
dis.close();
}
}

View File

@ -0,0 +1,102 @@
package filemanager;
import javax.microedition.lcdui.*;
import java.util.Vector;
import com.vmx.*;
public class ContextMenu implements MenuListener
{
protected cvsContextMenu mn;
public ContextMenu(cvsContextMenu menu)
{
mn = menu;
}
/**
* Îáðàáîò÷èê äëÿ ìåíþ
*/
public void menuAction(int string)
{
mn.ret();
if(main.dsp.getCurrent() == main.textEditor)
{
switch(string)
{
case Locale.SAVE_CMD:
if(main.textEditor.savePossible())
{
main.textEditor.saveEditText();
}
break;
case Locale.SAVE_AS_CMD:
main.textEditor.showSave();
break;
case Locale.EDIT_CMD:
if(main.textEditor.editPossible())
{
main.textEditor.editText();
}
break;
case Locale.UNDO_CMD:
if(main.textEditor.undoPossible())
{
main.textEditor.undo();
}
break;
case Locale.REDO_CMD:
if(main.textEditor.redoPossible())
{
main.textEditor.redo();
}
break;
case Locale.GOTO_CMD:
main.textEditor.showGoto();
break;
case Locale.GOTO_START_CMD:
main.textEditor.gotoStart();
break;
case Locale.GOTO_END_CMD:
main.textEditor.gotoEnd();
break;
case Locale.FIND_CMD:
main.textEditor.showFind();
break;
case Locale.FIND_NEXT_CMD:
main.textEditor.findNext(false);
break;
case Locale.FONT_CMD:
main.textEditor.showFont();
break;
case Locale.ENCODING_CMD:
if(main.textEditor.encPossible())
{
main.textEditor.showEncoding();
}
break;
case Locale.MINIMIZE_CMD:
try
{
main.dsp.setCurrent(null);
}
catch(Exception e)
{
}
break;
}
}
}
}

View File

@ -0,0 +1,100 @@
package filemanager;
import com.vmx.*;
import java.util.*;
import java.io.*;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import com.classpath.zip.*;
public class GZipper implements Runnable
{
protected String filename; // ÊÓÄÀ ïàêîâàòü
protected String file; // ×ÒÎ ïàêîâàòü
protected ProgressCallback callback;
public String error;
public boolean interrupt;
public GZipper(String fn, String f, ProgressCallback cb)
{
filename = fn;
file = f;
callback = cb;
error = null;
interrupt = false;
}
/**
* Êîïèðîâàòü ôàéë â ïîòîê
*/
protected void copyFileToStream(String fileName, OutputStream os, ProgressCallback callback) throws IOException
{
InputStream is = Connector.openInputStream("file:///" + fileName);
byte[] buf = new byte[main.COPYBUFSIZE];
int buflen;
while(is.available() > 0 && !interrupt)
{
os.write(buf, 0, buflen = is.read(buf));
if(callback != null)
{
callback.progress(buflen);
}
}
is.close();
}
/**
* Ôóíêöèÿ, îñóùåñòâëÿþùàÿ ñîáñòâåííî ñîçäàíèå GZIP ôàéëà
*/
public void run()
{
FileConnection fc = null;
try
{
fc = (FileConnection)Connector.open("file:///" + filename);
if(fc.exists() && fc.isDirectory())
{
fc.delete();
}
if(!fc.exists())
{
fc.create();
}
GZIPOutputStream gzos = new GZIPOutputStream(fc.openOutputStream());
if(callback != null)
{
callback.setMax((int)filesystem.getSize(file));
callback.setProgress(0);
}
copyFileToStream(file, gzos, callback);
gzos.close();
fc.close();
}
catch(Exception x)
{
error = x.toString(); // x.getClass().getName() + ": " + x.getMessage();
if(fc != null)
{
try
{
fc.close();
}
catch(Exception xx)
{
}
}
}
}
}

246
src/filemanager/Locale.java Normal file
View File

@ -0,0 +1,246 @@
package filemanager;
import java.io.*;
import java.util.Vector;
import java.util.Hashtable;
import com.vmx.*;
import com.one.*;
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, PATH_NOT_EXIST = 14,
CONFIRMATION = 15, DEL_RECORD_FAVOR = 16, DEL_ALL_FAVOR = 17,
YES_CMD = 18, NO_CMD = 19, SAVE_CMD = 20, CLEAR_CMD = 21,
ERROR = 22, FILE_NAME_EXIST = 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, MMC_INFO_CMD = 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, READ_ONLY = 52,
NOT_RENAMED = 53, PREF_SHOW_HIDDEN_FILES = 54, PREF_VISUAL = 55,
PREF_BROWSE = 56, PREF_ICONS_VISTA = 57, PREF_NO_SPLASH = 58,
PREF_SHOW_ERRORS = 59, CREATE_NEW_FOLDER = 60, CREATE_NEW_FILE = 61,
NOT_CREATE_NEW_FOLDER = 62, WAIT_PLEASE = 63, WAIT = 64,
PLAYER_STOP = 65, PLAYER_PLAY = 66, PLAYER_PAUSE = 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, DEL_FROM_BUFFER = 82,
DEL_ALL_FROM_BUFFER = 83, OPERATION_OK = 84, FILE = 85,
FILE_NOT_SAVED = 86, BUFFER_EMPTY = 87, MARK_CMD = 88,
MARK_ALL_CMD = 89, DEMARK_ALL_CMD = 90, PREF_OPEN_NOT_SUPP = 91,
PREF_USE_ALERT_ICONS = 92, FILE_TOO_BIG = 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, OVERWRITE_QUESTION = 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, EDIT_ID3_CMD = 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_FILE_CMD = 133, NEXT_FILE_CMD = 134, UP_LEVEL_CMD = 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, PREF_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, KEY_BACK = 158, KEY_CLEAR = 159, PREF_PLAYER_SETUP = 160,
PREF_PLAY_USE_ID3 = 161, PREF_SHOW_PLAY_PROGRESS = 162, PREF_PLAY_TEMP = 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,
PREF_EDIT_COLOR_SCHEME = 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_EXT_COLOR_SCHEME = 203, CREATE_PLAYLIST = 204,
PREF_ARCHIVE_ENCODING = 205, AUDIO = 206, VIDEO = 207,
PATH_SAVE = 208, PATH_ABSOLUTE = 209, PATH_RELATIVE = 210, COLOR_INFO = 211 /*[+0..9]*/,
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, TRANSCODE_IMPOSSIBLE = 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;
public static String ABOUT_MIDLET_NAME = "SieFM v" + main.loader.getAppProperty("MIDlet-Version");
public static String[] Strings;
public static final int STRING_COUNT = 253;
public static String lang;
public static String[] locales = null; // èìåíà ÿçûêîâ òèïà "ru", "en"...
public static String[] languages = null; // íàçâàíèÿ ÿçûêîâ (ðóññêèé, english, ...)
private static final char cmin1 = (char)-1;
/**
* Êîíñòðóêòîð
*/
public Locale()
{
}
public static void loadLocale(String newlang) throws Exception
{
lang = newlang;
Strings = new String[STRING_COUNT];
for(int k = 0; k < STRING_COUNT; k++)
{
Strings[k] = "#" + Integer.toString(k);
}
IniFile ini = new IniFile("/lang/" + lang + "/strings.ini");
IniRecord record = null;
while((record = ini.getNextRecord()) != null)
{
try
{
Strings[Integer.parseInt(record.key)] = record.value;
}
catch(Exception e)
{
}
}
ini.close();
}
/**
* Ïîëó÷èòü ïîòîê ñ òåêñòîì about'à
*/
public static InputStream getAboutStream()
{
try
{
return main.loader.getResourceAsStream("/lang/" + lang + "/about.txt");
}
catch(Exception e)
{
main.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)
{
main.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)
{
main.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;
}
}

View File

@ -0,0 +1,9 @@
package filemanager;
public interface MenuListener
{
/**
* Âûïîëíèòü äåéñòâèå ñ íàçâàíèåì Locale.Strings[code]
*/
public void menuAction (int code);
}

View File

@ -0,0 +1,537 @@
package filemanager;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
import java.io.*;
import com.one.*;
/**
* Êëàññ óïðàâëåíèÿ ïàíåëÿìè.
* Íà ïàíåëÿõ ìîæåò áûòü íå òîëüêî FileSelect,
* íî è ïëååð, ïðîñìîòð òåêñòà è ò. ä.
*/
public class PanelManager
{
protected static final String panelsStoreName = "SieFM_panels";
protected static RecordStore panelsStore;
protected String[] currpath;
protected String[] currfile;
protected Object[] currdisp;
protected boolean[] implicit;
protected int[] associat;
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];
for(int i = 0; i < pcount; i++)
{
currpath[i] = "";
currfile[i] = "";
currdisp[i] = main.FileSelect;
associat[i] = -1;
}
currpanel = 0;
prevpanel = pcount > 1 ? currpanel + 1 : currpanel;
prevpanelreq = -1;
}
/**
* Ñîõðàíåíèå äàííûõ ïàíåëåé.
* Ñîõðàíÿåòñÿ òîëüêî ïóòü è èìÿ òåêóùåãî ôàéëà.
*/
public void savePanels()
{
if(panelsStore != null)
{
byte[] data = null;
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++)
{
if(currpath[i] == null)
{
currpath[i] = "";
}
if(currfile[i] == null)
{
currfile[i] = "";
}
dos.writeUTF(currpath[i]);
dos.writeUTF(currfile[i]);
}
dos.flush();
data = baos.toByteArray();
dos.close();
panelsStore.setRecord(1, data, 0, data.length);
}
catch(InvalidRecordIDException ridex)
{
// Çàïèñü #1 íå ñóùåñòâóåò, ñîçäàòü íîâóþ
try
{
panelsStore.addRecord(data, 0, data.length);
}
catch(RecordStoreException ex)
{
main.showErrMsg(83, ex);
}
}
catch(Exception ex)
{
main.showErrMsg(84, ex);
}
}
if(panelsStore != null)
{
try
{
panelsStore.closeRecordStore();
panelsStore = null;
}
catch(RecordStoreException ex)
{
main.showErrMsg(85, ex);
}
}
}
/**
* Âîññòàíîâèòü äàííûå ïàíåëåé.
*/
public void restorePanels()
{
try
{
panelsStore = RecordStore.openRecordStore(panelsStoreName, true);
}
catch(RecordStoreException ex)
{
panelsStore = null;
main.showErrMsg(86, ex);
}
if(panelsStore != null)
{
try
{
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(panelsStore.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();
}
catch(InvalidRecordIDException iride)
{
}
catch(Exception e)
{
main.showErrMsg(87, e);
}
}
}
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]);
}
}
/**
* Âîçâðàò ê FileSelect
*/
public void ret()
{
if(associat[currpanel] >= 0)
{
// åñëè ñ ýòîé ïàíåëüþ êàêàÿ-òî áûëà ñâÿçàíà,
// òî ïåðåõîäèì ê ñâÿçàííîé,
int nextpanel = associat[currpanel];
// à ýòó âîçâðàùàåì â èñõîäíîå ñîñòîÿíèå
associat[currpanel] = -1;
currpath[currpanel] = null;
currfile[currpanel] = null;
currdisp[currpanel] = main.FileSelect;
currpanel = nextpanel;
showPanel(currpanel);
}
else
{
setCurrent(main.FileSelect, currpanel);
}
}
/**
* Ïîêàçûâàåì ÷òî-íèáóäü íà çàäàííîé ïàíåëè
*/
public void setCurrent(Object dp, int panel)
{
if(dp != main.wait && dp != main.FileSelect)
{
deassociate(panel);
}
currdisp[panel] = dp;
if(panel == currpanel)
{
dsp.setCurrent(dp);
}
}
/**
* Ïîêàçûâàåì ÷òî-íèáóäü íà òåêóùåé ïàíåëè
*/
public void setCurrent(Object dp)
{
if(dp != main.wait && dp != main.FileSelect)
{
deassociate(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);
}
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);
}
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)
{
if(panel != currpanel)
{
associat[panel] = currpanel;
}
currpath[panel] = main.currentPath;
currfile[panel] = main.currentFile;
}
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] == null || "".equals(currpath[i])))
{
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);
// }
}

View File

@ -0,0 +1,289 @@
package filemanager;
import com.vmx.*;
import java.util.*;
import java.io.*;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
public class Renamer implements Runnable
{
protected String template;
protected Vector files;
protected ProgressCallback callback;
public String error;
public boolean interrupt;
protected int counter;
public Renamer(String template, Vector filelist, ProgressCallback cb)
{
this.template = template;
files = filelist;
callback = cb;
error = null;
interrupt = false;
counter = -1;
}
/**
* Ôóíêöèÿ, îñóùåñòâëÿþùàÿ ñîáñòâåííî ïåðåèìåíîâàíèå
*/
public void run()
{
FileConnection fc = null;
String path = null;
String name = null;
int index = -1;
boolean usecb = callback != null;
if(usecb)
{
callback.setMax(files.size());
callback.setProgress(0);
}
initState();
try
{
for(int i = 0; i < files.size() && !interrupt; i++)
{
name = (String)files.elementAt(i);
index = name.lastIndexOf('/') + 1;
path = name.substring(0, index);
name = name.substring(index);
if(usecb)
{
callback.setText(name);
}
fc = (FileConnection)Connector.open("file:///" + path + name);
fc.rename(getNewName(name));
fc.close();
if(usecb)
{
callback.progress(1);
}
}
}
catch(Exception x)
{
error = x.toString(); // x.getClass().getName() + ": " + x.getMessage();
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);
// }
}

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