Import of CAB extractor for java
This commit is contained in:
commit
b446e3b008
7
.classpath
Normal file
7
.classpath
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/Dorkbox-Util"/>
|
||||
<classpathentry kind="output" path="classes"/>
|
||||
</classpath>
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/classes/
|
17
.project
Normal file
17
.project
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>CabExtractor</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
13
LICENSE
Normal file
13
LICENSE
Normal file
@ -0,0 +1,13 @@
|
||||
- Dorkbox Cab Extractor - Apache 2.0 License
|
||||
https://github.com/dorkbox
|
||||
Copyright 2012, dorkbox, llc
|
||||
|
||||
|
||||
- Dorkbox Utils - Apache 2.0 License
|
||||
https://github.com/dorkbox
|
||||
Copyright 2010, dorkbox, llc
|
||||
|
||||
|
||||
- jOOU, Unsigned Numbers for Java - Apache 2.0 License
|
||||
https://github.com/jOOQ/jOOU
|
||||
Copyright 2011-2013, Lukas Eder, lukas.eder@gmail.com
|
218
LICENSE.Apachev2
Normal file
218
LICENSE.Apachev2
Normal file
@ -0,0 +1,218 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
10
README.md
Normal file
10
README.md
Normal file
@ -0,0 +1,10 @@
|
||||
CAB Extractor
|
||||
=============
|
||||
|
||||
Provides a means to parse and extract data from Microsoft CAB files, from Java.
|
||||
|
||||
Specifically, to extract files from within a .cab which are compressed via the LZX compression algorithm.
|
||||
|
||||
Microsoft CAB file format: http://msdn.microsoft.com/en-us/library/bb417343.aspx
|
||||
|
||||
- This is for cross-platform use, specifically - linux 32/64, mac 32/64, and windows 32/64. Java 6+
|
167
src/dorkbox/util/cab/CabDecoder.java
Normal file
167
src/dorkbox/util/cab/CabDecoder.java
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.util.cab;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import dorkbox.util.cab.decompress.CabDecompressor;
|
||||
import dorkbox.util.cab.structure.CabEnumerator;
|
||||
import dorkbox.util.cab.structure.CabFileEntry;
|
||||
import dorkbox.util.cab.structure.CabFolderEntry;
|
||||
import dorkbox.util.cab.structure.CabHeader;
|
||||
|
||||
public final class CabDecoder {
|
||||
private CabInputStream cabInputStream;
|
||||
|
||||
private CabStreamSaver streamSaver;
|
||||
private ByteArrayOutputStream outputStream = null;
|
||||
|
||||
public CabHeader header;
|
||||
|
||||
public CabFolderEntry[] folders;
|
||||
public CabFileEntry[] files;
|
||||
|
||||
public CabDecoder(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)) {
|
||||
CabDecoder.this.outputStream = new ByteArrayOutputStream((int) cabFile.getSize());
|
||||
return CabDecoder.this.outputStream;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOutputStream(OutputStream outputStream, CabFileEntry cabFile) {
|
||||
if (outputStream != null) {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
readData();
|
||||
}
|
||||
|
||||
public CabDecoder(InputStream inputStream, CabStreamSaver streamSaver) throws CabException, IOException {
|
||||
this.streamSaver = streamSaver;
|
||||
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);
|
||||
|
||||
if (this.header.cbCabinet <= 2147483647L) {
|
||||
this.cabInputStream.mark((int) this.header.cbCabinet);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (this.header.cbCabinet <= 2147483647L) {
|
||||
this.cabInputStream.mark((int) this.header.cbCabinet);
|
||||
}
|
||||
}
|
||||
|
||||
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 NullOutputStream());
|
||||
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;
|
||||
}
|
||||
}
|
27
src/dorkbox/util/cab/CabException.java
Normal file
27
src/dorkbox/util/cab/CabException.java
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.util.cab;
|
||||
|
||||
public class CabException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CabException(String errorMessage) {
|
||||
super(errorMessage);
|
||||
}
|
||||
|
||||
public CabException() {
|
||||
}
|
||||
}
|
116
src/dorkbox/util/cab/CabInputStream.java
Normal file
116
src/dorkbox/util/cab/CabInputStream.java
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.util.cab;
|
||||
|
||||
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 = this.inputStream.skip(ammount);
|
||||
this.position += (int) l;
|
||||
return l;
|
||||
}
|
||||
}
|
26
src/dorkbox/util/cab/CabStreamSaver.java
Normal file
26
src/dorkbox/util/cab/CabStreamSaver.java
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.util.cab;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import dorkbox.util.cab.structure.CabFileEntry;
|
||||
|
||||
public interface CabStreamSaver {
|
||||
public abstract OutputStream openOutputStream(CabFileEntry entry);
|
||||
public abstract void closeOutputStream(OutputStream outputStream, CabFileEntry entry);
|
||||
public abstract boolean saveReservedAreaData(byte[] data, int dataLength);
|
||||
}
|
45
src/dorkbox/util/cab/Checksum.java
Normal file
45
src/dorkbox/util/cab/Checksum.java
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.util.cab;
|
||||
|
||||
public final class Checksum {
|
||||
@SuppressWarnings("fallthrough")
|
||||
public static int calculate(byte[] bytes, int currentBlock, int seed) {
|
||||
int c1 = (byte) (seed & 0xFF);
|
||||
int c2 = (byte) (seed >>> 8 & 0xFF);
|
||||
int c3 = (byte) (seed >>> 16 & 0xFF);
|
||||
int c4 = (byte) (seed >>> 24 & 0xFF);
|
||||
|
||||
int j = 0;
|
||||
int sizeOfBlock = currentBlock >>> 2;
|
||||
while (sizeOfBlock-- > 0) {
|
||||
c1 = (byte) (c1 ^ bytes[j++]);
|
||||
c2 = (byte) (c2 ^ bytes[j++]);
|
||||
c3 = (byte) (c3 ^ bytes[j++]);
|
||||
c4 = (byte) (c4 ^ bytes[j++]);
|
||||
}
|
||||
|
||||
switch (currentBlock & 0x3) {
|
||||
case 3 :
|
||||
c3 = (byte) (c3 ^ bytes[j++]);
|
||||
case 2 :
|
||||
c2 = (byte) (c2 ^ bytes[j++]);
|
||||
case 1 :
|
||||
c1 = (byte) (c1 ^ bytes[j++]);
|
||||
}
|
||||
return c1 & 0xFF | (c2 & 0xFF) << 8 | (c3 & 0xFF) << 16 | (c4 & 0xFF) << 24;
|
||||
}
|
||||
}
|
28
src/dorkbox/util/cab/CorruptCabException.java
Normal file
28
src/dorkbox/util/cab/CorruptCabException.java
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.util.cab;
|
||||
|
||||
|
||||
public final class CorruptCabException extends CabException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CorruptCabException(String errorMessage) {
|
||||
super(errorMessage);
|
||||
}
|
||||
|
||||
public CorruptCabException() {
|
||||
}
|
||||
}
|
35
src/dorkbox/util/cab/NullOutputStream.java
Normal file
35
src/dorkbox/util/cab/NullOutputStream.java
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.util.cab;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
final class NullOutputStream extends OutputStream {
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) {}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) {}
|
||||
|
||||
@Override
|
||||
public void write(int b) {}
|
||||
|
||||
@Override
|
||||
public void flush() {}
|
||||
}
|
122
src/dorkbox/util/cab/decompress/CabDecompressor.java
Normal file
122
src/dorkbox/util/cab/decompress/CabDecompressor.java
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.util.cab.decompress;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import dorkbox.util.cab.CabException;
|
||||
import dorkbox.util.cab.CorruptCabException;
|
||||
import dorkbox.util.cab.decompress.lzx.DecompressLzx;
|
||||
import dorkbox.util.cab.decompress.none.DecompressNone;
|
||||
import dorkbox.util.cab.decompress.zip.DecompressZip;
|
||||
import dorkbox.util.cab.structure.CabConstants;
|
||||
import dorkbox.util.cab.structure.CfDataRecord;
|
||||
|
||||
public final class CabDecompressor implements CabConstants {
|
||||
private byte[] readBuffer;
|
||||
private byte[] bytes;
|
||||
|
||||
private long uncompressedDataSize;
|
||||
|
||||
private int outputOffset;
|
||||
private int compressionMethod;
|
||||
|
||||
private InputStream inputStream;
|
||||
private Decompressor decompressor;
|
||||
private CfDataRecord cfDataRecord;
|
||||
|
||||
public CabDecompressor(InputStream paramInputStream, int sizeOfBlockData) {
|
||||
this.inputStream = paramInputStream;
|
||||
this.uncompressedDataSize = 0L;
|
||||
this.outputOffset = 0;
|
||||
this.compressionMethod = -1;
|
||||
this.bytes = new byte[33028];
|
||||
this.cfDataRecord = new CfDataRecord(sizeOfBlockData);
|
||||
}
|
||||
|
||||
public void read(long size, OutputStream outputStream) throws IOException, CabException {
|
||||
if (this.uncompressedDataSize >= size) {
|
||||
outputStream.write(this.bytes, this.outputOffset, (int) size);
|
||||
this.uncompressedDataSize -= size;
|
||||
this.outputOffset = (int) (this.outputOffset + size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.uncompressedDataSize > 0L) {
|
||||
outputStream.write(this.bytes, this.outputOffset, (int) this.uncompressedDataSize);
|
||||
}
|
||||
|
||||
size -= this.uncompressedDataSize;
|
||||
this.outputOffset = 0;
|
||||
this.uncompressedDataSize = 0L;
|
||||
|
||||
while (size > 0L) {
|
||||
this.cfDataRecord.read(this.inputStream, this.readBuffer);
|
||||
|
||||
if (!this.cfDataRecord.validateCheckSum(this.readBuffer)) {
|
||||
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.outputOffset = 0;
|
||||
|
||||
if (this.uncompressedDataSize >= size) {
|
||||
outputStream.write(this.bytes, this.outputOffset, (int) size);
|
||||
this.outputOffset = (int) (this.outputOffset + size);
|
||||
this.uncompressedDataSize -= size;
|
||||
size = 0L;
|
||||
} else {
|
||||
outputStream.write(this.bytes, this.outputOffset, (int) this.uncompressedDataSize);
|
||||
size -= this.uncompressedDataSize;
|
||||
this.outputOffset = 0;
|
||||
this.uncompressedDataSize = 0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void initialize(int compressionMethod) throws CabException {
|
||||
int type = compressionMethod & 0xF;
|
||||
int windowBits = (compressionMethod & 0x1F00) >>> 8;
|
||||
|
||||
if (compressionMethod == this.compressionMethod) {
|
||||
this.decompressor.reset(windowBits);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case COMPRESSION_TYPE_NONE :
|
||||
this.decompressor = new DecompressNone();
|
||||
break;
|
||||
case COMPRESSION_TYPE_MSZIP :
|
||||
this.decompressor = new DecompressZip();
|
||||
break;
|
||||
case COMPRESSION_TYPE_LZX :
|
||||
this.decompressor = new DecompressLzx();
|
||||
break;
|
||||
|
||||
case COMPRESSION_TYPE_QUANTUM :
|
||||
default :
|
||||
throw new CabException("Unknown compression type " + type);
|
||||
}
|
||||
|
||||
this.readBuffer = new byte[CabConstants.CAB_BLOCK_SIZE + this.decompressor.getMaxGrowth()];
|
||||
this.decompressor.init(windowBits);
|
||||
this.compressionMethod = compressionMethod;
|
||||
}
|
||||
}
|
27
src/dorkbox/util/cab/decompress/Decompressor.java
Normal file
27
src/dorkbox/util/cab/decompress/Decompressor.java
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.util.cab.decompress;
|
||||
|
||||
import dorkbox.util.cab.CabException;
|
||||
import dorkbox.util.cab.structure.CabConstants;
|
||||
|
||||
|
||||
public interface Decompressor extends CabConstants {
|
||||
public abstract void init(int windowBits) throws CabException;
|
||||
public abstract void decompress(byte[] inputBytes, byte[] outputBytes, int inputLength, int outputLength) throws CabException;
|
||||
public abstract int getMaxGrowth();
|
||||
public abstract void reset(int windowBits) throws CabException;
|
||||
}
|
608
src/dorkbox/util/cab/decompress/lzx/DecompressLzx.java
Normal file
608
src/dorkbox/util/cab/decompress/lzx/DecompressLzx.java
Normal file
@ -0,0 +1,608 @@
|
||||
/*
|
||||
* 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.util.cab.decompress.lzx;
|
||||
|
||||
import dorkbox.util.cab.CabException;
|
||||
import dorkbox.util.cab.CorruptCabException;
|
||||
import dorkbox.util.cab.decompress.Decompressor;
|
||||
|
||||
public final class DecompressLzx implements Decompressor, LZXConstants {
|
||||
private int[] extraBits = new int[51];
|
||||
private int[] positionBase = new int[51];
|
||||
|
||||
private DecompressLzxTree mainTree;
|
||||
private DecompressLzxTree lengthTree;
|
||||
private DecompressLzxTree alignedTree;
|
||||
private DecompressLzxTree preTree;
|
||||
|
||||
private int wndSize;
|
||||
private int windowMask;
|
||||
private int mainElements;
|
||||
private int blocksRemaining;
|
||||
private int blockType;
|
||||
private int blockRemaining;
|
||||
|
||||
private int blockLength;
|
||||
private int windowPosition;
|
||||
private int R0;
|
||||
private int R1;
|
||||
private int R2;
|
||||
|
||||
private byte[] localWindow;
|
||||
|
||||
private int windowSize;
|
||||
private boolean readHeader;
|
||||
|
||||
private int outputPosition;
|
||||
private int index;
|
||||
private int length;
|
||||
|
||||
private byte[] inputBytes;
|
||||
|
||||
private boolean abort;
|
||||
|
||||
int bitsLeft;
|
||||
|
||||
private int blockAlignOffset;
|
||||
private int intelFileSize;
|
||||
private int intelCursorPos;
|
||||
|
||||
private byte[] savedBytes = new byte[6];
|
||||
|
||||
private boolean intelStarted;
|
||||
private int framesRead;
|
||||
|
||||
public DecompressLzx() {
|
||||
int i = 4;
|
||||
int j = 1;
|
||||
do {
|
||||
this.extraBits[i] = j;
|
||||
this.extraBits[i + 1] = j;
|
||||
i += 2;
|
||||
j++;
|
||||
} while (j <= 16);
|
||||
|
||||
do {
|
||||
this.extraBits[i++] = 17;
|
||||
} while (i < 51);
|
||||
|
||||
i = -2;
|
||||
for (j = 0; j < this.extraBits.length; j++) {
|
||||
this.positionBase[j] = i;
|
||||
i += 1 << this.extraBits[j];
|
||||
}
|
||||
|
||||
this.windowSize = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(int windowBits) throws CabException {
|
||||
this.wndSize = 1 << windowBits;
|
||||
this.windowMask = this.wndSize - 1;
|
||||
reset(windowBits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompress(byte[] inputBytes, byte[] outputBytes, int inputLength, int outputLength) throws CabException {
|
||||
this.abort = false;
|
||||
this.index = 0;
|
||||
this.inputBytes = inputBytes;
|
||||
this.length = inputBytes.length;
|
||||
|
||||
initBitStream();
|
||||
|
||||
int decompressedOutputLength = decompressLoop(outputLength);
|
||||
System.arraycopy(this.localWindow, this.outputPosition, outputBytes, 0, decompressedOutputLength);
|
||||
|
||||
if (this.framesRead++ < LZXConstants.E8_DISABLE_THRESHOLD && this.intelFileSize != 0) {
|
||||
decodeIntelBlock(outputBytes, decompressedOutputLength);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxGrowth() {
|
||||
return LZXConstants.MAX_GROWTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(int windowBits) throws CabException {
|
||||
if (this.windowSize == windowBits) {
|
||||
this.mainTree.reset();
|
||||
this.lengthTree.reset();
|
||||
this.alignedTree.reset();
|
||||
}
|
||||
else {
|
||||
maybeReset();
|
||||
int i = NUM_CHARS + this.mainElements * ALIGNED_NUM_ELEMENTS;
|
||||
this.localWindow = new byte[this.wndSize + 261];
|
||||
|
||||
this.preTree = new DecompressLzxTree(PRETREE_NUM_ELEMENTS, ALIGNED_NUM_ELEMENTS, this, null);
|
||||
this.mainTree = new DecompressLzxTree(i, 9, this, this.preTree);
|
||||
this.lengthTree = new DecompressLzxTree(SECONDARY_NUM_ELEMENTS, 6, this, this.preTree);
|
||||
this.alignedTree = new DecompressLzxTree(ALIGNED_NUM_ELEMENTS, NUM_PRIMARY_LENGTHS, this, this.preTree);
|
||||
}
|
||||
|
||||
this.windowSize = windowBits;
|
||||
this.R0 = this.R1 = this.R2 = 1;
|
||||
|
||||
this.blocksRemaining = 0;
|
||||
this.windowPosition = 0;
|
||||
this.intelCursorPos = 0;
|
||||
|
||||
this.readHeader = true;
|
||||
this.intelStarted = false;
|
||||
this.framesRead = 0;
|
||||
this.blockType = BLOCKTYPE_INVALID;
|
||||
}
|
||||
|
||||
private int decompressLoop(int bytesToRead) throws CabException {
|
||||
int i = bytesToRead;
|
||||
int lastWindowPosition = 0;
|
||||
int k;
|
||||
int m;
|
||||
|
||||
if (this.readHeader == true) {
|
||||
// read header
|
||||
if (readBits(1) == 1) {
|
||||
k = readBits(16);
|
||||
m = readBits(16);
|
||||
this.intelFileSize = k << 16 | m;
|
||||
} else {
|
||||
this.intelFileSize = 0;
|
||||
}
|
||||
this.readHeader = false;
|
||||
}
|
||||
|
||||
lastWindowPosition = 0;
|
||||
while (bytesToRead > 0) {
|
||||
if (this.blocksRemaining == 0) {
|
||||
if (this.blockType == BLOCKTYPE_UNCOMPRESSED) {
|
||||
if ((this.blockLength & 0x1) != 0 && /* realign bitstream to word */
|
||||
this.index < this.length) {
|
||||
this.index++;
|
||||
}
|
||||
this.blockType = BLOCKTYPE_INVALID;
|
||||
initBitStream();
|
||||
}
|
||||
|
||||
this.blockType = readBits(3);
|
||||
k = readBits(8);
|
||||
m = readBits(8);
|
||||
int n = readBits(8);
|
||||
|
||||
if (this.abort) {
|
||||
break;
|
||||
}
|
||||
|
||||
this.blockRemaining = this.blockLength = (k << 16) + (m << 8) + n;
|
||||
|
||||
if (this.blockType == BLOCKTYPE_ALIGNED) {
|
||||
this.alignedTree.readLengths();
|
||||
this.alignedTree.buildTable();
|
||||
// rest of aligned header is same as verbatim
|
||||
}
|
||||
|
||||
if (this.blockType == BLOCKTYPE_ALIGNED || this.blockType == BLOCKTYPE_VERBATIM) {
|
||||
this.mainTree.read();
|
||||
this.lengthTree.read();
|
||||
|
||||
this.mainTree.readLengths(0, NUM_CHARS);
|
||||
this.mainTree.readLengths(NUM_CHARS, NUM_CHARS + this.mainElements * ALIGNED_NUM_ELEMENTS);
|
||||
this.mainTree.buildTable();
|
||||
|
||||
|
||||
if (this.mainTree.LENS[0xE8] != 0) {
|
||||
this.intelStarted = true;
|
||||
}
|
||||
|
||||
this.lengthTree.readLengths(0, SECONDARY_NUM_ELEMENTS);
|
||||
this.lengthTree.buildTable();
|
||||
}
|
||||
else if (this.blockType == BLOCKTYPE_UNCOMPRESSED) {
|
||||
// because we can't assume otherwise
|
||||
this.intelStarted = true;
|
||||
this.index -= 2; // align the bitstream
|
||||
|
||||
|
||||
if (this.index < 0 || this.index + 12 >= this.length) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
|
||||
this.R0 = readInt();
|
||||
this.R1 = readInt();
|
||||
this.R2 = readInt();
|
||||
}
|
||||
else {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
}
|
||||
this.blocksRemaining = 1;
|
||||
|
||||
while (this.blockRemaining > 0 && bytesToRead > 0) {
|
||||
if (this.blockRemaining < bytesToRead) {
|
||||
k = this.blockRemaining;
|
||||
} else {
|
||||
k = bytesToRead;
|
||||
}
|
||||
decompressBlockActions(k);
|
||||
|
||||
this.blockRemaining -= k;
|
||||
bytesToRead -= k;
|
||||
lastWindowPosition += k;
|
||||
}
|
||||
|
||||
if (this.blockRemaining == 0) {
|
||||
this.blocksRemaining = 0;
|
||||
}
|
||||
|
||||
if (bytesToRead == 0 && this.blockAlignOffset != 16) {
|
||||
readNumberBits(this.blockAlignOffset);
|
||||
}
|
||||
}
|
||||
|
||||
if (lastWindowPosition != i) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
|
||||
if (this.windowPosition == 0) {
|
||||
this.outputPosition = this.wndSize - lastWindowPosition;
|
||||
} else {
|
||||
this.outputPosition = this.windowPosition - lastWindowPosition;
|
||||
}
|
||||
|
||||
return lastWindowPosition;
|
||||
}
|
||||
|
||||
private void decodeIntelBlock(byte[] bytes, int outLength) {
|
||||
if (outLength <= 6 || !this.intelStarted) {
|
||||
this.intelCursorPos += outLength;
|
||||
return;
|
||||
}
|
||||
|
||||
int cursorPos = this.intelCursorPos;
|
||||
int fileSize = this.intelFileSize;
|
||||
int abs_off = 0;
|
||||
|
||||
int adjustedOutLength = outLength - 6;
|
||||
|
||||
// save bytes
|
||||
while (abs_off < 6) {
|
||||
this.savedBytes[abs_off] = bytes[adjustedOutLength + abs_off];
|
||||
bytes[adjustedOutLength + abs_off] = -24;
|
||||
abs_off++;
|
||||
}
|
||||
|
||||
int dataIndex = 0;
|
||||
int cursor_pos = cursorPos + adjustedOutLength;
|
||||
|
||||
while (cursorPos < cursor_pos) {
|
||||
while (bytes[dataIndex++] == -24) {
|
||||
if (cursorPos >= cursor_pos) {
|
||||
break;
|
||||
}
|
||||
|
||||
abs_off = bytes[dataIndex] & 0xFF |
|
||||
(bytes[dataIndex + 1] & 0xFF) << 8 |
|
||||
(bytes[dataIndex + 2] & 0xFF) << 16 |
|
||||
(bytes[dataIndex + 3] & 0xFF) << 24;
|
||||
|
||||
if (abs_off >= 0) {
|
||||
if (abs_off < fileSize) {
|
||||
int rel_off = abs_off - cursorPos;
|
||||
|
||||
bytes[dataIndex] = (byte) (rel_off & 0xFF);
|
||||
bytes[dataIndex + 1] = (byte) (rel_off >>> 8 & 0xFF);
|
||||
bytes[dataIndex + 2] = (byte) (rel_off >>> 16 & 0xFF);
|
||||
bytes[dataIndex + 3] = (byte) (rel_off >>> 24);
|
||||
}
|
||||
}
|
||||
else if (abs_off >= -cursorPos) {
|
||||
int rel_off = abs_off + this.intelFileSize;
|
||||
|
||||
bytes[dataIndex] = (byte) (rel_off & 0xFF);
|
||||
bytes[dataIndex + 1] = (byte) (rel_off >>> 8 & 0xFF);
|
||||
bytes[dataIndex + 2] = (byte) (rel_off >>> 16 & 0xFF);
|
||||
bytes[dataIndex + 3] = (byte) (rel_off >>> 24);
|
||||
}
|
||||
|
||||
dataIndex += 4;
|
||||
cursorPos += 5;
|
||||
}
|
||||
cursorPos++;
|
||||
}
|
||||
|
||||
this.intelCursorPos = cursor_pos + 6;
|
||||
|
||||
// restore saved bytes
|
||||
abs_off = 0;
|
||||
while (abs_off < 6) {
|
||||
bytes[adjustedOutLength + abs_off] = this.savedBytes[abs_off];
|
||||
abs_off++;
|
||||
}
|
||||
}
|
||||
|
||||
private void decompressBlockActions(int bytesToRead) throws CabException {
|
||||
this.windowPosition &= this.windowMask;
|
||||
|
||||
if (this.windowPosition + bytesToRead > this.wndSize) {
|
||||
throw new CabException();
|
||||
}
|
||||
|
||||
switch (this.blockType) {
|
||||
case BLOCKTYPE_UNCOMPRESSED :
|
||||
uncompressedAlgo(bytesToRead);
|
||||
return;
|
||||
case BLOCKTYPE_ALIGNED :
|
||||
alignedAlgo(bytesToRead);
|
||||
return;
|
||||
case BLOCKTYPE_VERBATIM :
|
||||
verbatimAlgo(bytesToRead);
|
||||
return;
|
||||
default :
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void readNumberBits(int numBits) {
|
||||
this.bitsLeft <<= numBits;
|
||||
this.blockAlignOffset -= numBits;
|
||||
|
||||
if (this.blockAlignOffset <= 0) {
|
||||
this.bitsLeft |= readShort() << -this.blockAlignOffset;
|
||||
this.blockAlignOffset += 16;
|
||||
}
|
||||
}
|
||||
|
||||
private void initBitStream() {
|
||||
if (this.blockType != BLOCKTYPE_UNCOMPRESSED) {
|
||||
this.bitsLeft = readShort() << 16 | readShort();
|
||||
this.blockAlignOffset = 16;
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeReset() {
|
||||
this.mainElements = 4;
|
||||
int i = 4;
|
||||
do {
|
||||
i += 1 << this.extraBits[this.mainElements];
|
||||
this.mainElements++;
|
||||
} while (i < this.wndSize);
|
||||
}
|
||||
|
||||
private void verbatimAlgo(int this_run) throws CorruptCabException {
|
||||
int i = this.windowPosition;
|
||||
int mask = this.windowMask;
|
||||
byte[] windowPosition = this.localWindow;
|
||||
int r0 = this.R0;
|
||||
int r1 = this.R1;
|
||||
int r2 = this.R2;
|
||||
|
||||
int[] arrayOfInt1 = this.extraBits;
|
||||
int[] arrayOfInt2 = this.positionBase;
|
||||
|
||||
DecompressLzxTree mainTree = this.mainTree;
|
||||
DecompressLzxTree lengthTree = this.lengthTree;
|
||||
|
||||
while (this_run > 0) {
|
||||
int main_element = mainTree.decodeElement();
|
||||
if (main_element < NUM_CHARS) {
|
||||
windowPosition[i++] = (byte) main_element;
|
||||
this_run--;
|
||||
}
|
||||
/* is a match */
|
||||
else {
|
||||
main_element -= NUM_CHARS;
|
||||
|
||||
int match_length = main_element & NUM_PRIMARY_LENGTHS;
|
||||
if (match_length == NUM_PRIMARY_LENGTHS) {
|
||||
match_length += lengthTree.decodeElement();
|
||||
}
|
||||
|
||||
int matchOffset = main_element >>> 3;
|
||||
|
||||
/* check for repeated offsets (positions 0,1,2) */
|
||||
if (matchOffset == 0) {
|
||||
matchOffset = r0;
|
||||
}
|
||||
else if (matchOffset == 1) {
|
||||
matchOffset = r1;
|
||||
r1 = r0;
|
||||
r0 = matchOffset;
|
||||
}
|
||||
else if (matchOffset > 2) {
|
||||
// not repeated offset
|
||||
if (matchOffset > 3) {
|
||||
matchOffset = verbatimAlgo2(arrayOfInt1[matchOffset]) + arrayOfInt2[matchOffset];
|
||||
} else {
|
||||
matchOffset = 1;
|
||||
}
|
||||
|
||||
r2 = r1;
|
||||
r1 = r0;
|
||||
r0 = matchOffset;
|
||||
} else {
|
||||
matchOffset = r2;
|
||||
r2 = r0;
|
||||
r0 = matchOffset;
|
||||
}
|
||||
match_length += MIN_MATCH;
|
||||
|
||||
this_run -= match_length;
|
||||
|
||||
while (match_length > 0) {
|
||||
windowPosition[i] = windowPosition[i - matchOffset & mask];
|
||||
i++;
|
||||
match_length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this_run != 0) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
|
||||
this.R0 = r0;
|
||||
this.R1 = r1;
|
||||
this.R2 = r2;
|
||||
this.windowPosition = i;
|
||||
}
|
||||
|
||||
private int verbatimAlgo2(int position) {
|
||||
int i = this.bitsLeft >>> 32 - position;
|
||||
|
||||
this.bitsLeft <<= position;
|
||||
this.blockAlignOffset -= position;
|
||||
|
||||
if (this.blockAlignOffset <= 0) {
|
||||
this.bitsLeft |= readShort() << -this.blockAlignOffset;
|
||||
this.blockAlignOffset += 16;
|
||||
|
||||
if (this.blockAlignOffset <= 0) {
|
||||
this.bitsLeft |= readShort() << -this.blockAlignOffset;
|
||||
this.blockAlignOffset += 16;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
private void alignedAlgo(int this_run) throws CorruptCabException {
|
||||
int windowPos = this.windowPosition;
|
||||
int mask = this.windowMask;
|
||||
byte[] window = this.localWindow;
|
||||
int r0 = this.R0;
|
||||
int r1 = this.R1;
|
||||
int r2 = this.R2;
|
||||
|
||||
while (this_run > 0) {
|
||||
int mainElement = this.mainTree.decodeElement();
|
||||
|
||||
if (mainElement < NUM_CHARS) {
|
||||
window[windowPos] = (byte) mainElement;
|
||||
windowPos = windowPos + 1 & mask;
|
||||
this_run--;
|
||||
}
|
||||
/* is a match */
|
||||
else {
|
||||
mainElement -= NUM_CHARS;
|
||||
|
||||
int matchLength = mainElement & NUM_PRIMARY_LENGTHS;
|
||||
if (matchLength == NUM_PRIMARY_LENGTHS) {
|
||||
matchLength += this.lengthTree.decodeElement();
|
||||
}
|
||||
|
||||
int match_offset = mainElement >>> 3;
|
||||
|
||||
if (match_offset > 2) {
|
||||
// not repeated offset
|
||||
int extra = this.extraBits[match_offset];
|
||||
match_offset = this.positionBase[match_offset];
|
||||
|
||||
if (extra > 3) {
|
||||
// verbatim and aligned bits
|
||||
match_offset += (readBits(extra - 3) << 3) + this.alignedTree.decodeElement();
|
||||
}
|
||||
else if (extra == 3) {
|
||||
// aligned bits only
|
||||
match_offset += this.alignedTree.decodeElement();
|
||||
}
|
||||
else if (extra > 0) {
|
||||
// verbatim bits only
|
||||
match_offset += readBits(extra);
|
||||
}
|
||||
else {
|
||||
match_offset = 1;
|
||||
}
|
||||
|
||||
// update repeated offset LRU queue
|
||||
r2 = r1;
|
||||
r1 = r0;
|
||||
r0 = match_offset;
|
||||
}
|
||||
else if (match_offset == 0) {
|
||||
match_offset = r0;
|
||||
}
|
||||
else if (match_offset == 1) {
|
||||
match_offset = r1;
|
||||
r1 = r0;
|
||||
r0 = match_offset;
|
||||
} else {
|
||||
match_offset = r2;
|
||||
r2 = r0;
|
||||
r0 = match_offset;
|
||||
}
|
||||
|
||||
matchLength += MIN_MATCH;
|
||||
this_run -= matchLength;
|
||||
|
||||
while (matchLength > 0) {
|
||||
window[windowPos] = window[windowPos - match_offset & mask];
|
||||
windowPos = windowPos + 1 & mask;
|
||||
matchLength--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this_run != 0) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
|
||||
this.R0 = r0;
|
||||
this.R1 = r1;
|
||||
this.R2 = r2;
|
||||
this.windowPosition = windowPos;
|
||||
}
|
||||
|
||||
private int readShort() {
|
||||
if (this.index < this.length) {
|
||||
int i = this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8;
|
||||
this.index += 2;
|
||||
return i;
|
||||
}
|
||||
|
||||
this.abort = true;
|
||||
this.index = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int readBits(int numBitsToRead) {
|
||||
int i = this.bitsLeft >>> 32 - numBitsToRead;
|
||||
readNumberBits(numBitsToRead);
|
||||
return i;
|
||||
}
|
||||
|
||||
private void uncompressedAlgo(int length) throws CorruptCabException {
|
||||
if (this.index + length > this.length || this.windowPosition + length > this.wndSize) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
|
||||
this.intelStarted = true;
|
||||
System.arraycopy(this.inputBytes, this.index, this.localWindow, this.windowPosition, length);
|
||||
this.index += length;
|
||||
this.windowPosition += length;
|
||||
}
|
||||
|
||||
private int readInt() {
|
||||
int i = this.inputBytes[this.index] & 0xFF |
|
||||
(this.inputBytes[this.index + 1] & 0xFF) << 8 |
|
||||
(this.inputBytes[this.index + 2] & 0xFF) << 16 |
|
||||
(this.inputBytes[this.index + 3] & 0xFF) << 24;
|
||||
this.index += 4;
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
261
src/dorkbox/util/cab/decompress/lzx/DecompressLzxTree.java
Normal file
261
src/dorkbox/util/cab/decompress/lzx/DecompressLzxTree.java
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* 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.util.cab.decompress.lzx;
|
||||
|
||||
import dorkbox.util.cab.CorruptCabException;
|
||||
|
||||
final class DecompressLzxTree implements LZXConstants {
|
||||
private int size;
|
||||
private int[] aa;
|
||||
int[] LENS;
|
||||
|
||||
private int[] a1;
|
||||
private int[] a2;
|
||||
private int[] table;
|
||||
|
||||
private int b1;
|
||||
private int b2;
|
||||
private int b3;
|
||||
private int b4;
|
||||
|
||||
private DecompressLzx decompressor;
|
||||
private DecompressLzxTree root;
|
||||
|
||||
private int[] c1 = new int[17];
|
||||
private int[] c2 = new int[17];
|
||||
private int[] c3 = new int[18];
|
||||
private static final byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
|
||||
|
||||
DecompressLzxTree(int size, int paramInt2, DecompressLzx decompressor, DecompressLzxTree root) {
|
||||
this.size = size;
|
||||
this.b1 = paramInt2;
|
||||
this.decompressor = decompressor;
|
||||
this.root = root;
|
||||
this.b2 = 1 << this.b1;
|
||||
this.b3 = this.b2 - 1;
|
||||
this.b4 = 32 - this.b1;
|
||||
this.a1 = new int[this.size * 2];
|
||||
this.a2 = new int[this.size * 2];
|
||||
this.table = new int[this.b2];
|
||||
this.aa = new int[this.size];
|
||||
this.LENS = new int[this.size];
|
||||
}
|
||||
|
||||
void reset() {
|
||||
for (int i = 0; i < this.size; i++) {
|
||||
this.LENS[i] = 0;
|
||||
this.aa[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void readLengths() {
|
||||
for (int i = 0; i < this.size; i++) {
|
||||
this.LENS[i] = this.decompressor.readBits(3);
|
||||
}
|
||||
}
|
||||
|
||||
void readLengths(int first, int last) throws CorruptCabException {
|
||||
for(int i = 0;i<20;i++) {
|
||||
this.root.LENS[i] = (byte) this.decompressor.readBits(4);
|
||||
}
|
||||
|
||||
this.root.buildTable();
|
||||
|
||||
for (int i = first; i < last; i++) {
|
||||
int k = this.root.decodeElement();
|
||||
int j;
|
||||
|
||||
if (k == 17) {
|
||||
j = this.decompressor.readBits(4) + 4;
|
||||
if (i + j >= last) {
|
||||
j = last - i;
|
||||
}
|
||||
while (j-- > 0) {
|
||||
this.LENS[i++] = 0;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
else if (k == 18) {
|
||||
j = this.decompressor.readBits(5) + 20;
|
||||
if (i + j >= last) {
|
||||
j = last - i;
|
||||
}
|
||||
while (j-- > 0) {
|
||||
this.LENS[i++] = 0;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
else if (k == 19) {
|
||||
j = this.decompressor.readBits(1) + 4;
|
||||
if (i + j >= last) {
|
||||
j = last - i;
|
||||
}
|
||||
|
||||
k = this.root.decodeElement();
|
||||
int m = array[this.aa[i] - k + 17];
|
||||
|
||||
while (j-- > 0) {
|
||||
this.LENS[i++] = m;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
else {
|
||||
this.LENS[i] = array[this.aa[i] - k + 17];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void buildTable() throws CorruptCabException {
|
||||
int[] table = this.table;
|
||||
int[] c3 = this.c3;
|
||||
int b1 = this.b1;
|
||||
int i = 1;
|
||||
|
||||
do {
|
||||
this.c1[i] = 0;
|
||||
i++;
|
||||
} while (i <= 16);
|
||||
|
||||
for (i = 0; i < this.size; i++) {
|
||||
this.c1[this.LENS[i]]++;
|
||||
}
|
||||
|
||||
c3[1] = 0;
|
||||
i = 1;
|
||||
do {
|
||||
c3[i + 1] = c3[i] + (this.c1[i] << 16 - i);
|
||||
i++;
|
||||
} while (i <= 16);
|
||||
if (c3[17] != 65536) {
|
||||
if (c3[17] == 0) {
|
||||
for (i = 0; i < this.b2; i++) {
|
||||
table[i] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
|
||||
int i2 = 16 - b1;
|
||||
for (i = 1; i <= b1; i++) {
|
||||
c3[i] >>>= i2;
|
||||
this.c2[i] = 1 << b1 - i;
|
||||
}
|
||||
|
||||
while (i <= 16) {
|
||||
this.c2[i] = 1 << 16 - i;
|
||||
i++;
|
||||
}
|
||||
|
||||
i = c3[b1 + 1] >>> i2;
|
||||
if (i != 65536) {
|
||||
while (i < this.b2) {
|
||||
table[i] = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
int k = this.size;
|
||||
for (int j = 0; j < this.size; j++) {
|
||||
int i1 = this.LENS[j];
|
||||
if (i1 != 0) {
|
||||
int m = c3[i1] + this.c2[i1];
|
||||
if (i1 <= b1) {
|
||||
if (m > this.b2) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
for (i = c3[i1]; i < m; i++) {
|
||||
table[i] = j;
|
||||
}
|
||||
c3[i1] = m;
|
||||
} else {
|
||||
int n = c3[i1];
|
||||
c3[i1] = m;
|
||||
int i6 = n >>> i2;
|
||||
int i5 = 2;
|
||||
i = i1 - b1;
|
||||
n <<= b1;
|
||||
|
||||
do {
|
||||
int i4;
|
||||
if (i5 == 2) {
|
||||
i4 = table[i6];
|
||||
}
|
||||
else if (i5 == 0) {
|
||||
i4 = this.a1[i6];
|
||||
}
|
||||
else {
|
||||
i4 = this.a2[i6];
|
||||
}
|
||||
|
||||
if (i4 == 0) {
|
||||
this.a1[k] = 0;
|
||||
this.a2[k] = 0;
|
||||
if (i5 == 2) {
|
||||
table[i6] = -k;
|
||||
} else if (i5 == 0) {
|
||||
this.a1[i6] = -k;
|
||||
} else {
|
||||
this.a2[i6] = -k;
|
||||
}
|
||||
i4 = -k;
|
||||
k++;
|
||||
}
|
||||
|
||||
i6 = -i4;
|
||||
if ((n & 0x8000) == 0) {
|
||||
i5 = 0;
|
||||
} else {
|
||||
i5 = 1;
|
||||
}
|
||||
n <<= 1;
|
||||
i--;
|
||||
} while (i != 0);
|
||||
|
||||
if (i5 == 0) {
|
||||
this.a1[i6] = j;
|
||||
} else {
|
||||
this.a2[i6] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void read() {
|
||||
System.arraycopy(this.LENS, 0, this.aa, 0, this.size);
|
||||
}
|
||||
|
||||
int decodeElement() {
|
||||
int i = this.table[this.decompressor.bitsLeft >>> this.b4 & this.b3];
|
||||
|
||||
while (i < 0) {
|
||||
int j = 1 << this.b4 - 1;
|
||||
do {
|
||||
i = -i;
|
||||
if ((this.decompressor.bitsLeft & j) == 0) {
|
||||
i = this.a1[i];
|
||||
} else {
|
||||
i = this.a2[i];
|
||||
}
|
||||
j >>>= 1;
|
||||
} while (i < 0);
|
||||
}
|
||||
|
||||
this.decompressor.readNumberBits(this.LENS[i]);
|
||||
return i;
|
||||
}
|
||||
}
|
39
src/dorkbox/util/cab/decompress/lzx/LZXConstants.java
Normal file
39
src/dorkbox/util/cab/decompress/lzx/LZXConstants.java
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.util.cab.decompress.lzx;
|
||||
|
||||
public interface LZXConstants {
|
||||
public static final int PRETREE_NUM_ELEMENTS = 20;
|
||||
public static final int NUM_CHARS = 256;
|
||||
|
||||
public static final int SECONDARY_NUM_ELEMENTS = 249;
|
||||
|
||||
public static final int ALIGNED_NUM_ELEMENTS = 8;
|
||||
public static final int NUM_PRIMARY_LENGTHS = 7;
|
||||
|
||||
public static final int MIN_MATCH = 2;
|
||||
public static final int MAX_MATCH = 257;
|
||||
|
||||
public static final int NUM_REPEATED_OFFSETS = 3;
|
||||
public static final int MAX_GROWTH = 6144;
|
||||
|
||||
public static final int E8_DISABLE_THRESHOLD = 32768;
|
||||
|
||||
public static final int BLOCKTYPE_VERBATIM = 1;
|
||||
public static final int BLOCKTYPE_ALIGNED = 2;
|
||||
public static final int BLOCKTYPE_UNCOMPRESSED = 3;
|
||||
public static final int BLOCKTYPE_INVALID = 4;
|
||||
}
|
43
src/dorkbox/util/cab/decompress/none/DecompressNone.java
Normal file
43
src/dorkbox/util/cab/decompress/none/DecompressNone.java
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.util.cab.decompress.none;
|
||||
|
||||
import dorkbox.util.cab.CabException;
|
||||
import dorkbox.util.cab.CorruptCabException;
|
||||
import dorkbox.util.cab.decompress.Decompressor;
|
||||
|
||||
public final class DecompressNone implements Decompressor {
|
||||
@Override
|
||||
public void init(int windowBits) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompress(byte[] inputBytes, byte[] outputBytes, int inputLength, int outputLength) throws CabException {
|
||||
if (inputLength != outputLength) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
System.arraycopy(inputBytes, 0, outputBytes, 0, outputLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxGrowth() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(int windowBits) {
|
||||
}
|
||||
}
|
404
src/dorkbox/util/cab/decompress/zip/DecompressZip.java
Normal file
404
src/dorkbox/util/cab/decompress/zip/DecompressZip.java
Normal file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* 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.util.cab.decompress.zip;
|
||||
|
||||
import dorkbox.util.cab.CabException;
|
||||
import dorkbox.util.cab.CorruptCabException;
|
||||
import dorkbox.util.cab.decompress.Decompressor;
|
||||
|
||||
public final class DecompressZip implements Decompressor {
|
||||
private static final int[] ar1 = {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};
|
||||
|
||||
private static final int[] ar2 = {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};
|
||||
|
||||
private static final int[] ar3 = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
|
||||
|
||||
private byte[] bytes = new byte[320];
|
||||
private byte[] inputBytes;
|
||||
private byte[] outputBytes;
|
||||
|
||||
private int index;
|
||||
private int inputPlus4;
|
||||
|
||||
int int1;
|
||||
|
||||
private int int2;
|
||||
private int int3;
|
||||
private int outputLength;
|
||||
|
||||
private DecompressZipState state1;
|
||||
private DecompressZipState state2;
|
||||
private DecompressZipState state3;
|
||||
|
||||
@Override
|
||||
public void init(int windowBits) {
|
||||
this.state1 = new DecompressZipState(288, 9, this);
|
||||
this.state2 = new DecompressZipState(32, 7, this);
|
||||
this.state3 = new DecompressZipState(19, 7, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompress(byte[] inputBytes, byte[] outputBytes, int inputLength, int outputLength) throws CabException {
|
||||
this.inputBytes = inputBytes;
|
||||
this.outputBytes = outputBytes;
|
||||
|
||||
if (this.inputBytes[0] != 67 || this.inputBytes[1] != 75) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
if (outputBytes.length < 33027) {
|
||||
throw new CabException();
|
||||
}
|
||||
if (inputBytes.length < 28) {
|
||||
throw new CabException();
|
||||
}
|
||||
|
||||
this.index = 2;
|
||||
this.inputPlus4 = inputLength + 4;
|
||||
this.outputLength = outputLength;
|
||||
this.int3 = 0;
|
||||
|
||||
maybeDecompress();
|
||||
while (this.int3 < this.outputLength) {
|
||||
decompressMore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxGrowth() {
|
||||
return 28;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(int windowBits) {
|
||||
}
|
||||
|
||||
private void maybeDecompress() throws CabException {
|
||||
if (this.index + 4 > this.inputPlus4) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
this.int1 = readShort() | readShort() << 16;
|
||||
this.int2 = 16;
|
||||
}
|
||||
|
||||
void add(int paramInt) {
|
||||
this.int1 >>>= paramInt;
|
||||
this.int2 -= paramInt;
|
||||
if (this.int2 <= 0) {
|
||||
this.int2 += 16;
|
||||
this.int1 |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << this.int2;
|
||||
this.index += 2;
|
||||
}
|
||||
}
|
||||
|
||||
private void check() throws CabException {
|
||||
if (this.index > this.inputPlus4) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
}
|
||||
|
||||
private void b() throws CabException {
|
||||
int i = this.int3;
|
||||
int j = this.outputLength;
|
||||
byte[] arrayOfByte1 = this.outputBytes;
|
||||
int[] arrayOfInt1 = this.state1.intA2;
|
||||
int[] arrayOfInt2 = this.state1.intA3;
|
||||
int[] arrayOfInt3 = this.state1.intA4;
|
||||
byte[] arrayOfByte2 = this.state1.byteA;
|
||||
int[] arrayOfInt4 = this.state2.intA2;
|
||||
int[] arrayOfInt5 = this.state2.intA3;
|
||||
int[] arrayOfInt6 = this.state2.intA4;
|
||||
byte[] arrayOfByte3 = this.state2.byteA;
|
||||
int k = this.int1;
|
||||
int m = this.int2;
|
||||
do {
|
||||
if (this.index > this.inputPlus4) {
|
||||
break;
|
||||
}
|
||||
int n = arrayOfInt1[k & 0x1FF];
|
||||
int i2;
|
||||
while (n < 0) {
|
||||
i2 = 512;
|
||||
do {
|
||||
n = -n;
|
||||
if ((k & i2) == 0) {
|
||||
n = arrayOfInt2[n];
|
||||
} else {
|
||||
n = arrayOfInt3[n];
|
||||
}
|
||||
i2 <<= 1;
|
||||
} while (n < 0);
|
||||
}
|
||||
int i1 = arrayOfByte2[n];
|
||||
k >>>= i1;
|
||||
m -= i1;
|
||||
if (m <= 0) {
|
||||
m += 16;
|
||||
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
|
||||
this.index += 2;
|
||||
}
|
||||
if (n < 256) {
|
||||
arrayOfByte1[i++] = (byte) n;
|
||||
} else {
|
||||
n -= 257;
|
||||
if (n < 0) {
|
||||
break;
|
||||
}
|
||||
if (n < 8) {
|
||||
n += 3;
|
||||
} else if (n != 28) {
|
||||
int i4 = n - 4 >>> 2;
|
||||
n = ar1[n] + (k & (1 << i4) - 1);
|
||||
k >>>= i4;
|
||||
m -= i4;
|
||||
if (m <= 0) {
|
||||
m += 16;
|
||||
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
|
||||
this.index += 2;
|
||||
}
|
||||
} else {
|
||||
n = 258;
|
||||
}
|
||||
i2 = arrayOfInt4[k & 0x7F];
|
||||
while (i2 < 0) {
|
||||
int i5 = 128;
|
||||
do {
|
||||
i2 = -i2;
|
||||
if ((k & i5) == 0) {
|
||||
i2 = arrayOfInt5[i2];
|
||||
} else {
|
||||
i2 = arrayOfInt6[i2];
|
||||
}
|
||||
i5 <<= 1;
|
||||
} while (i2 < 0);
|
||||
}
|
||||
i1 = arrayOfByte3[i2];
|
||||
k >>>= i1;
|
||||
m -= i1;
|
||||
if (m <= 0) {
|
||||
m += 16;
|
||||
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
|
||||
this.index += 2;
|
||||
}
|
||||
int i4 = i2 - 2 >> 1;
|
||||
int i3;
|
||||
if (i4 > 0) {
|
||||
i3 = ar2[i2] + (k & (1 << i4) - 1);
|
||||
k >>>= i4;
|
||||
m -= i4;
|
||||
if (m <= 0) {
|
||||
m += 16;
|
||||
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
|
||||
this.index += 2;
|
||||
}
|
||||
} else {
|
||||
i3 = i2 + 1;
|
||||
}
|
||||
do {
|
||||
arrayOfByte1[i] = arrayOfByte1[i - i3 & 0x7FFF];
|
||||
i++;
|
||||
n--;
|
||||
} while (n != 0);
|
||||
}
|
||||
} while (i <= j);
|
||||
this.int3 = i;
|
||||
this.int1 = k;
|
||||
this.int2 = m;
|
||||
check();
|
||||
}
|
||||
|
||||
private void readStuffcommon() throws CabException {
|
||||
this.state1.c();
|
||||
this.state2.c();
|
||||
}
|
||||
|
||||
private void c() {
|
||||
int i = 0;
|
||||
do {
|
||||
this.state1.byteA[i] = 8;
|
||||
i++;
|
||||
} while (i <= 143);
|
||||
i = 144;
|
||||
do {
|
||||
this.state1.byteA[i] = 9;
|
||||
i++;
|
||||
} while (i <= 255);
|
||||
i = 256;
|
||||
do {
|
||||
this.state1.byteA[i] = 7;
|
||||
i++;
|
||||
} while (i <= 279);
|
||||
i = 280;
|
||||
do {
|
||||
this.state1.byteA[i] = 8;
|
||||
i++;
|
||||
} while (i <= 287);
|
||||
i = 0;
|
||||
do {
|
||||
this.state2.byteA[i] = 5;
|
||||
i++;
|
||||
} while (i < 32);
|
||||
}
|
||||
|
||||
private int makeShort(byte byte1, byte byte2) {
|
||||
return byte1 & 0xFF | (byte2 & 0xFF) << 8;
|
||||
}
|
||||
|
||||
private void d() throws CabException {
|
||||
check();
|
||||
int i = calc(5) + 257;
|
||||
int j = calc(5) + 1;
|
||||
int k = calc(4) + 4;
|
||||
for (int n = 0; n < k; n++) {
|
||||
this.state3.byteA[ar3[n]] = (byte) calc(3);
|
||||
check();
|
||||
}
|
||||
for (int n = k; n < ar3.length; n++) {
|
||||
this.state3.byteA[ar3[n]] = 0;
|
||||
}
|
||||
this.state3.c();
|
||||
int m = i + j;
|
||||
int n = 0;
|
||||
while (n < m) {
|
||||
check();
|
||||
int i1 = (byte) this.state3.read();
|
||||
if (i1 <= 15) {
|
||||
this.bytes[n++] = (byte) i1;
|
||||
} else {
|
||||
int i3;
|
||||
int i2;
|
||||
if (i1 == 16) {
|
||||
if (n == 0) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
i3 = this.bytes[n - 1];
|
||||
i2 = calc(2) + 3;
|
||||
if (n + i2 > m) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
for (int i4 = 0; i4 < i2; i4++) {
|
||||
this.bytes[n++] = (byte) i3;
|
||||
}
|
||||
} else if (i1 == 17) {
|
||||
i2 = calc(3) + 3;
|
||||
if (n + i2 > m) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
for (i3 = 0; i3 < i2; i3++) {
|
||||
this.bytes[n++] = 0;
|
||||
}
|
||||
} else {
|
||||
i2 = calc(7) + 11;
|
||||
if (n + i2 > m) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
for (i3 = 0; i3 < i2; i3++) {
|
||||
this.bytes[n++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.arraycopy(this.bytes, 0, this.state1.byteA, 0, i);
|
||||
for (n = i; n < 288; n++) {
|
||||
this.state1.byteA[n] = 0;
|
||||
}
|
||||
for (n = 0; n < j; n++) {
|
||||
this.state2.byteA[n] = this.bytes[n + i];
|
||||
}
|
||||
for (n = j; n < 32; n++) {
|
||||
this.state2.byteA[n] = 0;
|
||||
}
|
||||
if (this.state1.byteA[256] == 0) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
}
|
||||
|
||||
private int readShort() {
|
||||
int i = this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8;
|
||||
this.index += 2;
|
||||
return i;
|
||||
}
|
||||
|
||||
private int calc(int paramInt) {
|
||||
int i = this.int1 & (1 << paramInt) - 1;
|
||||
add(paramInt);
|
||||
return i;
|
||||
}
|
||||
|
||||
private void decompressMore() throws CabException {
|
||||
@SuppressWarnings("unused")
|
||||
int i = calc(1);
|
||||
int j = calc(2);
|
||||
if (j == 2) {
|
||||
d();
|
||||
readStuffcommon();
|
||||
b();
|
||||
return;
|
||||
}
|
||||
if (j == 1) {
|
||||
c();
|
||||
readStuffcommon();
|
||||
b();
|
||||
return;
|
||||
}
|
||||
if (j == 0) {
|
||||
e();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new CabException();
|
||||
}
|
||||
|
||||
private void e() throws CabException {
|
||||
mod();
|
||||
if (this.index >= this.inputPlus4) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
int i = makeShort(this.inputBytes[this.index], this.inputBytes[this.index + 1]);
|
||||
int j = makeShort(this.inputBytes[this.index + 2], this.inputBytes[this.index + 3]);
|
||||
|
||||
if ((short) i != (short) (j ^ 0xFFFFFFFF)) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
|
||||
if (this.index + i > this.inputPlus4 || this.int3 + i > this.outputLength) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
|
||||
maybeDecompress();
|
||||
|
||||
System.arraycopy(this.inputBytes, this.index, this.outputBytes, this.int3, i);
|
||||
this.int3 += i;
|
||||
if (this.int3 < this.outputLength) {
|
||||
maybeDecompress();
|
||||
}
|
||||
}
|
||||
|
||||
private void mod() {
|
||||
if (this.int2 == 16) {
|
||||
this.index -= 4;
|
||||
} else if (this.int2 >= 8) {
|
||||
this.index -= 3;
|
||||
} else {
|
||||
this.index -= 2;
|
||||
}
|
||||
if (this.index < 0) {
|
||||
this.index = 0;
|
||||
}
|
||||
this.int2 = 0;
|
||||
}
|
||||
}
|
176
src/dorkbox/util/cab/decompress/zip/DecompressZipState.java
Normal file
176
src/dorkbox/util/cab/decompress/zip/DecompressZipState.java
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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.util.cab.decompress.zip;
|
||||
|
||||
import dorkbox.util.cab.CorruptCabException;
|
||||
|
||||
final class DecompressZipState {
|
||||
private int intA;
|
||||
private int[] intA1;
|
||||
|
||||
private int intB;
|
||||
private int intC;
|
||||
private int intD;
|
||||
|
||||
private DecompressZip decompressZipImpl;
|
||||
|
||||
byte[] byteA;
|
||||
int[] intA2;
|
||||
int[] intA3;
|
||||
int[] intA4;
|
||||
|
||||
DecompressZipState(int paramInt1, int paramInt2, DecompressZip decompressZipImpl) {
|
||||
this.intA = paramInt1;
|
||||
this.decompressZipImpl = decompressZipImpl;
|
||||
this.byteA = new byte[paramInt1];
|
||||
this.intA1 = new int[paramInt1];
|
||||
this.intB = paramInt2;
|
||||
this.intC = 1 << this.intB;
|
||||
this.intD = this.intC - 1;
|
||||
this.intA2 = new int[1 << this.intB];
|
||||
this.intA3 = new int[this.intA * 2];
|
||||
this.intA4 = new int[this.intA * 2];
|
||||
}
|
||||
|
||||
void c() throws CorruptCabException {
|
||||
int[] arrayOfInt1 = new int[17];
|
||||
int[] arrayOfInt2 = new int[17];
|
||||
int k = 0;
|
||||
do {
|
||||
arrayOfInt1[k] = 0;
|
||||
k++;
|
||||
} while (k <= 16);
|
||||
for (k = 0; k < this.intA; k++) {
|
||||
arrayOfInt1[this.byteA[k]] += 1;
|
||||
}
|
||||
int m;
|
||||
for (k = this.intB; k <= 16; k++) {
|
||||
if (arrayOfInt1[k] > 0) {
|
||||
for (m = 0; m < this.intC; m++) {
|
||||
this.intA2[m] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
int i = 0;
|
||||
arrayOfInt1[0] = 0;
|
||||
k = 1;
|
||||
do {
|
||||
i = i + arrayOfInt1[k - 1] << 1;
|
||||
arrayOfInt2[k] = i;
|
||||
k++;
|
||||
} while (k <= 16);
|
||||
for (k = 0; k < this.intA; k++) {
|
||||
m = this.byteA[k];
|
||||
if (m > 0) {
|
||||
this.intA1[k] = shiftAndOtherStuff(arrayOfInt2[m], m);
|
||||
arrayOfInt2[m] += 1;
|
||||
}
|
||||
}
|
||||
int j = this.intA;
|
||||
for (k = 0; k < this.intA; k++) {
|
||||
int n = this.byteA[k];
|
||||
m = this.intA1[k];
|
||||
if (n > 0) {
|
||||
int i1;
|
||||
int i2;
|
||||
int i3;
|
||||
if (n <= this.intB) {
|
||||
i1 = 1 << this.intB - n;
|
||||
i2 = 1 << n;
|
||||
if (m >= i2) {
|
||||
throw new CorruptCabException();
|
||||
}
|
||||
for (i3 = 0; i3 < i1; i3++) {
|
||||
this.intA2[m] = k;
|
||||
m += i2;
|
||||
}
|
||||
} else {
|
||||
i1 = n - this.intB;
|
||||
i2 = 1 << this.intB;
|
||||
int i4 = m & this.intD;
|
||||
i3 = 2;
|
||||
do {
|
||||
int i5;
|
||||
if (i3 == 2) {
|
||||
i5 = this.intA2[i4];
|
||||
} else if (i3 == 1) {
|
||||
i5 = this.intA4[i4];
|
||||
} else {
|
||||
i5 = this.intA3[i4];
|
||||
}
|
||||
if (i5 == 0) {
|
||||
this.intA3[j] = 0;
|
||||
this.intA4[j] = 0;
|
||||
if (i3 == 2) {
|
||||
this.intA2[i4] = -j;
|
||||
} else if (i3 == 1) {
|
||||
this.intA4[i4] = -j;
|
||||
} else {
|
||||
this.intA3[i4] = -j;
|
||||
}
|
||||
i5 = -j;
|
||||
j++;
|
||||
}
|
||||
i4 = -i5;
|
||||
if ((m & i2) == 0) {
|
||||
i3 = 0;
|
||||
} else {
|
||||
i3 = 1;
|
||||
}
|
||||
i2 <<= 1;
|
||||
i1--;
|
||||
} while (i1 != 0);
|
||||
if (i3 == 0) {
|
||||
this.intA3[i4] = k;
|
||||
} else {
|
||||
this.intA4[i4] = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int shiftAndOtherStuff(int paramInt1, int paramInt2) {
|
||||
int i = 0;
|
||||
do {
|
||||
i |= paramInt1 & 0x1;
|
||||
i <<= 1;
|
||||
paramInt1 >>>= 1;
|
||||
paramInt2--;
|
||||
} while (paramInt2 > 0);
|
||||
|
||||
return i >>> 1;
|
||||
}
|
||||
|
||||
int read() {
|
||||
int i = this.intA2[this.decompressZipImpl.int1 & this.intD];
|
||||
while (i < 0) {
|
||||
int j = 1 << this.intB;
|
||||
do {
|
||||
i = -i;
|
||||
if ((this.decompressZipImpl.int1 & j) == 0) {
|
||||
i = this.intA3[i];
|
||||
} else {
|
||||
i = this.intA4[i];
|
||||
}
|
||||
j <<= 1;
|
||||
} while (i < 0);
|
||||
}
|
||||
this.decompressZipImpl.add(this.byteA[i]);
|
||||
return i;
|
||||
}
|
||||
}
|
54
src/dorkbox/util/cab/structure/CabConstants.java
Normal file
54
src/dorkbox/util/cab/structure/CabConstants.java
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.util.cab.structure;
|
||||
|
||||
public interface CabConstants {
|
||||
public static final int CAB_BLOCK_SIZE = 32768;
|
||||
public static final int CAB_BLOCK_SIZE_THRESH = 32767;
|
||||
|
||||
public static final int COMPRESSION_TYPE_NONE = 0;
|
||||
public static final int COMPRESSION_TYPE_MSZIP = 1;
|
||||
public static final int COMPRESSION_TYPE_QUANTUM = 2;
|
||||
public static final int COMPRESSION_TYPE_LZX = 3;
|
||||
|
||||
public static final int RESERVED_CFHEADER = 1;
|
||||
public static final int RESERVED_CFFOLDER = 2;
|
||||
|
||||
public static final int RESERVED_CFDATA = 3;
|
||||
|
||||
public static final 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.
|
||||
*/
|
||||
static final 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.
|
||||
*/
|
||||
static final 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.
|
||||
*/
|
||||
static final int FLAG_RESERVE_PRESENT = 0x0004;
|
||||
}
|
66
src/dorkbox/util/cab/structure/CabEnumerator.java
Normal file
66
src/dorkbox/util/cab/structure/CabEnumerator.java
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.util.cab.structure;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import dorkbox.util.cab.CabDecoder;
|
||||
|
||||
public final class CabEnumerator implements Enumeration<Object> {
|
||||
private int fileCount = 0;
|
||||
private int folderCount = 0;
|
||||
|
||||
private CabDecoder cabDecoder;
|
||||
|
||||
private boolean b;
|
||||
private int folderIndex;
|
||||
|
||||
@Override
|
||||
public Object nextElement() {
|
||||
if (!this.b) {
|
||||
if (this.fileCount < this.cabDecoder.header.cFiles) {
|
||||
return this.cabDecoder.files[this.fileCount++];
|
||||
}
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
if (this.cabDecoder.files[this.fileCount].iFolder != this.folderIndex) {
|
||||
this.folderIndex = this.cabDecoder.files[this.fileCount].iFolder;
|
||||
|
||||
if (this.folderCount < this.cabDecoder.folders.length) {
|
||||
return this.cabDecoder.folders[this.folderCount++];
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fileCount < this.cabDecoder.header.cFiles) {
|
||||
return this.cabDecoder.files[this.fileCount++];
|
||||
}
|
||||
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
public CabEnumerator(CabDecoder decoder, boolean b) {
|
||||
this.cabDecoder = decoder;
|
||||
this.b = b;
|
||||
this.folderIndex = -2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return this.fileCount < this.cabDecoder.header.cFiles;
|
||||
}
|
||||
}
|
249
src/dorkbox/util/cab/structure/CabFileEntry.java
Normal file
249
src/dorkbox/util/cab/structure/CabFileEntry.java
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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.util.cab.structure;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Date;
|
||||
|
||||
import dorkbox.util.bytes.LittleEndian;
|
||||
import dorkbox.util.cab.CabException;
|
||||
import dorkbox.util.cab.CorruptCabException;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
70
src/dorkbox/util/cab/structure/CabFolderEntry.java
Normal file
70
src/dorkbox/util/cab/structure/CabFolderEntry.java
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.util.cab.structure;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import dorkbox.util.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;
|
||||
}
|
||||
}
|
||||
|
161
src/dorkbox/util/cab/structure/CabHeader.java
Normal file
161
src/dorkbox/util/cab/structure/CabHeader.java
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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.util.cab.structure;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import dorkbox.util.bytes.LittleEndian;
|
||||
import dorkbox.util.cab.CabException;
|
||||
import dorkbox.util.cab.CabStreamSaver;
|
||||
import dorkbox.util.cab.CorruptCabException;
|
||||
|
||||
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();
|
||||
// MSCF
|
||||
if (i != 77 || j != 83 || k != 67 || m != 70) {
|
||||
throw new CorruptCabException("Missing header signature");
|
||||
}
|
||||
|
||||
this.reserved1 = LittleEndian.UInt_.from(input).longValue();
|
||||
this.cbCabinet = LittleEndian.UInt_.from(input).longValue();
|
||||
this.reserved2 = LittleEndian.UInt_.from(input).longValue();
|
||||
this.coffFiles = LittleEndian.UInt_.from(input).longValue();
|
||||
this.reserved3 = LittleEndian.UInt_.from(input).longValue();
|
||||
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
80
src/dorkbox/util/cab/structure/CfDataRecord.java
Normal file
80
src/dorkbox/util/cab/structure/CfDataRecord.java
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.util.cab.structure;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import dorkbox.util.bytes.LittleEndian;
|
||||
import dorkbox.util.cab.CabException;
|
||||
import dorkbox.util.cab.Checksum;
|
||||
import dorkbox.util.cab.CorruptCabException;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user