Compare commits

...
63 Commits
Author SHA1 Message Date
tarsin 7af1e168a4 Bump Version
EhViewer / Build (push) Has been cancelled
Releases / Build (push) Has been cancelled
2022-05-23 20:46:46 +08:00
tarsin c8bf34e0d7 Switch to md3 switch 2022-05-23 20:46:09 +08:00
tarsin 86d2282cd6 native: Reformat code 2022-05-23 20:04:04 +08:00
tarsin cfdb23d6dc app: Reformat code 2022-05-23 19:59:40 +08:00
tarsin 1874ddd15b Add nativelib version check 2022-05-23 19:58:16 +08:00
tarsin a004c308cc Rename .java to .kt 2022-05-23 19:58:16 +08:00
tarsin 863337c789 Support fskip for better decompress perf
* Actually the whole impl can't be more sucks, will import algorithm to manage buffer and read strategy further
2022-05-23 17:34:59 +08:00
tarsin 64d91eed33 Upgrade libjpeg-turbo to 2.1.3 2022-05-23 14:55:15 +08:00
tarsin d0c3a3e14d Refactor cmake 2022-05-23 11:36:51 +08:00
tarsin 464636d87d Add zstd support 2022-05-23 11:28:28 +08:00
tarsin 0b0a1f456f Reduce supported ext
* hippo's legacy glgallery only support these four extensions, further support need we migrate to coil and drop glgallery, in progress
2022-05-23 08:40:15 +08:00
tarsin 302030ca65 Update README.md 2022-05-23 08:28:38 +08:00
tarsin 3e63738542 Make a release
EhViewer / Build (push) Has been cancelled
Releases / Build (push) Has been cancelled
2022-05-23 08:21:14 +08:00
tarsin d6823c9c8e Checkout to our newly patched libarchive 2022-05-23 08:04:59 +08:00
tarsin 6bc3866660 Build lzma
FIXME: Don't hack!!
https://github.com/asuka-mio/libarchive/commit/588598490ad0a80e44554ed5e608a9f9878220c0
2022-05-23 08:02:20 +08:00
tarsin f41f4dd8ba Support 7z read 2022-05-23 07:31:58 +08:00
tarsin cde39812ce Update proguard-rules.pro 2022-05-23 01:12:58 +08:00
tarsin 03c2abc901 Merge pull request #34 from txyyh/feature/Button
Use Material3 Button instead
2022-05-23 00:59:14 +08:00
tarsin 7646334525 Don't obfuscate native code 2022-05-23 00:59:00 +08:00
txyyh f8d1cd3fab Use Material3 Button instead 2022-05-23 00:47:28 +08:00
tarsin 4ea94be64a Update releases.yml 2022-05-23 00:44:56 +08:00
tarsin dc0470e75a Bump Version
EhViewer / Build (push) Has been cancelled
Releases / Build (push) Has been cancelled
2022-05-23 00:34:33 +08:00
tarsin 5d49ecdd7d Add lzma xz v5.2.5 2022-05-23 00:29:01 +08:00
tarsin ef2441116d Use more friendly suffix recogniser and support all image file 2022-05-22 23:17:35 +08:00
tarsin 207909c7be Initial libarchive simple support 2022-05-22 22:27:31 +08:00
tarsin ddb3dd2d95 Merge pull request #33 from txyyh/feature/buildguide
Add build guide
2022-05-22 02:17:38 +08:00
txyyh 8bb980fe97 Add build guide 2022-05-22 01:55:38 +08:00
tarsin 3c3a201ed8 Merge pull request #30 from txyyh/feature/README
Rewrite README header
2022-05-22 01:31:13 +08:00
tarsin 81bb37e929 Merge pull request #31 from asuka-mio/renovate/org.jboss.forge.roaster-roaster-api-2.x
Update dependency org.jboss.forge.roaster:roaster-api to v2.25.0.Final
2022-05-22 01:30:54 +08:00
Renovate Bot ae34690eb2 Update dependency org.jboss.forge.roaster:roaster-api to v2.25.0.Final 2022-05-21 17:30:16 +00:00
tarsin 285b0f5a69 Merge pull request #32 from asuka-mio/renovate/org.jboss.forge.roaster-roaster-jdt-2.x
Update dependency org.jboss.forge.roaster:roaster-jdt to v2.25.0.Final
2022-05-22 01:29:43 +08:00
Renovate Bot a5327fce07 Update dependency org.jboss.forge.roaster:roaster-jdt to v2.25.0.Final 2022-05-21 15:11:11 +00:00
txyyh a4b750f9cd Add description title 2022-05-21 21:58:53 +08:00
txyyh 943344d4bb Rewrite shields 2022-05-21 21:58:50 +08:00
txyyh 79f1b92960 Rewrite icon header 2022-05-21 21:26:48 +08:00
tarsin 575ae38a28 Re-checkout 2022-05-21 20:46:25 +08:00
tarsin f90e2a5c80 Checkout to our libarchive 2022-05-21 20:34:06 +08:00
tarsin 4d9b2877fe Build libarchive 2022-05-21 20:08:03 +08:00
tarsin 4a955947a2 Add libarchive 2022-05-21 19:41:09 +08:00
tarsin 7307c136ee Drop useless native part 2022-05-21 17:24:03 +08:00
tarsin 657e1b1d0f Drop a7zip for libarchive integrate 2022-05-21 17:04:27 +08:00
tarsin 43edf11275 Bump Version
EhViewer / Build (push) Has been cancelled
Releases / Build (push) Has been cancelled
2022-05-21 00:10:34 +08:00
tarsin 32ec4c6715 Merge pull request #29 from txyyh/feature/AutoSign
AutoSign and Releases
2022-05-21 00:04:58 +08:00
txyyh 84ac57d69e Releases with tag 2022-05-20 23:57:51 +08:00
txyyh 328e7745b7 Add step name 2022-05-20 23:23:14 +08:00
txyyh ccf22eaef4 Upload right artifact 2022-05-20 23:23:14 +08:00
txyyh c89d42f368 Use keystore in project 2022-05-20 23:23:14 +08:00
txyyh 41192ea7f5 Format 2022-05-20 23:23:14 +08:00
tarsin 7840987a7c native cmake tweaks 2022-05-20 22:59:23 +08:00
tarsin fcbe0a7f55 layout tweaks 2022-05-20 20:33:37 +08:00
tarsin f12894c95d Extract help message from add action 2022-05-20 20:32:15 +08:00
tarsin 40f139fda2 Merge pull request #28 from txyyh/master
Change gallery_detail button theme
2022-05-20 17:32:01 +08:00
txyyh b8507a371e Button side-by-side 2022-05-20 14:32:57 +08:00
txyyh e5a71ce906 Use TextButton instead 2022-05-20 14:32:57 +08:00
txyyh f9e708fe1e Disable bold text 2022-05-20 14:32:57 +08:00
txyyh 50ba6f2bd2 Use elevated instead 2022-05-20 14:32:57 +08:00
tarsin 2484371f8c Import compose activity 2022-05-20 13:42:02 +08:00
tarsin ba675c4212 Use SwitchPreferenceCompat 2022-05-20 13:40:52 +08:00
tarsin 6f9bc3135a Import Jetpack Compose 2022-05-20 13:04:54 +08:00
tarsin 4475d4d018 Search layout tweaks 2022-05-20 12:31:00 +08:00
tarsin 08e45db49d Update README.md 2022-05-20 01:34:25 +08:00
tarsin 85c76065a5 Delete codeql-analysis.yml 2022-05-20 01:28:53 +08:00
tarsin 13582c3f1b Create codeql-analysis.yml 2022-05-20 01:24:27 +08:00
114 changed files with 1211 additions and 8961 deletions

No files matched your search

