WIP migrating to kotlin.

master
Robinson 2023-08-16 19:44:03 -05:00
parent fd7583023d
commit ada5ffddd5
No known key found for this signature in database
GPG Key ID: 8E7DB78588BD6F5C
31 changed files with 1168 additions and 1663 deletions

389
LICENSE
View File

@ -6,23 +6,21 @@
Parse and extract data from Microsoft LZX compressed .cab files for Java 8+
Extra license information
- ByteUtilties - Byte manipulation and Unsigned Number Utilities
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- ByteUtils - Byte manipulation and SHA/xxHash utilities
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/ByteUtilities
Copyright 2023
Dorkbox LLC
Extra license information
- Byte Utils (UByte, UInteger, ULong, Unsigned, UNumber, UShort) -
[The Apache Software License, Version 2.0]
https://github.com/jOOQ/jOOQ/tree/master/jOOQ/src/main/java/org/jooq/types
Copyright 2017
Data Geekery GmbH (http://www.datageekery.com)
Lukas Eder
Ed Schaller
Jens Nerche
Ivan Sokolov
- Kryo Serialization -
[BSD 3-Clause License]
https://github.com/EsotericSoftware/kryo
@ -73,7 +71,7 @@
- Objenesis -
[The Apache Software License, Version 2.0]
http://objenesis.org
https://github.com/easymock/objenesis
Objenesis Team and all contributors
- MinLog-SLF4J -
@ -81,6 +79,13 @@
https://github.com/EsotericSoftware/minlog
Nathan Sweet
- LZ4 and xxHash - LZ4 compression for Java, based on Yann Collet's work
[The Apache Software License, Version 2.0]
https://github.com/lz4/lz4
Copyright 2023
Yann Collet
Adrien Grand
- Updates - Software Update Management
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Updates
@ -125,23 +130,6 @@
Sean Luke
Michael Lecuyer (portions Copyright 1993
- FileUtil (code from FilenameUtils.java for normalize + dependencies) -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Utilities
http://commons.apache.org/proper/commons-io/
Copyright 2013
The Apache Software Foundation
Kevin A. Burton
Scott Sanders
Daniel Rall
Christoph.Reck
Peter Donald
Jeff Turner
Matthew Hawthorne
Martin Cooper
Jeremias Maerki
Stephen Colebourne
- FastThreadLocal -
[BSD 3-Clause License]
https://git.dorkbox.com/dorkbox/Utilities
@ -151,21 +139,6 @@
Lightweight Java Game Library Project
Riven
- Base64Fast -
[BSD 3-Clause License]
https://git.dorkbox.com/dorkbox/Utilities
http://migbase64.sourceforge.net/
Copyright 2004
Mikael Grev, MiG InfoCom AB. (base64@miginfocom.com)
- BCrypt -
[BSD 2-Clause "Simplified" or "FreeBSD" license]
https://git.dorkbox.com/dorkbox/Utilities
http://www.mindrot.org/projects/jBCrypt
Copyright 2006
Damien Miller (djm@mindrot.org)
GWT modified version
- Modified hex conversion utility methods -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Utilities
@ -181,7 +154,7 @@
- Resource Listing - Listing the contents of a resource directory
[The Apache Software License, Version 2.0]
http://www.uofr.net/~greg/java/get-resource-listing.html
https://www.uofr.net/~greg/java/get-resource-listing.html
Copyright 2017
Greg Briggs
@ -192,17 +165,12 @@
Pronghorn Technology LLC
Dorkbox LLC
- UrlRewriteFilter - UrlRewriteFilter is a Java Web Filter for any J2EE compliant web application server
[BSD 3-Clause License]
https://github.com/paultuckey/urlrewritefilter
Copyright 2022
Paul Tuckey
- kotlinx.coroutines - Library support for Kotlin coroutines with multiplatform support
- Kotlin Coroutine CountDownLatch -
[The Apache Software License, Version 2.0]
https://github.com/Kotlin/kotlinx.coroutines
Copyright 2023
JetBrains s.r.o.
https://github.com/Kotlin/kotlinx.coroutines/issues/59
https://github.com/venkatperi/kotlin-coroutines-lib
Copyright 2018
Venkat Peri
- Java Uuid Generator - A set of Java classes for working with UUIDs
[The Apache Software License, Version 2.0]
@ -211,12 +179,6 @@
Tatu Saloranta (tatu.saloranta@iki.fi)
Contributors. See source release-notes/CREDITS
- SLF4J - Simple facade or abstraction for various logging frameworks
[MIT License]
http://www.slf4j.org
Copyright 2023
QOS.ch
- XZ for Java - Complete implementation of XZ data compression in pure Java
[Public Domain, per Creative Commons CC0]
https://tukaani.org/xz/java.html
@ -224,6 +186,13 @@
Lasse Collin
Igor Pavlov
- Netty - An event-driven asynchronous network application framework
[The Apache Software License, Version 2.0]
https://netty.io
Copyright 2023
The Netty Project
Contributors. See source NOTICE
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
@ -232,127 +201,16 @@
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- Netty - An event-driven asynchronous network application framework
- kotlinx.coroutines - Library support for Kotlin coroutines with multiplatform support
[The Apache Software License, Version 2.0]
https://netty.io
https://github.com/Kotlin/kotlinx.coroutines
Copyright 2023
The Netty Project
Contributors. See source NOTICE
- Bouncy Castle Crypto - Lightweight cryptography API and JCE Extension
[The Apache Software License, Version 2.0]
http://www.bouncycastle.org
Copyright 2023
The Legion of the Bouncy Castle Inc
- Lightweight Java Game Library - Java library that enables cross-platform access to popular native APIs
[BSD 3-Clause License]
https://github.com/LWJGL/lwjgl3
Copyright 2023
Lightweight Java Game Library
- TypeTools - A simple, zero-dependency library for working with types. Supports Java 1.6+ and Android.
[The Apache Software License, Version 2.0]
https://github.com/jhalterman/typetools
Copyright 2023
Jonathan Halterman and friends
- Collections - Niche collections to augment what is already available.
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
Copyright 2022
Dorkbox LLC
Extra license information
- AhoCorasickDoubleArrayTrie - Niche collections to augment what is already available.
[The Apache Software License, Version 2.0]
https://github.com/hankcs/AhoCorasickDoubleArrayTrie
Copyright 2018
hankcs <me@hankcs.com>
- Bias, BinarySearch -
[MIT License]
https://git.dorkbox.com/dorkbox/Collections
https://github.com/timboudreau/util
Copyright 2013
Tim Boudreau
- ConcurrentEntry -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
Copyright 2016
bennidi
dorkbox
- Collection Utilities (Array, ArrayMap, BooleanArray, ByteArray, CharArray, FloatArray, IdentityMap, IntArray, IntFloatMap, IntIntMap, IntMap, IntSet, LongArray, LongMap, ObjectFloatMap, ObjectIntMap, ObjectMap, ObjectSet, OrderedMap, OrderedSet) -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
Copyright 2011
LibGDX
Mario Zechner (badlogicgames@gmail.com)
Nathan Sweet (nathan.sweet@gmail.com)
- Predicate -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
Copyright 2011
LibGDX
Mario Zechner (badlogicgames@gmail.com)
Nathan Sweet (nathan.sweet@gmail.com)
xoppa
- Select, QuickSelect -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
Copyright 2011
LibGDX
Mario Zechner (badlogicgames@gmail.com)
Nathan Sweet (nathan.sweet@gmail.com)
Jon Renner
- TimSort, ComparableTimSort -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
Copyright 2008
The Android Open Source Project
- ConcurrentWeakIdentityHashMap - Concurrent WeakIdentity HashMap
[The Apache Software License, Version 2.0]
https://github.com/spring-projects/spring-loaded/blob/master/springloaded/src/main/java/org/springsource/loaded/support/ConcurrentWeakIdentityHashMap.java
Copyright 2016
zhanhb
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- Updates - Software Update Management
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Updates
Copyright 2021
Dorkbox LLC
Extra license information
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
JetBrains s.r.o.
- Executor - Shell, JVM, and SSH command execution on Linux, MacOS, or Windows for Java 8+
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Executor
Copyright 2022
Copyright 2023
Dorkbox LLC
Extra license information
@ -379,25 +237,25 @@
- kotlinx.coroutines - Library support for Kotlin coroutines with multiplatform support
[The Apache Software License, Version 2.0]
https://github.com/Kotlin/kotlinx.coroutines
Copyright 2022
Copyright 2023
JetBrains s.r.o.
- SLF4J - Simple facade or abstraction for various logging frameworks
[MIT License]
http://www.slf4j.org
Copyright 2022
https://www.slf4j.org
Copyright 2023
QOS.ch
- Logback - Logback is a logging framework for Java applications
[The Apache Software License, Version 2.0]
http://logback.qos.ch
Copyright 2022
https://logback.qos.ch
Copyright 2023
QOS.ch
- SSHJ - SSHv2 library for Java
[The Apache Software License, Version 2.0]
https://github.com/hierynomus/sshj
Copyright 2022
Copyright 2023
Jeroen van Erp
SSHJ Contributors
@ -414,13 +272,13 @@
- JZlib -
[The Apache Software License, Version 2.0]
http://www.jcraft.com/jzlib
https://github.com/ymnk/jzlib
Atsuhiko Yamanaka
JCraft, Inc.
- Bouncy Castle Crypto -
[The Apache Software License, Version 2.0]
http://www.bouncycastle.org
https://www.bouncycastle.org
The Legion of the Bouncy Castle Inc
- ed25519-java -
@ -443,169 +301,6 @@
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- NetworkUtils - Utilities for managing network configurations, IP/MAC address conversion, and ping (via OS native commands)
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/NetworkUtils
Copyright 2022
Dorkbox LLC
Extra license information
- Netty -
[The Apache Software License, Version 2.0]
https://netty.io/
Copyright 2014
The Netty Project
This product contains a modified portion of Netty Network Utils
- Apache Harmony -
[The Apache Software License, Version 2.0]
http://archive.apache.org/dist/harmony/
Copyright 2010
The Apache Software Foundation
This product contains a modified portion of 'Apache Harmony', an open source Java SE
- Apache HTTP Utils -
[The Apache Software License, Version 2.0]
http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/psl/
Copyright 2010
The Apache Software Foundation
This product contains a modified portion of 'PublicSuffixDomainFilter.java'
- SLF4J - Simple facade or abstraction for various logging frameworks
[MIT License]
http://www.slf4j.org
Copyright 2022
QOS.ch
- JNA - Simplified native library access for Java.
[The Apache Software License, Version 2.0]
https://github.com/twall/jna
Copyright 2022
Timothy Wall
- JNA-Platform - Mappings for a number of commonly used platform functions
[The Apache Software License, Version 2.0]
https://github.com/twall/jna
Copyright 2022
Timothy Wall
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- Executor - Shell, JVM, and SSH command execution on Linux, MacOS, or Windows for Java 8+
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Executor
Copyright 2022
Dorkbox LLC
Extra license information
- ZT Process Executor -
[The Apache Software License, Version 2.0]
https://github.com/zeroturnaround/zt-exec
Copyright 2014
ZeroTurnaround LLC
- Apache Commons Exec -
[The Apache Software License, Version 2.0]
https://commons.apache.org/proper/commons-exec/
Copyright 2014
The Apache Software Foundation
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- kotlinx.coroutines - Library support for Kotlin coroutines with multiplatform support
[The Apache Software License, Version 2.0]
https://github.com/Kotlin/kotlinx.coroutines
Copyright 2022
JetBrains s.r.o.
- SLF4J - Simple facade or abstraction for various logging frameworks
[MIT License]
http://www.slf4j.org
Copyright 2022
QOS.ch
- Logback - Logback is a logging framework for Java applications
[The Apache Software License, Version 2.0]
http://logback.qos.ch
Copyright 2022
QOS.ch
- SSHJ - SSHv2 library for Java
[The Apache Software License, Version 2.0]
https://github.com/hierynomus/sshj
Copyright 2022
Jeroen van Erp
SSHJ Contributors
Extra license information
- Apache MINA -
[The Apache Software License, Version 2.0]
https://mina.apache.org/sshd-project/
The Apache Software Foundation
- Apache Commons-Net -
[The Apache Software License, Version 2.0]
https://commons.apache.org/proper/commons-net/
The Apache Software Foundation
- JZlib -
[The Apache Software License, Version 2.0]
http://www.jcraft.com/jzlib
Atsuhiko Yamanaka
JCraft, Inc.
- Bouncy Castle Crypto -
[The Apache Software License, Version 2.0]
http://www.bouncycastle.org
The Legion of the Bouncy Castle Inc
- ed25519-java -
[Public Domain, per Creative Commons CC0]
https://github.com/str4d/ed25519-java
https://github.com/str4d
- Updates - Software Update Management
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Updates
Copyright 2021
Dorkbox LLC
Extra license information
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- Updates - Software Update Management
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Updates
Copyright 2021
Dorkbox LLC
Extra license information
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- OS - Information about the system, Java runtime, OS, Window Manager, and Desktop Environment.
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/OS

View File

@ -1,22 +0,0 @@
BSD License
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <ORGANIZATION> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2021 dorkbox, llc
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -26,10 +26,12 @@ gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS // always show th
gradle.startParameter.warningMode = WarningMode.All
plugins {
id("com.dorkbox.GradleUtils") version "3.9"
id("com.dorkbox.Licensing") version "2.19.1"
id("com.dorkbox.VersionUpdate") version "2.5"
id("com.dorkbox.GradlePublish") version "1.17"
id("com.dorkbox.GradleUtils") version "3.17"
id("com.dorkbox.Licensing") version "2.25"
id("com.dorkbox.VersionUpdate") version "2.8"
id("com.dorkbox.GradlePublish") version "1.18"
kotlin("jvm") version "1.8.0"
}
object Extras {
@ -44,8 +46,6 @@ object Extras {
const val vendor = "Dorkbox LLC"
const val vendorUrl = "https://dorkbox.com"
const val url = "https://git.dorkbox.com/dorkbox/CabParser"
val buildDate = Instant.now().toString()
}
///////////////////////////////
@ -64,6 +64,19 @@ licensing {
}
}
// make java source available to kotlin
kotlin {
sourceSets {
main {
// we have some java we depend on
kotlin.include("**/*.java", "**/*.kt")
}
test {
kotlin.include("**/*.java", "**/*.kt")
}
}
}
tasks.jar.get().apply {
manifest {
// https://docs.oracle.com/javase/tutorial/deployment/jar/packageman.html
@ -74,15 +87,15 @@ tasks.jar.get().apply {
attributes["Specification-Vendor"] = Extras.vendor
attributes["Implementation-Title"] = "${Extras.group}.${Extras.id}"
attributes["Implementation-Version"] = Extras.buildDate
attributes["Implementation-Version"] = GradleUtils.now()
attributes["Implementation-Vendor"] = Extras.vendor
}
}
dependencies {
api("com.dorkbox:ByteUtilities:1.6")
api("com.dorkbox:ByteUtilities:1.13")
api("com.dorkbox:Updates:1.1")
api("com.dorkbox:Utilities:1.39")
api("com.dorkbox:Utilities:1.44")
}
publishToSonatype {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012 dorkbox, llc
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -13,15 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
package dorkbox.cabParser
public class CabException extends Exception {
private static final long serialVersionUID = 1L;
public CabException(String errorMessage) {
super(errorMessage);
}
public CabException() {
}
open class CabException : Exception {
constructor(errorMessage: String?) : super(errorMessage)
constructor()
}

View File

@ -1,142 +0,0 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
import java.io.IOException;
import java.io.InputStream;
final class CabInputStream extends InputStream {
private InputStream inputStream;
private long position;
private long a;
private boolean markSupported;
@Override
public void close() throws IOException {
this.inputStream.close();
}
@Override
public synchronized void reset() throws IOException {
if (this.markSupported) {
this.inputStream.reset();
this.position = this.a;
return;
}
throw new IOException();
}
CabInputStream(InputStream inputStream) {
this.inputStream = inputStream;
this.position = 0L;
this.markSupported = this.inputStream.markSupported();
}
@Override
public int read() throws IOException {
int i = this.inputStream.read();
if (i >= 0) {
this.position += 1L;
}
return i;
}
@Override
public int read(byte[] bytes) throws IOException {
int i = this.inputStream.read(bytes);
if (i > 0) {
this.position += i;
}
return i;
}
@Override
public int read(byte[] bytes, int offset, int length) throws IOException {
int i = this.inputStream.read(bytes, offset, length);
if (i > 0) {
this.position += i;
}
return i;
}
@Override
public int available() throws IOException {
throw new IOException();
}
@Override
public synchronized void mark(int paramInt) {
if (this.markSupported) {
this.a = this.position;
this.inputStream.mark(paramInt);
}
}
public long getCurrentPosition() {
return this.position;
}
@Override
public boolean markSupported() {
return this.markSupported;
}
public void seek(long location) throws IOException {
if (location < this.position) {
throw new IOException("Cannot seek backwards");
}
if (location > this.position) {
skip(location - this.position);
}
}
@Override
public long skip(long ammount) throws IOException {
long l = betterSkip(this.inputStream, ammount);
this.position += (int) l;
return l;
}
/**
* Reliably skips over and discards n bytes of data from the input stream
* @param is input stream
* @param n the number of bytes to be skipped
* @return the actual number of bytes skipped
* @throws IOException
*/
public static long betterSkip(InputStream is, long n) throws IOException {
long left = n;
while(left > 0) {
long l = is.skip(left);
if(l > 0) {
left -= l;
} else if(l == 0) { // should we retry? lets read one byte
if(is.read() == -1) // EOF
break;
else
left--;
} else {
throw new IOException("skip() returned a negative value. This should never happen");
}
}
return n - left;
}
}

View File

@ -0,0 +1,141 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser
import java.io.IOException
import java.io.InputStream
internal class CabInputStream(private val inputStream: InputStream) : InputStream() {
companion object {
/**
* Reliably skips over and discards n bytes of data from the input stream
* @param is input stream
* @param n the number of bytes to be skipped
* @return the actual number of bytes skipped
*
* @throws IOException
*/
@Throws(IOException::class)
fun betterSkip(`is`: InputStream, n: Long): Long {
var left = n
while (left > 0) {
val l = `is`.skip(left)
if (l > 0) {
left -= l
}
else if (l == 0L) { // should we retry? lets read one byte
if (`is`.read() == -1) // EOF
break
else left--
}
else {
throw IOException("skip() returned a negative value. This should never happen")
}
}
return n - left
}
}
var currentPosition = 0L
private set
private var a: Long = 0
private val markSupported: Boolean
init {
markSupported = inputStream.markSupported()
}
@Throws(IOException::class)
override fun close() {
inputStream.close()
}
@Synchronized
@Throws(IOException::class)
override fun reset() {
if (markSupported) {
inputStream.reset()
currentPosition = a
return
}
throw IOException()
}
@Throws(IOException::class)
override fun read(): Int {
val i = inputStream.read()
if (i >= 0) {
currentPosition += 1L
}
return i
}
@Throws(IOException::class)
override fun read(bytes: ByteArray): Int {
val i = inputStream.read(bytes)
if (i > 0) {
currentPosition += i.toLong()
}
return i
}
@Throws(IOException::class)
override fun read(bytes: ByteArray, offset: Int, length: Int): Int {
val i = inputStream.read(bytes, offset, length)
if (i > 0) {
currentPosition += i.toLong()
}
return i
}
@Throws(IOException::class)
override fun available(): Int {
throw IOException()
}
@Synchronized
override fun mark(paramInt: Int) {
if (markSupported) {
a = currentPosition
inputStream.mark(paramInt)
}
}
override fun markSupported(): Boolean {
return markSupported
}
@Throws(IOException::class)
fun seek(location: Long) {
if (location < currentPosition) {
throw IOException("Cannot seek backwards")
}
if (location > currentPosition) {
skip(location - currentPosition)
}
}
@Throws(IOException::class)
override fun skip(ammount: Long): Long {
val l = betterSkip(inputStream, ammount)
currentPosition += l.toInt().toLong()
return l
}
}

View File

@ -1,207 +0,0 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.File;
import java.util.Enumeration;
import dorkbox.cabParser.decompress.CabDecompressor;
import dorkbox.cabParser.structure.CabEnumerator;
import dorkbox.cabParser.structure.CabFileEntry;
import dorkbox.cabParser.structure.CabFolderEntry;
import dorkbox.cabParser.structure.CabHeader;
public final class CabParser {
/**
* Gets the version number.
*/
public static
String getVersion() {
return "3.2";
}
static {
// Add this project to the updates system, which verifies this class + UUID + version information
dorkbox.updates.Updates.INSTANCE.add(CabParser.class, "41f560ca51c04bfdbca21328e0cbf206", getVersion());
}
private CabInputStream cabInputStream;
private CabStreamSaver streamSaver;
private ByteArrayOutputStream outputStream = null;
public CabHeader header;
public CabFolderEntry[] folders;
public CabFileEntry[] files;
public
CabParser(InputStream inputStream, final String fileNameToExtract) throws CabException, IOException {
if (fileNameToExtract == null || fileNameToExtract.isEmpty()) {
throw new IllegalArgumentException("Filename must be valid!");
}
this.cabInputStream = new CabInputStream(inputStream);
this.streamSaver = new CabStreamSaver() {
@Override
public boolean saveReservedAreaData(byte[] data, int dataLength) {
return false;
}
@Override
public OutputStream openOutputStream(CabFileEntry cabFile) {
String name = cabFile.getName();
if (fileNameToExtract.equalsIgnoreCase(name)) {
CabParser.this.outputStream = new ByteArrayOutputStream((int) cabFile.getSize());
return CabParser.this.outputStream;
} else {
return null;
}
}
@Override
public void closeOutputStream(OutputStream outputStream, CabFileEntry cabFile) {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException ignored) {
}
}
}
};
readData();
}
public
CabParser(InputStream inputStream, CabStreamSaver streamSaver) throws CabException, IOException {
this.streamSaver = streamSaver;
this.cabInputStream = new CabInputStream(inputStream);
readData();
}
public
CabParser(InputStream inputStream, File extractPath) throws CabException, IOException {
this.streamSaver = new DefaultCabStreamSaver(extractPath);
this.cabInputStream = new CabInputStream(inputStream);
readData();
}
public Enumeration<Object> entries() {
return new CabEnumerator(this, false);
}
public Enumeration<Object> entries(boolean b) {
return new CabEnumerator(this, b);
}
private void readData() throws CabException, IOException {
this.header = new CabHeader(this.streamSaver);
this.header.read(this.cabInputStream);
this.folders = new CabFolderEntry[this.header.cFolders];
for (int i = 0; i < this.header.cFolders; i++) {
this.folders[i] = new CabFolderEntry();
this.folders[i].read(this.cabInputStream);
}
this.files = new CabFileEntry[this.header.cFiles];
this.cabInputStream.seek(this.header.coffFiles);
for (int i = 0; i < this.header.cFiles; i++) {
this.files[i] = new CabFileEntry();
this.files[i].read(this.cabInputStream);
}
}
public ByteArrayOutputStream extractStream() throws CabException, IOException {
int folderCount = -1;
int currentCount = 0;
int totalCount = 0;
boolean init = true;
CabDecompressor extractor = new CabDecompressor(this.cabInputStream, this.header.cbCFData);
for (int fileIndex = 0; fileIndex < this.header.cFiles; fileIndex++) {
CabFileEntry entry = this.files[fileIndex];
if (entry.iFolder != folderCount) {
if (folderCount + 1 >= this.header.cFolders) {
throw new CorruptCabException();
}
folderCount++;
init = true;
currentCount = 0;
totalCount = 0;
}
OutputStream localOutputStream = this.streamSaver.openOutputStream(entry);
if (localOutputStream != null) {
if (init) {
CabFolderEntry cabFolderEntry = this.folders[folderCount];
this.cabInputStream.seek(cabFolderEntry.coffCabStart);
extractor.initialize(cabFolderEntry.compressionMethod);
init = false;
}
if (currentCount != totalCount) {
extractor.read(totalCount - currentCount, new OutputStream() {
@Override
public
void write(int i) throws IOException {
//do nothing
}
@Override
public
void write(byte[] b) throws IOException {
//do nothing
}
@Override
public
void write(byte[] b, int off, int len) throws IOException {
//do nothing
}
@Override
public
void flush() throws IOException {
//do nothing
}
});
currentCount = totalCount;
}
extractor.read(entry.cbFile, localOutputStream);
this.streamSaver.closeOutputStream(localOutputStream, entry);
currentCount = (int) (currentCount + entry.cbFile);
}
totalCount = (int) (totalCount + entry.cbFile);
}
return this.outputStream;
}
}

View File

@ -0,0 +1,178 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser
import dorkbox.cabParser.decompress.CabDecompressor
import dorkbox.cabParser.structure.CabEnumerator
import dorkbox.cabParser.structure.CabFileEntry
import dorkbox.cabParser.structure.CabFolderEntry
import dorkbox.cabParser.structure.CabHeader
import dorkbox.updates.Updates.add
import java.io.*
import java.util.*
class CabParser {
companion object {
/**
* Gets the version number.
*/
const val version: String = "3.2"
init {
// Add this project to the updates system, which verifies this class + UUID + version information
add(CabParser::class.java, "41f560ca51c04bfdbca21328e0cbf206", version)
}
}
private var cabInputStream: CabInputStream
private var streamSaver: CabStreamSaver
private var outputStream: ByteArrayOutputStream? = null
lateinit var header: CabHeader
lateinit var folders: Array<CabFolderEntry>
lateinit var files: Array<CabFileEntry>
constructor(inputStream: InputStream, fileNameToExtract: String) {
cabInputStream = CabInputStream(inputStream)
streamSaver = object : CabStreamSaver {
override fun saveReservedAreaData(data: ByteArray?, dataLength: Int): Boolean {
return false
}
override fun openOutputStream(entry: CabFileEntry): OutputStream? {
val name = entry.name
return if (fileNameToExtract.equals(name, ignoreCase = true)) {
outputStream = ByteArrayOutputStream(entry.size.toInt())
outputStream!!
}
else {
null
}
}
override fun closeOutputStream(outputStream: OutputStream, cabFile: CabFileEntry) {
try {
outputStream.close()
}
catch (ignored: IOException) {
}
}
}
readData()
}
constructor(inputStream: InputStream, streamSaver: CabStreamSaver) {
this.streamSaver = streamSaver
cabInputStream = CabInputStream(inputStream)
readData()
}
constructor(inputStream: InputStream, extractPath: File?) {
streamSaver = DefaultCabStreamSaver(extractPath)
cabInputStream = CabInputStream(inputStream)
readData()
}
fun entries(): Enumeration<Any> {
return CabEnumerator(this, false)
}
fun entries(b: Boolean): Enumeration<Any> {
return CabEnumerator(this, b)
}
@Suppress("UNCHECKED_CAST")
@Throws(CabException::class, IOException::class)
private fun readData() {
header = CabHeader(streamSaver)
header.read(cabInputStream)
folders = arrayOfNulls<CabFolderEntry>(header.cFolders) as Array<CabFolderEntry>
for (i in 0 until header.cFolders) {
folders[i] = CabFolderEntry()
folders[i].read(cabInputStream)
}
files = arrayOfNulls<CabFileEntry>(header.cFiles) as Array<CabFileEntry>
cabInputStream.seek(header.coffFiles)
for (i in 0 until header.cFiles) {
files[i] = CabFileEntry()
files[i].read(cabInputStream)
}
}
@Throws(CabException::class, IOException::class)
fun extractStream(): ByteArrayOutputStream? {
var folderCount = -1
var currentCount = 0
var totalCount = 0
var init = true
val extractor = CabDecompressor(cabInputStream, header.cbCFData)
for (fileIndex in 0 until header.cFiles) {
val entry = files[fileIndex]
if (entry.iFolder != folderCount) {
if (folderCount + 1 >= header.cFolders) {
throw CorruptCabException()
}
folderCount++
init = true
currentCount = 0
totalCount = 0
}
val localOutputStream = streamSaver.openOutputStream(entry)
if (localOutputStream != null) {
if (init) {
val cabFolderEntry = folders[folderCount]
cabInputStream.seek(cabFolderEntry.coffCabStart)
extractor.initialize(cabFolderEntry.compressionMethod)
init = false
}
if (currentCount != totalCount) {
extractor.read((totalCount - currentCount).toLong(), object : OutputStream() {
@Throws(IOException::class)
override fun write(i: Int) {
//do nothing
}
@Throws(IOException::class)
override fun write(b: ByteArray) {
//do nothing
}
@Throws(IOException::class)
override fun write(b: ByteArray, off: Int, len: Int) {
//do nothing
}
@Throws(IOException::class)
override fun flush() {
//do nothing
}
})
currentCount = totalCount
}
extractor.read(entry.cbFile, localOutputStream)
streamSaver.closeOutputStream(localOutputStream, entry)
currentCount = (currentCount + entry.cbFile).toInt()
}
totalCount = (totalCount + entry.cbFile).toInt()
}
return outputStream
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012 dorkbox, llc
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
package dorkbox.cabParser
import java.io.OutputStream;
import dorkbox.cabParser.structure.CabFileEntry
import java.io.OutputStream
import dorkbox.cabParser.structure.CabFileEntry;
public interface CabStreamSaver {
OutputStream openOutputStream(CabFileEntry entry);
void closeOutputStream(OutputStream outputStream, CabFileEntry entry);
boolean saveReservedAreaData(byte[] data, int dataLength);
interface CabStreamSaver {
fun openOutputStream(entry: CabFileEntry): OutputStream?
fun closeOutputStream(outputStream: OutputStream, entry: CabFileEntry)
fun saveReservedAreaData(data: ByteArray?, dataLength: Int): Boolean
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012 dorkbox, llc
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -13,16 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
package dorkbox.cabParser
public final class CorruptCabException extends CabException {
private static final long serialVersionUID = 1L;
public CorruptCabException(String errorMessage) {
super(errorMessage);
}
public CorruptCabException() {
}
class CorruptCabException : CabException {
constructor(errorMessage: String?) : super(errorMessage)
constructor()
}

View File

@ -1,77 +0,0 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
import dorkbox.cabParser.structure.CabFileEntry;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
/**
* provide default CabStreamSaver
*/
public class DefaultCabStreamSaver implements CabStreamSaver{
private File extractPath;
public DefaultCabStreamSaver(File extractPath) throws CabException {
this.extractPath = extractPath;
if(extractPath!=null){
if(!extractPath.exists()){
extractPath.mkdirs();
}else if(!extractPath.isDirectory()){
throw new CabException("extractPath is not directory");
}
}
}
@Override
public OutputStream openOutputStream(CabFileEntry entry) {
return new ByteArrayOutputStream((int) entry.getSize());
}
@Override
public void closeOutputStream(OutputStream outputStream, CabFileEntry entry) {
if (outputStream != null) {
try {
ByteArrayOutputStream bos = (ByteArrayOutputStream)outputStream;
File cabEntityFile = new File(extractPath, entry.getName().replace("\\", File.separator));
cabEntityFile.getParentFile().mkdirs();
FileOutputStream fileOutputStream = new FileOutputStream(cabEntityFile);
try {
bos.writeTo(fileOutputStream);
} finally {
fileOutputStream.close();
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
} finally {
try {
outputStream.close();
} catch (IOException e) {
}
}
}
}
@Override
public boolean saveReservedAreaData(byte[] data, int dataLength) {
return false;
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser
import dorkbox.cabParser.structure.CabFileEntry
import java.io.*
/**
* provide default CabStreamSaver
*/
class DefaultCabStreamSaver(private val extractPath: File?) : CabStreamSaver {
init {
if (extractPath != null) {
if (!extractPath.exists()) {
extractPath.mkdirs()
}
else if (!extractPath.isDirectory()) {
throw CabException("extractPath is not directory")
}
}
}
override fun openOutputStream(entry: CabFileEntry): OutputStream? {
return ByteArrayOutputStream(entry.size.toInt())
}
override fun closeOutputStream(outputStream: OutputStream, entry: CabFileEntry) {
try {
val bos = outputStream as ByteArrayOutputStream
val cabEntityFile = File(extractPath, entry.name.replace("\\", File.separator))
cabEntityFile.getParentFile().mkdirs()
val fileOutputStream = FileOutputStream(cabEntityFile)
try {
bos.writeTo(fileOutputStream)
}
finally {
fileOutputStream.close()
}
}
catch (e: FileNotFoundException) {
}
catch (e: IOException) {
}
finally {
try {
outputStream.close()
}
catch (e: IOException) {
}
}
}
override fun saveReservedAreaData(data: ByteArray?, dataLength: Int): Boolean {
return false
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012 dorkbox, llc
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -72,8 +72,8 @@ public final class CabDecompressor implements CabConstants {
throw new CorruptCabException("Invalid CFDATA checksum");
}
this.decompressor.decompress(this.readBuffer, this.bytes, this.cfDataRecord.cbData, this.cfDataRecord.cbUncomp);
this.uncompressedDataSize = this.cfDataRecord.cbUncomp;
this.decompressor.decompress(this.readBuffer, this.bytes, this.cfDataRecord.getCbData(), this.cfDataRecord.getCbUncomp());
this.uncompressedDataSize = this.cfDataRecord.getCbUncomp();
this.outputOffset = 0;
if (this.uncompressedDataSize >= size) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019 dorkbox, llc
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -160,7 +160,7 @@ public class CabExtractor {
}
public static String getVersion() {
return CabParser.getVersion();
return CabParser.version;
}
public Enumeration<Object> entries() {

View File

@ -13,19 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.extractor;
package dorkbox.cabParser.extractor
import dorkbox.cabParser.structure.CabFileEntry;
import dorkbox.cabParser.structure.CabFileEntry
/**
* Implement it to select files to extract from CAB.
*/
public interface CabFileFilter {
interface CabFileFilter {
/**
* Is invoked on each File Entry found in CAB file.
*
* @return <code>true</code> to extract file, <code>false</code> to ignore
*
* @return `true` to extract file, `false` to ignore
*/
public boolean test(CabFileEntry cabFile);
fun test(cabFile: CabFileEntry?): Boolean
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019 dorkbox, llc
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -13,35 +13,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.extractor;
package dorkbox.cabParser.extractor
import java.io.ByteArrayOutputStream;
import dorkbox.cabParser.structure.CabFileEntry;
import dorkbox.cabParser.structure.CabFileEntry
import java.io.ByteArrayOutputStream
/**
* To define how to handle (save) the file content, corresponding to each
* individual file extracted from CAB.
*/
public interface CabFileSaver {
interface CabFileSaver {
/**
* Save the extracted file content.
*
* @param fileContent
* extracted file content
* @param cabFile
* {@link CabFileEntry} defining file to be be saved
*
* @param fileContent extracted file content
* @param cabFile [CabFileEntry], file to be saved
*/
void save(ByteArrayOutputStream fileContent, CabFileEntry cabFile);
fun save(fileContent: ByteArrayOutputStream?, cabFile: CabFileEntry?)
/**
* @return amount successfully saved files
*/
int getSucceeded();
val succeeded: Int
/**
* @return amount of failed save attempts
*/
int getFailed();
val failed: Int
}

View File

@ -1,116 +0,0 @@
/*
* Copyright 2019 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.extractor;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import dorkbox.cabParser.CabStreamSaver;
import dorkbox.cabParser.structure.CabFileEntry;
/**
* Implementation of {@link CabStreamSaver} that filters files to extract.
* {@link CabFileFilter} and saves them using {@link CabFileSaver}.
*/
public class FilteredCabStreamSaver implements CabStreamSaver {
private final CabFileSaver saver;
private final CabFileFilter filter;
/**
* To save all files to defined extract directory.
*
* @param extractDirectory
* directory to extract files (no sub-directory will be created)
*/
public FilteredCabStreamSaver(File extractDirectory) {
this(extractDirectory, null);
}
/**
* To handle (save) all files using passed {@link CabFileSaver}.
*
* @param saver
* defines how to save the {@link ByteArrayOutputStream}
* corresponding to {@link CabFileEntry}
*/
public FilteredCabStreamSaver(CabFileSaver saver) {
this(saver, null);
}
/**
* To save some files to defined extract directory.
*
* @param extractDirectory
* directory to extract files (no sub-directory will be created)
* @param filter
* which files to extract (extract all files if
* <code>null</code>)
*/
public FilteredCabStreamSaver(File extractDirectory, CabFileFilter filter) {
this(new DefaultCabFileSaver(extractDirectory), filter);
}
/**
* To handle (save) some files using passed {@link CabFileSaver}.
*
* @param saver
* defines how to save the {@link ByteArrayOutputStream}
* corresponding to {@link CabFileEntry}
* @param filter
* which files to extract (extract all files if
* <code>null</code>)
*/
public FilteredCabStreamSaver(CabFileSaver saver, CabFileFilter filter) {
this.saver = null == saver ? new DefaultCabFileSaver(null) : saver;
this.filter = null == filter ? new CabFilePatternFilter(".+") : filter;
}
@Override
public void closeOutputStream(OutputStream outputStream, CabFileEntry cabFile) {
saver.save((ByteArrayOutputStream) outputStream, cabFile);
}
@Override
public OutputStream openOutputStream(CabFileEntry cabFile) {
if (filter.test(cabFile)) {
return new ByteArrayOutputStream((int) cabFile.getSize());
} else {
return null;
}
}
@Override
public boolean saveReservedAreaData(byte[] data, int dataLength) {
return false;
}
/**
* @return amount successfully saved files
*/
public int getSucceeded() {
return saver.getSucceeded();
}
/**
* @return amount of failed save attempts
*/
public int getFailed() {
return saver.getFailed();
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.extractor
import dorkbox.cabParser.CabStreamSaver
import dorkbox.cabParser.structure.CabFileEntry
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.OutputStream
/**
* Implementation of [CabStreamSaver] that filters files to extract.
* [CabFileFilter] and saves them using [CabFileSaver].
*/
class FilteredCabStreamSaver(
/**
* defines how to save the [ByteArrayOutputStream] corresponding to [CabFileEntry]
*/
val saver: CabFileSaver = DefaultCabFileSaver(null),
/**
* which files to extract (extract all files if `null`)
*/
val filter: CabFileFilter = CabFilePatternFilter(".+")) : CabStreamSaver {
/**
* To save some files to defined extract directory.
*
* @param extractDirectory directory to extract files (no sub-directory will be created)
* @param filter which files to extract (extract all files if `null`)
*/
constructor(extractDirectory: File?, filter: CabFileFilter) : this(DefaultCabFileSaver(extractDirectory), filter)
override fun closeOutputStream(outputStream: OutputStream, entry: CabFileEntry) {
saver.save(outputStream as ByteArrayOutputStream, entry)
}
override fun openOutputStream(entry: CabFileEntry): OutputStream? {
return if (filter.test(entry)) {
ByteArrayOutputStream(entry.size.toInt())
}
else {
null
}
}
override fun saveReservedAreaData(data: ByteArray?, dataLength: Int): Boolean {
return false
}
/**
* @return amount successfully saved files
*/
val succeeded: Int
get() = saver.succeeded
/**
* @return amount of failed save attempts
*/
val failed: Int
get() = saver.failed
}

View File

@ -1,54 +0,0 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
public interface CabConstants {
int CAB_BLOCK_SIZE = 32768;
int CAB_BLOCK_SIZE_THRESH = 32767;
int COMPRESSION_TYPE_NONE = 0;
int COMPRESSION_TYPE_MSZIP = 1;
int COMPRESSION_TYPE_QUANTUM = 2;
int COMPRESSION_TYPE_LZX = 3;
int RESERVED_CFHEADER = 1;
int RESERVED_CFFOLDER = 2;
int RESERVED_CFDATA = 3;
int CAB_PROGRESS_INPUT = 1;
/**
* FLAG_PREV_CABINET is set if this cabinet file is not the first in a set
* of cabinet files. When this bit is set, the szCabinetPrev and szDiskPrev
* fields are present in this CFHEADER.
*/
int FLAG_PREV_CABINET = 0x0001;
/**
* FLAG_NEXT_CABINET is set if this cabinet file is not the last in a set of
* cabinet files. When this bit is set, the szCabinetNext and szDiskNext
* fields are present in this CFHEADER.
*/
int FLAG_NEXT_CABINET = 0x0002;
/**
* FLAG_RESERVE_PRESENT is set if this cabinet file contains any reserved
* fields. When this bit is set, the cbCFHeader, cbCFFolder, and cbCFData
* fields are present in this CFHEADER.
*/
int FLAG_RESERVE_PRESENT = 0x0004;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure
interface CabConstants {
companion object {
const val CAB_BLOCK_SIZE = 32768
const val CAB_BLOCK_SIZE_THRESH = 32767
const val COMPRESSION_TYPE_NONE = 0
const val COMPRESSION_TYPE_MSZIP = 1
const val COMPRESSION_TYPE_QUANTUM = 2
const val COMPRESSION_TYPE_LZX = 3
const val RESERVED_CFHEADER = 1
const val RESERVED_CFFOLDER = 2
const val RESERVED_CFDATA = 3
const val CAB_PROGRESS_INPUT = 1
/**
* FLAG_PREV_CABINET is set if this cabinet file is not the first in a set
* of cabinet files. When this bit is set, the szCabinetPrev and szDiskPrev
* fields are present in this CFHEADER.
*/
const val FLAG_PREV_CABINET = 0x0001
/**
* FLAG_NEXT_CABINET is set if this cabinet file is not the last in a set of
* cabinet files. When this bit is set, the szCabinetNext and szDiskNext
* fields are present in this CFHEADER.
*/
const val FLAG_NEXT_CABINET = 0x0002
/**
* FLAG_RESERVE_PRESENT is set if this cabinet file contains any reserved
* fields. When this bit is set, the cbCFHeader, cbCFFolder, and cbCFData
* fields are present in this CFHEADER.
*/
const val FLAG_RESERVE_PRESENT = 0x0004
}
}

View File

@ -1,66 +0,0 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import dorkbox.cabParser.CabParser;
public final class CabEnumerator implements Enumeration<Object> {
private int fileCount = 0;
private int folderCount = 0;
private CabParser cabParser;
private boolean b;
private int folderIndex;
@Override
public Object nextElement() {
if (!this.b) {
if (this.fileCount < this.cabParser.header.cFiles) {
return this.cabParser.files[this.fileCount++];
}
throw new NoSuchElementException();
}
if (this.cabParser.files[this.fileCount].iFolder != this.folderIndex) {
this.folderIndex = this.cabParser.files[this.fileCount].iFolder;
if (this.folderCount < this.cabParser.folders.length) {
return this.cabParser.folders[this.folderCount++];
}
}
if (this.fileCount < this.cabParser.header.cFiles) {
return this.cabParser.files[this.fileCount++];
}
throw new NoSuchElementException();
}
public CabEnumerator(CabParser decoder, boolean b) {
this.cabParser = decoder;
this.b = b;
this.folderIndex = -2;
}
@Override
public boolean hasMoreElements() {
return this.fileCount < this.cabParser.header.cFiles;
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure
import dorkbox.cabParser.CabParser
import java.util.*
class CabEnumerator(private val cabParser: CabParser, private val b: Boolean) : Enumeration<Any> {
private var fileCount = 0
private var folderCount = 0
private var folderIndex: Int
init {
folderIndex = -2
}
override fun nextElement(): Any {
if (!b) {
if (fileCount < cabParser.header.cFiles) {
return cabParser.files[fileCount++]
}
throw NoSuchElementException()
}
if (cabParser.files[fileCount].iFolder != folderIndex) {
folderIndex = cabParser.files[fileCount].iFolder
if (folderCount < cabParser.folders.size) {
return cabParser.folders[folderCount++]
}
}
if (fileCount < cabParser.header.cFiles) {
return cabParser.files[fileCount++]
}
throw NoSuchElementException()
}
override fun hasMoreElements(): Boolean {
return fileCount < cabParser.header.cFiles
}
}

View File

@ -1,249 +0,0 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Date;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.bytes.LittleEndian;
public final class CabFileEntry {
public static final Charset US_ASCII = Charset.forName("US-ASCII");
/** file is read-only (in HEX) */
static final int READONLY = 0x01;
/** file is hidden (in HEX) */
static final int HIDDEN = 0x02;
/** file is a system file (in HEX) */
static final int SYSTEM = 0x04;
/** file modified since last backup (in HEX) */
static final int ARCHIVE = 0x20;
/** szName[] contains UTF (in HEX) */
static final int NAME_IS_UTF = 0x80;
/** uncompressed size of this file in bytes , 4bytes */
public long cbFile;
/** uncompressed offset of this file in the folder , 4bytes */
public long offFolderStart;
/** index into the CFFOLDER area , 2bytes */
public int iFolder;
/** time/date stamp for this file , 2bytes */
public Date date = new Date();
/** attribute flags for this file , 2bytes */
public int attribs;
/** name of this file , 1*n bytes */
public String szName;
private Object objectOrSomething;
public void read(InputStream input) throws IOException, CabException {
byte[] arrayOfByte = new byte[256];
this.cbFile = LittleEndian.UInt_.from(input).longValue();
this.offFolderStart = LittleEndian.UInt_.from(input).longValue();
this.iFolder = LittleEndian.UShort_.from(input).intValue();
int timeA = LittleEndian.UShort_.from(input).intValue();
int timeB = LittleEndian.UShort_.from(input).intValue();
this.date = getDate(timeA, timeB);
this.attribs = LittleEndian.UShort_.from(input).intValue();
int i = 0;
for (i = 0; i < arrayOfByte.length; i++) {
int m = input.read();
if (m == -1) {
throw new CorruptCabException("EOF reading cffile");
}
arrayOfByte[i] = (byte) m;
if (m == 0) {
break;
}
}
if (i >= arrayOfByte.length) {
throw new CorruptCabException("cffile filename not null terminated");
}
if ((this.attribs & NAME_IS_UTF) == NAME_IS_UTF) {
this.szName = readUtfString(arrayOfByte);
if (this.szName == null) {
throw new CorruptCabException("invalid utf8 code");
}
} else {
this.szName = new String(arrayOfByte, 0, i, US_ASCII).trim();
}
}
public boolean isReadOnly() {
return (this.attribs & READONLY) != 0;
}
public void setReadOnly(boolean bool) {
if (bool) {
this.attribs |= 1;
return;
}
this.attribs &= -2;
}
public boolean isHidden() {
return (this.attribs & HIDDEN) != 0;
}
public void setHidden(boolean bool) {
if (bool) {
this.attribs |= 2;
return;
}
this.attribs &= -3;
}
public boolean isSystem() {
return (this.attribs & SYSTEM) != 0;
}
public void setSystem(boolean bool) {
if (bool) {
this.attribs |= 4;
return;
}
this.attribs &= -5;
}
public boolean isArchive() {
return (this.attribs & ARCHIVE) != 0;
}
public void setArchive(boolean bool) {
if (bool) {
this.attribs |= 32;
return;
}
this.attribs &= -33;
}
public String getName() {
return this.szName;
}
public long getSize() {
return this.cbFile;
}
public void setName(String name) {
this.szName = name;
}
public void setSize(long size) {
this.cbFile = (int) size;
}
public Date getDate() {
return this.date;
}
public void setDate(Date paramDate) {
this.date = paramDate;
}
@SuppressWarnings("deprecation")
private Date getDate(int dateInfo, int timeInfo) {
int i = dateInfo & 0x1F;
int j = (dateInfo >>> 5) - 1 & 0xF;
int k = (dateInfo >>> 9) + 80;
int m = (timeInfo & 0x1F) << 1;
int n = timeInfo >>> 5 & 0x3F;
int i1 = timeInfo >>> 11 & 0x1F;
return new Date(k, j, i, i1, n, m);
}
public Object getApplicationData() {
return this.objectOrSomething;
}
public void setApplicationData(Object obj) {
this.objectOrSomething = obj;
}
@Override
public String toString() {
return this.szName;
}
private static String readUtfString(byte[] stringBytes) {
int j = 0;
int stringSize = 0;
int k = 0;
// count the size of the string
for (stringSize = 0; stringBytes[stringSize] != 0; stringSize++) {}
char[] stringChars = new char[stringSize];
for (k = 0; stringBytes[j] != 0; k++) {
int m = (char) (stringBytes[j++] & 0xFF);
if (m < 128) {
stringChars[k] = (char) m;
} else {
if (m < 192) {
return null;
}
if (m < 224) {
stringChars[k] = (char) ((m & 0x1F) << 6);
m = (char) (stringBytes[j++] & 0xFF);
if (m < 128 || m > 191) {
return null;
}
stringChars[k] = (char) (stringChars[k] | (char) (m & 0x3F));
}
else if (m < 240) {
stringChars[k] = (char) ((m & 0xF) << 12);
m = (char) (stringBytes[j++] & 0xFF);
if (m < 128 || m > 191) {
return null;
}
stringChars[k] = (char) (stringChars[k] | (char) ((m & 0x3F) << 6));
m = (char) (stringBytes[j++] & 0xFF);
if (m < 128 || m > 191) {
return null;
}
stringChars[k] = (char) (stringChars[k] | (char) (m & 0x3F));
} else {
return null;
}
}
}
return new String(stringChars, 0, k);
}
}

View File

@ -0,0 +1,207 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure
import dorkbox.bytes.LittleEndian
import dorkbox.cabParser.CabException
import dorkbox.cabParser.CorruptCabException
import java.io.IOException
import java.io.InputStream
import java.nio.charset.Charset
import java.util.*
class CabFileEntry {
/** uncompressed size of this file in bytes , 4bytes */
var cbFile: Long = 0
/** uncompressed offset of this file in the folder , 4bytes */
var offFolderStart: Long = 0
/** index into the CFFOLDER area , 2bytes */
var iFolder = 0
/** time/date stamp for this file , 2bytes */
var date = Date()
/** attribute flags for this file , 2bytes */
var attribs = 0
/** name of this file , 1*n bytes */
lateinit var name: String
var applicationData: Any? = null
@Throws(IOException::class, CabException::class)
fun read(input: InputStream) {
val arrayOfByte = ByteArray(256)
cbFile = LittleEndian.UInt_.from(input).toLong()
offFolderStart = LittleEndian.UInt_.from(input).toLong()
iFolder = LittleEndian.UShort_.from(input).toInt()
val timeA: Int = LittleEndian.UShort_.from(input).toInt()
val timeB: Int = LittleEndian.UShort_.from(input).toInt()
date = getDate(timeA, timeB)
attribs = LittleEndian.UShort_.from(input).toInt()
var i = 0
i = 0
while (i < arrayOfByte.size) {
val m = input.read()
if (m == -1) {
throw CorruptCabException("EOF reading cffile")
}
arrayOfByte[i] = m.toByte()
if (m == 0) {
break
}
i++
}
if (i >= arrayOfByte.size) {
throw CorruptCabException("cffile filename not null terminated")
}
name = if (attribs and NAME_IS_UTF == NAME_IS_UTF) {
readUtfString(arrayOfByte) ?: throw CorruptCabException("invalid name utf8 code")
}
else {
String(arrayOfByte, 0, i, US_ASCII).trim { it <= ' ' }
}
}
var isReadOnly: Boolean
get() = attribs and READONLY != 0
set(bool) {
if (bool) {
attribs = attribs or 1
return
}
attribs = attribs and -2
}
var isHidden: Boolean
get() = attribs and HIDDEN != 0
set(bool) {
if (bool) {
attribs = attribs or 2
return
}
attribs = attribs and -3
}
var isSystem: Boolean
get() = attribs and SYSTEM != 0
set(bool) {
if (bool) {
attribs = attribs or 4
return
}
attribs = attribs and -5
}
var isArchive: Boolean
get() = attribs and ARCHIVE != 0
set(bool) {
if (bool) {
attribs = attribs or 32
return
}
attribs = attribs and -33
}
var size: Long
get() = cbFile
set(size) {
cbFile = size.toInt().toLong()
}
private fun getDate(dateInfo: Int, timeInfo: Int): Date {
val i = dateInfo and 0x1F
val j = (dateInfo ushr 5) - 1 and 0xF
val k = (dateInfo ushr 9) + 80
val m = timeInfo and 0x1F shl 1
val n = timeInfo ushr 5 and 0x3F
val i1 = timeInfo ushr 11 and 0x1F
return Date(k, j, i, i1, n, m)
}
override fun toString(): String {
return name
}
companion object {
val US_ASCII = Charset.forName("US-ASCII")
/** file is read-only (in HEX) */
const val READONLY = 0x01
/** file is hidden (in HEX) */
const val HIDDEN = 0x02
/** file is a system file (in HEX) */
const val SYSTEM = 0x04
/** file modified since last backup (in HEX) */
const val ARCHIVE = 0x20
/** szName[] contains UTF (in HEX) */
const val NAME_IS_UTF = 0x80
private fun readUtfString(stringBytes: ByteArray): String? {
var j = 0
var stringSize = 0
var k = 0
// count the size of the string
stringSize = 0
while (stringBytes[stringSize].toInt() != 0) {
stringSize++
}
val stringChars = CharArray(stringSize)
k = 0
while (stringBytes[j].toInt() != 0) {
var m = (stringBytes[j++].toInt() and 0xFF).toChar().code
if (m < 128) {
stringChars[k] = m.toChar()
}
else {
if (m < 192) {
return null
}
if (m < 224) {
stringChars[k] = (m and 0x1F shl 6).toChar()
m = (stringBytes[j++].toInt() and 0xFF).toChar().code
if (m < 128 || m > 191) {
return null
}
stringChars[k] = (stringChars[k].code or (m and 0x3F).toChar().code).toChar()
}
else if (m < 240) {
stringChars[k] = (m and 0xF shl 12).toChar()
m = (stringBytes[j++].toInt() and 0xFF).toChar().code
if (m < 128 || m > 191) {
return null
}
stringChars[k] = (stringChars[k].code or (m and 0x3F shl 6).toChar().code).toChar()
m = (stringBytes[j++].toInt() and 0xFF).toChar().code
if (m < 128 || m > 191) {
return null
}
stringChars[k] = (stringChars[k].code or (m and 0x3F).toChar().code).toChar()
}
else {
return null
}
}
k++
}
return String(stringChars, 0, k)
}
}
}

View File

@ -1,72 +0,0 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
import java.io.IOException;
import java.io.InputStream;
import dorkbox.bytes.LittleEndian;
public final class CabFolderEntry implements CabConstants {
/** offset of the first CFDATA block in this folder, 4bytes */
public long coffCabStart;
/** number of CFDATA blocks in this folder, 2bytes */
public int cCFData;
/** compression type indicator , 2bytes */
public int compressionMethod = 0;
public int getCompressionMethod() {
return this.compressionMethod & 0xF;
}
public void read(InputStream input) throws IOException {
this.coffCabStart = LittleEndian.UInt_.from(input).longValue();
this.cCFData = LittleEndian.UShort_.from(input).intValue();
this.compressionMethod = LittleEndian.UShort_.from(input).intValue();
}
public int getCompressionWindowSize() {
if (this.compressionMethod == COMPRESSION_TYPE_NONE) {
return 0;
}
if (this.compressionMethod == COMPRESSION_TYPE_MSZIP) {
return 16;
}
return (this.compressionMethod & 0x1F00) >>> 8;
}
public String compressionToString() {
switch (getCompressionMethod()) {
default :
return "UNKNOWN";
case 0 :
return "NONE";
case 1 :
return "MSZIP";
case 2 :
return "QUANTUM:" + Integer.toString(getCompressionWindowSize());
case 3 :
}
return "LZX:" + Integer.toString(getCompressionWindowSize());
}
public void setCompression(int a, int b) {
this.compressionMethod = b << 8 | a;
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure
import dorkbox.bytes.LittleEndian
import java.io.IOException
import java.io.InputStream
class CabFolderEntry : CabConstants {
/** offset of the first CFDATA block in this folder, 4bytes */
var coffCabStart: Long = 0
/** number of CFDATA blocks in this folder, 2bytes */
var cCFData = 0
/** compression type indicator , 2bytes */
var compressionMethod = 0
@Throws(IOException::class)
fun read(input: InputStream) {
coffCabStart = LittleEndian.UInt_.from(input).toLong()
cCFData = LittleEndian.UShort_.from(input).toInt()
compressionMethod = LittleEndian.UShort_.from(input).toInt()
}
val compressionWindowSize: Int
get() {
if (compressionMethod == CabConstants.COMPRESSION_TYPE_NONE) {
return 0
}
return if (compressionMethod == CabConstants.COMPRESSION_TYPE_MSZIP) {
16
}
else compressionMethod and 0x1F00 ushr 8
}
fun compressionToString(): String {
when (compressionMethod) {
0 -> return "NONE"
1 -> return "MSZIP"
2 -> return "QUANTUM:" + compressionWindowSize.toString()
3 -> {}
else -> return "UNKNOWN"
}
return "LZX:" + compressionWindowSize.toString()
}
fun setCompression(a: Int, b: Int) {
compressionMethod = b shl 8 or a
}
}

View File

@ -1,161 +0,0 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.CabStreamSaver;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.bytes.LittleEndian;
public final class CabHeader implements CabConstants {
/** reserved , 4 bytes */
public long reserved1;
/** size of this cabinet file in bytes , 4 bytes */
public long cbCabinet;
/** reserved, 4 bytes */
public long reserved2;
/** offset of the first CFFILE entry , 4 bytes */
public long coffFiles;
/** reserved, 4 bytes*/
public long reserved3;
/** cabinet file format version, minor/major , 1 bytes*2 */
public int version;
/** number of CFFOLDER entries in this cabinet , 2 bytes */
public int cFolders;
/** number of CFFILE entries in this cabinet , 2 bytes */
public int cFiles;
/** cabinet file option indicators , 2 bytes */
public int flags;
/** must be the same for all cabinets in a set , 2 bytes */
public int setID;
/** number of this cabinet file in a set , 2 bytes */
public int iCabinet;
/** (optional) size of per-cabinet reserved area , 2 bytes */
public int cbCFHeader = 0;
/** (optional) size of per-folder reserved area , 1 bytes */
public int cbCFFolder = 0;
/** (optional) size of per-datablock reserved area , 1 bytes */
public int cbCFData = 0;
/** (optional) per-cabinet reserved area , 1*n bytes */
//final short abReserve[];
/** (optional) name of previous cabinet file , 1*n bytes */
//final String szCabinetPrev;
/** (optional) name of previous disk , 1*n bytes */
//final String szDiskPrev;
/** (optional) name of next cabinet file , 1*n bytes */
//final String szCabinetNext;
/** (optional) name of next disk , 1*n bytes */
//final String szDiskNext;
private CabStreamSaver decoder;
public CabHeader(CabStreamSaver paramCabDecoderInterface) {
this.decoder = paramCabDecoderInterface;
}
public void read(InputStream input) throws IOException, CabException {
int i = input.read();
int j = input.read();
int k = input.read();
int m = input.read();
// Contains the characters "M", "S", "C", and "F" (bytes 0x4D, 0x53, 0x43, 0x46). This field is used to ensure that the file is a cabinet (.cab) file.
if (i != 77 || j != 83 || k != 67 || m != 70) {
throw new CorruptCabException("Missing header signature");
}
this.reserved1 = LittleEndian.UInt_.from(input).longValue(); // must be 0
this.cbCabinet = LittleEndian.UInt_.from(input).longValue(); // Specifies the total size of the cabinet file, in bytes.
this.reserved2 = LittleEndian.UInt_.from(input).longValue(); // must be 0
this.coffFiles = LittleEndian.UInt_.from(input).longValue(); // Specifies the absolute file offset, in bytes, of the first CFFILE field entry.
this.reserved3 = LittleEndian.UInt_.from(input).longValue(); // must be 0
// Currently, versionMajor = 1 and versionMinor = 3
this.version = LittleEndian.UShort_.from(input).intValue();
this.cFolders = LittleEndian.UShort_.from(input).intValue();
this.cFiles = LittleEndian.UShort_.from(input).intValue();
this.flags = LittleEndian.UShort_.from(input).intValue();
this.setID = LittleEndian.UShort_.from(input).intValue();
this.iCabinet = LittleEndian.UShort_.from(input).intValue();
if ((this.flags & FLAG_RESERVE_PRESENT) == FLAG_RESERVE_PRESENT) {
this.cbCFHeader = LittleEndian.UShort_.from(input).intValue();
this.cbCFFolder = input.read();
this.cbCFData = input.read();
}
if ((this.flags & FLAG_PREV_CABINET) == FLAG_PREV_CABINET ||
(this.flags & FLAG_NEXT_CABINET) == FLAG_NEXT_CABINET) {
throw new CabException("Spanned cabinets not supported");
}
// not supported
// if (prevCabinet()) {
// szCabinetPrev = bytes.readString(false);
// szDiskPrev = bytes.readString(false);
// } else {
// szCabinetPrev = null;
// szDiskPrev = null;
// }
//
// if (nextCabinet()) {
// szCabinetNext = bytes.readString(false);
// szDiskNext = bytes.readString(false);
// } else {
// szCabinetNext = null;
// szDiskNext = null;
// }
if (this.cbCFHeader != 0) {
if (this.decoder.saveReservedAreaData(null, this.cbCFHeader) == true) {
byte[] data = new byte[this.cbCFHeader];
if (this.cbCFHeader != 0) {
int readTotal = 0;
while (readTotal < this.cbCFHeader) {
int read = input.read(data, readTotal, this.cbCFHeader - readTotal);
if (read < 0) {
throw new EOFException();
}
readTotal += read;
}
}
this.decoder.saveReservedAreaData(data, this.cbCFHeader);
return;
}
input.skip(this.cbCFHeader);
}
}
}

View File

@ -0,0 +1,150 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure
import dorkbox.bytes.LittleEndian
import dorkbox.cabParser.CabException
import dorkbox.cabParser.CabStreamSaver
import dorkbox.cabParser.CorruptCabException
import java.io.EOFException
import java.io.IOException
import java.io.InputStream
class CabHeader
(
/** (optional) name of next cabinet file , 1*n bytes */ //final String szCabinetNext;
/** (optional) name of next disk , 1*n bytes */ //final String szDiskNext;
private val decoder: CabStreamSaver
) : CabConstants {
/** reserved , 4 bytes */
var reserved1: Long = 0
/** size of this cabinet file in bytes , 4 bytes */
var cbCabinet: Long = 0
/** reserved, 4 bytes */
var reserved2: Long = 0
/** offset of the first CFFILE entry , 4 bytes */
var coffFiles: Long = 0
/** reserved, 4 bytes */
var reserved3: Long = 0
/** cabinet file format version, minor/major , 1 bytes*2 */
var version = 0
/** number of CFFOLDER entries in this cabinet , 2 bytes */
var cFolders = 0
/** number of CFFILE entries in this cabinet , 2 bytes */
var cFiles = 0
/** cabinet file option indicators , 2 bytes */
var flags = 0
/** must be the same for all cabinets in a set , 2 bytes */
var setID = 0
/** number of this cabinet file in a set , 2 bytes */
var iCabinet = 0
/** (optional) size of per-cabinet reserved area , 2 bytes */
var cbCFHeader = 0
/** (optional) size of per-folder reserved area , 1 bytes */
var cbCFFolder = 0
/** (optional) size of per-datablock reserved area , 1 bytes */
var cbCFData = 0
/** (optional) per-cabinet reserved area , 1*n bytes */ //final short abReserve[];
/** (optional) name of previous cabinet file , 1*n bytes */ //final String szCabinetPrev;
/** (optional) name of previous disk , 1*n bytes */ //final String szDiskPrev;
@Throws(IOException::class, CabException::class)
fun read(input: InputStream) {
val i = input.read()
val j = input.read()
val k = input.read()
val m = input.read()
// Contains the characters "M", "S", "C", and "F" (bytes 0x4D, 0x53, 0x43, 0x46). This field is used to ensure that the file is a cabinet (.cab) file.
if (i != 77 || j != 83 || k != 67 || m != 70) {
throw CorruptCabException("Missing header signature")
}
reserved1 = LittleEndian.UInt_.from(input).toLong() // must be 0
cbCabinet = LittleEndian.UInt_.from(input).toLong() // Specifies the total size of the cabinet file, in bytes.
reserved2 = LittleEndian.UInt_.from(input).toLong() // must be 0
coffFiles = LittleEndian.UInt_.from(input).toLong() // Specifies the absolute file offset, in bytes, of the first CFFILE field entry.
reserved3 = LittleEndian.UInt_.from(input).toLong() // must be 0
// Currently, versionMajor = 1 and versionMinor = 3
version = LittleEndian.UShort_.from(input).toInt()
cFolders = LittleEndian.UShort_.from(input).toInt()
cFiles = LittleEndian.UShort_.from(input).toInt()
flags = LittleEndian.UShort_.from(input).toInt()
setID = LittleEndian.UShort_.from(input).toInt()
iCabinet = LittleEndian.UShort_.from(input).toInt()
if (flags and CabConstants.FLAG_RESERVE_PRESENT == CabConstants.FLAG_RESERVE_PRESENT) {
cbCFHeader = LittleEndian.UShort_.from(input).toInt()
cbCFFolder = input.read()
cbCFData = input.read()
}
if (flags and CabConstants.FLAG_PREV_CABINET == CabConstants.FLAG_PREV_CABINET || flags and CabConstants.FLAG_NEXT_CABINET == CabConstants.FLAG_NEXT_CABINET) {
throw CabException("Spanned cabinets not supported")
}
// not supported
// if (prevCabinet()) {
// szCabinetPrev = bytes.readString(false);
// szDiskPrev = bytes.readString(false);
// } else {
// szCabinetPrev = null;
// szDiskPrev = null;
// }
//
// if (nextCabinet()) {
// szCabinetNext = bytes.readString(false);
// szDiskNext = bytes.readString(false);
// } else {
// szCabinetNext = null;
// szDiskNext = null;
// }
if (cbCFHeader != 0) {
if (decoder.saveReservedAreaData(null, cbCFHeader) == true) {
val data = ByteArray(cbCFHeader)
if (cbCFHeader != 0) {
var readTotal = 0
while (readTotal < cbCFHeader) {
val read = input.read(data, readTotal, cbCFHeader - readTotal)
if (read < 0) {
throw EOFException()
}
readTotal += read
}
}
decoder.saveReservedAreaData(data, cbCFHeader)
return
}
input.skip(cbCFHeader.toLong())
}
}
}

View File

@ -1,80 +0,0 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.Checksum;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.bytes.LittleEndian;
public final class CfDataRecord {
/** checksum of this CFDATA entry , 4bytes */
private int csum;
/** number of compressed bytes in this block , 2bytes */
public int cbData;
/** number of uncompressed bytes in this block , 2bytes */
public int cbUncomp;
private int sizeOfBlockData;
public CfDataRecord(int sizeOfBlockData) {
this.sizeOfBlockData = sizeOfBlockData;
}
public void read(InputStream input, byte[] bytes) throws IOException, CabException {
this.csum = LittleEndian.Int_.from(input); // safe to use signed here, since checksum also returns signed
this.cbData = LittleEndian.UShort_.from(input).intValue();
this.cbUncomp = LittleEndian.UShort_.from(input).intValue();
if (this.cbData > bytes.length) {
throw new CorruptCabException("Corrupt cfData record");
}
if (this.sizeOfBlockData != 0) {
input.skip(this.sizeOfBlockData);
}
int readTotal = 0;
while (readTotal < this.cbData) {
int read = input.read(bytes, readTotal, this.cbData - readTotal);
if (read < 0) {
throw new EOFException();
}
readTotal += read;
}
}
private int checksum(byte[] bytes) {
byte[] arrayOfByte = new byte[4];
arrayOfByte[0] = (byte) (this.cbData & 0xFF);
arrayOfByte[1] = (byte) (this.cbData >>> 8 & 0xFF);
arrayOfByte[2] = (byte) (this.cbUncomp & 0xFF);
arrayOfByte[3] = (byte) (this.cbUncomp >>> 8 & 0xFF);
return Checksum.calculate(bytes, this.cbData, Checksum.calculate(arrayOfByte, 4, 0));
}
public boolean validateCheckSum(byte[] bytesToCheck) {
return checksum(bytesToCheck) == this.csum;
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure
import dorkbox.bytes.LittleEndian
import dorkbox.bytes.LittleEndian.Int_.from
import dorkbox.cabParser.CabException
import dorkbox.cabParser.Checksum
import dorkbox.cabParser.CorruptCabException
import java.io.EOFException
import java.io.IOException
import java.io.InputStream
class CfDataRecord(private val sizeOfBlockData: Int) {
/** checksum of this CFDATA entry , 4bytes */
private var csum = 0
/** number of compressed bytes in this block , 2bytes */
var cbData = 0
/** number of uncompressed bytes in this block , 2bytes */
var cbUncomp = 0
@Throws(IOException::class, CabException::class)
fun read(input: InputStream, bytes: ByteArray) {
csum = from(input) // safe to use signed here, since checksum also returns signed
cbData = LittleEndian.UShort_.from(input).toInt()
cbUncomp = LittleEndian.UShort_.from(input).toInt()
if (cbData > bytes.size) {
throw CorruptCabException("Corrupt cfData record")
}
if (sizeOfBlockData != 0) {
input.skip(sizeOfBlockData.toLong())
}
var readTotal = 0
while (readTotal < cbData) {
val read = input.read(bytes, readTotal, cbData - readTotal)
if (read < 0) {
throw EOFException()
}
readTotal += read
}
}
private fun checksum(bytes: ByteArray): Int {
val arrayOfByte = ByteArray(4)
arrayOfByte[0] = (cbData and 0xFF).toByte()
arrayOfByte[1] = (cbData ushr 8 and 0xFF).toByte()
arrayOfByte[2] = (cbUncomp and 0xFF).toByte()
arrayOfByte[3] = (cbUncomp ushr 8 and 0xFF).toByte()
return Checksum.calculate(bytes, cbData, Checksum.calculate(arrayOfByte, 4, 0))
}
fun validateCheckSum(bytesToCheck: ByteArray): Boolean {
return checksum(bytesToCheck) == csum
}
}

View File

@ -8,7 +8,7 @@ module dorkbox.cabParser {
exports dorkbox.cabParser.structure;
requires transitive dorkbox.bytes;
requires transitive dorkbox.byteUtils;
requires transitive dorkbox.updates;
requires transitive dorkbox.utilities;
}