diff --git a/cocos/kr2/Resources/res/locale/en_us.xml b/cocos/kr2/Resources/res/locale/en_us.xml
index 8f503357..655f23e0 100644
--- a/cocos/kr2/Resources/res/locale/en_us.xml
+++ b/cocos/kr2/Resources/res/locale/en_us.xml
@@ -50,9 +50,12 @@
+
+
+
@@ -67,9 +70,10 @@
-
-
+
+
+
@@ -78,6 +82,7 @@
+
@@ -104,5 +109,14 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cocos/kr2/Resources/res/locale/ja_jp.xml b/cocos/kr2/Resources/res/locale/ja_jp.xml
index d6abfbd8..b0b2468c 100644
--- a/cocos/kr2/Resources/res/locale/ja_jp.xml
+++ b/cocos/kr2/Resources/res/locale/ja_jp.xml
@@ -50,9 +50,12 @@
+
+
+
@@ -65,9 +68,10 @@
-
-
+
+
+
@@ -75,6 +79,7 @@
+
@@ -100,6 +105,15 @@
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cocos/kr2/Resources/res/locale/zh_cn.xml b/cocos/kr2/Resources/res/locale/zh_cn.xml
index c04ae8f8..200819d7 100644
--- a/cocos/kr2/Resources/res/locale/zh_cn.xml
+++ b/cocos/kr2/Resources/res/locale/zh_cn.xml
@@ -50,9 +50,12 @@
+
+
+
@@ -69,6 +72,7 @@
+
@@ -78,6 +82,7 @@
+
@@ -104,5 +109,14 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cocos/kr2/Resources/res/locale/zh_tw.xml b/cocos/kr2/Resources/res/locale/zh_tw.xml
index fe2ea9ee..d2a1f07c 100644
--- a/cocos/kr2/Resources/res/locale/zh_tw.xml
+++ b/cocos/kr2/Resources/res/locale/zh_tw.xml
@@ -50,9 +50,12 @@
+
+
+
@@ -69,7 +72,8 @@
-
+
+
@@ -78,6 +82,7 @@
+
@@ -104,5 +109,14 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cocos/kr2/cocosstudio/ui/CheckListDialog.csd b/cocos/kr2/cocosstudio/ui/CheckListDialog.csd
new file mode 100644
index 00000000..ea324f2d
--- /dev/null
+++ b/cocos/kr2/cocosstudio/ui/CheckListDialog.csd
@@ -0,0 +1,186 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cocos/kr2/cocosstudio/ui/FileManageMenu.csd b/cocos/kr2/cocosstudio/ui/FileManageMenu.csd
new file mode 100644
index 00000000..d9d98bcf
--- /dev/null
+++ b/cocos/kr2/cocosstudio/ui/FileManageMenu.csd
@@ -0,0 +1,1193 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cocos/kr2/cocosstudio/ui/MenuList.csd b/cocos/kr2/cocosstudio/ui/MenuList.csd
index 3d5c678b..80ec9eaf 100644
--- a/cocos/kr2/cocosstudio/ui/MenuList.csd
+++ b/cocos/kr2/cocosstudio/ui/MenuList.csd
@@ -73,7 +73,7 @@
-
+
@@ -115,17 +115,17 @@
-
+
-
-
+
+
-
+
@@ -179,17 +179,17 @@
-
+
-
-
+
+
-
+
@@ -243,17 +243,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
@@ -298,14 +407,14 @@
-
-
+
+
-
+
@@ -350,14 +459,14 @@
-
-
+
+
-
+
@@ -403,7 +512,7 @@
-
+
diff --git a/cocos/kr2/cocosstudio/ui/MessageBox.csd b/cocos/kr2/cocosstudio/ui/MessageBox.csd
index b14f7f13..879a5047 100644
--- a/cocos/kr2/cocosstudio/ui/MessageBox.csd
+++ b/cocos/kr2/cocosstudio/ui/MessageBox.csd
@@ -1,5 +1,5 @@
-
+
diff --git a/cocos/kr2/cocosstudio/ui/ProgressBox.csd b/cocos/kr2/cocosstudio/ui/ProgressBox.csd
new file mode 100644
index 00000000..9b864b14
--- /dev/null
+++ b/cocos/kr2/cocosstudio/ui/ProgressBox.csd
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cocos/kr2/cocosstudio/ui/comctrl/SliderIconItem.csd b/cocos/kr2/cocosstudio/ui/comctrl/SliderIconItem.csd
index 9d7d9374..13e30eda 100644
--- a/cocos/kr2/cocosstudio/ui/comctrl/SliderIconItem.csd
+++ b/cocos/kr2/cocosstudio/ui/comctrl/SliderIconItem.csd
@@ -4,33 +4,33 @@
-
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
-
+
+
@@ -44,29 +44,29 @@
-
+
-
+
-
+
-
+
-
+
-
-
+
+
diff --git a/cocos/kr2/kr2.ccs b/cocos/kr2/kr2.ccs
index 44b5fa31..9b379e60 100644
--- a/cocos/kr2/kr2.ccs
+++ b/cocos/kr2/kr2.ccs
@@ -57,6 +57,7 @@
+
@@ -70,6 +71,7 @@
+
diff --git a/project/android/AndroidManifest.xml b/project/android/AndroidManifest.xml
index 30c815b2..e3dc35ae 100644
--- a/project/android/AndroidManifest.xml
+++ b/project/android/AndroidManifest.xml
@@ -4,8 +4,8 @@
-->
@@ -22,6 +22,8 @@
+
=Build.VERSION_CODES.LOLLIPOP) {
for(String path : getExtSdCardPaths(this)) {
if (!isWritableNormalOrSaf(path)) {
@@ -304,7 +304,7 @@ public void onCreate(Bundle savedInstanceState) {
}
}
}
-
+ */
initDump(this.getFilesDir().getAbsolutePath() + "/dump");
}
@@ -314,6 +314,11 @@ public void onDestroy() {
System.exit(0);
}
+ @Override
+ public void onLowMemory() {
+ nativeOnLowMemory();
+ }
+
static class DialogMessage
{
public String Title;
@@ -494,6 +499,7 @@ public void run() {
static public native void onNativeInit();
static public native void onBannerSizeChanged(int w, int h);
static private native void initDump(String path);
+ static private native void nativeOnLowMemory();
static public void MessageController(int what, int arg1, int arg2) {
Message msg = msgHandler.obtainMessage();
@@ -749,10 +755,18 @@ public Cocos2dxGLSurfaceView onCreateView() {
public int get_res_sd_operate_step() { return -1; }
- void guideDialogForLEXA(String path) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- ImageView image = new ImageView(this);
- image.setImageResource(get_res_sd_operate_step());
+ static void requireLEXA(final String path) {
+ msgHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ guideDialogForLEXA(path);
+ }
+ });
+ }
+ static void guideDialogForLEXA(final String path) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(sInstance);
+ ImageView image = new ImageView(sInstance);
+ image.setImageResource(sInstance.get_res_sd_operate_step());
builder
.setView(image)
.setTitle(path)
diff --git a/src/core/Android.mk b/src/core/Android.mk
index 107f84fc..f1191296 100644
--- a/src/core/Android.mk
+++ b/src/core/Android.mk
@@ -4,15 +4,13 @@ include $(CLEAR_VARS)
LOCAL_MODULE := krkr2
-ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
-ThreadPool11FILE :=
-else
-ThreadPool11FILE := utils/threadpool11/pool.cpp utils/threadpool11/worker.cpp
-endif
-
LOCAL_SRC_FILES := \
$(filter-out $(LOCAL_PATH)/visual/Resampler.cpp, $(wildcard $(LOCAL_PATH)/visual/*.cpp)) \
$(wildcard $(LOCAL_PATH)/base/7zip/*.c) \
+$(wildcard $(LOCAL_PATH)/base/7zip/C/*.c) \
+$(wildcard $(LOCAL_PATH)/base/7zip/CPP/*/*.cpp) \
+$(wildcard $(LOCAL_PATH)/base/7zip/CPP/*/*/*.cpp) \
+$(wildcard $(LOCAL_PATH)/base/7zip/CPP/*/*/*/*.cpp) \
$(wildcard $(LOCAL_PATH)/base/*.cpp) \
$(filter-out $(LOCAL_PATH)/base/win32/FuncStubs.cpp $(LOCAL_PATH)/base/win32/SusieArchive.cpp, $(wildcard $(LOCAL_PATH)/base/win32/*.cpp)) \
$(filter-out $(LOCAL_PATH)/environ/MainFormUnit.cpp, $(wildcard $(LOCAL_PATH)/environ/*.cpp)) \
@@ -37,7 +35,6 @@ $(wildcard $(LOCAL_PATH)/utils/encoding/*.c) \
$(wildcard $(LOCAL_PATH)/utils/minizip/*.c) \
$(wildcard $(LOCAL_PATH)/utils/minizip/*.cpp) \
$(wildcard $(LOCAL_PATH)/utils/win32/*.cpp) \
-$(ThreadPool11FILE) \
$(wildcard $(LOCAL_PATH)/visual/gl/*.cpp) \
$(wildcard $(LOCAL_PATH)/visual/ogl/*.cpp) \
$(filter-out $(LOCAL_PATH)/visual/win32/GDIFontRasterizer.cpp $(LOCAL_PATH)/visual/win32/NativeFreeTypeFace.cpp \
@@ -80,6 +77,7 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/base \
$(LOCAL_PATH)/../../vendor/threadpool11/ext/include \
$(LOCAL_PATH)/../../libs/android/bpg/include \
$(LOCAL_PATH)/../../libs/android/ffmpeg/include \
+ $(LOCAL_PATH)/../../libs/android/libarchive/include \
$(LOCAL_PATH)/visual/RenderScript/rs \
$(LOCAL_PATH)/../../vendor/cocos2d-x/current/cocos \
$(LOCAL_PATH)/../../vendor/cocos2d-x/current/cocos/platform \
@@ -89,10 +87,10 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/base \
$(LOCAL_PATH)/../../vendor/cocos2d-x/current/external \
LOCAL_CPPFLAGS += -DTJS_TEXT_OUT_CRLF -D__STDC_CONSTANT_MACROS
-LOCAL_CFLAGS += -DTJS_TEXT_OUT_CRLF
+LOCAL_CFLAGS += -DTJS_TEXT_OUT_CRLF -D_7ZIP_ST
LOCAL_STATIC_LIBRARIES := ffmpeg libopencv_imgproc libopencv_core libopencv_hal libtbb gdiplus_static cpufeatures \
opusfile_static opus_static onig_static libbpg_static vorbis_static cairo_static pixman_static expat_static \
- breakpad_client openal_static jxrlib_static
+ breakpad_client openal_static jxrlib_static libarchive_static
# libRScpp_static
include $(BUILD_STATIC_LIBRARY)
@@ -112,4 +110,5 @@ $(call import-module, pixman)
$(call import-module, gdiplus)
$(call import-module, expat)
$(call import-module, google_breakpad)
-#$(call import-module, libRScpp)
\ No newline at end of file
+#$(call import-module, libRScpp)
+$(call import-module, libarchive)
\ No newline at end of file
diff --git a/src/core/base/7zArchive.cpp b/src/core/base/7zArchive.cpp
index b49d7da1..345e97f0 100644
--- a/src/core/base/7zArchive.cpp
+++ b/src/core/base/7zArchive.cpp
@@ -7,22 +7,36 @@ extern "C" {
#include "7zip/C/7zFile.h"
#include "7zip/C/7zCrc.h"
}
+#include "StorageImpl.h"
static ISzAlloc allocImp = {
[](void *p, size_t size) -> void *{ return malloc(size); },
[](void *p, void *addr) { free(addr); }
};
-class SevenZipArchive : public tTVPArchive {
+class SevenZipStreamWrap {
+public:
CSzArEx db;
tTJSBinaryStream *_stream;
+ CLookToRead lookStream;
struct CSeekInStream : public ISeekInStream {
- SevenZipArchive *Host;
+ SevenZipStreamWrap *Host;
} archiveStream;
- CLookToRead lookStream;
-
- std::vector > filelist;
+public:
+ SevenZipStreamWrap(tTJSBinaryStream * st) : _stream(st) {
+ archiveStream.Host = this;
+ archiveStream.Read = [](void *p, void *buf, size_t *size)->SRes {return ((CSeekInStream*)p)->Host->StreamRead(buf, size); };
+ archiveStream.Seek = [](void *p, Int64 *pos, ESzSeek origin)->SRes {return ((CSeekInStream*)p)->Host->StreamSeek(pos, origin); };
+ LookToRead_CreateVTable(&lookStream, false);
+ lookStream.realStream = &archiveStream;
+ SzArEx_Init(&db);
+ if (!g_CrcTable[1]) CrcGenerateTable();
+ }
+ ~SevenZipStreamWrap() {
+ SzArEx_Free(&db, &allocImp);
+ delete _stream;
+ }
SRes StreamRead(void *buf, size_t *size) {
*size = _stream->Read(buf, *size);
return SZ_OK;
@@ -39,22 +53,16 @@ class SevenZipArchive : public tTVPArchive {
*pos = _stream->Seek(*pos, whence);
return SZ_OK;
}
+};
+
+class SevenZipArchive : public tTVPArchive, public SevenZipStreamWrap {
+ std::vector > filelist;
public:
- SevenZipArchive(const ttstr & name, tTJSBinaryStream *st) : tTVPArchive(name), _stream(st) {
- archiveStream.Host = this;
- archiveStream.Read = [](void *p, void *buf, size_t *size)->SRes{return ((CSeekInStream*)p)->Host->StreamRead(buf, size); };
- archiveStream.Seek = [](void *p, Int64 *pos, ESzSeek origin)->SRes{return ((CSeekInStream*)p)->Host->StreamSeek(pos, origin); };
- LookToRead_CreateVTable(&lookStream, false);
- lookStream.realStream = &archiveStream;
- SzArEx_Init(&db);
- if(!g_CrcTable[1]) CrcGenerateTable();
+ SevenZipArchive(const ttstr & name, tTJSBinaryStream *st) : tTVPArchive(name), SevenZipStreamWrap(st) {
}
- virtual ~SevenZipArchive() {
- SzArEx_Free(&db, &allocImp);
- delete _stream;
- }
+ virtual ~SevenZipArchive() { }
virtual tjs_uint GetCount() { return filelist.size(); }
virtual ttstr GetName(tjs_uint idx) { return filelist[idx].first; }
@@ -103,9 +111,12 @@ class SevenZipArchive : public tTVPArchive {
return mem;
}
- bool Open() {
+ bool Open(bool normalizeFileName) {
SRes res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocImp);
- if (res != SZ_OK) return false;
+ if (res != SZ_OK) {
+ _stream = nullptr;
+ return false;
+ }
for (int i = 0; i < db.NumFiles; i++) {
size_t offset = 0;
size_t outSizeProcessed = 0;
@@ -115,25 +126,102 @@ class SevenZipArchive : public tTVPArchive {
ttstr filename;
SzArEx_GetFileNameUtf16(&db, i, (UInt16*)filename.AllocBuffer(len));
filename.FixLen();
- NormalizeInArchiveStorageName(filename);
+ if (normalizeFileName)
+ NormalizeInArchiveStorageName(filename);
filelist.emplace_back(filename, i);
}
- std::sort(filelist.begin(), filelist.end(), [](const std::pair& a, const std::pair& b){
- return a.first < b.first;
- });
+ if (normalizeFileName) {
+ std::sort(filelist.begin(), filelist.end(), [](const std::pair& a, const std::pair& b) {
+ return a.first < b.first;
+ });
+ }
return true;
}
};
-tTVPArchive * TVPOpen7ZArchive(const ttstr & name, tTJSBinaryStream *st) {
+tTVPArchive * TVPOpen7ZArchive(const ttstr & name, tTJSBinaryStream *st, bool normalizeFileName) {
tjs_uint64 pos = st->GetPosition();
bool checkZIP = st->ReadI16LE() == 0x7A37; // '7z'
st->SetPosition(pos);
if (!checkZIP) return nullptr;
SevenZipArchive *arc = new SevenZipArchive(name, st);
- if (!arc->Open()) {
+ if (!arc->Open(normalizeFileName)) {
delete arc;
return nullptr;
}
return arc;
-}
\ No newline at end of file
+}
+
+#if 0
+void TVPUnpack7ZArchive(tTJSBinaryStream *st, ttstr outpath) {
+ tjs_uint64 origpos = st->GetPosition();
+ SevenZipStreamWrap szsw(st);
+ CSzArEx &db = szsw.db;
+ SRes res = SzArEx_Open(&db, &szsw.lookStream.s, &allocImp, &allocImp);
+ if (res != SZ_OK) return;
+ outpath += TJS_W("/");
+ for (int i = 0; i < db.db.NumFolders; ++i) {
+ ;
+ }
+ for (int i = 0; i < db.NumFiles; i++) {
+ size_t offset = 0;
+ size_t outSizeProcessed = 0;
+ size_t len = SzArEx_GetFileNameUtf16(&db, i, NULL);
+ ttstr filename;
+ SzArEx_GetFileNameUtf16(&db, i, (UInt16*)filename.AllocBuffer(len));
+ filename.FixLen();
+ bool isDir = SzArEx_IsDir(&db, i);
+ ttstr fullpath = outpath + filename;
+ if (isDir) {
+ if (!TVPCheckExistentLocalFolder(fullpath))
+ TVPCreateFolders(fullpath);
+ } else {
+ tjs_uint fileIndex = i;
+ UInt64 fileSize = SzArEx_GetFileSize(&db, fileIndex);
+ if (fileSize <= 0) {
+ FILE *fp = fopen(fullpath.AsStdString().c_str(), "wb");
+ fclose(fp);
+ }
+
+ UInt32 folderIndex = db.FileToFolder[fileIndex];
+ if (folderIndex == (UInt32)-1) continue;
+
+ const CSzAr *p = &db.db;
+ CSzFolder folder;
+ CSzData sd;
+ const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
+ sd.Data = data;
+ sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex];
+
+ if (SzGetNextFolderItem(&folder, &sd) != SZ_OK) continue;
+ if (folder.NumCoders == 1) {
+ UInt64 startPos = db.dataPos;
+ const UInt64 *packPositions = p->PackPositions + p->FoStartPackStreamIndex[folderIndex];
+ UInt64 offset = packPositions[0];
+ UInt64 inSize = packPositions[1] - offset;
+ if (folder.Coders[0].MethodID == k_Copy && inSize == fileSize) {
+ CopyStreamToFile(st, origpos + startPos + offset, inSize, fullpath);
+ continue;
+ }
+ }
+
+ UInt32 blockIndex;
+ Byte *outBuffer = nullptr;
+ size_t outBufferSize;
+ size_t offset, outSizeProcessed;
+ SRes res = SzArEx_Extract(&db, &szsw.lookStream.s, fileIndex, &blockIndex, &outBuffer, &outBufferSize,
+ &offset, &outSizeProcessed, &allocImp, &allocImp);
+ tTVPMemoryStream *mem;
+ if (offset == 0 && fileSize <= outBufferSize) {
+ mem = new tTVPMemoryStream(outBuffer, outBufferSize);
+ } else {
+ Byte *buf = new Byte[fileSize];
+ memcpy(buf, outBuffer, fileSize);
+ mem = new tTVPMemoryStream(buf, fileSize);
+ delete outBuffer;
+ }
+ return mem;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/core/base/StorageIntf.cpp b/src/core/base/StorageIntf.cpp
index 60637c87..9fd96fa7 100644
--- a/src/core/base/StorageIntf.cpp
+++ b/src/core/base/StorageIntf.cpp
@@ -775,7 +775,7 @@ class tTVPArchiveCache
}
// not exist in the cache
- tTVPArchive *arc = TVPOpenArchive(name);
+ tTVPArchive *arc = TVPOpenArchive(name, true);
tHolder holder(arc);
ArchiveCache.AddWithHash(name, hash, holder);
return arc;
diff --git a/src/core/base/StorageIntf.h b/src/core/base/StorageIntf.h
index 329d8948..a1679881 100644
--- a/src/core/base/StorageIntf.h
+++ b/src/core/base/StorageIntf.h
@@ -63,6 +63,7 @@ class tTVPArchive
tTJSHashTable, 1024> Hash;
bool Init;
+
public:
ttstr ArchiveName;
@@ -151,7 +152,7 @@ class iTVPStorageMedia
//---------------------------------------------------------------------------
// must be implemented in each platform
//---------------------------------------------------------------------------
-extern tTVPArchive * TVPOpenArchive(const ttstr & name);
+extern tTVPArchive * TVPOpenArchive(const ttstr & name, bool normalizeFileName);
// open archive and return tTVPArchive instance.
TJS_EXP_FUNC_DEF(ttstr, TVPGetTemporaryName, ());
@@ -341,12 +342,12 @@ class TArchiveStream : public tTJSBinaryStream {
break;
}
if (CurrentPos < 0) CurrentPos = 0;
- else if (CurrentPos > DataLength) CurrentPos = DataLength;
+ else if (CurrentPos > (tjs_int64)DataLength) CurrentPos = DataLength;
_instr->SetPosition(CurrentPos + StartPos);
return CurrentPos;
}
virtual tjs_uint TJS_INTF_METHOD Read(void *buffer, tjs_uint read_size) {
- if (CurrentPos + read_size >= DataLength) {
+ if (CurrentPos + read_size >= (tjs_int64)DataLength) {
read_size = (tjs_uint)(DataLength - CurrentPos);
}
diff --git a/src/core/base/TARArchive.cpp b/src/core/base/TARArchive.cpp
index da61acb3..c3e2cc20 100644
--- a/src/core/base/TARArchive.cpp
+++ b/src/core/base/TARArchive.cpp
@@ -51,7 +51,7 @@ class TARArchive : public tTVPArchive {
~TARArchive() {
TVPFreeArchiveHandlePoolByPointer(this);
}
- bool init(tTJSBinaryStream * _instr) {
+ bool init(tTJSBinaryStream * _instr, bool normalizeFileName) {
if (_instr) {
tjs_uint64 archiveSize = _instr->GetSize();
TAR_HEADER tar_header;
@@ -86,16 +86,19 @@ class TARArchive : public tTVPArchive {
}
EntryInfo item;
storeFilename(item.filename, &filename[0], ArchiveName);
- NormalizeInArchiveStorageName(item.filename);
+ if (normalizeFileName)
+ NormalizeInArchiveStorageName(item.filename);
item.size = original_size;
item.offset = _instr->GetPosition();
filelist.emplace_back(item);
tjs_uint64 readsize = (original_size + (TBLOCK - 1)) & ~(TBLOCK - 1);
_instr->SetPosition(item.offset + readsize);
}
- std::sort(filelist.begin(), filelist.end(), [](const EntryInfo& a, const EntryInfo& b){
- return a.filename < b.filename;
- });
+ if (normalizeFileName) {
+ std::sort(filelist.begin(), filelist.end(), [](const EntryInfo& a, const EntryInfo& b) {
+ return a.filename < b.filename;
+ });
+ }
TVPReleaseCachedArchiveHandle(this, _instr);
return true;
}
@@ -111,9 +114,9 @@ tTJSBinaryStream * TARArchive::CreateStreamByIndex(tjs_uint idx) {
return new TArchiveStream(this, info.offset, info.size);
}
-tTVPArchive * TVPOpenTARArchive(const ttstr & name, tTJSBinaryStream * st) {
+tTVPArchive * TVPOpenTARArchive(const ttstr & name, tTJSBinaryStream * st, bool normalizeFileName) {
TARArchive *arc = new TARArchive(name);
- if (!arc->init(st)) {
+ if (!arc->init(st, normalizeFileName)) {
delete arc;
return nullptr;
}
diff --git a/src/core/base/UtilStreams.cpp b/src/core/base/UtilStreams.cpp
index cac3ac7d..d98b134f 100644
--- a/src/core/base/UtilStreams.cpp
+++ b/src/core/base/UtilStreams.cpp
@@ -15,9 +15,10 @@
#include "DebugIntf.h"
#include "EventIntf.h"
#include "StorageIntf.h"
-
-
-
+#include
+#include
+#include
+#include "Platform.h"
@@ -368,3 +369,350 @@ tjs_uint64 TJS_INTF_METHOD tTVPPartialStream::GetSize()
//---------------------------------------------------------------------------
+
+extern "C" {
+#include "libarchive/archive.h"
+#include "libarchive/archive_entry.h"
+}
+#if 0
+class LibArchive_Archive : public tTVPArchive {
+ struct archive *_arc;
+ tTJSBinaryStream *_stream;
+ static const int BUFFER_SIZE = 16 * 1024;
+ tjs_uint8 *_buffer = new tjs_uint8[BUFFER_SIZE];
+ std::vector > _filelist;
+
+ void Clear() {
+ if (_arc) {
+ archive_read_free(_arc);
+ _arc = nullptr;
+ }
+ for (std::pair &it : _filelist) {
+ archive_entry_free(it.second);
+ }
+ _filelist.clear();
+ }
+
+public:
+ LibArchive_Archive(const ttstr & name, tTJSBinaryStream *st) : tTVPArchive(name), _stream(st) {
+ _arc = archive_read_new();
+ }
+ ~LibArchive_Archive() {
+ Clear();
+ if (_stream)
+ delete _stream;
+ if (_buffer)
+ delete[] _buffer;
+ }
+
+ virtual tjs_uint GetCount() { return _filelist.size(); }
+ virtual ttstr GetName(tjs_uint idx) { return _filelist[idx].first; }
+ virtual tTJSBinaryStream * CreateStreamByIndex(tjs_uint idx) {
+ struct archive_entry * entry = _filelist[idx].second;
+ tjs_uint64 fileSize = archive_entry_size(entry);
+ if (fileSize <= 0) return new tTVPMemoryStream();
+ return nullptr;
+ }
+
+ bool Open(bool normalizeFileName) {
+ archive_read_support_filter_all(_arc);
+ archive_read_support_format_all(_arc);
+ archive_read_set_seek_callback(_arc, seek_callback);
+ archive_read_open2(_arc, this, nullptr, read_callback, nullptr, nullptr);
+
+ struct archive_entry *entry = archive_entry_new2(_arc);
+ while (archive_read_next_header2(_arc, entry) == ARCHIVE_OK) {
+ ttstr filename(archive_entry_pathname_utf8(entry));
+ if (normalizeFileName)
+ NormalizeInArchiveStorageName(filename);
+ _filelist.emplace_back(filename, entry);
+ entry = archive_entry_new2(_arc);
+ }
+ archive_entry_free(entry);
+ if (normalizeFileName) {
+ std::sort(_filelist.begin(), _filelist.end(), [](const std::pair& a, const std::pair& b) {
+ return a.first < b.first;
+ });
+ }
+ }
+
+ void Detach() {
+ Clear();
+ _stream = nullptr;
+ }
+
+ static la_ssize_t read_callback(struct archive *, void *_client_data, const void **_buffer) {
+ LibArchive_Archive *_this = (LibArchive_Archive *)_client_data;
+ *_buffer = _this->_buffer;
+ return _this->_stream->Read(_this->_buffer, BUFFER_SIZE);
+ }
+
+ static la_int64_t seek_callback(struct archive *, void *_client_data, la_int64_t offset, int whence) {
+ LibArchive_Archive *_this = (LibArchive_Archive *)_client_data;
+ return _this->_stream->Seek(offset, whence);
+ }
+
+ static la_int64_t skip_callback(struct archive *, void *_client_data, la_int64_t request) {
+ LibArchive_Archive *_this = (LibArchive_Archive *)_client_data;
+ return _this->_stream->Seek(request, TJS_BS_SEEK_CUR);
+ }
+};
+
+tTVPArchive *TVPOpenLibArchive(const ttstr & name, tTJSBinaryStream *st, bool normalizeFileName) {
+ LibArchive_Archive *arc = new LibArchive_Archive(name, st);
+ if (arc->Open(normalizeFileName)) {
+ return arc;
+ }
+ arc->Detach();
+ delete arc;
+ return nullptr;
+}
+#endif
+
+static FILE *_fileopen(ttstr path) {
+ std::string strpath = path.AsStdString();
+ FILE *fp = fopen(strpath.c_str(), "wb");
+ if (!fp) { // make dirs
+ path = TVPExtractStoragePath(path);
+ TVPCreateFolders(path);
+ fp = fopen(strpath.c_str(), "wb");
+ }
+ return fp;
+}
+
+class tTVPUnpackArchiveImpl {
+ std::thread *ThreadObj;
+ std::mutex Mutex;
+ std::condition_variable Cond;
+ tTVPUnpackArchive *Owner;
+
+ void Entry() {
+ {
+ std::unique_lock lk(Mutex);
+ Cond.wait(lk);
+ }
+ Owner->Process();
+ }
+
+public:
+ tTVPUnpackArchiveImpl(tTVPUnpackArchive *owner) : Owner(owner) {
+ ThreadObj = new std::thread(&tTVPUnpackArchiveImpl::Entry, this);
+ }
+
+ ~tTVPUnpackArchiveImpl() {
+ if (ThreadObj->joinable()) {
+ ThreadObj->join();
+ }
+ delete ThreadObj;
+ }
+
+ void Start() {
+ Cond.notify_all();
+ }
+};
+
+int tTVPUnpackArchive::Prepare(const std::string &path, const std::string &_outpath, tjs_uint64 *totalSize) {
+ FpIn = fopen(path.c_str(), "rb");
+ if (!FpIn) return -1;
+ OutPath = _outpath + "/";
+ int file_count = 0;
+ tjs_uint64 size_count = 0;
+ ArcObj = archive_read_new();
+ archive_read_support_filter_all(ArcObj);
+ archive_read_support_format_all(ArcObj);
+ int r = archive_read_open_FILE(ArcObj, FpIn);
+ if (r < ARCHIVE_OK) {
+ fclose(FpIn);
+ FpIn = nullptr;
+ archive_read_free(ArcObj);
+ ArcObj = nullptr;
+ // try TVPArchive
+ pTVPArc = TVPOpenArchive(path, false);
+ if (pTVPArc) {
+ file_count = pTVPArc->GetCount();
+ *totalSize = 0;
+ for (int i = 0; i < file_count; ++i) {
+ tTJSBinaryStream *str = pTVPArc->CreateStreamByIndex(i);
+ if (str) {
+ *totalSize += str->GetSize();
+ delete str;
+ }
+ }
+ if (file_count) {
+ Impl = new tTVPUnpackArchiveImpl(this);
+ }
+ return file_count;
+ }
+ return -1;
+ }
+ r = 0;
+ while (true) {
+ struct archive_entry *entry;
+ int r = archive_read_next_header(ArcObj, &entry);
+ if (r == ARCHIVE_EOF) {
+ r = ARCHIVE_OK;
+ break;
+ }
+ if (r < ARCHIVE_OK)
+ OnError(r, archive_error_string(ArcObj));
+ if (r < ARCHIVE_WARN)
+ break;
+ ++file_count;
+ size_count += archive_entry_size(entry);
+ }
+
+ if (totalSize) *totalSize = size_count;
+ archive_read_close(ArcObj);
+ archive_read_free(ArcObj);
+ ArcObj = nullptr;
+ if (file_count) {
+ Impl = new tTVPUnpackArchiveImpl(this);
+ }
+ return file_count;
+}
+
+void tTVPUnpackArchive::Start()
+{
+ StopRequired = false;
+ Impl->Start();
+}
+
+void tTVPUnpackArchive::Stop()
+{
+ StopRequired = true;
+ Impl->Start();
+}
+
+void tTVPUnpackArchive::Process()
+{
+ if (StopRequired)
+ return;
+
+ tjs_uint64 total_size = 0;
+ if (pTVPArc) {
+ int file_count = pTVPArc->GetCount();
+ std::vector buffer; buffer.resize(4 * 1024 * 1024);
+ for (int index = 0; index < file_count && !StopRequired; ++index) {
+ tjs_uint64 file_size = 0;
+ std::string filename = pTVPArc->GetName(index).AsStdString();
+ if (filename.size() > 600) continue;
+ std::string fullpath = OutPath + filename;
+ FILE *fp = _fileopen(fullpath);
+ if (!fp) {
+ OnError(ARCHIVE_FAILED, "Cannot open output file");
+ break;
+ }
+ tTJSBinaryStream *str = pTVPArc->CreateStreamByIndex(index);
+ if (!str) {
+ OnError(ARCHIVE_FAILED, "Cannot open archive stream");
+ fclose(fp);
+ break;
+ }
+ OnNewFile(index, filename.c_str(), str->GetSize());
+ while (!StopRequired) {
+ tjs_uint readed = str->Read(&buffer.front(), buffer.size());
+ if (readed == 0) break;
+ if (readed != fwrite(&buffer.front(), 1, readed, fp)) {
+ OnError(ARCHIVE_FAILED, "Fail to write file.\nPlease check the disk space.");
+ break;
+ }
+ file_size += readed;
+ total_size += readed;
+ OnProgress(total_size, file_size);
+ if (readed < buffer.size())
+ break;
+ }
+ delete str;
+ fclose(fp);
+ }
+ pTVPArc->Release();
+ pTVPArc = nullptr;
+ OnEnded();
+ return;
+ }
+
+ fseek(FpIn, 0, SEEK_SET);
+ ArcObj = archive_read_new();
+ archive_read_support_filter_all(ArcObj);
+ archive_read_support_format_all(ArcObj);
+ int r = archive_read_open_FILE(ArcObj, FpIn);
+ if (r < ARCHIVE_OK) {
+ OnError(r, archive_error_string(ArcObj));
+ OnEnded();
+ return;
+ }
+ for (int index = 0; !StopRequired; ++index) {
+ struct archive_entry *entry;
+ int r = archive_read_next_header(ArcObj, &entry);
+ if (r == ARCHIVE_EOF) {
+ r = ARCHIVE_OK;
+ break;
+ }
+ if (r < ARCHIVE_OK)
+ OnError(r, archive_error_string(ArcObj));
+ if (r < ARCHIVE_WARN)
+ break;
+ const char *filename = archive_entry_pathname_utf8(entry);
+ std::string fullpath = OutPath + filename;
+ FILE *fp = _fileopen(fullpath);
+ if (!fp) {
+ OnError(ARCHIVE_FAILED, "Cannot open output file");
+ break;
+ }
+ OnNewFile(index, filename, archive_entry_size(entry));
+
+ const void *buff;
+ size_t size;
+ la_int64_t offset;
+ tjs_uint64 file_size = 0;
+ const char *errmsg;
+ while (!StopRequired) {
+ r = archive_read_data_block(ArcObj, &buff, &size, &offset);
+ if (r == ARCHIVE_EOF) {
+ r = ARCHIVE_OK;
+ break;
+ }
+ if (r < ARCHIVE_OK) {
+ errmsg = archive_error_string(ArcObj);
+ break;
+ }
+ if (size != fwrite(buff, 1, size, fp)) {
+ r = ARCHIVE_FAILED;
+ errmsg = "Fail to write file.\nPlease check the disk space.";
+ break;
+ }
+ file_size += size;
+ total_size += size;
+ OnProgress(total_size, file_size);
+ }
+ fclose(fp);
+ if (r < ARCHIVE_OK)
+ OnError(r, errmsg);
+ if (r < ARCHIVE_WARN)
+ break;
+ if (archive_entry_mtime_is_set(entry)) {
+ TVP_utime(fullpath.c_str(), archive_entry_mtime(entry));
+ }
+ }
+ archive_read_close(ArcObj);
+ OnEnded();
+}
+
+tTVPUnpackArchive::tTVPUnpackArchive()
+{
+}
+
+tTVPUnpackArchive::~tTVPUnpackArchive()
+{
+ if (Impl) delete Impl;
+ if (FpIn) {
+ fclose(FpIn);
+ FpIn = nullptr;
+ }
+ if (ArcObj) {
+ archive_read_close(ArcObj);
+ archive_free(ArcObj);
+ }
+ if (pTVPArc)
+ pTVPArc->Release();
+}
diff --git a/src/core/base/UtilStreams.h b/src/core/base/UtilStreams.h
index 1598703f..2f6b2ed7 100644
--- a/src/core/base/UtilStreams.h
+++ b/src/core/base/UtilStreams.h
@@ -13,6 +13,7 @@
#include "StorageIntf.h"
+#include
@@ -174,7 +175,59 @@ class tTVPPartialStream : public tTJSBinaryStream
};
//---------------------------------------------------------------------------
+class tTVPUnpackArchiveImpl;
+class tTVPUnpackArchive {
+public:
+ tTVPUnpackArchive();
+ virtual ~tTVPUnpackArchive(); // must ve deconstructed from main thread
+ int Prepare(const std::string &path, const std::string &_outpath, tjs_uint64 *totalSize);
+ void Start();
+ void Stop();
+
+ void SetCallback(
+ const std::function &funcOnEnded,
+ const std::function &funcOnError,
+ const std::function &funcOnProgress,
+ const std::function &funcOnNewFile) {
+ FuncOnEnded = funcOnEnded;
+ FuncOnError = funcOnError;
+ FuncOnProgress = funcOnProgress;
+ FuncOnNewFile = funcOnNewFile;
+ }
+protected:
+ // these callbacks are not in main thread !
+ virtual void OnEnded() {
+ if (FuncOnEnded)
+ FuncOnEnded();
+ }
+ virtual void OnError(int err, const char *msg) {
+ if (FuncOnError)
+ FuncOnError(err, msg);
+ }
+ virtual void OnProgress(tjs_uint64 total_size, tjs_uint64 file_size) {
+ if (FuncOnProgress)
+ FuncOnProgress(total_size, file_size);
+ }
+ virtual void OnNewFile(int idx, const char * utf8name, tjs_uint64 file_size) {
+ if (FuncOnNewFile)
+ FuncOnNewFile(idx, utf8name, file_size);
+ }
+private:
+ void Process();
+ FILE *FpIn = nullptr;
+ struct archive *ArcObj = nullptr;
+ std::string OutPath;
+ friend class tTVPUnpackArchiveImpl;
+ tTVPUnpackArchiveImpl *Impl = nullptr;
+ tTVPArchive *pTVPArc = nullptr;
+ bool StopRequired = false;
+
+ std::function FuncOnEnded;
+ std::function FuncOnError;
+ std::function FuncOnProgress;
+ std::function FuncOnNewFile;
+};
#endif
diff --git a/src/core/base/XP3Archive.cpp b/src/core/base/XP3Archive.cpp
index 96c17621..5b9e7773 100644
--- a/src/core/base/XP3Archive.cpp
+++ b/src/core/base/XP3Archive.cpp
@@ -526,7 +526,8 @@ void tTVPXP3Archive::Init(tTJSBinaryStream *st, tjs_int64 off, bool normalizeNam
}
// sort item vector by its name (required for tTVPArchive specification)
- std::stable_sort(ItemVector.begin(), ItemVector.end());
+ if(normalizeName)
+ std::stable_sort(ItemVector.begin(), ItemVector.end());
}
catch(...)
{
@@ -542,10 +543,10 @@ void tTVPXP3Archive::Init(tTJSBinaryStream *st, tjs_int64 off, bool normalizeNam
}
//---------------------------------------------------------------------------
-tTVPXP3Archive::tTVPXP3Archive(const ttstr & name, tTJSBinaryStream *st, tjs_int64 offset) : tTVPArchive(name)
+tTVPXP3Archive::tTVPXP3Archive(const ttstr & name, tTJSBinaryStream *st, tjs_int64 offset, bool normalizeFileName) : tTVPArchive(name)
{
if (!st) st = TVPCreateStream(name);
- Init(st, offset);
+ Init(st, offset, normalizeFileName);
}
//---------------------------------------------------------------------------
tTVPXP3Archive::~tTVPXP3Archive()
@@ -553,7 +554,7 @@ tTVPXP3Archive::~tTVPXP3Archive()
TVPFreeArchiveHandlePoolByPointer(this);
}
-tTVPArchive * tTVPXP3Archive::Create(const ttstr & name, tTJSBinaryStream *st)
+tTVPArchive * tTVPXP3Archive::Create(const ttstr & name, tTJSBinaryStream *st, bool normalizeFileName)
{
bool refStream = st;
if (!st) {
@@ -564,7 +565,7 @@ tTVPArchive * tTVPXP3Archive::Create(const ttstr & name, tTJSBinaryStream *st)
if (!refStream) delete st;
return nullptr;
}
- return new tTVPXP3Archive(name, st, offset);
+ return new tTVPXP3Archive(name, st, offset, normalizeFileName);
}
//---------------------------------------------------------------------------
diff --git a/src/core/base/XP3Archive.h b/src/core/base/XP3Archive.h
index 49beade4..cdae7099 100644
--- a/src/core/base/XP3Archive.h
+++ b/src/core/base/XP3Archive.h
@@ -115,10 +115,10 @@ class tTVPXP3Archive : public tTVPArchive
public:
tTVPXP3Archive(const ttstr & name, int) : tTVPArchive(name) {}
- tTVPXP3Archive(const ttstr & name, tTJSBinaryStream *st = nullptr, tjs_int64 offset = -1);
+ tTVPXP3Archive(const ttstr & name, tTJSBinaryStream *st = nullptr, tjs_int64 offset = -1, bool normalizeFileName = true);
~tTVPXP3Archive();
- static tTVPArchive *Create(const ttstr & name, tTJSBinaryStream *st = nullptr);
+ static tTVPArchive *Create(const ttstr & name, tTJSBinaryStream *st = nullptr, bool normalizeFileName = true);
tjs_uint GetCount() { return Count; }
const ttstr & GetName(tjs_uint idx) const { return ItemVector[idx].Name; }
diff --git a/src/core/base/ZIPArchive.cpp b/src/core/base/ZIPArchive.cpp
index 75ed7078..68836f2f 100644
--- a/src/core/base/ZIPArchive.cpp
+++ b/src/core/base/ZIPArchive.cpp
@@ -196,25 +196,13 @@ static voidpf zip_open64file(voidpf opaque, const void * filename, int mode) {
return nullptr;
}
-static uLong zip_readfile(voidpf, voidpf s, void *buf, uLong size) {
- return ((tTJSBinaryStream*)s)->Read(buf, size);
-}
-
-static uLong zip_writefile(voidpf, voidpf s, const void *buf, uLong size) {
- return ((tTJSBinaryStream*)s)->Write(buf, size);
-}
-
-static ZPOS64_T zip_tell64file(voidpf, voidpf s) {
- return ((tTJSBinaryStream*)s)->GetPosition();
-}
-
-static long zip_seek64file(voidpf, voidpf s, ZPOS64_T offset, int origin) {
- ((tTJSBinaryStream*)s)->Seek(offset, origin);
- return 0;
-}
+static uLong zip_readfile(voidpf, voidpf s, void *buf, uLong size);
+static uLong zip_writefile(voidpf, voidpf s, const void *buf, uLong size);
+static ZPOS64_T zip_tell64file(voidpf, voidpf s);
+static long zip_seek64file(voidpf, voidpf s, ZPOS64_T offset, int origin);
static int zip_closefile(voidpf, voidpf s) {
- delete ((tTJSBinaryStream*)s);
+// delete ((tTJSBinaryStream*)s);
return 0;
}
@@ -2060,21 +2048,41 @@ class ZipArchive : public tTVPArchive {
public:
~ZipArchive();
- ZipArchive(const ttstr & name, tTJSBinaryStream *st);
+ ZipArchive(const ttstr & name, tTJSBinaryStream *st, bool normalizeFileName);
bool isValid() { return uf != nullptr; }
virtual tjs_uint GetCount() { return filelist.size(); }
virtual ttstr GetName(tjs_uint idx) { return filelist[idx].first; }
virtual tTJSBinaryStream * CreateStreamByIndex(tjs_uint idx);
+
+ tTJSBinaryStream *_st = nullptr;
};
-tTVPArchive * TVPOpenZIPArchive(const ttstr & name, tTJSBinaryStream *st) {
+static uLong zip_readfile(voidpf, voidpf s, void *buf, uLong size) {
+ return ((ZipArchive*)s)->_st->Read(buf, size);
+}
+
+static uLong zip_writefile(voidpf, voidpf s, const void *buf, uLong size) {
+ return ((ZipArchive*)s)->_st->Write(buf, size);
+}
+
+static ZPOS64_T zip_tell64file(voidpf, voidpf s) {
+ return ((ZipArchive*)s)->_st->GetPosition();
+}
+
+static long zip_seek64file(voidpf, voidpf s, ZPOS64_T offset, int origin) {
+ ((ZipArchive*)s)->_st->Seek(offset, origin);
+ return 0;
+}
+
+tTVPArchive * TVPOpenZIPArchive(const ttstr & name, tTJSBinaryStream *st, bool normalizeFileName) {
tjs_uint64 pos = st->GetPosition();
bool checkZIP = st->ReadI16LE() == 0x4B50; // 'PK'
st->SetPosition(pos);
if (!checkZIP) return nullptr;
- ZipArchive *arc = new ZipArchive(name, st);
+ ZipArchive *arc = new ZipArchive(name, st, normalizeFileName);
if (!arc->isValid()) {
+ arc->_st = nullptr;
delete arc;
return nullptr;
}
@@ -2108,12 +2116,17 @@ ZipArchive::~ZipArchive() {
unzClose(uf);
uf = NULL;
}
+ if (_st) {
+ delete _st;
+ _st = nullptr;
+ }
}
void storeFilename(ttstr &name, const char *narrowName, const ttstr &filename);
-ZipArchive::ZipArchive(const ttstr & name, tTJSBinaryStream *st) : tTVPArchive(name) {
+ZipArchive::ZipArchive(const ttstr & name, tTJSBinaryStream *st, bool normalizeFileName) : tTVPArchive(name) {
if (!st) st = TVPCreateStream(name);
- if ((uf = unzOpenInternal(st, &zipfunc, 1)) != NULL) {
+ _st = st;
+ if ((uf = unzOpenInternal(this, &zipfunc, 1)) != NULL) {
//unzGoToFirstFile64(uf, NULL, NULL, 0);
unz_file_info file_info;
do {
@@ -2123,14 +2136,17 @@ ZipArchive::ZipArchive(const ttstr & name, tTJSBinaryStream *st) : tTVPArchive(n
char filename_inzip[1024];
if (unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0) == UNZ_OK) {
storeFilename(filename, filename_inzip, name);
- NormalizeInArchiveStorageName(filename);
+ if (normalizeFileName)
+ NormalizeInArchiveStorageName(filename);
filelist.emplace_back(filename, entry);
}
}
} while (unzGoToNextFile64(uf, NULL, NULL, 0) == UNZ_OK);
- std::sort(filelist.begin(), filelist.end(), [](const FileEntry& a, const FileEntry& b){
- return a.first < b.first;
- });
+ if (normalizeFileName) {
+ std::sort(filelist.begin(), filelist.end(), [](const FileEntry& a, const FileEntry& b) {
+ return a.first < b.first;
+ });
+ }
}
}
diff --git a/src/core/base/win32/StorageImpl.cpp b/src/core/base/win32/StorageImpl.cpp
index c63424bf..0f9fba5e 100644
--- a/src/core/base/win32/StorageImpl.cpp
+++ b/src/core/base/win32/StorageImpl.cpp
@@ -153,6 +153,10 @@ void TVPGetLocalFileListAt(const ttstr &name, const std::functiond_name);
+ if (file.length() <= 2) {
+ if (file == TJS_W(".") || file == TJS_W(".."))
+ continue;
+ }
tjs_char *p = file.Independ();
while (*p)
{
@@ -581,10 +585,10 @@ bool TVPCheckExistentLocalFolder(const ttstr &name)
-tTVPArchive * TVPOpenZIPArchive(const ttstr & name, tTJSBinaryStream *st);
-tTVPArchive * TVPOpen7ZArchive(const ttstr & name, tTJSBinaryStream *st);
-tTVPArchive * TVPOpenTARArchive(const ttstr & name, tTJSBinaryStream *st);
-static tTVPArchive*(*ArchiveCreators[])(const ttstr & name, tTJSBinaryStream *st) = {
+tTVPArchive * TVPOpenZIPArchive(const ttstr & name, tTJSBinaryStream *st, bool normalizeFileName);
+tTVPArchive * TVPOpen7ZArchive(const ttstr & name, tTJSBinaryStream *st, bool normalizeFileName);
+tTVPArchive * TVPOpenTARArchive(const ttstr & name, tTJSBinaryStream *st, bool normalizeFileName);
+static tTVPArchive*(*ArchiveCreators[])(const ttstr & name, tTJSBinaryStream *st, bool normalizeFileName) = {
TVPOpenZIPArchive,
TVPOpen7ZArchive,
TVPOpenTARArchive,
@@ -594,7 +598,7 @@ static tTVPArchive*(*ArchiveCreators[])(const ttstr & name, tTJSBinaryStream *st
//---------------------------------------------------------------------------
// TVPOpenArchive
//---------------------------------------------------------------------------
-tTVPArchive * TVPOpenArchive(const ttstr & name)
+tTVPArchive * TVPOpenArchive(const ttstr & name, bool normalizeFileName)
{
#if 0
tTVPArchive * archive = TVPOpenSusieArchive(name); // in SusieArchive.h
@@ -603,8 +607,8 @@ tTVPArchive * TVPOpenArchive(const ttstr & name)
tTJSBinaryStream *st = TVPCreateStream(name);
if (!st) return nullptr;
for (int i = 0; i < sizeof(ArchiveCreators) / sizeof(ArchiveCreators[0]); ++i) {
- tTVPArchive*(*creator)(const ttstr &, tTJSBinaryStream*) = ArchiveCreators[i];
- tTVPArchive * archive = creator(name, st);
+ tTVPArchive*(*creator)(const ttstr &, tTJSBinaryStream*, bool) = ArchiveCreators[i];
+ tTVPArchive * archive = creator(name, st, normalizeFileName);
if (archive) return archive;
st->SetPosition(0);
}
@@ -617,7 +621,7 @@ int TVPCheckArchive(const ttstr &localname)
tTVPArchive *arc = nullptr;
int validArchive = 2; // archive but no startup.tjs
try {
- arc = TVPOpenArchive(TVPNormalizeStorageName(localname));
+ arc = TVPOpenArchive(TVPNormalizeStorageName(localname), false);
if (arc) {
tjs_uint count = arc->GetCount();
ttstr str_startup_tjs = TJS_W("startup.tjs");
@@ -1504,3 +1508,30 @@ TJS_END_NATIVE_STATIC_METHOD_DECL_OUTER(/*object to register*/cls,
}
//---------------------------------------------------------------------------
+static FILE *_fileopen(ttstr path) {
+ std::string strpath = path.AsStdString();
+ FILE *fp = fopen(strpath.c_str(), "wb");
+ if (!fp) { // make dirs
+ path = TVPExtractStoragePath(path);
+ TVPCreateFolders(path);
+ fp = fopen(strpath.c_str(), "wb");
+ }
+ return fp;
+}
+
+bool TVPSaveStreamToFile(tTJSBinaryStream *st, tjs_uint64 offset, tjs_uint64 size, ttstr outpath) {
+ FILE *fp = _fileopen(outpath);
+ if (!fp) return false;
+ tjs_uint64 origpos = st->GetPosition();
+ st->SetPosition(offset);
+ std::vector buffer; buffer.resize(2 * 1024 * 1024);
+ while (size > 0) {
+ unsigned int readsize = size > buffer.size() ? buffer.size() : size;
+ readsize = st->Read(&buffer.front(), readsize);
+ fwrite(&buffer.front(), 1, readsize, fp);
+ size -= readsize;
+ }
+ fclose(fp);
+ st->SetPosition(origpos);
+ return true;
+}
diff --git a/src/core/base/win32/StorageImpl.h b/src/core/base/win32/StorageImpl.h
index 31c7cf0b..280ef117 100644
--- a/src/core/base/win32/StorageImpl.h
+++ b/src/core/base/win32/StorageImpl.h
@@ -199,4 +199,5 @@ class tTVPPluginHolder
//---------------------------------------------------------------------------
void TVPListDir(const std::string &folder, std::function cb);
+bool TVPSaveStreamToFile(tTJSBinaryStream *st, tjs_uint64 offset, tjs_uint64 size, ttstr outpath);
#endif
diff --git a/src/core/environ/ConfigManager/LocaleConfigManager.cpp b/src/core/environ/ConfigManager/LocaleConfigManager.cpp
index 1d3019cf..b6329ba6 100644
--- a/src/core/environ/ConfigManager/LocaleConfigManager.cpp
+++ b/src/core/environ/ConfigManager/LocaleConfigManager.cpp
@@ -61,6 +61,12 @@ bool LocaleConfigManager::initText(cocos2d::ui::Text *ctrl) {
return initText(ctrl, ctrl->getString());
}
+bool LocaleConfigManager::initText(cocos2d::ui::Button *ctrl)
+{
+ if (!ctrl) return false;
+ return initText(ctrl, ctrl->getTitleText());
+}
+
bool LocaleConfigManager::initText(cocos2d::ui::Text *ctrl, const std::string &tid) {
if (!ctrl) return false;
diff --git a/src/core/environ/ConfigManager/LocaleConfigManager.h b/src/core/environ/ConfigManager/LocaleConfigManager.h
index a01045f1..629ce5af 100644
--- a/src/core/environ/ConfigManager/LocaleConfigManager.h
+++ b/src/core/environ/ConfigManager/LocaleConfigManager.h
@@ -29,6 +29,7 @@ class LocaleConfigManager {
const std::string &GetText(const std::string &tid); // in utf8
bool initText(cocos2d::ui::Text *ctrl);
+ bool initText(cocos2d::ui::Button *ctrl);
bool initText(cocos2d::ui::Text *ctrl, const std::string &tid);
bool initText(cocos2d::ui::Button *ctrl, const std::string &tid);
diff --git a/src/core/environ/DetectCPU.cpp b/src/core/environ/DetectCPU.cpp
index c24b5dc8..63bea201 100644
--- a/src/core/environ/DetectCPU.cpp
+++ b/src/core/environ/DetectCPU.cpp
@@ -148,6 +148,7 @@ static ttstr TVPDumpCPUInfo(tjs_int cpu_num)
//---------------------------------------------------------------------------
static void TVPDisableCPU(tjs_uint32 featurebit, const tjs_char *name)
{
+#if 0
tTJSVariant val;
ttstr str;
if(TVPGetCommandLine(name, &val))
@@ -158,6 +159,7 @@ static void TVPDisableCPU(tjs_uint32 featurebit, const tjs_char *name)
else if(str == TJS_W("force"))
TVPCPUType |= featurebit;
}
+#endif
}
#if defined(WIN32) || defined(__ANDROID__)
diff --git a/src/core/environ/Platform.h b/src/core/environ/Platform.h
index 37cb72d9..48fcf283 100644
--- a/src/core/environ/Platform.h
+++ b/src/core/environ/Platform.h
@@ -54,4 +54,4 @@ struct tTVP_stat {
bool TVP_stat(const tjs_char *name, tTVP_stat &s);
bool TVP_stat(const char *name, tTVP_stat &s);
-
+void TVP_utime(const char *name, time_t modtime);
diff --git a/src/core/environ/XP3ArchiveRepack.cpp b/src/core/environ/XP3ArchiveRepack.cpp
index 0280ff9e..b0c7faee 100644
--- a/src/core/environ/XP3ArchiveRepack.cpp
+++ b/src/core/environ/XP3ArchiveRepack.cpp
@@ -16,19 +16,30 @@ extern "C" {
#include "win32io.h"
#include "GraphicsLoaderIntf.h"
#include "ogl/etcpak.h"
+#include
+#include "LayerIntf.h"
+#include "MsgIntf.h"
+#include "ncbind/ncbind.hpp"
+#include "visual/tvpgl_asm_init.h"
+#include "DetectCPU.h"
+#include
using namespace TJS;
using namespace NArchive::N7z;
#define COMPRESS_THRESHOLD 4 * 1024 * 1024
+#define S_INTERRUPT ((HRESULT)0x114705)
void TVPSetXP3FilterScript(ttstr content);
+void TVPSavePVRv3(void* formatdata, tTJSBinaryStream* dst, const iTVPBaseBitmap* image, const ttstr & mode, iTJSDispatch2* meta);
class tTVPXP3ArchiveEx : public tTVPXP3Archive {
public:
tTVPXP3ArchiveEx(const ttstr & name, tTJSBinaryStream *st) : tTVPXP3Archive(name, 0) {
Init(st, -1, false);
}
+
+ uint64_t TotalSize = 0;
};
class OutStreamFor7z : public IOutStream {
@@ -37,7 +48,7 @@ class OutStreamFor7z : public IOutStream {
public:
OutStreamFor7z(const std::string &path) {
- open(path.c_str(), O_RDWR | O_CREAT, 0666);
+ fp = open(path.c_str(), O_RDWR | O_CREAT, 0666);
}
~OutStreamFor7z() {
close(fp);
@@ -144,19 +155,142 @@ class SequentialInStreamFor7z : public ISequentialInStream {
}
};
-XP3ArchiveRepackAsync::XP3ArchiveRepackAsync(const std::string &xp3filter)
+class XP3ArchiveRepackAsyncImpl
+ : ICompressProgressInfo
+{
+public:
+ XP3ArchiveRepackAsyncImpl();
+ ~XP3ArchiveRepackAsyncImpl();
+ void Clear();
+ void Start();
+ void Stop() { bStopRequired = true; }
+ void DoConv();
+ uint64_t AddTask(const std::string &src);
+ void SetXP3Filter(const std::string &xp3filter);
+ void SetCallback(
+ const std::function &onNewFile,
+ const std::function &onNewArchive,
+ const std::function &onProgress,
+ const std::function &onError,
+ const std::function &onEnded) {
+ OnNewFile = onNewFile;
+ OnNewArchive = onNewArchive;
+ OnProgress = onProgress;
+ OnError = onError;
+ OnEnded = onEnded;
+ }
+ void SetOption(const std::string &name, bool v);
+
+public:
+ bool OptionUsingETC2 = false;
+ bool OptionMergeMaskImg = true;
+
+private:
+ HRESULT AddTo7zArchive(tTJSBinaryStream* s, const ttstr &_naem);
+
+ // ICompressProgressInfo
+ virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) override;
+ // IUnknown
+ virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) override { return E_NOTIMPL; }
+ virtual ULONG AddRef(void) override { return 0; }
+ virtual ULONG Release(void) override { return 0; }
+
+ std::vector > ConvFileList;
+ std::thread* Thread = nullptr;
+ CCreatedCoder CoderCompress, CoderCopy;
+ static const int nCodecMethod = 0x30101, // LZMA
+ nCodecMethodCopy = 0;
+ CArchiveDatabaseOut newDatabase;
+ OutStreamFor7z *strout;
+ CByteBuffer props;
+ bool bStopRequired = false;
+ uint64_t nTotalSize = 0, nArcSize = 0;
+
+ std::function OnNewFile;
+ std::function OnNewArchive;
+ std::function OnProgress;
+ std::function OnError;
+ std::function OnEnded;
+};
+
+XP3ArchiveRepackAsync::XP3ArchiveRepackAsync()
+ : _impl(new XP3ArchiveRepackAsyncImpl())
+{
+ TVPDetectCPU();
+ TVPGL_ASM_Init();
+}
+
+XP3ArchiveRepackAsync::~XP3ArchiveRepackAsync() {
+ delete _impl;
+}
+
+uint64_t XP3ArchiveRepackAsync::AddTask(const std::string &src) {
+ return _impl->AddTask(src);
+}
+
+void XP3ArchiveRepackAsync::Start()
+{
+ _impl->Start();
+}
+
+void XP3ArchiveRepackAsync::Stop()
+{
+ _impl->Stop();
+}
+
+void XP3ArchiveRepackAsync::SetXP3Filter(const std::string &xp3filter)
+{
+ _impl->SetXP3Filter(xp3filter);
+}
+
+void XP3ArchiveRepackAsync::SetCallback(
+ const std::function &onNewFile,
+ const std::function &onNewArchive,
+ const std::function &onProgress,
+ const std::function &onError,
+ const std::function &onEnded)
+{
+ _impl->SetCallback(onNewFile, onNewArchive, onProgress, onError, onEnded);
+}
+
+void XP3ArchiveRepackAsync::SetOption(const std::string &name, bool v)
+{
+ _impl->SetOption(name, v);
+}
+
+XP3ArchiveRepackAsyncImpl::XP3ArchiveRepackAsyncImpl()
{
if (!g_CrcTable[1]) CrcGenerateTable();
- ttstr xp3filterScript;
- iTJSTextReadStream * stream = TVPCreateTextStreamForRead(xp3filter, "");
- stream->Read(xp3filterScript, 0);
- delete stream;
- TVPSetXP3FilterScript(xp3filterScript);
+ CreateCoder(nCodecMethod, true, CoderCompress);
+ CreateCoder(nCodecMethodCopy, true, CoderCopy);
+
+ CMyComPtr writeCoderProperties;
+ CMyComPtr setCoderProperties;
+ CoderCompress.Coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
+ CoderCompress.Coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
+
+ if (setCoderProperties) {
+ const int nProp = 1;
+ PROPVARIANT propvars[nProp];
+ PROPID props[nProp] = {
+ NCoderPropID::kDictionarySize,
+ };
+ propvars[0].vt = VT_UI4;
+ propvars[0].ulVal = 4 * 1024 * 1024;
+ setCoderProperties->SetCoderProperties(props, propvars, nProp);
+ }
+ if (writeCoderProperties) {
+ CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
+ CMyComPtr dynOutStream(outStreamSpec);
+ outStreamSpec->Init();
+ writeCoderProperties->WriteCoderProperties(dynOutStream);
+ outStreamSpec->CopyToBuffer(props);
+ }
}
-XP3ArchiveRepackAsync::~XP3ArchiveRepackAsync()
+XP3ArchiveRepackAsyncImpl::~XP3ArchiveRepackAsyncImpl()
{
- std::thread* t = (std::thread*)Thread;
+ std::thread* t = Thread;
if (t && t->joinable()) {
t->join();
delete t;
@@ -164,273 +298,461 @@ XP3ArchiveRepackAsync::~XP3ArchiveRepackAsync()
Clear();
}
-uint64_t XP3ArchiveRepackAsync::AddTask(const std::string &src/*, const std::string &dst*/)
+uint64_t XP3ArchiveRepackAsyncImpl::AddTask(const std::string &src/*, const std::string &dst*/)
{
- uint64_t totalSize = 0;
ttstr path(src);
tTVPLocalFileStream *str = new tTVPLocalFileStream(path, path, TJS_BS_READ);
tTVPXP3ArchiveEx *xp3arc = new tTVPXP3ArchiveEx(path, str);
for (const tTVPXP3Archive::tArchiveItem &item : xp3arc->ItemVector) {
- totalSize += item.OrgSize;
+ xp3arc->TotalSize += item.OrgSize;
}
ConvFileList.emplace_back(xp3arc, src);
- return totalSize;
+ return xp3arc->TotalSize;
+}
+
+void XP3ArchiveRepackAsyncImpl::SetXP3Filter(const std::string &xp3filter)
+{
+ ttstr xp3filterScript;
+ iTJSTextReadStream * stream = TVPCreateTextStreamForRead(xp3filter, "");
+ stream->Read(xp3filterScript, 0);
+ delete stream;
+ TVPSetXP3FilterScript(xp3filterScript);
}
-void XP3ArchiveRepackAsync::Clear()
+void XP3ArchiveRepackAsyncImpl::SetOption(const std::string &name, bool v)
+{
+ if (name == "merge_mask_img") {
+ OptionMergeMaskImg = v;
+ } else if (name == "conv_etc2") {
+ OptionUsingETC2 = v;
+ }
+}
+
+void XP3ArchiveRepackAsyncImpl::Clear()
{
for (auto & it : ConvFileList) {
- delete it.first;
+ if (it.first)
+ delete it.first;
}
ConvFileList.clear();
TVPSetXP3FilterScript(TJS_W(""));
}
-void XP3ArchiveRepackAsync::Start()
+void XP3ArchiveRepackAsyncImpl::Start()
{
if (!Thread) {
- Thread = new std::thread(std::bind(&XP3ArchiveRepackAsync::DoConv, this));
+ Thread = new std::thread(std::bind(&XP3ArchiveRepackAsyncImpl::DoConv, this));
+ }
+}
+
+static bool CheckIsImage(tTJSBinaryStream *s) {
+ // convert image > 8k
+ tjs_uint8 header[16];
+ tjs_uint readed = s->Read(header, 16);
+ s->SetPosition(0);
+ if (readed != 16) return false;
+ if (!memcmp(header, "BM", 2)) {
+ return true;
+ } else if (!memcmp(header, "\x89PNG", 4)) {
+ return true;
+ } else if (!memcmp(header, "\xFF\xD8\xFF", 3)) { // JPEG
+ return true;
+ } else if (!memcmp(header, "TLG", 3)) {
+ return true;
+ } else if (!memcmp(header, "\x49\x49\xbc\x01", 4)) { // JXR
+ return true;
+ } else if (!memcmp(header, "BPG", 3)) {
+ return true;
+ } else if (!memcmp(header, "RIFF", 4)) {
+ if (!memcmp(header + 8, "WEBPVP8", 7)) {
+ return true;
+ }
}
+ return false;
}
-void XP3ArchiveRepackAsync::DoConv()
+HRESULT XP3ArchiveRepackAsyncImpl::AddTo7zArchive(tTJSBinaryStream* s, const ttstr &_name) {
+ CFileItem file;
+ CFileItem2 file2;
+ SequentialInStreamFor7z str(s);
+ tjs_uint64 origSize = s->GetSize();
+ file.Size = origSize;
+ file2.Init();
+ UString name(_name.c_str());
+ UInt64 inSizeForReduce = origSize;
+ UInt64 newSize = origSize;
+ bool compressable = origSize > 64 && origSize < 4 * 1024 * 1024;
+ if (compressable) {
+ // compressable quick check
+ tjs_uint8 header[16];
+ s->Read(header, 16);
+ if (!memcmp(header, "\x89PNG", 4)) {
+ compressable = false;
+ } else if (!memcmp(header, "OggS\x00", 5)) {
+ compressable = false;
+ } else if (!memcmp(header, "\xFF\xD8\xFF", 3)) { // JPEG
+ compressable = false;
+ } else if (!memcmp(header, "TLG", 3)) {
+ compressable = false;
+ } else if (!memcmp(header, "0&\xB2\x75\x8E\x66\xCF\x11", 8)) { // wmv/wma
+ compressable = false;
+ } else if (!memcmp(header, "AJPM", 4)) { // AMV
+ compressable = false;
+ } else if (!memcmp(header, "\x49\x49\xbc\x01", 4)) { // JXR
+ compressable = false;
+ } else if (!memcmp(header, "BPG", 3)) {
+ compressable = false;
+ } else if (!memcmp(header, "RIFF", 4)) {
+ if (!memcmp(header + 8, "WEBPVP8", 7)) {
+ compressable = false;
+ }
+ }
+ s->SetPosition(0);
+ }
+ HRESULT ret;
+ if (compressable) {
+ UInt64 expectedSize = origSize * 4 / 5;
+ OutStreamMemory tmp;
+ if ((ret = CoderCompress.Coder->Code(&str, &tmp, &inSizeForReduce, &newSize, this)) != S_OK)
+ return ret;
+ if (tmp.GetSize() < expectedSize) {
+ UInt32 writed;
+ if ((ret = strout->Write(tmp.GetInternalBuffer(), tmp.GetSize(), &writed)) != S_OK) {
+ return ret;
+ }
+ if (writed != tmp.GetSize())
+ return E_FAIL;
+ newDatabase.PackSizes.Add(tmp.GetSize());
+ newDatabase.CoderUnpackSizes.Add(origSize);
+ newDatabase.NumUnpackStreamsVector.Add(1);
+ CFolder &folder = newDatabase.Folders.AddNew();
+ folder.Bonds.SetSize(0);
+ folder.Coders.SetSize(1);
+ CCoderInfo &cod = folder.Coders[0];
+ cod.MethodID = nCodecMethod;
+ cod.NumStreams = 1;
+ cod.Props = props;
+ folder.PackStreams.SetSize(1);
+ folder.PackStreams[0] = 0; // only 1 stream
+ newDatabase.AddFile(file, file2, name);
+ return S_OK;
+ }
+ s->SetPosition(0);
+ }
+ // direct copy
+ newSize = origSize;
+ if ((ret = CoderCopy.Coder->Code(&str, strout, &inSizeForReduce, &newSize, this)) != S_OK) {
+ return ret;
+ }
+ newDatabase.PackSizes.Add(s->GetSize());
+ newDatabase.CoderUnpackSizes.Add(origSize);
+ newDatabase.NumUnpackStreamsVector.Add(1);
+ CFolder &folder = newDatabase.Folders.AddNew();
+ folder.Bonds.SetSize(0);
+ folder.Coders.SetSize(1);
+ CCoderInfo &cod = folder.Coders[0];
+ cod.MethodID = nCodecMethodCopy;
+ cod.NumStreams = 1;
+ folder.PackStreams.SetSize(1);
+ folder.PackStreams[0] = 0; // only 1 stream
+ newDatabase.AddFile(file, file2, name);
+ return S_OK;
+}
+
+HRESULT XP3ArchiveRepackAsyncImpl::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
{
- for (auto &it : ConvFileList) {
+ if (OnProgress) {
+ OnProgress(nTotalSize + *inSize, nArcSize + *inSize, *inSize);
+ }
+ return bStopRequired ? S_INTERRUPT : S_OK;
+}
+
+void XP3ArchiveRepackAsyncImpl::DoConv()
+{
+ nTotalSize = 0;
+ for (unsigned int arcidx = 0; arcidx < ConvFileList.size(); ++arcidx) {
+ auto &it = ConvFileList[arcidx];
+ if (bStopRequired) break;
+ if (OnNewArchive)
+ OnNewArchive(arcidx, it.first->TotalSize, it.second);
+
tTVPXP3ArchiveEx *xp3arc = it.first;
tjs_uint totalFile = xp3arc->GetCount();
std::string tmpname = it.second + ".7z";
- OutStreamFor7z *strout = new OutStreamFor7z(tmpname);
-
- const int nCodecMethod = 0x30101, // LZMA
- nCodecMethodCopy = 0;
- CCreatedCoder coder, coderCopy;
- CreateCoder(nCodecMethod, true, coder);
- CreateCoder(nCodecMethodCopy, true, coderCopy);
- CMyComPtr writeCoderProperties;
- CMyComPtr setCoderProperties;
- coder.Coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
- coder.Coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
- CByteBuffer props;
-
- if (setCoderProperties) {
- const int nProp = 1;
- PROPVARIANT propvars[nProp];
- PROPID props[nProp] = {
- NCoderPropID::kDictionarySize,
- };
- propvars[0].vt = VT_UI4;
- propvars[0].ulVal = 4 * 1024 * 1024;
- setCoderProperties->SetCoderProperties(props, propvars, nProp);
- }
- if (writeCoderProperties) {
- CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
- CMyComPtr dynOutStream(outStreamSpec);
- outStreamSpec->Init();
- writeCoderProperties->WriteCoderProperties(dynOutStream);
- outStreamSpec->CopyToBuffer(props);
- }
+ strout = new OutStreamFor7z(tmpname);
COutArchive archive;
- archive.Create(strout, false);
+ if (archive.Create(strout, false) != S_OK) {
+ if (OnError)
+ OnError(-1, "Fail to create output archive.");
+ break;
+ }
archive.SkipPrefixArchiveHeader();
- CArchiveDatabaseOut newDatabase;
-
- for (const tTVPXP3Archive::tArchiveItem &item : xp3arc->ItemVector) {
- if (!item.OrgSize) {
- CFileItem file;
- CFileItem2 file2;
- file2.Init();
- UString name(item.Name.c_str());
- file.Size = item.OrgSize;
- file.HasStream = false;
- newDatabase.AddFile(file, file2, name);
+ newDatabase.Clear();
+
+ nArcSize = 0;
+
+ // filter image files , img_mask = -1 means no mask available or normal file
+ std::map imglist;
+ std::vector filelist; // normal files
+ {
+ std::unordered_multimap allFileName;
+ std::vector allfilelist;
+ std::set masklist;
+ for (tjs_uint idx = 0; idx < xp3arc->ItemVector.size(); ++idx) {
+ const tTVPXP3Archive::tArchiveItem &item = xp3arc->ItemVector[idx];
+ if (!item.OrgSize) {
+ // add empty files first
+ CFileItem file;
+ CFileItem2 file2;
+ file2.Init();
+ UString name(item.Name.c_str());
+ file.Size = item.OrgSize;
+ file.HasStream = false;
+ newDatabase.AddFile(file, file2, name);
+ continue;
+ }
+ if (item.Name.length() > 256 && item.Name.StartsWith(TJS_W("$$$")))
+ continue;
+ ttstr name = TVPChopStorageExt(item.Name);
+ allFileName.emplace(name, &item);
+ allfilelist.emplace_back(idx);
}
- }
- for (const tTVPXP3Archive::tArchiveItem &item : xp3arc->ItemVector) {
- if (item.OrgSize) {
- CFileItem file;
- CFileItem2 file2;
- file2.Init();
- UString name(item.Name.c_str());
- file.Size = item.OrgSize;
- std::auto_ptr s(xp3arc->CreateStreamByIndex(&item - &xp3arc->ItemVector.front()));
- if (UsingETC2 && item.OrgSize > 8192) {
- // convert image > 8k
- tjs_uint8 header[16];
- s->Read(header, 16);
- bool isImage = false, isOpaque = false;
- if (!memcmp(header, "BM", 2)) {
- isImage = true;
- } else if (!memcmp(header, "\x89PNG", 4)) {
- isImage = true;
- } else if (!memcmp(header, "\xFF\xD8\xFF", 3)) { // JPEG
- isImage = true;
- } else if (!memcmp(header, "TLG", 3)) {
- isImage = true;
- } else if (!memcmp(header, "\x49\x49\xbc\x01", 4)) { // JXR
- isImage = true;
- } else if (!memcmp(header, "BPG", 3)) {
- isImage = true;
- } else if (!memcmp(header, "RIFF", 4)) {
- if (!memcmp(header + 8, "WEBPVP8", 7)) {
- isImage = true;
- }
+ if(OptionMergeMaskImg)
+ for (tjs_uint idx : allfilelist) {
+ const tTVPXP3Archive::tArchiveItem &item = xp3arc->ItemVector[idx];
+ ttstr name = TVPChopStorageExt(item.Name);
+ tjs_int pos = name.length() - 2;
+ if (pos > 0 && name.SubString(pos, 2) == TJS_W("_m")) {
+ ttstr prefix = name.SubString(0, pos);
+ int count = 0;
+ auto itpair = allFileName.equal_range(prefix);
+ for (auto it = itpair.first; it != itpair.second; ++it) {
+ ++count;
}
- // actual TVPLoadGraphicRouter
- static tTVPGraphicHandlerType *handler = TVPGetGraphicLoadHandler(TJS_W(".png"));
- if (isImage) {
- // skip 8-bit image
- s->SetPosition(0);
- iTJSDispatch2 *dic = nullptr;
- handler->Header(s.get(), &dic);
- if (dic) {
- dic->Release();
- tTJSVariant val;
- dic->PropGet(0, TJS_W("bpp"), 0, &val, dic);
- int bpp = val.AsInteger();
- isOpaque = bpp == 24;
- isImage = isOpaque || bpp == 32;
- } else {
- isImage = false; // unknown error, skip
- }
+ if (count == 1) { // assume that one mask associate to one image
+ const tTVPXP3Archive::tArchiveItem* imgItem = itpair.first->second;
+ allFileName.erase(itpair.first);
+ allFileName.erase(name);
+ imglist.emplace(imgItem - &xp3arc->ItemVector.front(), idx);
+ masklist.emplace(idx);
+ continue;
}
- if (isImage) {
- // TODO merge mask file
- s->SetPosition(0);
- typedef std::tuple > PicInfo;
- PicInfo picinfo;
- handler->Load(nullptr, &picinfo, [](void *callbackdata, tjs_uint w, tjs_uint h, tTVPGraphicPixelFormat fmt)->int {
- PicInfo &picinfo = *(PicInfo *)callbackdata;
- std::get<0>(picinfo) = w;
- std::get<1>(picinfo) = h;
- int pitch = w * 4;
- std::get<2>(picinfo) = pitch;
- std::get<3>(picinfo).resize(pitch * h);
- return w * 4;
- }, [](void *callbackdata, int y)->void* {
- PicInfo &picinfo = *(PicInfo *)callbackdata;
- int pitch = std::get<2>(picinfo);
- return &std::get<3>(picinfo)[pitch * y];
- }, [](void *callbackdata, const ttstr & name, const ttstr & value) {
- }, s.get(), 0, glmNormal);
-
- int w = std::get<0>(picinfo);
- int h = std::get<1>(picinfo);
- int pitch = std::get<2>(picinfo);
- uint8_t *imgdata = nullptr;
- size_t datalen;
- uint64_t pvr_pixfmt;
- if (isOpaque) {
- imgdata = (uint8_t *)ETCPacker::convert(&std::get<3>(picinfo).front(), w, h, pitch, true, datalen);
- pvr_pixfmt = 22; // ETC2_RGB
- } else {
- imgdata = (uint8_t *)ETCPacker::convertWithAlpha(&std::get<3>(picinfo).front(), w, h, pitch, datalen);
- pvr_pixfmt = 23; // ETC2_RGBA
- }
+ }
+ }
+ for (tjs_uint idx : allfilelist) {
+ if (imglist.find(idx) != imglist.end() || masklist.find(idx) != masklist.end())
+ continue;
+ filelist.push_back(idx);
+ }
+ }
- tTVPMemoryStream * memstr = new tTVPMemoryStream;
- // in pvr v3 container
- memstr->WriteBuffer("PVR\3", 4);
- memstr->WriteBuffer("\0\0\0\0", 4); // no premultiply alpha
- memstr->WriteBuffer(&pvr_pixfmt, sizeof(pvr_pixfmt));
- memstr->WriteBuffer("\0\0\0\0", 4); // colorSpace
- memstr->WriteBuffer("\0\0\0\0", 4); // channelType
- memstr->WriteBuffer(&h, sizeof(h));
- memstr->WriteBuffer(&w, sizeof(w));
- memstr->WriteBuffer("\1\0\0\0", 4); // depth
- memstr->WriteBuffer("\1\0\0\0", 4); // numberOfSurfaces
- memstr->WriteBuffer("\1\0\0\0", 4); // numberOfFaces
- memstr->WriteBuffer("\1\0\0\0", 4); // numberOfMipmaps
- memstr->WriteBuffer("\0\0\0\0", 4); // metadataLength
- memstr->WriteBuffer(imgdata, datalen);
- delete[] imgdata;
- memstr->SetPosition(0);
- s.reset(memstr);
- }
+ // merge image with mask
+ // actual TVPLoadGraphicRouter
+ static tTVPGraphicHandlerType *handler = TVPGetGraphicLoadHandler(TJS_W(".png"));
+ for (const auto &it : imglist) {
+ if (bStopRequired) break;
+ const tTVPXP3Archive::tArchiveItem &imgItem = xp3arc->ItemVector[it.first];
+ const tTVPXP3Archive::tArchiveItem &maskItem = xp3arc->ItemVector[it.second];
+ std::auto_ptr strImg(xp3arc->CreateStreamByIndex(&imgItem - &xp3arc->ItemVector.front()));
+ std::auto_ptr strMask(xp3arc->CreateStreamByIndex(&maskItem - &xp3arc->ItemVector.front()));
+ bool isImage = CheckIsImage(strImg.get()) && CheckIsImage(strMask.get());
+ if (isImage) {
+ // skip 8-bit image
+ iTJSDispatch2 *dic = nullptr;
+ handler->Header(strImg.get(), &dic);
+ strImg->SetPosition(0);
+ if (dic) {
+ tTJSVariant val;
+ dic->PropGet(0, TJS_W("bpp"), 0, &val, dic);
+ dic->Release();
+ int bpp = val.AsInteger();
+ isImage = bpp == 24 || bpp == 32;
+ } else {
+ isImage = false; // unknown error, skip
+ }
+ }
+ if (!isImage) {
+ filelist.push_back(it.first);
+ filelist.push_back(it.second);
+ continue;
+ }
+ struct BmpInfoWithMask {
+ tTVPBitmap* bmp = nullptr;
+ tTVPBitmap* bmpForMask = nullptr;
+ std::unordered_map metainfo;
+ ~BmpInfoWithMask() {
+ if (bmp) delete bmp;
+ if (bmpForMask) delete bmpForMask;
+ }
+ } data;
+
+ if (OnNewFile)
+ OnNewFile(it.first, imgItem.OrgSize, imgItem.Name.AsStdString());
+
+ // main part
+ handler->Load(handler->FormatData, &data,
+ [](void *callbackdata, tjs_uint w, tjs_uint h, tTVPGraphicPixelFormat fmt)->int{
+ BmpInfoWithMask * data = (BmpInfoWithMask *)callbackdata;
+ if (!data->bmp) {
+ data->bmp = new tTVPBitmap(w, h, 32);
+ }
+ return data->bmp->GetPitch();
+ }, [](void *callbackdata, tjs_int y)->void* {
+ BmpInfoWithMask * data = (BmpInfoWithMask *)callbackdata;
+ if (y >= 0) {
+ return data->bmp->GetScanLine(y);
+ }
+ return nullptr;
+ }, [](void *callbackdata, const ttstr & name, const ttstr & value) {
+ BmpInfoWithMask * data = (BmpInfoWithMask *)callbackdata;
+ data->metainfo.emplace(name, value);
+ }, strImg.get(), TVP_clNone, glmNormal);
+
+ // mask part
+ handler->Load(handler->FormatData, &data,
+ [](void *callbackdata, tjs_uint w, tjs_uint h, tTVPGraphicPixelFormat fmt)->int {
+ BmpInfoWithMask * data = (BmpInfoWithMask *)callbackdata;
+ if (data->bmp->GetWidth() != w || data->bmp->GetHeight() != h)
+ TVPThrowExceptionMessage(TVPMaskSizeMismatch);
+ if (!data->bmpForMask) {
+ data->bmpForMask = new tTVPBitmap(w, h, 8);
+ }
+ return data->bmpForMask->GetPitch();
+ }, [](void *callbackdata, tjs_int y)->void* {
+ BmpInfoWithMask * data = (BmpInfoWithMask *)callbackdata;
+ if (y >= 0) {
+ return data->bmpForMask->GetScanLine(y);
+ }
+ return nullptr;
+ }, [](void *callbackdata, const ttstr & name, const ttstr & value) {
+ // no metainfo for mask
+ }, strMask.get(), TVP_clNone, glmGrayscale);
+
+ for (tjs_uint y = 0; y < data.bmp->GetHeight(); ++y) {
+ TVPBindMaskToMain((tjs_uint32*)data.bmp->GetScanLine(y), (tjs_uint8*)data.bmpForMask->GetScanLine(y), data.bmp->GetWidth());
+ }
+ delete data.bmpForMask;
+ data.bmpForMask = nullptr;
+ ncbDictionaryAccessor meta;
+ for (const auto &it : data.metainfo) {
+ meta.SetValue(it.first.c_str(), it.second);
+ }
+ tTVPMemoryStream memstr;
+ tTVPBaseBitmap *bmp = new tTVPBaseBitmap(data.bmp->GetWidth(), data.bmp->GetHeight());
+ bmp->AssignBitmap(data.bmp);
+
+ if (OptionUsingETC2) {
+ TVPSavePVRv3(nullptr, &memstr, bmp, TJS_W("ETC2_RGBA"), meta.GetDispatch());
+ } else {
+ // convert to tlg5 for better performance
+ TVPSaveAsTLG(nullptr, &memstr, bmp, TJS_W("tlg5"), meta.GetDispatch());
+ }
+ delete bmp;
+ memstr.SetPosition(0);
+ HRESULT ret = AddTo7zArchive(&memstr, imgItem.Name);
+ if (OnProgress) {
+ uint64_t size = imgItem.OrgSize + maskItem.OrgSize;
+ nArcSize += size;
+ nTotalSize += size;
+ OnProgress(nTotalSize, nArcSize, size);
+ }
+ if (ret != S_OK) {
+ if (ret != S_INTERRUPT && OnError) {
+ OnError(ret, "Write to file fail.");
}
+ bStopRequired = true;
+ break;
+ }
+ }
+ for (tjs_uint idx : filelist) {
+ const tTVPXP3Archive::tArchiveItem& item = xp3arc->ItemVector[idx];
+
+ if (bStopRequired) break;
+ std::auto_ptr s(xp3arc->CreateStreamByIndex(idx));
+
+ if (OnNewFile)
+ OnNewFile(&item - &xp3arc->ItemVector.front(), item.OrgSize, item.Name.AsStdString());
- SequentialInStreamFor7z str(s.get());
- tjs_uint64 origSize = s->GetSize();
- UInt64 inSizeForReduce = origSize;
- UInt64 newSize = origSize;
- bool compressable = origSize > 64 && origSize < 4 * 1024 * 1024;
- if (compressable) {
- // compressable quick check
- tjs_uint8 header[16];
- s->Read(header, 16);
- if (!memcmp(header, "\x89PNG", 4)) {
- compressable = false;
- } else if (!memcmp(header, "OggS\x00", 5)) {
- compressable = false;
- } else if (!memcmp(header, "\xFF\xD8\xFF", 3)) { // JPEG
- compressable = false;
- } else if (!memcmp(header, "TLG", 3)) {
- compressable = false;
- } else if (!memcmp(header, "0&\xB2\x75\x8E\x66\xCF\x11", 8)) { // wmv/wma
- compressable = false;
- } else if (!memcmp(header, "AJPM", 4)) { // AMV
- compressable = false;
- } else if (!memcmp(header, "\x49\x49\xbc\x01", 4)) { // JXR
- compressable = false;
- } else if (!memcmp(header, "BPG", 3)) {
- compressable = false;
- } else if (!memcmp(header, "RIFF", 4)) {
- if (!memcmp(header + 8, "WEBPVP8", 7)) {
- compressable = false;
+ if (OptionUsingETC2 && item.OrgSize > 8192) {
+ // convert image > 8k
+ bool isImage = CheckIsImage(s.get());
+ int width = 0, height = 0;
+ struct BmpInfo {
+ tTVPBitmap* bmp = nullptr;
+ std::unordered_map metainfo;
+ tTVPGraphicPixelFormat fmt = gpfLuminance;
+ ~BmpInfo() {
+ if (bmp) delete bmp;
+ }
+ } data;
+
+ if (isImage) {
+ // main part
+ handler->Load(handler->FormatData, &data,
+ [](void *callbackdata, tjs_uint w, tjs_uint h, tTVPGraphicPixelFormat fmt)->int {
+ BmpInfo * data = (BmpInfo *)callbackdata;
+ if (!data->bmp) {
+ data->bmp = new tTVPBitmap(w, h, 32);
+ data->fmt = fmt;
+ }
+ return data->bmp->GetPitch();
+ }, [](void *callbackdata, tjs_int y)->void* {
+ BmpInfo * data = (BmpInfo *)callbackdata;
+ if (y >= 0) {
+ return data->bmp->GetScanLine(y);
}
+ return nullptr;
+ }, [](void *callbackdata, const ttstr & name, const ttstr & value) {
+ BmpInfo * data = (BmpInfo *)callbackdata;
+ data->metainfo.emplace(name, value);
+ }, s.get(), TVP_clNone, glmNormal);
+
+ // skip 8-bit image
+ if (data.fmt != gpfRGB || data.fmt != gpfRGBA) {
+ isImage = false;
}
- s->SetPosition(0);
}
- if (compressable) {
- UInt64 expectedSize = origSize * 4 / 5;
- OutStreamMemory tmp;
- coder.Coder->Code(&str, &tmp, &inSizeForReduce, &newSize, nullptr);
- if (tmp.GetSize() < expectedSize) {
- UInt32 writed;
- strout->Write(tmp.GetInternalBuffer(), tmp.GetSize(), &writed);
- newDatabase.PackSizes.Add(tmp.GetSize());
- newDatabase.CoderUnpackSizes.Add(origSize);
- newDatabase.NumUnpackStreamsVector.Add(1);
- CFolder &folder = newDatabase.Folders.AddNew();
- folder.Bonds.SetSize(0);
- folder.Coders.SetSize(1);
- CCoderInfo &cod = folder.Coders[0];
- cod.MethodID = nCodecMethod;
- cod.NumStreams = 1;
- cod.Props = props;
- folder.PackStreams.SetSize(1);
- folder.PackStreams[0] = 0; // only 1 stream
- newDatabase.AddFile(file, file2, name);
- continue;
+ if (isImage) {
+ tTVPBaseBitmap *bmp = new tTVPBaseBitmap(data.bmp->GetWidth(), data.bmp->GetHeight());
+ bmp->AssignBitmap(data.bmp);
+ s.reset(new tTVPMemoryStream);
+ ncbDictionaryAccessor meta;
+ for (const auto &it : data.metainfo) {
+ meta.SetValue(it.first.c_str(), it.second);
}
+ TVPSavePVRv3(nullptr, s.get(), bmp,
+ data.fmt == gpfRGB ? TJS_W("ETC2_RGB") : TJS_W("ETC2_RGBA"),
+ meta.GetDispatch());
+ delete bmp;
s->SetPosition(0);
}
- // direct copy
- newSize = origSize;
- coderCopy.Coder->Code(&str, strout, &inSizeForReduce, &newSize, nullptr);
- newDatabase.PackSizes.Add(s->GetSize());
- newDatabase.CoderUnpackSizes.Add(origSize);
- newDatabase.NumUnpackStreamsVector.Add(1);
- CFolder &folder = newDatabase.Folders.AddNew();
- folder.Bonds.SetSize(0);
- folder.Coders.SetSize(1);
- CCoderInfo &cod = folder.Coders[0];
- cod.MethodID = nCodecMethodCopy;
- cod.NumStreams = 1;
- folder.PackStreams.SetSize(1);
- folder.PackStreams[0] = 0; // only 1 stream
- newDatabase.AddFile(file, file2, name);
+ }
+ HRESULT ret = AddTo7zArchive(s.get(), item.Name);
+ nArcSize += item.OrgSize;
+ nTotalSize += item.OrgSize;
+ if (ret != S_OK) {
+ if (ret != S_INTERRUPT && OnError) {
+ OnError(ret, "Write to file fail.");
+ }
+ bStopRequired = true;
+ break;
}
}
+ if (bStopRequired)
+ break;
CCompressionMethodMode mode;
CHeaderOptions hdropt;
hdropt.CompressMainHeader = true;
archive.WriteDatabase(newDatabase, &mode, hdropt);
archive.Close();
+ strout = nullptr;
delete xp3arc;
+ it.first = nullptr;
remove(it.second.c_str());
rename(tmpname.c_str(), it.second.c_str());
}
- ConvFileList.clear();
+ Clear();
+ if (OnEnded) OnEnded();
}
diff --git a/src/core/environ/XP3ArchiveRepack.h b/src/core/environ/XP3ArchiveRepack.h
index e0f76f53..49b50724 100644
--- a/src/core/environ/XP3ArchiveRepack.h
+++ b/src/core/environ/XP3ArchiveRepack.h
@@ -1,20 +1,27 @@
#pragma once
#include
#include
+#include
-class tTVPXP3ArchiveEx;
+class XP3ArchiveRepackAsyncImpl;
class XP3ArchiveRepackAsync {
- std::vector > ConvFileList;
- void * /*std::thread*/ Thread = nullptr;
public:
- XP3ArchiveRepackAsync(const std::string &xp3filter);
+ XP3ArchiveRepackAsync();
~XP3ArchiveRepackAsync();
- uint64_t AddTask(const std::string &src/*, const std::string &dst*/);
- void Clear();
+ uint64_t AddTask(const std::string &src);
void Start();
- void DoConv();
-
-public:
- bool UsingETC2 = false;
+ void Stop();
+ void SetXP3Filter(const std::string &xp3filter);
+ void SetCallback(
+ const std::function &onNewFile,
+ const std::function &onNewArchive,
+ const std::function &onProgress,
+ const std::function &onError,
+ const std::function &onEnded);
+
+ void SetOption(const std::string &name, bool v);
+
+private:
+ XP3ArchiveRepackAsyncImpl *_impl;
};
diff --git a/src/core/environ/android/AndroidUtils.cpp b/src/core/environ/android/AndroidUtils.cpp
index 2c494bfc..db4faa96 100644
--- a/src/core/environ/android/AndroidUtils.cpp
+++ b/src/core/environ/android/AndroidUtils.cpp
@@ -696,28 +696,64 @@ bool TVPCreateFolders(const ttstr &folder)
return false;
}
-bool TVPWriteDataToFile(const ttstr &filepath, const void *data, unsigned int size) {
- std::string filename = filepath.AsStdString();
-// int Handle = open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
-// if (Handle >= 0) {
-// bool ret = write(Handle, data, size) == size;
-// close(Handle);
-// return ret;
-// }
+static bool TVPWriteDataToFileJava(const std::string &filename, const void* data, unsigned int size) {
JniMethodInfo methodInfo;
if (JniHelper::getStaticMethodInfo(methodInfo, "org/tvp/kirikiri2/KR2Activity", "WriteFile", "(Ljava/lang/String;[B)Z")) {
- jstring jstr = methodInfo.env->NewStringUTF(filename.c_str());
- jbyteArray arr = methodInfo.env->NewByteArray(size);
- methodInfo.env->SetByteArrayRegion(arr, 0, size, (jbyte*)data);
- bool ret = methodInfo.env->CallStaticBooleanMethod(methodInfo.classID, methodInfo.methodID, jstr, arr);
- methodInfo.env->DeleteLocalRef(arr);
- methodInfo.env->DeleteLocalRef(jstr);
- methodInfo.env->DeleteLocalRef(methodInfo.classID);
+ cocos2d::FileUtils *fileutil = cocos2d::FileUtils::getInstance();
+ bool ret = false;
+ do { // write files until file not exist
+ jstring jstr = methodInfo.env->NewStringUTF(filename.c_str());
+ jbyteArray arr = methodInfo.env->NewByteArray(size);
+ methodInfo.env->SetByteArrayRegion(arr, 0, size, (jbyte*)data);
+ bool ret = methodInfo.env->CallStaticBooleanMethod(methodInfo.classID, methodInfo.methodID, jstr, arr);
+ methodInfo.env->DeleteLocalRef(arr);
+ methodInfo.env->DeleteLocalRef(jstr);
+ methodInfo.env->DeleteLocalRef(methodInfo.classID);
+ } while (!fileutil->isFileExist(filename));
return ret;
}
return false;
}
+bool TVPWriteDataToFile(const ttstr &filepath, const void *data, unsigned int size) {
+ cocos2d::FileUtils *fileutil = cocos2d::FileUtils::getInstance();
+ std::string filename = filepath.AsStdString();
+ if (fileutil->isFileExist(filename)) {
+ // for number filename suffix issue
+ time_t t = time(nullptr);
+ std::vector buffer;
+ buffer.resize(filename.size() + 32);
+ sprintf(&buffer.front(), "%s.%d.bak", filename.c_str(), (int)t);
+ std::string tempname = &buffer.front();
+ if (rename(filename.c_str(), tempname.c_str()) == 0) {
+ // file api is OK
+ FILE *fp = fopen(filename.c_str(), "wb");
+ if (fp) {
+ bool ret = fwrite(data, 1, size, fp) == size;
+ fclose(fp);
+ ret = (remove(tempname.c_str()) == 0) && ret;
+ return ret;
+ }
+ }
+ while (fileutil->isFileExist(filename)) {
+ if (!TVPRenameFile(filename, tempname)) {
+ return false;
+ }
+ }
+ bool ret = TVPWriteDataToFileJava(filename, data, size);
+ ret = TVPDeleteFile(tempname) && ret;
+ return ret;
+ }
+ FILE *fp = fopen(filename.c_str(), "wb");
+ if (fp) {
+ // file api is OK
+ int writed = fwrite(data, 1, size, fp);
+ fclose(fp);
+ return writed == size;
+ }
+ return TVPWriteDataToFileJava(filename, data, size);
+}
+
std::string TVPGetCurrentLanguage() {
JniMethodInfo t;
std::string ret("");
diff --git a/src/core/environ/cocos2d/AppDelegate.cpp b/src/core/environ/cocos2d/AppDelegate.cpp
index b6638a43..eb9dd55f 100644
--- a/src/core/environ/cocos2d/AppDelegate.cpp
+++ b/src/core/environ/cocos2d/AppDelegate.cpp
@@ -9,13 +9,14 @@
#include "Platform.h"
#include "ui/MessageBox.h"
#include "ui/GlobalPreferenceForm.h"
+#include "CustomFileUtils.h"
USING_NS_CC;
static Size designResolutionSize(960, 640);
bool TVPCheckStartupArg();
std::string TVPGetCurrentLanguage();
-cocos2d::FileUtils *TVPCreateCustomFileUtils();
+cocos2d::CustomFileUtils *TVPCreateCustomFileUtils();
void TVPAppDelegate::applicationWillEnterForeground() {
::Application->OnActivate();
@@ -30,7 +31,8 @@ void TVPAppDelegate::applicationDidEnterBackground() {
bool TVPAppDelegate::applicationDidFinishLaunching() {
cocos2d::log("applicationDidFinishLaunching");
// initialize director
- FileUtils::setDelegate(TVPCreateCustomFileUtils());
+ cocos2d::CustomFileUtils *fileutil = TVPCreateCustomFileUtils();
+ FileUtils::setDelegate(fileutil);
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if (!glview) {
@@ -56,6 +58,15 @@ bool TVPAppDelegate::applicationDidFinishLaunching() {
// this can make sure that the resource's height could fit for the height of design resolution.
searchPath.emplace_back("res");
+ std::string skinpath = GlobalConfigManager::GetInstance()->GetValue("skin_path", "");
+ if (!skinpath.empty()) {
+ if (!fileutil->isFileExist(skinpath)) {
+ GlobalConfigManager::GetInstance()->SetValue("skin_path", "");
+ } else {
+ fileutil->addAutoSearchArchive(skinpath);
+ }
+ }
+
// set searching path
FileUtils::getInstance()->setSearchPaths(searchPath);
diff --git a/src/core/environ/cocos2d/CustomFileUtils.cpp b/src/core/environ/cocos2d/CustomFileUtils.cpp
index f97e15cb..22cfca6c 100644
--- a/src/core/environ/cocos2d/CustomFileUtils.cpp
+++ b/src/core/environ/cocos2d/CustomFileUtils.cpp
@@ -1,52 +1,7 @@
-#include "cocos2d.h"
-#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
-#include "platform/win32/CCFileUtils-win32.h"
-#elif CC_TARGET_PLATFORM == CC_PLATFORM_IOS
-#import
-#import "platform/apple/CCFileUtils-apple.h"
-#elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
-#include "platform/android/CCFileUtils-android.h"
-#endif
-#ifdef MINIZIP_FROM_SYSTEM
-#include
-#else // from our embedded sources
-#include "external/unzip/unzip.h"
-#endif
+#include "CustomFileUtils.h"
NS_CC_BEGIN
-typedef
-#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
-FileUtilsWin32
-#elif CC_TARGET_PLATFORM == CC_PLATFORM_IOS
-FileUtilsApple
-#elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
-FileUtilsAndroid
-#endif
-FileUtilsInherit;
-class CustomFileUtils : public FileUtilsInherit
-{
-public:
- CustomFileUtils();
-
- void addAutoSearchArchive(const std::string& path);
- virtual std::string fullPathForFilename(const std::string &filename) const override;
- virtual std::string getStringFromFile(const std::string& filename) override;
- virtual Data getDataFromFile(const std::string& filename) override;
- virtual unsigned char* getFileData(const std::string& filename, const char* mode, ssize_t *size) override;
- virtual bool isFileExistInternal(const std::string& strFilePath) const override;
- virtual bool isDirectoryExistInternal(const std::string& dirPath) const override;
- virtual bool init() override {
- return FileUtilsInherit::init();
- }
-
-private:
- unsigned char* getFileDataFromArchive(const std::string& filename, ssize_t *size);
-
- std::unordered_map > _autoSearchArchive;
- std::mutex _lock;
-};
-
CustomFileUtils::CustomFileUtils()
{
}
@@ -146,7 +101,7 @@ std::string CustomFileUtils::getStringFromFile(const std::string& filename)
NS_CC_END
-cocos2d::FileUtils *TVPCreateCustomFileUtils() {
+cocos2d::CustomFileUtils *TVPCreateCustomFileUtils() {
cocos2d::CustomFileUtils *ret = new cocos2d::CustomFileUtils;
ret->init();
return ret;
diff --git a/src/core/environ/cocos2d/CustomFileUtils.h b/src/core/environ/cocos2d/CustomFileUtils.h
new file mode 100644
index 00000000..f1046ca4
--- /dev/null
+++ b/src/core/environ/cocos2d/CustomFileUtils.h
@@ -0,0 +1,52 @@
+#pragma once
+#include "cocos2d.h"
+#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
+#include "platform/win32/CCFileUtils-win32.h"
+#elif CC_TARGET_PLATFORM == CC_PLATFORM_IOS
+#import
+#import "platform/apple/CCFileUtils-apple.h"
+#elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
+#include "platform/android/CCFileUtils-android.h"
+#endif
+#ifdef MINIZIP_FROM_SYSTEM
+#include
+#else // from our embedded sources
+#include "external/unzip/unzip.h"
+#endif
+
+NS_CC_BEGIN
+
+typedef
+#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
+FileUtilsWin32
+#elif CC_TARGET_PLATFORM == CC_PLATFORM_IOS
+FileUtilsApple
+#elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
+FileUtilsAndroid
+#endif
+FileUtilsInherit;
+
+class CustomFileUtils : public FileUtilsInherit
+{
+public:
+ CustomFileUtils();
+
+ void addAutoSearchArchive(const std::string& path);
+ virtual std::string fullPathForFilename(const std::string &filename) const override;
+ virtual std::string getStringFromFile(const std::string& filename) override;
+ virtual Data getDataFromFile(const std::string& filename) override;
+ virtual unsigned char* getFileData(const std::string& filename, const char* mode, ssize_t *size) override;
+ virtual bool isFileExistInternal(const std::string& strFilePath) const override;
+ virtual bool isDirectoryExistInternal(const std::string& dirPath) const override;
+ virtual bool init() override {
+ return FileUtilsInherit::init();
+ }
+
+private:
+ unsigned char* getFileDataFromArchive(const std::string& filename, ssize_t *size);
+
+ std::unordered_map > _autoSearchArchive;
+ std::mutex _lock;
+};
+
+NS_CC_END
\ No newline at end of file
diff --git a/src/core/environ/linux/Platform.cpp b/src/core/environ/linux/Platform.cpp
index b49ca628..381fc0a0 100644
--- a/src/core/environ/linux/Platform.cpp
+++ b/src/core/environ/linux/Platform.cpp
@@ -70,4 +70,13 @@ void TVPGetMemoryInfo(TVPMemoryInfo &m)
#include
void TVPRelinquishCPU(){
sched_yield();
-}
\ No newline at end of file
+}
+
+void TVP_utime(const char *name, time_t modtime) {
+ timeval mt[2];
+ mt[0].tv_sec = modtime;
+ mt[0].tv_usec = 0;
+ mt[1].tv_sec = modtime;
+ mt[1].tv_usec = 0;
+ utimes(name, mt);
+}
diff --git a/src/core/environ/ui/BaseForm.cpp b/src/core/environ/ui/BaseForm.cpp
index 1eca06fb..63ee8fbd 100644
--- a/src/core/environ/ui/BaseForm.cpp
+++ b/src/core/environ/ui/BaseForm.cpp
@@ -238,7 +238,7 @@ void iTVPFloatForm::rearrangeLayout()
RootNode->setContentSize(sceneSize);
ui::Helper::doLayout(RootNode);
RootNode->setScale(scale);
- RootNode->setAnchorPoint(sceneSize / 2);
+ RootNode->setAnchorPoint(Vec2(0.5f, 0.5f));
RootNode->setPosition(center);
}
}
diff --git a/src/core/environ/ui/FileSelectorForm.cpp b/src/core/environ/ui/FileSelectorForm.cpp
index d2122946..ee92721b 100644
--- a/src/core/environ/ui/FileSelectorForm.cpp
+++ b/src/core/environ/ui/FileSelectorForm.cpp
@@ -13,6 +13,8 @@
#include "base/CCDirector.h"
#include "MessageBox.h"
#include "platform/CCDevice.h"
+#include "base/CCScheduler.h"
+#include "utils/TickCount.h"
using namespace cocos2d;
using namespace cocos2d::extension;
@@ -219,7 +221,6 @@ void TVPBaseFileSelectorForm::onCellLongPress(int idx)
LocaleConfigManager::GetInstance()->initText(reader.findController("titleCut"));
LocaleConfigManager::GetInstance()->initText(reader.findController("titlePaste"));
LocaleConfigManager::GetInstance()->initText(reader.findController("titleUnpack"));
- LocaleConfigManager::GetInstance()->initText(reader.findController("titleRepack", false));
LocaleConfigManager::GetInstance()->initText(reader.findController("titleDelete"));
LocaleConfigManager::GetInstance()->initText(reader.findController("titleSendTo"));
_fileOperateMenulist = reader.findController("list");
@@ -229,7 +230,6 @@ void TVPBaseFileSelectorForm::onCellLongPress(int idx)
_fileOperateCell_cut = reader.findWidget("cut");
_fileOperateCell_paste = reader.findWidget("paste");
_fileOperateCell_delete = reader.findWidget("delete");
- _fileOperateCell_repack = reader.findWidget("repack", false);
_fileOperateCell_unpack = reader.findWidget("unpack", false);
_fileOperateCell_sendto = reader.findWidget("sendto");
Widget *btn;;
@@ -251,9 +251,6 @@ void TVPBaseFileSelectorForm::onCellLongPress(int idx)
if ((btn = reader.findWidget("btnUnpack", false))) {
btn->addClickEventListener(std::bind(&TVPBaseFileSelectorForm::onUnpackClicked, this, std::placeholders::_1));
}
- if ((btn = reader.findWidget("btnRepack", false))) {
- btn->addClickEventListener(std::bind(&TVPBaseFileSelectorForm::onRepackClicked, this, std::placeholders::_1));
- }
if ((btn = reader.findWidget("btnDelete"))) {
btn->addClickEventListener(std::bind(&TVPBaseFileSelectorForm::onDeleteClicked, this, std::placeholders::_1));
}
@@ -485,14 +482,143 @@ void TVPBaseFileSelectorForm::onPasteClicked(cocos2d::Ref *owner)
void TVPBaseFileSelectorForm::onUnpackClicked(cocos2d::Ref *owner)
{
-
+ if (_selectedFileIndex.size() != 1) {
+ return;
+ }
+ FileInfo &info = CurrentDirList[*_selectedFileIndex.begin()];
+ _selectedFileIndex.clear();
clearFileMenu();
-}
+ ttstr outpath = TVPChopStorageExt(info.FullPath);
-void TVPBaseFileSelectorForm::onRepackClicked(cocos2d::Ref *owner)
-{
+ class UnpackArchive {
+ const int UpdateMS = 100; // update rate 10 fps
+ tTVPUnpackArchive ArcUnpacker;
- clearFileMenu();
+ public:
+ bool Init(const std::string &path, const std::string &outpath) {
+ if (ArcUnpacker.Prepare(path, outpath, &TotalSize) <= 0) {
+ return false;
+ }
+ if (TotalSize > 1024 * 1024) {
+ ProgressForm = TVPSimpleProgressForm::create();
+ TVPMainScene::GetInstance()->pushUIForm(ProgressForm, TVPMainScene::eEnterAniNone);
+ std::vector > > vecButtons;
+ vecButtons.emplace_back("Stop", [this](Ref*) {
+ ArcUnpacker.Stop();
+ });
+ ProgressForm->initButtons(vecButtons);
+ ProgressForm->setTitle("Unpacking...");
+ ProgressForm->setPercentOnly(0);
+ ProgressForm->setPercentOnly2(0);
+ ProgressForm->setPercentText("");
+ ProgressForm->setPercentText2("");
+ ProgressForm->setContent("");
+ }
+ ArcUnpacker.SetCallback(
+ std::bind(&UnpackArchive::OnEnded, this),
+ std::bind(&UnpackArchive::OnError, this, std::placeholders::_1, std::placeholders::_2),
+ std::bind(&UnpackArchive::OnProgress, this, std::placeholders::_1, std::placeholders::_2),
+ std::bind(&UnpackArchive::OnNewFile, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)
+ );
+ return true;
+ }
+ virtual ~UnpackArchive() {
+ if (ProgressForm) {
+ TVPMainScene::GetInstance()->popUIForm(ProgressForm, TVPMainScene::eLeaveAniNone);
+ ProgressForm = nullptr;
+ }
+ }
+ void Start(const std::function &onEnded) {
+ FuncOnEnded = onEnded;
+ ArcUnpacker.Start();
+ }
+
+ private:
+ void OnEnded() {
+ Director::getInstance()->getScheduler()->performFunctionInCocosThread([this] {
+ if (FuncOnEnded)
+ FuncOnEnded();
+ delete this;
+ });
+ }
+ void OnError(int err, const char *msg) {
+ Director::getInstance()->getScheduler()->performFunctionInCocosThread([this, err, msg] {
+ char buf[64];
+ sprintf(buf, "Error %d\n", err);
+ ttstr strmsg(buf);
+ strmsg += msg;
+ TVPShowSimpleMessageBox(strmsg, TJS_W("Fail to unpack archive"));
+ });
+ }
+ void OnProgress(tjs_uint64 total_size, tjs_uint64 file_size) {
+ if (!ProgressForm) return;
+ tjs_uint32 tick = TVPGetRoughTickCount32();
+ if ((int)(tick - LastUpdate) < UpdateMS) {
+ return;
+ }
+ LastUpdate = tick;
+ Director::getInstance()->getScheduler()->performFunctionInCocosThread([this, total_size, file_size] {
+ ProgressForm->setPercentOnly((float)total_size / TotalSize);
+ ProgressForm->setPercentOnly2((float)file_size / CurrentFileSize);
+ char buf[64];
+ int sizeMB = static_cast(total_size / (1024 * 1024)),
+ totalMB = static_cast(TotalSize / (1024 * 1024));
+ sprintf(buf, "%d / %dMB", sizeMB, totalMB);
+ ProgressForm->setPercentText(buf);
+ sizeMB = static_cast(file_size / (1024 * 1024));
+ totalMB = static_cast(CurrentFileSize / (1024 * 1024));
+ sprintf(buf, "%d / %dMB", sizeMB, totalMB);
+ ProgressForm->setPercentText2(buf);
+ });
+ }
+ void OnNewFile(int idx, const char * utf8name, tjs_uint64 file_size) {
+ if (!ProgressForm) return;
+ tjs_uint32 tick = TVPGetRoughTickCount32();
+ if ((int)(tick - LastUpdate) < UpdateMS && file_size < 1024 * 1024) {
+ return;
+ }
+ LastUpdate = tick;
+ CurrentFileSize = file_size;
+ std::string filename(utf8name);
+ Director::getInstance()->getScheduler()->performFunctionInCocosThread([this, filename] {
+ ProgressForm->setContent(filename);
+ });
+ }
+
+ TVPSimpleProgressForm *ProgressForm = nullptr;
+ tjs_uint32 LastUpdate = 0;
+ tjs_uint64 TotalSize, CurrentFileSize;
+ std::function FuncOnEnded;
+ };
+ UnpackArchive *unpacker = new UnpackArchive;
+ // using libarchive to unpack archive
+ if (unpacker->Init(info.FullPath, outpath.AsStdString())) {
+ unpacker->Start([this]() {
+ ListDir(CurrentPath);
+ });
+ return;
+ }
+ delete unpacker;
+
+ // use internal archive module
+ tTVPArchive *arc = TVPOpenArchive(info.FullPath, false);
+ if (!arc) {
+ LocaleConfigManager *localeMgr = LocaleConfigManager::GetInstance();
+ TVPShowSimpleMessageBox(info.FullPath, localeMgr->GetText("fail_to_open_archive"));
+ return;
+ }
+
+ tjs_uint count = arc->GetCount();
+ for (tjs_uint i = 0; i < count; ++i) {
+ ttstr name = arc->GetName(i);
+ ttstr fullpath = outpath + name;
+ tTJSBinaryStream *st = arc->CreateStreamByIndex(i);
+ if (!st) continue;
+ TVPSaveStreamToFile(st, 0, st->GetSize(), fullpath);
+ delete st;
+ }
+
+ delete arc;
}
void TVPBaseFileSelectorForm::onDeleteClicked(cocos2d::Ref *owner)
@@ -540,8 +666,7 @@ void TVPBaseFileSelectorForm::updateFileMenu()
}
if (_selectedFileIndex.size() == 1) {
if (_fileOperateCell_view) _fileOperateMenulist->pushBackCustomItem(_fileOperateCell_view.get());
- // _fileOperateMenulist->pushBackCustomItem(_fileOperateCell_unpack.get());
- // _fileOperateMenulist->pushBackCustomItem(_fileOperateCell_repack.get());
+ _fileOperateMenulist->pushBackCustomItem(_fileOperateCell_unpack.get());
// _fileOperateMenulist->pushBackCustomItem(_fileOperateCell_sendto.get());
}
if (!_selectedFileIndex.empty()) {
diff --git a/src/core/environ/ui/FileSelectorForm.h b/src/core/environ/ui/FileSelectorForm.h
index b7b8c796..e069fca2 100644
--- a/src/core/environ/ui/FileSelectorForm.h
+++ b/src/core/environ/ui/FileSelectorForm.h
@@ -73,7 +73,6 @@ class TVPBaseFileSelectorForm : public iTVPBaseForm, public cocos2d::extension::
void onCutClicked(cocos2d::Ref *owner);
void onPasteClicked(cocos2d::Ref *owner);
void onUnpackClicked(cocos2d::Ref *owner);
- void onRepackClicked(cocos2d::Ref *owner);
void onDeleteClicked(cocos2d::Ref *owner);
void onSendToClicked(cocos2d::Ref *owner);
void updateFileMenu();
diff --git a/src/core/environ/ui/GlobalPreferenceForm.cpp b/src/core/environ/ui/GlobalPreferenceForm.cpp
index 85aa690a..55863b07 100644
--- a/src/core/environ/ui/GlobalPreferenceForm.cpp
+++ b/src/core/environ/ui/GlobalPreferenceForm.cpp
@@ -13,7 +13,24 @@ using namespace cocos2d::ui;
const char * const FileName_NaviBar = "ui/NaviBar.csb";
const char * const FileName_Body = "ui/ListView.csb";
-
+static bool PreferenceGetValueBool(const std::string &name, bool defval) {
+ return GlobalConfigManager::GetInstance()->GetValue(name, defval);
+}
+static void PreferenceSetValueBool(const std::string &name, bool v) {
+ GlobalConfigManager::GetInstance()->SetValueInt(name, v);
+}
+static std::string PreferenceGetValueString(const std::string &name, const std::string& defval) {
+ return GlobalConfigManager::GetInstance()->GetValue(name, defval);
+}
+static void PreferenceSetValueString(const std::string &name, const std::string& v) {
+ GlobalConfigManager::GetInstance()->SetValue(name, v);
+}
+static float PreferenceGetValueFloat(const std::string &name, float defval) {
+ return GlobalConfigManager::GetInstance()->GetValue(name, defval);
+}
+static void PreferenceSetValueFloat(const std::string &name, float v) {
+ GlobalConfigManager::GetInstance()->SetValueFloat(name, v);
+}
#include "PreferenceConfig.h"
TVPGlobalPreferenceForm * TVPGlobalPreferenceForm::create(const tPreferenceScreen *config) {
diff --git a/src/core/environ/ui/IndividualPreferenceForm.cpp b/src/core/environ/ui/IndividualPreferenceForm.cpp
index 0daee1a4..129d2515 100644
--- a/src/core/environ/ui/IndividualPreferenceForm.cpp
+++ b/src/core/environ/ui/IndividualPreferenceForm.cpp
@@ -13,13 +13,29 @@ using namespace cocos2d::ui;
const char * const FileName_NaviBar = "ui/NaviBar.csb";
const char * const FileName_Body = "ui/ListView.csb";
-#define GlobalConfigManager IndividualConfigManager
#define TVPGlobalPreferenceForm IndividualPreferenceForm
+static bool PreferenceGetValueBool(const std::string &name, bool defval) {
+ return IndividualConfigManager::GetInstance()->GetValue(name, defval);
+}
+static void PreferenceSetValueBool(const std::string &name, bool v) {
+ IndividualConfigManager::GetInstance()->SetValueInt(name, v);
+}
+static std::string PreferenceGetValueString(const std::string &name, const std::string& defval) {
+ return IndividualConfigManager::GetInstance()->GetValue(name, defval);
+}
+static void PreferenceSetValueString(const std::string &name, const std::string& v) {
+ IndividualConfigManager::GetInstance()->SetValue(name, v);
+}
+static float PreferenceGetValueFloat(const std::string &name, float defval) {
+ return IndividualConfigManager::GetInstance()->GetValue(name, defval);
+}
+static void PreferenceSetValueFloat(const std::string &name, float v) {
+ IndividualConfigManager::GetInstance()->SetValueFloat(name, v);
+}
#include "PreferenceConfig.h"
#undef TVPGlobalPreferenceForm
-#undef GlobalConfigManager
static void initInividualConfig() {
if (!RootPreference.Preferences.empty()) return;
diff --git a/src/core/environ/ui/MainFileSelectorForm.cpp b/src/core/environ/ui/MainFileSelectorForm.cpp
index f4d8e073..b0057001 100644
--- a/src/core/environ/ui/MainFileSelectorForm.cpp
+++ b/src/core/environ/ui/MainFileSelectorForm.cpp
@@ -19,6 +19,7 @@
#include "tinyxml2/tinyxml2.h"
#include "StorageImpl.h"
#include "TipsHelpForm.h"
+#include "XP3RepackForm.h"
using namespace cocos2d;
using namespace cocos2d::ui;
@@ -108,7 +109,7 @@ static bool _CheckGameFolder(const std::string &path) {
return c - ('A' - 'a');
return c;
});
- int pos = lowername.rfind('.');
+ size_t pos = lowername.rfind('.');
if (pos == lowername.npos) return;
if (lowername.substr(pos) == ".xp3") {
isValidGameFolder = true;
@@ -220,7 +221,8 @@ TVPMainFileSelectorForm * TVPMainFileSelectorForm::create() {
void TVPMainFileSelectorForm::initFromFile()
{
_LoadHistory();
- if (!_HistoryPath.empty()) {
+// if (!_HistoryPath.empty())
+ {
CSBReader reader;
Node *root = reader.Load("ui/MainFileSelector.csb");
_fileList = reader.findController("fileList");
@@ -302,13 +304,14 @@ void TVPMainFileSelectorForm::showMenu(Ref*) {
// captions
LocaleConfigManager *localeMgr = LocaleConfigManager::GetInstance();
- localeMgr->initText(dynamic_cast(reader.findController("titleRotate")));
- localeMgr->initText(dynamic_cast(reader.findController("titleGlobalPref")));
- localeMgr->initText(dynamic_cast(reader.findController("titleNewLocalPref")));
- localeMgr->initText(dynamic_cast(reader.findController("titleLocalPref")));
- localeMgr->initText(dynamic_cast(reader.findController("titleHelp")));
- localeMgr->initText(dynamic_cast(reader.findController("titleAbout")));
- localeMgr->initText(dynamic_cast(reader.findController("titleExit")));
+ localeMgr->initText(reader.findController("titleRotate"));
+ localeMgr->initText(reader.findController("titleGlobalPref"));
+ localeMgr->initText(reader.findController("titleNewLocalPref"));
+ localeMgr->initText(reader.findController("titleLocalPref"));
+ localeMgr->initText(reader.findController("titleHelp"));
+ localeMgr->initText(reader.findController("titleAbout"));
+ localeMgr->initText(reader.findController("titleExit"));
+ localeMgr->initText(reader.findController("titleRepack"));
// button events
reader.findWidget("btnRotate")->addClickEventListener([](Ref*) {
@@ -380,6 +383,10 @@ void TVPMainFileSelectorForm::showMenu(Ref*) {
_AskExit();
});
}
+ reader.findWidget("btnRepack")->addClickEventListener([this](Ref*) {
+ TVPProcessXP3Repack(CurrentPath);
+ hideMenu(nullptr);
+ });
}
const Size &uiSize = getContentSize();
diff --git a/src/core/environ/ui/MessageBox.cpp b/src/core/environ/ui/MessageBox.cpp
index 972c34f6..1781b7dc 100644
--- a/src/core/environ/ui/MessageBox.cpp
+++ b/src/core/environ/ui/MessageBox.cpp
@@ -4,6 +4,7 @@
#include "ui/UIText.h"
#include "ui/UIScrollView.h"
#include "ui/UIHelper.h"
+#include "ui/UILoadingBar.h"
#include "2d/CCLabel.h"
#include "ConfigManager/LocaleConfigManager.h"
@@ -119,3 +120,102 @@ void TVPMessageBoxForm::onKeyPressed(cocos2d::EventKeyboard::KeyCode keyCode, co
}
}
+TVPSimpleProgressForm* TVPSimpleProgressForm::create()
+{
+ TVPSimpleProgressForm* form = new TVPSimpleProgressForm;
+ form->autorelease();
+ form->initFromFile("ui/ProgressBox.csb");
+ return form;
+}
+
+void TVPSimpleProgressForm::initButtons(const std::vector > > &vec)
+{
+ Size btnSize = _btnCell->getContentSize();
+ float totalWidth = 0;
+ float containerWidth = _btnContainer->getContentSize().width;
+ float edge = _btnCell->getPosition().x;
+ containerWidth -= edge * 2;
+ std::vector buttons;
+ float btnEdge = btnSize.width - _btnButton->getTitleRenderer()->getContentSize().width;
+ for (const auto &it : vec) {
+ _btnButton->setTitleText(it.first);
+ _btnButton->addClickEventListener(it.second);
+ btnSize.width = _btnButton->getTitleRenderer()->getContentSize().width + btnEdge;
+ _btnCell->setContentSize(btnSize);
+ ui::Helper::doLayout(_btnCell);
+ totalWidth += btnSize.width;
+ Widget *btn = _btnCell->clone();
+ buttons.push_back(btn);
+ _btnContainer->addChild(btn);
+ }
+ float x = edge;
+ float gap = (containerWidth - totalWidth) / buttons.size();
+ for (Node *btn : buttons) {
+ btn->setPositionX(x);
+ x += btn->getContentSize().width;
+ }
+}
+
+void TVPSimpleProgressForm::setTitle(const std::string &text)
+{
+ _textTitle->setString(text);
+}
+void TVPSimpleProgressForm::setContent(const std::string &text)
+{
+ _textContent->setString(text);
+}
+
+void TVPSimpleProgressForm::setPercentWithText(float percent)
+{
+ _progressBar[0]->setPercent(percent);
+ char tmp[16];
+ sprintf(tmp, "%2.2f%%", percent);
+ _textProgress[0]->setString(tmp);
+}
+void TVPSimpleProgressForm::setPercentWithText2(float percent)
+{
+ _progressBar[1]->setPercent(percent);
+ char tmp[16];
+ sprintf(tmp, "%2.2f%%", percent);
+ _textProgress[1]->setString(tmp);
+}
+
+void TVPSimpleProgressForm::setPercentOnly(float percent)
+{
+ _progressBar[0]->setPercent(percent * 100);
+}
+
+void TVPSimpleProgressForm::setPercentOnly2(float percent)
+{
+ _progressBar[1]->setPercent(percent * 100);
+}
+
+void TVPSimpleProgressForm::setPercentText(const std::string &text)
+{
+ _textProgress[0]->setString(text);
+}
+
+void TVPSimpleProgressForm::setPercentText2(const std::string &text)
+{
+ _textProgress[1]->setString(text);
+}
+
+void TVPSimpleProgressForm::setProgress2Visible(bool visible)
+{
+ // TODO
+}
+
+void TVPSimpleProgressForm::bindBodyController(const NodeMap &allNodes)
+{
+ LocaleConfigManager *localeMgr = LocaleConfigManager::GetInstance();
+ _progressBar[0] = allNodes.findController("progrss_1");
+ _progressBar[1] = allNodes.findController("progrss_2");
+ _textProgress[0] = allNodes.findController("progress_text_1");
+ _textProgress[1] = allNodes.findController("progress_text_2");
+ _textContent = allNodes.findController("text");
+ _textTitle = allNodes.findController("title");
+ _btnContainer = allNodes.findController("btnList");
+ _btnCell = allNodes.findWidget("btnCell");
+ _btnButton = allNodes.findController