+20 -6
View File
@@ -7,22 +7,36 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
- name: Checkout
uses: actions/checkout@v3
- name: Setup Java 11
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 11
- name: Setup Android SDK Tools
uses: android-actions/setup-android@v2
- name: Install NDK
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;24.0.8215888" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
- uses: gradle/gradle-build-action@v2
- name: Gradle Build
uses: gradle/gradle-build-action@v2
- run: |
git submodule update --init --recursive
gradle assembleRelease
- uses: actions/upload-artifact@v3
- name: Update ARM64
uses: actions/upload-artifact@v3
with:
name: github-${{ github.sha }}
path: app/build/outputs/apk/release/app-arm64-v8a-release-unsigned.apk
name: arm64-${{ github.sha }}
path: app/build/outputs/apk/release/app-arm64-v8a-release.apk
- name: Update x86_64
uses: actions/upload-artifact@v3
with:
name: x86_64-${{ github.sha }}
path: app/build/outputs/apk/release/app-x86_64-release.apk
+41
View File
@@ -0,0 +1,41 @@
name: Releases
on:
push:
tags:
- "*"
jobs:
linux:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Java 11
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 11
- name: Setup Android SDK Tools
uses: android-actions/setup-android@v2
- name: Install NDK
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;24.0.8215888" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
- name: Gradle Build
uses: gradle/gradle-build-action@v2
- run: |
git submodule update --init --recursive
gradle assembleRelease
- name: Releases
uses: softprops/action-gh-release@v0.1.14
with:
body: Bump Version
files: |
app/build/outputs/apk/release/app-arm64-v8a-release.apk
app/build/outputs/apk/release/app-x86_64-release.apk
+10 -4
View File
@@ -1,12 +1,18 @@
[submodule "native/src/main/jni/a7zip/p7zip/p7zip"]
path = native/src/main/jni/a7zip/p7zip/p7zip
url = https://github.com/seven332/p7zip.git
[submodule "native/src/main/jni/image/libjpeg-turbo/libjpeg-turbo"]
path = native/src/main/jni/image/libjpeg-turbo/libjpeg-turbo
url = https://gitlab.com/NekoInverter/libjpeg-turbo.git
url = https://github.com/asuka-mio/libjpeg-turbo
[submodule "native/src/main/jni/image/giflib/giflib"]
path = native/src/main/jni/image/giflib/giflib
url = https://gitlab.com/NekoInverter/giflib.git
[submodule "native/src/main/jni/image/libpng/libpng"]
path = native/src/main/jni/image/libpng/libpng
url = https://gitlab.com/NekoInverter/libpng.git
[submodule "native/src/main/jni/libarchive"]
path = native/src/main/jni/libarchive
url = https://github.com/asuka-mio/libarchive
[submodule "native/src/main/jni/liblzma"]
path = native/src/main/jni/liblzma
url = https://git.tukaani.org/xz.git
[submodule "native/src/main/jni/libzstd"]
path = native/src/main/jni/libzstd
url = https://github.com/facebook/zstd
+34 -2
View File
@@ -1,7 +1,27 @@
# EhViewer
<h1 align="center">
<img src="art/launcher_icon-web.png" width="200">
<br>EhViewer<br>
</h1>
![Icon](art/launcher_icon-web.png)
<p align="center">
<a href="https://github.com/asuka-mio/Ehviewer/actions">
<img src="https://img.shields.io/github/workflow/status/asuka-mio/Ehviewer/EhViewer" alt="Github Actions">
</a>
<a href="https://github.com/asuka-mio/Ehviewer/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/asuka-mio/Ehviewer" alt="LICENSE">
</a>
<a href="https://www.codefactor.io/repository/github/asuka-mio/ehviewer">
<img src="https://www.codefactor.io/repository/github/asuka-mio/ehviewer/badge" alt="CodeFactor">
</a>
<a href="https://github.com/asuka-mio/Ehviewer/releases">
<img src="https://img.shields.io/github/v/release/asuka-mio/ehviewer?include_prereleases" alt="Release">
</a>
<a href="https://github.com/asuka-mio/Ehviewer/issues">
<img src="https://img.shields.io/github/issues/asuka-mio/ehviewer" alt="Issues">
</a>
</p>
# Description
这是一个 E-Hentai Android 平台的浏览器
已针对性适配 Material Design 3 及其动态取色系统
@@ -24,6 +44,16 @@ Only Support Android S and above!
![screenshot-01](art/screenshot-01.png)
# Build
本项目使用了 CMake 3.23.1 作为构建工具链之一,而当前版本的 Android Studio SDK Tool 无法满足本项目需求。
因此,在构建本项目前需要提前配置好 CMake >=3.23.1。
This Project use CMake 3.23.1, with is highter than Android Studio bundle CMake.
So you need to pre-install CMake>=3.23.1 before build.
# Thanks
本项目受到了诸多开源项目的帮助
@@ -44,6 +74,8 @@ Here is the libraries
- [ShowcaseView](https://github.com/amlcurran/ShowcaseView)
- [Slabo](https://github.com/TiroTypeworks/Slabo)
- [TagSoup](http://home.ccil.org/~cowan/tagsoup/)
- [libarchive](http://www.libarchive.org/)
- [XZ Utils](https://tukaani.org/xz/)
# License
+24 -17
View File
@@ -22,22 +22,24 @@ android {
}
signingConfigs {
if (localProperties.getProperty("storeFile") != null) {
sign {
storeFile file(localProperties.getProperty("storeFile"))
storePassword localProperties.getProperty("storePassword")
keyAlias localProperties.getProperty("keyAlias")
keyPassword localProperties.getProperty("keyPassword")
}
sign {
storeFile file(signStoreFile)
storePassword signStorePassword
keyAlias signkeyAlias
keyPassword signkeyPassword
}
}
buildFeatures {
compose true
}
defaultConfig {
applicationId "io.github.nekoinverter.ehviewer"
minSdkVersion 31
targetSdkVersion 32
versionCode 114518
versionName "1.7.26.9"
versionCode 114522
versionName "1.7.27.2"
resConfigs 'zh', 'zh-rCN', 'zh-rHK', 'zh-rTW', 'es', 'ja', 'ko', 'fr', 'de', 'th'
}
@@ -72,17 +74,11 @@ android {
minifyEnabled true
shrinkResources true
proguardFiles 'proguard-rules.pro'
if (localProperties.getProperty("storeFile") != null) {
signingConfig signingConfigs.sign
}
signingConfig signingConfigs.sign
}
debug {
applicationIdSuffix ".debug"
if (localProperties.getProperty("storeFile") != null) {
signingConfig signingConfigs.sign
} else {
signingConfig signingConfigs.debug
}
signingConfig signingConfigs.debug
}
}
@@ -91,6 +87,10 @@ android {
java.srcDirs += 'src/main/java-gen'
}
}
composeOptions {
kotlinCompilerExtensionVersion compose
}
namespace 'com.hippo.ehviewer'
}
@@ -100,6 +100,7 @@ tasks.withType(JavaCompile) {
dependencies {
implementation 'androidx.activity:activity:1.4.0'
implementation "androidx.activity:activity-compose:1.4.0"
implementation 'androidx.biometric:biometric:1.1.0'
implementation 'androidx.browser:browser:1.4.0'
implementation 'androidx.core:core:1.7.0'
@@ -138,6 +139,12 @@ dependencies {
implementation 'org.greenrobot:greendao:3.3.0'
implementation 'org.jsoup:jsoup:1.15.1'
implementation projects.native
implementation "androidx.compose.material3:material3:1.0.0-alpha12"
implementation "androidx.compose.ui:ui:$compose"
implementation "androidx.compose.ui:ui-util:$compose"
implementation "androidx.compose.animation:animation-graphics:$compose"
}
configurations.all {
Binary file not shown.
@@ -457,14 +457,6 @@ public class Settings {
putBoolean(KEY_SELECT_SITE, value);
}
public static boolean getQuickSearchTip() {
return getBoolean(KEY_QUICK_SEARCH_TIP, DEFAULT_QUICK_SEARCH_TIP);
}
public static void putQuickSearchTip(boolean value) {
putBoolean(KEY_QUICK_SEARCH_TIP, value);
}
public static int getTheme() {
return getIntFromStr(KEY_THEME, DEFAULT_THEME);
}
@@ -1,174 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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 com.hippo.ehviewer.gallery;
import androidx.annotation.NonNull;
import com.hippo.a7zip.ArchiveException;
import com.hippo.a7zip.InArchive;
import com.hippo.a7zip.PropID;
import com.hippo.a7zip.PropType;
import com.hippo.a7zip.SeekableInputStream;
import com.hippo.unifile.UniRandomAccessFile;
import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
class A7ZipArchive implements Closeable {
private final InArchive archive;
private A7ZipArchive(InArchive archive) {
this.archive = archive;
}
private static boolean isSupportedFilename(String name) {
for (String extension : GalleryProvider2.SUPPORT_IMAGE_EXTENSIONS) {
if (name.endsWith(extension)) {
return true;
}
}
return false;
}
static A7ZipArchive create(UniRandomAccessFile file) throws ArchiveException {
SeekableInputStream store = new UniRandomAccessFileInStream(file);
InArchive archive = InArchive.open(store);
if ((archive.getArchivePropertyType(PropID.ENCRYPTED) == PropType.BOOL && archive.getArchiveBooleanProperty(PropID.ENCRYPTED))
|| (archive.getArchivePropertyType(PropID.SOLID) == PropType.BOOL && archive.getArchiveBooleanProperty(PropID.SOLID))
|| (archive.getArchivePropertyType(PropID.IS_VOLUME) == PropType.BOOL && archive.getArchiveBooleanProperty(PropID.IS_VOLUME))) {
throw new ArchiveException("Unsupported archive");
}
return new A7ZipArchive(archive);
}
@Override
public void close() {
archive.close();
}
List<A7ZipArchiveEntry> getArchiveEntries() {
List<A7ZipArchiveEntry> entries = new ArrayList<>();
for (int i = 0, n = archive.getNumberOfEntries(); i < n; i++) {
if (!archive.getEntryBooleanProperty(i, PropID.ENCRYPTED)
&& !archive.getEntryBooleanProperty(i, PropID.IS_DIR)
&& !archive.getEntryBooleanProperty(i, PropID.IS_VOLUME)
&& !archive.getEntryBooleanProperty(i, PropID.SOLID)) {
String path = archive.getEntryPath(i);
if (isSupportedFilename(path.toLowerCase())) {
entries.add(new A7ZipArchiveEntry(archive, i, path));
}
}
}
return entries;
}
static class A7ZipArchiveEntry {
private final InArchive archive;
private final int index;
private final String path;
private A7ZipArchiveEntry(InArchive archive, int index, String path) {
this.archive = archive;
this.index = index;
this.path = path;
}
String getPath() {
return path;
}
void extract(OutputStream os) throws ArchiveException {
archive.extractEntry(index, new OutputStreamSequentialOutStream(os));
}
}
private static class UniRandomAccessFileInStream extends SeekableInputStream {
private final byte[] scratch = new byte[8];
private final UniRandomAccessFile file;
public UniRandomAccessFileInStream(UniRandomAccessFile file) {
this.file = file;
}
@Override
public void seek(long pos) throws IOException {
file.seek(pos);
}
@Override
public long tell() throws IOException {
return file.getFilePointer();
}
@Override
public long size() throws IOException {
return file.length();
}
@Override
public int read() throws IOException {
return (file.read(scratch, 0, 1) != -1) ? scratch[0] & 0xff : -1;
}
@Override
public int read(@NonNull byte[] b) throws IOException {
return file.read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return file.read(b, off, len);
}
@Override
public void close() throws IOException {
file.close();
}
}
private static class OutputStreamSequentialOutStream extends OutputStream {
private final OutputStream stream;
public OutputStreamSequentialOutStream(OutputStream stream) {
this.stream = stream;
}
@Override
public void write(int b) throws IOException {
stream.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
stream.write(b, off, len);
}
@Override
public void close() throws IOException {
stream.close();
}
}
}
@@ -23,23 +23,18 @@ import android.os.Process;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.hippo.a7zip.ArchiveException;
import com.hippo.UriArchiveAccessor;
import com.hippo.ehviewer.GetText;
import com.hippo.ehviewer.R;
import com.hippo.glgallery.GalleryPageView;
import com.hippo.image.Image;
import com.hippo.unifile.UniFile;
import com.hippo.unifile.UniRandomAccessFile;
import com.hippo.util.NaturalComparator;
import com.hippo.yorozuya.thread.PriorityThread;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicInteger;
@@ -47,15 +42,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class ArchiveGalleryProvider extends GalleryProvider2 {
private static final AtomicInteger sIdGenerator = new AtomicInteger();
private static final Comparator<A7ZipArchive.A7ZipArchiveEntry> naturalComparator = new Comparator<A7ZipArchive.A7ZipArchiveEntry>() {
private final NaturalComparator comparator = new NaturalComparator();
@Override
public int compare(A7ZipArchive.A7ZipArchiveEntry o1, A7ZipArchive.A7ZipArchiveEntry o2) {
return comparator.compare(o1.getPath(), o2.getPath());
}
};
private final UniFile file;
private final UriArchiveAccessor archiveAccessor;
private final Stack<Integer> requests = new Stack<>();
private final AtomicInteger extractingIndex = new AtomicInteger(GalleryPageView.INVALID_INDEX);
private final LinkedHashMap<Integer, InputStream> streams = new LinkedHashMap<>();
@@ -66,7 +53,14 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
private String error;
public ArchiveGalleryProvider(Context context, Uri uri) {
file = UniFile.fromMediaUri(context, uri);
UriArchiveAccessor archiveAccessor1;
try {
archiveAccessor1 = new UriArchiveAccessor(context, uri);
} catch (FileNotFoundException e) {
archiveAccessor1 = null;
e.printStackTrace();
}
archiveAccessor = archiveAccessor1;
}
@Override
@@ -167,37 +161,14 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
private class ArchiveTask implements Runnable {
@Override
public void run() {
UniRandomAccessFile uraf = null;
try {
uraf = file.createRandomAccessFile("r");
} catch (IOException e) {
e.printStackTrace();
}
if (uraf == null) {
size = archiveAccessor.open();
if (size <= 0) {
size = STATE_ERROR;
error = GetText.getString(R.string.error_reading_failed);
notifyDataChanged();
return;
}
A7ZipArchive archive = null;
try {
archive = A7ZipArchive.create(uraf);
} catch (ArchiveException e) {
e.printStackTrace();
}
if (archive == null) {
size = STATE_ERROR;
error = GetText.getString(R.string.error_invalid_archive);
notifyDataChanged();
return;
}
List<A7ZipArchive.A7ZipArchiveEntry> entries = archive.getArchiveEntries();
Collections.sort(entries, naturalComparator);
// Update size and notify changed
size = entries.size();
notifyDataChanged();
while (!Thread.currentThread().isInterrupted()) {
@@ -217,13 +188,13 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
}
// Check index valid
if (index < 0 || index >= entries.size()) {
if (index < 0 || index >= size) {
extractingIndex.lazySet(GalleryPageView.INVALID_INDEX);
notifyPageFailed(index, GetText.getString(R.string.error_out_of_range));
continue;
}
Pipe pipe = new Pipe(4 * 1024);
Pipe pipe = new Pipe(4096);
synchronized (streams) {
if (streams.get(index) != null) {
@@ -233,13 +204,7 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
streams.notify();
}
try {
entries.get(index).extract(pipe.getOutputStream());
} catch (ArchiveException e) {
e.printStackTrace();
} finally {
extractingIndex.lazySet(GalleryPageView.INVALID_INDEX);
}
archiveAccessor.extractTargetIndexToOutputStream(index, pipe.getOutputStream());
}
}
}
@@ -282,4 +247,4 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
}
}
}
}
}
@@ -107,13 +107,6 @@ class Pipe {
public void write(@NonNull byte[] b, int off, int len) throws IOException {
synchronized (Pipe.this) {
while (len != 0) {
if (outClosed) {
throw new IOException("The OutputStream is closed");
}
if (inClosed) {
throw new IOException("The InputStream is closed");
}
if (head == tail && full) {
// The buffer is full, wait for InputStream read bytes
try {
@@ -1,58 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* 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 com.hippo.ehviewer.preference;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.AttributeSet;
import androidx.preference.Preference;
import com.hippo.ehviewer.R;
public class VersionPreference extends Preference {
public VersionPreference(Context context) {
super(context);
init(context);
}
public VersionPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public VersionPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
setTitle(R.string.settings_about_version);
String version;
try {
PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
version = pInfo.versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
version = context.getString(R.string.error_unknown);
}
setSummary(version);
}
}
@@ -0,0 +1,46 @@
/*
* Copyright 2016 Hippo Seven
*
* 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 com.hippo.ehviewer.preference
import android.content.Context
import android.content.pm.PackageManager
import android.util.AttributeSet
import androidx.appcompat.app.AlertDialog
import com.hippo.Native
import com.hippo.ehviewer.R
import com.hippo.preference.MessagePreference
class VersionPreference @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : MessagePreference(context, attrs) {
init {
setTitle(R.string.settings_about_version)
val version: String = try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
pInfo.versionName
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
context.getString(R.string.error_unknown)
}
summary = version
}
override fun onPrepareDialogBuilder(builder: AlertDialog.Builder) {
super.onPrepareDialogBuilder(builder)
builder.setTitle(R.string.show_library_version)
builder.setMessage(Native.getlibarchiveVersion() + "\nlzma(xz-utils) " + Native.getliblzmaVersion() + "\nlibzstd " + Native.getlibzstdVersion() + "\nzlib " + Native.getzlibVersion() + "\nlibjpeg-turbo " + Native.getlibjpeg_turboVersion())
}
}
@@ -66,6 +66,7 @@ import androidx.core.view.WindowInsetsCompat;
import androidx.core.view.WindowInsetsControllerCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.switchmaterial.SwitchMaterial;
import com.hippo.ehviewer.AppConfig;
import com.hippo.ehviewer.BuildConfig;
import com.hippo.ehviewer.R;
@@ -238,28 +239,15 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
}
} else if (Intent.ACTION_VIEW.equals(mAction)) {
if (mUri != null) {
// Only support zip now
try {
grantUriPermission(BuildConfig.APPLICATION_ID, mUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
} catch (Exception e) {
// Some stupid file manager send us a uri and don't allow us to read it
// java.lang.SecurityException: UID 10671 does not have permission to
// content://com.UCMobile.fileProvider/external_files/BaiduNetdisk/getvoice [user 0]
Toast.makeText(this, R.string.error_reading_failed, Toast.LENGTH_SHORT).show();
}
mGalleryProvider = new ArchiveGalleryProvider(this, mUri);
}
}
} ActivityResultLauncher<String> requestStoragePermissionLauncher = registerForActivityResult(
new ActivityResultContracts.RequestPermission(),
result -> {
if (result && mSavingPage != -1) {
saveImage(mSavingPage);
} else {
Toast.makeText(this, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show();
}
mSavingPage = -1;
});
}
private void onInit() {
Intent intent = getIntent();
@@ -273,7 +261,16 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
mGalleryInfo = intent.getParcelableExtra(KEY_GALLERY_INFO);
mPage = intent.getIntExtra(KEY_PAGE, -1);
buildProvider();
}
} ActivityResultLauncher<String> requestStoragePermissionLauncher = registerForActivityResult(
new ActivityResultContracts.RequestPermission(),
result -> {
if (result && mSavingPage != -1) {
saveImage(mSavingPage);
} else {
Toast.makeText(this, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show();
}
mSavingPage = -1;
});
private void onRestore(@NonNull Bundle savedInstanceState) {
mAction = savedInstanceState.getString(KEY_ACTION);
@@ -1051,15 +1048,15 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
private final Spinner mScaleMode;
private final Spinner mStartPosition;
private final Spinner mReadTheme;
private final Switch mKeepScreenOn;
private final Switch mShowClock;
private final Switch mShowProgress;
private final Switch mShowBattery;
private final Switch mShowPageInterval;
private final Switch mVolumePage;
private final Switch mReverseVolumePage;
private final Switch mReadingFullscreen;
private final Switch mCustomScreenLightness;
private final SwitchMaterial mKeepScreenOn;
private final SwitchMaterial mShowClock;
private final SwitchMaterial mShowProgress;
private final SwitchMaterial mShowBattery;
private final SwitchMaterial mShowPageInterval;
private final SwitchMaterial mVolumePage;
private final SwitchMaterial mReverseVolumePage;
private final SwitchMaterial mReadingFullscreen;
private final SwitchMaterial mCustomScreenLightness;
private final SeekBar mScreenLightness;
@SuppressLint("InflateParams")
@@ -69,7 +69,6 @@ import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter;
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableItemViewHolder;
import com.hippo.app.CheckBoxDialogBuilder;
import com.hippo.app.EditTextDialogBuilder;
import com.hippo.drawable.AddDeleteDrawable;
import com.hippo.drawable.DrawerArrowDrawable;
@@ -709,15 +708,10 @@ public final class GalleryListScene extends BaseScene
if (null == context) {
return;
}
final CheckBoxDialogBuilder builder = new CheckBoxDialogBuilder(
context, getString(R.string.add_quick_search_tip), getString(R.string.get_it), false);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context);
builder.setMessage(R.string.add_quick_search_tip);
builder.setTitle(R.string.readme);
builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
if (builder.isChecked()) {
Settings.putQuickSearchTip(false);
}
showAddQuickSearchDialog(adapter, recyclerView, tip);
}).show();
builder.show();
}
@@ -823,11 +817,9 @@ public final class GalleryListScene extends BaseScene
toolbar.setOnMenuItemClickListener(item -> {
int id = item.getItemId();
if (id == R.id.action_add) {
if (Settings.getQuickSearchTip()) {
showQuickSearchTipDialog(qsDrawerAdapter, recyclerView, tip);
} else {
showAddQuickSearchDialog(qsDrawerAdapter, recyclerView, tip);
}
showAddQuickSearchDialog(qsDrawerAdapter, recyclerView, tip);
} else if (id == R.id.action_help) {
showQuickSearchTipDialog(qsDrawerAdapter, recyclerView, tip);
}
return true;
});
@@ -141,7 +141,7 @@ public final class ImageSearchLayout extends LinearLayout implements View.OnClic
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os);
mImagePath = temp.getPath();
mPreview.setImageBitmap(bitmap);
((View)mPreview.getParent()).setVisibility(VISIBLE);
((View) mPreview.getParent()).setVisibility(VISIBLE);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
@@ -166,7 +166,7 @@ public final class ImageSearchLayout extends LinearLayout implements View.OnClic
}
mImagePath = imagePath;
mPreview.setImageBitmap(bitmap);
((View)mPreview.getParent()).setVisibility(VISIBLE);
((View) mPreview.getParent()).setVisibility(VISIBLE);
} catch (FileNotFoundException e) {
// Ignore
} finally {
@@ -15,103 +15,72 @@
*/
package com.hippo.ehviewer.widget
import com.hippo.easyrecyclerview.EasyRecyclerView
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import android.view.LayoutInflater
import com.google.android.material.chip.ChipGroup
import com.hippo.widget.RadioGridGroup
import com.google.android.material.tabs.TabLayout
import androidx.recyclerview.widget.LinearLayoutManager
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.net.Uri
import android.os.Bundle
import androidx.recyclerview.widget.DefaultItemAnimator
import com.hippo.ehviewer.R
import com.hippo.easyrecyclerview.MarginItemDecoration
import android.view.ViewGroup
import android.util.SparseArray
import android.os.Parcelable
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import kotlin.Throws
import com.hippo.ehviewer.client.exception.EhException
import com.hippo.ehviewer.client.data.ListUrlBuilder
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import androidx.annotation.IntDef
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.switchmaterial.SwitchMaterial
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.hippo.easyrecyclerview.EasyRecyclerView
import com.hippo.easyrecyclerview.MarginItemDecoration
import com.hippo.easyrecyclerview.SimpleHolder
import com.hippo.ehviewer.R
import com.hippo.ehviewer.client.EhConfig
import com.hippo.ehviewer.client.data.ListUrlBuilder
import com.hippo.ehviewer.client.exception.EhException
import com.hippo.widget.RadioGridGroup
import com.hippo.yorozuya.NumberUtils
import com.hippo.yorozuya.ViewUtils
import java.lang.IndexOutOfBoundsException
class SearchLayout : EasyRecyclerView, CompoundButton.OnCheckedChangeListener, View.OnClickListener,
@SuppressLint("InflateParams")
class SearchLayout @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : EasyRecyclerView(context, attrs), CompoundButton.OnCheckedChangeListener, View.OnClickListener,
ImageSearchLayout.Helper, OnTabSelectedListener {
private val mInflater : LayoutInflater
private val mSharePref : SharedPreferences
@SearchMode
private var mSearchMode = SEARCH_MODE_NORMAL
private var mEnableAdvance = false
private var mNormalView: View? = null
private var mNormalSearchMode: RadioGridGroup? = null
private var mNormalSearchModeHelp: ImageView? = null
private var mEnableAdvanceSwitch: Switch? = null
private var mAdvanceView: View? = null
private var mTableAdvanceSearch: AdvanceSearchTable? = null
private var mImageView: ImageSearchLayout? = null
private var mActionView: View? = null
private var mAction: TabLayout? = null
private var mLayoutManager: LinearLayoutManager? = null
private var mAdapter: SearchAdapter? = null
private var mCategoryGroup: ChipGroup
private var mNormalView: View
private var mNormalSearchMode: RadioGridGroup
private var mNormalSearchModeHelp: ImageView
private var mEnableAdvanceSwitch: SwitchMaterial
private var mAdvanceView: View
private var mTableAdvanceSearch: AdvanceSearchTable
private var mImageView: ImageSearchLayout
private var mActionView: View
private var mAction: TabLayout
private var mAdapter: SearchAdapter
private var mHelper: Helper? = null
private val mSharePref: SharedPreferences
private val mInflater: LayoutInflater
private val mCategoryTable : ArrayList<Pair<Int, Int>> = arrayListOf(
Pair(EhConfig.DOUJINSHI, R.string.doujinshi),
Pair(EhConfig.MANGA, R.string.manga),
Pair(EhConfig.ARTIST_CG, R.string.artist_cg),
Pair(EhConfig.GAME_CG, R.string.game_cg),
Pair(EhConfig.WESTERN, R.string.western),
Pair(EhConfig.NON_H, R.string.non_h),
Pair(EhConfig.IMAGE_SET, R.string.image_set),
Pair(EhConfig.COSPLAY, R.string.cosplay),
Pair(EhConfig.ASIAN_PORN, R.string.asian_porn),
Pair(EhConfig.MISC, R.string.misc)
)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init {
mSharePref = PreferenceManager.getDefaultSharedPreferences(context)
mInflater = LayoutInflater.from(context)
init(context)
}
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(
context,
attrs,
defStyle
) {
mSharePref = PreferenceManager.getDefaultSharedPreferences(context)
mInflater = LayoutInflater.from(context)
init(context)
}
@SuppressLint("InflateParams")
private fun init(context: Context) {
val resources = context.resources
mLayoutManager = SearchLayoutManager(context)
layoutManager = SearchLayoutManager(context)
mAdapter = SearchAdapter()
mAdapter!!.setHasStableIds(true)
layoutManager = mLayoutManager
mAdapter.setHasStableIds(true)
adapter = mAdapter
setHasFixedSize(true)
clipToPadding = false
(itemAnimator as DefaultItemAnimator?)!!.supportsChangeAnimations = false
(itemAnimator as DefaultItemAnimator?)?.supportsChangeAnimations = false
val interval = resources.getDimensionPixelOffset(R.dimen.search_layout_interval)
val paddingH = resources.getDimensionPixelOffset(R.dimen.search_layout_margin_h)
val paddingV = resources.getDimensionPixelOffset(R.dimen.search_layout_margin_v)
@@ -120,13 +89,10 @@ class SearchLayout : EasyRecyclerView, CompoundButton.OnCheckedChangeListener, V
)
addItemDecoration(decoration)
decoration.applyPaddings(this)
// Create normal view
val normalView = mInflater.inflate(R.layout.search_normal, null)
mNormalView = normalView
mNormalView = mInflater.inflate(R.layout.search_normal, null)
val mCategoryStored = mSharePref.getInt(SEARCH_CATEGORY_PREF, EhConfig.ALL_CATEGORY)
val mCategoryGroup = normalView.findViewById(R.id.search_category_chipgroup) as ChipGroup
mCategoryGroup = mNormalView.findViewById(R.id.search_category_chipgroup)
for (mPair in mCategoryTable) {
val mChip = IdentifiedChip(context)
mChip.isCheckable = true
@@ -142,46 +108,44 @@ class SearchLayout : EasyRecyclerView, CompoundButton.OnCheckedChangeListener, V
}
mSharePref.edit { putInt(SEARCH_CATEGORY_PREF, mCategory) }
}
mNormalSearchMode = normalView.findViewById(R.id.normal_search_mode)
mNormalSearchModeHelp = normalView.findViewById(R.id.normal_search_mode_help)
mEnableAdvanceSwitch = normalView.findViewById(R.id.search_enable_advance)
mNormalSearchModeHelp!!.setOnClickListener(this)
mEnableAdvanceSwitch!!.setOnCheckedChangeListener(this)
mEnableAdvanceSwitch!!.switchPadding = resources.getDimensionPixelSize(R.dimen.switch_padding)
mNormalSearchMode = mNormalView.findViewById(R.id.normal_search_mode)
mNormalSearchModeHelp = mNormalView.findViewById(R.id.normal_search_mode_help)
mEnableAdvanceSwitch = mNormalView.findViewById(R.id.search_enable_advance)
mNormalSearchModeHelp.setOnClickListener(this)
mEnableAdvanceSwitch.setOnCheckedChangeListener(this)
mEnableAdvanceSwitch.switchPadding =
resources.getDimensionPixelSize(R.dimen.switch_padding)
// Create advance view
mAdvanceView = mInflater.inflate(R.layout.search_advance, null)
mTableAdvanceSearch = mAdvanceView!!.findViewById(R.id.search_advance_search_table)
mTableAdvanceSearch = mAdvanceView.findViewById(R.id.search_advance_search_table)
// Create image view
mImageView = mInflater.inflate(R.layout.search_image, null) as ImageSearchLayout
mImageView!!.setHelper(this)
mImageView.setHelper(this)
// Create action view
mActionView = mInflater.inflate(R.layout.search_action, null)
mActionView!!.layoutParams = LayoutParams(
mActionView.layoutParams = LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
mAction = mActionView!!.findViewById(R.id.action)
mAction!!.addOnTabSelectedListener(this)
mAction = mActionView.findViewById(R.id.action)
mAction.addOnTabSelectedListener(this)
}
fun setHelper(helper: Helper?) {
mHelper = helper
}
fun scrollSearchContainerToTop() {
mLayoutManager!!.scrollToPositionWithOffset(0, 0)
(layoutManager as LinearLayoutManager).scrollToPositionWithOffset(0, 0)
}
fun setImageUri(imageUri: Uri?) {
mImageView!!.setImageUri(imageUri)
mImageView.setImageUri(imageUri)
}
fun setNormalSearchMode(id: Int) {
mNormalSearchMode!!.check(id)
mNormalSearchMode.check(id)
}
override fun onSelectImage() {
@@ -190,47 +154,15 @@ class SearchLayout : EasyRecyclerView, CompoundButton.OnCheckedChangeListener, V
}
}
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
super.dispatchSaveInstanceState(container)
mNormalView!!.saveHierarchyState(container)
mAdvanceView!!.saveHierarchyState(container)
mImageView!!.saveHierarchyState(container)
mActionView!!.saveHierarchyState(container)
}
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
super.dispatchRestoreInstanceState(container)
mNormalView!!.restoreHierarchyState(container)
mAdvanceView!!.restoreHierarchyState(container)
mImageView!!.restoreHierarchyState(container)
mActionView!!.restoreHierarchyState(container)
}
override fun onSaveInstanceState(): Parcelable {
val state = Bundle()
state.putParcelable(STATE_KEY_SUPER, super.onSaveInstanceState())
state.putInt(STATE_KEY_SEARCH_MODE, mSearchMode)
state.putBoolean(STATE_KEY_ENABLE_ADVANCE, mEnableAdvance)
return state
}
override fun onRestoreInstanceState(state: Parcelable) {
if (state is Bundle) {
super.onRestoreInstanceState(state.getParcelable(STATE_KEY_SUPER))
mSearchMode = state.getInt(STATE_KEY_SEARCH_MODE)
mEnableAdvance = state.getBoolean(STATE_KEY_ENABLE_ADVANCE)
}
}
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
if (buttonView === mEnableAdvanceSwitch) {
post {
mEnableAdvance = isChecked
if (mSearchMode == SEARCH_MODE_NORMAL) {
if (mEnableAdvance) {
mAdapter!!.notifyItemInserted(1)
mAdapter.notifyItemInserted(1)
} else {
mAdapter!!.notifyItemRemoved(1)
mAdapter.notifyItemRemoved(1)
}
if (mHelper != null) {
mHelper!!.onChangeSearchMode()
@@ -246,7 +178,7 @@ class SearchLayout : EasyRecyclerView, CompoundButton.OnCheckedChangeListener, V
urlBuilder.reset()
when (mSearchMode) {
SEARCH_MODE_NORMAL -> {
when (mNormalSearchMode!!.checkedRadioButtonId) {
when (mNormalSearchMode.checkedRadioButtonId) {
R.id.search_subscription_search -> {
urlBuilder.mode = ListUrlBuilder.MODE_SUBSCRIPTION
}
@@ -262,17 +194,18 @@ class SearchLayout : EasyRecyclerView, CompoundButton.OnCheckedChangeListener, V
}
urlBuilder.keyword = query
urlBuilder.category = PreferenceManager.getDefaultSharedPreferences(context).getInt(
SEARCH_CATEGORY_PREF, 0)
SEARCH_CATEGORY_PREF, 0
)
if (mEnableAdvance) {
urlBuilder.advanceSearch = mTableAdvanceSearch!!.advanceSearch
urlBuilder.minRating = mTableAdvanceSearch!!.minRating
urlBuilder.pageFrom = mTableAdvanceSearch!!.pageFrom
urlBuilder.pageTo = mTableAdvanceSearch!!.pageTo
urlBuilder.advanceSearch = mTableAdvanceSearch.advanceSearch
urlBuilder.minRating = mTableAdvanceSearch.minRating
urlBuilder.pageFrom = mTableAdvanceSearch.pageFrom
urlBuilder.pageTo = mTableAdvanceSearch.pageTo
}
}
SEARCH_MODE_IMAGE -> {
urlBuilder.mode = ListUrlBuilder.MODE_IMAGE_SEARCH
mImageView!!.formatListUrlBuilder(urlBuilder)
mImageView.formatListUrlBuilder(urlBuilder)
}
}
}
@@ -290,11 +223,11 @@ class SearchLayout : EasyRecyclerView, CompoundButton.OnCheckedChangeListener, V
}
fun setSearchMode(@SearchMode mode: Int) {
val oldItemCount = mAdapter!!.itemCount
val oldItemCount = mAdapter.itemCount
mSearchMode = mode
val newItemCount = mAdapter!!.itemCount
mAdapter!!.notifyItemRangeRemoved(0, oldItemCount - 1)
mAdapter!!.notifyItemRangeInserted(0, newItemCount - 1)
val newItemCount = mAdapter.itemCount
mAdapter.notifyItemRangeRemoved(0, oldItemCount - 1)
mAdapter.notifyItemRangeInserted(0, newItemCount - 1)
if (mHelper != null) {
mHelper!!.onChangeSearchMode()
}
@@ -370,7 +303,7 @@ class SearchLayout : EasyRecyclerView, CompoundButton.OnCheckedChangeListener, V
override fun onBindViewHolder(holder: SimpleHolder, position: Int) {
if (holder.itemViewType == ITEM_TYPE_ACTION) {
mAction!!.selectTab(mAction!!.getTabAt(mSearchMode))
mAction.selectTab(mAction.getTabAt(mSearchMode))
}
}
@@ -386,15 +319,12 @@ class SearchLayout : EasyRecyclerView, CompoundButton.OnCheckedChangeListener, V
inner class IdentifiedChip @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : Chip(context, attrs) {
var idt = 0
var idt = 0
}
companion object {
const val SEARCH_MODE_NORMAL = 0
const val SEARCH_MODE_IMAGE = 1
private const val STATE_KEY_SUPER = "super"
private const val STATE_KEY_SEARCH_MODE = "search_mode"
private const val STATE_KEY_ENABLE_ADVANCE = "enable_advance"
const val SEARCH_CATEGORY_PREF = "search_pref"
private const val ITEM_TYPE_NORMAL = 0
private const val ITEM_TYPE_NORMAL_ADVANCE = 1
@@ -403,6 +333,18 @@ class SearchLayout : EasyRecyclerView, CompoundButton.OnCheckedChangeListener, V
private val SEARCH_ITEM_COUNT_ARRAY = intArrayOf(
3, 2
)
private val mCategoryTable: ArrayList<Pair<Int, Int>> = arrayListOf(
Pair(EhConfig.DOUJINSHI, R.string.doujinshi),
Pair(EhConfig.MANGA, R.string.manga),
Pair(EhConfig.ARTIST_CG, R.string.artist_cg),
Pair(EhConfig.GAME_CG, R.string.game_cg),
Pair(EhConfig.WESTERN, R.string.western),
Pair(EhConfig.NON_H, R.string.non_h),
Pair(EhConfig.IMAGE_SET, R.string.image_set),
Pair(EhConfig.COSPLAY, R.string.cosplay),
Pair(EhConfig.ASIAN_PORN, R.string.asian_porn),
Pair(EhConfig.MISC, R.string.misc)
)
private val SEARCH_ITEM_TYPE = arrayOf(
intArrayOf(ITEM_TYPE_NORMAL, ITEM_TYPE_NORMAL_ADVANCE, ITEM_TYPE_ACTION), intArrayOf(
ITEM_TYPE_IMAGE, ITEM_TYPE_ACTION
@@ -42,7 +42,11 @@ public class BatteryView extends AppCompatTextView {
private BatteryDrawable mDrawable;
private boolean mAttached = false;
private boolean mIsChargerWorking = false; private final Runnable mCharger = new Runnable() {
private boolean mIsChargerWorking = false;
public BatteryView(Context context) {
super(context);
init();
} private final Runnable mCharger = new Runnable() {
private int level = 0;
@@ -56,10 +60,6 @@ public class BatteryView extends AppCompatTextView {
getHandler().postDelayed(mCharger, 200);
}
};
public BatteryView(Context context) {
super(context);
init();
}
public BatteryView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -85,6 +85,22 @@ public class BatteryView extends AppCompatTextView {
int height = (int) getTextSize();
mDrawable.setBounds(0, 0, (int) (height / 0.618f), height);
setCompoundDrawables(mDrawable, null, null, null);
}
@Override
public void setTextColor(int color) {
if (mCurrentColor == color) {
return;
}
mCurrentColor = color;
super.setTextColor(color);
}
private void startCharger() {
if (!mIsChargerWorking) {
getHandler().post(mCharger);
mIsChargerWorking = true;
}
} private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
@@ -116,22 +132,6 @@ public class BatteryView extends AppCompatTextView {
}
};
@Override
public void setTextColor(int color) {
if (mCurrentColor == color) {
return;
}
mCurrentColor = color;
super.setTextColor(color);
}
private void startCharger() {
if (!mIsChargerWorking) {
getHandler().post(mCharger);
mIsChargerWorking = true;
}
}
private void stopCharger() {
if (mIsChargerWorking) {
getHandler().removeCallbacks(mCharger);
@@ -65,7 +65,10 @@ public class TextClock extends AppCompatTextView {
}
onTimeChanged();
}
}; private final Runnable mTicker = new Runnable() {
};
public TextClock(Context context) {
this(context, null);
} private final Runnable mTicker = new Runnable() {
@Override
public void run() {
onTimeChanged();
@@ -76,24 +79,10 @@ public class TextClock extends AppCompatTextView {
getHandler().postAtTime(mTicker, next);
}
};
public TextClock(Context context) {
this(context, null);
}
public TextClock(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
chooseFormat();
onTimeChanged();
}
@Override
public void onChange(boolean selfChange, Uri uri) {
chooseFormat();
onTimeChanged();
}
};
}
public TextClock(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
@@ -109,7 +98,19 @@ public class TextClock extends AppCompatTextView {
createTime(mTimeZone);
// Wait until onAttachedToWindow() to handle the ticker
chooseFormat(false);
}
} private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
chooseFormat();
onTimeChanged();
}
@Override
public void onChange(boolean selfChange, Uri uri) {
chooseFormat();
onTimeChanged();
}
};
private void createTime(String timeZone) {
if (timeZone != null) {
+24 -37
View File
@@ -14,7 +14,7 @@
~ limitations under the License.
-->
<rikka.widget.borderview.BorderNestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -37,8 +37,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:text="@string/settings_read_screen_rotation"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_screen_rotation" />
<com.hippo.widget.CuteSpinner
android:id="@+id/screen_rotation"
@@ -60,8 +59,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:text="@string/settings_read_reading_direction"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_reading_direction" />
<com.hippo.widget.CuteSpinner
android:id="@+id/reading_direction"
@@ -83,8 +81,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:text="@string/settings_read_page_scaling"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_page_scaling" />
<com.hippo.widget.CuteSpinner
android:id="@+id/page_scaling"
@@ -106,8 +103,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:text="@string/settings_read_start_position"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_start_position" />
<com.hippo.widget.CuteSpinner
android:id="@+id/start_position"
@@ -129,8 +125,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:text="@string/read_theme"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/read_theme" />
<com.hippo.widget.CuteSpinner
android:id="@+id/read_theme"
@@ -142,68 +137,60 @@
</LinearLayout>
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/keep_screen_on"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_read_keep_screen_on"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_keep_screen_on" />
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/show_clock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_read_show_clock"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_show_clock" />
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/show_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_read_show_progress"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_show_progress" />
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/show_battery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_read_show_battery"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_show_battery" />
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/show_page_interval"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_read_show_page_interval"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_show_page_interval" />
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/volume_page"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_read_volume_page"
android:textColor="?android:attr/textColorPrimary" />
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/reverse_volume_page"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_read_reverse_volume"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_reverse_volume" />
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/reading_fullscreen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_read_reading_fullscreen"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_reading_fullscreen" />
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/custom_screen_lightness"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_read_custom_screen_lightness"
android:textColor="?android:attr/textColorPrimary" />
android:text="@string/settings_read_custom_screen_lightness" />
<SeekBar
android:id="@+id/screen_lightness"
@@ -212,4 +199,4 @@
android:max="200" />
</LinearLayout>
</rikka.widget.borderview.BorderNestedScrollView>
</androidx.core.widget.NestedScrollView>
+2 -5
View File
@@ -14,12 +14,10 @@
~ limitations under the License.
-->
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/Widget.Material3.CardView.Filled"
style="@style/Widget.Material3.CardView.Elevated"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:cardBackgroundColor="?android:attr/windowBackground">
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
@@ -32,7 +30,6 @@
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
android:saveEnabled="false" />
<FrameLayout
@@ -70,9 +70,9 @@
android:maxLines="5"
android:textSize="@dimen/text_little_large" />
<com.google.android.material.chip.Chip
<Button
android:id="@+id/uploader"
style="@style/Widget.Material3.Chip.Assist"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
@@ -81,17 +81,16 @@
android:singleLine="true"
android:textAllCaps="true" />
<com.google.android.material.chip.Chip
<Button
android:id="@+id/category"
style="@style/Widget.Material3.Chip.Assist"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/uploader"
android:layout_alignStart="@id/title"
android:layout_below="@id/title"
android:layout_toRightOf="@id/uploader"
android:ellipsize="end"
android:singleLine="true"
android:textAllCaps="true"
android:textStyle="bold" />
android:textAllCaps="true" />
<ImageView
android:id="@+id/other_actions"
@@ -111,47 +110,37 @@
</RelativeLayout>
<com.google.android.material.card.MaterialCardView
<LinearLayout
android:id="@+id/action_card"
style="@style/Widget.Material3.CardView.Elevated"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/keyline_margin"
android:layout_marginRight="@dimen/keyline_margin"
app:cardUseCompatPadding="true">
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
<Button
android:id="@+id/download"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:layout_weight="1"
android:clickable="true"
android:focusable="true" />
<TextView
android:id="@+id/download"
style="@style/ButtonInCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:focusable="true" />
<android.widget.Space
android:layout_width="8dp"
android:layout_height="wrap_content" />
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="?attr/dividerColor" />
<Button
android:id="@+id/read"
style="@style/Widget.Material3.Button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:focusable="true"
android:text="@string/read" />
<TextView
android:id="@+id/read"
style="@style/ButtonInCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:focusable="true"
android:text="@string/read" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</LinearLayout>
</FrameLayout>
+2 -2
View File
@@ -24,7 +24,7 @@
android:id="@+id/search_category_chipgroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/search_item_interval"/>
android:layout_marginBottom="@dimen/search_item_interval" />
<com.hippo.widget.RadioGridGroup
android:id="@+id/normal_search_mode"
@@ -89,7 +89,7 @@
android:layout_height="wrap_content"
android:layout_weight="1" />
<Switch
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/search_enable_advance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -20,7 +20,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:visibility="gone" >
android:visibility="gone">
<com.hippo.widget.FixedAspectImageView
+5 -6
View File
@@ -14,20 +14,19 @@
~ limitations under the License.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_add"
android:icon="@drawable/v_plus_dark_x24"
android:title="@string/settings"
app:showAsAction="always" />
android:showAsAction="always"
android:title="@string/settings" />
<item
android:id="@+id/action_default_download_label"
android:icon="@drawable/v_download_box_dark_x24"
android:title="@string/default_download_label"
app:showAsAction="ifRoom" />
android:showAsAction="ifRoom"
android:title="@string/default_download_label" />
</menu>
@@ -14,13 +14,18 @@
~ limitations under the License.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_help"
android:icon="@drawable/v_help_circle_x24"
android:showAsAction="ifRoom"
android:title="@string/add" />
<item
android:id="@+id/action_add"
android:icon="@drawable/v_plus_dark_x24"
android:title="@string/add"
app:showAsAction="always" />
android:showAsAction="always"
android:title="@string/add" />
</menu>
@@ -759,4 +759,6 @@
<string name="app_link_not_verified_message">对于 Android 12 及更新的版本,您需要手动添加链接到已验证链接才能在 EhViewer 中打开 E-Hentai 链接。</string>
<string name="app_link_not_verified_title">应用链接未验证</string>
<string name="open_by_default">默认打开</string>
<string name="show_library_version">依赖库之版本</string>
</resources>
+2
View File
@@ -823,4 +823,6 @@
<string name="app_link_not_verified_message">For Android 12 and newer, you need to manually add link to verified links in order to open E-Hentai links in EhViewer.</string>
<string name="app_link_not_verified_title">App links not verified</string>
<string name="open_by_default">Open by default</string>
<string name="show_library_version">Library Version</string>
</resources>
+4 -4
View File
@@ -17,14 +17,14 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="save_parse_error_body"
android:summary="@string/settings_advanced_save_parse_error_body_summary"
android:title="@string/settings_advanced_save_parse_error_body"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="save_crash_log"
android:summary="@string/settings_advanced_save_crash_log_summary"
@@ -72,7 +72,7 @@
android:title="@string/settings_advanced_proxy"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="built_in_hosts_2"
android:summary="@string/settings_advanced_built_in_hosts_summary"
@@ -86,7 +86,7 @@
android:title="@string/settings_advanced_custom_hosts_title"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="domain_fronting"
android:summary="@string/settings_advanced_domain_fronting_summary"
+2 -2
View File
@@ -22,7 +22,7 @@
android:title="@string/settings_download_download_location"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="media_scan"
android:title="@string/settings_download_media_scan"
@@ -66,7 +66,7 @@
app:entryValues="@array/image_resolution_entry_values"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="download_origin_image"
android:summary="@string/settings_download_download_origin_image_summary"
+7 -7
View File
@@ -61,7 +61,7 @@
android:title="@string/dark_theme"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:key="black_dark_theme"
android:title="@string/black_dark_theme"
app:iconSpaceReserved="false" />
@@ -111,27 +111,27 @@
app:entryValues="@array/thumb_resolution_entry_values"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="fix_thumb_url"
android:title="@string/settings_eh_fix_thumb_url"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="show_jpn_title"
android:summary="@string/settings_eh_show_jpn_title_summary"
android:title="@string/settings_eh_show_jpn_title"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="show_gallery_pages"
android:summary="@string/settings_eh_show_gallery_pages_summary"
android:title="@string/settings_eh_show_gallery_pages"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="show_tag_translations"
android:summary="@string/settings_eh_show_tag_translations_summary"
@@ -151,13 +151,13 @@
android:title="@string/settings_eh_filter"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="cellular_network_warning"
android:title="@string/settings_eh_metered_network_warning"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="request_news"
android:title="@string/settings_request_news_title"
+1 -1
View File
@@ -8,7 +8,7 @@
android:title="@string/settings_privacy_pattern_protection_title"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="enable_secure"
android:title="@string/settings_privacy_secure"
+9 -9
View File
@@ -62,56 +62,56 @@
app:entryValues="@array/read_theme_entry_values"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="keep_screen_on"
android:title="@string/settings_read_keep_screen_on"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="gallery_show_clock"
android:title="@string/settings_read_show_clock"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="gallery_show_progress"
android:title="@string/settings_read_show_progress"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="gallery_show_battery"
android:title="@string/settings_read_show_battery"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="gallery_show_page_interval"
android:title="@string/settings_read_show_page_interval"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="volume_page"
android:title="@string/settings_read_volume_page"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:dependency="volume_page"
android:key="reserve_volume_page"
android:title="@string/settings_read_reverse_volume"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="reading_fullscreen"
android:title="@string/settings_read_reading_fullscreen"
app:iconSpaceReserved="false" />
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="custom_screen_lightness"
android:title="@string/settings_read_custom_screen_lightness"
+6
View File
@@ -1,3 +1,9 @@
buildscript {
ext {
compose = '1.2.0-beta02'
}
}
plugins {
id 'com.android.application' version '7.2.0' apply false
id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
+2 -2
View File
@@ -24,6 +24,6 @@ task executeDaoGenerator(type:JavaExec) {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'org.greenrobot:greendao-generator:3.3.0'
implementation 'org.jboss.forge.roaster:roaster-api:2.24.0.Final'
implementation 'org.jboss.forge.roaster:roaster-jdt:2.24.0.Final'
implementation 'org.jboss.forge.roaster:roaster-api:2.25.0.Final'
implementation 'org.jboss.forge.roaster:roaster-jdt:2.25.0.Final'
}
+7
View File
@@ -21,3 +21,10 @@ android.useAndroidX=true
android.enableJetifier=true
android.enableAppCompileTimeRClass=true
android.nonTransitiveRClass=true
# signing environment variable
signStoreFile=keystore/androidkey.jks
signStorePassword=000000
signkeyAlias=key0
signkeyPassword=000000
+1 -6
View File
@@ -12,12 +12,6 @@ android {
targetSdkVersion 32
consumerProguardFiles 'proguard-rules.pro'
externalNativeBuild {
cmake {
arguments '-DANDROID_STL=c++_static'
}
}
ndk {
abiFilters 'arm64-v8a', 'x86_64'
}
@@ -25,6 +19,7 @@ android {
externalNativeBuild {
cmake {
version "3.23.1"
path 'src/main/jni/CMakeLists.txt'
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
-keep class com.hippo.a7zip.* { *; }
-keep class com.hippo.* { *; }
-keep class com.hippo.image.* { *; }
@@ -5,4 +5,14 @@ public class Native {
public static void initialize() {
System.loadLibrary("ehviewer");
}
public static native String getlibarchiveVersion();
public static native String getliblzmaVersion();
public static native String getlibzstdVersion();
public static native String getlibjpeg_turboVersion();
public static native String getzlibVersion();
}
@@ -0,0 +1,105 @@
package com.hippo;
import android.content.Context;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
public class UriArchiveAccessor implements Closeable {
public static int OPEN_OK = 1;
public static int OPEN_ERR = 2;
private final OsReadableFile osf;
public UriArchiveAccessor(Context ctx, Uri uri) throws FileNotFoundException {
osf = new OsReadableFile(ctx, uri);
}
public int open() {
return openArchive(osf);
}
public void extractTargetIndexToOutputStream(int index, OutputStream os) {
extracttoOutputStream(osf, index, os);
}
private native int openArchive(OsReadableFile osf);
private native int extracttoOutputStream(OsReadableFile osf, int index, OutputStream os);
@Override
public void close() throws IOException {
osf.close();
}
static class OsReadableFile {
ParcelFileDescriptor pfd;
FileDescriptor fd;
public OsReadableFile(Context ctx, Uri uri) throws FileNotFoundException {
pfd = ctx.getContentResolver().openFileDescriptor(uri, "r");
fd = pfd.getFileDescriptor();
}
public int read(byte[] b, int off, int len) throws IOException, ErrnoException {
return Os.read(fd, b, off, len);
}
public int read(byte[] b) throws IOException, ErrnoException {
return read(b, 0, b.length);
}
public long length() throws IOException, ErrnoException {
return Os.fstat(fd).st_size;
}
public long seek(long pos, int whence) throws IOException, ErrnoException {
try {
return Os.lseek(fd, pos, whence);
} catch (Exception e) {
e.printStackTrace();
return -30;
}
}
public void rewind() throws IOException, ErrnoException {
Os.lseek(fd, 0, OsConstants.SEEK_SET);
}
public long skip(long n) throws IOException, ErrnoException {
long pos;
long len;
long newpos;
if (n <= 0) {
return 0;
}
pos = Os.lseek(fd, 0L, OsConstants.SEEK_CUR);
len = length();
newpos = pos + n;
if (newpos > len) {
newpos = len;
}
seek(newpos, OsConstants.SEEK_SET);
/* return the actual number of bytes skipped */
return newpos - pos;
}
public void close() throws IOException {
pfd.close();
try {
Os.close(fd);
} catch (ErrnoException e) {
throw new IOException("An ErrnoException occurs", e);
}
}
}
}
@@ -1,28 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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 com.hippo.a7zip;
public class ArchiveException extends Exception {
public ArchiveException(String message) {
super(message);
}
public ArchiveException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -1,76 +0,0 @@
/*
* Copyright 2020 Hippo Seven
*
* 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 com.hippo.a7zip;
import androidx.annotation.NonNull;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class FileSeekableInputStream extends SeekableInputStream {
private final RandomAccessFile file;
public FileSeekableInputStream(String path) throws FileNotFoundException {
this(new File(path));
}
public FileSeekableInputStream(File file) throws FileNotFoundException {
this(new RandomAccessFile(file, "r"));
}
public FileSeekableInputStream(RandomAccessFile file) {
this.file = file;
}
@Override
public void seek(long pos) throws IOException {
file.seek(pos);
}
@Override
public long tell() throws IOException {
return file.getFilePointer();
}
@Override
public long size() throws IOException {
return file.length();
}
@Override
public int read() throws IOException {
return file.read();
}
@Override
public int read(@NonNull byte[] b) throws IOException {
return file.read(b);
}
@Override
public int read(@NonNull byte[] b, int off, int len) throws IOException {
return file.read(b, off, len);
}
@Override
public void close() throws IOException {
file.close();
}
}
@@ -1,81 +0,0 @@
/*
* Copyright 2020 Hippo Seven
*
* 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 com.hippo.a7zip;
import androidx.annotation.NonNull;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class FileSeekableOutputStream extends SeekableOutputStream {
private final RandomAccessFile file;
public FileSeekableOutputStream(String path) throws FileNotFoundException {
this(new File(path));
}
public FileSeekableOutputStream(File file) throws FileNotFoundException {
this(new RandomAccessFile(file, "rw"));
}
public FileSeekableOutputStream(RandomAccessFile file) {
this.file = file;
}
@Override
public void seek(long pos) throws IOException {
file.seek(pos);
}
@Override
public long tell() throws IOException {
return file.getFilePointer();
}
@Override
public long size() throws IOException {
return file.length();
}
@Override
public void truncate(long size) throws IOException {
file.setLength(size);
}
@Override
public void write(int b) throws IOException {
file.write(b);
}
@Override
public void write(@NonNull byte[] b) throws IOException {
file.write(b);
}
@Override
public void write(@NonNull byte[] b, int off, int len) throws IOException {
file.write(b, off, len);
}
@Override
public void close() throws IOException {
file.close();
}
}
@@ -1,456 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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 com.hippo.a7zip;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
public class InArchive implements Closeable {
private long nativePtr;
@Nullable
private final Charset charset;
@Nullable
private final String password;
private InArchive(long nativePtr, @Nullable Charset charset, @Nullable String password) {
this.nativePtr = nativePtr;
this.charset = charset;
this.password = password;
}
private void checkClosed() {
if (nativePtr == 0) {
throw new IllegalStateException("This InArchive is closed.");
}
}
// Sometimes p7zip returns string in the original charset, sometimes in utf-16.
// If it's in the original charset, each byte stores in each char,
// so every char in the string is smaller than 0xFF.
// But if every char in the string is smaller than 0xFF,
// it's hard to tell the string is in utf-16 or the original charset.
// TODO Let p7zip tell whether it have encoded the string.
private static String applyCharsetToString(String str, Charset charset) {
if (str == null || charset == null) {
return str;
}
int length = str.length();
for (int i = 0; i < length; i++) {
char c = str.charAt(i);
if (c > 0xFF) {
// It's not a pure byte list, can't apply charset
return str;
}
}
byte[] bytes = new byte[length];
for (int i = 0; i < length; i++) {
bytes[i] = (byte) str.charAt(i);
}
return new String(bytes, charset);
}
private static String applyCharsetToPassword(String str, Charset charset) {
if (str == null || charset == null) {
return str;
}
byte[] bytes = str.getBytes(charset);
char[] chars = new char[bytes.length];
for (int i = 0; i < chars.length; i++) {
chars[i] = (char) (bytes[i] & 0xFF);
}
return new String(chars);
}
/**
* Returns the format name of this archive.
* Empty string if can't get the name.
*/
@NonNull
public String getFormatName() {
checkClosed();
return nativeGetFormatName(nativePtr);
}
/**
* Returns the number of entries in this archive.
* {@code -1} if get error.
*/
public int getNumberOfEntries() {
checkClosed();
return nativeGetNumberOfEntries(nativePtr);
}
/**
* Returns the type of the property for the archive.
*
* @param propID the id of the property
* @return one of {@link PropType}
*/
public PropType getArchivePropertyType(PropID propID) {
int type = nativeGetArchivePropertyType(nativePtr, propID.ordinal());
if (type >= 0 && type < PropType.values().length) {
return PropType.values()[type];
} else {
return PropType.UNKNOWN;
}
}
/**
* Returns boolean property for the archive.
*
* @param propID the id of the property
* @return the boolean property, {@code false} if get error
*/
public boolean getArchiveBooleanProperty(PropID propID) {
checkClosed();
return nativeGetArchiveBooleanProperty(nativePtr, propID.ordinal());
}
/**
* Returns int property for the archive.
*
* @param propID the id of the property
* @return the int property, {@code 0} if get error
*/
public int getArchiveIntProperty(PropID propID) {
checkClosed();
return nativeGetArchiveIntProperty(nativePtr, propID.ordinal());
}
/**
* Returns long property for the archive.
*
* @param propID the id of the property
* @return the long property, {@code 0} if get error
*/
public long getArchiveLongProperty(PropID propID) {
checkClosed();
return nativeGetArchiveLongProperty(nativePtr, propID.ordinal());
}
/**
* Returns string property for the archive.
*
* @param propID the id of the property
* @return the string property, empty string if get error
*/
@NonNull
public String getArchiveStringProperty(PropID propID) {
return getArchiveStringProperty(propID, charset);
}
/**
* Returns string property for the archive.
*
* @param propID the id of the property
* @param charset the charset of the string, {@code null} to let p7zip handle it
* @return the string property, empty string if get error
*/
@NonNull
public String getArchiveStringProperty(PropID propID, @Nullable Charset charset) {
checkClosed();
String str = nativeGetArchiveStringProperty(nativePtr, propID.ordinal());
str = applyCharsetToString(str, charset);
return str != null ? str : "";
}
/**
* Returns the type of the property for the archive.
*
* @param propID the id of the property
* @return one of {@link PropType}
*/
public PropType getEntryPropertyType(int index, PropID propID) {
int type = nativeGetEntryPropertyType(nativePtr, index, propID.ordinal());
if (type >= 0 && type < PropType.values().length) {
return PropType.values()[type];
} else {
return PropType.UNKNOWN;
}
}
/**
* Returns boolean property for the entry.
*
* @param index the index of the entry
* @param propID the id of the property
* @return the boolean property, {@code false} if get error
*/
public boolean getEntryBooleanProperty(int index, PropID propID) {
checkClosed();
return nativeGetEntryBooleanProperty(nativePtr, index, propID.ordinal());
}
/**
* Returns int property for the entry.
*
* @param index the index of the entry
* @param propID the id of the property
* @return the int property, {@code 0} if get error
*/
public int getEntryIntProperty(int index, PropID propID) {
checkClosed();
return nativeGetEntryIntProperty(nativePtr, index, propID.ordinal());
}
/**
* Returns long property for the entry.
*
* @param index the index of the entry
* @param propID the id of the property
* @return the long property, {@code 0} if get error
*/
public long getEntryLongProperty(int index, PropID propID) {
checkClosed();
return nativeGetEntryLongProperty(nativePtr, index, propID.ordinal());
}
/**
* Returns string property for the entry.
*
* @param index the index of the entry
* @param propID the id of the property
* @return the string property, empty string if get error
*/
@NonNull
public String getEntryStringProperty(int index, PropID propID) {
return getEntryStringProperty(index, propID, charset);
}
/**
* Returns string property for the entry.
*
* @param index the index of the entry
* @param propID the id of the property
* @param charset the charset of the string, {@code null} to let p7zip handle it
* @return the string property, empty string if get error
*/
@NonNull
public String getEntryStringProperty(int index, PropID propID, @Nullable Charset charset) {
checkClosed();
String str = nativeGetEntryStringProperty(nativePtr, index, propID.ordinal());
str = applyCharsetToString(str, charset);
return str != null ? str : "";
}
/**
* Returns the path of the entry.
*
* @param index the index of the entry
* @return the path, empty string if get error
*/
@NonNull
public String getEntryPath(int index) {
return getEntryPath(index, charset);
}
/**
* Returns the path of the entry.
*
* @param index the index of the entry
* @param charset the charset of the string, {@code null} to let p7zip handle it
* @return the path, empty string if get error
*/
@NonNull
public String getEntryPath(int index, @Nullable Charset charset) {
return getEntryStringProperty(index, PropID.PATH, charset);
}
/**
* Returns the stream of the entry. Only a few archive formats support it.
*
* @param index the index of the entry
* @return the stream of the entry
* @throws ArchiveException if the archive format doesn't support the operation or get error
* @see #extractEntry(int, OutputStream)
* @see #extractEntry(int, String, OutputStream)
*/
@NonNull
public InputStream getEntryStream(int index) throws ArchiveException {
return nativeGetEntryStream(nativePtr, index);
}
/**
* Extracts the context of the entry into the output stream.
*
* @param index the index of the entry
* @param os the output steam to receive the content,
* it will be closed at the end of this method
* @throws ArchiveException if get error
* @see #getEntryStream(int)
*/
public void extractEntry(int index, @NonNull OutputStream os) throws ArchiveException {
extractEntry(index, password, os);
}
/**
* Extracts the context of the entry into the output stream.
*
* @param index the index of the entry
* @param password the password of the entry
* @param os the output steam to receive the content,
* it will be closed at the end of this method
* @throws ArchiveException if get error
*/
@SuppressWarnings("ThrowFromFinallyBlock")
public void extractEntry(int index, String password, @NonNull OutputStream os) throws ArchiveException {
try {
checkClosed();
nativeExtractEntry(nativePtr, index, password, os);
} finally {
try {
os.close();
} catch (IOException e) {
throw new ArchiveException("Catch IOException while closing the OutputStream", e);
}
}
}
@Override
public void close() {
if (nativePtr != 0) {
nativeClose(nativePtr);
nativePtr = 0;
}
}
/**
* Returns {@code true} if the archive is closed.
*/
public boolean isClosed() {
return nativePtr == 0;
}
@NonNull
public static InArchive open(File file) throws ArchiveException {
try {
return open(new FileSeekableInputStream(file), null, null, file.getName(), new OpenVolumeInDirCallback(file.getParentFile()));
} catch (FileNotFoundException e) {
throw new ArchiveException("Can't open the archive: " + file.getPath(), e);
}
}
@NonNull
public static InArchive open(SeekableInputStream stream) throws ArchiveException {
return open(stream, null, null, null, null);
}
/**
* Opens an archive to read from the specified stream.
* <p>
* {@code charset} is for password and string property.
* The charset of string property can reset in
* {@link InArchive#getArchiveStringProperty(PropID, Charset)}.
*/
@NonNull
public static InArchive open(
SeekableInputStream stream,
@Nullable Charset charset,
@Nullable String password,
@Nullable String filename,
@Nullable OpenVolumeCallback openVolumeCallback
) throws ArchiveException {
password = applyCharsetToPassword(password, charset);
long nativePtr = nativeOpen(stream, password, filename, openVolumeCallback);
if (nativePtr == 0) {
// It should not be 0
throw new ArchiveException("a7zip is buggy");
}
return new InArchive(nativePtr, charset, password);
}
@Keep
public interface OpenVolumeCallback {
@NonNull
SeekableInputStream openVolume(String filename) throws ArchiveException;
}
public static class OpenVolumeInDirCallback implements OpenVolumeCallback {
private final File dir;
public OpenVolumeInDirCallback(File dir) {
this.dir = dir;
}
@NonNull
@Override
public SeekableInputStream openVolume(String filename) throws ArchiveException {
try {
return new FileSeekableInputStream(new File(dir, filename));
} catch (FileNotFoundException e) {
throw new ArchiveException("Can't find the file<" + filename + "> in dir<" + dir.getPath() + ">", e);
}
}
}
private static native long nativeOpen(
SeekableInputStream stream,
String password,
String filename,
OpenVolumeCallback openVolumeCallback
) throws ArchiveException;
private static native String nativeGetFormatName(long nativePtr);
private static native int nativeGetNumberOfEntries(long nativePtr);
private static native int nativeGetArchivePropertyType(long nativePtr, int propID);
private static native boolean nativeGetArchiveBooleanProperty(long nativePtr, int propID);
private static native int nativeGetArchiveIntProperty(long nativePtr, int propID);
private static native long nativeGetArchiveLongProperty(long nativePtr, int propID);
@Nullable
private static native String nativeGetArchiveStringProperty(long nativePtr, int propID);
private static native int nativeGetEntryPropertyType(long nativePtr, int index, int propID);
private static native boolean nativeGetEntryBooleanProperty(long nativePtr, int index, int propID);
private static native int nativeGetEntryIntProperty(long nativePtr, int index, int propID);
private static native long nativeGetEntryLongProperty(long nativePtr, int index, int propID);
@Nullable
private static native String nativeGetEntryStringProperty(long nativePtr, int index, int propID);
@NonNull
private static native InputStream nativeGetEntryStream(long nativePtr, int index) throws ArchiveException;
private static native void nativeExtractEntry(long nativePtr, int index, String password, OutputStream os) throws ArchiveException;
private static native void nativeClose(long nativePtr);
}
@@ -1,66 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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 com.hippo.a7zip;
import androidx.annotation.NonNull;
import java.io.IOException;
import java.io.InputStream;
class NativeInputStream extends InputStream {
private long nativePtr;
private final byte[] scratch = new byte[8];
private NativeInputStream(long nativePtr) {
this.nativePtr = nativePtr;
}
private void checkClosed() {
if (nativePtr == 0) {
throw new IllegalStateException("This JavaInputStream is closed.");
}
}
@Override
public int read() throws IOException {
return (read(scratch, 0, 1) != -1) ? scratch[0] & 0xff : -1;
}
@Override
public int read(@NonNull byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
checkClosed();
return nativeRead(nativePtr, b, off, len);
}
@Override
public void close() throws IOException {
if (nativePtr != 0) {
nativeClose(nativePtr);
nativePtr = 0;
}
}
private static native int nativeRead(long nativePtr, byte[] b, int off, int len) throws IOException;
private static native void nativeClose(long nativePtr) throws IOException;
}
@@ -1,89 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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 com.hippo.a7zip;
import androidx.annotation.NonNull;
import java.io.IOException;
class NativeSeekableInputStream extends SeekableInputStream {
private long nativePtr;
private final byte[] scratch = new byte[8];
private NativeSeekableInputStream(long nativePtr) {
this.nativePtr = nativePtr;
}
private void checkClosed() {
if (nativePtr == 0) {
throw new IllegalStateException("This JavaSeekableInputStream is closed.");
}
}
@Override
public void seek(long pos) throws IOException {
checkClosed();
nativeSeek(nativePtr, pos);
}
@Override
public long tell() throws IOException {
checkClosed();
return nativeTell(nativePtr);
}
@Override
public long size() throws IOException {
checkClosed();
return nativeSize(nativePtr);
}
@Override
public int read() throws IOException {
return (read(scratch, 0, 1) != -1) ? scratch[0] & 0xff : -1;
}
@Override
public int read(@NonNull byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
checkClosed();
return nativeRead(nativePtr, b, off, len);
}
@Override
public void close() throws IOException {
if (nativePtr != 0) {
nativeClose(nativePtr);
nativePtr = 0;
}
}
private static native void nativeSeek(long nativePtr, long pos) throws IOException;
private static native long nativeTell(long nativePtr) throws IOException;
private static native long nativeSize(long nativePtr) throws IOException;
private static native int nativeRead(long nativePtr, byte[] b, int off, int len) throws IOException;
private static native void nativeClose(long nativePtr) throws IOException;
}
@@ -1,31 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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 com.hippo.a7zip;
import androidx.annotation.Keep;
@Keep
public class PasswordException extends ArchiveException {
public PasswordException(String message) {
super(message);
}
public PasswordException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -1,116 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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 com.hippo.a7zip;
public enum PropID {
NO_PROPERTY,
MAIN_SUBFILE,
HANDLER_ITEM_INDEX,
PATH,
NAME,
EXTENSION,
IS_DIR,
SIZE,
PACK_SIZE,
ATTRIB,
C_TIME,
A_TIME,
M_TIME,
SOLID,
COMMENTED,
ENCRYPTED,
SPLIT_BEFORE,
SPLIT_AFTER,
DICTIONARY_SIZE,
CRC,
TYPE,
IS_ANTI,
METHOD,
HOST_OS,
FILE_SYSTEM,
USER,
GROUP,
BLOCK,
COMMENT,
POSITION,
PREFIX,
NUM_SUB_DIRS,
NUM_SUB_FILES,
UNPACK_VER,
VOLUME,
IS_VOLUME,
OFFSET,
LINKS,
NUM_BLOCKS,
NUM_VOLUMES,
TIME_TYPE,
BIT64,
BIG_ENDIAN,
CPU,
PHY_SIZE,
HEADERS_SIZE,
CHECKSUM,
CHARACTS,
VA,
ID,
SHORT_NAME,
CREATOR_APP,
SECTOR_SIZE,
POSIX_ATTRIB,
SYM_LINK,
ERROR,
TOTAL_SIZE,
FREE_SPACE,
CLUSTER_SIZE,
VOLUME_NAME,
LOCAL_NAME,
PROVIDER,
NT_SECURE,
IS_ALT_STREAM,
IS_AUX,
IS_DELETED,
IS_TREE,
SHA1,
SHA256,
ERROR_TYPE,
NUM_ERRORS,
ERROR_FLAGS,
WARNING_FLAGS,
WARNING,
NUM_STREAMS,
NUM_ALT_STREAMS,
ALT_STREAMS_SIZE,
VIRTUAL_SIZE,
UNPACK_SIZE,
TOTAL_PHY_SIZE,
VOLUME_INDEX,
SUB_TYPE,
SHORT_COMMENT,
CODE_PAGE,
IS_NOT_ARC_TYPE,
PHY_SIZE_CANT_BE_DETECTED,
ZEROS_TAIL_IS_ALLOWED,
TAIL_SIZE,
EMBEDDED_STUB_SIZE,
NT_REPARSE,
HARD_LINK,
INODE,
STREAM_ID,
READ_ONLY,
OUT_NAME,
COPY_LINK,
}
@@ -1,28 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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 com.hippo.a7zip;
public enum PropType {
UNKNOWN,
EMPTY,
BOOL,
INT,
LONG,
FLOAT,
DOUBLE,
STRING,
}
@@ -1,40 +0,0 @@
/*
* Copyright 2020 Hippo Seven
*
* 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 com.hippo.a7zip;
import java.io.IOException;
import java.io.InputStream;
public abstract class SeekableInputStream extends InputStream {
/**
* Sets the position, measured from the beginning,
* at which the next read occurs. The offset may be
* set beyond the end of the file.
*/
public abstract void seek(long pos) throws IOException;
/**
* Returns current position, measured from the beginning.
*/
public abstract long tell() throws IOException;
/**
* Returns the size.
*/
public abstract long size() throws IOException;
}
@@ -1,45 +0,0 @@
/*
* Copyright 2020 Hippo Seven
*
* 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 com.hippo.a7zip;
import java.io.IOException;
import java.io.OutputStream;
public abstract class SeekableOutputStream extends OutputStream {
/**
* Sets the position, measured from the beginning,
* at which the next write occurs. The offset may be
* set beyond the end of the file.
*/
public abstract void seek(long pos) throws IOException;
/**
* Returns current position, measured from the beginning.
*/
public abstract long tell() throws IOException;
/**
* Returns the size.
*/
public abstract long size() throws IOException;
/**
* Sets the size.
*/
public abstract void truncate(long size) throws IOException;
}
+78 -80
View File
@@ -55,12 +55,10 @@ public final class Image {
public static final int FORMAT_GIF = 3;
private static final AtomicInteger sImageCount = new AtomicInteger();
private long mNativePtr;
private final int mFormat;
private final int mWidth;
private final int mHeight;
private long mNativePtr;
private Throwable mRecycleTracker;
private Image(long nativePtr, int format, int width, int height) {
@@ -72,6 +70,83 @@ public final class Image {
sImageCount.getAndIncrement();
}
/**
* Decode image from {@code InputStream}
*/
@Nullable
public static Image decode(InputStream is, boolean partially) {
if (!(is instanceof BufferedInputStream)) {
is = new BufferedInputStream(is);
}
return nativeDecode(is, partially);
}
/**
* Create a plain image from Bitmap
*/
@Nullable
public static Image create(Bitmap bitmap) {
return nativeCreate(bitmap);
}
/**
* Return all un-recycled {@code Image} instance count.
* It is useful for debug.
*/
public static int getImageCount() {
return sImageCount.get();
}
/**
* Return all supported image formats, exclude {@link #FORMAT_PLAIN}
*/
public static int[] getSupportedImageFormats() {
return nativeGetSupportedImageFormats();
}
/**
* Return decoder description of the image format,
* {@code null} for invalid image format.
*/
public static String getDecoderDescription(int format) {
return nativeGetDecoderDescription(format);
}
private static native Image nativeDecode(InputStream is, boolean partially);
private static native Image nativeCreate(Bitmap bitmap);
private static native int nativeGetByteCount(long nativePtr, int format);
private static native boolean nativeComplete(long nativePtr, int format);
private static native boolean nativeIsCompleted(long nativePtr, int format);
private static native void nativeRender(long nativePtr, int format,
int srcX, int srcY, Bitmap dst, int dstX, int dstY,
int width, int height, boolean fillBlank, int defaultColor);
private static native void nativeTexImage(long nativePtr, int format,
boolean init, int offsetX, int offsetY, int width, int height);
private static native void nativeAdvance(long nativePtr, int format);
private static native int nativeGetDelay(long nativePtr, int format);
private static native int nativeFrameCount(long nativePtr, int format);
private static native boolean nativeIsOpaque(long nativePtr, int format);
private static native boolean nativeIsGray(long nativePtr, int format, int error);
private static native void nativeClahe(long nativePtr, int format, boolean toGray);
private static native void nativeRecycle(long nativePtr, int format);
private static native int[] nativeGetSupportedImageFormats();
private static native String nativeGetDecoderDescription(int format);
/**
* Return the format of the image
*/
@@ -218,81 +293,4 @@ public final class Image {
public boolean isRecycled() {
return mNativePtr == 0;
}
/**
* Decode image from {@code InputStream}
*/
@Nullable
public static Image decode(InputStream is, boolean partially) {
if (!(is instanceof BufferedInputStream)) {
is = new BufferedInputStream(is);
}
return nativeDecode(is, partially);
}
/**
* Create a plain image from Bitmap
*/
@Nullable
public static Image create(Bitmap bitmap) {
return nativeCreate(bitmap);
}
/**
* Return all un-recycled {@code Image} instance count.
* It is useful for debug.
*/
public static int getImageCount() {
return sImageCount.get();
}
/**
* Return all supported image formats, exclude {@link #FORMAT_PLAIN}
*/
public static int[] getSupportedImageFormats() {
return nativeGetSupportedImageFormats();
}
/**
* Return decoder description of the image format,
* {@code null} for invalid image format.
*/
public static String getDecoderDescription(int format) {
return nativeGetDecoderDescription(format);
}
private static native Image nativeDecode(InputStream is, boolean partially);
private static native Image nativeCreate(Bitmap bitmap);
private static native int nativeGetByteCount(long nativePtr, int format);
private static native boolean nativeComplete(long nativePtr, int format);
private static native boolean nativeIsCompleted(long nativePtr, int format);
private static native void nativeRender(long nativePtr, int format,
int srcX, int srcY, Bitmap dst, int dstX, int dstY,
int width, int height, boolean fillBlank, int defaultColor);
private static native void nativeTexImage(long nativePtr, int format,
boolean init, int offsetX, int offsetY, int width, int height);
private static native void nativeAdvance(long nativePtr, int format);
private static native int nativeGetDelay(long nativePtr, int format);
private static native int nativeFrameCount(long nativePtr, int format);
private static native boolean nativeIsOpaque(long nativePtr, int format);
private static native boolean nativeIsGray(long nativePtr, int format, int error);
private static native void nativeClahe(long nativePtr, int format, boolean toGray);
private static native void nativeRecycle(long nativePtr, int format);
private static native int[] nativeGetSupportedImageFormats();
private static native String nativeGetDecoderDescription(int format);
}
@@ -40,19 +40,18 @@ import java.util.Set;
public final class ImageBitmap implements Animatable, Runnable {
private static final Handler HANDLER = new Handler(Looper.getMainLooper());
@Nullable
private Image mImage;
@NonNull
private final Bitmap mBitmap;
private final int mFormat;
private final boolean mIsOpaque;
private final int mByteCount;
private final int mFrameCount;
private final Set<WeakReference<Callback>> mCallbackSet = new LinkedHashSet<>();
@Nullable
private Image mImage;
private int mReferences;
private int mAnimationReferences;
private boolean mRunning;
private final Set<WeakReference<Callback>> mCallbackSet = new LinkedHashSet<>();
private ImageBitmap(@NonNull Image image) throws OutOfMemoryError {
int width = image.getWidth();
+31 -11
View File
@@ -1,17 +1,37 @@
project(ehviewer)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Oz -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Oz -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -fno-stack-protector")
# Build liblzma as shared lib
set(BUILD_SHARED_LIBS ON)
add_subdirectory(liblzma)
add_subdirectory(a7zip)
# Build libzstd
add_subdirectory(libzstd/build/cmake)
# Configure libarchive for android platform
include_directories(libarchive/contrib/android/include)
# Configure lzma support for libarchive
include_directories(liblzma/src/liblzma/api)
SET(HAVE_LIBLZMA 1)
SET(HAVE_LZMA_H 1)
SET(HAVE_LZMA_STREAM_ENCODER_MT 1)
SET(HAVE_LZMADEC_H 1)
SET(HAVE_LIBLZMADEC 1)
# Configure zstd support for libarchive
include_directories(libzstd/lib)
SET(HAVE_LIBZSTD 1)
SET(HAVE_LIBZSTD_COMPRESSOR 1)
SET(HAVE_ZSTD_H 1)
# Build libarchive
add_subdirectory(libarchive)
# Build hippo's image lib
add_subdirectory(image)
add_subdirectory(integrity)
add_library(${PROJECT_NAME} SHARED main.c)
target_compile_options(${PROJECT_NAME} PUBLIC -Oz -fvisibility=hidden -fvisibility-inlines-hidden -fno-exceptions)
target_include_directories(${PROJECT_NAME} PUBLIC a7zip/a7zip image/image integrity)
target_link_libraries(${PROJECT_NAME} a7zip image genuine)
# Build and link our app's native lib
add_library(${PROJECT_NAME} SHARED main.c archive.c)
target_include_directories(${PROJECT_NAME} PUBLIC image/image libarchive/libarchive)
target_link_libraries(${PROJECT_NAME} image archive)
-24
View File
@@ -1,24 +0,0 @@
cmake_minimum_required(VERSION 3.4.1)
project(a7zip C CXX)
add_subdirectory(p7zip)
set(A_SEVEN_ZIP_SOURCES
a7zip/BlackHole.cpp
a7zip/InArchive.cpp
a7zip/JavaEnv.cpp
a7zip/JavaHelper.cpp
a7zip/JavaInArchive.cpp
a7zip/JavaInitA7Zip.cpp
a7zip/JavaInputStream.cpp
a7zip/JavaSeekableInputStream.cpp
a7zip/OpenVolumeCallback.cpp
a7zip/OutputStream.cpp
a7zip/SeekableInputStream.cpp
a7zip/SevenZip.cpp
)
add_library(a7zip STATIC ${A_SEVEN_ZIP_SOURCES})
target_link_libraries(a7zip PUBLIC p7zip log)
@@ -1,69 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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.
*/
#include "BlackHole.h"
using namespace a7zip;
BlackHole::BlackHole(): pos(0), size(0) { }
HRESULT BlackHole::Write(const void*, UInt32 size, UInt32* processedSize) {
if (processedSize != nullptr) {
*processedSize = size;
}
this->pos += size;
if (this->size < this->pos) {
this->size = this->pos;
}
return S_OK;
}
HRESULT BlackHole::Seek(Int64 offset, UInt32 seekOrigin, UInt64* newPosition) {
Int64 newPos = -1;
switch (seekOrigin) {
case STREAM_SEEK_SET:
newPos = offset;
break;
case STREAM_SEEK_CUR:
newPos = this->pos + offset;
break;
case STREAM_SEEK_END:
newPos = this->size + offset;
break;
default:
return E_INVALIDARG;
}
if (newPos < 0) {
return STG_E_INVALIDFUNCTION;
}
*newPosition = this->pos;
return S_OK;
}
HRESULT BlackHole::SetSize(UInt64 newSize) {
this->size = newSize;
if (this->pos > this->size) {
this->pos = this->size;
}
return S_OK;
}
@@ -1,47 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_BLACK_HOLE_H__
#define __A7ZIP_BLACK_HOLE_H__
#include <Common/MyCom.h>
#include <7zip/IStream.h>
#include "Log.h"
namespace a7zip {
class BlackHole :
public IOutStream,
public CMyUnknownImp
{
public:
BlackHole();
public:
MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStream)
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
STDMETHOD(SetSize)(UInt64 newSize);
private:
UInt64 pos;
UInt64 size;
};
}
#endif //__A7ZIP_BLACK_HOLE_H__
@@ -1,360 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#include "InArchive.h"
#include <Windows/PropVariant.h>
#include <7zip/ICoder.h>
#include <7zip/IPassword.h>
#include "BlackHole.h"
#include "Log.h"
#include "Utils.h"
using namespace a7zip;
class ArchiveExtractCallback :
public IArchiveExtractCallback,
public ICryptoGetTextPassword,
public CMyUnknownImp
{
public:
ArchiveExtractCallback(UInt32 index, BSTR password, CMyComPtr<ISequentialOutStream>& out_stream);
~ArchiveExtractCallback();
public:
MY_UNKNOWN_IMP2(IArchiveExtractCallback, ICryptoGetTextPassword)
STDMETHOD(SetTotal)(UInt64 total);
STDMETHOD(SetCompleted)(const UInt64 *completeValue);
STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream** outStream, Int32 askExtractMode);
STDMETHOD(PrepareOperation)(Int32 askExtractMode);
STDMETHOD(SetOperationResult)(Int32 opRes);
STDMETHOD(CryptoGetTextPassword)(BSTR *password);
HRESULT GetBetterResult(HRESULT result);
private:
UInt32 index;
BSTR password;
CMyComPtr<ISequentialOutStream> out_stream;
bool has_asked_password;
};
ArchiveExtractCallback::ArchiveExtractCallback(
UInt32 index,
BSTR password,
CMyComPtr<ISequentialOutStream>& out_stream
) :
index(index),
password(::SysAllocString(password)),
out_stream(out_stream),
has_asked_password(false) {}
ArchiveExtractCallback::~ArchiveExtractCallback() {
::SysFreeString(password);
}
HRESULT ArchiveExtractCallback::SetTotal(UInt64 total) {
// Ignored
return S_OK;
}
HRESULT ArchiveExtractCallback::SetCompleted(const UInt64 *completeValue) {
// Ignored
return S_OK;
}
HRESULT ArchiveExtractCallback::GetStream(
UInt32 index,
ISequentialOutStream** outStream,
Int32 askExtractMode
) {
// If it's not extract mode or the index is different, return a black hole to skip data
if (askExtractMode != NArchive::NExtract::NAskMode::kExtract || this->index != index) {
CMyComPtr<ISequentialOutStream> black_hole(new BlackHole());
*outStream = black_hole.Detach();
return S_OK;
}
if (out_stream == nullptr) {
return E_NO_OUT_STREAM;
}
CMyComPtr<ISequentialOutStream> steam_copy(out_stream);
*outStream = steam_copy.Detach();
return S_OK;
}
HRESULT ArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) {
// Always return S_OK
return S_OK;
}
HRESULT ArchiveExtractCallback::SetOperationResult(Int32 opRes) {
// Stop extracting action if operation result is not OK
switch (opRes) {
case NArchive::NExtract::NOperationResult::kOK:
return S_OK;
case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
return E_UNSUPPORTED_METHOD;
case NArchive::NExtract::NOperationResult::kDataError:
return E_DATA_ERROR;
case NArchive::NExtract::NOperationResult::kCRCError:
return E_CRC_ERROR;
case NArchive::NExtract::NOperationResult::kUnavailable:
return E_UNAVAILABLE;
case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
return E_UNEXPECTED_END;
case NArchive::NExtract::NOperationResult::kDataAfterEnd:
return E_DATA_AFTER_END;
case NArchive::NExtract::NOperationResult::kIsNotArc:
return E_IS_NOT_ARC;
case NArchive::NExtract::NOperationResult::kHeadersError:
return E_HEADERS_ERROR;
case NArchive::NExtract::NOperationResult::kWrongPassword:
return E_WRONG_PASSWORD;
default:
return E_UNKNOWN_ERROR;
}
}
HRESULT ArchiveExtractCallback::CryptoGetTextPassword(BSTR* password) {
has_asked_password = true;
*password = ::SysAllocString(this->password);
return this->password != nullptr ? S_OK : E_NO_PASSWORD;
}
HRESULT ArchiveExtractCallback::GetBetterResult(HRESULT result) {
if (result == S_OK) {
return S_OK;
} else if (has_asked_password) {
if (password != nullptr) {
return E_WRONG_PASSWORD;
} else {
return E_NO_PASSWORD;
}
} else {
return result;
}
}
InArchive::InArchive(
InArchive* parent,
CMyComPtr<IInArchive>& in_archive,
AString& format_name
) :
parent(parent),
in_archive(in_archive),
format_name(format_name) { }
InArchive::~InArchive() {
this->in_archive->Close();
if (parent != nullptr) {
delete parent;
parent = nullptr;
}
}
const AString& InArchive::GetFormatName() {
return this->format_name;
}
HRESULT InArchive::GetNumberOfEntries(UInt32& number) {
return this->in_archive->GetNumberOfItems(&number);
}
static PropType VarTypeToPropType(VARTYPE var_enum) {
// TODO VT_ERROR
switch (var_enum) {
case VT_EMPTY:
return PT_EMPTY;
case VT_BOOL:
return PT_BOOL;
case VT_I1:
case VT_I2:
case VT_I4:
case VT_INT:
case VT_UI1:
case VT_UI2:
case VT_UI4:
case VT_UINT:
return PT_INT;
case VT_I8:
case VT_UI8:
case VT_FILETIME:
return PT_LONG;
case VT_BSTR:
return PT_STRING;
default:
return PT_UNKNOWN;
}
}
#define GET_ARCHIVE_PROPERTY_START(METHOD_NAME, VALUE_TYPE) \
HRESULT InArchive::METHOD_NAME(PROPID prop_id, VALUE_TYPE value) { \
NWindows::NCOM::CPropVariant prop; \
RETURN_SAME_IF_NOT_ZERO(this->in_archive->GetArchiveProperty(prop_id, &prop));
#define GET_ARCHIVE_PROPERTY_END \
}
#define GET_ENTRY_PROPERTY_START(METHOD_NAME, VALUE_TYPE) \
HRESULT InArchive::METHOD_NAME(UInt32 index, PROPID prop_id, VALUE_TYPE value) { \
NWindows::NCOM::CPropVariant prop; \
RETURN_SAME_IF_NOT_ZERO(this->in_archive->GetProperty(index, prop_id, &prop));
#define GET_ENTRY_PROPERTY_END \
}
#define GET_PROPERTY_TYPE \
*value = VarTypeToPropType(prop.vt); \
return S_OK;
GET_ARCHIVE_PROPERTY_START(GetArchivePropertyType, PropType*)
GET_PROPERTY_TYPE
GET_ARCHIVE_PROPERTY_END
GET_ENTRY_PROPERTY_START(GetEntryPropertyType, PropType*)
GET_PROPERTY_TYPE
GET_ENTRY_PROPERTY_END
#define GET_BOOLEAN_PROPERTY \
switch (prop.vt) { \
case VT_BOOL: \
*value = prop.boolVal != 0; \
return S_OK; \
case VT_EMPTY: \
return E_EMPTY_PROP; \
default: \
return E_INCONSISTENT_PROP_TYPE; \
}
GET_ARCHIVE_PROPERTY_START(GetArchiveBooleanProperty, bool*)
GET_BOOLEAN_PROPERTY
GET_ARCHIVE_PROPERTY_END
GET_ENTRY_PROPERTY_START(GetEntryBooleanProperty, bool*)
GET_BOOLEAN_PROPERTY
GET_ENTRY_PROPERTY_END
#define GET_INT_PROPERTY \
switch (prop.vt) { \
case VT_I1: \
*value = prop.cVal; \
return S_OK; \
case VT_I2: \
*value = prop.iVal; \
return S_OK; \
case VT_I4: \
*value = prop.lVal; \
return S_OK; \
case VT_INT: \
*value = prop.intVal; \
return S_OK; \
case VT_UI1: \
*value = prop.bVal; \
return S_OK; \
case VT_UI2: \
*value = prop.uiVal; \
return S_OK; \
case VT_UI4: \
*value = prop.ulVal; \
return S_OK; \
case VT_UINT: \
*value = prop.uintVal; \
return S_OK; \
case VT_EMPTY: \
return E_EMPTY_PROP; \
default: \
return E_INCONSISTENT_PROP_TYPE; \
}
GET_ARCHIVE_PROPERTY_START(GetArchiveIntProperty, Int32*)
GET_INT_PROPERTY
GET_ARCHIVE_PROPERTY_END
GET_ENTRY_PROPERTY_START(GetEntryIntProperty, Int32*)
GET_INT_PROPERTY
GET_ENTRY_PROPERTY_END
static const UInt64 FILE_TIME_OFFSET = (369 * 365 + 89) * 86400ULL * 10000000ULL;
static const UInt64 FILE_TIME_MULTIPLE = 10000ULL;
#define GET_LONG_PROPERTY \
switch (prop.vt) { \
case VT_I8: \
*value = prop.hVal.QuadPart; \
return S_OK; \
case VT_UI8: \
*value = prop.uhVal.QuadPart; \
return S_OK; \
case VT_FILETIME: \
*value = (*reinterpret_cast<UInt64*>(&prop.filetime) - FILE_TIME_OFFSET) / \
FILE_TIME_MULTIPLE; \
return S_OK; \
case VT_EMPTY: \
return E_EMPTY_PROP; \
default: \
return E_INCONSISTENT_PROP_TYPE; \
}
GET_ARCHIVE_PROPERTY_START(GetArchiveLongProperty, Int64*)
GET_LONG_PROPERTY
GET_ARCHIVE_PROPERTY_END
GET_ENTRY_PROPERTY_START(GetEntryLongProperty, Int64*)
GET_LONG_PROPERTY
GET_ENTRY_PROPERTY_END
#define GET_STRING_PROPERTY \
switch (prop.vt) { \
case VT_BSTR: \
*value = ::SysAllocString(prop.bstrVal); \
return S_OK; \
case VT_EMPTY: \
return E_EMPTY_PROP; \
default: \
return E_INCONSISTENT_PROP_TYPE; \
}
GET_ARCHIVE_PROPERTY_START(GetArchiveStringProperty, BSTR*)
GET_STRING_PROPERTY
GET_ARCHIVE_PROPERTY_END
GET_ENTRY_PROPERTY_START(GetEntryStringProperty, BSTR*)
GET_STRING_PROPERTY
GET_ENTRY_PROPERTY_END
HRESULT InArchive::GetEntryStream(UInt32 index, ISequentialInStream** stream) {
*stream = nullptr;
CMyComPtr<IInArchiveGetStream> in_archive_get_stream;
in_archive->QueryInterface(IID_IInArchiveGetStream, reinterpret_cast<void **>(&in_archive_get_stream));
if (in_archive_get_stream != nullptr) {
return in_archive_get_stream->GetStream(index, stream);
} else {
return E_NOTIMPL;
}
}
HRESULT InArchive::ExtractEntry(UInt32 index, BSTR password, CMyComPtr<ISequentialOutStream>& out_stream) {
CMyComPtr<ArchiveExtractCallback> callback(new ArchiveExtractCallback(index, password, out_stream));
HRESULT result = this->in_archive->Extract(&index, 1, false, callback);
return callback->GetBetterResult(result);
}
@@ -1,62 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_IN_ARCHIVE_H__
#define __A7ZIP_IN_ARCHIVE_H__
#include <include_windows/windows.h>
#include <Common/MyCom.h>
#include <Common/MyString.h>
#include <7zip/Archive/IArchive.h>
#include "PropType.h"
namespace a7zip {
class InArchive {
public:
InArchive(InArchive* parent, CMyComPtr<IInArchive>& in_archive, AString& format_name);
~InArchive();
public:
const AString& GetFormatName();
HRESULT GetNumberOfEntries(UInt32& number);
HRESULT GetArchivePropertyType(PROPID prop_id, PropType* prop_type);
HRESULT GetArchiveBooleanProperty(PROPID prop_id, bool *bool_prop);
HRESULT GetArchiveIntProperty(PROPID prop_id, Int32* int_prop);
HRESULT GetArchiveLongProperty(PROPID prop_id, Int64* long_prop);
HRESULT GetArchiveStringProperty(PROPID prop_id, BSTR* str_prop);
HRESULT GetEntryPropertyType(UInt32 index, PROPID prop_id, PropType* prop_type);
HRESULT GetEntryBooleanProperty(UInt32 index, PROPID prop_id, bool *bool_prop);
HRESULT GetEntryIntProperty(UInt32 index, PROPID prop_id, Int32* int_prop);
HRESULT GetEntryLongProperty(UInt32 index, PROPID prop_id, Int64* long_prop);
HRESULT GetEntryStringProperty(UInt32 index, PROPID prop_id, BSTR* str_prop);
HRESULT GetEntryStream(UInt32 index, ISequentialInStream** stream);
HRESULT ExtractEntry(UInt32 index, BSTR password, CMyComPtr<ISequentialOutStream>& out_stream);
private:
InArchive* parent;
CMyComPtr<IInArchive> in_archive;
AString format_name;
};
}
#endif //__A7ZIP_IN_ARCHIVE_H__
@@ -1,46 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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.
*/
#include "JavaEnv.h"
using namespace a7zip;
JavaVM* JavaEnv::jvm = nullptr;
void JavaEnv::Initialize(JavaVM* jvm) {
JavaEnv::jvm = jvm;
}
JavaEnv::JavaEnv() {
env = nullptr;
if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) == JNI_EDETACHED) {
should_detach = jvm->AttachCurrentThread(&env, nullptr) == JNI_OK;
} else {
should_detach = false;
}
}
JavaEnv::~JavaEnv() {
if (jvm != nullptr && should_detach) {
jvm->DetachCurrentThread();
env = nullptr;
should_detach = false;
}
}
bool JavaEnv::IsValid() {
return env != nullptr;
}
-46
View File
@@ -1,46 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_JAVA_ENV_H__
#define __A7ZIP_JAVA_ENV_H__
#include <jni.h>
namespace a7zip {
class JavaEnv {
public:
JavaEnv();
~JavaEnv();
bool IsValid();
JNIEnv* operator->() const { return env; }
explicit operator JNIEnv*() const { return env; }
private:
JNIEnv* env;
bool should_detach;
public:
static void Initialize(JavaVM* jvm);
private:
static JavaVM* jvm;
};
}
#endif //__A7ZIP_JAVA_ENV_H__
@@ -1,121 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#include "JavaHelper.h"
#include <jni.h>
#include <cstdio>
#include "Utils.h"
#define MAX_MSG_SIZE 1024
using namespace a7zip;
static jint ThrowExceptionInternal(
JNIEnv* env,
const char* exception_name,
const char* message,
va_list va_args
) {
char formatted_message[MAX_MSG_SIZE];
vsnprintf(formatted_message, MAX_MSG_SIZE, message, va_args);
jclass exception_class = env->FindClass(exception_name);
return env->ThrowNew(exception_class, formatted_message);
}
jint JavaHelper::ThrowException(
JNIEnv* env,
const char* exception_name,
const char* message,
...
) {
va_list va_args;
va_start(va_args, message);
jint result = ThrowExceptionInternal(env, exception_name, message, va_args);
va_end(va_args);
return result;
}
static const char* GetMessageForCode(HRESULT code) {
switch (code) {
case E_NOT_INITIALIZED:
return "The module is not initialized";
case S_OK:
case E_INTERNAL:
return "a7zip is buggy";
case E_CLASS_NOT_FOUND:
return "Can't find the class";
case E_METHOD_NOT_FOUND:
return "Can't find the method";
case E_JAVA_EXCEPTION:
return "Catch a java exception";
case E_FAILED_CONSTRUCT:
return "Failed to create new class";
case E_FAILED_REGISTER:
return "Failed to register methods";
case E_INCONSISTENT_PROP_TYPE:
return "Inconsistent property type";
case E_EMPTY_PROP:
return "Empty property";
case E_UNKNOWN_FORMAT:
return "Unknown archive format";
case E_UNSUPPORTED_EXTRACT_MODE:
return "Unsupported extract mode";
case E_NO_OUT_STREAM:
return "No out stream";
case E_UNSUPPORTED_METHOD:
return "Unsupported method";
case E_DATA_ERROR:
return "Data error";
case E_DATA_ERROR_ENCRYPTED:
return "Data Error in encrypted file. Wrong password?";
case E_CRC_ERROR:
return "CRC failed";
case E_CRC_ERROR_ENCRYPTED:
return "CRC Failed in encrypted file. Wrong password?";
case E_UNAVAILABLE:
return "Unavailable data";
case E_UNEXPECTED_END:
return "Unexpected end of data";
case E_DATA_AFTER_END:
return "There are some data after the end of the payload data";
case E_IS_NOT_ARC:
return "Is not archive";
case E_HEADERS_ERROR:
return "Headers Error";
case E_WRONG_PASSWORD:
return "Wrong password";
case E_NO_PASSWORD:
return "No password";
case E_NOTIMPL:
return "Not implemented";
case E_OUTOFMEMORY:
return "Out of memory";
case E_UNKNOWN_ERROR:
default:
return "Unknown error.";
}
}
jint JavaHelper::ThrowException(
JNIEnv* env,
const char* exception_name,
HRESULT code
) {
return ThrowException(env, exception_name, GetMessageForCode(code));
}
@@ -1,89 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_JAVA_HELPER_H__
#define __A7ZIP_JAVA_HELPER_H__
#include <jni.h>
#include <Common/MyWindows.h>
#define CLASS_NAME_ILLEGAL_STATE_EXCEPTION "java/lang/IllegalStateException"
#define CLASS_NAME_IO_EXCEPTION "java/io/IOException"
#define CLASS_NAME_ARCHIVE_EXCEPTION "com/hippo/a7zip/ArchiveException"
#define CLASS_NAME_PASSWORD_EXCEPTION "com/hippo/a7zip/PasswordException"
#define THROW_EXCEPTION(ENV, EXCEPTION_NAME, ...) \
do { \
a7zip::JavaHelper::ThrowException((ENV), (EXCEPTION_NAME), __VA_ARGS__); \
return; \
} while (0)
#define THROW_EXCEPTION_RET(ENV, RET, EXCEPTION_NAME, ...) \
do { \
a7zip::JavaHelper::ThrowException((ENV), (EXCEPTION_NAME), __VA_ARGS__); \
return (RET); \
} while (0)
#define THROW_IO_EXCEPTION(ENV, CODE) \
THROW_EXCEPTION(ENV, CLASS_NAME_IO_EXCEPTION, CODE)
#define THROW_IO_EXCEPTION_RET(ENV, RET, CODE) \
THROW_EXCEPTION_RET(ENV, RET, CLASS_NAME_IO_EXCEPTION, CODE)
#define THROW_ARCHIVE_EXCEPTION(ENV, CODE) \
do { \
if ((CODE) == E_NO_PASSWORD || (CODE) == E_WRONG_PASSWORD) { \
THROW_EXCEPTION(ENV, CLASS_NAME_PASSWORD_EXCEPTION, CODE); \
} else { \
THROW_EXCEPTION(ENV, CLASS_NAME_ARCHIVE_EXCEPTION, CODE); \
} \
} while (0)
#define THROW_ARCHIVE_EXCEPTION_RET(ENV, RET, CODE) \
do { \
if ((CODE) == E_NO_PASSWORD || (CODE) == E_WRONG_PASSWORD) { \
THROW_EXCEPTION_RET(ENV, RET, CLASS_NAME_PASSWORD_EXCEPTION, CODE); \
} else { \
THROW_EXCEPTION_RET(ENV, RET, CLASS_NAME_ARCHIVE_EXCEPTION, CODE); \
} \
} while (0)
#define CHECK_CLOSED(ENV, NATIVE_PTR) \
do { \
if ((NATIVE_PTR) == 0) { \
THROW_EXCEPTION(ENV, CLASS_NAME_ILLEGAL_STATE_EXCEPTION, "It's closed"); \
} \
} while (0)
#define CHECK_CLOSED_RET(ENV, RET, NATIVE_PTR) \
do { \
if ((NATIVE_PTR) == 0) { \
THROW_EXCEPTION_RET( \
ENV, RET, CLASS_NAME_ILLEGAL_STATE_EXCEPTION, "It's closed"); \
} \
} while (0)
namespace a7zip {
namespace JavaHelper {
jint ThrowException(JNIEnv* env, const char* exception_name, const char* message, ...);
jint ThrowException(JNIEnv* env, const char* exception_name, HRESULT code);
}
}
#endif //__A7ZIP_JAVA_HELPER_H__
@@ -1,397 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#include "JavaInArchive.h"
#include <cstdio>
#include <type_traits>
#include <include_windows/windows.h>
#include <7zip/Archive/IArchive.h>
#include "OpenVolumeCallback.h"
#include "SeekableInputStream.h"
#include "JavaHelper.h"
#include "JavaSeekableInputStream.h"
#include "JavaInputStream.h"
#include "Log.h"
#include "OutputStream.h"
#include "SevenZip.h"
#include "Utils.h"
#ifdef LOG_TAG
# undef LOG_TAG
#endif //LOG_TAG
#define LOG_TAG "JavaArchive"
using namespace a7zip;
static void CopyJStringToBSTR(BSTR bstr, const jchar* jstr, int length) {
for (int i = 0; i < length; i++) {
*bstr++ = *jstr++;
}
*bstr = 0;
}
static BSTR JStringToBSTR(JNIEnv* env, jstring jstr) {
BSTR bstr = nullptr;
if (jstr != nullptr) {
jsize length = env->GetStringLength(jstr);
const jchar* jchars = env->GetStringChars(jstr, nullptr);
bstr = ::SysAllocStringLen(nullptr, static_cast<UINT>(length));
CopyJStringToBSTR(bstr, jchars, length);
env->ReleaseStringChars(jstr, jchars);
}
return bstr;
}
static jlong NativeOpen(
JNIEnv* env,
jclass,
jobject stream,
jstring password,
jstring filename,
jobject open_volume_callback
) {
CMyComPtr<IInStream> in_stream = nullptr;
HRESULT result = SeekableInputStream::Create(env, stream, in_stream);
if (result != S_OK || in_stream == nullptr) {
// Call java methods before throw exception
if (in_stream != nullptr) {
in_stream.Release();
}
THROW_ARCHIVE_EXCEPTION_RET(env, 0, result);
}
BSTR bstr_password = nullptr;
BSTR bstr_filename = nullptr;
CMyComPtr<OpenVolumeCallback> open_volume_callback_wrapper = nullptr;
if (filename != nullptr && open_volume_callback != nullptr) {
result = OpenVolumeCallback::Create(env, open_volume_callback, open_volume_callback_wrapper);
if (result != S_OK) {
// Call java methods before throw exception
if (in_stream != nullptr) {
in_stream.Release();
}
THROW_ARCHIVE_EXCEPTION_RET(env, 0, result);
}
bstr_filename = JStringToBSTR(env, filename);
}
bstr_password = JStringToBSTR(env, password);
InArchive* archive = nullptr;
result = SevenZip::OpenArchive(in_stream, bstr_password, bstr_filename, open_volume_callback_wrapper, &archive);
::SysFreeString(bstr_password);
::SysFreeString(bstr_filename);
if (result != S_OK || archive == nullptr) {
// Call java methods before throw exception
in_stream.Release();
delete archive;
THROW_ARCHIVE_EXCEPTION_RET(env, 0, result);
}
return reinterpret_cast<jlong>(archive);
}
static jstring NativeGetFormatName(
JNIEnv* env,
jclass,
jlong native_ptr
) {
CHECK_CLOSED_RET(env, nullptr, native_ptr);
InArchive* archive = reinterpret_cast<InArchive*>(native_ptr);
return env->NewStringUTF(archive->GetFormatName());
}
static jint NativeGetNumberOfEntries(
JNIEnv* env,
jclass,
jlong native_ptr
) {
CHECK_CLOSED_RET(env, 0, native_ptr);
InArchive* archive = reinterpret_cast<InArchive*>(native_ptr);
UInt32 number = 0;
HRESULT result = archive->GetNumberOfEntries(number);
return result == S_OK ? number : -1;
}
#define GET_ARCHIVE_PROPERTY_START(METHOD_NAME, RETURN_TYPE) \
static RETURN_TYPE METHOD_NAME(JNIEnv* env, jclass, jlong native_ptr, jint prop_id) { \
CHECK_CLOSED_RET(env, 0, native_ptr); \
InArchive* archive = reinterpret_cast<InArchive*>(native_ptr);
#define GET_ARCHIVE_PROPERTY_END \
}
#define GET_ENTRY_PROPERTY_START(METHOD_NAME, RETURN_TYPE) \
static RETURN_TYPE METHOD_NAME(JNIEnv* env, jclass, jlong native_ptr, jint index, jint prop_id) {\
CHECK_CLOSED_RET(env, 0, native_ptr); \
InArchive* archive = reinterpret_cast<InArchive*>(native_ptr);
#define GET_ENTRY_PROPERTY_END \
}
#define GET_PROPERTY_TYPE(GETTER) \
PropType prop_type; \
HRESULT result = (GETTER); \
return result == S_OK ? prop_type : PT_UNKNOWN;
GET_ARCHIVE_PROPERTY_START(NativeGetArchivePropertyType, jint)
GET_PROPERTY_TYPE(archive->GetArchivePropertyType(static_cast<PROPID>(prop_id), &prop_type))
GET_ARCHIVE_PROPERTY_END
GET_ENTRY_PROPERTY_START(NativeGetEntryPropertyType, jint)
GET_PROPERTY_TYPE(archive->GetEntryPropertyType(static_cast<UInt32>(index), static_cast<PROPID>(prop_id), &prop_type))
GET_ENTRY_PROPERTY_END
#define GET_BOOL_TYPE(GETTER) \
bool bool_prop; \
HRESULT result = (GETTER); \
return result == S_OK ? bool_prop : false;
GET_ARCHIVE_PROPERTY_START(NativeGetArchiveBooleanProperty, jboolean)
GET_BOOL_TYPE(archive->GetArchiveBooleanProperty(static_cast<PROPID>(prop_id), &bool_prop))
GET_ARCHIVE_PROPERTY_END
GET_ENTRY_PROPERTY_START(NativeGetEntryBooleanProperty, jboolean)
GET_BOOL_TYPE(archive->GetEntryBooleanProperty(static_cast<UInt32>(index), static_cast<PROPID>(prop_id), &bool_prop))
GET_ENTRY_PROPERTY_END
#define GET_INT_TYPE(GETTER) \
Int32 int_prop; \
HRESULT result = (GETTER); \
return result == S_OK ? int_prop : 0;
GET_ARCHIVE_PROPERTY_START(NativeGetArchiveIntProperty, jint)
GET_INT_TYPE(archive->GetArchiveIntProperty(static_cast<PROPID>(prop_id), &int_prop))
GET_ARCHIVE_PROPERTY_END
GET_ENTRY_PROPERTY_START(NativeGetEntryIntProperty, jint)
GET_INT_TYPE(archive->GetEntryIntProperty(static_cast<UInt32>(index), static_cast<PROPID>(prop_id), &int_prop))
GET_ENTRY_PROPERTY_END
#define GET_LONG_TYPE(GETTER) \
Int64 long_prop; \
HRESULT result = (GETTER); \
return result == S_OK ? long_prop : 0;
GET_ARCHIVE_PROPERTY_START(NativeGetArchiveLongProperty, jlong)
GET_LONG_TYPE(archive->GetArchiveLongProperty(static_cast<PROPID>(prop_id), &long_prop))
GET_ARCHIVE_PROPERTY_END
GET_ENTRY_PROPERTY_START(NativeGetEntryLongProperty, jlong)
GET_LONG_TYPE(archive->GetEntryLongProperty(static_cast<UInt32>(index), static_cast<PROPID>(prop_id), &long_prop))
GET_ENTRY_PROPERTY_END
static void shrink(BSTR bstr) {
jchar* jstr = reinterpret_cast<jchar*>(bstr);
UINT n = ::SysStringLen(bstr);
for (UINT i = 0; i < n; i++) {
jstr[i] = static_cast<jchar>(bstr[i]);
}
jstr[n] = 0;
}
#define GET_STRING_PROPERTY(GETTER) \
BSTR str_prop = nullptr; \
HRESULT result = (GETTER); \
if (result != S_OK || str_prop == nullptr) { \
if (str_prop != nullptr) ::SysFreeString(str_prop); \
return nullptr; \
} \
shrink(str_prop); \
jstring jstr = \
env->NewString(reinterpret_cast<const jchar*>(str_prop), ::SysStringLen(str_prop)); \
::SysFreeString(str_prop); \
return jstr;
GET_ARCHIVE_PROPERTY_START(NativeGetArchiveStringProperty, jstring)
GET_STRING_PROPERTY(archive->GetArchiveStringProperty(static_cast<PROPID>(prop_id), &str_prop))
GET_ARCHIVE_PROPERTY_END
GET_ENTRY_PROPERTY_START(NativeGetEntryStringProperty, jstring)
GET_STRING_PROPERTY(archive->GetEntryStringProperty(static_cast<UInt32>(index), static_cast<PROPID>(prop_id), &str_prop))
GET_ENTRY_PROPERTY_END
static jobject NativeGetEntryStream(
JNIEnv* env,
jclass,
jlong native_ptr,
jint index
) {
CHECK_CLOSED_RET(env, nullptr, native_ptr);
InArchive* archive = reinterpret_cast<InArchive*>(native_ptr);
CMyComPtr<ISequentialInStream> sequential_in_stream = nullptr;
HRESULT result = archive->GetEntryStream(static_cast<UInt32>(index), &sequential_in_stream);
if (result != S_OK || sequential_in_stream == nullptr) {
if (sequential_in_stream != nullptr) {
// Release the stream manually before throw java exception
sequential_in_stream.Release();
}
THROW_ARCHIVE_EXCEPTION_RET(env, nullptr, result);
}
// Try to get IInStream
CMyComPtr<IInStream> in_stream = nullptr;
sequential_in_stream.QueryInterface(IID_IInStream, &in_stream);
if (in_stream != nullptr) {
// It's an IInStream
jobject object = nullptr;
result = JavaSeekableInputStream::NewInstance(env, in_stream, &object);
if (object == nullptr) {
// Release the stream manually before throw java exception
in_stream->Release();
sequential_in_stream->Release();
THROW_ARCHIVE_EXCEPTION_RET(env, nullptr, result);
}
return object;
} else {
// It's just an ISequentialInStream
jobject object = nullptr;
result = JavaInputStream::NewInstance(env, sequential_in_stream, &object);
if (object == nullptr) {
// Release the stream manually before throw java exception
sequential_in_stream->Release();
THROW_ARCHIVE_EXCEPTION_RET(env, nullptr, result);
}
return object;
}
}
static void NativeExtractEntry(
JNIEnv* env,
jclass,
jlong native_ptr,
jint index,
jstring password,
jobject stream
) {
CHECK_CLOSED(env, native_ptr);
InArchive* archive = reinterpret_cast<InArchive*>(native_ptr);
CMyComPtr<ISequentialOutStream> out_stream = nullptr;
HRESULT result = OutputStream::Create(env, stream, out_stream);
if (result != S_OK || out_stream == nullptr) {
if (out_stream != nullptr) {
// Call java methods before throw exception
out_stream.Release();
} else {
// Let java code closes the OutStream
}
THROW_ARCHIVE_EXCEPTION(env, result);
}
const jchar* j_password = nullptr;
BSTR bstr_password = nullptr;
if (password != nullptr) {
jsize length = env->GetStringLength(password);
j_password = env->GetStringChars(password, nullptr);
bstr_password = ::SysAllocStringLen(nullptr, static_cast<UINT>(length));
CopyJStringToBSTR(bstr_password, j_password, length);
}
result = archive->ExtractEntry(static_cast<UInt32>(index), bstr_password, out_stream);
if (password != nullptr) {
::SysFreeString(bstr_password);
env->ReleaseStringChars(password, j_password);
}
if (result != S_OK) {
// Call java methods before throw exception
out_stream.Release();
THROW_ARCHIVE_EXCEPTION(env, result);
}
}
static void NativeClose(
JNIEnv* env,
jclass,
jlong native_ptr
) {
CHECK_CLOSED(env, native_ptr);
InArchive* archive = reinterpret_cast<InArchive*>(native_ptr);
delete archive;
}
static JNINativeMethod archive_methods[] = {
{ "nativeOpen",
"(Lcom/hippo/a7zip/SeekableInputStream;Ljava/lang/String;Ljava/lang/String;Lcom/hippo/a7zip/InArchive$OpenVolumeCallback;)J",
reinterpret_cast<void *>(NativeOpen) },
{ "nativeGetFormatName",
"(J)Ljava/lang/String;",
reinterpret_cast<void *>(NativeGetFormatName) },
{ "nativeGetNumberOfEntries",
"(J)I",
reinterpret_cast<void *>(NativeGetNumberOfEntries) },
{ "nativeGetArchivePropertyType",
"(JI)I",
reinterpret_cast<void *>(NativeGetArchivePropertyType) },
{ "nativeGetArchiveBooleanProperty",
"(JI)Z",
reinterpret_cast<void *>(NativeGetArchiveBooleanProperty) },
{ "nativeGetArchiveIntProperty",
"(JI)I",
reinterpret_cast<void *>(NativeGetArchiveIntProperty) },
{ "nativeGetArchiveLongProperty",
"(JI)J",
reinterpret_cast<void *>(NativeGetArchiveLongProperty) },
{ "nativeGetArchiveStringProperty",
"(JI)Ljava/lang/String;",
reinterpret_cast<void *>(NativeGetArchiveStringProperty) },
{ "nativeGetEntryPropertyType",
"(JII)I",
reinterpret_cast<void *>(NativeGetEntryPropertyType) },
{ "nativeGetEntryBooleanProperty",
"(JII)Z",
reinterpret_cast<void *>(NativeGetEntryBooleanProperty) },
{ "nativeGetEntryIntProperty",
"(JII)I",
reinterpret_cast<void *>(NativeGetEntryIntProperty) },
{ "nativeGetEntryLongProperty",
"(JII)J",
reinterpret_cast<void *>(NativeGetEntryLongProperty) },
{ "nativeGetEntryStringProperty",
"(JII)Ljava/lang/String;",
reinterpret_cast<void *>(NativeGetEntryStringProperty) },
{ "nativeGetEntryStream",
"(JI)Ljava/io/InputStream;",
reinterpret_cast<void *>(NativeGetEntryStream) },
{ "nativeExtractEntry",
"(JILjava/lang/String;Ljava/io/OutputStream;)V",
reinterpret_cast<void *>(NativeExtractEntry) },
{ "nativeClose",
"(J)V",
reinterpret_cast<void *>(NativeClose) }
};
HRESULT JavaInArchive::RegisterMethods(JNIEnv* env) {
jclass clazz = env->FindClass("com/hippo/a7zip/InArchive");
if (clazz == nullptr) return E_CLASS_NOT_FOUND;
jint result = env->RegisterNatives(clazz, archive_methods, std::extent<decltype(archive_methods)>::value);
if (result < 0) {
return E_FAILED_REGISTER;
}
return S_OK;
}
@@ -1,32 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_JAVA_IN_ARCHIVE_H__
#define __A7ZIP_JAVA_IN_ARCHIVE_H__
#include <jni.h>
#include <Common/MyWindows.h>
namespace a7zip {
namespace JavaInArchive {
HRESULT RegisterMethods(JNIEnv* env);
}
}
#endif //__A7ZIP_JAVA_IN_ARCHIVE_H__
@@ -1,60 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#include <jni.h>
#include "SeekableInputStream.h"
#include "JavaEnv.h"
#include "JavaInArchive.h"
#include "JavaInitA7Zip.h"
#include "JavaSeekableInputStream.h"
#include "JavaInputStream.h"
#include "OpenVolumeCallback.h"
#include "OutputStream.h"
#include "SevenZip.h"
#include "Utils.h"
using namespace a7zip;
#ifdef __cplusplus
extern "C"
{
#endif
bool a7zip_onLoad(JavaVM *vm) {
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return false;
}
JavaEnv::Initialize(vm);
RETURN_JNI_ERR_IF_NOT_ZERO(SeekableInputStream::Initialize(env));
RETURN_JNI_ERR_IF_NOT_ZERO(JavaSeekableInputStream::Initialize(env));
RETURN_JNI_ERR_IF_NOT_ZERO(JavaInputStream::Initialize(env));
RETURN_JNI_ERR_IF_NOT_ZERO(OpenVolumeCallback::Initialize(env));
RETURN_JNI_ERR_IF_NOT_ZERO(OutputStream::Initialize(env));
RETURN_JNI_ERR_IF_NOT_ZERO(SevenZip::Initialize());
RETURN_JNI_ERR_IF_NOT_ZERO(JavaInArchive::RegisterMethods(static_cast<JNIEnv *>(env)));
RETURN_JNI_ERR_IF_NOT_ZERO(
JavaSeekableInputStream::RegisterMethods(static_cast<JNIEnv *>(env)));
RETURN_JNI_ERR_IF_NOT_ZERO(JavaInputStream::RegisterMethods(static_cast<JNIEnv *>(env)));
return true;
}
#ifdef __cplusplus
}
#endif
@@ -1,11 +0,0 @@
#include <jni.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C"
{
#endif
bool a7zip_onLoad(JavaVM *vm);
#ifdef __cplusplus
}
#endif
@@ -1,126 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#include "JavaInputStream.h"
#include <type_traits>
#include <Common/MyCom.h>
#include "JavaHelper.h"
#include "Utils.h"
using namespace a7zip;
static jint NativeRead(
JNIEnv* env,
jclass,
jlong native_ptr,
jbyteArray array,
jint offset,
jint length
) {
CHECK_CLOSED_RET(env, 0, native_ptr);
ISequentialInStream* stream = reinterpret_cast<ISequentialInStream*>(native_ptr);
jbyte* bytes = env->GetByteArrayElements(array, nullptr);
if (bytes == nullptr) THROW_IO_EXCEPTION_RET(env, 0, E_JAVA_EXCEPTION);
UInt32 processed_size;
HRESULT result = stream->Read(bytes + offset, static_cast<UInt32>(length), &processed_size);
env->ReleaseByteArrayElements(array, bytes, 0);
if (result != S_OK) THROW_IO_EXCEPTION_RET(env, 0, result);
if (length != 0 && processed_size == 0) {
// EOF
return -1;
}
return processed_size;
}
static void NativeClose(
JNIEnv* env,
jclass,
jlong native_ptr
) {
CHECK_CLOSED(env, native_ptr);
ISequentialInStream* stream = reinterpret_cast<ISequentialInStream*>(native_ptr);
stream->Release();
}
static bool initialized = false;
static jclass class_native_sequential_in_stream = nullptr;
static jmethodID constructor_native_sequential_in_stream = nullptr;
HRESULT JavaInputStream::Initialize(JNIEnv* env) {
if (initialized) {
return S_OK;
}
class_native_sequential_in_stream = env->FindClass("com/hippo/a7zip/NativeInputStream");
if (class_native_sequential_in_stream == nullptr) return E_CLASS_NOT_FOUND;
class_native_sequential_in_stream = static_cast<jclass>(env->NewGlobalRef(class_native_sequential_in_stream));
if (class_native_sequential_in_stream == nullptr) return E_OUTOFMEMORY;
constructor_native_sequential_in_stream = env->GetMethodID(class_native_sequential_in_stream, "<init>", "(J)V");
if (constructor_native_sequential_in_stream == nullptr) return E_METHOD_NOT_FOUND;
initialized = true;
return JNI_OK;
}
static JNINativeMethod stream_methods[] = {
{ "nativeRead",
"(J[BII)I",
reinterpret_cast<void *>(NativeRead) },
{ "nativeClose",
"(J)V",
reinterpret_cast<void *>(NativeClose) }
};
HRESULT JavaInputStream::RegisterMethods(JNIEnv* env) {
if (!initialized) {
return E_NOT_INITIALIZED;
}
jint result = env->RegisterNatives(class_native_sequential_in_stream, stream_methods, std::extent<decltype(stream_methods)>::value);
if (result < 0) {
return E_FAILED_REGISTER;
}
return S_OK;
}
HRESULT JavaInputStream::NewInstance(JNIEnv* env, ISequentialInStream* stream, jobject* object) {
*object = nullptr;
if (!initialized) {
return E_NOT_INITIALIZED;
}
*object = env->NewObject(class_native_sequential_in_stream, constructor_native_sequential_in_stream, stream);
if (*object == nullptr) {
// Clear java exception and return
RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(env);
// No java exception, but it's still an error
return E_UNKNOWN_ERROR;
}
// Ignore if any exception is pending
CLEAR_IF_EXCEPTION_PENDING(env);
return S_OK;
}
@@ -1,37 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_JAVA_SEQUENTIAL_IN_STREAM_H__
#define __A7ZIP_JAVA_SEQUENTIAL_IN_STREAM_H__
#include <jni.h>
#include <Common/MyWindows.h>
#include <7zip/IStream.h>
namespace a7zip {
namespace JavaInputStream {
HRESULT Initialize(JNIEnv* env);
HRESULT RegisterMethods(JNIEnv* env);
HRESULT NewInstance(JNIEnv* env, ISequentialInStream* stream, jobject* object);
}
}
#endif //__A7ZIP_JAVA_SEQUENTIAL_IN_STREAM_H__
@@ -1,202 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#include "JavaSeekableInputStream.h"
#include <type_traits>
#include <Common/MyCom.h>
#include "JavaHelper.h"
#include "Utils.h"
using namespace a7zip;
static void NativeSeek(
JNIEnv* env,
jclass,
jlong native_ptr,
jlong pos
) {
CHECK_CLOSED(env, native_ptr);
IInStream* stream = reinterpret_cast<IInStream*>(native_ptr);
UInt64 newPosition; // Ignored
HRESULT result = stream->Seek(pos, STREAM_SEEK_SET, &newPosition);
if (result != S_OK) THROW_IO_EXCEPTION(env, result);
}
static jlong NativeTell(
JNIEnv* env,
jclass,
jlong native_ptr
) {
CHECK_CLOSED_RET(env, 0, native_ptr);
IInStream* stream = reinterpret_cast<IInStream*>(native_ptr);
UInt64 newPosition;
HRESULT result = stream->Seek(0, STREAM_SEEK_CUR, &newPosition);
if (result != S_OK) THROW_IO_EXCEPTION_RET(env, 0, result);
return static_cast<jlong>(newPosition);
}
static jlong NativeSize(
JNIEnv* env,
jclass,
jlong native_ptr
) {
CHECK_CLOSED_RET(env, 0, native_ptr);
IInStream* stream = reinterpret_cast<IInStream*>(native_ptr);
// Try to get IStreamGetSize
CMyComPtr<IStreamGetSize> stream_get_size;
stream->QueryInterface(IID_IStreamGetSize, reinterpret_cast<void **>(&stream_get_size));
if (stream_get_size != nullptr) {
// It's an IStreamGetSize
UInt64 size;
HRESULT result = stream_get_size->GetSize(&size);
if (result != S_OK) THROW_IO_EXCEPTION_RET(env, 0, result);
return static_cast<jlong>(size);
} else {
// It's not an IStreamGetSize
// Backup current position
UInt64 cur;
HRESULT result = stream->Seek(0, STREAM_SEEK_CUR, &cur);
if (result != S_OK) THROW_IO_EXCEPTION_RET(env, 0, result);
// Seek to the end of steam to get size
UInt64 size;
result = stream->Seek(0, STREAM_SEEK_END, &size);
if (result != S_OK) THROW_IO_EXCEPTION_RET(env, 0, result);
// Back to previous position
UInt64 ignored;
result = stream->Seek(cur, STREAM_SEEK_SET, &ignored);
if (result != S_OK) THROW_IO_EXCEPTION_RET(env, 0, result);
return static_cast<jlong>(size);
}
}
static jint NativeRead(
JNIEnv* env,
jclass,
jlong native_ptr,
jbyteArray array,
jint offset,
jint length
) {
CHECK_CLOSED_RET(env, 0, native_ptr);
IInStream* stream = reinterpret_cast<IInStream*>(native_ptr);
jbyte* bytes = env->GetByteArrayElements(array, nullptr);
if (bytes == nullptr) THROW_IO_EXCEPTION_RET(env, 0, E_JAVA_EXCEPTION);
UInt32 processed_size;
HRESULT result = stream->Read(bytes + offset, static_cast<UInt32>(length), &processed_size);
env->ReleaseByteArrayElements(array, bytes, 0);
if (result != S_OK) THROW_IO_EXCEPTION_RET(env, 0, result);
if (length != 0 && processed_size == 0) {
// EOF
return -1;
}
return processed_size;
}
static void NativeClose(
JNIEnv* env,
jclass,
jlong native_ptr
) {
CHECK_CLOSED(env, native_ptr);
IInStream* stream = reinterpret_cast<IInStream*>(native_ptr);
stream->Release();
}
static bool initialized = false;
static jclass class_native_in_stream = nullptr;
static jmethodID constructor_native_in_stream = nullptr;
HRESULT JavaSeekableInputStream::Initialize(JNIEnv* env) {
if (initialized) {
return S_OK;
}
class_native_in_stream = env->FindClass("com/hippo/a7zip/NativeSeekableInputStream");
if (class_native_in_stream == nullptr) return E_CLASS_NOT_FOUND;
class_native_in_stream = static_cast<jclass>(env->NewGlobalRef(class_native_in_stream));
if (class_native_in_stream == nullptr) return E_OUTOFMEMORY;
constructor_native_in_stream = env->GetMethodID(class_native_in_stream, "<init>", "(J)V");
if (constructor_native_in_stream == nullptr) return E_METHOD_NOT_FOUND;
initialized = true;
return JNI_OK;
}
static JNINativeMethod stream_methods[] = {
{ "nativeSeek",
"(JJ)V",
reinterpret_cast<void *>(NativeSeek) },
{ "nativeTell",
"(J)J",
reinterpret_cast<void *>(NativeTell) },
{ "nativeSize",
"(J)J",
reinterpret_cast<void *>(NativeSize) },
{ "nativeRead",
"(J[BII)I",
reinterpret_cast<void *>(NativeRead) },
{ "nativeClose",
"(J)V",
reinterpret_cast<void *>(NativeClose) }
};
HRESULT JavaSeekableInputStream::RegisterMethods(JNIEnv* env) {
if (!initialized) {
return E_NOT_INITIALIZED;
}
jint result = env->RegisterNatives(class_native_in_stream, stream_methods, std::extent<decltype(stream_methods)>::value);
if (result < 0) {
return E_FAILED_REGISTER;
}
return S_OK;
}
HRESULT JavaSeekableInputStream::NewInstance(JNIEnv* env, IInStream* stream, jobject* object) {
*object = nullptr;
if (!initialized) {
return E_NOT_INITIALIZED;
}
*object = env->NewObject(class_native_in_stream, constructor_native_in_stream, stream);
if (*object == nullptr) {
// Clear java exception and return
RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(env);
// No java exception, but it's still an error
return E_UNKNOWN_ERROR;
}
// Ignore if any exception is pending
CLEAR_IF_EXCEPTION_PENDING(env);
return S_OK;
}
@@ -1,37 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_JAVA_IN_STREAM_H__
#define __A7ZIP_JAVA_IN_STREAM_H__
#include <jni.h>
#include <Common/MyWindows.h>
#include <7zip/IStream.h>
namespace a7zip {
namespace JavaSeekableInputStream {
HRESULT Initialize(JNIEnv* env);
HRESULT RegisterMethods(JNIEnv* env);
HRESULT NewInstance(JNIEnv* env, IInStream* stream, jobject* object);
}
}
#endif //__A7ZIP_JAVA_IN_STREAM_H__
-14
View File
@@ -1,14 +0,0 @@
#ifndef __A7ZIP_LOG_H__
#define __A7ZIP_LOG_H__
#include <android/log.h>
#define LOG_TAG "a7zip"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG ,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG ,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG ,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG ,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG ,__VA_ARGS__)
#endif //__A7ZIP_LOG_H__
@@ -1,111 +0,0 @@
/*
* Copyright 2020 Hippo Seven
*
* 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.
*/
#include "OpenVolumeCallback.h"
#include <malloc.h>
#include <MyString.h>
#include "SeekableInputStream.h"
#include "JavaEnv.h"
#include "Utils.h"
#include "Log.h"
using namespace a7zip;
bool OpenVolumeCallback::initialized = false;
jmethodID OpenVolumeCallback::method_open_volume = nullptr;
OpenVolumeCallback::OpenVolumeCallback(jobject callback) : callback(callback) { }
OpenVolumeCallback::~OpenVolumeCallback() {
JavaEnv env;
if (!env.IsValid()) return;
env->DeleteGlobalRef(callback);
callback = nullptr;
}
HRESULT OpenVolumeCallback::OpenVolume(const wchar_t *name, CMyComPtr<IInStream>& in_stream) {
JavaEnv env;
// const wchar_t* to jstring
unsigned len = MyStringLen(name);
jchar *buffer = reinterpret_cast<jchar *>(malloc(len * sizeof(jchar)));
if (buffer == nullptr) {
return E_OUTOFMEMORY;
}
for (int i = 0; i < len; i++) {
buffer[i] = static_cast<jchar>(name[i]);
}
jstring j_name = env->NewString(buffer, len);
free(buffer);
if (j_name == nullptr) {
return E_OUTOFMEMORY;
}
// Wrap java stream
jobject stream = env->CallObjectMethod(callback, method_open_volume, j_name);
RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(env);
RETURN_SAME_IF_NOT_ZERO(SeekableInputStream::Create(static_cast<JNIEnv*>(env), stream, in_stream));
return S_OK;
}
HRESULT OpenVolumeCallback::Initialize(JNIEnv* env) {
if (initialized) {
return S_OK;
}
jclass clazz = env->FindClass("com/hippo/a7zip/InArchive$OpenVolumeCallback");
if (clazz == nullptr) return E_CLASS_NOT_FOUND;
method_open_volume = env->GetMethodID(clazz, "openVolume", "(Ljava/lang/String;)Lcom/hippo/a7zip/SeekableInputStream;");
if (method_open_volume == nullptr) return E_METHOD_NOT_FOUND;
initialized = true;
return S_OK;
}
HRESULT OpenVolumeCallback::Create(
JNIEnv* env,
jobject callback,
OpenVolumeCallback** result
) {
if (!initialized) {
return E_NOT_INITIALIZED;
}
jobject g_callback = env->NewGlobalRef(callback);
if (g_callback == nullptr) {
return E_OUTOFMEMORY;
}
*result = new OpenVolumeCallback(g_callback);
return S_OK;
}
HRESULT OpenVolumeCallback::Create(
JNIEnv* env,
jobject callback,
CMyComPtr<OpenVolumeCallback>& result
) {
OpenVolumeCallback *callback_ptr = nullptr;
RETURN_SAME_IF_NOT_ZERO(Create(env, callback, &callback_ptr));
result = callback_ptr;
return S_OK;
}
@@ -1,54 +0,0 @@
/*
* Copyright 2020 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_OPEN_VOLUME_CALLBACK_H__
#define __A7ZIP_OPEN_VOLUME_CALLBACK_H__
#include <jni.h>
#include <Common/MyCom.h>
#include <7zip/IStream.h>
namespace a7zip {
class OpenVolumeCallback : public CMyUnknownImp
{
private:
OpenVolumeCallback(jobject callback);
public:
virtual ~OpenVolumeCallback();
public:
MY_ADDREF_RELEASE
HRESULT OpenVolume(const wchar_t *name, CMyComPtr<IInStream>& in_stream);
private:
jobject callback;
public:
static HRESULT Initialize(JNIEnv* env);
static HRESULT Create(JNIEnv* env, jobject callback, OpenVolumeCallback** result);
static HRESULT Create(JNIEnv* env, jobject callback, CMyComPtr<OpenVolumeCallback>& result);
private:
static bool initialized;
static jmethodID method_open_volume;
};
}
#endif //__A7ZIP_OPEN_VOLUME_CALLBACK_H__
@@ -1,127 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#include "OutputStream.h"
#include "JavaEnv.h"
#include "Utils.h"
#include "Log.h"
#define ARRAY_SIZE DEFAULT_BUFFER_SIZE
using namespace a7zip;
bool OutputStream::initialized = false;
jmethodID OutputStream::method_write = nullptr;
jmethodID OutputStream::method_close = nullptr;
OutputStream::OutputStream(
jobject stream,
jbyteArray array
) :
stream(stream),
array(array) { }
OutputStream::~OutputStream() {
JavaEnv env;
if (!env.IsValid()) return;
env->CallVoidMethod(stream, method_close);
CLEAR_IF_EXCEPTION_PENDING(env);
env->DeleteGlobalRef(stream);
env->DeleteGlobalRef(array);
stream = nullptr;
array = nullptr;
}
HRESULT OutputStream::Write(const void* data, UInt32 size, UInt32* processedSize) {
if (processedSize != nullptr) {
*processedSize = 0;
}
if (size == 0) {
return S_OK;
}
JavaEnv env;
if (!env.IsValid()) return E_JAVA_EXCEPTION;
// Make size not bigger than ARRAY_SIZE
size = MIN(ARRAY_SIZE, size);
// Copy data from native buffer to java buffer
env->SetByteArrayRegion(array, 0, size, reinterpret_cast<const jbyte*>(data));
RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(env);
// Write data to sink
env->CallVoidMethod(stream, method_write, array, 0, size);
RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(env);
if (processedSize != nullptr) {
*processedSize = size;
}
return S_OK;
}
HRESULT OutputStream::Initialize(JNIEnv* env) {
if (initialized) {
return S_OK;
}
jclass clazz = env->FindClass("java/io/OutputStream");
if (clazz == nullptr) return E_CLASS_NOT_FOUND;
method_write = env->GetMethodID(clazz, "write", "([BII)V");
if (method_write == nullptr) return E_METHOD_NOT_FOUND;
method_close = env->GetMethodID(clazz, "close", "()V");
if (method_close == nullptr) return E_METHOD_NOT_FOUND;
initialized = true;
return S_OK;
}
HRESULT OutputStream::Create(
JNIEnv* env,
jobject stream,
CMyComPtr<ISequentialOutStream>& out_stream
) {
if (!initialized) {
return E_NOT_INITIALIZED;
}
jobject g_stream = env->NewGlobalRef(stream);
if (g_stream == nullptr) {
return E_OUTOFMEMORY;
}
jbyteArray array = env->NewByteArray(ARRAY_SIZE);
if (array == nullptr) {
env->DeleteGlobalRef(g_stream);
return E_FAILED_CONSTRUCT;
}
jbyteArray g_array = static_cast<jbyteArray>(env->NewGlobalRef(array));
if (g_array == nullptr) {
env->DeleteGlobalRef(g_stream);
return E_OUTOFMEMORY;
}
out_stream = new OutputStream(g_stream, g_array);
return S_OK;
}
@@ -1,57 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_OUTPUT_STREAM_OUT_STREAM_H__
#define __A7ZIP_OUTPUT_STREAM_OUT_STREAM_H__
#include <jni.h>
#include <Common/MyCom.h>
#include <7zip/IStream.h>
namespace a7zip {
class OutputStream :
public ISequentialOutStream,
public CMyUnknownImp
{
private:
OutputStream(jobject stream, jbyteArray array);
public:
virtual ~OutputStream();
public:
MY_UNKNOWN_IMP
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
private:
jobject stream;
jbyteArray array;
public:
static HRESULT Initialize(JNIEnv* env);
static HRESULT Create(JNIEnv* env, jobject stream, CMyComPtr<ISequentialOutStream>& out_stream);
private:
static bool initialized;
static jmethodID method_write;
static jmethodID method_close;
};
}
#endif //__A7ZIP_OUTPUT_STREAM_OUT_STREAM_H__
@@ -1,37 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_PROP_TYPE_H__
#define __A7ZIP_PROP_TYPE_H__
namespace a7zip {
enum PropTypeEnum {
PT_UNKNOWN,
PT_EMPTY,
PT_BOOL,
PT_INT,
PT_LONG,
PT_FLOAT,
PT_DOUBLE,
PT_STRING,
};
typedef unsigned short PropType;
}
#endif //__A7ZIP_PROP_TYPE_H__
@@ -1,196 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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.
*/
#include <assert.h>
#include "SeekableInputStream.h"
#include "JavaEnv.h"
#include "Utils.h"
#include "Log.h"
#define ARRAY_SIZE DEFAULT_BUFFER_SIZE
using namespace a7zip;
bool SeekableInputStream::initialized = false;
jmethodID SeekableInputStream::method_read = nullptr;
jmethodID SeekableInputStream::method_seek = nullptr;
jmethodID SeekableInputStream::method_tell = nullptr;
jmethodID SeekableInputStream::method_size = nullptr;
jmethodID SeekableInputStream::method_close = nullptr;
SeekableInputStream::SeekableInputStream(
jobject stream,
jbyteArray array
) :
stream(stream),
array(array) { }
SeekableInputStream::~SeekableInputStream() {
JavaEnv env;
if (!env.IsValid()) return;
env->CallVoidMethod(stream, method_close);
CLEAR_IF_EXCEPTION_PENDING(env);
env->DeleteGlobalRef(stream);
env->DeleteGlobalRef(array);
stream = nullptr;
array = nullptr;
}
HRESULT SeekableInputStream::Read(void* data, UInt32 size, UInt32* processedSize) {
if (processedSize != nullptr) {
*processedSize = 0;
}
if (size == 0) {
return S_OK;
}
JavaEnv env;
if (!env.IsValid()) return E_JAVA_EXCEPTION;
// Make size not bigger than ARRAY_SIZE
size = MIN(ARRAY_SIZE, size);
jint read = env->CallIntMethod(stream, method_read, array, 0, size);
RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(env);
// Check EOF
if (read <= 0) {
return S_OK;
}
env->GetByteArrayRegion(array, 0, read, static_cast<jbyte*>(data));
RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(env);
if (processedSize != nullptr) {
*processedSize = static_cast<UInt32>(read);
}
return S_OK;
}
HRESULT SeekableInputStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64* newPosition) {
JavaEnv env;
if (!env.IsValid()) return E_JAVA_EXCEPTION;
jlong actual_offset;
switch (seekOrigin) {
case STREAM_SEEK_SET: {
actual_offset = static_cast<jlong>(offset);
break;
}
case STREAM_SEEK_CUR: {
jlong position = env->CallLongMethod(stream, method_tell);
RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(env);
actual_offset = position + offset;
break;
}
case STREAM_SEEK_END: {
jlong size = env->CallLongMethod(stream, method_size);
RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(env);
actual_offset = size + offset;
break;
}
default: {
return E_INVALIDARG;
}
}
if (actual_offset < 0) {
return E_INVALIDARG;
}
env->CallVoidMethod(stream, method_seek, actual_offset);
RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(env);
if (newPosition != nullptr) {
*newPosition = static_cast<UInt64>(actual_offset);
}
return S_OK;
}
HRESULT SeekableInputStream::GetSize(UInt64* size) {
JavaEnv env;
if (!env.IsValid()) return E_JAVA_EXCEPTION;
jlong store_size = env->CallLongMethod(stream, method_size);
RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(env);
if (size != nullptr) {
*size = static_cast<UInt64>(store_size);
}
return S_OK;
}
HRESULT SeekableInputStream::Initialize(JNIEnv* env) {
if (initialized) {
return S_OK;
}
jclass clazz = env->FindClass("com/hippo/a7zip/SeekableInputStream");
if (clazz == nullptr) return E_CLASS_NOT_FOUND;
method_read = env->GetMethodID(clazz, "read", "([BII)I");
if (method_read == nullptr) return E_METHOD_NOT_FOUND;
method_seek = env->GetMethodID(clazz, "seek", "(J)V");
if (method_seek == nullptr) return E_METHOD_NOT_FOUND;
method_tell = env->GetMethodID(clazz, "tell", "()J");
if (method_tell == nullptr) return E_METHOD_NOT_FOUND;
method_size = env->GetMethodID(clazz, "size", "()J");
if (method_size == nullptr) return E_METHOD_NOT_FOUND;
method_close = env->GetMethodID(clazz, "close", "()V");
if (method_close == nullptr) return E_METHOD_NOT_FOUND;
initialized = true;
return JNI_OK;
}
HRESULT SeekableInputStream::Create(
JNIEnv* env,
jobject stream,
CMyComPtr<IInStream>& in_stream
) {
if (!initialized) {
return E_NOT_INITIALIZED;
}
jobject g_stream = env->NewGlobalRef(stream);
if (g_stream == nullptr) {
return E_OUTOFMEMORY;
}
jbyteArray array = env->NewByteArray(ARRAY_SIZE);
if (array == nullptr) {
env->DeleteGlobalRef(g_stream);
return E_FAILED_CONSTRUCT;
}
jbyteArray g_array = static_cast<jbyteArray>(env->NewGlobalRef(array));
if (g_array == nullptr) {
env->DeleteGlobalRef(g_stream);
return E_OUTOFMEMORY;
}
in_stream = new SeekableInputStream(g_stream, g_array);
return S_OK;
}
@@ -1,65 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_IN_STREAM_H__
#define __A7ZIP_IN_STREAM_H__
#include <jni.h>
#include <7zip/IStream.h>
#include <Common/MyCom.h>
namespace a7zip {
class SeekableInputStream :
public IInStream,
public IStreamGetSize,
public CMyUnknownImp
{
private:
SeekableInputStream(jobject stream, jbyteArray array);
public:
virtual ~SeekableInputStream();
public:
MY_UNKNOWN_IMP2(IInStream, IStreamGetSize)
STDMETHOD(Read)(void* data, UInt32 size, UInt32* processedSize);
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64* newPosition);
STDMETHOD(GetSize)(UInt64* size);
private:
jobject stream;
jbyteArray array;
public:
static HRESULT Initialize(JNIEnv* env);
static HRESULT Create(JNIEnv* env, jobject stream, CMyComPtr<IInStream>& in_stream);
private:
static bool initialized;
static jmethodID method_read;
static jmethodID method_seek;
static jmethodID method_tell;
static jmethodID method_size;
static jmethodID method_close;
};
}
#endif //__A7ZIP_IN_STREAM_H__
@@ -1,567 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#include "SevenZip.h"
#include <dlfcn.h>
#include <Windows/PropVariant.h>
#include <7zip/Archive/IArchive.h>
#include <7zip/IPassword.h>
#include "Log.h"
#include "Utils.h"
#include "OpenVolumeCallback.h"
#ifdef LOG_TAG
# undef LOG_TAG
# define LOG_TAG "P7Zip"
#endif
using namespace a7zip;
extern "C" HRESULT GetNumberOfMethods(UINT32 *numCodecs);
extern "C" HRESULT GetNumberOfFormats(UINT32 *numFormats);
extern "C" HRESULT GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT* value);
extern "C" HRESULT GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT* value);
extern "C" HRESULT CreateObject(const GUID* clsid, const GUID* iid, void** outObject);
typedef HRESULT (*GetPropertyFunc)(UInt32 index, PROPID propID, PROPVARIANT* value);
class Method {
public:
bool has_name;
AString name;
bool has_encoder;
GUID encoder;
bool has_decoder;
GUID decoder;
};
class Format {
public:
GUID class_id;
bool has_name;
AString name;
UInt32 signature_offset;
CObjectVector<CByteBuffer> signatures;
};
class CompressCodecsInfo :
public ICompressCodecsInfo,
public CMyUnknownImp {
public:
MY_UNKNOWN_IMP1(ICompressCodecsInfo)
STDMETHOD(GetNumMethods)(UInt32* numMethods);
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT* value);
STDMETHOD(CreateDecoder)(UInt32 index, const GUID* interfaceID, void** coder);
STDMETHOD(CreateEncoder)(UInt32 index, const GUID* interfaceID, void** coder);
};
static bool initialized = false;
static void* handle = nullptr;
static CObjectVector<Method> methods;
static CObjectVector<Format> formats;
static CompressCodecsInfo compress_codecs_info;
HRESULT CompressCodecsInfo::GetNumMethods(UInt32 *numMethods) {
if (numMethods != nullptr) {
*numMethods = methods.Size();
}
return S_OK;
}
HRESULT CompressCodecsInfo::GetProperty(UInt32 index, PROPID propID, PROPVARIANT* value) {
Method& method = methods[index];
switch (propID) {
case NMethodPropID::kDecoderIsAssigned: {
NWindows::NCOM::CPropVariant propVariant;
propVariant = method.has_decoder;
propVariant.Detach(value);
return S_OK;
}
case NMethodPropID::kEncoderIsAssigned: {
NWindows::NCOM::CPropVariant propVariant;
propVariant = method.has_encoder;
propVariant.Detach(value);
return S_OK;
}
default: {
return GetMethodProperty(index, propID, value);
}
}
}
HRESULT CompressCodecsInfo::CreateDecoder(
UInt32 index,
const GUID* interfaceID,
void** coder
) {
Method& method = methods[index];
if (method.has_decoder) {
return CreateObject(&(method.decoder), interfaceID, coder);
} else {
return S_OK;
}
}
HRESULT CompressCodecsInfo::CreateEncoder(
UInt32 index,
const GUID* interfaceID,
void** coder
) {
Method& method = methods[index];
if (method.has_encoder) {
return CreateObject(&(method.encoder), interfaceID, coder);
} else {
return S_OK;
}
}
class ArchiveOpenCallback :
public IArchiveOpenCallback,
public ICryptoGetTextPassword,
public CMyUnknownImp {
public:
ArchiveOpenCallback(BSTR password) {
this->password = ::SysAllocString(password);
this->has_asked_password = false;
}
~ArchiveOpenCallback() {
::SysFreeString(password);
}
public:
MY_UNKNOWN_IMP2(IArchiveOpenCallback, ICryptoGetTextPassword)
INTERFACE_IArchiveOpenCallback({ return S_OK; });
STDMETHOD(CryptoGetTextPassword)(BSTR *password) {
has_asked_password = true;
*password = ::SysAllocString(this->password);
return this->password != nullptr ? S_OK : E_NO_PASSWORD;
}
HRESULT GetBetterResult(HRESULT result) {
if (result == S_OK) {
return S_OK;
} else if (has_asked_password) {
if (password != nullptr) {
return E_WRONG_PASSWORD;
} else {
return E_NO_PASSWORD;
}
} else {
return result;
}
}
private:
BSTR password;
bool has_asked_password;
};
class ArchiveOpenCallback2 :
public ArchiveOpenCallback,
public IArchiveOpenVolumeCallback {
public:
ArchiveOpenCallback2(
BSTR password,
BSTR filename,
CMyComPtr<OpenVolumeCallback>& callback
):
ArchiveOpenCallback(password),
filename(filename),
callback(callback) { }
public:
MY_UNKNOWN_IMP3(
IArchiveOpenCallback,
IArchiveOpenVolumeCallback,
ICryptoGetTextPassword)
STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) {
NWindows::NCOM::CPropVariant prop;
if (propID == kpidName) {
prop = filename;
}
prop.Detach(value);
return S_OK;
}
STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) {
CMyComPtr<IInStream> stream = nullptr;
HRESULT result = callback->OpenVolume(name, stream);
*inStream = stream.Detach();
return result != S_OK ? S_FALSE : S_OK;
}
private:
UString filename;
CMyComPtr<OpenVolumeCallback> callback;
};
#define GET_PROP_METHOD(METHOD_NAME, PROP_TYPE, VALUE_TYPE, CONVERTER) \
HRESULT METHOD_NAME( \
GetPropertyFunc get_property, \
UInt32 index, \
PROPID prop_id, \
PROP_TYPE& value, \
bool& is_assigned \
) { \
NWindows::NCOM::CPropVariant prop; \
is_assigned = false; \
\
RETURN_SAME_IF_NOT_ZERO(get_property(index, prop_id, &prop)); \
\
if (prop.vt == VALUE_TYPE) { \
is_assigned = true; \
CONVERTER; \
} else if (prop.vt != VT_EMPTY) { \
return E_INCONSISTENT_PROP_TYPE; \
} \
\
return S_OK; \
}
GET_PROP_METHOD(GetAString, AString, VT_BSTR, value.SetFromWStr_if_Ascii(prop.bstrVal));
GET_PROP_METHOD(GetGUID, GUID, VT_BSTR, value = *reinterpret_cast<const GUID*>(prop.bstrVal));
GET_PROP_METHOD(GetCByteBuffer, CByteBuffer, VT_BSTR, value.CopyFrom((const Byte *)prop.bstrVal, ::SysStringByteLen(prop.bstrVal)));
GET_PROP_METHOD(GetUInt32, UInt32, VT_UI4, value = prop.ulVal);
#undef GET_PROP_METHOD
static HRESULT LoadMethods() {
UInt32 method_number = 0;
RETURN_SAME_IF_NOT_ZERO(GetNumberOfMethods(&method_number));
for(UInt32 i = 0; i < method_number; i++) {
Method& method = methods.AddNew();
# define GET_PROP(METHOD, PROP, VALUE, ASSIGNED) \
if (METHOD(GetMethodProperty, i, PROP, VALUE, ASSIGNED) != S_OK) { \
methods.DeleteBack(); \
continue; \
}
// It's ok to assume all characters in method name are in ascii charset
GET_PROP(GetAString, NMethodPropID::kName, method.name, method.has_name);
GET_PROP(GetGUID, NMethodPropID::kDecoder, method.decoder, method.has_decoder);
GET_PROP(GetGUID, NMethodPropID::kEncoder, method.encoder, method.has_encoder);
# undef GET_PROP
}
return S_OK;
}
static void AppendMultiSignature(
CObjectVector<CByteBuffer>& signatures,
const unsigned char* multi_signature,
size_t size
) {
while (size > 0) {
unsigned length = *multi_signature++;
size--;
if (length > size) {
return;
}
signatures.AddNew().CopyFrom(multi_signature, length);
multi_signature += length;
size -= length;
}
}
static HRESULT LoadFormats() {
UInt32 format_number = 0;
RETURN_SAME_IF_NOT_ZERO(GetNumberOfFormats(&format_number));
for(UInt32 i = 0; i < format_number; i++) {
Format& format = formats.AddNew();
# define GET_PROP(METHOD, PROP, VALUE, ASSIGNED) \
if (METHOD(GetHandlerProperty2, i, PROP, VALUE, ASSIGNED) != S_OK) { \
formats.DeleteBack(); \
continue; \
}
// ClassID is required
bool has_class_id;
GET_PROP(GetGUID, NArchive::NHandlerPropID::kClassID, format.class_id, has_class_id);
if (!has_class_id) {
formats.DeleteBack();
continue;
}
// It's ok to assume all characters in format name are in ascii charset
GET_PROP(GetAString, NArchive::NHandlerPropID::kName, format.name, format.has_name);
bool has_signature;
CByteBuffer signature;
GET_PROP(GetUInt32, NArchive::NHandlerPropID::kSignatureOffset, format.signature_offset, has_signature);
if (!has_signature) {
format.signature_offset = 0;
}
GET_PROP(GetCByteBuffer, NArchive::NHandlerPropID::kSignature, signature, has_signature);
if (has_signature) {
format.signatures.AddNew().CopyFrom(signature, signature.Size());
}
GET_PROP(GetCByteBuffer, NArchive::NHandlerPropID::kMultiSignature, signature, has_signature);
if (has_signature) {
AppendMultiSignature(format.signatures, signature, signature.Size());
}
# undef GET_PROP
}
return S_OK;
}
HRESULT SevenZip::Initialize() {
if (initialized) {
return S_OK;
}
RETURN_SAME_IF_NOT_ZERO(LoadMethods());
RETURN_SAME_IF_NOT_ZERO(LoadFormats());
initialized = true;
return S_OK;
}
static HRESULT ReadFully(CMyComPtr<IInStream>& stream, Byte* data, UInt32 size, UInt32* processedSize) {
UInt32 read = 0;
while (read < size) {
RETURN_SAME_IF_NOT_ZERO(stream->Read(data + read, size - read, processedSize));
if (*processedSize == 0) {
// EOF
break;
}
read += *processedSize;
}
*processedSize = read;
return S_OK;
}
static HRESULT OpenInArchive(
GUID& class_id,
CMyComPtr<IInStream>& in_stream,
BSTR password,
BSTR filename,
CMyComPtr<OpenVolumeCallback>& open_volume_callback,
CMyComPtr<IInArchive>& in_archive
) {
RETURN_SAME_IF_NOT_ZERO(CreateObject(&class_id, &IID_IInArchive, reinterpret_cast<void **>(&in_archive)));
UInt64 newPosition = 0;
HRESULT result = in_stream->Seek(0, STREAM_SEEK_SET, &newPosition);
if (result != S_OK) {
in_archive->Close();
in_archive = nullptr;
return result;
}
UInt64 maxCheckStartPosition = 1 << 22;
ArchiveOpenCallback* callback_ptr = nullptr;
if (filename != nullptr && open_volume_callback != nullptr) {
callback_ptr = new ArchiveOpenCallback2(password, filename, open_volume_callback);
} else {
callback_ptr = new ArchiveOpenCallback(password);
}
CMyComPtr<ArchiveOpenCallback> callback(callback_ptr);
result = in_archive->Open(in_stream, &maxCheckStartPosition, callback);
result = callback->GetBetterResult(result);
if (result != S_OK) {
in_archive->Close();
in_archive = nullptr;
return result;
}
return S_OK;
}
static HRESULT OpenInArchive(
CMyComPtr<IInStream>& in_stream,
BSTR password,
BSTR filename,
CMyComPtr<OpenVolumeCallback>& open_volume_callback,
CMyComPtr<IInArchive>& in_archive,
AString& format_name
) {
bool formats_checked[formats.Size()];
memset(formats_checked, 0, formats.Size() * sizeof(bool));
for (int i = 0; i < formats.Size(); i++) {
Format& format = formats[i];
// Skip format without signatures
if (format.signatures.Size() == 0) {
continue;
}
// Check each signature
for (int j = 0; j < format.signatures.Size(); j++) {
CByteBuffer& signature = format.signatures[j];
UInt32 processedSize;
CByteBuffer bytes(signature.Size());
UInt64 newPosition;
CONTINUE_IF_NOT_ZERO(in_stream->Seek(format.signature_offset, STREAM_SEEK_SET, &newPosition));
if (newPosition != format.signature_offset) continue;
CONTINUE_IF_NOT_ZERO(ReadFully(in_stream, bytes, static_cast<UInt32>(signature.Size()), &processedSize));
if (processedSize != signature.Size() || bytes != signature) continue;
// The signature matched, try to open it
HRESULT result = OpenInArchive(format.class_id, in_stream, password, filename, open_volume_callback, in_archive);
// Mark the format
formats_checked[i] = true;
if (result == S_OK) {
format_name = format.name;
return S_OK;
}
if (result == E_NO_PASSWORD || result == E_WRONG_PASSWORD) {
// It's a password error, the archive format is confirmed
return result;
}
// Can't open archive in this format
// Skip this format
break;
}
}
// Try other unchecked formats
for (int i = 0; i < formats.Size(); i++) {
if (!formats_checked[i]) {
Format& format = formats[i];
HRESULT result = OpenInArchive(format.class_id, in_stream, password, filename, open_volume_callback, in_archive);
if (result == S_OK) {
format_name = format.name;
return S_OK;
}
if (result == E_NO_PASSWORD || result == E_WRONG_PASSWORD) {
// It's a password error, the archive format is confirmed
return result;
}
}
}
return E_UNKNOWN_FORMAT;
}
HRESULT SevenZip::OpenArchive(
CMyComPtr<IInStream>& in_stream,
BSTR password,
BSTR filename,
CMyComPtr<OpenVolumeCallback>& open_volume_callback,
InArchive** archive
) {
HRESULT result = S_FALSE;
InArchive* previous_archive = nullptr;
CMyComPtr<IInStream> arg_in_stream = in_stream;
BSTR arg_password = password;
BSTR arg_filename = filename;
CMyComPtr<OpenVolumeCallback> arg_open_volume_callback = open_volume_callback;
while (true) {
CMyComPtr<IInArchive> in_archive = nullptr;
AString format_name;
result = OpenInArchive(
arg_in_stream,
arg_password,
arg_filename,
arg_open_volume_callback,
in_archive,
format_name
);
if (result != S_OK || in_archive == nullptr) {
if (in_archive != nullptr) {
in_archive->Close();
in_archive = nullptr;
}
if (result == S_OK) {
result = E_INTERNAL;
}
break;
}
previous_archive = new InArchive(previous_archive, in_archive, format_name);
// Break if it has no entry or more than one entry
UInt32 number = 0;
previous_archive->GetNumberOfEntries(number);
if (number != 1) {
break;
}
// Break if it's not IInArchiveGetStream
CMyComPtr<IInArchiveGetStream> archive_get_stream;
in_archive->QueryInterface(IID_IInArchiveGetStream, (void**)&archive_get_stream);
if (archive_get_stream == nullptr) {
break;
}
// Break if GetStream returns null
CMyComPtr<ISequentialInStream> sequential_in_stream;
archive_get_stream->GetStream(0, &sequential_in_stream);
if (sequential_in_stream == nullptr) {
break;
}
// Break if the stream is not IInStream
arg_in_stream = nullptr;
sequential_in_stream->QueryInterface(IID_IInStream, (void**)&arg_in_stream);
if (arg_in_stream == nullptr) {
break;
}
// Clear arguments for the first archive
arg_password = nullptr;
arg_filename = nullptr;
arg_open_volume_callback = nullptr;
}
*archive = previous_archive;
return *archive != nullptr ? S_OK : result;
}
@@ -1,47 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_P7ZIP_H__
#define __A7ZIP_P7ZIP_H__
#include <jni.h>
#include <include_windows/windows.h>
#include <Common/MyBuffer.h>
#include <Common/MyCom.h>
#include <Common/MyString.h>
#include <7zip/ICoder.h>
#include "InArchive.h"
#include "OpenVolumeCallback.h"
namespace a7zip {
namespace SevenZip {
HRESULT Initialize();
HRESULT OpenArchive(
CMyComPtr<IInStream>& stream,
BSTR password,
BSTR filename,
CMyComPtr<OpenVolumeCallback>& callback,
InArchive** archive
);
}
}
#endif //__A7ZIP_P7ZIP_H__
-95
View File
@@ -1,95 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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.
*/
#ifndef __A7ZIP_UTILS_H__
#define __A7ZIP_UTILS_H__
#define DEFAULT_BUFFER_SIZE (4 * 1024)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define E_NOT_INITIALIZED ((HRESULT)0x82210000L)
#define E_INTERNAL ((HRESULT)0x82210001L)
#define E_UNKNOWN_ERROR ((HRESULT)0x82210002L)
#define E_CLASS_NOT_FOUND ((HRESULT)0x82220000L)
#define E_METHOD_NOT_FOUND ((HRESULT)0x82220001L)
#define E_JAVA_EXCEPTION ((HRESULT)0x82220002L)
#define E_FAILED_CONSTRUCT ((HRESULT)0x82220003L)
#define E_FAILED_REGISTER ((HRESULT)0x82220004L)
#define E_FAILED_UNREGISTER ((HRESULT)0x82220005L)
#define E_INCONSISTENT_PROP_TYPE ((HRESULT)0x82240000L)
#define E_EMPTY_PROP ((HRESULT)0x82240001L)
#define E_UNKNOWN_FORMAT ((HRESULT)0x82240002L)
#define E_UNSUPPORTED_EXTRACT_MODE ((HRESULT)0x82240003L)
#define E_NO_OUT_STREAM ((HRESULT)0x82240004L)
#define E_UNSUPPORTED_METHOD ((HRESULT)0x82250000L)
#define E_DATA_ERROR ((HRESULT)0x82250001L)
#define E_DATA_ERROR_ENCRYPTED ((HRESULT)0x82250002L)
#define E_CRC_ERROR ((HRESULT)0x82250003L)
#define E_CRC_ERROR_ENCRYPTED ((HRESULT)0x82250004L)
#define E_UNAVAILABLE ((HRESULT)0x82250005L)
#define E_UNEXPECTED_END ((HRESULT)0x82250006L)
#define E_DATA_AFTER_END ((HRESULT)0x82250007L)
#define E_IS_NOT_ARC ((HRESULT)0x82250008L)
#define E_HEADERS_ERROR ((HRESULT)0x82250009L)
#define E_WRONG_PASSWORD ((HRESULT)0x82250010L)
#define E_NO_PASSWORD ((HRESULT)0x82250011L)
#define CLEAR_IF_EXCEPTION_PENDING(ENV) \
do { \
if ((ENV)->ExceptionCheck()) { \
(ENV)->ExceptionDescribe(); \
(ENV)->ExceptionClear(); \
} \
} while (0)
#define RETURN_E_JAVA_EXCEPTION_IF_EXCEPTION_PENDING(ENV) \
do { \
if ((ENV)->ExceptionCheck()) { \
(ENV)->ExceptionDescribe(); \
(ENV)->ExceptionClear(); \
return E_JAVA_EXCEPTION; \
} \
} while (0)
#define RETURN_JNI_ERR_IF_NOT_ZERO(VALUE) \
do { \
if ((VALUE) != 0) { \
return JNI_ERR; \
} \
} while (0)
#define RETURN_SAME_IF_NOT_ZERO(VALUE) \
do { \
auto __temp__ = (VALUE); \
if (__temp__ != 0) { \
return __temp__; \
} \
} while (0)
#define CONTINUE_IF_NOT_ZERO(VALUE) \
do { \
if ((VALUE) != 0) { \
continue; \
} \
} while (0)
#endif //__A7ZIP_UTILS_H__
@@ -1,240 +0,0 @@
cmake_minimum_required(VERSION 3.4.1)
project(p7zip C CXX)
set(P_SEVEN_ZIP_EXTRACT_LITE_SOURCES
p7zip/CPP/7zip/Archive/7z/7zDecode.cpp
p7zip/CPP/7zip/Archive/7z/7zExtract.cpp
p7zip/CPP/7zip/Archive/7z/7zHandler.cpp
p7zip/CPP/7zip/Archive/7z/7zHeader.cpp
p7zip/CPP/7zip/Archive/7z/7zIn.cpp
p7zip/CPP/7zip/Archive/7z/7zProperties.cpp
p7zip/CPP/7zip/Archive/7z/7zRegister.cpp
p7zip/CPP/7zip/Archive/Common/CoderMixer2.cpp
p7zip/CPP/7zip/Archive/Common/FindSignature.cpp
p7zip/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
p7zip/CPP/7zip/Archive/Common/ItemNameUtils.cpp
p7zip/CPP/7zip/Archive/Common/MultiStream.cpp
p7zip/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
p7zip/CPP/7zip/Archive/Rar/RarHandler.cpp
p7zip/CPP/7zip/Archive/Rar/Rar5Handler.cpp
p7zip/CPP/7zip/Archive/Zip/ZipHandler.cpp
p7zip/CPP/7zip/Archive/Zip/ZipIn.cpp
p7zip/CPP/7zip/Archive/Zip/ZipItem.cpp
p7zip/CPP/7zip/Archive/Zip/ZipRegister.cpp
p7zip/CPP/7zip/Archive/ArchiveExports.cpp
p7zip/CPP/7zip/Archive/DllExports2.cpp
p7zip/CPP/7zip/Archive/HandlerCont.cpp
p7zip/CPP/7zip/Archive/SplitHandler.cpp
p7zip/CPP/7zip/Archive/XzHandler.cpp
p7zip/CPP/7zip/Common/CWrappers.cpp
p7zip/CPP/7zip/Common/CreateCoder.cpp
p7zip/CPP/7zip/Common/FilterCoder.cpp
p7zip/CPP/7zip/Common/InBuffer.cpp
p7zip/CPP/7zip/Common/LimitedStreams.cpp
p7zip/CPP/7zip/Common/OutBuffer.cpp
p7zip/CPP/7zip/Common/ProgressUtils.cpp
p7zip/CPP/7zip/Common/PropId.cpp
p7zip/CPP/7zip/Common/StreamObjects.cpp
p7zip/CPP/7zip/Common/StreamUtils.cpp
p7zip/CPP/7zip/Compress/Bcj2Coder.cpp
p7zip/CPP/7zip/Compress/Bcj2Register.cpp
p7zip/CPP/7zip/Compress/BcjCoder.cpp
p7zip/CPP/7zip/Compress/BcjRegister.cpp
p7zip/CPP/7zip/Compress/BitlDecoder.cpp
p7zip/CPP/7zip/Compress/BranchMisc.cpp
p7zip/CPP/7zip/Compress/BranchRegister.cpp
p7zip/CPP/7zip/Compress/ByteSwap.cpp
p7zip/CPP/7zip/Compress/BZip2Crc.cpp
p7zip/CPP/7zip/Compress/BZip2Decoder.cpp
p7zip/CPP/7zip/Compress/BZip2Register.cpp
p7zip/CPP/7zip/Compress/CodecExports.cpp
p7zip/CPP/7zip/Compress/CopyCoder.cpp
p7zip/CPP/7zip/Compress/CopyRegister.cpp
p7zip/CPP/7zip/Compress/Deflate64Register.cpp
p7zip/CPP/7zip/Compress/DeflateDecoder.cpp
p7zip/CPP/7zip/Compress/DeflateRegister.cpp
p7zip/CPP/7zip/Compress/DeltaFilter.cpp
p7zip/CPP/7zip/Compress/ImplodeDecoder.cpp
p7zip/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp
p7zip/CPP/7zip/Compress/Lzma2Decoder.cpp
p7zip/CPP/7zip/Compress/Lzma2Register.cpp
p7zip/CPP/7zip/Compress/LzmaDecoder.cpp
p7zip/CPP/7zip/Compress/LzmaRegister.cpp
p7zip/CPP/7zip/Compress/LzOutWindow.cpp
p7zip/CPP/7zip/Compress/PpmdDecoder.cpp
p7zip/CPP/7zip/Compress/PpmdRegister.cpp
p7zip/CPP/7zip/Compress/PpmdZip.cpp
p7zip/CPP/7zip/Compress/Rar1Decoder.cpp
p7zip/CPP/7zip/Compress/Rar2Decoder.cpp
p7zip/CPP/7zip/Compress/Rar3Decoder.cpp
p7zip/CPP/7zip/Compress/Rar3Vm.cpp
p7zip/CPP/7zip/Compress/Rar5Decoder.cpp
p7zip/CPP/7zip/Compress/RarCodecsRegister.cpp
p7zip/CPP/7zip/Compress/ShrinkDecoder.cpp
p7zip/CPP/7zip/Crypto/7zAes.cpp
p7zip/CPP/7zip/Crypto/7zAesRegister.cpp
p7zip/CPP/7zip/Crypto/HmacSha1.cpp
p7zip/CPP/7zip/Crypto/HmacSha256.cpp
p7zip/CPP/7zip/Crypto/MyAes.cpp
p7zip/CPP/7zip/Crypto/MyAesReg.cpp
p7zip/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp
p7zip/CPP/7zip/Crypto/RandGen.cpp
p7zip/CPP/7zip/Crypto/Rar20Crypto.cpp
p7zip/CPP/7zip/Crypto/Rar5Aes.cpp
p7zip/CPP/7zip/Crypto/RarAes.cpp
p7zip/CPP/7zip/Crypto/WzAes.cpp
p7zip/CPP/7zip/Crypto/ZipCrypto.cpp
p7zip/CPP/7zip/Crypto/ZipStrong.cpp
p7zip/CPP/Common/CRC.cpp
p7zip/CPP/Common/CrcReg.cpp
p7zip/CPP/Common/IntToString.cpp
p7zip/CPP/Common/MyString.cpp
p7zip/CPP/Common/MyVector.cpp
p7zip/CPP/Common/MyWindows.cpp
p7zip/CPP/Common/Sha1Reg.cpp
p7zip/CPP/Common/Sha256Reg.cpp
p7zip/CPP/Common/StringConvert.cpp
p7zip/CPP/Common/StringToInt.cpp
p7zip/CPP/Common/UTFConvert.cpp
p7zip/CPP/Common/Wildcard.cpp
p7zip/CPP/Common/XzCrc64Reg.cpp
p7zip/CPP/Windows/PropVariant.cpp
p7zip/CPP/Windows/PropVariantUtils.cpp
p7zip/CPP/Windows/System.cpp
p7zip/CPP/Windows/TimeUtils.cpp
p7zip/CPP/myWindows/wine_date_and_time.cpp
p7zip/C/7zCrc.c
p7zip/C/7zCrcOpt.c
p7zip/C/7zStream.c
p7zip/C/Aes.c
p7zip/C/Alloc.c
p7zip/C/Bcj2.c
p7zip/C/Blake2s.c
p7zip/C/Bra.c
p7zip/C/Bra86.c
p7zip/C/BraIA64.c
p7zip/C/CpuArch.c
p7zip/C/Delta.c
p7zip/C/Lzma2Dec.c
p7zip/C/LzmaDec.c
p7zip/C/Ppmd7.c
p7zip/C/Ppmd7Dec.c
p7zip/C/Ppmd8.c
p7zip/C/Ppmd8Dec.c
p7zip/C/Sha1.c
p7zip/C/Sha256.c
p7zip/C/Xz.c
p7zip/C/XzCrc64.c
p7zip/C/XzCrc64Opt.c
p7zip/C/XzDec.c
p7zip/C/XzIn.c
)
set(P_SEVEN_ZIP_EXTRACT_SOURCES
p7zip/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
p7zip/CPP/7zip/Archive/Cab/CabHandler.cpp
p7zip/CPP/7zip/Archive/Cab/CabHeader.cpp
p7zip/CPP/7zip/Archive/Cab/CabIn.cpp
p7zip/CPP/7zip/Archive/Cab/CabRegister.cpp
p7zip/CPP/7zip/Archive/Chm/ChmHandler.cpp
p7zip/CPP/7zip/Archive/Chm/ChmIn.cpp
p7zip/CPP/7zip/Archive/Common/DummyOutStream.cpp
p7zip/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
p7zip/CPP/7zip/Archive/Iso/IsoHandler.cpp
p7zip/CPP/7zip/Archive/Iso/IsoHeader.cpp
p7zip/CPP/7zip/Archive/Iso/IsoIn.cpp
p7zip/CPP/7zip/Archive/Iso/IsoRegister.cpp
p7zip/CPP/7zip/Archive/Nsis/NsisDecode.cpp
p7zip/CPP/7zip/Archive/Nsis/NsisHandler.cpp
p7zip/CPP/7zip/Archive/Nsis/NsisIn.cpp
p7zip/CPP/7zip/Archive/Nsis/NsisRegister.cpp
p7zip/CPP/7zip/Archive/Tar/TarHandler.cpp
p7zip/CPP/7zip/Archive/Tar/TarHeader.cpp
p7zip/CPP/7zip/Archive/Tar/TarIn.cpp
p7zip/CPP/7zip/Archive/Tar/TarRegister.cpp
p7zip/CPP/7zip/Archive/Udf/UdfHandler.cpp
p7zip/CPP/7zip/Archive/Udf/UdfIn.cpp
p7zip/CPP/7zip/Archive/Wim/WimHandler.cpp
p7zip/CPP/7zip/Archive/Wim/WimIn.cpp
p7zip/CPP/7zip/Archive/Wim/WimRegister.cpp
p7zip/CPP/7zip/Archive/ApmHandler.cpp
p7zip/CPP/7zip/Archive/ArHandler.cpp
p7zip/CPP/7zip/Archive/ArjHandler.cpp
p7zip/CPP/7zip/Archive/Bz2Handler.cpp
p7zip/CPP/7zip/Archive/ComHandler.cpp
p7zip/CPP/7zip/Archive/CpioHandler.cpp
p7zip/CPP/7zip/Archive/CramfsHandler.cpp
p7zip/CPP/7zip/Archive/DmgHandler.cpp
p7zip/CPP/7zip/Archive/ElfHandler.cpp
p7zip/CPP/7zip/Archive/ExtHandler.cpp
p7zip/CPP/7zip/Archive/FatHandler.cpp
p7zip/CPP/7zip/Archive/FlvHandler.cpp
p7zip/CPP/7zip/Archive/GptHandler.cpp
p7zip/CPP/7zip/Archive/GzHandler.cpp
p7zip/CPP/7zip/Archive/HfsHandler.cpp
p7zip/CPP/7zip/Archive/IhexHandler.cpp
p7zip/CPP/7zip/Archive/LzhHandler.cpp
p7zip/CPP/7zip/Archive/LzmaHandler.cpp
p7zip/CPP/7zip/Archive/MachoHandler.cpp
p7zip/CPP/7zip/Archive/MbrHandler.cpp
p7zip/CPP/7zip/Archive/MslzHandler.cpp
p7zip/CPP/7zip/Archive/MubHandler.cpp
p7zip/CPP/7zip/Archive/NtfsHandler.cpp
p7zip/CPP/7zip/Archive/PeHandler.cpp
p7zip/CPP/7zip/Archive/PpmdHandler.cpp
p7zip/CPP/7zip/Archive/QcowHandler.cpp
p7zip/CPP/7zip/Archive/RpmHandler.cpp
p7zip/CPP/7zip/Archive/SquashfsHandler.cpp
p7zip/CPP/7zip/Archive/SwfHandler.cpp
p7zip/CPP/7zip/Archive/UefiHandler.cpp
p7zip/CPP/7zip/Archive/VdiHandler.cpp
p7zip/CPP/7zip/Archive/VhdHandler.cpp
p7zip/CPP/7zip/Archive/VmdkHandler.cpp
p7zip/CPP/7zip/Archive/XarHandler.cpp
p7zip/CPP/7zip/Archive/ZHandler.cpp
p7zip/CPP/7zip/Compress/BZip2Decoder.cpp
p7zip/CPP/7zip/Compress/BZip2Register.cpp
p7zip/CPP/7zip/Compress/LzhDecoder.cpp
p7zip/CPP/7zip/Compress/LzmsDecoder.cpp
p7zip/CPP/7zip/Compress/LzxDecoder.cpp
p7zip/CPP/7zip/Compress/QuantumDecoder.cpp
p7zip/CPP/7zip/Compress/XpressDecoder.cpp
p7zip/CPP/7zip/Compress/ZDecoder.cpp
p7zip/CPP/7zip/Compress/ZlibDecoder.cpp
p7zip/CPP/Common/MyMap.cpp
p7zip/CPP/Common/MyXml.cpp
p7zip/C/HuffEnc.c
p7zip/C/Sort.c
)
set(P_SEVEN_ZIP_INCLUDES
p7zip/C
p7zip/CPP
p7zip/CPP/Common
p7zip/CPP/include_windows
p7zip/CPP/myWindows
p7zip/CPP/Windows
)
set(P_SEVEN_ZIP_EXTRACT_FLAGS
"-DEXTRACT_ONLY -D_7ZIP_ST"
)
set(P_SEVEN_ZIP_COMMON_FLAGS
"-DANDROID_NDK -DNDEBUG -D_REENTRANT -DENV_UNIX -DEXTERNAL_CODECS -DUNICODE -D_UNICODE -DUNIX_USE_WIN_FILE"
)
set(P_SEVEN_ZIP_SOURCES ${P_SEVEN_ZIP_EXTRACT_LITE_SOURCES})
set(P_SEVEN_ZIP_FLAGS "${P_SEVEN_ZIP_COMMON_FLAGS} ${P_SEVEN_ZIP_EXTRACT_FLAGS}")
set(P_SEVEN_ZIP_NAME "p7zip")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${P_SEVEN_ZIP_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${P_SEVEN_ZIP_FLAGS}")
add_library(p7zip SHARED ${P_SEVEN_ZIP_SOURCES})
target_include_directories(p7zip PUBLIC ${P_SEVEN_ZIP_INCLUDES})
set_target_properties(p7zip PROPERTIES OUTPUT_NAME ${P_SEVEN_ZIP_NAME})
target_compile_options(p7zip PRIVATE -fvisibility=default)
+171
View File
@@ -0,0 +1,171 @@
//
// Created by tarsin on 2022/5/21.
//
#include <jni.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <android/log.h>
#include <archive.h>
#include <archive_entry.h>
#define LOG_TAG "libarchive"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG ,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG ,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG ,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG ,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG ,__VA_ARGS__)
#define BLOCK_SIZE 4096
#define READ_DATA_ERR 3
typedef struct archive_inst_sc {
struct archive *archive;
int entry_num;
JNIEnv *env;
jobject file;
jmethodID readID;
jmethodID seekID;
jmethodID skipID;
void *read_buffer;
void *output_buffer;
jbyteArray jbr;
} archive_inst;
static int filename_is_playable_file(const char *name) {
const char *dotptr = strrchr(name, '.');
if (dotptr++) {
switch (*dotptr) {
case 'j':
return (strcmp(dotptr, "jpg") == 0) || (strcmp(dotptr, "jpeg") == 0);
case 'p':
return strcmp(dotptr, "png") == 0;
case 'g':
return strcmp(dotptr, "gif") == 0;
default:
return 0;
}
}
return 0;
}
static void archive_list_all_entries(struct archive_inst_sc *inst) {
struct archive *a = inst->archive;
struct archive_entry *entry;
int count = 0;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
if (filename_is_playable_file(archive_entry_pathname(entry)))
count++;
archive_read_data_skip(a);
}
inst->entry_num = count;
}
ssize_t ins_read(struct archive *a, void *client_data_ptr, const void **buff) {
archive_inst *arc = client_data_ptr;
int32_t r = (*arc->env)->CallIntMethod(arc->env, arc->file, arc->readID, arc->jbr);
(*arc->env)->GetByteArrayRegion(arc->env, arc->jbr, 0, r, arc->read_buffer);
*buff = arc->read_buffer;
return r;
}
int ins_close(struct archive *a, void *client_data) {
archive_inst *arc = client_data;
JNIEnv *env = arc->env;
jmethodID rewind = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, arc->file), "rewind",
"()V");
(*arc->env)->CallVoidMethod(arc->env, arc->file, rewind);
return ARCHIVE_OK;
}
la_int64_t ins_seek(struct archive *a, void *client_data, la_int64_t offset, int whence) {
archive_inst *arc = client_data;
jlong ret = (*arc->env)->CallLongMethod(arc->env, arc->file, arc->seekID, offset, whence);
return ret;
}
la_int64_t ins_skip(struct archive *a, void *client_data, la_int64_t request) {
archive_inst *arc = client_data;
jlong ret = (*arc->env)->CallLongMethod(arc->env, arc->file, arc->skipID, request);
return ret;
}
static archive_inst *archive_create_inst(JNIEnv *env, jobject file) {
archive_inst *inst = malloc(sizeof(archive_inst));
inst->archive = archive_read_new();
archive_read_set_seek_callback(inst->archive, ins_seek);
archive_read_set_skip_callback(inst->archive, ins_skip);
archive_read_support_format_all(inst->archive);
archive_read_support_filter_all(inst->archive);
inst->env = env;
inst->file = file;
inst->readID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, file), "read", "([B)I");
inst->seekID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, file), "seek", "(JI)J");
inst->skipID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, file), "skip", "(J)J");
inst->jbr = (*env)->NewByteArray(env, BLOCK_SIZE);
inst->read_buffer = malloc(BLOCK_SIZE);
inst->output_buffer = malloc(BLOCK_SIZE);
return inst;
}
static void archive_destroy_inst(archive_inst *inst) {
JNIEnv *env = inst->env;
archive_read_close(inst->archive);
(*env)->DeleteLocalRef(env, inst->jbr);
free(inst->read_buffer);
free(inst->output_buffer);
free(inst);
}
JNIEXPORT jint JNICALL
Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *env, jobject thiz, jobject osf) {
int r;
archive_inst *arc = archive_create_inst(env, osf);
r = archive_read_open(arc->archive, arc, NULL, ins_read, ins_close);
if (r) {
r = 0;
} else {
archive_list_all_entries(arc);
r = arc->entry_num;
}
archive_destroy_inst(arc);
return r;
}
JNIEXPORT jint JNICALL
Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *env, jobject thiz, jobject osf,
jint index, jobject os) {
int count = 0;
struct archive_entry *entry;
archive_inst *arc = archive_create_inst(env, osf);
int32_t size;
jmethodID writeID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, os), "write", "([B)V");
jmethodID flushID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, os), "flush", "()V");
archive_read_open(arc->archive, arc, NULL, ins_read, ins_close);
while (archive_read_next_header(arc->archive, &entry) == ARCHIVE_OK) {
if (!filename_is_playable_file(archive_entry_pathname(entry)))
continue;
if (count == index) {
for (;;) {
size = (int32_t) archive_read_data(arc->archive, arc->output_buffer, BLOCK_SIZE);
if (size < 0) {
return READ_DATA_ERR;
}
if (size == 0)
break;
(*arc->env)->SetByteArrayRegion(env, arc->jbr, 0, size, arc->output_buffer);
(*arc->env)->CallVoidMethod(env, os, writeID, arc->jbr);
(*arc->env)->CallVoidMethod(env, os, flushID);
}
break;
} else {
archive_read_data_skip(arc->archive);
}
count++;
}
archive_destroy_inst(arc);
return 0;
}
-2
View File
@@ -14,8 +14,6 @@
cmake_minimum_required(VERSION 3.4.1)
include(AndroidNdkModules)
android_ndk_import_module_cpufeatures()
add_subdirectory(image)
add_subdirectory(stream)
add_subdirectory(libjpeg-turbo)
@@ -16,11 +16,11 @@ cmake_minimum_required(VERSION 3.4.1)
project(giflib C)
set(GIFLIB_SOURCES
giflib/dgif_lib.c
giflib/gif_hash.c
giflib/gifalloc.c
giflib/openbsd-reallocarray.c
)
giflib/dgif_lib.c
giflib/gif_hash.c
giflib/gifalloc.c
giflib/openbsd-reallocarray.c
)
set(GIFLIB_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/giflib)
add_library(giflib STATIC ${GIFLIB_SOURCES})
+20 -20
View File
@@ -16,28 +16,28 @@ cmake_minimum_required(VERSION 3.4.1)
project(image C)
set(IMAGE_SOURCES
image.c
image_utils.c
image_plain.c
image_jpeg.c
image_png.c
image_gif.c
filter/clahe.c
filter/gray.c
java_wrapper.c
)
image.c
image_utils.c
image_plain.c
image_jpeg.c
image_png.c
image_gif.c
filter/clahe.c
filter/gray.c
java_wrapper.c
)
set(IMAGE_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}
)
${CMAKE_CURRENT_SOURCE_DIR}
)
set(IMAGE_LIBRARIES
log
jnigraphics
GLESv2
stream
libjpeg-turbo
libpng
giflib
)
log
jnigraphics
GLESv2
stream
libjpeg-turbo
libpng
giflib
)
add_library(image STATIC ${IMAGE_SOURCES})
target_include_directories(image PRIVATE ${IMAGE_INCLUDES})
@@ -16,194 +16,194 @@ cmake_minimum_required(VERSION 3.4.1)
project(libjpeg-turbo C)
set(LIBJPEG_TURBO_SOURCES
libjpeg-turbo/jaricom.c
libjpeg-turbo/jcomapi.c
libjpeg-turbo/jdapimin.c
libjpeg-turbo/jdapistd.c
libjpeg-turbo/jdarith.c
libjpeg-turbo/jdatasrc.c
libjpeg-turbo/jdatasrc-tj.c
libjpeg-turbo/jdcoefct.c
libjpeg-turbo/jdcolor.c
libjpeg-turbo/jddctmgr.c
libjpeg-turbo/jdhuff.c
libjpeg-turbo/jdinput.c
libjpeg-turbo/jdmainct.c
libjpeg-turbo/jdmarker.c
libjpeg-turbo/jdmaster.c
libjpeg-turbo/jdmerge.c
libjpeg-turbo/jdphuff.c
libjpeg-turbo/jdpostct.c
libjpeg-turbo/jdsample.c
libjpeg-turbo/jdtrans.c
libjpeg-turbo/jerror.c
libjpeg-turbo/jfdctflt.c
libjpeg-turbo/jfdctfst.c
libjpeg-turbo/jfdctint.c
libjpeg-turbo/jidctflt.c
libjpeg-turbo/jidctfst.c
libjpeg-turbo/jidctint.c
libjpeg-turbo/jidctred.c
libjpeg-turbo/jmemmgr.c
libjpeg-turbo/jmemnobs.c
libjpeg-turbo/jquant1.c
libjpeg-turbo/jquant2.c
libjpeg-turbo/jutils.c
)
libjpeg-turbo/jaricom.c
libjpeg-turbo/jcomapi.c
libjpeg-turbo/jdapimin.c
libjpeg-turbo/jdapistd.c
libjpeg-turbo/jdarith.c
libjpeg-turbo/jdatasrc.c
libjpeg-turbo/jdatasrc-tj.c
libjpeg-turbo/jdcoefct.c
libjpeg-turbo/jdcolor.c
libjpeg-turbo/jddctmgr.c
libjpeg-turbo/jdhuff.c
libjpeg-turbo/jdinput.c
libjpeg-turbo/jdmainct.c
libjpeg-turbo/jdmarker.c
libjpeg-turbo/jdmaster.c
libjpeg-turbo/jdmerge.c
libjpeg-turbo/jdphuff.c
libjpeg-turbo/jdpostct.c
libjpeg-turbo/jdsample.c
libjpeg-turbo/jdtrans.c
libjpeg-turbo/jerror.c
libjpeg-turbo/jfdctflt.c
libjpeg-turbo/jfdctfst.c
libjpeg-turbo/jfdctint.c
libjpeg-turbo/jidctflt.c
libjpeg-turbo/jidctfst.c
libjpeg-turbo/jidctint.c
libjpeg-turbo/jidctred.c
libjpeg-turbo/jmemmgr.c
libjpeg-turbo/jmemnobs.c
libjpeg-turbo/jquant1.c
libjpeg-turbo/jquant2.c
libjpeg-turbo/jutils.c
)
set(LIBJPEG_TURBO_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/libjpeg-turbo
)
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/libjpeg-turbo
)
if (${ANDROID_ABI} STREQUAL "armeabi-v7a")
enable_language(ASM)
enable_language(ASM)
add_definitions(-DNEON_INTRINSICS)
add_definitions(-DNEON_INTRINSICS)
set(LIBJPEG_TURBO_SOURCES
${LIBJPEG_TURBO_SOURCES}
libjpeg-turbo/simd/arm/jccolor-neon.c
libjpeg-turbo/simd/arm/jidctred-neon.c
libjpeg-turbo/simd/arm/jquanti-neon.c
libjpeg-turbo/simd/arm/jidctint-neon.c
libjpeg-turbo/simd/arm/jidctfst-neon.c
libjpeg-turbo/simd/arm/jfdctint-neon.c
libjpeg-turbo/simd/arm/jfdctfst-neon.c
libjpeg-turbo/simd/arm/jdsample-neon.c
libjpeg-turbo/simd/arm/jdmerge-neon.c
libjpeg-turbo/simd/arm/jdcolor-neon.c
libjpeg-turbo/simd/arm/jcsample-neon.c
libjpeg-turbo/simd/arm/jcphuff-neon.c
libjpeg-turbo/simd/arm/jcgray-neon.c
libjpeg-turbo/simd/arm/aarch32/jchuff-neon.c
libjpeg-turbo/simd/arm/aarch32/jsimd.c
)
set(LIBJPEG_TURBO_SOURCES
${LIBJPEG_TURBO_SOURCES}
libjpeg-turbo/simd/arm/jccolor-neon.c
libjpeg-turbo/simd/arm/jidctred-neon.c
libjpeg-turbo/simd/arm/jquanti-neon.c
libjpeg-turbo/simd/arm/jidctint-neon.c
libjpeg-turbo/simd/arm/jidctfst-neon.c
libjpeg-turbo/simd/arm/jfdctint-neon.c
libjpeg-turbo/simd/arm/jfdctfst-neon.c
libjpeg-turbo/simd/arm/jdsample-neon.c
libjpeg-turbo/simd/arm/jdmerge-neon.c
libjpeg-turbo/simd/arm/jdcolor-neon.c
libjpeg-turbo/simd/arm/jcsample-neon.c
libjpeg-turbo/simd/arm/jcphuff-neon.c
libjpeg-turbo/simd/arm/jcgray-neon.c
libjpeg-turbo/simd/arm/aarch32/jchuff-neon.c
libjpeg-turbo/simd/arm/aarch32/jsimd.c
)
elseif (${ANDROID_ABI} STREQUAL "arm64-v8a")
enable_language(ASM)
enable_language(ASM)
add_definitions(-DNEON_INTRINSICS)
add_definitions(-DNEON_INTRINSICS)
set(LIBJPEG_TURBO_SOURCES
${LIBJPEG_TURBO_SOURCES}
libjpeg-turbo/simd/arm/jccolor-neon.c
libjpeg-turbo/simd/arm/jidctred-neon.c
libjpeg-turbo/simd/arm/jquanti-neon.c
libjpeg-turbo/simd/arm/jidctint-neon.c
libjpeg-turbo/simd/arm/jidctfst-neon.c
libjpeg-turbo/simd/arm/jfdctint-neon.c
libjpeg-turbo/simd/arm/jfdctfst-neon.c
libjpeg-turbo/simd/arm/jdsample-neon.c
libjpeg-turbo/simd/arm/jdmerge-neon.c
libjpeg-turbo/simd/arm/jdcolor-neon.c
libjpeg-turbo/simd/arm/jcsample-neon.c
libjpeg-turbo/simd/arm/jcphuff-neon.c
libjpeg-turbo/simd/arm/jcgray-neon.c
libjpeg-turbo/simd/arm/aarch64/jchuff-neon.c
libjpeg-turbo/simd/arm/aarch64/jsimd.c
)
set(LIBJPEG_TURBO_SOURCES
${LIBJPEG_TURBO_SOURCES}
libjpeg-turbo/simd/arm/jccolor-neon.c
libjpeg-turbo/simd/arm/jidctred-neon.c
libjpeg-turbo/simd/arm/jquanti-neon.c
libjpeg-turbo/simd/arm/jidctint-neon.c
libjpeg-turbo/simd/arm/jidctfst-neon.c
libjpeg-turbo/simd/arm/jfdctint-neon.c
libjpeg-turbo/simd/arm/jfdctfst-neon.c
libjpeg-turbo/simd/arm/jdsample-neon.c
libjpeg-turbo/simd/arm/jdmerge-neon.c
libjpeg-turbo/simd/arm/jdcolor-neon.c
libjpeg-turbo/simd/arm/jcsample-neon.c
libjpeg-turbo/simd/arm/jcphuff-neon.c
libjpeg-turbo/simd/arm/jcgray-neon.c
libjpeg-turbo/simd/arm/aarch64/jchuff-neon.c
libjpeg-turbo/simd/arm/aarch64/jsimd.c
)
elseif (${ANDROID_ABI} STREQUAL "x86")
enable_language(ASM_NASM)
enable_language(ASM_NASM)
set(LIBJPEG_TURBO_SOURCES
${LIBJPEG_TURBO_SOURCES}
libjpeg-turbo/simd/i386/jsimd.c
libjpeg-turbo/simd/i386/jsimdcpu.asm
libjpeg-turbo/simd/i386/jfdctflt-3dn.asm
libjpeg-turbo/simd/i386/jidctflt-3dn.asm
libjpeg-turbo/simd/i386/jquant-3dn.asm
libjpeg-turbo/simd/i386/jccolor-mmx.asm
libjpeg-turbo/simd/i386/jcgray-mmx.asm
libjpeg-turbo/simd/i386/jcsample-mmx.asm
libjpeg-turbo/simd/i386/jdcolor-mmx.asm
libjpeg-turbo/simd/i386/jdmerge-mmx.asm
libjpeg-turbo/simd/i386/jdsample-mmx.asm
libjpeg-turbo/simd/i386/jfdctfst-mmx.asm
libjpeg-turbo/simd/i386/jfdctint-mmx.asm
libjpeg-turbo/simd/i386/jidctfst-mmx.asm
libjpeg-turbo/simd/i386/jidctint-mmx.asm
libjpeg-turbo/simd/i386/jidctred-mmx.asm
libjpeg-turbo/simd/i386/jquant-mmx.asm
libjpeg-turbo/simd/i386/jfdctflt-sse.asm
libjpeg-turbo/simd/i386/jidctflt-sse.asm
libjpeg-turbo/simd/i386/jquant-sse.asm
libjpeg-turbo/simd/i386/jccolor-sse2.asm
libjpeg-turbo/simd/i386/jcgray-sse2.asm
libjpeg-turbo/simd/i386/jchuff-sse2.asm
libjpeg-turbo/simd/i386/jcphuff-sse2.asm
libjpeg-turbo/simd/i386/jcsample-sse2.asm
libjpeg-turbo/simd/i386/jdcolor-sse2.asm
libjpeg-turbo/simd/i386/jdmerge-sse2.asm
libjpeg-turbo/simd/i386/jdsample-sse2.asm
libjpeg-turbo/simd/i386/jfdctfst-sse2.asm
libjpeg-turbo/simd/i386/jfdctint-sse2.asm
libjpeg-turbo/simd/i386/jidctflt-sse2.asm
libjpeg-turbo/simd/i386/jidctfst-sse2.asm
libjpeg-turbo/simd/i386/jidctint-sse2.asm
libjpeg-turbo/simd/i386/jidctred-sse2.asm
libjpeg-turbo/simd/i386/jquantf-sse2.asm
libjpeg-turbo/simd/i386/jquanti-sse2.asm
libjpeg-turbo/simd/i386/jccolor-avx2.asm
libjpeg-turbo/simd/i386/jcgray-avx2.asm
libjpeg-turbo/simd/i386/jcsample-avx2.asm
libjpeg-turbo/simd/i386/jdcolor-avx2.asm
libjpeg-turbo/simd/i386/jdmerge-avx2.asm
libjpeg-turbo/simd/i386/jdsample-avx2.asm
libjpeg-turbo/simd/i386/jfdctint-avx2.asm
libjpeg-turbo/simd/i386/jidctint-avx2.asm
libjpeg-turbo/simd/i386/jquanti-avx2.asm
)
set(LIBJPEG_TURBO_SOURCES
${LIBJPEG_TURBO_SOURCES}
libjpeg-turbo/simd/i386/jsimd.c
libjpeg-turbo/simd/i386/jsimdcpu.asm
libjpeg-turbo/simd/i386/jfdctflt-3dn.asm
libjpeg-turbo/simd/i386/jidctflt-3dn.asm
libjpeg-turbo/simd/i386/jquant-3dn.asm
libjpeg-turbo/simd/i386/jccolor-mmx.asm
libjpeg-turbo/simd/i386/jcgray-mmx.asm
libjpeg-turbo/simd/i386/jcsample-mmx.asm
libjpeg-turbo/simd/i386/jdcolor-mmx.asm
libjpeg-turbo/simd/i386/jdmerge-mmx.asm
libjpeg-turbo/simd/i386/jdsample-mmx.asm
libjpeg-turbo/simd/i386/jfdctfst-mmx.asm
libjpeg-turbo/simd/i386/jfdctint-mmx.asm
libjpeg-turbo/simd/i386/jidctfst-mmx.asm
libjpeg-turbo/simd/i386/jidctint-mmx.asm
libjpeg-turbo/simd/i386/jidctred-mmx.asm
libjpeg-turbo/simd/i386/jquant-mmx.asm
libjpeg-turbo/simd/i386/jfdctflt-sse.asm
libjpeg-turbo/simd/i386/jidctflt-sse.asm
libjpeg-turbo/simd/i386/jquant-sse.asm
libjpeg-turbo/simd/i386/jccolor-sse2.asm
libjpeg-turbo/simd/i386/jcgray-sse2.asm
libjpeg-turbo/simd/i386/jchuff-sse2.asm
libjpeg-turbo/simd/i386/jcphuff-sse2.asm
libjpeg-turbo/simd/i386/jcsample-sse2.asm
libjpeg-turbo/simd/i386/jdcolor-sse2.asm
libjpeg-turbo/simd/i386/jdmerge-sse2.asm
libjpeg-turbo/simd/i386/jdsample-sse2.asm
libjpeg-turbo/simd/i386/jfdctfst-sse2.asm
libjpeg-turbo/simd/i386/jfdctint-sse2.asm
libjpeg-turbo/simd/i386/jidctflt-sse2.asm
libjpeg-turbo/simd/i386/jidctfst-sse2.asm
libjpeg-turbo/simd/i386/jidctint-sse2.asm
libjpeg-turbo/simd/i386/jidctred-sse2.asm
libjpeg-turbo/simd/i386/jquantf-sse2.asm
libjpeg-turbo/simd/i386/jquanti-sse2.asm
libjpeg-turbo/simd/i386/jccolor-avx2.asm
libjpeg-turbo/simd/i386/jcgray-avx2.asm
libjpeg-turbo/simd/i386/jcsample-avx2.asm
libjpeg-turbo/simd/i386/jdcolor-avx2.asm
libjpeg-turbo/simd/i386/jdmerge-avx2.asm
libjpeg-turbo/simd/i386/jdsample-avx2.asm
libjpeg-turbo/simd/i386/jfdctint-avx2.asm
libjpeg-turbo/simd/i386/jidctint-avx2.asm
libjpeg-turbo/simd/i386/jquanti-avx2.asm
)
set(CMAKE_ASM_NASM_FLAGS "-DELF -DPIC -I${CMAKE_CURRENT_SOURCE_DIR}/libjpeg-turbo/simd/nasm")
set(CMAKE_ASM_NASM_FLAGS "-DELF -DPIC -I${CMAKE_CURRENT_SOURCE_DIR}/libjpeg-turbo/simd/nasm")
elseif (${ANDROID_ABI} STREQUAL "x86_64")
enable_language(ASM_NASM)
enable_language(ASM_NASM)
set(LIBJPEG_TURBO_SOURCES
${LIBJPEG_TURBO_SOURCES}
libjpeg-turbo/simd/x86_64/jsimd.c
libjpeg-turbo/simd/x86_64/jsimdcpu.asm
libjpeg-turbo/simd/x86_64/jfdctflt-sse.asm
libjpeg-turbo/simd/x86_64/jccolor-sse2.asm
libjpeg-turbo/simd/x86_64/jcgray-sse2.asm
libjpeg-turbo/simd/x86_64/jchuff-sse2.asm
libjpeg-turbo/simd/x86_64/jcphuff-sse2.asm
libjpeg-turbo/simd/x86_64/jcsample-sse2.asm
libjpeg-turbo/simd/x86_64/jdcolor-sse2.asm
libjpeg-turbo/simd/x86_64/jdmerge-sse2.asm
libjpeg-turbo/simd/x86_64/jdsample-sse2.asm
libjpeg-turbo/simd/x86_64/jfdctfst-sse2.asm
libjpeg-turbo/simd/x86_64/jfdctint-sse2.asm
libjpeg-turbo/simd/x86_64/jidctflt-sse2.asm
libjpeg-turbo/simd/x86_64/jidctfst-sse2.asm
libjpeg-turbo/simd/x86_64/jidctint-sse2.asm
libjpeg-turbo/simd/x86_64/jidctred-sse2.asm
libjpeg-turbo/simd/x86_64/jquantf-sse2.asm
libjpeg-turbo/simd/x86_64/jquanti-sse2.asm
libjpeg-turbo/simd/x86_64/jccolor-avx2.asm
libjpeg-turbo/simd/x86_64/jcgray-avx2.asm
libjpeg-turbo/simd/x86_64/jcsample-avx2.asm
libjpeg-turbo/simd/x86_64/jdcolor-avx2.asm
libjpeg-turbo/simd/x86_64/jdmerge-avx2.asm
libjpeg-turbo/simd/x86_64/jdsample-avx2.asm
libjpeg-turbo/simd/x86_64/jfdctint-avx2.asm
libjpeg-turbo/simd/x86_64/jidctint-avx2.asm
libjpeg-turbo/simd/x86_64/jquanti-avx2.asm
)
set(LIBJPEG_TURBO_SOURCES
${LIBJPEG_TURBO_SOURCES}
libjpeg-turbo/simd/x86_64/jsimd.c
libjpeg-turbo/simd/x86_64/jsimdcpu.asm
libjpeg-turbo/simd/x86_64/jfdctflt-sse.asm
libjpeg-turbo/simd/x86_64/jccolor-sse2.asm
libjpeg-turbo/simd/x86_64/jcgray-sse2.asm
libjpeg-turbo/simd/x86_64/jchuff-sse2.asm
libjpeg-turbo/simd/x86_64/jcphuff-sse2.asm
libjpeg-turbo/simd/x86_64/jcsample-sse2.asm
libjpeg-turbo/simd/x86_64/jdcolor-sse2.asm
libjpeg-turbo/simd/x86_64/jdmerge-sse2.asm
libjpeg-turbo/simd/x86_64/jdsample-sse2.asm
libjpeg-turbo/simd/x86_64/jfdctfst-sse2.asm
libjpeg-turbo/simd/x86_64/jfdctint-sse2.asm
libjpeg-turbo/simd/x86_64/jidctflt-sse2.asm
libjpeg-turbo/simd/x86_64/jidctfst-sse2.asm
libjpeg-turbo/simd/x86_64/jidctint-sse2.asm
libjpeg-turbo/simd/x86_64/jidctred-sse2.asm
libjpeg-turbo/simd/x86_64/jquantf-sse2.asm
libjpeg-turbo/simd/x86_64/jquanti-sse2.asm
libjpeg-turbo/simd/x86_64/jccolor-avx2.asm
libjpeg-turbo/simd/x86_64/jcgray-avx2.asm
libjpeg-turbo/simd/x86_64/jcsample-avx2.asm
libjpeg-turbo/simd/x86_64/jdcolor-avx2.asm
libjpeg-turbo/simd/x86_64/jdmerge-avx2.asm
libjpeg-turbo/simd/x86_64/jdsample-avx2.asm
libjpeg-turbo/simd/x86_64/jfdctint-avx2.asm
libjpeg-turbo/simd/x86_64/jidctint-avx2.asm
libjpeg-turbo/simd/x86_64/jquanti-avx2.asm
)
set(CMAKE_ASM_NASM_FLAGS "-D__x86_64__ -DELF -DPIC -I${CMAKE_CURRENT_SOURCE_DIR}/libjpeg-turbo/simd/nasm")
set(CMAKE_ASM_NASM_FLAGS "-D__x86_64__ -DELF -DPIC -I${CMAKE_CURRENT_SOURCE_DIR}/libjpeg-turbo/simd/nasm")
else ()
set(LIBJPEG_TURBO_SOURCES
${LIBJPEG_TURBO_SOURCES}
libjpeg-turbo/jsimd_none.c
)
set(LIBJPEG_TURBO_SOURCES
${LIBJPEG_TURBO_SOURCES}
libjpeg-turbo/jsimd_none.c
)
endif ()
@@ -4,22 +4,22 @@
#define JPEG_LIB_VERSION 62
/* libjpeg-turbo version */
#define LIBJPEG_TURBO_VERSION 2.0.0
#define LIBJPEG_TURBO_VERSION 2.1.3
/* libjpeg-turbo version in integer form */
#define LIBJPEG_TURBO_VERSION_NUMBER 2000000
#define LIBJPEG_TURBO_VERSION_NUMBER 2001003
/* Support arithmetic encoding */
#define C_ARITH_CODING_SUPPORTED
#define C_ARITH_CODING_SUPPORTED 1
/* Support arithmetic decoding */
#define D_ARITH_CODING_SUPPORTED
#define D_ARITH_CODING_SUPPORTED 1
/* Support in-memory source/destination managers */
#define MEM_SRCDST_SUPPORTED
#define MEM_SRCDST_SUPPORTED 1
/* Use accelerated SIMD routines. */
#define WITH_SIMD
#define WITH_SIMD 1
/*
* Define BITS_IN_JSAMPLE as either
@@ -32,42 +32,6 @@
#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
/* Define to 1 if you have the <locale.h> header file. */
#define HAVE_LOCALE_H
/* Define to 1 if you have the <stddef.h> header file. */
#define HAVE_STDDEF_H
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H
/* Define if you need to include <sys/types.h> to get size_t. */
#define NEED_SYS_TYPES_H
/* Define if you have BSD-like bzero and bcopy in <strings.h> rather than
memset/memcpy in <string.h>. */
/* #undef NEED_BSD_STRINGS */
/* Define to 1 if the system has the type `unsigned char'. */
#define HAVE_UNSIGNED_CHAR
/* Define to 1 if the system has the type `unsigned short'. */
#define HAVE_UNSIGNED_SHORT
/* Compiler does not support pointers to undefined structures. */
/* #undef INCOMPLETE_TYPES_BROKEN */
/* Define if your (broken) compiler shifts signed values as if they were
unsigned. */
/* #undef RIGHT_SHIFT_IS_UNSIGNED */
/* Define to 1 if type `char' is unsigned and you are not using gcc. */
#ifndef __CHAR_UNSIGNED__
/* #undef __CHAR_UNSIGNED__ */
#endif
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */
@@ -1,5 +1,5 @@
/* libjpeg-turbo build number */
#define BUILD "20180730"
#define BUILD "20220523"
/* Compiler's inline keyword */
#undef inline
@@ -7,14 +7,17 @@
/* How to obtain function inlining. */
#define INLINE __inline__ __attribute__((always_inline))
/* How to obtain thread-local storage */
#define THREAD_LOCAL __thread
/* Define to the full name of this package. */
#define PACKAGE_NAME "libjpeg-turbo"
/* Version number of package */
#define VERSION "2.0.0"
#define VERSION "2.1.3"
/* The size of `size_t', as computed by sizeof. */
#define SIZEOF_SIZE_T __SIZEOF_SIZE_T__
#define SIZEOF_SIZE_T 8
/* Define if your compiler has __builtin_ctzl() and sizeof(unsigned long) == sizeof(size_t). */
#define HAVE_BUILTIN_CTZL
@@ -0,0 +1,54 @@
/*
* jversion.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2010, 2012-2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains software version identification.
*/
#if JPEG_LIB_VERSION >= 80
#define JVERSION "8d 15-Jan-2012"
#elif JPEG_LIB_VERSION >= 70
#define JVERSION "7 27-Jun-2009"
#else
#define JVERSION "6b 27-Mar-1998"
#endif
/*
* NOTE: It is our convention to place the authors in the following order:
* - libjpeg-turbo authors (2009-) in descending order of the date of their
* most recent contribution to the project, then in ascending order of the
* date of their first contribution to the project, then in alphabetical
* order
* - Upstream authors in descending order of the date of the first inclusion of
* their code
*/
#define JCOPYRIGHT \
"Copyright (C) 2009-2022 D. R. Commander\n" \
"Copyright (C) 2015, 2020 Google, Inc.\n" \
"Copyright (C) 2019-2020 Arm Limited\n" \
"Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \
"Copyright (C) 2011-2016 Siarhei Siamashka\n" \
"Copyright (C) 2015 Intel Corporation\n" \
"Copyright (C) 2013-2014 Linaro Limited\n" \
"Copyright (C) 2013-2014 MIPS Technologies, Inc.\n" \
"Copyright (C) 2009, 2012 Pierre Ossman for Cendio AB\n" \
"Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)\n" \
"Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
"Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding"
#define JCOPYRIGHT_SHORT \
"Copyright (C) 1991-2022 The libjpeg-turbo Project and many others"
+61 -60
View File
@@ -16,77 +16,78 @@ cmake_minimum_required(VERSION 3.4.1)
project(libpng C)
set(LIBPNG_SOURCES
libpng/png.c
libpng/pngerror.c
libpng/pngget.c
libpng/pngmem.c
libpng/pngpread.c
libpng/pngread.c
libpng/pngrio.c
libpng/pngrtran.c
libpng/pngrutil.c
libpng/pngset.c
libpng/pngtrans.c
)
libpng/png.c
libpng/pngerror.c
libpng/pngget.c
libpng/pngmem.c
libpng/pngpread.c
libpng/pngread.c
libpng/pngrio.c
libpng/pngrtran.c
libpng/pngrutil.c
libpng/pngset.c
libpng/pngtrans.c
)
set(LIBPNG_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/libpng
)
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/libpng
)
set(LIBPNG_DEFINITIONS)
set(LIBPNG_LIBRARIES z)
if (${ANDROID_ABI} STREQUAL "armeabi-v7a")
enable_language(ASM)
enable_language(ASM)
set(LIBPNG_SOURCES
${LIBPNG_SOURCES}
libpng/arm/arm_init.c
libpng/arm/filter_neon.S
)
set(LIBPNG_INCLUDES
${LIBPNG_INCLUDES}
${ANDROID_NDK}/sources/android/cpufeatures
)
set(LIBPNG_DEFINITIONS
${LIBPNG_DEFINITIONS}
-DPNG_ARM_NEON_API_SUPPORTED
-DPNG_ARM_NEON_CHECK_SUPPORTED
-DPNG_ARM_NEON_OPT=1
-DPNG_ARM_NEON_IMPLEMENTATION=2
-DPNG_ARM_NEON_FILE=\"contrib/arm-neon/android-ndk.c\"
)
set(LIBPNG_LIBRARIES
${LIBPNG_LIBRARIES}
cpufeatures
)
set(LIBPNG_SOURCES
${LIBPNG_SOURCES}
libpng/arm/arm_init.c
libpng/arm/filter_neon.S
${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c
)
set(LIBPNG_INCLUDES
${LIBPNG_INCLUDES}
${ANDROID_NDK}/sources/android/cpufeatures
)
set(LIBPNG_DEFINITIONS
${LIBPNG_DEFINITIONS}
-DPNG_ARM_NEON_API_SUPPORTED
-DPNG_ARM_NEON_CHECK_SUPPORTED
-DPNG_ARM_NEON_OPT=1
-DPNG_ARM_NEON_IMPLEMENTATION=2
-DPNG_ARM_NEON_FILE=\"contrib/arm-neon/android-ndk.c\"
)
set(LIBPNG_LIBRARIES
${LIBPNG_LIBRARIES}
)
elseif (${ANDROID_ABI} STREQUAL "arm64-v8a")
enable_language(ASM)
enable_language(ASM)
set(LIBPNG_SOURCES
${LIBPNG_SOURCES}
libpng/arm/arm_init.c
libpng/arm/filter_neon_intrinsics.c
libpng/arm/palette_neon_intrinsics.c
)
set(LIBPNG_INCLUDES
${LIBPNG_INCLUDES}
${ANDROID_NDK}/sources/android/cpufeatures
)
set(LIBPNG_DEFINITIONS
${LIBPNG_DEFINITIONS}
-DPNG_ARM_NEON_API_SUPPORTED
-DPNG_ARM_NEON_CHECK_SUPPORTED
-DPNG_ARM_NEON_OPT=1
-DPNG_ARM_NEON_IMPLEMENTATION=1
-DPNG_ARM_NEON_FILE=\"contrib/arm-neon/android-ndk.c\"
)
set(LIBPNG_LIBRARIES
${LIBPNG_LIBRARIES}
cpufeatures
)
set(LIBPNG_SOURCES
${LIBPNG_SOURCES}
libpng/arm/arm_init.c
libpng/arm/filter_neon_intrinsics.c
libpng/arm/palette_neon_intrinsics.c
${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c
)
set(LIBPNG_INCLUDES
${LIBPNG_INCLUDES}
${ANDROID_NDK}/sources/android/cpufeatures
)
set(LIBPNG_DEFINITIONS
${LIBPNG_DEFINITIONS}
-DPNG_ARM_NEON_API_SUPPORTED
-DPNG_ARM_NEON_CHECK_SUPPORTED
-DPNG_ARM_NEON_OPT=1
-DPNG_ARM_NEON_IMPLEMENTATION=1
-DPNG_ARM_NEON_FILE=\"contrib/arm-neon/android-ndk.c\"
)
set(LIBPNG_LIBRARIES
${LIBPNG_LIBRARIES}
)
endif ()
@@ -1,12 +0,0 @@
project(genuine C)
add_library(genuine STATIC
am-proxy.c
apk-sign-v2.c
common.c
genuine.c
inline.c
openat.c
path.c
plt.c)
target_include_directories(genuine PUBLIC integrity)
-824
View File
@@ -1,824 +0,0 @@
//
// Created by Thom on 2019/3/15.
//
#include "common.h"
#include "am-proxy.h"
static inline void fill_android_app_ActivityManager(char v[]) {
// android/app/ActivityManager
static unsigned int m = 0;
if (m == 0) {
m = 23;
} else if (m == 29) {
m = 31;
}
v[0x0] = 'e';
v[0x1] = 'k';
v[0x2] = 'b';
v[0x3] = 'u';
v[0x4] = 'g';
v[0x5] = '`';
v[0x6] = 'n';
v[0x7] = '$';
v[0x8] = 'm';
v[0x9] = '}';
v[0xa] = '~';
v[0xb] = ' ';
v[0xc] = 'Q';
v[0xd] = 'r';
v[0xe] = 'f';
v[0xf] = 'z';
v[0x10] = 'b';
v[0x11] = '|';
v[0x12] = 'b';
v[0x13] = 'y';
v[0x14] = 'L';
v[0x15] = 'c';
v[0x16] = 'm';
v[0x17] = 'e';
v[0x18] = 'b';
v[0x19] = 'c';
v[0x1a] = 'u';
for (unsigned int i = 0; i < 0x1b; ++i) {
v[i] ^= ((i + 0x1b) % m);
}
v[0x1b] = '\0';
}
static inline void fill_getService(char v[]) {
// getService
static unsigned int m = 0;
if (m == 0) {
m = 7;
} else if (m == 11) {
m = 13;
}
v[0x0] = 'd';
v[0x1] = 'a';
v[0x2] = 'q';
v[0x3] = 'U';
v[0x4] = 'e';
v[0x5] = 's';
v[0x6] = 't';
v[0x7] = 'j';
v[0x8] = 'g';
v[0x9] = '`';
for (unsigned int i = 0; i < 0xa; ++i) {
v[i] ^= ((i + 0xa) % m);
}
v[0xa] = '\0';
}
static inline void fill_getService_signature(char v[]) {
// ()Landroid/app/IActivityManager;
static unsigned int m = 0;
if (m == 0) {
m = 31;
} else if (m == 37) {
m = 41;
}
v[0x0] = ')';
v[0x1] = '+';
v[0x2] = 'O';
v[0x3] = 'e';
v[0x4] = 'k';
v[0x5] = 'b';
v[0x6] = 'u';
v[0x7] = 'g';
v[0x8] = '`';
v[0x9] = 'n';
v[0xa] = '$';
v[0xb] = 'm';
v[0xc] = '}';
v[0xd] = '~';
v[0xe] = ' ';
v[0xf] = 'Y';
v[0x10] = 'P';
v[0x11] = 'q';
v[0x12] = 'g';
v[0x13] = '}';
v[0x14] = 'c';
v[0x15] = '\x7f';
v[0x16] = 'c';
v[0x17] = 'a';
v[0x18] = 'T';
v[0x19] = '{';
v[0x1a] = 'u';
v[0x1b] = '}';
v[0x1c] = 'z';
v[0x1d] = '{';
v[0x1e] = 'r';
v[0x1f] = ':';
for (unsigned int i = 0; i < 0x20; ++i) {
v[i] ^= ((i + 0x20) % m);
}
v[0x20] = '\0';
}
static inline void fill_android_app_ActivityManagerNative(char v[]) {
// android/app/ActivityManagerNative
static unsigned int m = 0;
if (m == 0) {
m = 31;
} else if (m == 37) {
m = 41;
}
v[0x0] = 'c';
v[0x1] = 'm';
v[0x2] = '`';
v[0x3] = 'w';
v[0x4] = 'i';
v[0x5] = 'n';
v[0x6] = 'l';
v[0x7] = '&';
v[0x8] = 'k';
v[0x9] = '{';
v[0xa] = '|';
v[0xb] = '"';
v[0xc] = 'O';
v[0xd] = 'l';
v[0xe] = 'd';
v[0xf] = 'x';
v[0x10] = 'd';
v[0x11] = 'z';
v[0x12] = '`';
v[0x13] = 'l';
v[0x14] = '[';
v[0x15] = 'v';
v[0x16] = 'v';
v[0x17] = 'x';
v[0x18] = '}';
v[0x19] = '~';
v[0x1a] = 'n';
v[0x1b] = 'S';
v[0x1c] = '\x7f';
v[0x1d] = 't';
v[0x1e] = 'h';
v[0x1f] = 't';
v[0x20] = 'f';
for (unsigned int i = 0; i < 0x21; ++i) {
v[i] ^= ((i + 0x21) % m);
}
v[0x21] = '\0';
}
static inline void fill_getDefault(char v[]) {
// getDefault
static unsigned int m = 0;
if (m == 0) {
m = 7;
} else if (m == 11) {
m = 13;
}
v[0x0] = 'd';
v[0x1] = 'a';
v[0x2] = 'q';
v[0x3] = 'B';
v[0x4] = 'e';
v[0x5] = 'g';
v[0x6] = 'c';
v[0x7] = 'v';
v[0x8] = 'h';
v[0x9] = 'q';
for (unsigned int i = 0; i < 0xa; ++i) {
v[i] ^= ((i + 0xa) % m);
}
v[0xa] = '\0';
}
static inline void fill_getDefault_signature(char v[]) {
// ()Landroid/app/IActivityManager;
static unsigned int m = 0;
if (m == 0) {
m = 31;
} else if (m == 37) {
m = 41;
}
v[0x0] = ')';
v[0x1] = '+';
v[0x2] = 'O';
v[0x3] = 'e';
v[0x4] = 'k';
v[0x5] = 'b';
v[0x6] = 'u';
v[0x7] = 'g';
v[0x8] = '`';
v[0x9] = 'n';
v[0xa] = '$';
v[0xb] = 'm';
v[0xc] = '}';
v[0xd] = '~';
v[0xe] = ' ';
v[0xf] = 'Y';
v[0x10] = 'P';
v[0x11] = 'q';
v[0x12] = 'g';
v[0x13] = '}';
v[0x14] = 'c';
v[0x15] = '\x7f';
v[0x16] = 'c';
v[0x17] = 'a';
v[0x18] = 'T';
v[0x19] = '{';
v[0x1a] = 'u';
v[0x1b] = '}';
v[0x1c] = 'z';
v[0x1d] = '{';
v[0x1e] = 'r';
v[0x1f] = ':';
for (unsigned int i = 0; i < 0x20; ++i) {
v[i] ^= ((i + 0x20) % m);
}
v[0x20] = '\0';
}
static inline void fill_android_os_BinderProxy(char v[]) {
// android/os/BinderProxy
static unsigned int m = 0;
if (m == 0) {
m = 19;
} else if (m == 23) {
m = 29;
}
v[0x0] = 'b';
v[0x1] = 'j';
v[0x2] = 'a';
v[0x3] = 't';
v[0x4] = 'h';
v[0x5] = 'a';
v[0x6] = 'm';
v[0x7] = '%';
v[0x8] = 'd';
v[0x9] = '\x7f';
v[0xa] = '"';
v[0xb] = 'L';
v[0xc] = 'f';
v[0xd] = '~';
v[0xe] = 'u';
v[0xf] = 'w';
v[0x10] = 'r';
v[0x11] = 'Q';
v[0x12] = 'p';
v[0x13] = 'l';
v[0x14] = '|';
v[0x15] = '|';
for (unsigned int i = 0; i < 0x16; ++i) {
v[i] ^= ((i + 0x16) % m);
}
v[0x16] = '\0';
}
static inline void fill_android_os_IInterface(char v[]) {
// android/os/IInterface
static unsigned int m = 0;
if (m == 0) {
m = 19;
} else if (m == 23) {
m = 29;
}
v[0x0] = 'c';
v[0x1] = 'm';
v[0x2] = '`';
v[0x3] = 'w';
v[0x4] = 'i';
v[0x5] = 'n';
v[0x6] = 'l';
v[0x7] = '&';
v[0x8] = 'e';
v[0x9] = 'x';
v[0xa] = '#';
v[0xb] = 'D';
v[0xc] = 'G';
v[0xd] = 'a';
v[0xe] = 'd';
v[0xf] = 't';
v[0x10] = '`';
v[0x11] = 'f';
v[0x12] = '`';
v[0x13] = 'a';
v[0x14] = 'f';
for (unsigned int i = 0; i < 0x15; ++i) {
v[i] ^= ((i + 0x15) % m);
}
v[0x15] = '\0';
}
static inline void fill_asBinder(char v[]) {
// asBinder
static unsigned int m = 0;
if (m == 0) {
m = 7;
} else if (m == 11) {
m = 13;
}
v[0x0] = '`';
v[0x1] = 'q';
v[0x2] = 'A';
v[0x3] = 'm';
v[0x4] = 'k';
v[0x5] = 'b';
v[0x6] = 'e';
v[0x7] = 's';
for (unsigned int i = 0; i < 0x8; ++i) {
v[i] ^= ((i + 0x8) % m);
}
v[0x8] = '\0';
}
static inline void fill_asBinder_signature(char v[]) {
// ()Landroid/os/IBinder;
static unsigned int m = 0;
if (m == 0) {
m = 19;
} else if (m == 23) {
m = 29;
}
v[0x0] = '+';
v[0x1] = '-';
v[0x2] = 'I';
v[0x3] = 'g';
v[0x4] = 'i';
v[0x5] = 'l';
v[0x6] = '{';
v[0x7] = 'e';
v[0x8] = 'b';
v[0x9] = 'h';
v[0xa] = '"';
v[0xb] = 'a';
v[0xc] = '|';
v[0xd] = '?';
v[0xe] = 'X';
v[0xf] = 'P';
v[0x10] = 'i';
v[0x11] = 'o';
v[0x12] = 'f';
v[0x13] = 'f';
v[0x14] = 'v';
v[0x15] = '>';
for (unsigned int i = 0; i < 0x16; ++i) {
v[i] ^= ((i + 0x16) % m);
}
v[0x16] = '\0';
}
static inline void fill_android_os_ServiceManager(char v[]) {
// android/os/ServiceManager
static unsigned int m = 0;
if (m == 0) {
m = 23;
} else if (m == 29) {
m = 31;
}
v[0x0] = 'c';
v[0x1] = 'm';
v[0x2] = '`';
v[0x3] = 'w';
v[0x4] = 'i';
v[0x5] = 'n';
v[0x6] = 'l';
v[0x7] = '&';
v[0x8] = 'e';
v[0x9] = 'x';
v[0xa] = '#';
v[0xb] = '^';
v[0xc] = 'k';
v[0xd] = '}';
v[0xe] = 'f';
v[0xf] = 'x';
v[0x10] = 'q';
v[0x11] = 'v';
v[0x12] = 'Y';
v[0x13] = 't';
v[0x14] = 'x';
v[0x15] = 'a';
v[0x16] = 'f';
v[0x17] = 'g';
v[0x18] = 'q';
for (unsigned int i = 0; i < 0x19; ++i) {
v[i] ^= ((i + 0x19) % m);
}
v[0x19] = '\0';
}
static inline void fill_getService_signature_IBinder(char v[]) {
// (Ljava/lang/String;)Landroid/os/IBinder;
static unsigned int m = 0;
if (m == 0) {
m = 37;
} else if (m == 41) {
m = 43;
}
v[0x0] = '+';
v[0x1] = 'H';
v[0x2] = 'o';
v[0x3] = 'g';
v[0x4] = 'q';
v[0x5] = 'i';
v[0x6] = '&';
v[0x7] = 'f';
v[0x8] = 'j';
v[0x9] = 'b';
v[0xa] = 'j';
v[0xb] = '!';
v[0xc] = '\\';
v[0xd] = 'd';
v[0xe] = 'c';
v[0xf] = '{';
v[0x10] = '}';
v[0x11] = 's';
v[0x12] = '.';
v[0x13] = '?';
v[0x14] = '[';
v[0x15] = 'y';
v[0x16] = 'w';
v[0x17] = '~';
v[0x18] = 'i';
v[0x19] = 's';
v[0x1a] = 't';
v[0x1b] = 'z';
v[0x1c] = '0';
v[0x1d] = 'O';
v[0x1e] = 'R';
v[0x1f] = '\r';
v[0x20] = 'j';
v[0x21] = 'f';
v[0x22] = 'i';
v[0x23] = 'o';
v[0x24] = 'f';
v[0x25] = 'f';
v[0x26] = 'v';
v[0x27] = '>';
for (unsigned int i = 0; i < 0x28; ++i) {
v[i] ^= ((i + 0x28) % m);
}
v[0x28] = '\0';
}
static inline void fill_activity(char v[]) {
// activity
static unsigned int m = 0;
if (m == 0) {
m = 7;
} else if (m == 11) {
m = 13;
}
v[0x0] = '`';
v[0x1] = 'a';
v[0x2] = 'w';
v[0x3] = 'm';
v[0x4] = 's';
v[0x5] = 'o';
v[0x6] = 't';
v[0x7] = 'x';
for (unsigned int i = 0; i < 0x8; ++i) {
v[i] ^= ((i + 0x8) % m);
}
v[0x8] = '\0';
}
static inline void fill_getName(char v[]) {
// getName
static unsigned int m = 0;
if (m == 0) {
m = 5;
} else if (m == 7) {
m = 11;
}
v[0x0] = 'e';
v[0x1] = 'f';
v[0x2] = 'p';
v[0x3] = 'N';
v[0x4] = '`';
v[0x5] = 'o';
v[0x6] = 'f';
for (unsigned int i = 0; i < 0x7; ++i) {
v[i] ^= ((i + 0x7) % m);
}
v[0x7] = '\0';
}
static inline void fill_getName_signature(char v[]) {
// ()Ljava/lang/String;
static unsigned int m = 0;
if (m == 0) {
m = 19;
} else if (m == 23) {
m = 29;
}
v[0x0] = ')';
v[0x1] = '+';
v[0x2] = 'O';
v[0x3] = 'n';
v[0x4] = 'd';
v[0x5] = 'p';
v[0x6] = 'f';
v[0x7] = '\'';
v[0x8] = 'e';
v[0x9] = 'k';
v[0xa] = 'e';
v[0xb] = 'k';
v[0xc] = '"';
v[0xd] = ']';
v[0xe] = '{';
v[0xf] = 'b';
v[0x10] = 'x';
v[0x11] = '|';
v[0x12] = 'g';
v[0x13] = ':';
for (unsigned int i = 0; i < 0x14; ++i) {
v[i] ^= ((i + 0x14) % m);
}
v[0x14] = '\0';
}
static inline void fill_activity_manager_service_is_s(char v[]) {
// activity manager service is %s
static unsigned int m = 0;
if (m == 0) {
m = 29;
} else if (m == 31) {
m = 37;
}
v[0x0] = '`';
v[0x1] = 'a';
v[0x2] = 'w';
v[0x3] = 'm';
v[0x4] = 's';
v[0x5] = 'o';
v[0x6] = 's';
v[0x7] = 'q';
v[0x8] = ')';
v[0x9] = 'g';
v[0xa] = 'j';
v[0xb] = 'b';
v[0xc] = 'l';
v[0xd] = 'i';
v[0xe] = 'j';
v[0xf] = 'b';
v[0x10] = '1';
v[0x11] = 'a';
v[0x12] = 'v';
v[0x13] = 'f';
v[0x14] = 'c';
v[0x15] = '\x7f';
v[0x16] = 't';
v[0x17] = '}';
v[0x18] = '9';
v[0x19] = 's';
v[0x1a] = 'h';
v[0x1b] = '<';
v[0x1c] = '%';
v[0x1d] = 'r';
for (unsigned int i = 0; i < 0x1e; ++i) {
v[i] ^= ((i + 0x1e) % m);
}
v[0x1e] = '\0';
}
static inline void showError(JNIEnv *env, jclass object) {
char v1[0x8], v2[0x1f];
if (object == NULL) {
fill_activity_manager_service_is_s(v2); // 0x1f
LOGE(v2, NULL);
} else {
fill_getName(v1); // 0x8
fill_getName_signature(v2); // 0x15
jclass clazz = (*env)->GetObjectClass(env, object);
jmethodID method = (*env)->GetMethodID(env, clazz, v1, v2);
jstring string = (*env)->CallObjectMethod(env, object, method);
const char *name = (*env)->GetStringUTFChars(env, string, NULL);
fill_activity_manager_service_is_s(v2); // 0x1f
LOGE(v2, name);
(*env)->ReleaseStringUTFChars(env, string, name);
(*env)->DeleteLocalRef(env, string);
(*env)->DeleteLocalRef(env, clazz);
}
}
bool isAmProxy(JNIEnv *env, int sdk) {
char v1[0xb], v2[0x29];
bool proxy = false;
jmethodID method;
jclass classActivityManager;
if (sdk >= 26) {
fill_android_app_ActivityManager(v2); // 0x1b + 1
classActivityManager = (*env)->FindClass(env, v2);
debug(env, "ActivityManager: %s", classActivityManager);
fill_getService(v1); // 0xa + 1
fill_getService_signature(v2); // 0x20 + 1
method = (*env)->GetStaticMethodID(env, classActivityManager, v1, v2);
#ifdef DEBUG
LOGI("ActivityManager.getService: %p", method);
#endif
if (method == NULL) {
#ifdef DEBUG
LOGW("cannot find ActivityManager.getService");
#endif
(*env)->ExceptionClear(env);
goto clean3;
}
} else {
fill_android_app_ActivityManagerNative(v2); // 0x21 + 1
classActivityManager = (*env)->FindClass(env, v2);
debug(env, "ActivityManagerNative: %s", classActivityManager);
fill_getDefault(v1); // 0xa + 1
fill_getDefault_signature(v2); // 0x20 + 1
method = (*env)->GetStaticMethodID(env, classActivityManager, v1, v2);
#ifdef DEBUG
LOGI("ActivityManagerNative.getDefault: %p", method);
#endif
}
jobject activityManager = (*env)->CallStaticObjectMethod(env, classActivityManager, method);
if (activityManager == NULL) {
#ifdef DEBUG
LOGW("activity manager is null");
#endif
if ((*env)->ExceptionCheck(env)) {
#ifdef DEBUG
(*env)->ExceptionDescribe(env);
#endif
(*env)->ExceptionClear(env);
}
goto clean3;
}
debug(env, "activity manager: %s", activityManager);
jclass binderClass = NULL;
jobject binder = NULL;
fill_android_os_BinderProxy(v2); // 0x16 + 1
jclass classBinderProxy = (*env)->FindClass(env, v2);
if (classBinderProxy == NULL) {
#ifdef DEBUG
LOGW("cannot find BinderProxy");
#endif
(*env)->ExceptionClear(env);
} else {
debug(env, "BinderProxy: %s", classBinderProxy);
}
fill_android_os_IInterface(v2); // 0x15 + 1
jclass classIInterface = (*env)->FindClass(env, v2);
debug(env, "IInterface: %s", classIInterface);
if (!(*env)->IsInstanceOf(env, activityManager, classIInterface)) {
#ifdef DEBUG
LOGW("activity manager is not IInterface");
#endif
goto clean2;
}
fill_asBinder(v1); // 0x8 + 1
fill_asBinder_signature(v2); // 0x16 + 1
method = (*env)->GetMethodID(env, classIInterface, v1, v2);
#ifdef DEBUG
LOGI("IInterface.asBinder: %p", method);
#endif
binder = (*env)->CallObjectMethod(env, activityManager, method);
if (binder == NULL) {
if ((*env)->ExceptionCheck(env)) {
#ifdef DEBUG
(*env)->ExceptionDescribe(env);
#endif
(*env)->ExceptionClear(env);
}
showError(env, NULL);
proxy = true;
goto clean2;
}
debug(env, "binder: %s", binder);
binderClass = (*env)->GetObjectClass(env, binder);
debug(env, "binder class: %s", binderClass);
if (classBinderProxy != NULL && !(*env)->IsSameObject(env, binderClass, classBinderProxy)) {
showError(env, binderClass);
proxy = true;
goto clean2;
}
fill_android_os_ServiceManager(v2); // 0x19 + 1
jclass classServiceManager = (*env)->FindClass(env, v2);
if (classServiceManager == NULL) {
#ifdef DEBUG
LOGW("cannot find ServiceManager");
#endif
(*env)->ExceptionClear(env);
goto clean2;
}
debug(env, "ServiceManager: %s", classServiceManager);
fill_getService(v1); // 0xa + 1
fill_getService_signature_IBinder(v2); // 0x28 + 1
method = (*env)->GetStaticMethodID(env, classServiceManager, v1, v2);
#ifdef DEBUG
LOGI("ServiceManager.getService: %p", method);
#endif
if (method == NULL) {
(*env)->ExceptionClear(env);
goto clean1;
}
fill_activity(v2); // 0x8 + 1
jstring stringActivity = (*env)->NewStringUTF(env, v2);
jobject service = (*env)->CallStaticObjectMethod(env, classServiceManager, method,
stringActivity);
jclass serviceClass = NULL;
if (service == NULL) {
if ((*env)->ExceptionCheck(env)) {
#ifdef DEBUG
(*env)->ExceptionDescribe(env);
#endif
(*env)->ExceptionClear(env);
}
showError(env, NULL);
proxy = true;
goto clean;
}
debug(env, "service: %s", service);
serviceClass = (*env)->GetObjectClass(env, service);
debug(env, "service class: %s", serviceClass);
if (classBinderProxy != NULL && !(*env)->IsSameObject(env, serviceClass, classBinderProxy)) {
showError(env, serviceClass);
proxy = true;
goto clean;
}
bool equals = (*env)->IsSameObject(env, binder, service);
#ifdef DEBUG
LOGI("binder: %p, service: %p, equals: %d", binder, service, equals);
#endif
proxy = !equals;
clean:
if (serviceClass != NULL) {
(*env)->DeleteLocalRef(env, serviceClass);
}
if (service != NULL) {
(*env)->DeleteLocalRef(env, service);
}
(*env)->DeleteLocalRef(env, stringActivity);
clean1:
(*env)->DeleteLocalRef(env, classServiceManager);
clean2:
if (binderClass != NULL) {
(*env)->DeleteLocalRef(env, binderClass);
}
if (binder != NULL) {
(*env)->DeleteLocalRef(env, binder);
}
if (classBinderProxy != NULL) {
(*env)->DeleteLocalRef(env, classBinderProxy);
}
(*env)->DeleteLocalRef(env, classIInterface);
(*env)->DeleteLocalRef(env, activityManager);
clean3:
(*env)->DeleteLocalRef(env, classActivityManager);
return proxy;
}
-21
View File
@@ -1,21 +0,0 @@
//
// Created by Thom on 2019/3/15.
//
#ifndef BREVENT_AM_PROXY_H
#define BREVENT_AM_PROXY_H
#include <jni.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
bool isAmProxy(JNIEnv *env, int sdk);
#ifdef __cplusplus
}
#endif
#endif //BREVENT_AM_PROXY_H
-169
View File
@@ -1,169 +0,0 @@
//
// Created by Thom on 2019/3/8.
//
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#ifdef MAIN
#include <stdio.h>
#else
#include "common.h"
#include "openat.h"
#endif
static bool isApkSigBlock42(const char *buffer) {
// APK Sig Block 42
return *buffer == 'A'
&& *++buffer == 'P'
&& *++buffer == 'K'
&& *++buffer == ' '
&& *++buffer == 'S'
&& *++buffer == 'i'
&& *++buffer == 'g'
&& *++buffer == ' '
&& *++buffer == 'B'
&& *++buffer == 'l'
&& *++buffer == 'o'
&& *++buffer == 'c'
&& *++buffer == 'k'
&& *++buffer == ' '
&& *++buffer == '4'
&& *++buffer == '2';
}
int checkSignature(const char *path) {
unsigned char buffer[0x11] = {0};
uint32_t size4;
uint64_t size8, size_of_block;
#ifdef DEBUG
LOGI("check signature for %s", path);
#endif
int sign = -1;
int fd = (int) openAt(AT_FDCWD, path, O_RDONLY);
#ifdef DEBUG_OPENAT
LOGI("openat %s returns %d", path, fd);
#endif
if (fd < 0) {
return sign;
}
sign = 1;
// https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD)
for (int i = 0;; ++i) {
unsigned short n;
lseek(fd, -i - 2, SEEK_END);
read(fd, &n, 2);
if (n == i) {
lseek(fd, -22, SEEK_CUR);
read(fd, &size4, 4);
if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
#ifdef MAIN
if (i > 0) {
printf("warning: comment length is %d\n", i);
}
#endif
break;
}
}
if (i == 0xffff) {
#ifdef MAIN
printf("error: cannot find eocd\n");
#endif
goto clean;
}
}
lseek(fd, 12, SEEK_CUR);
// offset
read(fd, &size4, 0x4);
lseek(fd, (off_t) (size4 - 0x18), SEEK_SET);
read(fd, &size8, 0x8);
read(fd, buffer, 0x10);
if (!isApkSigBlock42((char *) buffer)) {
goto clean;
}
lseek(fd, (off_t) (size4 - (size8 + 0x8)), SEEK_SET);
read(fd, &size_of_block, 0x8);
if (size_of_block != size8) {
goto clean;
}
for (;;) {
uint32_t id;
uint32_t offset;
read(fd, &size8, 0x8); // sequence length
if (size8 == size_of_block) {
break;
}
read(fd, &id, 0x4); // id
offset = 4;
#ifdef MAIN
printf("id: 0x%08x\n", id);
#endif
if ((id ^ 0xdeadbeefu) == 0xafa439f5u || (id ^ 0xdeadbeefu) == 0x2efed62f) {
read(fd, &size4, 0x4); // signer-sequence length
read(fd, &size4, 0x4); // signer length
read(fd, &size4, 0x4); // signed data length
offset += 0x4 * 3;
read(fd, &size4, 0x4); // digests-sequence length
lseek(fd, (off_t) (size4), SEEK_CUR);// skip digests
offset += 0x4 + size4;
read(fd, &size4, 0x4); // certificates length
read(fd, &size4, 0x4); // certificate length
offset += 0x4 * 2;
#ifdef MAIN
int hash = 1;
signed char c;
for (unsigned i = 0; i < size4; ++i) {
read(fd, &c, 0x1);
hash = 31 * hash + c;
}
offset += size4;
printf(" size: 0x%04x, hash: 0x%08x\n", size4, ((unsigned) hash) ^ 0x14131211u);
#else
#if defined(GENUINE_SIZE) && defined(GENUINE_HASH)
if (size4 == GENUINE_SIZE) {
int hash = 1;
signed char c;
for (unsigned i = 0; i < size4; ++i) {
read(fd, &c, 0x1);
hash = 31 * hash + c;
}
offset += size4;
if ((((unsigned) hash) ^ 0x14131211u) == GENUINE_HASH) {
sign = 0;
break;
}
}
#else
sign = 0;
break;
#endif
#endif
}
lseek(fd, (off_t) (size8 - offset), SEEK_CUR);
}
clean:
close(fd);
return sign;
}
#ifdef MAIN
int main(int argc, char **argv) {
if (argc > 1) {
checkSignature(argv[1]);
}
}
#endif
@@ -1,18 +0,0 @@
//
// Created by Thom on 2019/3/8.
//
#ifndef BREVENT_APK_SIGN_V2_H
#define BREVENT_APK_SIGN_V2_H
#ifdef __cplusplus
extern "C" {
#endif
int checkSignature(const char *path);
#ifdef __cplusplus
}
#endif
#endif //BREVENT_APK_SIGN_V2_H
-233
View File
@@ -1,233 +0,0 @@
//
// Created by Thom on 2019/3/20.
//
#include <jni.h>
#include <string.h>
#include <stdlib.h>
#include <sys/system_properties.h>
#include "common.h"
#include "plt.h"
static volatile int mGenuine;
static bool onCheckTrue(JNIEnv *env __unused) {
#ifdef DEBUG_NATIVE
has_native_libs();
#endif
#ifdef DEBUG_GENUINE_MOCK
start_native_activity_async(env);
#endif
return true;
}
static bool onCheckFalse(JNIEnv *env __unused) {
#if defined(GENUINE_FALSE_CRASH)
return false;
#elif defined(GENUINE_FALSE_NATIVE)
start_native_activity_async(env);
#endif
return true;
}
static bool onCheckFake(JNIEnv *env __unused) {
#if defined(GENUINE_FAKE_CRASH)
return false;
#elif defined(GENUINE_FAKE_NATIVE)
start_native_activity_async(env);
#endif
return true;
}
static bool onCheckOverlay(JNIEnv *env __unused) {
#if defined(GENUINE_OVERLAY_CRASH)
return false;
#elif defined(GENUINE_OVERLAY_NATIVE)
start_native_activity_async(env);
#endif
return true;
}
static bool onCheckOdex(JNIEnv *env __unused) {
#if defined(GENUINE_ODEX_CRASH)
return false;
#elif defined(GENUINE_ODEX_NATIVE)
start_native_activity_async(env);
#endif
return true;
}
static bool onCheckDex(JNIEnv *env __unused) {
#if defined(GENUINE_DEX_CRASH)
return false;
#elif defined(GENUINE_DEX_NATIVE)
start_native_activity_async(env);
#endif
return true;
}
static bool onCheckProxy(JNIEnv *env __unused) {
#if defined(GENUINE_PROXY_CRASH)
return false;
#elif defined(GENUINE_PROXY_NATIVE)
start_native_activity_async(env);
#endif
return true;
}
static bool onCheckError(JNIEnv *env __unused) {
#if defined(GENUINE_ERROR_CRASH)
return false;
#elif defined(GENUINE_ERROR_NATIVE)
start_native_activity_async(env);
#endif
return true;
}
static bool onCheckFatal(JNIEnv *env __unused) {
#if defined(GENUINE_FATAL_CRASH)
return false;
#elif defined(GENUINE_FATAL_NATIVE)
start_native_activity_async(env);
#endif
return true;
}
static bool onCheckNoapk(JNIEnv *env __unused) {
#if defined(GENUINE_NOAPK_CRASH)
return false;
#elif defined(GENUINE_NOAPK_NATIVE)
start_native_activity_async(env);
#endif
return true;
}
bool setGenuine(JNIEnv *env, int genuine) {
mGenuine = genuine;
switch (genuine) {
case CHECK_TRUE:
return onCheckTrue(env);
case CHECK_FALSE:
return onCheckFalse(env);
case CHECK_FAKE:
return onCheckFake(env);
case CHECK_OVERLAY:
return onCheckOverlay(env);
case CHECK_ODEX:
return onCheckOdex(env);
case CHECK_DEX:
return onCheckDex(env);
case CHECK_PROXY:
return onCheckProxy(env);
case CHECK_ERROR:
return onCheckError(env);
case CHECK_FATAL:
return onCheckFatal(env);
case CHECK_NOAPK:
return onCheckNoapk(env);
default:
return true;
}
}
int getGenuine() {
return mGenuine;
}
char *getGenuinePackageName() {
#ifdef GET_GENUINE_PACKAGE_NAME
return GET_GENUINE_PACKAGE_NAME();
#elif defined(GENUINE_NAME)
static unsigned int m = 0;
if (m == 0) {
m = 20;
} else if (m == 23) {
m = 29;
}
char name[] = GENUINE_NAME;
unsigned int length = sizeof(name) - 1;
for (unsigned int i = 0; i < length; ++i) {
name[i] ^= ((i + length) % m);
}
name[length] = '\0';
return strdup(name);
#else
return NULL;
#endif
}
__attribute__((__format__ (__printf__, 2, 0)))
void genuine_log_print(int prio, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
__android_log_vprint(prio, TAG, fmt, ap);
va_end(ap);
}
static inline void fill_ro_build_version_sdk(char v[]) {
// ro.build.version.sdk
static unsigned int m = 0;
if (m == 0) {
m = 19;
} else if (m == 23) {
m = 29;
}
v[0x0] = 's';
v[0x1] = 'm';
v[0x2] = '-';
v[0x3] = 'f';
v[0x4] = 'p';
v[0x5] = 'o';
v[0x6] = 'k';
v[0x7] = 'l';
v[0x8] = '\'';
v[0x9] = '|';
v[0xa] = 'n';
v[0xb] = '~';
v[0xc] = '~';
v[0xd] = 'g';
v[0xe] = '`';
v[0xf] = '~';
v[0x10] = '?';
v[0x11] = 'a';
v[0x12] = 'd';
v[0x13] = 'j';
for (unsigned int i = 0; i < 0x14; ++i) {
v[i] ^= ((i + 0x14) % m);
}
v[0x14] = '\0';
}
int getSdk() {
static int sdk = 0;
if (sdk == 0) {
char v1[0x20];
char prop[PROP_VALUE_MAX] = {0};
fill_ro_build_version_sdk(v1);
__system_property_get(v1, prop);
sdk = (int) strtol(prop, NULL, 10);
}
return sdk;
}
#ifdef DEBUG
void debug(JNIEnv *env, const char *format, jobject object) {
if (object == NULL) {
LOGI(format, NULL);
} else {
jclass objectClass = (*env)->FindClass(env, "java/lang/Object");
jmethodID toString = (*env)->GetMethodID(env, objectClass, "toString",
"()Ljava/lang/String;");
jstring string = (jstring) (*env)->CallObjectMethod(env, object, toString);
const char *value = (*env)->GetStringUTFChars(env, string, NULL);
LOGI(format, value);
(*env)->ReleaseStringUTFChars(env, string, value);
(*env)->DeleteLocalRef(env, string);
(*env)->DeleteLocalRef(env, objectClass);
}
}
#endif
-73
View File
@@ -1,73 +0,0 @@
//
// Created by Thom on 2019/3/20.
//
#ifndef BREVENT_COMMON_H
#define BREVENT_COMMON_H
#include <jni.h>
#include <stdbool.h>
#include <android/log.h>
#if __has_include("genuine.h")
#include "genuine.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
enum {
CHECK_TRUE,
CHECK_FALSE,
CHECK_FAKE,
CHECK_OVERLAY,
CHECK_ODEX,
CHECK_DEX,
CHECK_PROXY,
CHECK_ERROR,
CHECK_FATAL,
CHECK_NOAPK,
};
#ifndef TAG
#define TAG "Genuine"
#endif
#ifndef LOGI
#define LOGI(...) (genuine_log_print(ANDROID_LOG_INFO, __VA_ARGS__))
#endif
#ifndef LOGW
#define LOGW(...) (genuine_log_print(ANDROID_LOG_WARN, __VA_ARGS__))
#endif
#ifndef LOGE
#define LOGE(...) (genuine_log_print(ANDROID_LOG_ERROR, __VA_ARGS__))
#endif
void genuine_log_print(int prio, const char *fmt, ...);
char *getGenuinePackageName();
bool setGenuine(JNIEnv *env, int genuine);
int getGenuine();
int getSdk();
bool has_native_libs();
#ifdef DEBUG
void debug(JNIEnv *env, const char *format, jobject object);
#else
#define debug(...) do {} while(0);
#endif
#ifdef __cplusplus
}
#endif
#endif //BREVENT_COMMON_H
Loaded 100 of 114 files, more files were not shown because too many files have changed in this diff. Show more