├── CMakeLists.txt ├── CMakeLists.txt.user ├── README.md ├── Readme_ru.md ├── android ├── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── res │ ├── drawable-hdpi │ └── icon.png │ ├── drawable-ldpi │ └── icon.png │ ├── drawable-mdpi │ └── icon.png │ ├── drawable-xhdpi │ └── icon.png │ ├── drawable-xxhdpi │ └── icon.png │ ├── drawable-xxxhdpi │ └── icon.png │ ├── values │ └── libs.xml │ └── xml │ └── qtprovider_paths.xml ├── headers ├── mainwindow.h └── processing.h ├── res ├── Pusia-Bold.otf ├── icon.ico ├── rc.rc ├── res.qrc └── translate │ ├── X-coder_ru.qm │ └── X-coder_ru.ts ├── source ├── SWFFile.hpp ├── config.hpp ├── json.hpp ├── main.cpp ├── mainwindow.cpp └── processing.cpp └── ui ├── mainwindow.ui └── processing.ui /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | project(X-coder VERSION 0.1 LANGUAGES CXX) 4 | 5 | set(CMAKE_AUTOUIC ON) 6 | set(CMAKE_AUTOMOC ON) 7 | set(CMAKE_AUTORCC ON) 8 | 9 | set(CMAKE_CXX_STANDARD 17) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network) 13 | find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Qml LinguistTools) 14 | 15 | 16 | set(TS_FILES res/translate/X-coder_ru.ts) 17 | set(PROJECT_SOURCES 18 | source/main.cpp 19 | source/mainwindow.cpp 20 | source/processing.cpp 21 | source/json.hpp 22 | source/SWFFile.hpp 23 | source/config.hpp 24 | headers/mainwindow.h 25 | headers/processing.h 26 | ui/mainwindow.ui 27 | ui/processing.ui 28 | ${TS_FILES} 29 | ) 30 | 31 | if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) 32 | qt_add_executable(X-coder 33 | MANUAL_FINALIZATION 34 | ${PROJECT_SOURCES} 35 | android/AndroidManifest.xml 36 | res/rc.rc 37 | res/res.qrc 38 | ) 39 | endif() 40 | target_link_libraries(X-coder PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt6::Network) 41 | include_directories(headers ui source) 42 | if(${QT_VERSION} VERSION_LESS 6.1.0) 43 | set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.X-coder) 44 | endif() 45 | set_target_properties(X-coder PROPERTIES 46 | ${BUNDLE_ID_OPTION} 47 | MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} 48 | MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} 49 | MACOSX_BUNDLE TRUE 50 | WIN32_EXECUTABLE TRUE 51 | ) 52 | 53 | include(GNUInstallDirs) 54 | install(TARGETS X-coder 55 | BUNDLE DESTINATION . 56 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 57 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 58 | ) 59 | set_property(TARGET X-coder APPEND PROPERTY 60 | QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android 61 | ) 62 | include(FetchContent) 63 | # Adding SupercellFlash 64 | FetchContent_Declare( 65 | SupercellFlash 66 | GIT_REPOSITORY https://github.com/sc-workshop/SupercellFlash.git 67 | GIT_TAG dev 68 | ) 69 | FetchContent_MakeAvailable(SupercellFlash) 70 | 71 | # CPP 17 72 | target_compile_features( 73 | X-coder PRIVATE 74 | cxx_std_17 75 | ) 76 | 77 | target_link_libraries( 78 | X-coder PRIVATE 79 | SupercellFlash 80 | ) 81 | qt6_add_translations(X-coder 82 | TS_FILES ${TS_FILES} 83 | QM_FILES_OUTPUT_VARIABLE qm_files) 84 | #install(FILES ${qm_files} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}) 85 | if (ANDROID) 86 | include(C:/DEV/ANDROID/SDK/android_openssl/android_openssl.cmake) 87 | add_android_openssl_libraries(X-coder) 88 | set_property (TARGET X-coder APPEND PROPERTY 89 | QT_ANDROID_EXTRA_LIBS "C:/DEV/ANDROID/SDK/android_openssl/ssl_3/arm64-v8a/libcrypto_3.so" "C:/DEV/ANDROID/SDK/android_openssl/ssl_3/arm64-v8a/libssl_3.so" "C:/DEV/ANDROID/SDK/android_openssl/ssl_3/armeabi-v7a/libcrypto_3.so" "C:/DEV/ANDROID/SDK/android_openssl/ssl_3/armeabi-v7a/libssl_3.so" 90 | ) 91 | endif() 92 | if(QT_VERSION_MAJOR EQUAL 6) 93 | qt_finalize_executable(X-coder) 94 | endif() 95 | 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # X-coder 2 | [ДЛЯ РУССКИХ](https://github.com/lilmuff2/X-coder/blob/master/Readme_ru.md) 3 | 4 | A tool for decoding (sc to png) and encoding (png to sc) sc files used in Supercell games. 5 | ![Menu](https://github.com/lilmuff2/X-coder/blob/images/new_menu.png?raw=true) 6 | # How to use 7 | 1. Download the version you need from [releases](https://github.com/lilmuff2/X-coder/releases/tag/v2.2 ) (apk - for android, setup.exe - installer for Windows, zip archive with exe for Windows) 8 | 3. Select the desired option (each one is described below) 9 | 5. Select or type the input file or folder 10 | 7. Optionally select either type the out folder or file, or it will be selected automatically !IT WILL BE DELETED! 11 | 8. Press the button at the bottom (not close) and wait 12 | 13 | 14 | # DECODE FILE: 15 | Converts sc to png
16 | Input file - _tex.sc , not .sc! or _dl.sc in rare cases
17 | Starting with the 54th version of brawl stars, zktx files appeared. They need to be placed in the same folder as the input file
18 | Out folder - the folder in which the apg will be saved
19 | 20 | ![Decode example](https://github.com/lilmuff2/X-coder/blob/images/new_decode.png?raw=true) 21 | 22 | # ENCODE FOLDER: 23 | Converts png to sc
24 | Input folder - folder with png and [json file](#json-file)(optionally)
25 | The name of the json file must match the name of the folder
26 | Out file - where to save sc
27 | If you need sc for the old version, change the compression in the json file from Zstandard to Lzma
28 | 29 | ![Encode example](https://github.com/lilmuff2/X-coder/blob/images/new_encode.png?raw=true) 30 | 31 | 32 | # DECODE FILES: 33 | Converts a lot of sc files to png, it is usfull to simply copy the sc folder from the apk and decode them all at once 34 | Input folder - folder with _tex.sc , not .sc! or _dl.sc files
35 | Outfolder - the folder where the folders will be created in which the pngs will be saved
36 | 37 | ![Decode folder example](https://github.com/lilmuff2/X-coder/blob/images/new_decode_folder.png?raw=true) 38 | 39 | 40 | # ENCODE FOLDERS: 41 | Converts many png folders to sc files
42 | Input folder - a folder with folders containing png
43 | Output folder - the folder where the sc files will be saved
44 | 45 | ![Encode folder example](https://github.com/lilmuff2/X-coder/blob/images/new_encode_folder.png?raw=true) 46 | # .json file: 47 | This file generated after decoding example: 48 | ```javascript 49 | { 50 | "Textures": [ 51 | { 52 | "Encoding": "khronos", 53 | "PixelFormat": "RGBA8", 54 | "Filtering": "LINEAR_NEAREST", 55 | "Linear": true 56 | }, 57 | { 58 | "Encoding": "khronos", 59 | "PixelFormat": "RGBA8", 60 | "Filtering": "LINEAR_NEAREST", 61 | "Linear": true 62 | } 63 | ], 64 | "IsDL": false, 65 | "HasZKTX": true, 66 | "Compression": "Zstandard" 67 | } 68 | ``` 69 | 70 | ## Encoding 71 | Can be khronos (low weight) and raw (fast encoding) if HasZKTX enabled textures are encoded in khronos 72 | 73 | Example ui_highres_tex with Zstandard compression: 74 | Encoding | Encoding time | File size 75 | ---|---|--- 76 | khronos | 35 s | 30 MB 77 | raw | 7 s | 41 MB 78 | > I recommend using raw during mod development and khronos on release. 79 | ## HasZKTX 80 | Parameter responsible for the existence of zktk files 81 | ## ISDL 82 | Parameter responsible for creating dl file (combining sc and tex_sc), usually used in Clash Royale requires sc file in the folder. 83 | ### Compression 84 | File compression, with HasZKTX enabled, Zstandard is always used. 85 | Example of compression on ui_highres_tex 86 | Compression | File encoding time | File weight | Total 87 | --- | --- | --- | --- 88 | Lzma | 41 s | 26MB| Longer but compresses better. 89 | Lzham | 73sec | 27MB | It's useless. 90 | Zstandard | 35secs | 30MB | Standard, fast and compresses well. 91 | 92 | # Any questions? 93 | My social networking nickname is lilmuff1 message me or join [Telegram](https://t.me/XcoderBS) or [Discord](https://discord.com/invite/yNajwpBe) 94 | -------------------------------------------------------------------------------- /Readme_ru.md: -------------------------------------------------------------------------------- 1 | # X-coder 2 | #X-coder 3 | Инструмент для декодирования (sc в png) и кодирования (png в sc) файлов sc которые используются в играх Supercell 4 | # Как пользоваться 5 | 1. Скачиваем нужную нам версию с [релизов](https://github.com/lilmuff2/X-coder/releases/tag/v2.2) (apk - на андроид, setup.exe - установщик на винду, zip - архив с exe для винды) 6 | 3. Выбрать нужную опцию (о каждой расписано ниже) 7 | 5. Выбрать или ввести входной файл или папку 8 | 7. По желанию выбрать или ввести выходную папку или файл, или она будет выбрана автоматически !ОНА БУДЕТ УДАЛЕНА! 9 | 8. Нажать на кнопку снизу (не закрыть) и ждать 10 | 11 | 12 | ![Menu](https://github.com/lilmuff2/X-coder/blob/images/ru_menu.png?raw=true) 13 | 14 | # ДЕКОД ФАЙЛ: 15 | Конвертирует sc в пнг
16 | Входной файл - _tex.sc, не .sc! или _dl.sc в редких случаях
17 | Начиная с 54 версии бравл старса появились zktx файлы их нужно поместить в ту же папку, что и входной файл
18 | Выходная папка - папка в которую будут сохранены пнг
19 | 20 | ![Decode example](https://github.com/lilmuff2/X-coder/blob/images/ru_decode.png?raw=true) 21 | 22 | 23 | # ЕНКОД ПАПКУ: 24 | Конвертирует пнг в sc
25 | Входная папка - папка с пнг и [json файлом](#json-%D1%84%D0%B0%D0%B9%D0%BB) (желательно)
26 | Имя json файла должно совпадать с названием папки
27 | Выходной файл - куда сохранять sc
28 | Если вам нужен sc для старой версии измените сжатие в json файле с Zstandard на Lzma
29 | 30 | ![Encode example](https://github.com/lilmuff2/X-coder/blob/images/ru_encode.png?raw=true) 31 | 32 | 33 | # ДЕКОД ФАЙЛЫ: 34 | Конвертирует много sc файлов в пнг, удобно просто скопировать папку sc из апк и декодировать их все разом
35 | Входная папка - папка с _tex.sc, не .sc! или _dl.sc файлами
36 | Выходная папка - папка где будут созданы папки в которых будут пнг
37 | 38 | ![Decode folder example](https://github.com/lilmuff2/X-coder/blob/images/ru_decodefolder.png?raw=true) 39 | 40 | 41 | # ЕНКОД ПАПКИ: 42 | Конвертирует много папок с пнг в sc файлы
43 | Входная папка - папка с папками в которых лежат пнг
44 | Выходная папка - папка куда будут сохранены sc файлы
45 | 46 | ![Encode folder example](https://github.com/lilmuff2/X-coder/blob/images/ru_encodefolder.png?raw=true) 47 | 48 | 49 | # .json файл: 50 | Этот файл генерируется при декодировании 51 | Пример: 52 | ```javascript 53 | { 54 | "Textures": [ 55 | { 56 | "Encoding": "khronos", 57 | "PixelFormat": "RGBA8", 58 | "Filtering": "LINEAR_NEAREST", 59 | "Linear": true 60 | }, 61 | { 62 | "Encoding": "khronos", 63 | "PixelFormat": "RGBA8", 64 | "Filtering": "LINEAR_NEAREST", 65 | "Linear": true 66 | } 67 | ], 68 | "IsDL": false, 69 | "HasZKTX": true, 70 | "Compression": "Zstandard" 71 | } 72 | ``` 73 | 74 | ## Encoding 75 | Может быть khronos (мало весит) и raw (быстро кодируется), при включённом HasZKTX текстуры кодируются в khronos
76 | Пример ui_highres_tex с Zstandard сжатием: 77 | Encoding | Время кодирования | Размер файла 78 | ---|---|--- 79 | khronos | 35 с | 30 MB 80 | raw | 7 с | 41 MB 81 | > Я рекомендую во время разработки мода использовать raw а при релизе khronos 82 | ## HasZKTX 83 | Параметр отвечающий за наличие zktk файлов 84 | ### ISDL 85 | Параметр отвечающий за создание dl файла (объединение sc и tex_sc), обычно используется в Clash Royale требует наличия sc файла в папке 86 | ## Compression 87 | Сжатие файла, при включённом HasZKTX всегда используется Zstandard. 88 | Пример сжатия на ui_highres_tex: 89 | Compression | Время кодирования файла | Вес файла | Итог 90 | --- | --- | --- | --- 91 | Lzma | 41 с | 26MB| Дольше, но сжимает лучше 92 | Lzham | 73с | 27MB | Оно бесполезно 93 | Zstandard | 35 с | 30 MB| Стандартное, быстрое и хорошо сжимает 94 | 95 | # Остались вопросы? 96 | Мой ник в соцсетях lilmuff1 пишите или присоединяйтесь к [Telegram](https://t.me/XcoderBS) or [Discord](https://discord.com/invite/yNajwpBe) 97 | -------------------------------------------------------------------------------- /android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:7.4.1' 9 | } 10 | } 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | } 16 | 17 | apply plugin: 'com.android.application' 18 | 19 | dependencies { 20 | implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) 21 | implementation 'androidx.documentfile:documentfile:1.0.1' 22 | implementation 'androidx.appcompat:appcompat:1.0.0' 23 | } 24 | 25 | android { 26 | /******************************************************* 27 | * The following variables: 28 | * - androidBuildToolsVersion, 29 | * - androidCompileSdkVersion 30 | * - qtAndroidDir - holds the path to qt android files 31 | * needed to build any Qt application 32 | * on Android. 33 | * 34 | * are defined in gradle.properties file. This file is 35 | * updated by QtCreator and androiddeployqt tools. 36 | * Changing them manually might break the compilation! 37 | *******************************************************/ 38 | 39 | compileSdkVersion androidCompileSdkVersion 40 | buildToolsVersion androidBuildToolsVersion 41 | ndkVersion androidNdkVersion 42 | 43 | // Extract native libraries from the APK 44 | packagingOptions.jniLibs.useLegacyPackaging true 45 | 46 | sourceSets { 47 | main { 48 | manifest.srcFile 'AndroidManifest.xml' 49 | java.srcDirs = [qtAndroidDir + '/src', 'src', 'java'] 50 | aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl'] 51 | res.srcDirs = [qtAndroidDir + '/res', 'res'] 52 | resources.srcDirs = ['resources'] 53 | renderscript.srcDirs = ['src'] 54 | assets.srcDirs = ['assets'] 55 | jniLibs.srcDirs = ['libs'] 56 | } 57 | } 58 | 59 | tasks.withType(JavaCompile) { 60 | options.incremental = true 61 | } 62 | 63 | compileOptions { 64 | sourceCompatibility JavaVersion.VERSION_1_8 65 | targetCompatibility JavaVersion.VERSION_1_8 66 | } 67 | 68 | lintOptions { 69 | abortOnError false 70 | } 71 | 72 | // Do not compress Qt binary resources file 73 | aaptOptions { 74 | noCompress 'rcc' 75 | } 76 | 77 | defaultConfig { 78 | resConfig "en" 79 | minSdkVersion qtMinSdkVersion 80 | targetSdkVersion qtTargetSdkVersion 81 | ndk.abiFilters = qtTargetAbiList.split(",") 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # For more details on how to configure your build environment visit 3 | # http://www.gradle.org/docs/current/userguide/build_environment.html 4 | # Specifies the JVM arguments used for the daemon process. 5 | # The setting is particularly useful for tweaking memory settings. 6 | org.gradle.jvmargs=-Xmx2500m -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 7 | 8 | # Enable building projects in parallel 9 | org.gradle.parallel=true 10 | 11 | # Gradle caching allows reusing the build artifacts from a previous 12 | # build with the same inputs. However, over time, the cache size will 13 | # grow. Uncomment the following line to enable it. 14 | #org.gradle.caching=true 15 | #org.gradle.configuration-cache=true 16 | 17 | # Allow AndroidX usage 18 | android.useAndroidX=true 19 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilmuff2/X-coder/285c36067251cb3b118f006329bc94785d09f183/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command; 206 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 207 | # shell script including quotes and variable substitutions, so put them in 208 | # double quotes to make sure that they get re-expanded; and 209 | # * put everything else in single quotes, so that it's not re-expanded. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /android/res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilmuff2/X-coder/285c36067251cb3b118f006329bc94785d09f183/android/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /android/res/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilmuff2/X-coder/285c36067251cb3b118f006329bc94785d09f183/android/res/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /android/res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilmuff2/X-coder/285c36067251cb3b118f006329bc94785d09f183/android/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /android/res/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilmuff2/X-coder/285c36067251cb3b118f006329bc94785d09f183/android/res/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /android/res/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilmuff2/X-coder/285c36067251cb3b118f006329bc94785d09f183/android/res/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /android/res/drawable-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilmuff2/X-coder/285c36067251cb3b118f006329bc94785d09f183/android/res/drawable-xxxhdpi/icon.png -------------------------------------------------------------------------------- /android/res/values/libs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /android/res/xml/qtprovider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /headers/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include "config.hpp" 6 | 7 | QT_BEGIN_NAMESPACE 8 | namespace Ui { 9 | class MainWindow; 10 | } 11 | QT_END_NAMESPACE 12 | 13 | class MainWindow : public QMainWindow 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | MainWindow(QWidget *parent = nullptr); 19 | ~MainWindow(); 20 | Config *cfg; 21 | std::vector langs = {"en","ru"}; 22 | bool lanchanged = false; 23 | int CheckUpdates(); 24 | private slots: 25 | void BtnCLicked(); 26 | 27 | void on_About_clicked(); 28 | 29 | void on_comboBox_currentIndexChanged(int index); 30 | 31 | private: 32 | Ui::MainWindow *ui; 33 | }; 34 | #endif // MAINWINDOW_H 35 | -------------------------------------------------------------------------------- /headers/processing.h: -------------------------------------------------------------------------------- 1 | #ifndef PROCESSING_H 2 | #define PROCESSING_H 3 | 4 | #include 5 | #include 6 | 7 | 8 | namespace Ui { 9 | class Processing; 10 | } 11 | 12 | class Processing : public QWidget 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit Processing(QWidget *parent = nullptr); 18 | ~Processing(); 19 | void ChangeTitle(QString newtitle); 20 | bool Folder = false; 21 | bool Encode = false; 22 | void print(std::string str); 23 | void decode(std::filesystem::path input_path,std::filesystem::path output_path); 24 | void encode(std::filesystem::path input_path,std::filesystem::path output_path); 25 | void print(QString str); 26 | private slots: 27 | void on_Select1_clicked(); 28 | 29 | void on_Select2_clicked(); 30 | 31 | void on_Run_clicked(); 32 | 33 | void on_ExitBtn_clicked(); 34 | 35 | private: 36 | Ui::Processing *ui; 37 | }; 38 | #endif // PROCESSING_H 39 | -------------------------------------------------------------------------------- /res/Pusia-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilmuff2/X-coder/285c36067251cb3b118f006329bc94785d09f183/res/Pusia-Bold.otf -------------------------------------------------------------------------------- /res/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilmuff2/X-coder/285c36067251cb3b118f006329bc94785d09f183/res/icon.ico -------------------------------------------------------------------------------- /res/rc.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON "icon.ico" -------------------------------------------------------------------------------- /res/res.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | translate/X-coder_ru.qm 4 | Pusia-Bold.otf 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/translate/X-coder_ru.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilmuff2/X-coder/285c36067251cb3b118f006329bc94785d09f183/res/translate/X-coder_ru.qm -------------------------------------------------------------------------------- /res/translate/X-coder_ru.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MainWindow 6 | 7 | 8 | 9 | X CODER 10 | 11 | 12 | 13 | 14 | <html><head/><body><p><a href="tg://resolve?domain=XcoderBS"><span style=" font-size:14pt; text-decoration: underline; color:#007af4;">https://t.me/XcoderBS</span></a></p></body></html> 15 | 16 | 17 | 18 | 19 | DECODE 20 | ДЕКОД 21 | 22 | 23 | 24 | FILE 25 | ФАЙЛ 26 | 27 | 28 | 29 | FILES 30 | ФАЙЛЫ 31 | 32 | 33 | 34 | FOLDER 35 | ПАПКУ 36 | 37 | 38 | 39 | ENCODE 40 | ЕНКОД 41 | 42 | 43 | 44 | FOLDERS 45 | ПАПКИ 46 | 47 | 48 | 49 | LANGUAGE 50 | ЯЗЫК 51 | 52 | 53 | 54 | English 55 | 56 | 57 | 58 | 59 | Русский 60 | 61 | 62 | 63 | 64 | 65 | ABOUT 66 | ИНФО 67 | 68 | 69 | 70 | en 71 | ru 72 | 73 | 74 | 75 | 76 | UPDATE AVAILABE 77 | ДОСТУПНО ОБНОВЛЕНИЕ 78 | 79 | 80 | 81 | 82 | You can find new version on <a href='https://github.com/lilmuff2/X-coder/releases'>https://github.com/lilmuff2/X-coder/releases</a> 83 | Ты можешь найти новую версию на <a href='https://github.com/lilmuff2/X-coder/releases'>https://github.com/lilmuff2/X-coder/releases</a> 84 | 85 | 86 | 87 | 88 | UPDATE 89 | ОБНОВИТЬ 90 | 91 | 92 | 93 | EXIT 94 | ВЫЙТИ 95 | 96 | 97 | 98 | Author: <a href='tg://resolve?domain=lilmuff1'>lilmuff1</a> 99 | <br>THX FOR HELP: <a href='https://github.com/Daniil-SV'>Danil SV</a><br>DISCORD: <a href='https://discord.com/invite/yNajwpBe'>discord.com/invite/yNajwpBe</a><br>TG: <a href='tg://resolve?domain=XcoderBS'>t.me/XcoderBS</a><br>GITHUB: <a href='https://github.com/lilmuff2/X-coder'>github.com/lilmuff2/X-coder</a> 100 | Автор: <a href='tg://resolve?domain=lilmuff1'>lilmuff1</a> 101 | <br>ПОМОГАЛ: <a href='https://github.com/Daniil-SV'>Danil SV</a><br>DISCORD: <a href='https://discord.com/invite/yNajwpBe'>discord.com/invite/yNajwpBe</a><br>TG: <a href='tg://resolve?domain=XcoderBS'>t.me/XcoderBS</a><br>GITHUB: <a href='https://github.com/lilmuff2/X-coder'>github.com/lilmuff2/X-coder</a> 102 | 103 | 104 | 105 | Processing 106 | 107 | 108 | 109 | 110 | DECODE 111 | ДЕКОД 112 | 113 | 114 | 115 | <html><head/><body><p><a href="tg://resolve?domain=XcoderBS"><span style=" font-size:14pt; text-decoration: underline; color:#007af4;">https://t.me/XcoderBS</span></a></p></body></html> 116 | 117 | 118 | 119 | 120 | 121 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 122 | <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> 123 | p, li { white-space: pre-wrap; } 124 | hr { height: 1px; border-width: 0; } 125 | li.unchecked::marker { content: "\2610"; } 126 | li.checked::marker { content: "\2612"; } 127 | </style></head><body style=" font-family:'Segoe UI'; font-size:15pt; font-weight:700; font-style:normal;"> 128 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><br /></p></body></html> 129 | 130 | 131 | 132 | 133 | OUT FOLDER (OPTIONALLY) 134 | ВЫХОДНЯ ПАПКА (ОПЦИОНАЛЬНО) 135 | 136 | 137 | 138 | INPUT FILE 139 | ВХОДНОЙ ФАЙЛ 140 | 141 | 142 | 143 | 144 | SELECT 145 | ВЫБРАТЬ 146 | 147 | 148 | 149 | 150 | CONSOLE: 151 | КОНСОЛЬ: 152 | 153 | 154 | 155 | CLOSE 156 | ЗАКРЫТЬ 157 | 158 | 159 | 160 | 161 | 162 | ENCODE 163 | ЕНКОД 164 | 165 | 166 | 167 | OUT FILE (OPTIONALLY) 168 | ВЫХОДНОЙ ФАЙЛ (ОПЦИОНАЛЬНО) 169 | 170 | 171 | 172 | 173 | INPUT FOLDER 174 | ВХОДНАЯ ПАПКА 175 | 176 | 177 | 178 | 179 | Decoding took: 180 | Декод занял: 181 | 182 | 183 | 184 | 185 | Encoding took: 186 | Енкод занял: 187 | 188 | 189 | 190 | 191 | 192 | ERROR: Input folder doesnt exist! 193 | ОШИБКА: Входной папки не существует! 194 | 195 | 196 | 197 | 198 | 199 | 200 | INFO: Out path is empty, so it will be: 201 | 202 | ИНФО: Выходной путь пустой, он выбран автоматически: 203 | 204 | 205 | 206 | Decoding %d files took: 207 | Декод %d файлов занял: 208 | 209 | 210 | 211 | ERROR: No _tex.sc in input folder. Folder must contains texture files! 212 | ОШИБКА: Нету _tex.sc файлов в входной папке. Папка должна содержать файлы текстур! 213 | 214 | 215 | 216 | Encoding %d files took: 217 | Енкод %d файлов занял: 218 | 219 | 220 | 221 | ERROR: No folders in input folder. Folder must contains folders with pngs! 222 | ОШИБКА: Нету папок в входной папке. Пака должа содержать папки с пнгшками! 223 | 224 | 225 | 226 | ERROR: Input file doesnt exist! 227 | ОШИБКА: Входной файл не существует! 228 | 229 | 230 | 231 | WARNING: INPUT FILE MAY NOT BE _TEX.SC if so out will be empty. INPUT FILE MUST BE TEXTURE FILE 232 | ПРЕДДУПРЕЖДЕНИЕ: Возможно это не файл текстуры. Входной файл должен быть _tex.sc 233 | 234 | 235 | 236 | 237 | Working on 238 | Работаем над 239 | 240 | 241 | 242 | Loading file... 243 | Загружаем файл... 244 | 245 | 246 | 247 | INFO: It is dl file, so it will be coped to out folder 248 | ИНФО: Это dl файл, он быдет скопирован в выходнкю папку 249 | 250 | 251 | 252 | Decoding file... 253 | Декод файла.... 254 | 255 | 256 | 257 | 258 | ERROR: 259 | ОШИБКА: 260 | 261 | 262 | 263 | INFO: It is dl, so loading sc... 264 | ИНФО: это dl, загружаем sc... 265 | 266 | 267 | 268 | Loading images... 269 | Загружем картинки... 270 | 271 | 272 | 273 | Saving file... 274 | Сохраняем файл... 275 | 276 | 277 | 278 | QTranslator 279 | 280 | 281 | en 282 | ru 283 | 284 | 285 | 286 | -------------------------------------------------------------------------------- /source/SWFFile.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "json.hpp" 11 | 12 | using json = nlohmann::ordered_json; 13 | 14 | namespace sc 15 | { 16 | class SWFFile : public SupercellSWF 17 | { 18 | public: 19 | SWFFile() {}; 20 | bool isdl = false; 21 | bool has_zktx = false; 22 | // If the file is a real texture, only the texture tags are loaded, otherwise the entire file is loaded. 23 | SWFFile(std::filesystem::path path) 24 | { 25 | current_file = path; 26 | stream.open_file(path); 27 | 28 | // Path Check 29 | if (path.string().find("_tex") != std::string::npos) 30 | { 31 | load_texures_from_binary(); 32 | 33 | return; 34 | } 35 | // Whole file loading 36 | if(path.string().find("_dl") != std::string::npos) 37 | { 38 | isdl=true; 39 | // Skip of all count fields 40 | stream.seek(17); 41 | 42 | // export names skip 43 | uint16_t exports_count = stream.read_unsigned_short(); 44 | 45 | for (uint16_t i = 0; exports_count > i; i++) 46 | { 47 | stream.read_unsigned_short(); 48 | } 49 | 50 | for (uint16_t i = 0; exports_count > i; i++) 51 | { 52 | uint8_t length = stream.read_unsigned_byte(); 53 | stream.seek(length, sc::Seek::Add); 54 | } 55 | 56 | load_texures_from_binary(); 57 | } 58 | } 59 | 60 | public: 61 | void load_texures_from_binary() 62 | { 63 | while (true) 64 | { 65 | uint8_t tag = stream.read_unsigned_byte(); 66 | int32_t tag_length = stream.read_int(); 67 | 68 | if (tag == TAG_END) 69 | break; 70 | 71 | if (tag_length < 0) 72 | throw NegativeTagLengthException(tag, stream.position()); 73 | 74 | switch (tag) 75 | { 76 | case TAG_TEXTURE_10: 77 | has_zktx = true; 78 | case TAG_TEXTURE: 79 | case TAG_TEXTURE_2: 80 | case TAG_TEXTURE_3: 81 | case TAG_TEXTURE_4: 82 | case TAG_TEXTURE_5: 83 | case TAG_TEXTURE_6: 84 | case TAG_TEXTURE_7: 85 | case TAG_TEXTURE_8: 86 | case TAG_TEXTURE_9: 87 | textures.emplace_back().load(*this, tag, true); 88 | break; 89 | 90 | default: 91 | stream.seek(tag_length, Seek::Add); 92 | break; 93 | } 94 | } 95 | } 96 | 97 | void save_textures_to_folder(std::filesystem::path output_path) 98 | { 99 | json texture_infos = json::array(); 100 | 101 | for (uint16_t i = 0; textures.size() > i; i++) 102 | { 103 | SWFTexture& texture = textures[i]; 104 | 105 | // Texture Info 106 | { 107 | std::string encoding; 108 | { 109 | switch (texture.encoding()) 110 | { 111 | case SWFTexture::TextureEncoding::KhronosTexture: 112 | encoding = "khronos"; 113 | break; 114 | case SWFTexture::TextureEncoding::Raw: 115 | encoding = "raw"; 116 | break; 117 | default: 118 | break; 119 | } 120 | } 121 | 122 | std::string pixel_type = "RGBA8"; 123 | 124 | switch (texture.pixel_format()) 125 | { 126 | case SWFTexture::PixelFormat::RGBA4: 127 | pixel_type = "RGBA4"; 128 | break; 129 | case SWFTexture::PixelFormat::RGB5_A1: 130 | pixel_type = "RGB5_A1"; 131 | break; 132 | case SWFTexture::PixelFormat::RGB565: 133 | pixel_type = "RGB565"; 134 | break; 135 | case SWFTexture::PixelFormat::LUMINANCE8_ALPHA8: 136 | pixel_type = "LUMINANCE8_ALPHA8"; 137 | break; 138 | case SWFTexture::PixelFormat::LUMINANCE8: 139 | pixel_type = "LUMINANCE8"; 140 | break; 141 | 142 | case SWFTexture::PixelFormat::RGBA8: 143 | default: 144 | break; 145 | } 146 | 147 | std::string filtering = "LINEAR_NEAREST"; 148 | 149 | switch (texture.filtering) 150 | { 151 | case SWFTexture::Filter::LINEAR_MIPMAP_NEAREST: 152 | filtering = "LINEAR_MIPMAP_NEAREST"; 153 | break; 154 | case SWFTexture::Filter::NEAREST_NEAREST: 155 | filtering = "NEAREST_NEAREST"; 156 | break; 157 | case SWFTexture::Filter::LINEAR_NEAREST: 158 | default: 159 | break; 160 | } 161 | 162 | json texture_info = { 163 | {"Encoding", encoding}, 164 | {"PixelFormat", pixel_type}, 165 | {"Filtering", filtering}, 166 | {"Linear", texture.linear()}, 167 | }; 168 | 169 | texture_infos.push_back(texture_info); 170 | } 171 | 172 | // Texture Image 173 | std::filesystem::path basename = output_path.stem(); 174 | std::filesystem::path output_image_path = output_path / basename.concat("_").concat(std::to_string(i)).concat(".png"); 175 | OutputFileStream output_image(output_image_path); 176 | 177 | stb::ImageFormat format = stb::ImageFormat::PNG; 178 | 179 | switch (texture.encoding()) 180 | { 181 | case SWFTexture::TextureEncoding::KhronosTexture: 182 | { 183 | RawImage image( 184 | texture.image()->width(), texture.image()->height(), 185 | texture.image()->depth() 186 | ); 187 | 188 | sc::MemoryStream image_data(image.data(), image.data_length()); 189 | ((sc::KhronosTexture*)(texture.image()))->decompress_data(image_data); 190 | 191 | stb::write_image(image, format, output_image); 192 | } 193 | break; 194 | 195 | case SWFTexture::TextureEncoding::Raw: 196 | texture.linear(true); 197 | stb::write_image( 198 | *(sc::RawImage*)(texture.image()), 199 | format, 200 | output_image 201 | ); 202 | break; 203 | 204 | default: 205 | break; 206 | } 207 | } 208 | json info = {{"Textures",texture_infos},{"IsDL",isdl},{"HasZKTX",has_zktx},{"Compression","Zstandard"}}; 209 | std::string serialized_data = info.dump(4); 210 | 211 | OutputFileStream file_info(output_path / output_path.stem().concat(".json")); 212 | file_info.write(serialized_data.data(), serialized_data.size()); 213 | } 214 | 215 | void load_textures_from_folder(std::filesystem::path input) 216 | { 217 | current_file = input; 218 | std::filesystem::path basename = input.stem(); 219 | std::filesystem::path texture_info_path = std::filesystem::path(input / basename.concat(".json")); 220 | 221 | // Texture Info Parsing 222 | json texture_infos = json::array({}); 223 | 224 | if (std::filesystem::exists(texture_info_path)) 225 | { 226 | std::ifstream file(texture_info_path); 227 | texture_infos = json::parse(file)["Textures"]; 228 | } 229 | 230 | 231 | // Texture Images path gather 232 | SWFVector texture_images_paths; 233 | 234 | for (auto const& file_descriptor : std::filesystem::directory_iterator(input)) 235 | { 236 | std::filesystem::path filepath = file_descriptor.path(); 237 | std::filesystem::path file_extension = filepath.extension(); 238 | 239 | if (file_extension == ".png") 240 | { 241 | texture_images_paths.push_back(filepath); 242 | 243 | } 244 | } 245 | 246 | //Texture Converting 247 | for (uint16_t i = 0; texture_images_paths.size() > i; i++) 248 | { 249 | // Image Loading 250 | RawImage* image = nullptr; 251 | InputFileStream image_file(texture_images_paths[i]); 252 | stb::load_image(image_file, &image); 253 | MemoryStream image_data(image->data(), image->data_length()); 254 | 255 | // Image Converting 256 | SWFTexture texture; 257 | texture.load_from_image(*image); 258 | 259 | if (texture_infos.size() > i) 260 | { 261 | json texture_info = texture_infos[i]; 262 | 263 | SWFTexture::PixelFormat texture_type = SWFTexture::PixelFormat::RGBA8; 264 | 265 | if (texture_info["PixelFormat"] == "RGBA4") 266 | { 267 | texture_type = SWFTexture::PixelFormat::RGBA4; 268 | } 269 | else if (texture_info["PixelFormat"] == "RGB5_A1") 270 | { 271 | texture_type = SWFTexture::PixelFormat::RGB5_A1; 272 | } 273 | else if (texture_info["PixelFormat"] == "RGB565") 274 | { 275 | texture_type = SWFTexture::PixelFormat::RGB565; 276 | } 277 | else if (texture_info["PixelFormat"] == "LUMINANCE8_ALPHA8") 278 | { 279 | texture_type = SWFTexture::PixelFormat::LUMINANCE8_ALPHA8; 280 | } 281 | else if (texture_info["PixelFormat"] == "LUMINANCE8") 282 | { 283 | texture_type = SWFTexture::PixelFormat::LUMINANCE8; 284 | } 285 | 286 | if (texture_info["Filtering"] == "LINEAR_NEAREST") 287 | { 288 | texture.filtering = SWFTexture::Filter::LINEAR_NEAREST; 289 | } 290 | else if (texture_info["Filtering"] == "LINEAR_MIPMAP_NEAREST") 291 | { 292 | texture.filtering = SWFTexture::Filter::LINEAR_MIPMAP_NEAREST; 293 | } 294 | else if (texture_info["Filtering"] == "NEAREST_NEAREST") 295 | { 296 | texture.filtering = SWFTexture::Filter::NEAREST_NEAREST; 297 | } 298 | 299 | if (texture_info["Encoding"] == "khronos") 300 | { 301 | texture.encoding(SWFTexture::TextureEncoding::KhronosTexture); 302 | } 303 | else if (texture_info["Encoding"] == "raw") 304 | { 305 | texture.encoding(SWFTexture::TextureEncoding::Raw); 306 | texture.pixel_format(texture_type); 307 | } 308 | } 309 | 310 | // Texture Insert 311 | if (textures.size() <= i) 312 | { 313 | textures.push_back(texture); 314 | } 315 | else 316 | { 317 | textures[i] = texture; 318 | } 319 | } 320 | } 321 | }; 322 | } 323 | -------------------------------------------------------------------------------- /source/config.hpp: -------------------------------------------------------------------------------- 1 | #include "json.hpp" 2 | using json = nlohmann::ordered_json; 3 | #include 4 | #include 5 | class Config 6 | { 7 | public : 8 | json config; 9 | std::filesystem::path path = "config.json"; 10 | 11 | json basecfg = {{"language","none"},{"ActualVersion",0},{"MinVersion",0}}; 12 | Config() { 13 | if(!std::filesystem::exists(path)){ 14 | config = basecfg; 15 | update(); 16 | }else{ 17 | try{ 18 | std::ifstream cfile(path); 19 | config = json::parse(cfile); 20 | for (auto& [key, value] : basecfg.items()) { 21 | if(!config.contains(key)) config[key] = value; 22 | } 23 | } catch(...){ 24 | config = basecfg; 25 | } 26 | update(); 27 | } 28 | }; 29 | // std::string lang(){ 30 | // return config["language"]; 31 | // } 32 | int* versions(){ 33 | static int v[2] = {config["ActualVersion"],config["MinVersion"]}; 34 | return v; 35 | } 36 | void versions(int ActualVersion,int MinVersion){ 37 | config["ActualVersion"] = ActualVersion; 38 | config["MinVersion"] = MinVersion; 39 | update(); 40 | } 41 | QString lang(){ 42 | return QString::fromStdString(config["language"]); 43 | } 44 | void lang(QString lan){ 45 | config["language"] = lan.toStdString(); 46 | update(); 47 | } 48 | void update(){ 49 | std::ofstream o(path); 50 | o << config.dump(4); 51 | } 52 | } ; 53 | -------------------------------------------------------------------------------- /source/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #if defined Q_OS_ANDROID 8 | #include 9 | #include 10 | #endif 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | int currentExitCode = 0; 15 | do { 16 | QApplication a(argc, argv); 17 | QTranslator translator; 18 | Config *cfg = new Config(); 19 | QString lan = cfg->lang(); 20 | if(lan=="none"){ 21 | for (const QString &locale : QLocale::system().uiLanguages()) { 22 | if (translator.load("X-coder_" + QLocale(locale).name()) || translator.load(":/translate/X-coder_" + QLocale(locale).name())) { 23 | a.installTranslator(&translator); 24 | break; 25 | } 26 | } 27 | cfg->lang(QTranslator::tr("en")); 28 | }else{ 29 | if (translator.load("X-coder_" + lan) || translator.load(":/translate/X-coder_" +lan)) { 30 | a.installTranslator(&translator); 31 | }else if(lan!="en"){ 32 | cfg->lang("en"); 33 | } 34 | } 35 | QFontDatabase::addApplicationFont(":/Pusia-Bold.otf"); 36 | a.setFont(QFont("Pusia-Bold", 11, QFont::Normal, false)); 37 | MainWindow w; 38 | w.show(); 39 | #if defined Q_OS_ANDROID 40 | if (QtAndroidPrivate::androidSdkVersion() >= 30){ 41 | #define PACKAGE_NAME "package:lilmuff1.xcoder" 42 | jboolean value = QJniObject::callStaticMethod("android/os/Environment", "isExternalStorageManager"); 43 | if(value == false) { 44 | QJniObject filepermit = QJniObject::getStaticObjectField( "android/provider/Settings", "ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION","Ljava/lang/String;" ); 45 | QJniObject pkgName = QJniObject::fromString(PACKAGE_NAME); 46 | QJniObject parsedUri = QJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", pkgName.object()); 47 | QJniObject intent("android/content/Intent", "(Ljava/lang/String;Landroid/net/Uri;)V", filepermit.object(),parsedUri.object()); 48 | QtAndroidPrivate::startActivity(intent, 0); 49 | } 50 | } 51 | else{ 52 | const QVector permissions({ 53 | "android.permission.WRITE_EXTERNAL_STORAGE", 54 | "android.permission.READ_EXTERNAL_STORAGE"}); 55 | for(const QString &permission : permissions){ 56 | auto result = QtAndroidPrivate::checkPermission(permission).result(); 57 | if(result == QtAndroidPrivate::Denied){ 58 | QtAndroidPrivate::requestPermission(permission); 59 | } 60 | } 61 | } 62 | #endif 63 | #if not defined Q_OS_ANDROID 64 | if(!currentExitCode){ 65 | if(w.CheckUpdates()){ 66 | return currentExitCode; 67 | } 68 | } 69 | #else 70 | std::thread th( 71 | [¤tExitCode, &w, &a](){ 72 | if(!currentExitCode){ 73 | if(w.CheckUpdates()){ 74 | a.exit(currentExitCode); 75 | } 76 | } 77 | }); 78 | th.detach(); 79 | #endif 80 | currentExitCode = a.exec(); 81 | } while( currentExitCode == 69 ); 82 | return currentExitCode; 83 | } 84 | -------------------------------------------------------------------------------- /source/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "./../ui/ui_mainwindow.h" 3 | #include "processing.h" 4 | #include 5 | #include 6 | #include "json.hpp" 7 | using json = nlohmann::ordered_json; 8 | #include 9 | #include 10 | #include 11 | #include 12 | void htmlGet(const QUrl &url, const std::function &fun) { 13 | QScopedPointer manager(new QNetworkAccessManager); 14 | QNetworkReply *response = manager->get(QNetworkRequest(QUrl(url))); 15 | QObject::connect(response, &QNetworkReply::finished, [response, fun]{ 16 | response->deleteLater(); 17 | response->manager()->deleteLater(); 18 | if (response->error() != QNetworkReply::NoError) return; 19 | auto const html = QString::fromUtf8(response->readAll()); 20 | fun(html); // do something with the data 21 | 22 | }) && manager.take(); 23 | } 24 | MainWindow::MainWindow(QWidget *parent) 25 | : QMainWindow(parent) 26 | , ui(new Ui::MainWindow) 27 | { 28 | cfg = new Config(); 29 | ui->setupUi(this); 30 | connect(ui->DecodeFile, SIGNAL(clicked()),this,SLOT(BtnCLicked())); 31 | connect(ui->DecodeFolder, SIGNAL(clicked()),this,SLOT(BtnCLicked())); 32 | connect(ui->EncodeFile, SIGNAL(clicked()),this,SLOT(BtnCLicked())); 33 | connect(ui->EncodeFolder, SIGNAL(clicked()),this,SLOT(BtnCLicked())); 34 | for(int i = 0;icomboBox->setCurrentIndex(i); 37 | break; 38 | } 39 | } 40 | lanchanged = true; 41 | } 42 | 43 | MainWindow::~MainWindow() 44 | { 45 | delete ui; 46 | } 47 | 48 | int MainWindow::CheckUpdates() 49 | { 50 | htmlGet({"https://raw.githubusercontent.com/lilmuff2/X-coder/images/v.json"}, [this](const QString &body){ 51 | json v = json::parse(body.toStdString()); 52 | int ActualVersion = v["ActualVersion"]; 53 | int MinVersion = v["MinVersion"]; 54 | cfg->versions(ActualVersion,MinVersion); 55 | }); 56 | if(cfg->versions()[1]>22){ 57 | QMessageBox msgBox; 58 | msgBox.setWindowTitle(tr("UPDATE AVAILABE")); 59 | msgBox.setTextFormat(Qt::RichText); //this is what makes the links clickable 60 | msgBox.setText(tr("You can find new version on https://github.com/lilmuff2/X-coder/releases")); 61 | QPushButton *btn = msgBox.addButton(tr("UPDATE"), QMessageBox::ActionRole); 62 | msgBox.addButton(tr("EXIT"), QMessageBox::ActionRole); 63 | msgBox.exec(); 64 | if (msgBox.clickedButton() == btn) { 65 | QDesktopServices::openUrl(QUrl("https://github.com/lilmuff2/X-coder/releases")); 66 | } 67 | return 1; 68 | }else if(cfg->versions()[0]>22){ 69 | QMessageBox msgBox; 70 | msgBox.setWindowTitle(tr("UPDATE AVAILABE")); 71 | msgBox.setTextFormat(Qt::RichText); //this is what makes the links clickable 72 | msgBox.setText(tr("You can find new version on https://github.com/lilmuff2/X-coder/releases")); 73 | QPushButton *btn = msgBox.addButton(tr("UPDATE"), QMessageBox::ActionRole); 74 | msgBox.setStandardButtons(QMessageBox::Ok); 75 | msgBox.exec(); 76 | if (msgBox.clickedButton() == btn) { 77 | QDesktopServices::openUrl(QUrl("https://github.com/lilmuff2/X-coder/releases")); 78 | } 79 | } 80 | return 0; 81 | } 82 | 83 | void MainWindow::BtnCLicked() 84 | { 85 | Processing *processWindow = new Processing(); 86 | processWindow->show(); 87 | QString action = sender()->objectName(); 88 | processWindow->ChangeTitle(action); 89 | } 90 | 91 | void MainWindow::on_About_clicked() 92 | { 93 | QMessageBox msgBox; 94 | msgBox.setWindowTitle(tr("ABOUT")); 95 | msgBox.setTextFormat(Qt::RichText); //this is what makes the links clickable 96 | msgBox.setText(tr("Author: lilmuff1\n
THX FOR HELP: Danil SV" 97 | "
DISCORD: discord.com/invite/yNajwpBe" 98 | "
TG: t.me/XcoderBS" 99 | "
GITHUB: github.com/lilmuff2/X-coder")); 100 | msgBox.setStandardButtons(QMessageBox::Ok); 101 | msgBox.exec(); 102 | } 103 | 104 | void MainWindow::on_comboBox_currentIndexChanged(int index) 105 | { 106 | if(lanchanged){ 107 | cfg->lang(langs[index]); 108 | qApp->exit(69); 109 | } 110 | } 111 | 112 | -------------------------------------------------------------------------------- /source/processing.cpp: -------------------------------------------------------------------------------- 1 | #include "processing.h" 2 | #include "../ui/ui_processing.h" 3 | #include "SWFFile.hpp" 4 | #include "logger/time.h" 5 | #include "json.hpp" 6 | #include 7 | #include 8 | #if defined Q_OS_ANDROID 9 | #include 10 | #include 11 | #endif 12 | using json = nlohmann::ordered_json; 13 | Processing::Processing(QWidget *parent) 14 | : QWidget(parent) 15 | , ui(new Ui::Processing) 16 | { 17 | ui->setupUi(this); 18 | #if defined Q_OS_ANDROID 19 | ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); 20 | #endif 21 | } 22 | static QString getRealPathFromUri(const QUrl &url) 23 | { 24 | QString path = ""; 25 | #ifdef Q_OS_ANDROID 26 | QJniObject jUrl = QJniObject::fromString(url.toString()); 27 | QJniObject jContext = QtAndroidPrivate::context(); 28 | QJniObject jContentResolver = jContext.callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;"); 29 | QJniObject jUri = QJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", jUrl.object()); 30 | QJniObject jCursor = jContentResolver.callObjectMethod("query", "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;", jUri.object(), nullptr, nullptr, nullptr, nullptr); 31 | QJniObject jScheme = jUri.callObjectMethod("getScheme", "()Ljava/lang/String;"); 32 | QJniObject authority; 33 | if(jScheme.isValid()) 34 | { 35 | authority = jUri.callObjectMethod("getAuthority", "()Ljava/lang/String;"); 36 | } 37 | if(authority.isValid() && authority.toString() == "com.android.externalstorage.documents") 38 | { 39 | QJniObject jPath = jUri.callObjectMethod("getPath", "()Ljava/lang/String;"); 40 | path = jPath.toString(); 41 | } 42 | else if(jCursor.isValid() && jCursor.callMethod("moveToFirst")) 43 | { 44 | QJniObject jColumnIndex = QJniObject::fromString("_data"); 45 | jint columnIndex = jCursor.callMethod("getColumnIndexOrThrow", "(Ljava/lang/String;)I", jColumnIndex.object()); 46 | QJniObject jRealPath = jCursor.callObjectMethod("getString", "(I)Ljava/lang/String;", columnIndex); 47 | path = jRealPath.toString(); 48 | if(authority.isValid() && authority.toString().startsWith("com.android.providers") && !url.toString().startsWith("content://media/external/")) 49 | { 50 | QStringList list = path.split(":"); 51 | if(list.count() == 2) 52 | { 53 | QString type = list.at(0); 54 | QString id = list.at(1); 55 | if(type == "image") 56 | type = type + "s"; 57 | if(type == "document" || type == "documents") 58 | type = "file"; 59 | if(type == "msf") 60 | type = "downloads"; 61 | if(QList({"images","video","audio"}).contains(type)) 62 | type = type + "/media"; 63 | path = "content://media/external/"+type; 64 | path = path + "/" + id; 65 | return getRealPathFromUri(path); 66 | } 67 | } 68 | } 69 | else 70 | { 71 | QJniObject jPath = jUri.callObjectMethod("getPath", "()Ljava/lang/String;"); 72 | path = jPath.toString(); 73 | qDebug() << QFile::exists(path) <retranslateUi(this); 117 | if(newtitle.startsWith("Encode")){ 118 | ui->Run->setText(tr("ENCODE")); 119 | ui->Title->setText(tr("ENCODE")); 120 | Processing::setWindowTitle(tr("ENCODE")); 121 | Processing::Encode = true; 122 | if(!newtitle.endsWith("Folder")){ui->Input2->setPlaceholderText(tr("OUT FILE (OPTIONALLY)"));} 123 | ui->Input1->setPlaceholderText(tr("INPUT FOLDER")); 124 | } 125 | if(newtitle.endsWith("Folder")){ 126 | ui->Input1->setPlaceholderText(tr("INPUT FOLDER")); 127 | Processing::Folder = true; 128 | Processing::setWindowTitle(Processing::windowTitle()+" FOLDER"); 129 | } 130 | } 131 | 132 | 133 | 134 | 135 | void Processing::on_Select1_clicked() 136 | { 137 | QString text; 138 | if(Processing::Encode || Processing::Folder){ 139 | text = QFileDialog::getExistingDirectory(this); 140 | }else{ 141 | #if defined Q_OS_ANDROID 142 | text = QFileDialog::getOpenFileName(this); 143 | #else 144 | text = QFileDialog::getOpenFileName(this,nullptr,nullptr,"SC FILE (*.sc)"); 145 | #endif 146 | } 147 | #if defined Q_OS_ANDROID 148 | text = getRealPathFromUri(text); 149 | #endif 150 | ui->Input1->setText(text); 151 | } 152 | 153 | 154 | void Processing::on_Select2_clicked() 155 | { 156 | QString text; 157 | if(Processing::Encode && !Processing::Folder){ 158 | #if defined Q_OS_ANDROID 159 | text = QFileDialog::getSaveFileName(this); 160 | #else 161 | text = QFileDialog::getSaveFileName(this,nullptr,nullptr,"SC FILE (*.sc)"); 162 | #endif 163 | }else{ 164 | text = QFileDialog::getExistingDirectory(this); 165 | } 166 | #if defined Q_OS_ANDROID 167 | text = getRealPathFromUri(text); 168 | #endif 169 | ui->Input2->setText(text); 170 | } 171 | void Processing::print(std::string str) 172 | { 173 | ui->Output->setText(QString::fromStdString(ui->Output->text().toStdString()+"\n"+str)); 174 | ui->scrollArea->verticalScrollBar()->setValue(10000000); 175 | } 176 | void Processing::print(QString str) 177 | { 178 | ui->Output->setText((ui->Output->text()+"\n"+str)); 179 | ui->scrollArea->verticalScrollBar()->setValue(10000000); 180 | } 181 | void Processing::on_ExitBtn_clicked() 182 | { 183 | this->close(); 184 | } 185 | 186 | 187 | void Processing::on_Run_clicked() 188 | { 189 | ui->Run->setEnabled(false); 190 | ui->Output->setText(tr("CONSOLE:")); 191 | if(!Processing::Encode && !Processing::Folder){//decoding 192 | std::thread th( 193 | [this](){ 194 | std::chrono::time_point doperation_start = std::chrono::high_resolution_clock::now(); 195 | decode(ui->Input1->toPlainText().toStdString(),ui->Input2->toPlainText().toStdString()); 196 | print(tr("Decoding took: ").toStdString()+sc::time::calculate_time(doperation_start, std::chrono::high_resolution_clock::now())); 197 | QMetaObject::invokeMethod(ui->Run,"setEnabled", Qt::QueuedConnection,Q_ARG(bool, true)); 198 | 199 | } 200 | ); 201 | th.detach(); 202 | } 203 | else if(Processing::Encode && !Processing::Folder){//encode 204 | std::thread th( 205 | [this](){ 206 | std::chrono::time_point eoperation_start = std::chrono::high_resolution_clock::now(); 207 | encode(ui->Input1->toPlainText().toStdString(),ui->Input2->toPlainText().toStdString()); 208 | print(tr("Encoding took: ").toStdString()+sc::time::calculate_time(eoperation_start, std::chrono::high_resolution_clock::now())); 209 | QMetaObject::invokeMethod(ui->Run,"setEnabled", Qt::QueuedConnection,Q_ARG(bool, true)); 210 | } 211 | ); 212 | th.detach(); 213 | } 214 | else if(!Processing::Encode && Processing::Folder){//decode folder 215 | std::thread th( 216 | [this](){ 217 | std::chrono::time_point operation_start = std::chrono::high_resolution_clock::now(); 218 | fs::path input_path =ui->Input1->toPlainText().toStdString(); fs::path output_path = ui->Input2->toPlainText().toStdString(); 219 | if(!fs::exists(input_path)){ 220 | print(tr("ERROR: Input folder doesnt exist!")); 221 | QMetaObject::invokeMethod(ui->Run,"setEnabled", Qt::QueuedConnection,Q_ARG(bool, true)); 222 | return; 223 | } 224 | if(output_path==""){ 225 | output_path = input_path.string() + "/Decoded"; 226 | print(tr("INFO: Out path is empty, so it will be:\n").toStdString() + output_path.string()); 227 | } 228 | if (fs::exists(output_path)) 229 | { 230 | fs::remove_all(output_path); 231 | } 232 | int dec = 0; 233 | fs::create_directories(output_path); 234 | for (auto const& file_descriptor : std::filesystem::directory_iterator(input_path)) 235 | { 236 | std::filesystem::path filepath = file_descriptor.path(); 237 | if (file_descriptor.is_regular_file() && (filepath.stem().string().find("_tex") != std::string::npos || filepath.stem().string().find("_dl") != std::string::npos)) 238 | { 239 | dec++; 240 | std::chrono::time_point doperation_start = std::chrono::high_resolution_clock::now(); 241 | decode(filepath,output_path/filepath.stem()); 242 | print(tr("Decoding took: ").toStdString()+sc::time::calculate_time(doperation_start, std::chrono::high_resolution_clock::now())); 243 | } 244 | } 245 | if(dec>0){ 246 | print(tr("Decoding %d files took: ").replace("%d",QString::number(dec)).toStdString()+sc::time::calculate_time(operation_start, std::chrono::high_resolution_clock::now())); 247 | }else{ 248 | print(tr("ERROR: No _tex.sc in input folder. Folder must contains texture files!")); 249 | } 250 | QMetaObject::invokeMethod(ui->Run,"setEnabled", Qt::QueuedConnection,Q_ARG(bool, true)); 251 | 252 | } 253 | ); 254 | th.detach(); 255 | } 256 | else if(Processing::Encode && Processing::Folder){//encode folder 257 | std::thread th( 258 | [this](){ 259 | std::chrono::time_point operation_start = std::chrono::high_resolution_clock::now(); 260 | fs::path input_path =ui->Input1->toPlainText().toStdString(); fs::path output_path = ui->Input2->toPlainText().toStdString(); 261 | 262 | if(!fs::exists(input_path)){ 263 | print(tr("ERROR: Input folder doesnt exist!")); 264 | QMetaObject::invokeMethod(ui->Run,"setEnabled", Qt::QueuedConnection,Q_ARG(bool, true)); 265 | return; 266 | } 267 | if(output_path==""){ 268 | output_path = input_path.string() + "/Encoded"; 269 | print(tr("INFO: Out path is empty, so it will be:\n").toStdString() + output_path.string()); 270 | } 271 | if (fs::exists(output_path)) 272 | { 273 | fs::remove_all(output_path); 274 | } 275 | fs::create_directories(output_path); 276 | int enc = 0; 277 | for (auto const& file_descriptor : std::filesystem::directory_iterator(input_path)) 278 | { 279 | std::filesystem::path filepath = file_descriptor.path(); 280 | if (file_descriptor.is_directory() && (filepath.stem().string().find("_tex") != std::string::npos || filepath.stem().string().find("_dl") != std::string::npos)) 281 | { 282 | enc++; 283 | std::chrono::time_point eoperation_start = std::chrono::high_resolution_clock::now(); 284 | encode(filepath,output_path/filepath.stem().concat(".sc")); 285 | print(tr("Encoding took: ").toStdString()+sc::time::calculate_time(eoperation_start, std::chrono::high_resolution_clock::now())); 286 | } 287 | } 288 | if(enc>0){ 289 | print(tr("Encoding %d files took: ").replace("%d",QString::number(enc)).toStdString()+sc::time::calculate_time(operation_start, std::chrono::high_resolution_clock::now())); 290 | }else{ 291 | print(tr("ERROR: No folders in input folder. Folder must contains folders with pngs!")); 292 | } 293 | QMetaObject::invokeMethod(ui->Run,"setEnabled", Qt::QueuedConnection,Q_ARG(bool, true)); 294 | } 295 | ); 296 | th.detach(); 297 | } 298 | 299 | } 300 | void Processing::decode(fs::path input_path,fs::path output_path){ 301 | try { 302 | if(!fs::exists(input_path)){ 303 | print(tr("ERROR: Input file doesnt exist!")); 304 | return; 305 | } 306 | if(input_path.stem().string().find("_tex") == std::string::npos && input_path.stem().string().find("_dl") == std::string::npos){ 307 | print(tr("WARNING: INPUT FILE MAY NOT BE _TEX.SC if so out will be empty. INPUT FILE MUST BE TEXTURE FILE")); 308 | } 309 | print(tr("Working on ").toStdString() + input_path.stem().string() + "..."); 310 | print(tr("Loading file...")); 311 | sc::SWFFile file(input_path); 312 | if(output_path==""){ 313 | output_path = input_path; 314 | output_path.replace_extension(); 315 | print(tr("INFO: Out path is empty, so it will be:\n").toStdString() + output_path.string()); 316 | } 317 | if (fs::exists(output_path)) 318 | { 319 | fs::remove_all(output_path); 320 | } 321 | fs::create_directories(output_path); 322 | if(file.isdl){ 323 | print(tr("INFO: It is dl file, so it will be coped to out folder")); 324 | if(fs::exists(output_path/input_path.filename())){ 325 | fs::remove(output_path/input_path.filename()); 326 | } 327 | copy_file(input_path,output_path/input_path.filename()); 328 | } 329 | print(tr("Decoding file...")); 330 | file.save_textures_to_folder(output_path); 331 | } 332 | catch (sc::GeneralRuntimeException& e) { 333 | print(tr("ERROR:")); 334 | print(tr(e.what())); 335 | 336 | } 337 | } 338 | 339 | void Processing::encode(std::filesystem::path input_path, std::filesystem::path output_path) 340 | { 341 | try{ 342 | if(!fs::exists(input_path)){ 343 | print(tr("ERROR: Input folder doesnt exist!")); 344 | return; 345 | } 346 | print(tr("Working on ").toStdString() + input_path.stem().string() + "..."); 347 | json config={{"IsDL",false},{"HasZKTX",true},{"Compression","Zstandard"}}; 348 | if(fs::exists(input_path / input_path.stem().concat(".json"))){std::ifstream cfile(input_path / input_path.stem().concat(".json")); config = json::parse(cfile);} 349 | sc::SWFFile file; 350 | if(config["IsDL"]){ 351 | print(tr("INFO: It is dl, so loading sc...")); 352 | file.load(input_path / input_path.stem().concat(".sc")); 353 | } 354 | print(tr("Loading images...")); 355 | file.load_textures_from_folder(input_path); 356 | if(output_path==""){ 357 | output_path = input_path/input_path.stem().concat(config["IsDL"]? "_new.sc" : ".sc"); 358 | print(tr("INFO: Out path is empty, so it will be:\n").toStdString() + output_path.string()); 359 | } 360 | print(tr("Saving file...")); 361 | file.use_external_texture_files = config["HasZKTX"]; 362 | sc::SWFStream::Signature sig = sc::SWFStream::Signature::Zstandard; 363 | if(config["Compression"]=="Lzma"){sig=sc::SWFStream::Signature::Lzma;}else if(config["Compression"]=="Lzham"){sig = sc::SWFStream::Signature::Lzham;} 364 | if (config["IsDL"]) 365 | { 366 | file.save(output_path,sig); 367 | } 368 | else 369 | { 370 | file.current_file = output_path; 371 | file.save_internal(true, false); 372 | file.stream.save_file(output_path, sig); 373 | file.stream.clear(); 374 | } 375 | 376 | } 377 | catch (sc::GeneralRuntimeException& e) { 378 | print(tr("ERROR:")); 379 | print(tr(e.what())); 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /ui/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 507 10 | 905 11 | 12 | 13 | 14 | 15 | 600 16 | 950 17 | 18 | 19 | 20 | X CODER 21 | 22 | 23 | 24 | icon.icoicon.ico 25 | 26 | 27 | background-color: rgb(4, 15, 15) 28 | 29 | 30 | 31 | true 32 | 33 | 34 | 35 | 36 | 37 | 38 | 6 39 | 40 | 41 | 42 | 43 | 0 44 | 45 | 46 | QLayout::SizeConstraint::SetDefaultConstraint 47 | 48 | 49 | 50 | 51 | true 52 | 53 | 54 | 55 | 16777215 56 | 100 57 | 58 | 59 | 60 | 61 | 80 62 | true 63 | 64 | 65 | 66 | color: rgb(0, 210, 105); 67 | 68 | 69 | X CODER 70 | 71 | 72 | false 73 | 74 | 75 | Qt::AlignmentFlag::AlignCenter 76 | 77 | 78 | false 79 | 80 | 81 | 0 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 16777215 90 | 25 91 | 92 | 93 | 94 | 95 | 13 96 | false 97 | true 98 | false 99 | false 100 | true 101 | 102 | 103 | 104 | <html><head/><body><p><a href="tg://resolve?domain=XcoderBS"><span style=" font-size:14pt; text-decoration: underline; color:#007af4;">https://t.me/XcoderBS</span></a></p></body></html> 105 | 106 | 107 | false 108 | 109 | 110 | Qt::AlignmentFlag::AlignHCenter|Qt::AlignmentFlag::AlignTop 111 | 112 | 113 | true 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 16777215 124 | 100000 125 | 126 | 127 | 128 | background-color: rgba(255, 255,255, 60); 129 | border: 2px solid rgba(252, 255, 255, 80); 130 | border-radius: 10px; 131 | 132 | 133 | 134 | 9 135 | 136 | 137 | 9 138 | 139 | 140 | 9 141 | 142 | 143 | 9 144 | 145 | 146 | 9 147 | 148 | 149 | 150 | 151 | 152 | 80 153 | true 154 | 155 | 156 | 157 | background-color: none; 158 | color: white; 159 | border: 0px; 160 | 161 | 162 | DECODE 163 | 164 | 165 | Qt::AlignmentFlag::AlignCenter 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 0 176 | 65 177 | 178 | 179 | 180 | 181 | 40 182 | true 183 | PreferDefaultHinting 184 | 185 | 186 | 187 | QPushButton {color: white;} 188 | QPushButton:hover:!pressed 189 | { 190 | background-color: rgba(255, 255,255, 80); 191 | border: 2px solid rgba(252, 255, 255, 210); 192 | } 193 | QPushButton:pressed 194 | { 195 | background-color: rgba(255, 255,255, 100); 196 | border: 2px solid rgba(252, 255, 255, 220); 197 | } 198 | 199 | 200 | FILE 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 0 209 | 65 210 | 211 | 212 | 213 | 214 | 40 215 | true 216 | 217 | 218 | 219 | QPushButton {color: white;} 220 | QPushButton:hover:!pressed 221 | { 222 | background-color: rgba(255, 255,255, 80); 223 | border: 2px solid rgba(252, 255, 255, 210); 224 | } 225 | QPushButton:pressed 226 | { 227 | background-color: rgba(255, 255,255, 100); 228 | border: 2px solid rgba(252, 255, 255, 220); 229 | } 230 | 231 | 232 | FILES 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | background-color: rgba(255, 255,255, 60); 245 | border: 2px solid rgba(252, 255, 255, 80); 246 | border-radius: 10px; 247 | 248 | 249 | 250 | 0 251 | 252 | 253 | 254 | 255 | 256 | 80 257 | true 258 | 259 | 260 | 261 | background-color: none; 262 | color: white; 263 | border: 0px; 264 | 265 | 266 | ENCODE 267 | 268 | 269 | Qt::AlignmentFlag::AlignCenter 270 | 271 | 272 | 273 | 274 | 275 | 276 | 6 277 | 278 | 279 | 280 | 281 | 282 | 0 283 | 65 284 | 285 | 286 | 287 | 288 | 40 289 | true 290 | 291 | 292 | 293 | QPushButton {color: white;} 294 | QPushButton:hover:!pressed 295 | { 296 | background-color: rgba(255, 255,255, 80); 297 | border: 2px solid rgba(252, 255, 255, 210); 298 | } 299 | QPushButton:pressed 300 | { 301 | background-color: rgba(255, 255,255, 100); 302 | border: 2px solid rgba(252, 255, 255, 220); 303 | } 304 | 305 | 306 | FOLDER 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 0 315 | 65 316 | 317 | 318 | 319 | 320 | 40 321 | true 322 | 323 | 324 | 325 | QPushButton {color: white;} 326 | QPushButton:hover:!pressed 327 | { 328 | background-color: rgba(255, 255,255, 80); 329 | border: 2px solid rgba(252, 255, 255, 210); 330 | } 331 | QPushButton:pressed 332 | { 333 | background-color: rgba(255, 255,255, 100); 334 | border: 2px solid rgba(252, 255, 255, 220); 335 | } 336 | 337 | 338 | FOLDERS 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | background-color: rgba(255, 255,255, 60); 351 | border: 2px solid rgba(252, 255, 255, 80); 352 | border-radius: 10px; 353 | 354 | 355 | 356 | 6 357 | 358 | 359 | 360 | 361 | 362 | 65 363 | true 364 | 365 | 366 | 367 | background-color: none; 368 | color: white; 369 | border: 0px; 370 | 371 | 372 | LANGUAGE 373 | 374 | 375 | Qt::AlignmentFlag::AlignCenter 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 0 384 | 0 385 | 386 | 387 | 388 | 389 | 30 390 | true 391 | 392 | 393 | 394 | false 395 | 396 | 397 | QComboBox { 398 | color:white; 399 | margin: 5px; 400 | } 401 | 402 | QComboBox::drop-down { 403 | width: 40px; 404 | } 405 | QComboBox:editable { 406 | background: white; 407 | } 408 | 409 | 410 | false 411 | 412 | 413 | 414 | English 415 | 416 | 417 | 418 | 419 | Русский 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 0 432 | 50 433 | 434 | 435 | 436 | 437 | 20 438 | true 439 | 440 | 441 | 442 | QPushButton:hover:!pressed 443 | { 444 | background-color: rgba(255, 255,255, 100); 445 | border: 2px solid rgba(252, 255, 255, 210); 446 | } 447 | QPushButton:pressed 448 | { 449 | background-color: rgba(255, 255,255, 110); 450 | border: 2px solid rgba(252, 255, 255, 220); 451 | } 452 | QPushButton 453 | { 454 | color: white; 455 | background-color: rgba(255, 255, 255,90); 456 | border: 2px solid rgba(252, 255, 255, 100); 457 | border-radius: 10px; 458 | } 459 | 460 | 461 | 462 | ABOUT 463 | 464 | 465 | 466 | 467 | 468 | 469 | Qt::Orientation::Vertical 470 | 471 | 472 | 473 | 20 474 | 40 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | -------------------------------------------------------------------------------- /ui/processing.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Processing 4 | 5 | 6 | 7 | 0 8 | 0 9 | 540 10 | 900 11 | 12 | 13 | 14 | 15 | 540 16 | 900 17 | 18 | 19 | 20 | DECODE 21 | 22 | 23 | background-color: rgb(4, 15, 15); 24 | 25 | 26 | 27 | 6 28 | 29 | 30 | 31 | 32 | 0 33 | 34 | 35 | 36 | 37 | 38 | 16777215 39 | 100 40 | 41 | 42 | 43 | 44 | 70 45 | true 46 | 47 | 48 | 49 | color: rgb(0, 210, 105); 50 | 51 | 52 | DECODE 53 | 54 | 55 | Qt::AlignmentFlag::AlignHCenter|Qt::AlignmentFlag::AlignTop 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 0 64 | 0 65 | 66 | 67 | 68 | 69 | 16777215 70 | 30 71 | 72 | 73 | 74 | 75 | false 76 | true 77 | true 78 | 79 | 80 | 81 | <html><head/><body><p><a href="tg://resolve?domain=XcoderBS"><span style=" font-size:14pt; text-decoration: underline; color:#007af4;">https://t.me/XcoderBS</span></a></p></body></html> 82 | 83 | 84 | Qt::AlignmentFlag::AlignHCenter|Qt::AlignmentFlag::AlignTop 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 16777215 95 | 80 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 0 107 | 70 108 | 109 | 110 | 111 | 112 | 16777215 113 | 70 114 | 115 | 116 | 117 | 118 | 15 119 | true 120 | 121 | 122 | 123 | color: white; 124 | background-color: rgba(255, 255,255, 60); 125 | border: 2px solid rgba(252, 255, 255, 80); 126 | border-radius: 10px; 127 | 128 | 129 | Qt::ScrollBarPolicy::ScrollBarAlwaysOff 130 | 131 | 132 | Qt::ScrollBarPolicy::ScrollBarAlwaysOff 133 | 134 | 135 | 136 | 137 | 138 | QTextEdit::LineWrapMode::WidgetWidth 139 | 140 | 141 | 142 | 143 | 144 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 145 | <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> 146 | p, li { white-space: pre-wrap; } 147 | hr { height: 1px; border-width: 0; } 148 | li.unchecked::marker { content: "\2610"; } 149 | li.checked::marker { content: "\2612"; } 150 | </style></head><body style=" font-family:'Segoe UI'; font-size:15pt; font-weight:700; font-style:normal;"> 151 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><br /></p></body></html> 152 | 153 | 154 | INPUT FILE 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 100 163 | 70 164 | 165 | 166 | 167 | 168 | 30 169 | true 170 | 171 | 172 | 173 | 174 | QPushButton{ 175 | background-color: rgba(255, 255,255, 60); 176 | border: 2px solid rgba(252, 255, 255, 80); 177 | border-radius: 10px; 178 | color: white;} 179 | QPushButton:hover:!pressed{ 180 | background-color: rgba(255, 255,255, 80); 181 | border: 2px solid rgba(252, 255, 255, 210); 182 | } 183 | QPushButton:pressed{ 184 | background-color: rgba(255, 255,255, 100); 185 | border: 2px solid rgba(252, 255, 255, 220);} 186 | 187 | 188 | SELECT 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 16777215 200 | 80 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 6 209 | 210 | 211 | 0 212 | 213 | 214 | 215 | 216 | 217 | 0 218 | 70 219 | 220 | 221 | 222 | 223 | 16777215 224 | 70 225 | 226 | 227 | 228 | 229 | 15 230 | true 231 | 232 | 233 | 234 | color: white; 235 | background-color: rgba(255, 255,255, 60); 236 | border: 2px solid rgba(252, 255, 255, 80); 237 | border-radius: 10px; 238 | 239 | 240 | Qt::ScrollBarPolicy::ScrollBarAlwaysOff 241 | 242 | 243 | Qt::ScrollBarPolicy::ScrollBarAlwaysOff 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 253 | <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> 254 | p, li { white-space: pre-wrap; } 255 | hr { height: 1px; border-width: 0; } 256 | li.unchecked::marker { content: "\2610"; } 257 | li.checked::marker { content: "\2612"; } 258 | </style></head><body style=" font-family:'Segoe UI'; font-size:15pt; font-weight:700; font-style:normal;"> 259 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><br /></p></body></html> 260 | 261 | 262 | OUT FOLDER (OPTIONALLY) 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 100 271 | 70 272 | 273 | 274 | 275 | 276 | 30 277 | true 278 | 279 | 280 | 281 | 282 | QPushButton{ 283 | background-color: rgba(255, 255,255, 60); 284 | border: 2px solid rgba(252, 255, 255, 80); 285 | border-radius: 10px; 286 | color: white;} 287 | QPushButton:hover:!pressed{ 288 | background-color: rgba(255, 255,255, 80); 289 | border: 2px solid rgba(252, 255, 255, 210); 290 | } 291 | QPushButton:pressed{ 292 | background-color: rgba(255, 255,255, 100); 293 | border: 2px solid rgba(252, 255, 255, 220);} 294 | 295 | 296 | SELECT 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 16777215 308 | 16777215 309 | 310 | 311 | 312 | 313 | border: 2px solid rgba(252, 255, 255, 80); 314 | border-radius: 10px; 315 | 316 | 317 | Qt::ScrollBarPolicy::ScrollBarAlwaysOff 318 | 319 | 320 | Qt::ScrollBarPolicy::ScrollBarAlwaysOff 321 | 322 | 323 | QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents 324 | 325 | 326 | true 327 | 328 | 329 | Qt::AlignmentFlag::AlignCenter 330 | 331 | 332 | 333 | 334 | 0 335 | 0 336 | 518 337 | 374 338 | 339 | 340 | 341 | 342 | 1111111 343 | 16777215 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 0 352 | 353 | 354 | 0 355 | 356 | 357 | 0 358 | 359 | 360 | 0 361 | 362 | 363 | 0 364 | 365 | 366 | 367 | 368 | 369 | 0 370 | 0 371 | 372 | 373 | 374 | 375 | 11111 376 | 16777215 377 | 378 | 379 | 380 | 381 | 20 382 | true 383 | 384 | 385 | 386 | background-color: rgba(255, 255,255, 60); color:white; 387 | 388 | 389 | QFrame::Shape::NoFrame 390 | 391 | 392 | CONSOLE: 393 | 394 | 395 | Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop 396 | 397 | 398 | true 399 | 400 | 401 | 0 402 | 403 | 404 | Qt::TextInteractionFlag::LinksAccessibleByMouse 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 50 417 | true 418 | 419 | 420 | 421 | 422 | QPushButton{ 423 | background-color: rgba(255, 255,255, 60); 424 | border: 2px solid rgba(252, 255, 255, 80); 425 | border-radius: 10px; 426 | color: white;} 427 | QPushButton:hover:!pressed{ 428 | background-color: rgba(255, 255,255, 80); 429 | border: 2px solid rgba(252, 255, 255, 210); 430 | } 431 | QPushButton:pressed{ 432 | background-color: rgba(255, 255,255, 100); 433 | border: 2px solid rgba(252, 255, 255, 220);} 434 | 435 | 436 | DECODE 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 50 445 | true 446 | 447 | 448 | 449 | 450 | QPushButton{ 451 | background-color: rgba(255, 255,255, 60); 452 | border: 2px solid rgba(252, 255, 255, 80); 453 | border-radius: 10px; 454 | color: white;} 455 | QPushButton:hover:!pressed{ 456 | background-color: rgba(255, 255,255, 80); 457 | border: 2px solid rgba(252, 255, 255, 210); 458 | } 459 | QPushButton:pressed{ 460 | background-color: rgba(255, 255,255, 100); 461 | border: 2px solid rgba(252, 255, 255, 220);} 462 | 463 | 464 | CLOSE 465 | 466 | 467 | 468 | 469 | 470 | 471 | Input1 472 | Run 473 | Input2 474 | Select1 475 | Select2 476 | 477 | 478 | 479 | 480 | --------------------------------------------------------------------------------