initial commit
@@ -9,3 +9,5 @@ install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
.vscode
|
||||
build
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(ps4_remote_client)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDONT_HAVE_STRUPR")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
|
||||
|
||||
include_directories(
|
||||
source
|
||||
source/webdav
|
||||
source/pugixml
|
||||
)
|
||||
|
||||
add_executable(ps4_remote_client
|
||||
source/pugixml/pugixml.cpp
|
||||
source/webdav/callback.cpp
|
||||
source/webdav/client.cpp
|
||||
source/webdav/fsinfo.cpp
|
||||
source/webdav/header.cpp
|
||||
source/webdav/request.cpp
|
||||
source/webdav/urn.cpp
|
||||
source/actions.cpp
|
||||
source/config.cpp
|
||||
source/fs.cpp
|
||||
source/ftpclient.cpp
|
||||
source/gui.cpp
|
||||
source/getentropy.c
|
||||
source/ime_dialog.cpp
|
||||
source/inifile.c
|
||||
source/installer.cpp
|
||||
source/lang.cpp
|
||||
source/main.cpp
|
||||
source/orbis_jbc.c
|
||||
source/rtc.cpp
|
||||
source/smbclient.cpp
|
||||
source/windows.cpp
|
||||
source/webdavclient.cpp
|
||||
source/imgui_draw.cpp
|
||||
source/imgui_impl_sdl.cpp
|
||||
source/imgui_impl_sdlrenderer.cpp
|
||||
source/imgui_tables.cpp
|
||||
source/imgui_widgets.cpp
|
||||
source/imgui.cpp
|
||||
)
|
||||
|
||||
add_self(ps4_remote_client)
|
||||
|
||||
add_pkg(ps4_remote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "PS4 Remote Client" "01.00" 32 0)
|
||||
|
||||
target_link_libraries(ps4_remote_client
|
||||
c
|
||||
c++
|
||||
png
|
||||
z
|
||||
pthread
|
||||
SDL2
|
||||
samplerate
|
||||
jbc
|
||||
crypto
|
||||
ssl
|
||||
curl
|
||||
lexbor
|
||||
smb2
|
||||
kernel
|
||||
SceShellCoreUtil
|
||||
SceSysmodule
|
||||
SceSystemService
|
||||
ScePigletv2VSH
|
||||
ScePrecompiledShaders
|
||||
SceRtc
|
||||
SceUserService
|
||||
ScePad
|
||||
SceAudioOut
|
||||
SceSysUtil
|
||||
SceImeDialog
|
||||
SceNet
|
||||
SceBgft
|
||||
SceAppInstUtil
|
||||
)
|
||||
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,75 @@
|
||||
STR_CONNECTION_SETTINGS=إعداد الاتصال
|
||||
STR_SITE=الموقع
|
||||
STR_LOCAL=محلي
|
||||
STR_REMOTE=بعيد
|
||||
STR_MESSAGES=الرسائل
|
||||
STR_UPDATE_SOFTWARE=تحديث التطبيق
|
||||
STR_CONNECT_WEBDAV=توصيل
|
||||
STR_DISCONNECT_WEBDAV=قطع الاتصال
|
||||
STR_SEARCH=بحث
|
||||
STR_REFRESH=تحديث
|
||||
STR_SERVER=الخادم
|
||||
STR_USERNAME=اسم المستخدم
|
||||
STR_PASSWORD=كلمة المرور
|
||||
STR_PORT=المنفذ
|
||||
STR_PASV=متجاوز
|
||||
STR_DIRECTORY=المسار
|
||||
STR_FILTER=الفلتر
|
||||
STR_YES=نعم
|
||||
STR_NO=لا
|
||||
STR_CANCEL=إلغاء
|
||||
STR_CONTINUE=استمرار
|
||||
STR_CLOSE=اغلاق
|
||||
STR_FOLDER=المجلد
|
||||
STR_FILE=الملف
|
||||
STR_TYPE=النوع
|
||||
STR_NAME=الاسم
|
||||
STR_SIZE=الحجم
|
||||
STR_DATE=التاريخ
|
||||
STR_NEW_FOLDER=مجلد جديد
|
||||
STR_RENAME=أعادة تسمية
|
||||
STR_DELETE=حذف
|
||||
STR_UPLOAD=رفع
|
||||
STR_DOWNLOAD=تحميل
|
||||
STR_SELECT_ALL=تحديد الكل
|
||||
STR_CLEAR_ALL=تجاهل الكل
|
||||
STR_UPLOADING=قيد الرفع
|
||||
STR_DOWNLOADING=قيد التحميل
|
||||
STR_OVERWRITE=الكتابة فوق
|
||||
STR_DONT_OVERWRITE=لاتكتب فوق
|
||||
STR_ASK_FOR_CONFIRM=أسال لتأكيد
|
||||
STR_DONT_ASK_CONFIRM=لاتسأل لتأكيد
|
||||
STR_ALLWAYS_USE_OPTION=استخدم هذا الاختيار بشكل دائم ولاتسأل مجددا
|
||||
STR_ACTIONS=الإجراءات
|
||||
STR_CONFIRM=تأكيد
|
||||
STR_OVERWRITE_OPTIONS=خيارات الاستبدال او الكتابة فوق
|
||||
STR_PROPERTIES=الخصائص
|
||||
STR_PROGRESS=التقدم
|
||||
STR_UPDATES=التحديثات
|
||||
STR_DEL_CONFIRM_MSG=هل انت متأكد من اجراء حذف حذف الملف او المجلد?
|
||||
STR_CANCEL_ACTION_MSG=قيد الإلغاء. بأنتظار الاتصال الاخير ليتم إلغائه
|
||||
STR_FAIL_UPLOAD_MSG=فشل في رفع الملف
|
||||
STR_FAIL_DOWNLOAD_MSG=فشل في تحميل الملف
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=فشل في قراءة محتويات المسار او المجلد غير متوفر.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=٤٢٦ أغلق الاتصال.
|
||||
STR_REMOTE_TERM_CONN_MSG=٤٢٦ الخادم البعيد قطع الإتصال.
|
||||
STR_FAIL_LOGIN_MSG=٣٠٠ فشل تسجيل الدخول. الرجاء التاكد من اسم المستخدم وكلمة المرور.
|
||||
STR_FAIL_TIMEOUT_MSG=٤٢٦ فشل. انتهى الاتصال.
|
||||
STR_FAIL_DEL_DIR_MSG=فشل في حذف المسار
|
||||
STR_DELETING=قيد الحذف
|
||||
STR_FAIL_DEL_FILE_MSG=فشل في حذف الملف
|
||||
STR_DELETED=تم الحذف
|
||||
STR_LINK=ربط
|
||||
STR_SHARE=مشاركة
|
||||
STR_FAILED=٣١٠ فشل
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG= فشل في انشاء الملف في المحلي ٣١٠
|
||||
STR_INSTALL=تثبيت
|
||||
STR_INSTALLING=يقوم بالتثبيت
|
||||
STR_INSTALL_SUCCESS=تم بنجاح
|
||||
STR_INSTALL_FAILED=فشل
|
||||
STR_INSTALL_SKIPPED=تم التخطي
|
||||
STR_CHECK_HTTP_MSG=فحص الإتصال بخادم HTTP البعيد
|
||||
STR_FAILED_HTTP_CHECK=فشل الإتصال بخادم HTTP
|
||||
STR_REMOTE_NOT_HTTP=البعيد ليس خادم HTTP
|
||||
STR_INSTALL_FROM_DATA_MSG=الحزمة غير متوفرة في /data او /mnt/usbX مجلد
|
||||
STR_ALREADY_INSTALLED_MSG=الحزمة مثبتة مسبقا
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Configuració de connexió
|
||||
STR_SITE=Lloc
|
||||
STR_LOCAL=Local
|
||||
STR_REMOTE=Remot
|
||||
STR_MESSAGES=Missatges
|
||||
STR_UPDATE_SOFTWARE=Actualització de programari
|
||||
STR_CONNECT_WEBDAV=Connectar
|
||||
STR_DISCONNECT_WEBDAV=Desconnectar
|
||||
STR_SEARCH=Cercar
|
||||
STR_REFRESH=Refrescar
|
||||
STR_SERVER=Servidor
|
||||
STR_USERNAME=Nom d'usuari
|
||||
STR_PASSWORD=Mot de pas
|
||||
STR_PORT=Port
|
||||
STR_PASV=Passiu
|
||||
STR_DIRECTORY=Directori
|
||||
STR_FILTER=Filtre
|
||||
STR_YES=Sí
|
||||
STR_NO=No
|
||||
STR_CANCEL=Cancel·lar
|
||||
STR_CONTINUE=Continuar
|
||||
STR_CLOSE=Tancar
|
||||
STR_FOLDER=Carpeta
|
||||
STR_FILE=Arxiu
|
||||
STR_TYPE=Tipus
|
||||
STR_NAME=Nom
|
||||
STR_SIZE=Mida
|
||||
STR_DATE=Data
|
||||
STR_NEW_FOLDER=Nova carpeta
|
||||
STR_RENAME=Reanomenar
|
||||
STR_DELETE=Esborrar
|
||||
STR_UPLOAD=Pujar
|
||||
STR_DOWNLOAD=Descarregar
|
||||
STR_SELECT_ALL=Seleccionar tot
|
||||
STR_CLEAR_ALL=Netejar tot
|
||||
STR_UPLOADING=Pujant
|
||||
STR_DOWNLOADING=Descarregant
|
||||
STR_OVERWRITE=Sobreescriure
|
||||
STR_DONT_OVERWRITE=No sobreescriguis
|
||||
STR_ASK_FOR_CONFIRM=Demana confirmació
|
||||
STR_DONT_ASK_CONFIRM=No demanis confirmació
|
||||
STR_ALLWAYS_USE_OPTION=Empra sempre aquesta opció i no tornis a preguntar
|
||||
STR_ACTIONS=Accions
|
||||
STR_CONFIRM=Confirmar
|
||||
STR_OVERWRITE_OPTIONS=Opcions de sobreescritura
|
||||
STR_PROPERTIES=Propietats
|
||||
STR_PROGRESS=Progrés
|
||||
STR_UPDATES=Actualitzacions
|
||||
STR_DEL_CONFIRM_MSG=Realment vols esborrar aquest fitxer(s)/carpeta(s)?
|
||||
STR_CANCEL_ACTION_MSG=Cancel·lant. Esperant a que es completi la última acció.
|
||||
STR_FAIL_UPLOAD_MSG=Errada al pujar fitxer.
|
||||
STR_FAIL_DOWNLOAD_MSG=Errada al descarregar fitxer.
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Errada al llegir els continguts del directori o el directori no existeix.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Connexió tancada.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 El servidor remot ha tancat la connexió.
|
||||
STR_FAIL_LOGIN_MSG=300 Inici de sessió fallit. Si us plau, comproba el nom d'usuari i mot de pas.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Fallit. S'ha superat el temps màxim d'espera de connexió.
|
||||
STR_FAIL_DEL_DIR_MSG=Errada a l'esborrar la carpeta.
|
||||
STR_DELETING=Esborrant.
|
||||
STR_FAIL_DEL_FILE_MSG=Error a l'esborrar el fitxer.
|
||||
STR_DELETED=Esborrat.
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Postavke spajanja
|
||||
STR_SITE=Stranica
|
||||
STR_LOCAL=Lokalno
|
||||
STR_REMOTE=Daljinsko
|
||||
STR_MESSAGES=Poruke
|
||||
STR_UPDATE_SOFTWARE=Ažuriranje softvera
|
||||
STR_CONNECT_WEBDAV=Spajanje
|
||||
STR_DISCONNECT_WEBDAV=Odspajanje
|
||||
STR_SEARCH=Pretražiti
|
||||
STR_REFRESH=Osvježiti
|
||||
STR_SERVER=Server
|
||||
STR_USERNAME=Korisničko ime
|
||||
STR_PASSWORD=Šifra
|
||||
STR_PORT=Port
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Direktorij
|
||||
STR_FILTER=Filter
|
||||
STR_YES=Da
|
||||
STR_NO=Ne
|
||||
STR_CANCEL=Odustani
|
||||
STR_CONTINUE=Nastavi
|
||||
STR_CLOSE=Zatvori
|
||||
STR_FOLDER=Mapa
|
||||
STR_FILE=Datoteka
|
||||
STR_TYPE=Tip
|
||||
STR_NAME=Ime
|
||||
STR_SIZE=Veličina
|
||||
STR_DATE=Datum
|
||||
STR_NEW_FOLDER=Nova mapa
|
||||
STR_RENAME=Preimenovati
|
||||
STR_DELETE=Izbrisati
|
||||
STR_UPLOAD=Učitati
|
||||
STR_DOWNLOAD=Skinuti
|
||||
STR_SELECT_ALL=Izabrati sve
|
||||
STR_CLEAR_ALL=Pobrisati sve
|
||||
STR_UPLOADING=Učitavanje
|
||||
STR_DOWNLOADING=Skidanje
|
||||
STR_OVERWRITE=Prebrisati
|
||||
STR_DONT_OVERWRITE=Nemoj prebrisati
|
||||
STR_ASK_FOR_CONFIRM=Pitati za dopuštenje
|
||||
STR_DONT_ASK_CONFIRM=Nemoj pitati za dopuštenje
|
||||
STR_ALLWAYS_USE_OPTION=Uvijek koristiti ovu opciju i ne pitaj me više
|
||||
STR_ACTIONS=Akcija
|
||||
STR_CONFIRM=Potvrdi
|
||||
STR_OVERWRITE_OPTIONS=Prebrisati opcije
|
||||
STR_PROPERTIES=Svojstva
|
||||
STR_PROGRESS=Napredak
|
||||
STR_UPDATES=Ažuriranja
|
||||
STR_DEL_CONFIRM_MSG=Dali ste sigurni da želite izbrisati ovu/e mapu/e, datoteku/e?
|
||||
STR_CANCEL_ACTION_MSG=Odustajanje. Čekanje da završi zadnji zadatak
|
||||
STR_FAIL_UPLOAD_MSG=Neuspješno učitavanje podataka
|
||||
STR_FAIL_DOWNLOAD_MSG=Neuspješno skidanje podataka
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Neuspješno čitanje sadržaja ova datoteka ili mapa ne postoji
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Koneckija zatvorena
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Daljinski server je prekinio konekciju
|
||||
STR_FAIL_LOGIN_MSG=300 Neuspjelo ulogiranje. Provjerite svoje korisničko ime i šifru.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Neuspjelo. Konekcijska pauza
|
||||
STR_FAIL_DEL_DIR_MSG=Neuspješno brisanje mape
|
||||
STR_DELETING=Brisanje
|
||||
STR_FAIL_DEL_FILE_MSG=Neuspješno brisanje datoteke
|
||||
STR_DELETED=Obrisano
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Verbindingsinstellingen
|
||||
STR_SITE=Site
|
||||
STR_LOCAL=Lokaal
|
||||
STR_REMOTE=Extern
|
||||
STR_MESSAGES=Berichten
|
||||
STR_UPDATE_SOFTWARE=Update Software
|
||||
STR_CONNECT_WEBDAV=Verbind met
|
||||
STR_DISCONNECT_WEBDAV=Verbreek verbinding met
|
||||
STR_SEARCH=Zoek
|
||||
STR_REFRESH=Vernieuw
|
||||
STR_SERVER=Server
|
||||
STR_USERNAME=Gebruikersnaam
|
||||
STR_PASSWORD=Wachtwoord
|
||||
STR_PORT=Poort
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Locatie
|
||||
STR_FILTER=Filter
|
||||
STR_YES=Ja
|
||||
STR_NO=Nee
|
||||
STR_CANCEL=Annuleren
|
||||
STR_CONTINUE=Ga door
|
||||
STR_CLOSE=Sluit
|
||||
STR_FOLDER=Map
|
||||
STR_FILE=Bestand
|
||||
STR_TYPE=Type
|
||||
STR_NAME=Naam
|
||||
STR_SIZE=Grootte
|
||||
STR_DATE=Datum
|
||||
STR_NEW_FOLDER=Nieuwe Map
|
||||
STR_RENAME=Hernoemen
|
||||
STR_DELETE=Verwijderen
|
||||
STR_UPLOAD=Upload
|
||||
STR_DOWNLOAD=Download
|
||||
STR_SELECT_ALL=Alles selecteren
|
||||
STR_CLEAR_ALL=Alles wissen
|
||||
STR_UPLOADING=Uploaden
|
||||
STR_DOWNLOADING=Downloaden
|
||||
STR_OVERWRITE=Overschrijven
|
||||
STR_DONT_OVERWRITE=Niet Overschrijven
|
||||
STR_ASK_FOR_CONFIRM=Vraag om bevestiging
|
||||
STR_DONT_ASK_CONFIRM=Vraag niet om bevestiging
|
||||
STR_ALLWAYS_USE_OPTION=Gebruik altijd deze optie en niet opnieuw vragen
|
||||
STR_ACTIONS=Acties
|
||||
STR_CONFIRM=Bevestig
|
||||
STR_OVERWRITE_OPTIONS=Opties Overschrijven
|
||||
STR_PROPERTIES=Eigenschappen
|
||||
STR_PROGRESS=Voortgang
|
||||
STR_UPDATES=Updates
|
||||
STR_DEL_CONFIRM_MSG=Ben je zeker dat je dit(deze) bestand(en) of map(pen) wilt verwijderen?
|
||||
STR_CANCEL_ACTION_MSG=Annuleren. Wachten tot de laatste actie voltooid is.
|
||||
STR_FAIL_UPLOAD_MSG=Uploaden van bestand mislukt
|
||||
STR_FAIL_DOWNLOAD_MSG=Downloaden van bestand mislukt
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Lezen van inhoud mislukt, map is onbekend
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Verbinding verbroken.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Externe server heeft de verbinding verbroken.
|
||||
STR_FAIL_LOGIN_MSG=300 Inloggen mislukt. Controleer je gebruikersnaam of wachtwoord.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Mislukt. Verbinding time-out.
|
||||
STR_FAIL_DEL_DIR_MSG=Verwijderen van map mislukt.
|
||||
STR_DELETING=Verwijderen
|
||||
STR_FAIL_DEL_FILE_MSG=Verwijderen van bestand mislukt.
|
||||
STR_DELETED=Verwijderd
|
||||
@@ -0,0 +1,88 @@
|
||||
STR_CONNECTION_SETTINGS=Connection Settings
|
||||
STR_SITE=Site
|
||||
STR_LOCAL=Local
|
||||
STR_REMOTE=Remote
|
||||
STR_MESSAGES=Messages
|
||||
STR_UPDATE_SOFTWARE=Update Software
|
||||
STR_CONNECT_WEBDAV=Connect
|
||||
STR_DISCONNECT_WEBDAV=Disconnect
|
||||
STR_SEARCH=Search
|
||||
STR_REFRESH=Refresh
|
||||
STR_SERVER=Server
|
||||
STR_USERNAME=Username
|
||||
STR_PASSWORD=Password
|
||||
STR_PORT=Port
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Directory
|
||||
STR_FILTER=Filter
|
||||
STR_YES=Yes
|
||||
STR_NO=No
|
||||
STR_CANCEL=Cancel
|
||||
STR_CONTINUE=Continue
|
||||
STR_CLOSE=Close
|
||||
STR_FOLDER=Folder
|
||||
STR_FILE=File
|
||||
STR_TYPE=Type
|
||||
STR_NAME=Name
|
||||
STR_SIZE=Size
|
||||
STR_DATE=Date
|
||||
STR_NEW_FOLDER=New Folder
|
||||
STR_RENAME=Rename
|
||||
STR_DELETE=Delete
|
||||
STR_UPLOAD=Upload
|
||||
STR_DOWNLOAD=Download
|
||||
STR_SELECT_ALL=Select All
|
||||
STR_CLEAR_ALL=Clear All
|
||||
STR_UPLOADING=Uploading
|
||||
STR_DOWNLOADING=Downloading
|
||||
STR_OVERWRITE=Overwrite
|
||||
STR_DONT_OVERWRITE=Don't Overwrite
|
||||
STR_ASK_FOR_CONFIRM=Ask for Confirmation
|
||||
STR_DONT_ASK_CONFIRM=Don't Ask for Confirmation
|
||||
STR_ALLWAYS_USE_OPTION=Always use this option and don't ask again
|
||||
STR_ACTIONS=Actions
|
||||
STR_CONFIRM=Confirm
|
||||
STR_OVERWRITE_OPTIONS=Overwrite Options
|
||||
STR_PROPERTIES=Properties
|
||||
STR_PROGRESS=Progress
|
||||
STR_UPDATES=Updates
|
||||
STR_DEL_CONFIRM_MSG=Are you sure you want to delete this file(s)/folder(s)?
|
||||
STR_CANCEL_ACTION_MSG=Canceling. Waiting for last action to complete
|
||||
STR_FAIL_UPLOAD_MSG=Failed to upload file
|
||||
STR_FAIL_DOWNLOAD_MSG=Failed to download file
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Failed to read contents of directory or folder does not exist.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Connection closed.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Remote Server has terminated the connection.
|
||||
STR_FAIL_LOGIN_MSG=300 Failed Login. Please check your username or password.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Failed. Connection timeout.
|
||||
STR_FAIL_DEL_DIR_MSG=Failed to delete directory
|
||||
STR_DELETING=Deleting
|
||||
STR_FAIL_DEL_FILE_MSG=Failed to delete file
|
||||
STR_DELETED=Deleted
|
||||
STR_LINK=Link
|
||||
STR_SHARE=Share
|
||||
STR_FAILED=310 Failed
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 Failed to create file on local
|
||||
STR_INSTALL=Install
|
||||
STR_INSTALLING=Installing
|
||||
STR_INSTALL_SUCCESS=Success
|
||||
STR_INSTALL_FAILED=Failed
|
||||
STR_INSTALL_SKIPPED=Skipped
|
||||
STR_CHECK_HTTP_MSG=Checking connection to remote HTTP Server
|
||||
STR_FAILED_HTTP_CHECK=Failed connecting to HTTP Server
|
||||
STR_REMOTE_NOT_HTTP=Remote is not a HTTP Server
|
||||
STR_INSTALL_FROM_DATA_MSG=Package not in the /data or /mnt/usbX folder
|
||||
STR_ALREADY_INSTALLED_MSG=Package is already installed
|
||||
STR_INSTALL_FROM_URL=Install from URL
|
||||
STR_CANNOT_READ_PKG_HDR_MSG=Could not read package header info
|
||||
STR_FAVORITE_URLS=Favorite URLs
|
||||
STR_SLOT=Slot
|
||||
STR_EDIT=Edit
|
||||
STR_ONETIME_URL=One Time Url
|
||||
STR_NOT_A_VALID_PACKAGE=Not a valid Package
|
||||
STR_WAIT_FOR_INSTALL_MSG=Waiting for Package to finish installing
|
||||
STR_FAIL_INSTALL_TMP_PKG_MSG=Failed to install pkg file. Please delete the tmp pkg manually
|
||||
STR_FAIL_TO_OBTAIN_GG_DL_MSG=Failed to obtain google download URL
|
||||
STR_AUTO_DELETE_TMP_PKG=Auto delete temporary downloaded pkg file after install
|
||||
STR_PROTOCOL_NOT_SUPPORTED=Protocol not supported
|
||||
STR_COULD_NOT_RESOLVE_HOST=Could not resolve hostname
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Konexio ezarpenak
|
||||
STR_SITE=Gunea
|
||||
STR_LOCAL=Lekuko
|
||||
STR_REMOTE=Urrunekoa
|
||||
STR_MESSAGES=Mezuak
|
||||
STR_UPDATE_SOFTWARE=Eguneratu Softwarea
|
||||
STR_CONNECT_WEBDAV=Konektatu
|
||||
STR_DISCONNECT_WEBDAV=Deskonektatu
|
||||
STR_SEARCH=Bilatu
|
||||
STR_REFRESH=Freskatu
|
||||
STR_SERVER=Zerbitzaria
|
||||
STR_USERNAME=Erabiltzaile izena
|
||||
STR_PASSWORD=Pasahitza
|
||||
STR_PORT=Portua
|
||||
STR_PASV=Pasiboa
|
||||
STR_DIRECTORY=Direktorioa
|
||||
STR_FILTER=Iragazkia
|
||||
STR_YES=Bai
|
||||
STR_NO=Ez
|
||||
STR_CANCEL=Utzi
|
||||
STR_CONTINUE=Jarraitu
|
||||
STR_CLOSE=Itxi
|
||||
STR_FOLDER=Karpeta
|
||||
STR_FILE=Fitxategia
|
||||
STR_TYPE=Mota
|
||||
STR_NAME=Izena
|
||||
STR_SIZE=Tamaina
|
||||
STR_DATE=Data
|
||||
STR_NEW_FOLDER=Karpeta berria
|
||||
STR_RENAME=Aldatu izena
|
||||
STR_DELETE=Ezabatu
|
||||
STR_UPLOAD=Kargatu
|
||||
STR_DOWNLOAD=Deskargatu
|
||||
STR_SELECT_ALL=Hautatu guztiak
|
||||
STR_CLEAR_ALL=Garbitu guztiak
|
||||
STR_UPLOADING=Kargatzen
|
||||
STR_DOWNLOADING=Deskargatzen
|
||||
STR_OVERWRITE=Gainidatzi
|
||||
STR_DONT_OVERWRITE=Ez gainidatzi
|
||||
STR_ASK_FOR_CONFIRM=Baieztapena eskatu
|
||||
STR_DONT_ASK_CONFIRM=Ez eskatu baieztapena
|
||||
STR_ALLWAYS_USE_OPTION=Erabili beti aukera hau eta ez galdetu berriro
|
||||
STR_ACTIONS=Ekintzak
|
||||
STR_CONFIRM=Berretsi
|
||||
STR_OVERWRITE_OPTIONS=Gainidatzi aukerak
|
||||
STR_PROPERTIES=Propietateak
|
||||
STR_PROGRESS=Aurrerapena
|
||||
STR_UPDATES=Eguneraketak
|
||||
STR_DEL_CONFIRM_MSG=Ziur fitxategi/karpeta hau(k) ezabatu nahi duzula?
|
||||
STR_CANCEL_ACTION_MSG=Bertan behera uzten. Azken ekintza amaitzeko zain
|
||||
STR_FAIL_UPLOAD_MSG=Ezin izan da fitxategia kargatu
|
||||
STR_FAIL_DOWNLOAD_MSG=Ezin izan da deskargatu fitxategia
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Ezin izan da direktorioa edo karpetaren edukia irakurtzean existitzen.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Konexioa itxita.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Urruneko zerbitzariak konexioa amaitu du.
|
||||
STR_FAIL_LOGIN_MSG=300 Ezin izan da saioa hasi. Mesedez, egiaztatu zure erabiltzaile-izena edo pasahitza.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Huts egin. Konexioaren denbora-muga.
|
||||
STR_FAIL_DEL_DIR_MSG=Ezin izan da ezabatu direktorioa
|
||||
STR_DELETING=Ezabatzen
|
||||
STR_FAIL_DEL_FILE_MSG=Ezin izan da fitxategia ezabatu
|
||||
STR_DELETED=Ezabatu da
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Paramètres de connexion
|
||||
STR_SITE=Site
|
||||
STR_LOCAL=Local
|
||||
STR_REMOTE=A distance
|
||||
STR_MESSAGES=Messages
|
||||
STR_UPDATE_SOFTWARE=Mise à jour logicielle
|
||||
STR_CONNECT_WEBDAV=Connexion
|
||||
STR_DISCONNECT_WEBDAV=Déconnexion
|
||||
STR_SEARCH=Rechercher
|
||||
STR_REFRESH=Rafraîchir
|
||||
STR_SERVER=Serveur
|
||||
STR_USERNAME=Identifiant
|
||||
STR_PASSWORD=Mot de passe
|
||||
STR_PORT=Port
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Répertoire
|
||||
STR_FILTER=Filtre
|
||||
STR_YES=Oui
|
||||
STR_NO=Non
|
||||
STR_CANCEL=Annuler
|
||||
STR_CONTINUE=Continuer
|
||||
STR_CLOSE=Fermer
|
||||
STR_FOLDER=Dossier
|
||||
STR_FILE=Fichier
|
||||
STR_TYPE=Type
|
||||
STR_NAME=Nom
|
||||
STR_SIZE=Taille
|
||||
STR_DATE=Date
|
||||
STR_NEW_FOLDER=Nouveau dossier
|
||||
STR_RENAME=Renommer
|
||||
STR_DELETE=Supprimer
|
||||
STR_UPLOAD=Uploader
|
||||
STR_DOWNLOAD=Télécharger
|
||||
STR_SELECT_ALL=Tout sélectionner
|
||||
STR_CLEAR_ALL=Tout vider
|
||||
STR_UPLOADING=En cours d'upload
|
||||
STR_DOWNLOADING=En cours de téléchargement
|
||||
STR_OVERWRITE=Remplacer
|
||||
STR_DONT_OVERWRITE=Ne pas remplacer
|
||||
STR_ASK_FOR_CONFIRM=Demander confirmation
|
||||
STR_DONT_ASK_CONFIRM=Ne pas demander confirmation
|
||||
STR_ALLWAYS_USE_OPTION=Toujours utiliser cette option et ne plus jamais me demander
|
||||
STR_ACTIONS=Actions
|
||||
STR_CONFIRM=Confirmer
|
||||
STR_OVERWRITE_OPTIONS=Remplacer les options
|
||||
STR_PROPERTIES=Propriétés
|
||||
STR_PROGRESS=Etat d'avancement
|
||||
STR_UPDATES=Mises à jour
|
||||
STR_DEL_CONFIRM_MSG=Êtes vous sûr de vouloir supprimer ce(s) fichier(s)/dossier(s) ?
|
||||
STR_CANCEL_ACTION_MSG=En cours d'annulation. En attente de la fin de la dernière action.
|
||||
STR_FAIL_UPLOAD_MSG=Echec de l'upload du fichier
|
||||
STR_FAIL_DOWNLOAD_MSG=Echec du téléchargement du fichier
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Echec de la lecture du contenu du dossier/le dossier n'existe pas.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Connexion interrompue
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Le serveur à distance à interrompu la connexion
|
||||
STR_FAIL_LOGIN_MSG=300 Echec d'identification. Merci de vérifier votre identifiant et votre mot de passe
|
||||
STR_FAIL_TIMEOUT_MSG=426 Echec. La connection a mis trop de temps à répondre
|
||||
STR_FAIL_DEL_DIR_MSG=Echec de la suppression du dossier
|
||||
STR_DELETING=En cours de suppression
|
||||
STR_FAIL_DEL_FILE_MSG=Echec de la suppression du fichier
|
||||
STR_DELETED=Supprimé
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Axustes de conexión
|
||||
STR_SITE=Sitio
|
||||
STR_LOCAL=Local
|
||||
STR_REMOTE=Remoto
|
||||
STR_MESSAGES=Mensaxes
|
||||
STR_UPDATE_SOFTWARE=Actualizar Software
|
||||
STR_CONNECT_WEBDAV=Conectar
|
||||
STR_DISCONNECT_WEBDAV=Desconectar
|
||||
STR_SEARCH=Busca
|
||||
STR_REFRESH=Actualizar
|
||||
STR_SERVER=Servidor
|
||||
STR_USERNAME=Nome de usuario
|
||||
STR_PASSWORD=Contrasinal
|
||||
STR_PORT=Porto
|
||||
STR_PASV=Pasivo
|
||||
STR_DIRECTORY=Directorio
|
||||
STR_FILTER=Filtro
|
||||
STR_YES=Si
|
||||
STR_NO=Non
|
||||
STR_CANCEL=Cancelar
|
||||
STR_CONTINUE=Continuar
|
||||
STR_CLOSE=Pechar
|
||||
STR_FOLDER=Carpeta
|
||||
STR_FILE=Arquivo
|
||||
STR_TYPE=Tipo
|
||||
STR_NAME=Nome
|
||||
STR_SIZE=Tamaño
|
||||
STR_DATE=Data
|
||||
STR_NEW_FOLDER=Nova carpeta
|
||||
STR_RENAME=Renomear
|
||||
STR_DELETE=Eliminar
|
||||
STR_UPLOAD=Cargar
|
||||
STR_DOWNLOAD=Descargar
|
||||
STR_SELECT_ALL=Seleccionar todo
|
||||
STR_CLEAR_ALL=Limpar todo
|
||||
STR_UPLOADING=Cargando
|
||||
STR_DOWNLOADING=Descargando
|
||||
STR_OVERWRITE=Sobrescribir
|
||||
STR_DONT_OVERWRITE=Non sobrescribir
|
||||
STR_ASK_FOR_CONFIRM=Pedir confirmación
|
||||
STR_DONT_ASK_CONFIRM=Non pidas confirmación
|
||||
STR_ALLWAYS_USE_OPTION=Use sempre esta opción e non volva preguntar
|
||||
STR_ACTIONS=Accións
|
||||
STR_CONFIRM=Confirmar
|
||||
STR_OVERWRITE_OPTIONS=Opcións de sobrescritura
|
||||
STR_PROPERTIES=Propiedades
|
||||
STR_PROGRESS=Progreso
|
||||
STR_UPDATES=Actualizacións
|
||||
STR_DEL_CONFIRM_MSG=Estás seguro de que queres eliminar este(s) ficheiro(s)/cartafol(s)?
|
||||
STR_CANCEL_ACTION_MSG=Cancelando. Agardando a que se complete a última acción.
|
||||
STR_FAIL_UPLOAD_MSG=Produciuse un erro ao cargar o ficheiro.
|
||||
STR_FAIL_DOWNLOAD_MSG=Produciuse un erro ao descargar o ficheiro.
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Non se puido ler o contido do directorio ou cartafol non existe.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Conexión pechada.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 O servidor remoto rematou a conexión.
|
||||
STR_FAIL_LOGIN_MSG=300 Fallou o inicio de sesión. Comproba o teu nome de usuario ou contrasinal.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Fallou. Superouse o tempo de espera da conexión.
|
||||
STR_FAIL_DEL_DIR_MSG=Produciuse un erro ao eliminar o directorio.
|
||||
STR_DELETING=Eliminando...
|
||||
STR_FAIL_DEL_FILE_MSG=Produciuse un erro ao eliminar o ficheiro.
|
||||
STR_DELETED=Eliminado.
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Verbindungseinstellungen
|
||||
STR_SITE=Site
|
||||
STR_LOCAL=Lokal
|
||||
STR_REMOTE=Remote
|
||||
STR_MESSAGES=Nachrichten
|
||||
STR_UPDATE_SOFTWARE=Software aktualisieren
|
||||
STR_CONNECT_WEBDAV=Verbinde
|
||||
STR_DISCONNECT_WEBDAV=Trenne
|
||||
STR_SEARCH=Suchen
|
||||
STR_REFRESH=Aktualisieren
|
||||
STR_SERVER=Server
|
||||
STR_USERNAME=Benutzername
|
||||
STR_PASSWORD=Passwort
|
||||
STR_PORT=Port
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Verzeichnis
|
||||
STR_FILTER=Filter
|
||||
STR_YES=Ja
|
||||
STR_NO=Nein
|
||||
STR_CANCEL=Abbrechen
|
||||
STR_CONTINUE=Fortfahren
|
||||
STR_CLOSE=Schließen
|
||||
STR_FOLDER=Ordner
|
||||
STR_FILE=Datei
|
||||
STR_TYPE=Typ
|
||||
STR_NAME=Name
|
||||
STR_SIZE=Größe
|
||||
STR_DATE=Datum
|
||||
STR_NEW_FOLDER=Neuer Ordner
|
||||
STR_RENAME=Umbenennen
|
||||
STR_DELETE=Löschen
|
||||
STR_UPLOAD=Hochladen
|
||||
STR_DOWNLOAD=Herunterladen
|
||||
STR_SELECT_ALL=Alles auswählen
|
||||
STR_CLEAR_ALL=Alles abwählen
|
||||
STR_UPLOADING=Hochladen
|
||||
STR_DOWNLOADING=Herunterladen
|
||||
STR_OVERWRITE=Überschreiben
|
||||
STR_DONT_OVERWRITE=Nicht Überschreiben
|
||||
STR_ASK_FOR_CONFIRM=Nach einer Bestätigung fragen
|
||||
STR_DONT_ASK_CONFIRM=Nicht nach einer Bestätigung fragen
|
||||
STR_ALLWAYS_USE_OPTION=Immer diese Option verwenden und nicht mehr nachfragen
|
||||
STR_ACTIONS=Aktionen
|
||||
STR_CONFIRM=Bestätigen
|
||||
STR_OVERWRITE_OPTIONS=Optionen für das Überschreiben
|
||||
STR_PROPERTIES=Eigenschaften
|
||||
STR_PROGRESS=Fortschritt
|
||||
STR_UPDATES=Updates
|
||||
STR_DEL_CONFIRM_MSG=Sind Sie sicher, dass Sie diese Datei(en)/Ordner löschen wollen?
|
||||
STR_CANCEL_ACTION_MSG=Abbruch. Warte auf Abschluss der letzten Aktion
|
||||
STR_FAIL_UPLOAD_MSG=Dateiupload gescheitert
|
||||
STR_FAIL_DOWNLOAD_MSG=Dateidownload gescheitert
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Inhalt des Verzeichnisses konnte nicht gelesen werden oder der Ordner existiert nicht.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Verbindung getrennt.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Remote Server hat die die Verbindung getrennt.
|
||||
STR_FAIL_LOGIN_MSG=300 Login fehlgeschlagen. Bitte Passwort und Benutzernamen überprüfen.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Fehler. Verbindung abgelaufen.
|
||||
STR_FAIL_DEL_DIR_MSG=Verzeichnis konnte nicht gelöscht werden
|
||||
STR_DELETING=Löschen
|
||||
STR_FAIL_DEL_FILE_MSG=Datei konnte nicht gelöscht werden
|
||||
STR_DELETED=Gelöscht
|
||||
@@ -0,0 +1,75 @@
|
||||
STR_CONNECTION_SETTINGS=Ρυθμίσεις Σύνδεσης
|
||||
STR_SITE=Τοποθεσία
|
||||
STR_LOCAL=Τοπικό
|
||||
STR_REMOTE=Remote
|
||||
STR_MESSAGES=Απομακρυσμένο
|
||||
STR_UPDATE_SOFTWARE=Ενημέρωση Λογισμικού
|
||||
STR_CONNECT_WEBDAV=Σύνδεση
|
||||
STR_DISCONNECT_WEBDAV=Αποσύνδεση
|
||||
STR_SEARCH=Αναζήτηση
|
||||
STR_REFRESH=Ανανέωση
|
||||
STR_SERVER=Διακομιστής
|
||||
STR_USERNAME=Όνομα Χρήστη
|
||||
STR_PASSWORD=Κωδικός Πρόσβασης
|
||||
STR_PORT=Θύρα
|
||||
STR_PASV=Παθητ.Λειτ.
|
||||
STR_DIRECTORY=Κατάλογος
|
||||
STR_FILTER=Φίλτρο
|
||||
STR_YES=Ναί
|
||||
STR_NO=Όχι
|
||||
STR_CANCEL=Ακύρωση
|
||||
STR_CONTINUE=Συνεχίστε
|
||||
STR_CLOSE=Κλείσιμο
|
||||
STR_FOLDER=Φάκελος
|
||||
STR_FILE=Αρχείο
|
||||
STR_TYPE=Τύπος
|
||||
STR_NAME=Όνομα
|
||||
STR_SIZE=Μέγεθος
|
||||
STR_DATE=Ημερομηνία
|
||||
STR_NEW_FOLDER=Νέος Φάκελος
|
||||
STR_RENAME=Μετονομασία
|
||||
STR_DELETE=Διαγραφή
|
||||
STR_UPLOAD=Ανέβασμα
|
||||
STR_DOWNLOAD=Λήψη
|
||||
STR_SELECT_ALL=Επιλογή Όλων
|
||||
STR_CLEAR_ALL=Εκκαθάριση Όλων
|
||||
STR_UPLOADING=Μεταφόρτωση
|
||||
STR_DOWNLOADING=Κατεβαίνει
|
||||
STR_OVERWRITE=Αντικατάσταση
|
||||
STR_DONT_OVERWRITE=Μην Αντικαταστήσετε
|
||||
STR_ASK_FOR_CONFIRM=Ρωτήστε για επιβεβαίωση
|
||||
STR_DONT_ASK_CONFIRM=Μη Ρωτάτε για επιβεβαίωση
|
||||
STR_ALLWAYS_USE_OPTION=Χρησιμοποιήστε πάντα αυτή την επιλογή και μην ξαναρωτήσετε
|
||||
STR_ACTIONS=Ενέργειες
|
||||
STR_CONFIRM=Επιβεβαίωση
|
||||
STR_OVERWRITE_OPTIONS=Επιλογές Αντικατάστασης
|
||||
STR_PROPERTIES=Ιδιότητες
|
||||
STR_PROGRESS=Πρόοδος
|
||||
STR_UPDATES=Ενημερώσεις
|
||||
STR_DEL_CONFIRM_MSG=Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό(-α) το(-α) αρχείο(-α)/φάκελο(-ους);
|
||||
STR_CANCEL_ACTION_MSG=Ακύρωση. Αναμονή για την ολοκλήρωση της τελευταίας ενέργειας
|
||||
STR_FAIL_UPLOAD_MSG=Απέτυχε το ανέβασμα Αρχείου
|
||||
STR_FAIL_DOWNLOAD_MSG=Αποτυχία λήψης αρχείου
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Απέτυχε να διαβάσει τα περιεχόμενα του καταλόγου ή ο φάκελος δεν υπάρχει.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Η σύνδεση έκλεισε.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Ο απομακρυσμένος διακομιστής τερμάτισε τη σύνδεση.
|
||||
STR_FAIL_LOGIN_MSG=300 Αποτυχημένη σύνδεση. Παρακαλούμε ελέγξτε το όνομα χρήστη ή τον κωδικό πρόσβασής σας.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Απέτυχε. Η σύνδεση έχει διακοπεί.
|
||||
STR_FAIL_DEL_DIR_MSG=Απέτυχε η διαγραφή καταλόγου
|
||||
STR_DELETING=Διαγραφή
|
||||
STR_FAIL_DEL_FILE_MSG=Αποτυχία διαγραφής αρχείου
|
||||
STR_DELETED=Διαγράφηκε(-αν)
|
||||
STR_LINK=Σύνδεσμος
|
||||
STR_SHARE=Μοιραστείτε
|
||||
STR_FAILED=310 Απέτυχε
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 Απέτυχε η δημιουργία αρχείου στο τοπικό
|
||||
STR_INSTALL=Εγκαταστήστε το
|
||||
STR_INSTALLING=Εγκατάσταση
|
||||
STR_INSTALL_SUCCESS=Επιτυχία
|
||||
STR_INSTALL_FAILED=Αποτυχία
|
||||
STR_INSTALL_SKIPPED=Παραλείπεται(-ονται/φθηκε/φθηκαν)
|
||||
STR_CHECK_HTTP_MSG=Έλεγχος σύνδεσης με απομακρυσμένο διακομιστή HTTP
|
||||
STR_FAILED_HTTP_CHECK=Απέτυχε η σύνδεση με τον διακομιστή HTTP
|
||||
STR_REMOTE_NOT_HTTP=Το απομακρυσμένο δεν είναι διακομιστής HTTP
|
||||
STR_INSTALL_FROM_DATA_MSG=Το Package δεν βρίσκεται στο φάκελο /data ή /mnt/usbX
|
||||
STR_ALREADY_INSTALLED_MSG=Το Package είναι ήδη εγκατεστημένο
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Kapcsolati beállítások
|
||||
STR_SITE=Site
|
||||
STR_LOCAL=Helyi
|
||||
STR_REMOTE=Távoli
|
||||
STR_MESSAGES=Üzenetek
|
||||
STR_UPDATE_SOFTWARE=Szoftver frissítés
|
||||
STR_CONNECT_WEBDAV=Kapcsolódás
|
||||
STR_DISCONNECT_WEBDAV=Szétkapcsol
|
||||
STR_SEARCH=Keres
|
||||
STR_REFRESH=Frissít
|
||||
STR_SERVER=Szerver
|
||||
STR_USERNAME=Felhasználónév
|
||||
STR_PASSWORD=Jelszó
|
||||
STR_PORT=Port
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Útvonal
|
||||
STR_FILTER=Szűrés
|
||||
STR_YES=Igen
|
||||
STR_NO=Nem
|
||||
STR_CANCEL=Kilép
|
||||
STR_CONTINUE=Folytatás
|
||||
STR_CLOSE=Bezár
|
||||
STR_FOLDER=Mappa
|
||||
STR_FILE=Fájl
|
||||
STR_TYPE=Típus
|
||||
STR_NAME=Fájlnév
|
||||
STR_SIZE=Méret
|
||||
STR_DATE=Dátum
|
||||
STR_NEW_FOLDER=Új Mappa
|
||||
STR_RENAME=Átnevez
|
||||
STR_DELETE=Töröl
|
||||
STR_UPLOAD=Feltölt
|
||||
STR_DOWNLOAD=Letölt
|
||||
STR_SELECT_ALL=Mind kijelöl
|
||||
STR_CLEAR_ALL=Kijelölést megszüntet
|
||||
STR_UPLOADING=Feltöltés
|
||||
STR_DOWNLOADING=Letöltés
|
||||
STR_OVERWRITE=Felülír
|
||||
STR_DONT_OVERWRITE=Ne írja felül
|
||||
STR_ASK_FOR_CONFIRM=Kérjen megerősítést
|
||||
STR_DONT_ASK_CONFIRM=Ne kérjen megerősítést
|
||||
STR_ALLWAYS_USE_OPTION=Mindig ezt a beállítást használja és ne kérdezze úja
|
||||
STR_ACTIONS=Műveletek
|
||||
STR_CONFIRM=Megerősít
|
||||
STR_OVERWRITE_OPTIONS=Felülírási beállítások
|
||||
STR_PROPERTIES=Tulajdonságok
|
||||
STR_PROGRESS=Folyamat
|
||||
STR_UPDATES=Frissítések
|
||||
STR_DEL_CONFIRM_MSG=Biztos benne, hogy törli a mappá(ka)t vagy a fájl(oka)t?
|
||||
STR_CANCEL_ACTION_MSG=Kilépés. Várakozás az utolsó művelet befejezésére
|
||||
STR_FAIL_UPLOAD_MSG=Sikertelen feltöltés
|
||||
STR_FAIL_DOWNLOAD_MSG=Sikertelen letöltés
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Az útvonal nem érhető el vagy a mappa nem létezik.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Kapcsolat megszakadt.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Távoli szerver megszakította a kapcsolatot.
|
||||
STR_FAIL_LOGIN_MSG=300 Sikertelen belépés. Kérem, ellenőrizze a felhasználónevet és a jelszót.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Hiba. Kapcsolat időtúllépés.
|
||||
STR_FAIL_DEL_DIR_MSG=Nem sikerült a mappát törölni
|
||||
STR_DELETING=Törlés
|
||||
STR_FAIL_DEL_FILE_MSG=A fájl törlése sikertelen
|
||||
STR_DELETED=Törölve
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Pengaturan Koneksi
|
||||
STR_SITE=Situs
|
||||
STR_LOCAL=Lokal
|
||||
STR_REMOTE=Remote
|
||||
STR_MESSAGES=Pesan
|
||||
STR_UPDATE_SOFTWARE=Perbarui Software
|
||||
STR_CONNECT_WEBDAV=Hubungkan
|
||||
STR_DISCONNECT_WEBDAV=Putuskan
|
||||
STR_SEARCH=Cari
|
||||
STR_REFRESH=Refresh
|
||||
STR_SERVER=Server
|
||||
STR_USERNAME=Nama Pengguna
|
||||
STR_PASSWORD=Kata Sandi
|
||||
STR_PORT=Port
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Direktori
|
||||
STR_FILTER=Filter
|
||||
STR_YES=Iya
|
||||
STR_NO=Tidak
|
||||
STR_CANCEL=Batal
|
||||
STR_CONTINUE=Lanjut
|
||||
STR_CLOSE=Tutup
|
||||
STR_FOLDER=Folder
|
||||
STR_FILE=File
|
||||
STR_TYPE=Jenis
|
||||
STR_NAME=Nama
|
||||
STR_SIZE=Ukuran
|
||||
STR_DATE=Tanggal
|
||||
STR_NEW_FOLDER=Folder Baru
|
||||
STR_RENAME=Ganti Nama
|
||||
STR_DELETE=Hapus
|
||||
STR_UPLOAD=Unggah
|
||||
STR_DOWNLOAD=Unduh
|
||||
STR_SELECT_ALL=Pilih Semua
|
||||
STR_CLEAR_ALL=Lepaskan Semua
|
||||
STR_UPLOADING=Mengunggah
|
||||
STR_DOWNLOADING=Mengunduh
|
||||
STR_OVERWRITE=Overwrite
|
||||
STR_DONT_OVERWRITE=Jangan Overwrite
|
||||
STR_ASK_FOR_CONFIRM=Minta untuk Konfirmasi
|
||||
STR_DONT_ASK_CONFIRM=Jangan minta untuk Konfirmasi
|
||||
STR_ALLWAYS_USE_OPTION=Selalu gunakan opsi ini dan jangan tanya lagi
|
||||
STR_ACTIONS=Aksi
|
||||
STR_CONFIRM=Setuju
|
||||
STR_OVERWRITE_OPTIONS=Opsi Overwrite
|
||||
STR_PROPERTIES=Perincian
|
||||
STR_PROGRESS=Progres
|
||||
STR_UPDATES=Pembaruan
|
||||
STR_DEL_CONFIRM_MSG=Apakah kamu mau menghapus file/folder ini?
|
||||
STR_CANCEL_ACTION_MSG=Membatalkan. Menunggu aksi terakhir untuk selesai
|
||||
STR_FAIL_UPLOAD_MSG=Pengunggahan file gagal
|
||||
STR_FAIL_DOWNLOAD_MSG=Pengunduhan file gagal
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Isi direktori gagal dibaca atau folder tidak ada.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Koneksi ditutup.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Server Remote telah menutupkan koneksi.
|
||||
STR_FAIL_LOGIN_MSG=300 Login gagal. Tolong perhatikan nama pengguna dan kata sandi.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Gagal. Waktu koneksi habis/timeout.
|
||||
STR_FAIL_DEL_DIR_MSG=Direktori gagal dihapus
|
||||
STR_DELETING=Menghapus
|
||||
STR_FAIL_DEL_FILE_MSG=File gagal dihapus
|
||||
STR_DELETED=Dihapus
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Impostazioni di rete
|
||||
STR_SITE=Sito
|
||||
STR_LOCAL=Locale
|
||||
STR_REMOTE=Remoto
|
||||
STR_MESSAGES=Messaggi
|
||||
STR_UPDATE_SOFTWARE=Aggiornamento di sistema
|
||||
STR_CONNECT_WEBDAV=Connesione
|
||||
STR_DISCONNECT_WEBDAV=Disconnetti da
|
||||
STR_SEARCH=Cerca
|
||||
STR_REFRESH=Aggiorna
|
||||
STR_SERVER=Server
|
||||
STR_USERNAME=Nome utente
|
||||
STR_PASSWORD=Password
|
||||
STR_PORT=Porta
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Percorso
|
||||
STR_FILTER=Filtro
|
||||
STR_YES=Sì
|
||||
STR_NO=No
|
||||
STR_CANCEL=Annulla
|
||||
STR_CONTINUE=Conferma
|
||||
STR_CLOSE=Chiudi
|
||||
STR_FOLDER=Cartella
|
||||
STR_FILE=File
|
||||
STR_TYPE=Tipo
|
||||
STR_NAME=Nome
|
||||
STR_SIZE=Dimensione
|
||||
STR_DATE=Data
|
||||
STR_NEW_FOLDER=Nuova cartella
|
||||
STR_RENAME=Rinomina
|
||||
STR_DELETE=Elimina
|
||||
STR_UPLOAD=Carica
|
||||
STR_DOWNLOAD=Scarica
|
||||
STR_SELECT_ALL=Seleziona tutto
|
||||
STR_CLEAR_ALL=Elimina tutto
|
||||
STR_UPLOADING=Caricando
|
||||
STR_DOWNLOADING=Scaricando
|
||||
STR_OVERWRITE=Socrascrivi
|
||||
STR_DONT_OVERWRITE=Non sovrascrivere
|
||||
STR_ASK_FOR_CONFIRM=Chiedere conferma
|
||||
STR_DONT_ASK_CONFIRM=Non chiedere conferma
|
||||
STR_ALLWAYS_USE_OPTION=Usa sempre questa opzione e non chiedere in seguito
|
||||
STR_ACTIONS=Opzioni
|
||||
STR_CONFIRM=Conferma
|
||||
STR_OVERWRITE_OPTIONS=Sovrascrivere impostazioni
|
||||
STR_PROPERTIES=Proprietà
|
||||
STR_PROGRESS=Stato
|
||||
STR_UPDATES=Aggiornamenti
|
||||
STR_DEL_CONFIRM_MSG=Sei sicuro di voler eliminare questo(i) file o cartella(e)?
|
||||
STR_CANCEL_ACTION_MSG=Annulamento. Attendo il completamento dell'ultima operazione eseguita.
|
||||
STR_FAIL_UPLOAD_MSG=Caricamento fallito
|
||||
STR_FAIL_DOWNLOAD_MSG=Scaricamento fallito
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Non è stato possibile leggere il contenuto del percorso o la cartella non esiste.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Connessione chiusa.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Errore. Il server remoto ha terminato la connessione.
|
||||
STR_FAIL_LOGIN_MSG=300 Login Fallito. Controllare Nome utente o password.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Errore. La connessione ha richiesto troppo tempo.
|
||||
STR_FAIL_DEL_DIR_MSG=Impossibile eliminare il percorso
|
||||
STR_DELETING=Eliminazione
|
||||
STR_FAIL_DEL_FILE_MSG=Impossibile eliminare il file
|
||||
STR_DELETED=Eliminato
|
||||
@@ -0,0 +1,75 @@
|
||||
STR_CONNECTION_SETTINGS=接続の設定
|
||||
STR_SITE=サイト
|
||||
STR_LOCAL=ローカル
|
||||
STR_REMOTE=リモート
|
||||
STR_MESSAGES=メッセージ
|
||||
STR_UPDATE_SOFTWARE=ソフトウェアの更新
|
||||
STR_CONNECT_WEBDAV=に接続
|
||||
STR_DISCONNECT_WEBDAV=を切断
|
||||
STR_SEARCH=検索
|
||||
STR_REFRESH=更新
|
||||
STR_SERVER=サーバー
|
||||
STR_USERNAME=ユーザー名
|
||||
STR_PASSWORD=パスワード
|
||||
STR_PORT=ポート
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=ディレクトリ
|
||||
STR_FILTER=フィルター
|
||||
STR_YES=はい
|
||||
STR_NO=いいえ
|
||||
STR_CANCEL=キャンセル
|
||||
STR_CONTINUE=続ける
|
||||
STR_CLOSE=閉じる
|
||||
STR_FOLDER=フォルダー
|
||||
STR_FILE=ファイル
|
||||
STR_TYPE=タイプ
|
||||
STR_NAME=名前
|
||||
STR_SIZE=サイズ
|
||||
STR_DATE=日付
|
||||
STR_NEW_FOLDER=新しいフォルダー
|
||||
STR_RENAME=名前を変更
|
||||
STR_DELETE=消去
|
||||
STR_UPLOAD=アップロード
|
||||
STR_DOWNLOAD=ダウンロード
|
||||
STR_SELECT_ALL=全て選択
|
||||
STR_CLEAR_ALL=全てクリア
|
||||
STR_UPLOADING=アップロード
|
||||
STR_DOWNLOADING=ダウンロード
|
||||
STR_OVERWRITE=上書き
|
||||
STR_DONT_OVERWRITE=上書きしない
|
||||
STR_ASK_FOR_CONFIRM=確認を求める
|
||||
STR_DONT_ASK_CONFIRM=確認を求めない
|
||||
STR_ALLWAYS_USE_OPTION=常にこのオプションを使用し、二度と尋ねない
|
||||
STR_ACTIONS=アクション
|
||||
STR_CONFIRM=確認
|
||||
STR_OVERWRITE_OPTIONS=上書きオプション
|
||||
STR_PROPERTIES=プロパティ
|
||||
STR_PROGRESS=進捗
|
||||
STR_UPDATES=更新
|
||||
STR_DEL_CONFIRM_MSG=このファイル/フォルダを削除してもよろしいですか?
|
||||
STR_CANCEL_ACTION_MSG=キャンセルします。 最後のアクションが完了するのを待っています
|
||||
STR_FAIL_UPLOAD_MSG=ファイルのアップロードに失敗しました
|
||||
STR_FAIL_DOWNLOAD_MSG=ファイルのダウンロードに失敗しました
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=ディレクトリまたはフォルダの内容の読み取りに失敗しましたが存在しません。
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 接続が閉じられました。
|
||||
STR_REMOTE_TERM_CONN_MSG=426 リモートサーバーが接続を終了しました。
|
||||
STR_FAIL_LOGIN_MSG=300 ログインに失敗しました。 ユーザー名またはパスワードを確認してください。
|
||||
STR_FAIL_TIMEOUT_MSG=426 失敗した。 接続タイムアウト。
|
||||
STR_FAIL_DEL_DIR_MSG=ディレクトリの削除に失敗しました
|
||||
STR_DELETING=削除
|
||||
STR_FAIL_DEL_FILE_MSG=ファイルの削除に失敗しました
|
||||
STR_DELETED=削除
|
||||
STR_LINK=リンク
|
||||
STR_SHARE=共有
|
||||
STR_FAILED=310 失敗
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 ローカルでファイルを作成できませんでした
|
||||
STR_INSTALL=インストール
|
||||
STR_INSTALLING=インストール
|
||||
STR_INSTALL_SUCCESS=成功
|
||||
STR_INSTALL_FAILED=失敗
|
||||
STR_INSTALL_SKIPPED=スキップしました
|
||||
STR_CHECK_HTTP_MSG=リモート HTTPサーバーへの接続を確認しています
|
||||
STR_FAILED_HTTP_CHECK=HTTPサーバーの接続に失敗しました
|
||||
STR_REMOTE_NOT_HTTP=リモートはHTTPサーバーではありません
|
||||
STR_INSTALL_FROM_DATA_MSG=/dataまたは/mnt/usbXフォルダーにないパッケージ
|
||||
STR_ALREADY_INSTALLED_MSG=パッケージは既にインストールされています
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=접속 설정
|
||||
STR_SITE=사이트
|
||||
STR_LOCAL=로컬
|
||||
STR_REMOTE=리모트
|
||||
STR_MESSAGES=메시지
|
||||
STR_UPDATE_SOFTWARE=소프트웨어 업데이트
|
||||
STR_CONNECT_WEBDAV=접속
|
||||
STR_DISCONNECT_WEBDAV=끊기
|
||||
STR_SEARCH=검색
|
||||
STR_REFRESH=새로고침
|
||||
STR_SERVER=서버
|
||||
STR_USERNAME=사용자
|
||||
STR_PASSWORD=비밀번호
|
||||
STR_PORT=포트
|
||||
STR_PASV=수동형
|
||||
STR_DIRECTORY=디렉토리
|
||||
STR_FILTER=필터
|
||||
STR_YES=네
|
||||
STR_NO=아니오
|
||||
STR_CANCEL=취소
|
||||
STR_CONTINUE=계속
|
||||
STR_CLOSE=닫기
|
||||
STR_FOLDER=폴더
|
||||
STR_FILE=파일
|
||||
STR_TYPE=종류
|
||||
STR_NAME=이름
|
||||
STR_SIZE=크기
|
||||
STR_DATE=일시
|
||||
STR_NEW_FOLDER=새 폴더
|
||||
STR_RENAME=이름 변경
|
||||
STR_DELETE=삭제
|
||||
STR_UPLOAD=업로드
|
||||
STR_DOWNLOAD=다운로드
|
||||
STR_SELECT_ALL=전체 선택
|
||||
STR_CLEAR_ALL=전체 삭제
|
||||
STR_UPLOADING=업로드 중
|
||||
STR_DOWNLOADING=다운로드 중
|
||||
STR_OVERWRITE=덮어쓰기
|
||||
STR_DONT_OVERWRITE=덮어쓰기 금지
|
||||
STR_ASK_FOR_CONFIRM=수락여부를 질문
|
||||
STR_DONT_ASK_CONFIRM=수락여부를 묻지 않음
|
||||
STR_ALLWAYS_USE_OPTION=두번다시 묻지 않고 항상 이 설정을 사용
|
||||
STR_ACTIONS=실행
|
||||
STR_CONFIRM=확인
|
||||
STR_OVERWRITE_OPTIONS=덮어쓰기 옵션
|
||||
STR_PROPERTIES=속성
|
||||
STR_PROGRESS=진행
|
||||
STR_UPDATES=업데이트
|
||||
STR_DEL_CONFIRM_MSG=이 파일(들) 또는 폴더(들)를 삭제하시겠습니까?
|
||||
STR_CANCEL_ACTION_MSG=취소되었습니다. 마지막 실행이 완료될 때 까지 대기하여 주십시오.
|
||||
STR_FAIL_UPLOAD_MSG=파일 업로드에 실패하였습니다.
|
||||
STR_FAIL_DOWNLOAD_MSG=파일 다운로드에 실패하였습니다.
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=디렉토리의 내용을 읽을 수 없거나 폴더가 존재하지 않습니다.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 접속 종료.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 원격 서버의 접속이 종료되었습니다.
|
||||
STR_FAIL_LOGIN_MSG=300 로그인에 실패하였습니다. 사용자명과 패스워드를 체크하여 주십시오.
|
||||
STR_FAIL_TIMEOUT_MSG=426 실패. 접속시간 초과.
|
||||
STR_FAIL_DEL_DIR_MSG=디렉토리 삭제에 실패하였습니다.
|
||||
STR_DELETING=삭제 중
|
||||
STR_FAIL_DEL_FILE_MSG=파일 삭제에 실패하였습니다.
|
||||
STR_DELETED=삭제됨
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Ustawienia połączenia
|
||||
STR_SITE=Strona
|
||||
STR_LOCAL=Lokalny
|
||||
STR_REMOTE=Zdalny
|
||||
STR_MESSAGES=Wiadomości
|
||||
STR_UPDATE_SOFTWARE=Aktualizuj aplikację
|
||||
STR_CONNECT_WEBDAV=Połącz
|
||||
STR_DISCONNECT_WEBDAV=Rozłącz
|
||||
STR_SEARCH=Szukaj
|
||||
STR_REFRESH=Odśwież
|
||||
STR_SERVER=Serwer
|
||||
STR_USERNAME=Użytkownik
|
||||
STR_PASSWORD=Hasło
|
||||
STR_PORT=Port
|
||||
STR_PASV=Pasywny
|
||||
STR_DIRECTORY=Katalog
|
||||
STR_FILTER=Filtr
|
||||
STR_YES=Tak
|
||||
STR_NO=Nie
|
||||
STR_CANCEL=Anuluj
|
||||
STR_CONTINUE=Kontynuuj
|
||||
STR_CLOSE=Zamknij
|
||||
STR_FOLDER=Folder
|
||||
STR_FILE=Plik
|
||||
STR_TYPE=Typ
|
||||
STR_NAME=Nazwa
|
||||
STR_SIZE=Rozmiar
|
||||
STR_DATE=Data
|
||||
STR_NEW_FOLDER=Nowy folder
|
||||
STR_RENAME=Zmień nazwę
|
||||
STR_DELETE=Usuń
|
||||
STR_UPLOAD=Wyślij
|
||||
STR_DOWNLOAD=Pobierz
|
||||
STR_SELECT_ALL=Zaznacz wszystko
|
||||
STR_CLEAR_ALL=Wyczyść zaznaczenie
|
||||
STR_UPLOADING=Wysyłanie
|
||||
STR_DOWNLOADING=Pobieranie
|
||||
STR_OVERWRITE=Nadpisz
|
||||
STR_DONT_OVERWRITE=Nie nadpisuj
|
||||
STR_ASK_FOR_CONFIRM=Pytaj o potwierdzenie
|
||||
STR_DONT_ASK_CONFIRM=Nie pytaj o potwierdzenie
|
||||
STR_ALLWAYS_USE_OPTION=Zawsze używaj tej opcji i nie pytaj ponownie
|
||||
STR_ACTIONS=Akcje
|
||||
STR_CONFIRM=Potwierdź
|
||||
STR_OVERWRITE_OPTIONS=Nadpisz Opcje
|
||||
STR_PROPERTIES=Właściwości
|
||||
STR_PROGRESS=Postęp
|
||||
STR_UPDATES=Aktualizacje
|
||||
STR_DEL_CONFIRM_MSG=Czy na pewno usunąć wybrane plik(i)/folder(y)?
|
||||
STR_CANCEL_ACTION_MSG=Anulowanie. Oczekiwanie na zakończenie ostatniej operacji
|
||||
STR_FAIL_UPLOAD_MSG=Niepowodzenie wysłania pliku
|
||||
STR_FAIL_DOWNLOAD_MSG=Niepowodzenie pobierania pliku
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Nie udało się odczytać listy plików w katalogu lub katalog nie istnieje.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Połączenie zamknięte.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Serwer zdalny zakończył połączenie.
|
||||
STR_FAIL_LOGIN_MSG=300 Nieudane logowanie. Sprawdź nazwę użytkownika i/lub hasło.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Przekroczono limit czasu oczekiwania na połączenie.
|
||||
STR_FAIL_DEL_DIR_MSG=Niepowodzenie usuwania katalogu
|
||||
STR_DELETING=Usuwanie
|
||||
STR_FAIL_DEL_FILE_MSG=Niepowodzenie usuwania pliku
|
||||
STR_DELETED=Usunięto
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Configurações de Conexão
|
||||
STR_SITE=Site
|
||||
STR_LOCAL=Local
|
||||
STR_REMOTE=Remoto
|
||||
STR_MESSAGES=Mensagens
|
||||
STR_UPDATE_SOFTWARE=Atualizar Software
|
||||
STR_CONNECT_WEBDAV=Conectar
|
||||
STR_DISCONNECT_WEBDAV=Desconectar
|
||||
STR_SEARCH=Pesquisar
|
||||
STR_REFRESH=Recarregar
|
||||
STR_SERVER=Servidor
|
||||
STR_USERNAME=Usuário
|
||||
STR_PASSWORD=Senha
|
||||
STR_PORT=Porta
|
||||
STR_PASV=Salvar
|
||||
STR_DIRECTORY=Diretório
|
||||
STR_FILTER=Filtro
|
||||
STR_YES=Sim
|
||||
STR_NO=Não
|
||||
STR_CANCEL=Cancelar
|
||||
STR_CONTINUE=Continuar
|
||||
STR_CLOSE=Fechar
|
||||
STR_FOLDER=Pasta
|
||||
STR_FILE=Arquivo
|
||||
STR_TYPE=Tipo
|
||||
STR_NAME=Nome
|
||||
STR_SIZE=Tamanho
|
||||
STR_DATE=Data
|
||||
STR_NEW_FOLDER=Nova pasta
|
||||
STR_RENAME=Renomear
|
||||
STR_DELETE=Deletar
|
||||
STR_UPLOAD=Carregar
|
||||
STR_DOWNLOAD=Baixar
|
||||
STR_SELECT_ALL=Selecionar tudo
|
||||
STR_CLEAR_ALL=Apagar tudo
|
||||
STR_UPLOADING=Carregando
|
||||
STR_DOWNLOADING=Baixando
|
||||
STR_OVERWRITE=Sobrescrever
|
||||
STR_DONT_OVERWRITE=Não sobrescrever
|
||||
STR_ASK_FOR_CONFIRM=Perguntar novamente
|
||||
STR_DONT_ASK_CONFIRM=Não perguntar novamente
|
||||
STR_ALLWAYS_USE_OPTION=Usar sempre esta opção e não perguntar novamente
|
||||
STR_ACTIONS=Ações
|
||||
STR_CONFIRM=Confirmar
|
||||
STR_OVERWRITE_OPTIONS=Sobrescrever opções
|
||||
STR_PROPERTIES=Propriedades
|
||||
STR_PROGRESS=Progresso
|
||||
STR_UPDATES=Atualizações
|
||||
STR_DEL_CONFIRM_MSG=Tem certeza que deseja deletar este(a) arquivo(s)/pasta(s)?
|
||||
STR_CANCEL_ACTION_MSG=Cancelando. Aguardando a conclusão da última ação
|
||||
STR_FAIL_UPLOAD_MSG=Falha em carregar o arquivo
|
||||
STR_FAIL_DOWNLOAD_MSG=Falha em baixar o arquivo
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Falha ao ler o conteúdo do diretório ou pasta não existe.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Conexão encerrada.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 O servidor remoto encerrou a conexão.
|
||||
STR_FAIL_LOGIN_MSG=300 Falha no login. Favor checar o usuário e senha.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Falha. Tempo limite de conexão atingido.
|
||||
STR_FAIL_DEL_DIR_MSG=Falha ao excluir o diretório
|
||||
STR_DELETING=Excluindo
|
||||
STR_FAIL_DEL_FILE_MSG=Falha ao excluir o arquivo
|
||||
STR_DELETED=Excluido
|
||||
@@ -0,0 +1,86 @@
|
||||
STR_CONNECTION_SETTINGS=Setări de conecțiune
|
||||
STR_SITE=Site
|
||||
STR_LOCAL=Local
|
||||
STR_REMOTE=Distant
|
||||
STR_MESSAGES=Mesaje
|
||||
STR_UPDATE_SOFTWARE=Update de aplicație
|
||||
STR_CONNECT_WEBDAV=Conecteazăte
|
||||
STR_DISCONNECT_WEBDAV=Deconecteazăte
|
||||
STR_SEARCH=Caută
|
||||
STR_REFRESH=Reîncarca
|
||||
STR_SERVER=Servere
|
||||
STR_USERNAME=Nume de utilizator
|
||||
STR_PASSWORD=Parola
|
||||
STR_PORT=Portul
|
||||
STR_PASV=Pasv-ul
|
||||
STR_DIRECTORY=Directorul
|
||||
STR_FILTER=Filtru
|
||||
STR_YES=Da
|
||||
STR_NO=Nu
|
||||
STR_CANCEL=Anulează
|
||||
STR_CONTINUE=Continuă
|
||||
STR_CLOSE=Închide
|
||||
STR_FOLDER=Dosar
|
||||
STR_FILE=Fișier
|
||||
STR_TYPE=Tip
|
||||
STR_NAME=Nume
|
||||
STR_SIZE=Mărime
|
||||
STR_DATE=Data
|
||||
STR_NEW_FOLDER=Nou dosar
|
||||
STR_RENAME=Renumește
|
||||
STR_DELETE=Șterge
|
||||
STR_UPLOAD=Încarcă
|
||||
STR_DOWNLOAD=Descarcă
|
||||
STR_SELECT_ALL=Selectează tot
|
||||
STR_CLEAR_ALL=Șterge tot
|
||||
STR_UPLOADING=Încarcă
|
||||
STR_DOWNLOADING=Descarcă
|
||||
STR_OVERWRITE=Suprascrie
|
||||
STR_DONT_OVERWRITE=Nu suprascrie
|
||||
STR_ASK_FOR_CONFIRM=Întreabă pentru confirmare
|
||||
STR_DONT_ASK_CONFIRM=Nu întreba pentru confirmare
|
||||
STR_ALLWAYS_USE_OPTION=Mereu să folosești această opțiune și să nu mă m-ai întrebi
|
||||
STR_ACTIONS=Acțiuni
|
||||
STR_CONFIRM=Confirmă
|
||||
STR_OVERWRITE_OPTIONS=Suprascrie opțiunile
|
||||
STR_PROPERTIES=Proprietăți
|
||||
STR_PROGRESS=Progres
|
||||
STR_UPDATES=Updateturi
|
||||
STR_DEL_CONFIRM_MSG=Ești sigur că vrei să ștergi aceast fișier(e)/dosar(e)?
|
||||
STR_CANCEL_ACTION_MSG=Anulînd. Așteptînd pentru ultima acțiune să fie completată
|
||||
STR_FAIL_UPLOAD_MSG=Fișierul a eșuat să fie încărcat
|
||||
STR_FAIL_DOWNLOAD_MSG=Fișierul a eșuat să fie descărcat
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=A eșuat să citească conținutul directorului sau dosarului care nu există
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Conecțiune închisă
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Servărul distant ți-a terminat conecțiunea.
|
||||
STR_FAIL_LOGIN_MSG=300 Autentificarea eșuata. Te rog sa verifici numele de utilizator și parola.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Eșuat. Conecțiune terminată
|
||||
STR_FAIL_DEL_DIR_MSG=A eșuat sa se ștearga directorul
|
||||
STR_DELETING=Ștergînd
|
||||
STR_FAIL_DEL_FILE_MSG=A eșuat ștersul fișierului
|
||||
STR_DELETED=Șters
|
||||
STR_LINK=Link
|
||||
STR_SHARE=Înpărtășește
|
||||
STR_FAILED=310 Eșuat
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 A eșuat să se creeze fișierul pe local
|
||||
STR_INSTALL=Instalat
|
||||
STR_INSTALLING=Instalează
|
||||
STR_INSTALL_SUCCESS=Succes
|
||||
STR_INSTALL_FAILED=Eșuat
|
||||
STR_INSTALL_SKIPPED=Sărit
|
||||
STR_CHECK_HTTP_MSG=Vericînd conecțiunea la servărul distant HTTP
|
||||
STR_FAILED_HTTP_CHECK=Eșuat conecțiunea la servărul HTTP
|
||||
STR_REMOTE_NOT_HTTP=Servărul distant nu este de tip HTTP
|
||||
STR_INSTALL_FROM_DATA_MSG=Pachetul nu se află in /data sau fișierul /mnt/usbX
|
||||
STR_ALREADY_INSTALLED_MSG=Pachetul este deja instalat
|
||||
STR_INSTALL_FROM_URL=Instalează din URL
|
||||
STR_CANNOT_READ_PKG_HDR_MSG=Nu sa putut citit antetul de info al pachetului
|
||||
STR_FAVORITE_URLS=URL-urile favorite
|
||||
STR_SLOT=Slot
|
||||
STR_EDIT=Editează
|
||||
STR_ONETIME_URL=Un Url pentru o singură dată
|
||||
STR_NOT_A_VALID_PACKAGE=Nu este un pachet valid
|
||||
STR_WAIT_FOR_INSTALL_MSG=Așteptînd pachetul să se termine de instalat
|
||||
STR_FAIL_INSTALL_TMP_PKG_MSG=A eșuat instalarea fișierului pkg. Te rog șterge pkg temporar manual
|
||||
STR_FAIL_TO_OBTAIN_GG_DL_MSG=A eșuat obținerea URL-ului de instalare de la google
|
||||
STR_AUTO_DELETE_TMP_PKG=Auto șterge fișierele temporare pkg instalate dupa instalare
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Настройка Связей
|
||||
STR_SITE=Сайт
|
||||
STR_LOCAL=Локальная
|
||||
STR_REMOTE=Дистанционная
|
||||
STR_MESSAGES=Сообщения
|
||||
STR_UPDATE_SOFTWARE=Обновить Программу
|
||||
STR_CONNECT_WEBDAV=Подключить
|
||||
STR_DISCONNECT_WEBDAV=Отключить
|
||||
STR_SEARCH=Найти
|
||||
STR_REFRESH=Обновить
|
||||
STR_SERVER=Сервер
|
||||
STR_USERNAME=Пользователь
|
||||
STR_PASSWORD=Пароль
|
||||
STR_PORT=Порт
|
||||
STR_PASV=Пассивный
|
||||
STR_DIRECTORY=Директория
|
||||
STR_FILTER=Фильтр
|
||||
STR_YES=Да
|
||||
STR_NO=Нет
|
||||
STR_CANCEL=Отменить
|
||||
STR_CONTINUE=Продолжить
|
||||
STR_CLOSE=Закрыть
|
||||
STR_FOLDER=Папка
|
||||
STR_FILE=Файл
|
||||
STR_TYPE=Тип
|
||||
STR_NAME=Название
|
||||
STR_SIZE=Размер
|
||||
STR_DATE=Дата
|
||||
STR_NEW_FOLDER=Новая Папка
|
||||
STR_RENAME=Переименовать
|
||||
STR_DELETE=Удалить
|
||||
STR_UPLOAD=Отправить
|
||||
STR_DOWNLOAD=Получить
|
||||
STR_SELECT_ALL=Выбрать Все
|
||||
STR_CLEAR_ALL=Отменить Все
|
||||
STR_UPLOADING=Получаются
|
||||
STR_DOWNLOADING=Отправляются
|
||||
STR_OVERWRITE=Переписать
|
||||
STR_DONT_OVERWRITE=Не Переписывать
|
||||
STR_ASK_FOR_CONFIRM=Спросить Подтверждение
|
||||
STR_DONT_ASK_CONFIRM=Не Спрашивать Подтверждение
|
||||
STR_ALLWAYS_USE_OPTION=Всегда используйте эту опцию, и больше не спрашивайте
|
||||
STR_ACTIONS=Действия
|
||||
STR_CONFIRM=Подтвердить
|
||||
STR_OVERWRITE_OPTIONS=Переписать Опции
|
||||
STR_PROPERTIES=Свойства
|
||||
STR_PROGRESS=Прогресс
|
||||
STR_UPDATES=Обновления
|
||||
STR_DEL_CONFIRM_MSG=Уверены, что хотите удалить эти файлы/папки?
|
||||
STR_CANCEL_ACTION_MSG=Отмена. Ожидаем завершения последнего действия
|
||||
STR_FAIL_UPLOAD_MSG=Отправление файла неуспешно
|
||||
STR_FAIL_DOWNLOAD_MSG=Загрузка файла неуспешна
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Чтение содержимых файла или папки неуспешно, или папка не существует
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Соединениние Закрыто.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Дистанционный Сервер Закрыл Соединение.
|
||||
STR_FAIL_LOGIN_MSG=300 Неуспешный Логин. Пожалуйста проверьте ваше имя пользователя или пароль.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Неуспешно. Время соединения вышло.
|
||||
STR_FAIL_DEL_DIR_MSG=Удаление папки неуспешно
|
||||
STR_DELETING=Удаляются
|
||||
STR_FAIL_DEL_FILE_MSG=Удаление файла неуспешно
|
||||
STR_DELETED=Удалено
|
||||
@@ -0,0 +1,75 @@
|
||||
STR_CONNECTION_SETTINGS=接続ぬ設定
|
||||
STR_SITE=サイト
|
||||
STR_LOCAL=ローカル
|
||||
STR_REMOTE=リモート
|
||||
STR_MESSAGES=メッセージ
|
||||
STR_UPDATE_SOFTWARE=ソフトウェアぬ更新
|
||||
STR_CONNECT_WEBDAV=んかい接続
|
||||
STR_DISCONNECT_WEBDAV=切断
|
||||
STR_SEARCH=検索
|
||||
STR_REFRESH=更新
|
||||
STR_SERVER=サーバー
|
||||
STR_USERNAME=ユーザー名
|
||||
STR_PASSWORD=パスワード
|
||||
STR_PORT=ポート
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=ディレクトリ
|
||||
STR_FILTER=フィルター
|
||||
STR_YES=はい
|
||||
STR_NO=うぅーうぅー
|
||||
STR_CANCEL=キャンセル
|
||||
STR_CONTINUE=続きーん
|
||||
STR_CLOSE=くーいん
|
||||
STR_FOLDER=フォルダー
|
||||
STR_FILE=ファイル
|
||||
STR_TYPE=タイプ
|
||||
STR_NAME=なめー
|
||||
STR_SIZE=サイズ
|
||||
STR_DATE=日付
|
||||
STR_NEW_FOLDER=みーさるフォルダー
|
||||
STR_RENAME=なめー変更
|
||||
STR_DELETE=消去
|
||||
STR_UPLOAD=アップロード
|
||||
STR_DOWNLOAD=ダウンロード
|
||||
STR_SELECT_ALL=まじり選択
|
||||
STR_CLEAR_ALL=まじりクリア
|
||||
STR_UPLOADING=アップロード
|
||||
STR_DOWNLOADING=ダウンロード
|
||||
STR_OVERWRITE=上書き
|
||||
STR_DONT_OVERWRITE=上書きさん
|
||||
STR_ASK_FOR_CONFIRM=確認むとぅみーん
|
||||
STR_DONT_ASK_CONFIRM=確認むとぅみらん
|
||||
STR_ALLWAYS_USE_OPTION=常にくぬオプション使用しー、二度とぅたんにらん
|
||||
STR_ACTIONS=アクション
|
||||
STR_CONFIRM=確認
|
||||
STR_OVERWRITE_OPTIONS=上書きオプション
|
||||
STR_PROPERTIES=プロパティ
|
||||
STR_PROGRESS=進捗
|
||||
STR_UPDATES=更新
|
||||
STR_DEL_CONFIRM_MSG=くぬファイル/フォルダ削除しんゆたさいびーが?
|
||||
STR_CANCEL_ACTION_MSG=キャンセルさびーん。 最後ぬアクションぬしーうわいし待っちょーいびーん
|
||||
STR_FAIL_UPLOAD_MSG=ファイルぬアップロードんかいしーやんじゃびたん
|
||||
STR_FAIL_DOWNLOAD_MSG=ファイルぬダウンロードんかいしーやんじゃびたん
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=ディレクトリあらんでぃフォルダぬ内容ぬ読み取りんかいしーやんじゃびたんしが存在さびらん。
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 接続ぬくーららりやびたん。
|
||||
STR_REMOTE_TERM_CONN_MSG=426 リモートサーバーぬ接続終了さびたん。
|
||||
STR_FAIL_LOGIN_MSG=300 ログインんかいしーやんじゃびたん。 ユーザー名あらんでぃパスワード確認しくぃみそーれー。
|
||||
STR_FAIL_TIMEOUT_MSG=426 しーやんたん。 接続タイムアウト。
|
||||
STR_FAIL_DEL_DIR_MSG=ディレクトリぬ削除んかいしーやんじゃびたん
|
||||
STR_DELETING=削除
|
||||
STR_FAIL_DEL_FILE_MSG=ファイルぬ削除んかいしーやんじゃびたん
|
||||
STR_DELETED=削除
|
||||
STR_LINK=リンク
|
||||
STR_SHARE=共有
|
||||
STR_FAILED=310 失敗
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 ローカルっしファイル作成なやびらんたん
|
||||
STR_INSTALL=インストール
|
||||
STR_INSTALLING=インストール
|
||||
STR_INSTALL_SUCCESS=成功
|
||||
STR_INSTALL_FAILED=失敗
|
||||
STR_INSTALL_SKIPPED=スキップさびたん
|
||||
STR_CHECK_HTTP_MSG=リモート HTTPサーバーんかいぬ接続確認そーいびーん
|
||||
STR_FAILED_HTTP_CHECK=HTTPサーバーぬ接続んかいしーやんじゃびたん
|
||||
STR_REMOTE_NOT_HTTP=リモートーHTTPサーバーっしぇーあいびらん
|
||||
STR_INSTALL_FROM_DATA_MSG=/dataあらんでぃ/mnt/usbXフォルダーんかいねーんパッケージ
|
||||
STR_ALREADY_INSTALLED_MSG=パッケージェーしでぃにインストールさりとーいびーん
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=连接设置
|
||||
STR_SITE=地点
|
||||
STR_LOCAL=当地的
|
||||
STR_REMOTE=偏僻的
|
||||
STR_MESSAGES=留言
|
||||
STR_UPDATE_SOFTWARE=更新软件
|
||||
STR_CONNECT_WEBDAV=连接
|
||||
STR_DISCONNECT_WEBDAV=断开
|
||||
STR_SEARCH=搜索
|
||||
STR_REFRESH=刷新
|
||||
STR_SERVER=服务器
|
||||
STR_USERNAME=用户名
|
||||
STR_PASSWORD=密码
|
||||
STR_PORT=港口
|
||||
STR_PASV=帕夫
|
||||
STR_DIRECTORY=目录
|
||||
STR_FILTER=筛选
|
||||
STR_YES=是的
|
||||
STR_NO=不
|
||||
STR_CANCEL=取消
|
||||
STR_CONTINUE=继续
|
||||
STR_CLOSE=关闭
|
||||
STR_FOLDER=文件夹
|
||||
STR_FILE=文件
|
||||
STR_TYPE=类型
|
||||
STR_NAME=姓名
|
||||
STR_SIZE=尺寸
|
||||
STR_DATE=日期
|
||||
STR_NEW_FOLDER=新建文件夹
|
||||
STR_RENAME=改名
|
||||
STR_DELETE=删除
|
||||
STR_UPLOAD=上传
|
||||
STR_DOWNLOAD=下载
|
||||
STR_SELECT_ALL=全选
|
||||
STR_CLEAR_ALL=全部清除
|
||||
STR_UPLOADING=上传
|
||||
STR_DOWNLOADING=下载
|
||||
STR_OVERWRITE=覆盖
|
||||
STR_DONT_OVERWRITE=不要覆盖
|
||||
STR_ASK_FOR_CONFIRM=要求确认
|
||||
STR_DONT_ASK_CONFIRM=不要要求确认
|
||||
STR_ALLWAYS_USE_OPTION=始终使用此选项,不再询问
|
||||
STR_ACTIONS=行动
|
||||
STR_CONFIRM=确认
|
||||
STR_OVERWRITE_OPTIONS=覆盖选项
|
||||
STR_PROPERTIES=特性
|
||||
STR_PROGRESS=进步
|
||||
STR_UPDATES=更新
|
||||
STR_DEL_CONFIRM_MSG=您确定要删除此文件/文件夹吗?
|
||||
STR_CANCEL_ACTION_MSG=取消。 等待最后一个动作完成
|
||||
STR_FAIL_UPLOAD_MSG=上传文件失败
|
||||
STR_FAIL_DOWNLOAD_MSG=下载文件失败
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=读取目录内容失败或文件夹不存在。
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 连接已关闭。
|
||||
STR_REMOTE_TERM_CONN_MSG=426 远程服务器已终止连接。
|
||||
STR_FAIL_LOGIN_MSG=300 登录失败。 请检查您的用户名或密码。
|
||||
STR_FAIL_TIMEOUT_MSG=426 失败。 连接超时。
|
||||
STR_FAIL_DEL_DIR_MSG=删除目录失败
|
||||
STR_DELETING=删除
|
||||
STR_FAIL_DEL_FILE_MSG=删除文件失败
|
||||
STR_DELETED=已删除
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=Ajustes de conexión
|
||||
STR_SITE=Sitio
|
||||
STR_LOCAL=Local
|
||||
STR_REMOTE=Remoto
|
||||
STR_MESSAGES=Mensajes
|
||||
STR_UPDATE_SOFTWARE=Actualizar software
|
||||
STR_CONNECT_WEBDAV=Conectar
|
||||
STR_DISCONNECT_WEBDAV=Desconectar
|
||||
STR_SEARCH=Buscar
|
||||
STR_REFRESH=Actualizar
|
||||
STR_SERVER=Servidor
|
||||
STR_USERNAME=Usuario
|
||||
STR_PASSWORD=Contraseña
|
||||
STR_PORT=Puerto
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Directorio
|
||||
STR_FILTER=Filtro
|
||||
STR_YES=Sí
|
||||
STR_NO=No
|
||||
STR_CANCEL=Cancelar
|
||||
STR_CONTINUE=Continuar
|
||||
STR_CLOSE=Cerrar
|
||||
STR_FOLDER=Carpeta
|
||||
STR_FILE=Archivo
|
||||
STR_TYPE=Tipo
|
||||
STR_NAME=Nombre
|
||||
STR_SIZE=Tamaño
|
||||
STR_DATE=Fecha
|
||||
STR_NEW_FOLDER=Nueva carpeta
|
||||
STR_RENAME=Cambiar nombre
|
||||
STR_DELETE=Eliminar
|
||||
STR_UPLOAD=Enviar
|
||||
STR_DOWNLOAD=Descargar
|
||||
STR_SELECT_ALL=Seleccionar todo
|
||||
STR_CLEAR_ALL=Deseleccionar todo
|
||||
STR_UPLOADING=Enviando
|
||||
STR_DOWNLOADING=Descargando
|
||||
STR_OVERWRITE=Sobrescribir
|
||||
STR_DONT_OVERWRITE=No sobrescribir
|
||||
STR_ASK_FOR_CONFIRM=Pedir confirmación
|
||||
STR_DONT_ASK_CONFIRM=No pedir confirmación
|
||||
STR_ALLWAYS_USE_OPTION=Usar siempre esta opción y no volver a preguntar
|
||||
STR_ACTIONS=Acciones
|
||||
STR_CONFIRM=Confirmación
|
||||
STR_OVERWRITE_OPTIONS=Opciones de sobrescritura
|
||||
STR_PROPERTIES=Propiedades
|
||||
STR_PROGRESS=Progreso
|
||||
STR_UPDATES=Actualizaciones
|
||||
STR_DEL_CONFIRM_MSG=¿Seguro que deseas eliminar este(estos) archivo(s) o carpeta(s)?
|
||||
STR_CANCEL_ACTION_MSG=Cancelando. Esperando a finalizar la última acción
|
||||
STR_FAIL_UPLOAD_MSG=Error al enviar el archivo
|
||||
STR_FAIL_DOWNLOAD_MSG=Error al descargar el archivo
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Error al leer los contenidos del directorio o la carpeta no existe.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426: conexión cerrada.
|
||||
STR_REMOTE_TERM_CONN_MSG=426: el servidor remoto ha cerrado la conexión.
|
||||
STR_FAIL_LOGIN_MSG=300: error al iniciar sesión. Comprueba tu nombre de usuario y contraseña.
|
||||
STR_FAIL_TIMEOUT_MSG=426: error se agotó el tiempo de espera.
|
||||
STR_FAIL_DEL_DIR_MSG=Error al eliminar el directorio
|
||||
STR_DELETING=Eliminando
|
||||
STR_FAIL_DEL_FILE_MSG=Error al eliminar el archivo
|
||||
STR_DELETED=Eliminado
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=การตั้งค่าการเชื่อมต่อ
|
||||
STR_SITE=เวปไซต์
|
||||
STR_LOCAL=ภายใน
|
||||
STR_REMOTE=ระยะไกล
|
||||
STR_MESSAGES=ข้อความ
|
||||
STR_UPDATE_SOFTWARE=อัปเดตซอฟต์แวร์
|
||||
STR_CONNECT_WEBDAV=เชื่อมต่อ
|
||||
STR_DISCONNECT_WEBDAV=ยกเลิกการเชื่อมต่อ
|
||||
STR_SEARCH=ค้นหา
|
||||
STR_REFRESH=รีเฟรช
|
||||
STR_SERVER=เซิร์ฟเวอร์
|
||||
STR_USERNAME=ชื่อผู้ใช้
|
||||
STR_PASSWORD=รหัสผ่าน
|
||||
STR_PORT=พอร์ต
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=ไดเรกทอรี
|
||||
STR_FILTER=ฟิลเตอร์
|
||||
STR_YES=ใช่
|
||||
STR_NO=ไม่
|
||||
STR_CANCEL=ยกเลิก
|
||||
STR_CONTINUE=ดำเนินการต่อ
|
||||
STR_CLOSE=ปิด
|
||||
STR_FOLDER=โฟลเดอร์
|
||||
STR_FILE=ไฟล์
|
||||
STR_TYPE=ประเภท
|
||||
STR_NAME=ชื่อ
|
||||
STR_SIZE=ขนาด
|
||||
STR_DATE=วันที่
|
||||
STR_NEW_FOLDER=โฟลเดอร์ใหม่
|
||||
STR_RENAME=เปลี่ยนชื่อ
|
||||
STR_DELETE=ลบ
|
||||
STR_UPLOAD=อัปโหลด
|
||||
STR_DOWNLOAD=ดาวน์โหลด
|
||||
STR_SELECT_ALL=เลือกทั้งหมด
|
||||
STR_CLEAR_ALL=ล้างทั้งหมด
|
||||
STR_UPLOADING=กำลังอัปโหลด
|
||||
STR_DOWNLOADING=กำลังดาวน์โหลด
|
||||
STR_OVERWRITE=เขียนทับ
|
||||
STR_DONT_OVERWRITE=ไม่เขียนทับ
|
||||
STR_ASK_FOR_CONFIRM=ไม่ต้องยืนยัน
|
||||
STR_DONT_ASK_CONFIRM=ต้องยืนยัน
|
||||
STR_ALLWAYS_USE_OPTION=ใช้ตัวเลือกนี้อยู่เสมอและไม่แสดงอีก
|
||||
STR_ACTIONS=การดำเนินการ
|
||||
STR_CONFIRM=ยืนยัน
|
||||
STR_OVERWRITE_OPTIONS=ตัวเลือกเขียนทับ
|
||||
STR_PROPERTIES=คุณสมบัติ
|
||||
STR_PROGRESS=ความคืบหน้า
|
||||
STR_UPDATES=อัปเดต
|
||||
STR_DEL_CONFIRM_MSG=คุณแน่ใจหรือว่าต้องการลบไฟล์/โฟลเดอร์นี้?
|
||||
STR_CANCEL_ACTION_MSG=ยกเลิก กำลังรอการดำเนินการสุดท้าย
|
||||
STR_FAIL_UPLOAD_MSG=อัปโหลดไฟล์ล้มเหลว
|
||||
STR_FAIL_DOWNLOAD_MSG=ดาวน์โหลดไฟล์ล้มเหลว
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=ไม่สามารถอ่านเนื้อหาของไดเรกทอรีหรือโฟลเดอร์นี้ได้ หรือโฟลเดอร์ไม่มีอยู่
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 การเชื่อมต่อถูกปิด
|
||||
STR_REMOTE_TERM_CONN_MSG=426 เซิร์ฟเวอร์ระยะไกลได้ยุติการเชื่อมต่อ
|
||||
STR_FAIL_LOGIN_MSG=300 การเข้าสู่ระบบล้มเหลว กรุณาตรวจสอบชื่อผู้ใช้หรือรหัสผ่านของคุณ
|
||||
STR_FAIL_TIMEOUT_MSG=426 ล้มเหลว หมดเวลาการเชื่อมต่อ
|
||||
STR_FAIL_DEL_DIR_MSG=ไม่สามารถลบไดเรกทอรี
|
||||
STR_DELETING=กำลังลบ
|
||||
STR_FAIL_DEL_FILE_MSG=ไม่สามารถลบไฟล์
|
||||
STR_DELETED=ลบแล้ว
|
||||
@@ -0,0 +1,61 @@
|
||||
STR_CONNECTION_SETTINGS=連接設定
|
||||
STR_SITE=主機
|
||||
STR_LOCAL=本地
|
||||
STR_REMOTE=遠端
|
||||
STR_MESSAGES=狀態
|
||||
STR_UPDATE_SOFTWARE=更新版本
|
||||
STR_CONNECT_WEBDAV=連接
|
||||
STR_DISCONNECT_WEBDAV=中斷
|
||||
STR_SEARCH=搜尋
|
||||
STR_REFRESH=重新整理
|
||||
STR_SERVER=伺服器
|
||||
STR_USERNAME=使用者
|
||||
STR_PASSWORD=密碼
|
||||
STR_PORT=連接埠
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=路徑
|
||||
STR_FILTER=篩選
|
||||
STR_YES=是
|
||||
STR_NO=否
|
||||
STR_CANCEL=取消
|
||||
STR_CONTINUE=繼續
|
||||
STR_CLOSE=關閉
|
||||
STR_FOLDER=資料夾
|
||||
STR_FILE=檔案
|
||||
STR_TYPE=類型
|
||||
STR_NAME=名稱
|
||||
STR_SIZE=大小
|
||||
STR_DATE=日期
|
||||
STR_NEW_FOLDER=新建資料夾
|
||||
STR_RENAME=更名
|
||||
STR_DELETE=刪除
|
||||
STR_UPLOAD=上傳
|
||||
STR_DOWNLOAD=下載
|
||||
STR_SELECT_ALL=全選
|
||||
STR_CLEAR_ALL=全部清除
|
||||
STR_UPLOADING=上傳
|
||||
STR_DOWNLOADING=下載
|
||||
STR_OVERWRITE=覆蓋
|
||||
STR_DONT_OVERWRITE=不要覆蓋
|
||||
STR_ASK_FOR_CONFIRM=詢問確認
|
||||
STR_DONT_ASK_CONFIRM=無須再次確認
|
||||
STR_ALLWAYS_USE_OPTION=預設使用此設定,不再詢問
|
||||
STR_ACTIONS=操作
|
||||
STR_CONFIRM=確認
|
||||
STR_OVERWRITE_OPTIONS=覆蓋選項
|
||||
STR_PROPERTIES=屬性
|
||||
STR_PROGRESS=進程
|
||||
STR_UPDATES=更新
|
||||
STR_DEL_CONFIRM_MSG=確認要刪除此檔案/資料夾嗎?
|
||||
STR_CANCEL_ACTION_MSG=取消,等待最後一個動作完成
|
||||
STR_FAIL_UPLOAD_MSG=上傳檔案失敗
|
||||
STR_FAIL_DOWNLOAD_MSG=下載檔案失敗
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=讀取資料夾失敗或資料夾不存在。
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 連線已關閉。
|
||||
STR_REMOTE_TERM_CONN_MSG=426 遠端伺服器已終止連線。
|
||||
STR_FAIL_LOGIN_MSG=300 連線失敗。請檢查使用者名稱或密碼。
|
||||
STR_FAIL_TIMEOUT_MSG=426 連線失敗。連線逾時。
|
||||
STR_FAIL_DEL_DIR_MSG=刪除資料夾失敗
|
||||
STR_DELETING=正在刪除
|
||||
STR_FAIL_DEL_FILE_MSG=刪除檔案失敗
|
||||
STR_DELETED=已刪除
|
||||
@@ -0,0 +1,75 @@
|
||||
STR_CONNECTION_SETTINGS=Bağlantı Ayarları
|
||||
STR_SITE=Site
|
||||
STR_LOCAL=Yerel
|
||||
STR_REMOTE=Uzaktan
|
||||
STR_MESSAGES=Mesajlar
|
||||
STR_UPDATE_SOFTWARE=Yazılımı Güncelle
|
||||
STR_CONNECT_WEBDAV=Bağlan
|
||||
STR_DISCONNECT_WEBDAV=Bağlantıyı kes
|
||||
STR_SEARCH=Ara
|
||||
STR_REFRESH=Yenile
|
||||
STR_SERVER=Sunucu
|
||||
STR_USERNAME=Kullanıcı Adı
|
||||
STR_PASSWORD=Şifre
|
||||
STR_PORT=Port
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Dizin
|
||||
STR_FILTER=Filtre
|
||||
STR_YES=Evet
|
||||
STR_NO=Hayır
|
||||
STR_CANCEL=İptal
|
||||
STR_CONTINUE=Devam
|
||||
STR_CLOSE=Kapat
|
||||
STR_FOLDER=Klasör
|
||||
STR_FILE=Dosya
|
||||
STR_TYPE=Tip
|
||||
STR_NAME=Ad
|
||||
STR_SIZE=Boyut
|
||||
STR_DATE=Tarih
|
||||
STR_NEW_FOLDER=Yeni Klasör
|
||||
STR_RENAME=Yeniden Adlandır
|
||||
STR_DELETE=Sil
|
||||
STR_UPLOAD=Karşıya Yükle
|
||||
STR_DOWNLOAD=İndir
|
||||
STR_SELECT_ALL=Tümünü Seç
|
||||
STR_CLEAR_ALL=Tümünü Temizle
|
||||
STR_UPLOADING=Karşıya Yükleniyor
|
||||
STR_DOWNLOADING=İndiriliyor
|
||||
STR_OVERWRITE=Üzerine yaz
|
||||
STR_DONT_OVERWRITE=Üzerine yazma
|
||||
STR_ASK_FOR_CONFIRM=Onaylamak için sor
|
||||
STR_DONT_ASK_CONFIRM=Onaylamak için sorma
|
||||
STR_ALLWAYS_USE_OPTION=Daima bu seçeneği kullan ve bir daha sorma
|
||||
STR_ACTIONS=Eylemler
|
||||
STR_CONFIRM=Onayla
|
||||
STR_OVERWRITE_OPTIONS=Ayarların üzerine yaz
|
||||
STR_PROPERTIES=Özellikler
|
||||
STR_PROGRESS=Durum
|
||||
STR_UPDATES=Güncellemeler
|
||||
STR_DEL_CONFIRM_MSG=Bu dosya(ları)/klasör(leri) silmek istediğinizden emin misiniz?
|
||||
STR_CANCEL_ACTION_MSG=İptal ediliyor. Son işlemin tamamlanması bekleniyor
|
||||
STR_FAIL_UPLOAD_MSG=Dosya karşıya yükleme başarısız
|
||||
STR_FAIL_DOWNLOAD_MSG=Dosya indirme başarısız
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Dizindeki içerikler okunamadı ya da öyle bir klasör yok
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Bağlantı kesildi.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Uzaktan Sunucu bağlantıyı kesti.
|
||||
STR_FAIL_LOGIN_MSG=300 Giriş başarısız. Lütfen kullanıcı adınızı ve şifrenizi kontrol edin.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Başarısız. Bağlantı zaman aşımına uğradı.
|
||||
STR_FAIL_DEL_DIR_MSG=Dizin silme başarısız
|
||||
STR_DELETING=Siliniyor
|
||||
STR_FAIL_DEL_FILE_MSG=Dosya silme başarısız
|
||||
STR_DELETED=Silindi
|
||||
STR_LINK=Link
|
||||
STR_SHARE=Paylaş
|
||||
STR_FAILED=310 Başarısız
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 Yerelde dosya oluşturulumu başarısız
|
||||
STR_INSTALL=Yükle
|
||||
STR_INSTALLING=Yükleniyor
|
||||
STR_INSTALL_SUCCESS=Başarılı
|
||||
STR_INSTALL_FAILED=Başarısız
|
||||
STR_INSTALL_SKIPPED=Atlandı
|
||||
STR_CHECK_HTTP_MSG=Uzaktan HTTP Sunucusu bağlantısı kontrol ediliyor
|
||||
STR_FAILED_HTTP_CHECK=HTTP Sunucusuna bağlantı başarısız
|
||||
STR_REMOTE_NOT_HTTP=Uzaktaki HTTP Sunucusu değil
|
||||
STR_INSTALL_FROM_DATA_MSG=Paket /data ya da /mnt/usbX dizininde değil
|
||||
STR_ALREADY_INSTALLED_MSG=Paket zaten kurulu
|
||||
|
After Width: | Height: | Size: 350 KiB |
@@ -0,0 +1,87 @@
|
||||
#ifndef ACTIONS_H
|
||||
#define ACTIONS_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include "common.h"
|
||||
|
||||
#define CONFIRM_NONE -1
|
||||
#define CONFIRM_WAIT 0
|
||||
#define CONFIRM_YES 1
|
||||
#define CONFIRM_NO 2
|
||||
|
||||
enum ACTIONS
|
||||
{
|
||||
ACTION_NONE = 0,
|
||||
ACTION_UPLOAD,
|
||||
ACTION_DOWNLOAD,
|
||||
ACTION_DELETE_LOCAL,
|
||||
ACTION_DELETE_REMOTE,
|
||||
ACTION_RENAME_LOCAL,
|
||||
ACTION_RENAME_REMOTE,
|
||||
ACTION_NEW_LOCAL_FOLDER,
|
||||
ACTION_NEW_REMOTE_FOLDER,
|
||||
ACTION_CHANGE_LOCAL_DIRECTORY,
|
||||
ACTION_CHANGE_REMOTE_DIRECTORY,
|
||||
ACTION_APPLY_LOCAL_FILTER,
|
||||
ACTION_APPLY_REMOTE_FILTER,
|
||||
ACTION_REFRESH_LOCAL_FILES,
|
||||
ACTION_REFRESH_REMOTE_FILES,
|
||||
ACTION_SHOW_LOCAL_PROPERTIES,
|
||||
ACTION_SHOW_REMOTE_PROPERTIES,
|
||||
ACTION_LOCAL_SELECT_ALL,
|
||||
ACTION_REMOTE_SELECT_ALL,
|
||||
ACTION_LOCAL_CLEAR_ALL,
|
||||
ACTION_REMOTE_CLEAR_ALL,
|
||||
ACTION_CONNECT_WEBDAV,
|
||||
ACTION_DISCONNECT_WEBDAV,
|
||||
ACTION_DISCONNECT_WEBDAV_AND_EXIT,
|
||||
ACTION_INSTALL_REMOTE_PKG,
|
||||
ACTION_INSTALL_LOCAL_PKG,
|
||||
ACTION_INSTALL_URL_PKG
|
||||
};
|
||||
|
||||
enum OverWriteType
|
||||
{
|
||||
OVERWRITE_NONE = 0,
|
||||
OVERWRITE_PROMPT,
|
||||
OVERWRITE_ALL
|
||||
};
|
||||
|
||||
static pthread_t bk_activity_thid;
|
||||
static pthread_t ftp_keep_alive_thid;
|
||||
|
||||
namespace Actions
|
||||
{
|
||||
|
||||
void RefreshLocalFiles(bool apply_filter);
|
||||
void RefreshRemoteFiles(bool apply_filter);
|
||||
void HandleChangeLocalDirectory(const DirEntry entry);
|
||||
void HandleChangeRemoteDirectory(const DirEntry entry);
|
||||
void HandleRefreshLocalFiles();
|
||||
void HandleRefreshRemoteFiles();
|
||||
void CreateNewLocalFolder(char *new_folder);
|
||||
void CreateNewRemoteFolder(char *new_folder);
|
||||
void RenameLocalFolder(const char *old_path, const char *new_path);
|
||||
void RenameRemoteFolder(const char *old_path, const char *new_path);
|
||||
void *DeleteSelectedLocalFilesThread(void *argp);
|
||||
void DeleteSelectedLocalFiles();
|
||||
void *DeleteSelectedRemotesFilesThread(void *argp);
|
||||
void DeleteSelectedRemotesFiles();
|
||||
void *UploadFilesThread(void *argp);
|
||||
void UploadFiles();
|
||||
void *DownloadFilesThread(void *argp);
|
||||
void DownloadFiles();
|
||||
void ConnectWebDav();
|
||||
void DisconnectWebDav();
|
||||
void SelectAllLocalFiles();
|
||||
void SelectAllRemoteFiles();
|
||||
void *InstallRemotePkgsThread(void *argp);
|
||||
void InstallRemotePkgs();
|
||||
void *InstallLocalPkgsThread(void *argp);
|
||||
void InstallLocalPkgs();
|
||||
void *InstallUrlPkgThread(void *argp);
|
||||
void InstallUrlPkg();
|
||||
void *KeepAliveThread(void *argp);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t dayOfWeek;
|
||||
uint8_t hours;
|
||||
uint8_t minutes;
|
||||
uint8_t seconds;
|
||||
uint32_t microsecond;
|
||||
} DateTime;
|
||||
|
||||
struct DirEntry
|
||||
{
|
||||
char directory[512];
|
||||
char name[256];
|
||||
char display_size[48];
|
||||
char display_date[32];
|
||||
char path[768];
|
||||
uint64_t file_size;
|
||||
bool isDir;
|
||||
bool isLink;
|
||||
DateTime modified;
|
||||
|
||||
friend bool operator<(DirEntry const &a, DirEntry const &b)
|
||||
{
|
||||
return strcmp(a.name, b.name) < 0;
|
||||
}
|
||||
|
||||
static int DirEntryComparator(const void *v1, const void *v2)
|
||||
{
|
||||
const DirEntry *p1 = (DirEntry *)v1;
|
||||
const DirEntry *p2 = (DirEntry *)v2;
|
||||
if (strcasecmp(p1->name, "..") == 0)
|
||||
return -1;
|
||||
if (strcasecmp(p2->name, "..") == 0)
|
||||
return 1;
|
||||
|
||||
if (p1->isDir && !p2->isDir)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (!p1->isDir && p2->isDir)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return strcasecmp(p1->name, p2->name);
|
||||
}
|
||||
|
||||
static void Sort(std::vector<DirEntry> &list)
|
||||
{
|
||||
qsort(&list[0], list.size(), sizeof(DirEntry), DirEntryComparator);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,160 @@
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "lang.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "inifile.h"
|
||||
}
|
||||
|
||||
bool swap_xo;
|
||||
WebDavSettings *webdav_settings;
|
||||
char local_directory[255];
|
||||
char remote_directory[255];
|
||||
char app_ver[6];
|
||||
char last_site[32];
|
||||
char display_site[32];
|
||||
char language[128];
|
||||
std::vector<std::string> sites;
|
||||
std::map<std::string, WebDavSettings> site_settings;
|
||||
char install_pkg_url[512];
|
||||
char favorite_urls[MAX_FAVORITE_URLS][512];
|
||||
bool auto_delete_tmp_pkg;
|
||||
RemoteClient *webdavclient;
|
||||
|
||||
namespace CONFIG
|
||||
{
|
||||
|
||||
void LoadConfig()
|
||||
{
|
||||
if (!FS::FolderExists(DATA_PATH))
|
||||
{
|
||||
FS::MkDirs(DATA_PATH);
|
||||
}
|
||||
|
||||
sites = {"Site 1", "Site 2", "Site 3", "Site 4", "Site 5", "Site 6", "Site 7", "Site 8", "Site 9", "Site 10",
|
||||
"Site 11", "Site 12", "Site 13", "Site 14", "Site 15", "Site 16", "Site 17", "Site 18", "Site 19", "Site 20"};
|
||||
|
||||
OpenIniFile(CONFIG_INI_FILE);
|
||||
|
||||
// Load global config
|
||||
sprintf(language, "%s", ReadString(CONFIG_GLOBAL, CONFIG_LANGUAGE, ""));
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_LANGUAGE, language);
|
||||
|
||||
sprintf(local_directory, "%s", ReadString(CONFIG_GLOBAL, CONFIG_LOCAL_DIRECTORY, "/"));
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_LOCAL_DIRECTORY, local_directory);
|
||||
|
||||
sprintf(remote_directory, "%s", ReadString(CONFIG_GLOBAL, CONFIG_REMOTE_DIRECTORY, "/"));
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_REMOTE_DIRECTORY, remote_directory);
|
||||
|
||||
auto_delete_tmp_pkg = ReadBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, true);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg);
|
||||
|
||||
for (int i = 0; i < sites.size(); i++)
|
||||
{
|
||||
WebDavSettings setting;
|
||||
sprintf(setting.site_name, "%s", sites[i].c_str());
|
||||
|
||||
sprintf(setting.server, "%s", ReadString(sites[i].c_str(), CONFIG_WEBDAV_SERVER_IP, ""));
|
||||
WriteString(sites[i].c_str(), CONFIG_WEBDAV_SERVER_IP, setting.server);
|
||||
|
||||
sprintf(setting.username, "%s", ReadString(sites[i].c_str(), CONFIG_WEBDAV_SERVER_USER, ""));
|
||||
WriteString(sites[i].c_str(), CONFIG_WEBDAV_SERVER_USER, setting.username);
|
||||
|
||||
sprintf(setting.password, "%s", ReadString(sites[i].c_str(), CONFIG_WEBDAV_SERVER_PASSWORD, ""));
|
||||
WriteString(sites[i].c_str(), CONFIG_WEBDAV_SERVER_PASSWORD, setting.password);
|
||||
|
||||
site_settings.insert(std::make_pair(sites[i], setting));
|
||||
}
|
||||
|
||||
sprintf(last_site, "%s", ReadString(CONFIG_GLOBAL, CONFIG_LAST_SITE, sites[0].c_str()));
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_LAST_SITE, last_site);
|
||||
|
||||
webdav_settings = &site_settings[std::string(last_site)];
|
||||
|
||||
for (int i = 0; i < MAX_FAVORITE_URLS; i++)
|
||||
{
|
||||
const char *index = std::to_string(i).c_str();
|
||||
sprintf(favorite_urls[i], "%s", ReadString(CONFIG_FAVORITE_URLS, index, ""));
|
||||
WriteString(CONFIG_FAVORITE_URLS, index, favorite_urls[i]);
|
||||
}
|
||||
|
||||
WriteIniFile(CONFIG_INI_FILE);
|
||||
CloseIniFile();
|
||||
}
|
||||
|
||||
void SaveConfig()
|
||||
{
|
||||
OpenIniFile(CONFIG_INI_FILE);
|
||||
|
||||
WriteString(last_site, CONFIG_WEBDAV_SERVER_IP, webdav_settings->server);
|
||||
WriteString(last_site, CONFIG_WEBDAV_SERVER_USER, webdav_settings->username);
|
||||
WriteString(last_site, CONFIG_WEBDAV_SERVER_PASSWORD, webdav_settings->password);
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_LAST_SITE, last_site);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg);
|
||||
WriteIniFile(CONFIG_INI_FILE);
|
||||
CloseIniFile();
|
||||
}
|
||||
|
||||
void SaveFavoriteUrl(int index, char *url)
|
||||
{
|
||||
OpenIniFile(CONFIG_INI_FILE);
|
||||
const char *idx = std::to_string(index).c_str();
|
||||
WriteString(CONFIG_FAVORITE_URLS, idx, url);
|
||||
WriteIniFile(CONFIG_INI_FILE);
|
||||
CloseIniFile();
|
||||
}
|
||||
|
||||
void ParseMultiValueString(const char *prefix_list, std::vector<std::string> &prefixes, bool toLower)
|
||||
{
|
||||
std::string prefix = "";
|
||||
int length = strlen(prefix_list);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
char c = prefix_list[i];
|
||||
if (c != ' ' && c != '\t' && c != ',')
|
||||
{
|
||||
if (toLower)
|
||||
{
|
||||
prefix += std::tolower(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix += c;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == ',' || i == length - 1)
|
||||
{
|
||||
prefixes.push_back(prefix);
|
||||
prefix = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetMultiValueString(std::vector<std::string> &multi_values)
|
||||
{
|
||||
std::string vts = std::string("");
|
||||
if (multi_values.size() > 0)
|
||||
{
|
||||
for (int i = 0; i < multi_values.size() - 1; i++)
|
||||
{
|
||||
vts.append(multi_values[i]).append(",");
|
||||
}
|
||||
vts.append(multi_values[multi_values.size() - 1]);
|
||||
}
|
||||
return vts;
|
||||
}
|
||||
|
||||
void RemoveFromMultiValues(std::vector<std::string> &multi_values, std::string value)
|
||||
{
|
||||
auto itr = std::find(multi_values.begin(), multi_values.end(), value);
|
||||
if (itr != multi_values.end())
|
||||
multi_values.erase(itr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#ifndef LAUNCHER_CONFIG_H
|
||||
#define LAUNCHER_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include "remote_client.h"
|
||||
|
||||
#define APP_ID "ps4-remote-client"
|
||||
#define DATA_PATH "/data/" APP_ID
|
||||
#define CONFIG_INI_FILE DATA_PATH "/config.ini"
|
||||
#define COOKIE_FILE DATA_PATH "/cookies.txt"
|
||||
|
||||
#define CONFIG_GLOBAL "Global"
|
||||
|
||||
#define CONFIG_WEBDAV_SERVER_NAME "webdav_server_name"
|
||||
#define CONFIG_WEBDAV_SERVER_IP "webdav_server_ip"
|
||||
#define CONFIG_WEBDAV_SERVER_PORT "webdav_server_port"
|
||||
#define CONFIG_WEBDAV_SERVER_USER "webdav_server_user"
|
||||
#define CONFIG_WEBDAV_SERVER_PASSWORD "webdav_server_password"
|
||||
#define CONFIG_WEBDAV_SERVER_SHARE "webdav_server_share"
|
||||
#define CONFIG_WEBDAV_SERVER_HTTP_PORT "webdav_server_http_port"
|
||||
|
||||
#define CONFIG_FAVORITE_URLS "favorite_urls"
|
||||
#define MAX_FAVORITE_URLS 30
|
||||
|
||||
#define CONFIG_LAST_SITE "last_site"
|
||||
#define CONFIG_AUTO_DELETE_TMP_PKG "auto_delete_tmp_pkg"
|
||||
|
||||
#define CONFIG_LOCAL_DIRECTORY "local_directory"
|
||||
#define CONFIG_REMOTE_DIRECTORY "remote_directory"
|
||||
|
||||
#define CONFIG_LANGUAGE "language"
|
||||
|
||||
struct WebDavSettings
|
||||
{
|
||||
char site_name[32];
|
||||
char server[256];
|
||||
char username[33];
|
||||
char password[25];
|
||||
};
|
||||
|
||||
extern std::vector<std::string> sites;
|
||||
extern std::map<std::string, WebDavSettings> site_settings;
|
||||
extern char local_directory[255];
|
||||
extern char remote_directory[255];
|
||||
extern char app_ver[6];
|
||||
extern char last_site[32];
|
||||
extern char display_site[32];
|
||||
extern char language[128];
|
||||
extern WebDavSettings *webdav_settings;
|
||||
extern RemoteClient *webdavclient;
|
||||
extern char install_pkg_url[512];
|
||||
extern char favorite_urls[MAX_FAVORITE_URLS][512];
|
||||
extern bool auto_delete_tmp_pkg;
|
||||
|
||||
namespace CONFIG
|
||||
{
|
||||
void LoadConfig();
|
||||
void SaveConfig();
|
||||
void SaveFavoriteUrl(int index, char *url);
|
||||
void RemoveFromMultiValues(std::vector<std::string> &multi_values, std::string value);
|
||||
void ParseMultiValueString(const char *prefix_list, std::vector<std::string> &prefixes, bool toLower);
|
||||
std::string GetMultiValueString(std::vector<std::string> &multi_values);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,435 @@
|
||||
#include "fs.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <dirent.h>
|
||||
#include <filesystem>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "lang.h"
|
||||
#include "rtc.h"
|
||||
#include "windows.h"
|
||||
|
||||
namespace FS
|
||||
{
|
||||
int hasEndSlash(const char *path)
|
||||
{
|
||||
return path[strlen(path) - 1] == '/';
|
||||
}
|
||||
|
||||
void MkDirs(const std::string &ppath, bool prev)
|
||||
{
|
||||
std::string path = ppath;
|
||||
if (!prev)
|
||||
{
|
||||
path.push_back('/');
|
||||
}
|
||||
auto ptr = path.begin();
|
||||
while (true)
|
||||
{
|
||||
ptr = std::find(ptr, path.end(), '/');
|
||||
if (ptr == path.end())
|
||||
break;
|
||||
|
||||
char last = *ptr;
|
||||
*ptr = 0;
|
||||
int err = mkdir(path.c_str(), 0777);
|
||||
*ptr = last;
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Rm(const std::string &file)
|
||||
{
|
||||
remove(file.c_str());
|
||||
}
|
||||
|
||||
void RmDir(const std::string &path)
|
||||
{
|
||||
remove(path.c_str());
|
||||
}
|
||||
|
||||
int64_t GetSize(const std::string &path)
|
||||
{
|
||||
struct stat file_stat = {0};
|
||||
int err = stat(path.c_str(), &file_stat);
|
||||
if (err < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return file_stat.st_size;
|
||||
}
|
||||
|
||||
bool FileExists(const std::string &path)
|
||||
{
|
||||
struct stat file_stat = {0};
|
||||
return (stat(path.c_str(), std::addressof(file_stat)) == 0 && S_ISREG(file_stat.st_mode));
|
||||
}
|
||||
|
||||
bool FolderExists(const std::string &path)
|
||||
{
|
||||
struct stat dir_stat = {0};
|
||||
return (stat(path.c_str(), &dir_stat) == 0);
|
||||
}
|
||||
|
||||
void Rename(const std::string &from, const std::string &to)
|
||||
{
|
||||
int res = rename(from.c_str(), to.c_str());
|
||||
}
|
||||
|
||||
FILE *Create(const std::string &path)
|
||||
{
|
||||
FILE *fd = fopen(path.c_str(), "w");
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
FILE *OpenRW(const std::string &path)
|
||||
{
|
||||
FILE *fd = fopen(path.c_str(), "w+");
|
||||
return fd;
|
||||
}
|
||||
|
||||
FILE *OpenRead(const std::string &path)
|
||||
{
|
||||
FILE *fd = fopen(path.c_str(), "rb");
|
||||
return fd;
|
||||
}
|
||||
|
||||
FILE *Append(const std::string &path)
|
||||
{
|
||||
FILE *fd = fopen(path.c_str(), "a");
|
||||
return fd;
|
||||
}
|
||||
|
||||
int64_t Seek(FILE *f, uint64_t offset)
|
||||
{
|
||||
auto const pos = fseek(f, offset, SEEK_SET);
|
||||
return pos;
|
||||
}
|
||||
|
||||
int Read(FILE *f, void *buffer, uint32_t size)
|
||||
{
|
||||
const auto read = fread(buffer, 1, size, f);
|
||||
return read;
|
||||
}
|
||||
|
||||
int Write(FILE *f, const void *buffer, uint32_t size)
|
||||
{
|
||||
int write = fwrite(buffer, size, 1, f);
|
||||
return write;
|
||||
}
|
||||
|
||||
void Close(FILE *fd)
|
||||
{
|
||||
int err = fclose(fd);
|
||||
}
|
||||
|
||||
std::vector<char> Load(const std::string &path)
|
||||
{
|
||||
FILE *fd = fopen(path.c_str(), "r");
|
||||
if (fd == nullptr)
|
||||
return std::vector<char>(0);
|
||||
|
||||
const auto size = fseek(fd, 0, SEEK_END);
|
||||
fseek(fd, 0, SEEK_SET);
|
||||
|
||||
std::vector<char> data(size);
|
||||
|
||||
const auto read = fread(data.data(), data.size(), 1, fd);
|
||||
fclose(fd);
|
||||
if (read < 0)
|
||||
return std::vector<char>(0);
|
||||
|
||||
data.resize(read);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void Save(const std::string &path, const void *data, uint32_t size)
|
||||
{
|
||||
FILE *fd = fopen(path.c_str(), "w+");
|
||||
if (fd == nullptr)
|
||||
return;
|
||||
|
||||
const char *data8 = static_cast<const char *>(data);
|
||||
while (size != 0)
|
||||
{
|
||||
int written = fwrite(data8, size, 1, fd);
|
||||
fclose(fd);
|
||||
if (written <= 0)
|
||||
return;
|
||||
data8 += written;
|
||||
size -= written;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DirEntry> ListDir(const std::string &ppath, int *err)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
std::string path = ppath;
|
||||
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
sprintf(entry.name, "..");
|
||||
sprintf(entry.display_size, "%s",lang_strings[STR_FOLDER]);
|
||||
sprintf(entry.path, "%s", path.c_str());
|
||||
entry.file_size = 0;
|
||||
entry.isDir = true;
|
||||
out.push_back(entry);
|
||||
|
||||
DIR *fd = opendir(path.c_str());
|
||||
*err = 0;
|
||||
if (fd == NULL)
|
||||
{
|
||||
*err = 1;
|
||||
return out;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
struct dirent *dirent;
|
||||
DirEntry entry;
|
||||
dirent = readdir(fd);
|
||||
if (dirent == NULL)
|
||||
{
|
||||
closedir(fd);
|
||||
return out;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(entry.directory, 512, "%s", path.c_str());
|
||||
snprintf(entry.name, 256, "%s", dirent->d_name);
|
||||
|
||||
if (hasEndSlash(path.c_str()))
|
||||
{
|
||||
sprintf(entry.path, "%s%s", path.c_str(), dirent->d_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.path, "%s/%s", path.c_str(), dirent->d_name);
|
||||
}
|
||||
struct stat file_stat = {0};
|
||||
stat(entry.path, &file_stat);
|
||||
struct tm tm = *localtime(&file_stat.st_mtim.tv_sec);
|
||||
|
||||
OrbisDateTime gmt;
|
||||
OrbisDateTime lt;
|
||||
|
||||
gmt.day = tm.tm_mday;
|
||||
gmt.month = tm.tm_mon + 1;
|
||||
gmt.year = tm.tm_year + 1900;
|
||||
gmt.hour = tm.tm_hour;
|
||||
gmt.minute = tm.tm_min;
|
||||
gmt.second = tm.tm_sec;
|
||||
|
||||
convertUtcToLocalTime(&gmt, <);
|
||||
|
||||
entry.modified.day = lt.day;
|
||||
entry.modified.month = lt.month;
|
||||
entry.modified.year = lt.year;
|
||||
entry.modified.hours = lt.hour;
|
||||
entry.modified.minutes = lt.minute;
|
||||
entry.modified.seconds = lt.second;
|
||||
entry.file_size = file_stat.st_size;
|
||||
|
||||
if (dirent->d_type & DT_DIR)
|
||||
{
|
||||
entry.isDir = true;
|
||||
entry.file_size = 0;
|
||||
sprintf(entry.display_size, "%s",lang_strings[STR_FOLDER]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (entry.file_size < 1024)
|
||||
{
|
||||
sprintf(entry.display_size, "%luB", entry.file_size);
|
||||
}
|
||||
else if (entry.file_size < 1024 * 1024)
|
||||
{
|
||||
sprintf(entry.display_size, "%.2fKB", entry.file_size * 1.0f / 1024);
|
||||
}
|
||||
else if (entry.file_size < 1024 * 1024 * 1024)
|
||||
{
|
||||
sprintf(entry.display_size, "%.2fMB", entry.file_size * 1.0f / (1024 * 1024));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.display_size, "%.2fGB", entry.file_size * 1.0f / (1024 * 1024 * 1024));
|
||||
}
|
||||
entry.isDir = false;
|
||||
}
|
||||
out.push_back(entry);
|
||||
}
|
||||
}
|
||||
closedir(fd);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::string> ListFiles(const std::string &path)
|
||||
{
|
||||
DIR *fd = opendir(path.c_str());
|
||||
if (fd == NULL)
|
||||
return std::vector<std::string>(0);
|
||||
|
||||
std::vector<std::string> out;
|
||||
while (true)
|
||||
{
|
||||
struct dirent *dirent;
|
||||
dirent = readdir(fd);
|
||||
if (dirent == NULL)
|
||||
{
|
||||
closedir(fd);
|
||||
return out;
|
||||
}
|
||||
|
||||
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dirent->d_type & DT_DIR)
|
||||
{
|
||||
std::vector<std::string> files = FS::ListFiles(path + "/" + dirent->d_name);
|
||||
for (std::vector<std::string>::iterator it = files.begin(); it != files.end();)
|
||||
{
|
||||
out.push_back(std::string(dirent->d_name) + "/" + *it);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out.push_back(dirent->d_name);
|
||||
}
|
||||
}
|
||||
closedir(fd);
|
||||
return out;
|
||||
}
|
||||
|
||||
int RmRecursive(const std::string &path)
|
||||
{
|
||||
if (stop_activity)
|
||||
return 1;
|
||||
|
||||
DIR *dfd = opendir(path.c_str());
|
||||
if (dfd != NULL)
|
||||
{
|
||||
struct dirent *dir = NULL;
|
||||
do
|
||||
{
|
||||
dir = readdir(dfd);
|
||||
if (dir == NULL || strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char new_path[512];
|
||||
snprintf(new_path, 512, "%s%s%s", path.c_str(), hasEndSlash(path.c_str()) ? "" : "/", dir->d_name);
|
||||
|
||||
if (dir->d_type & DT_DIR)
|
||||
{
|
||||
int ret = RmRecursive(new_path);
|
||||
if (ret <= 0)
|
||||
{
|
||||
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], new_path);
|
||||
closedir(dfd);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETING], new_path);
|
||||
int ret = remove(new_path);
|
||||
if (ret < 0)
|
||||
{
|
||||
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], new_path);
|
||||
closedir(dfd);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} while (dir != NULL && !stop_activity);
|
||||
|
||||
closedir(dfd);
|
||||
|
||||
if (stop_activity)
|
||||
return 0;
|
||||
|
||||
int ret = rmdir(path.c_str());
|
||||
if (ret < 0)
|
||||
{
|
||||
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], path.c_str());
|
||||
return ret;
|
||||
}
|
||||
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETED], path.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
int ret = remove(path.c_str());
|
||||
if (ret < 0)
|
||||
{
|
||||
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], path.c_str());
|
||||
return ret;
|
||||
}
|
||||
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETED], path.c_str());
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DirEntryComparator(const void *v1, const void *v2)
|
||||
{
|
||||
const DirEntry *p1 = (DirEntry *)v1;
|
||||
const DirEntry *p2 = (DirEntry *)v2;
|
||||
if (strcasecmp(p1->name, "..") == 0)
|
||||
return -1;
|
||||
if (strcasecmp(p2->name, "..") == 0)
|
||||
return 1;
|
||||
|
||||
if (p1->isDir && !p2->isDir)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (!p1->isDir && p2->isDir)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return strcasecmp(p1->name, p2->name);
|
||||
}
|
||||
|
||||
void Sort(std::vector<DirEntry> &list)
|
||||
{
|
||||
qsort(&list[0], list.size(), sizeof(DirEntry), DirEntryComparator);
|
||||
}
|
||||
|
||||
std::string GetPath(const std::string &ppath1, const std::string &ppath2)
|
||||
{
|
||||
std::string path1 = ppath1;
|
||||
std::string path2 = ppath2;
|
||||
path2 = Util::Rtrim(Util::Trim(path2, " "), "/");
|
||||
return path1 + "/" + path2;
|
||||
}
|
||||
|
||||
int Head(const std::string &path, void* buffer, uint16_t len)
|
||||
{
|
||||
FILE *file = OpenRead(path);
|
||||
int ret = Read(file, buffer, len);
|
||||
if (ret != len)
|
||||
{
|
||||
Close(file);
|
||||
return 0;
|
||||
}
|
||||
Close(file);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef LAUNCHER_FS_H
|
||||
#define LAUNCHER_FS_H
|
||||
|
||||
#pragma once
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define MAX_PATH_LENGTH 1024
|
||||
|
||||
namespace FS
|
||||
{
|
||||
std::string GetPath(const std::string &path1, const std::string &path2);
|
||||
|
||||
void MkDirs(const std::string &path, bool prev = false);
|
||||
|
||||
void Rm(const std::string &file);
|
||||
void RmDir(const std::string &path);
|
||||
int RmRecursive(const std::string &path);
|
||||
|
||||
int64_t GetSize(const std::string &path);
|
||||
|
||||
bool FileExists(const std::string &path);
|
||||
bool FolderExists(const std::string &path);
|
||||
|
||||
void Rename(const std::string &from, const std::string &to);
|
||||
|
||||
// creates file (if it exists, truncates size to 0)
|
||||
FILE *Create(const std::string &path);
|
||||
|
||||
// open existing file in read/write, fails if file does not exist
|
||||
FILE *OpenRW(const std::string &path);
|
||||
|
||||
// open existing file in read/write, fails if file does not exist
|
||||
FILE *OpenRead(const std::string &path);
|
||||
|
||||
// open file for writing, next write will append data to end of it
|
||||
FILE *Append(const std::string &path);
|
||||
|
||||
void Close(FILE *f);
|
||||
|
||||
int64_t Seek(FILE *f, uint64_t offset);
|
||||
int Read(FILE *f, void *buffer, uint32_t size);
|
||||
int Write(FILE *f, const void *buffer, uint32_t size);
|
||||
|
||||
std::vector<char> Load(const std::string &path);
|
||||
void Save(const std::string &path, const void *data, uint32_t size);
|
||||
|
||||
std::vector<std::string> ListFiles(const std::string &path);
|
||||
std::vector<DirEntry> ListDir(const std::string &path, int *err);
|
||||
|
||||
void Sort(std::vector<DirEntry> &list);
|
||||
|
||||
int hasEndSlash(const char *path);
|
||||
|
||||
int Head(const std::string &path, void* buffer, uint16_t len);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,127 @@
|
||||
#ifndef FTPCLIENT_H
|
||||
#define FTPCLIENT_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "remote_client.h"
|
||||
|
||||
#define FTP_CLIENT_MAX_FILENAME_LEN 128
|
||||
|
||||
typedef int (*FtpCallbackXfer)(int64_t xfered, void *arg);
|
||||
|
||||
struct ftphandle
|
||||
{
|
||||
char *cput, *cget;
|
||||
int handle;
|
||||
int cavail, cleft;
|
||||
char *buf;
|
||||
int dir;
|
||||
ftphandle *ctrl;
|
||||
int cmode;
|
||||
int64_t xfered;
|
||||
int64_t xfered1;
|
||||
int64_t cbbytes;
|
||||
char response[512];
|
||||
int64_t offset;
|
||||
bool correctpasv;
|
||||
FtpCallbackXfer xfercb;
|
||||
void *cbarg;
|
||||
bool is_connected;
|
||||
};
|
||||
|
||||
class FtpClient : public RemoteClient
|
||||
{
|
||||
public:
|
||||
enum accesstype
|
||||
{
|
||||
dir = 1,
|
||||
dirverbose,
|
||||
dirmlsd,
|
||||
fileread,
|
||||
filewrite,
|
||||
filereadappend,
|
||||
filewriteappend
|
||||
};
|
||||
|
||||
enum transfermode
|
||||
{
|
||||
ascii = 'A',
|
||||
image = 'I'
|
||||
};
|
||||
|
||||
enum connmode
|
||||
{
|
||||
pasv = 1,
|
||||
port
|
||||
};
|
||||
|
||||
enum attributes
|
||||
{
|
||||
directory = 1,
|
||||
readonly = 2
|
||||
};
|
||||
|
||||
FtpClient();
|
||||
~FtpClient();
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
void SetConnmode(connmode mode);
|
||||
int Site(const std::string &cmd);
|
||||
int Raw(const std::string &cmd);
|
||||
int SysType(char *buf, int max);
|
||||
int Mkdir(const std::string &path);
|
||||
int Chdir(const std::string &path);
|
||||
int Cdup();
|
||||
int Rmdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
int Get(const std::string &outputfile, const std::string &path, uint64_t offset = 0);
|
||||
int Put(const std::string &inputfile, const std::string &path, uint64_t offset = 0);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
int Delete(const std::string &path);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
void SetCallbackXferFunction(FtpCallbackXfer pointer);
|
||||
void SetCallbackArg(void *arg);
|
||||
void SetCallbackBytes(int64_t bytes);
|
||||
bool Noop();
|
||||
bool Ping();
|
||||
bool FileExists(const std::string &path);
|
||||
bool IsConnected();
|
||||
char *LastResponse();
|
||||
long GetIdleTime();
|
||||
int Quit();
|
||||
std::string GetPath(std::string path1, std::string path2);
|
||||
ClientType clientType();
|
||||
|
||||
private:
|
||||
ftphandle *mp_ftphandle;
|
||||
struct tm cur_time;
|
||||
timeval tick;
|
||||
char server[128];
|
||||
int server_port;
|
||||
|
||||
int FtpSendCmd(const std::string &cmd, char expected_resp, ftphandle *nControl);
|
||||
ftphandle *RawOpen(const std::string &path, accesstype type, transfermode mode);
|
||||
int RawClose(ftphandle *handle);
|
||||
int RawWrite(void *buf, int len, ftphandle *handle);
|
||||
int RawRead(void *buf, int max, ftphandle *handle);
|
||||
int ReadResponse(char c, ftphandle *nControl);
|
||||
int Readline(char *buf, int max, ftphandle *nControl);
|
||||
int Writeline(char *buf, int len, ftphandle *nData);
|
||||
void ClearHandle();
|
||||
int FtpOpenPasv(ftphandle *nControl, ftphandle **nData, transfermode mode, int dir, std::string &cmd);
|
||||
int FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode mode, int dir, std::string &cmd);
|
||||
int FtpAcceptConnection(ftphandle *nData, ftphandle *nControl);
|
||||
int CorrectPasvResponse(int *v);
|
||||
int FtpAccess(const std::string &path, accesstype type, transfermode mode, ftphandle *nControl, ftphandle **nData);
|
||||
int FtpXfer(const std::string &localfile, const std::string &path, ftphandle *nControl, accesstype type, transfermode mode);
|
||||
int FtpWrite(void *buf, int len, ftphandle *nData);
|
||||
int FtpRead(void *buf, int max, ftphandle *nData);
|
||||
int FtpClose(ftphandle *nData);
|
||||
int ParseDirEntry(char *line, DirEntry *dirEntry);
|
||||
int ParseMLSDDirEntry(char *line, DirEntry *dirEntry);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/random.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
int getentropy(void *buffer, size_t len)
|
||||
{
|
||||
int cs, ret = 0;
|
||||
char *pos = buffer;
|
||||
|
||||
if (len > 256) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||
|
||||
while (len) {
|
||||
ret = getrandom(pos, len, 0);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
else break;
|
||||
}
|
||||
pos += ret;
|
||||
len -= ret;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
pthread_setcancelstate(cs, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "imgui.h"
|
||||
#include <stdio.h>
|
||||
#include "windows.h"
|
||||
#include "gui.h"
|
||||
#include "SDL2/SDL.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include "imgui_impl_sdlrenderer.h"
|
||||
|
||||
bool done = false;
|
||||
int gui_mode = GUI_MODE_BROWSER;
|
||||
|
||||
namespace GUI
|
||||
{
|
||||
int RenderLoop(SDL_Renderer *renderer)
|
||||
{
|
||||
Windows::Init();
|
||||
while (!done)
|
||||
{
|
||||
if (gui_mode == GUI_MODE_BROWSER)
|
||||
{
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||
}
|
||||
|
||||
ImGui_ImplSDLRenderer_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
Windows::HandleWindowInput();
|
||||
Windows::MainWindow();
|
||||
Windows::ExecuteActions();
|
||||
|
||||
ImGui::Render();
|
||||
ImGui_ImplSDLRenderer_RenderDrawData(ImGui::GetDrawData());
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
else if (gui_mode == GUI_MODE_IME)
|
||||
{
|
||||
Windows::HandleImeInput();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef LAUNCHER_GUI_H
|
||||
#define LAUNCHER_GUI_H
|
||||
|
||||
#include <string>
|
||||
#include "SDL2/SDL.h"
|
||||
|
||||
#define GUI_MODE_BROWSER 0
|
||||
#define GUI_MODE_IME 1
|
||||
|
||||
extern bool done;
|
||||
extern int gui_mode;
|
||||
|
||||
namespace GUI
|
||||
{
|
||||
int RenderLoop(SDL_Renderer *renderer);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,125 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||
//-----------------------------------------------------------------------------
|
||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||
//#define IMGUI_USE_WCHAR32
|
||||
|
||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
|
||||
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||
//#define IMGUI_USE_STB_SPRINTF
|
||||
|
||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
|
||||
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
//#define ImDrawIdx unsigned int
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
//struct ImDrawCmd;
|
||||
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||
//#define ImDrawCallback MyImDrawCallback
|
||||
|
||||
//---- Debug Tools: Macro to break in Debugger
|
||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||
//#define IM_DEBUG_BREAK __debugbreak()
|
||||
|
||||
//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(),
|
||||
// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.)
|
||||
// This adds a small runtime cost which is why it is not enabled by default.
|
||||
//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
|
||||
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
//#define IMGUI_DEBUG_PARANOID
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, const MyMatrix44& v);
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,191 @@
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <orbis/UserService.h>
|
||||
#include "ime_dialog.h"
|
||||
|
||||
static int ime_dialog_running = 0;
|
||||
static uint16_t inputTextBuffer[512+1];
|
||||
static uint8_t storebuffer[512];
|
||||
static char initial_ime_text[512];
|
||||
static int max_text_length;
|
||||
|
||||
static void utf16_to_utf8(const uint16_t *src, uint8_t *dst)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; src[i]; i++)
|
||||
{
|
||||
if ((src[i] & 0xFF80) == 0)
|
||||
{
|
||||
*(dst++) = src[i] & 0xFF;
|
||||
}
|
||||
else if ((src[i] & 0xF800) == 0)
|
||||
{
|
||||
*(dst++) = ((src[i] >> 6) & 0xFF) | 0xC0;
|
||||
*(dst++) = (src[i] & 0x3F) | 0x80;
|
||||
}
|
||||
else if ((src[i] & 0xFC00) == 0xD800 && (src[i + 1] & 0xFC00) == 0xDC00)
|
||||
{
|
||||
*(dst++) = (((src[i] + 64) >> 8) & 0x3) | 0xF0;
|
||||
*(dst++) = (((src[i] >> 2) + 16) & 0x3F) | 0x80;
|
||||
*(dst++) = ((src[i] >> 4) & 0x30) | 0x80 | ((src[i + 1] << 2) & 0xF);
|
||||
*(dst++) = (src[i + 1] & 0x3F) | 0x80;
|
||||
i += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(dst++) = ((src[i] >> 12) & 0xF) | 0xE0;
|
||||
*(dst++) = ((src[i] >> 6) & 0x3F) | 0x80;
|
||||
*(dst++) = (src[i] & 0x3F) | 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
static void utf8_to_utf16(const uint8_t *src, uint16_t *dst)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; src[i];)
|
||||
{
|
||||
if ((src[i] & 0xE0) == 0xE0)
|
||||
{
|
||||
*(dst++) = ((src[i] & 0x0F) << 12) | ((src[i + 1] & 0x3F) << 6) | (src[i + 2] & 0x3F);
|
||||
i += 3;
|
||||
}
|
||||
else if ((src[i] & 0xC0) == 0xC0)
|
||||
{
|
||||
*(dst++) = ((src[i] & 0x1F) << 6) | (src[i + 1] & 0x3F);
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(dst++) = src[i];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
namespace Dialog
|
||||
{
|
||||
|
||||
int initImeDialog(const char *Title, const char *initialTextBuffer, int max_text_length, OrbisImeType type, float posx, float posy)
|
||||
{
|
||||
if (ime_dialog_running)
|
||||
return IME_DIALOG_ALREADY_RUNNING;
|
||||
|
||||
uint16_t title[100];
|
||||
|
||||
if ((initialTextBuffer && strlen(initialTextBuffer) > 511) || (Title && strlen(Title) > 99))
|
||||
{
|
||||
ime_dialog_running = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&inputTextBuffer[0], 0, sizeof(inputTextBuffer));
|
||||
memset(&storebuffer[0], 0, sizeof(storebuffer));
|
||||
memset(&initial_ime_text[0], 0, sizeof(initial_ime_text));
|
||||
|
||||
if (initialTextBuffer)
|
||||
{
|
||||
snprintf(initial_ime_text, 511, "%s", initialTextBuffer);
|
||||
}
|
||||
|
||||
// converts the multibyte string src to a wide-character string starting at dest.
|
||||
utf8_to_utf16((uint8_t *)initialTextBuffer, inputTextBuffer);
|
||||
utf8_to_utf16((uint8_t *)Title, title);
|
||||
|
||||
OrbisImeDialogSetting param;
|
||||
memset(¶m, 0, sizeof(OrbisImeDialogSetting));
|
||||
|
||||
int UserID = 0;
|
||||
sceUserServiceGetInitialUser(&UserID);
|
||||
param.supportedLanguages = 0;
|
||||
param.maxTextLength = max_text_length;
|
||||
param.inputTextBuffer = reinterpret_cast<wchar_t*>(inputTextBuffer);
|
||||
param.title = reinterpret_cast<wchar_t*>(title);
|
||||
param.userId = UserID;
|
||||
param.type = type;
|
||||
param.posx = posx;
|
||||
param.posy = posy;
|
||||
param.enterLabel = ORBIS_BUTTON_LABEL_DEFAULT;
|
||||
|
||||
int res = sceImeDialogInit(¶m, NULL);
|
||||
if (res >= 0)
|
||||
{
|
||||
ime_dialog_running = 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int isImeDialogRunning()
|
||||
{
|
||||
return ime_dialog_running;
|
||||
}
|
||||
|
||||
uint8_t *getImeDialogInputText()
|
||||
{
|
||||
return storebuffer;
|
||||
}
|
||||
|
||||
uint16_t *getImeDialogInputText16()
|
||||
{
|
||||
return inputTextBuffer;
|
||||
}
|
||||
|
||||
const char *getImeDialogInitialText()
|
||||
{
|
||||
return initial_ime_text;
|
||||
}
|
||||
|
||||
int updateImeDialog()
|
||||
{
|
||||
if (!ime_dialog_running)
|
||||
return IME_DIALOG_RESULT_NONE;
|
||||
|
||||
int status;
|
||||
while (1)
|
||||
{
|
||||
status = sceImeDialogGetStatus();
|
||||
|
||||
if (status == ORBIS_DIALOG_STATUS_STOPPED)
|
||||
{
|
||||
OrbisDialogResult result;
|
||||
memset(&result, 0, sizeof(OrbisDialogResult));
|
||||
sceImeDialogGetResult(&result);
|
||||
|
||||
if (result.endstatus == ORBIS_DIALOG_CANCEL)
|
||||
{
|
||||
status = IME_DIALOG_RESULT_CANCELED;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (result.endstatus == ORBIS_DIALOG_OK)
|
||||
{
|
||||
utf16_to_utf8(inputTextBuffer, storebuffer);
|
||||
status = IME_DIALOG_RESULT_FINISHED;
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == ORBIS_DIALOG_STATUS_NONE)
|
||||
{
|
||||
status = IME_DIALOG_RESULT_NONE;
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
Finished:
|
||||
sceImeDialogTerm();
|
||||
ime_dialog_running = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace Dialog
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
VitaShell
|
||||
Copyright (C) 2015-2018, TheFloW
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __IME_DIALOG_H__
|
||||
#define __IME_DIALOG_H__
|
||||
|
||||
#define IME_DIALOG_RESULT_NONE 0
|
||||
#define IME_DIALOG_RESULT_RUNNING 1
|
||||
#define IME_DIALOG_RESULT_FINISHED 2
|
||||
#define IME_DIALOG_RESULT_CANCELED 3
|
||||
|
||||
#define IME_DIALOG_ALREADY_RUNNING -1
|
||||
|
||||
#include <orbis/ImeDialog.h>
|
||||
|
||||
typedef void (*ime_callback_t)(int ime_result);
|
||||
|
||||
namespace Dialog
|
||||
{
|
||||
int initImeDialog(const char *Title, const char *initialTextBuffer, int max_text_length, OrbisImeType type, float posx, float posy);
|
||||
uint8_t *getImeDialogInputText();
|
||||
uint16_t *getImeDialogInputText16();
|
||||
const char *getImeDialogInitialText();
|
||||
int isImeDialogRunning();
|
||||
int updateImeDialog();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,630 @@
|
||||
// dear imgui: Platform Backend for SDL2
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||
// (Prefer SDL 2.0.5+ for full feature support.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// Missing features:
|
||||
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2022-09-26: Inputs: Disable SDL 2.0.22 new "auto capture" (SDL_HINT_MOUSE_AUTO_CAPTURE) which prevents drag and drop across windows for multi-viewport support + don't capture when drag and dropping. (#5710)
|
||||
// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
|
||||
// 2022-03-22: Inputs: Fix mouse position issues when dragging outside of boundaries. SDL_CaptureMouse() erroneously still gives out LEAVE events when hovering OS decorations.
|
||||
// 2022-03-22: Inputs: Added support for extra mouse buttons (SDL_BUTTON_X1/SDL_BUTTON_X2).
|
||||
// 2022-02-04: Added SDL_Renderer* parameter to ImGui_ImplSDL2_InitForSDLRenderer(), so we can use SDL_GetRendererOutputSize() instead of SDL_GL_GetDrawableSize() when bound to a SDL_Renderer.
|
||||
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
|
||||
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||
// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates.
|
||||
// 2022-01-12: Update mouse inputs using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.
|
||||
// 2022-01-12: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
|
||||
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||
// 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST.
|
||||
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+)
|
||||
// 2021-06-29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950)
|
||||
// 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends.
|
||||
// 2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2).
|
||||
// 2019-12-17: Inputs: On Wayland, use SDL_GetMouseState (because there is no global mouse state).
|
||||
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||
// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
|
||||
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
|
||||
// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
|
||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
|
||||
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
|
||||
// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
|
||||
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
|
||||
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
|
||||
// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
|
||||
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
|
||||
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
|
||||
// SDL
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_syswm.h>
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__)
|
||||
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
|
||||
#else
|
||||
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
|
||||
#endif
|
||||
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
|
||||
|
||||
#define ANALOG_THRESHOLD 20000
|
||||
#define BUTTON_LEFT 0x00000010
|
||||
#define BUTTON_RIGHT 0x00000020
|
||||
#define BUTTON_UP 0x00000040
|
||||
#define BUTTON_DOWN 0x00000080
|
||||
|
||||
static uint32_t previous_down = 0;
|
||||
static int repeat_count = 0;
|
||||
static int repeat_delay = 70;
|
||||
static uint64_t previous_time = 0;
|
||||
|
||||
// Disabled controller buttons
|
||||
bool disabled_buttons[21] = {false, false, false, false, false, false, false, false, false, false,
|
||||
false, false, false, false, false, false, false, false, false, false, false};
|
||||
|
||||
// SDL Data
|
||||
struct ImGui_ImplSDL2_Data
|
||||
{
|
||||
SDL_Window* Window;
|
||||
SDL_Renderer* Renderer;
|
||||
Uint64 Time;
|
||||
int MouseButtonsDown;
|
||||
SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT];
|
||||
int PendingMouseLeaveFrame;
|
||||
char* ClipboardTextData;
|
||||
bool MouseCanUseGlobalState;
|
||||
|
||||
ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
||||
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
|
||||
static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplSDL2_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
|
||||
}
|
||||
|
||||
// Functions
|
||||
static const char* ImGui_ImplSDL2_GetClipboardText(void*)
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
if (bd->ClipboardTextData)
|
||||
SDL_free(bd->ClipboardTextData);
|
||||
bd->ClipboardTextData = SDL_GetClipboardText();
|
||||
return bd->ClipboardTextData;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
|
||||
{
|
||||
SDL_SetClipboardText(text);
|
||||
}
|
||||
|
||||
static ImGuiKey ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode)
|
||||
{
|
||||
switch (keycode)
|
||||
{
|
||||
case SDLK_TAB: return ImGuiKey_Tab;
|
||||
case SDLK_LEFT: return ImGuiKey_LeftArrow;
|
||||
case SDLK_RIGHT: return ImGuiKey_RightArrow;
|
||||
case SDLK_UP: return ImGuiKey_UpArrow;
|
||||
case SDLK_DOWN: return ImGuiKey_DownArrow;
|
||||
case SDLK_PAGEUP: return ImGuiKey_PageUp;
|
||||
case SDLK_PAGEDOWN: return ImGuiKey_PageDown;
|
||||
case SDLK_HOME: return ImGuiKey_Home;
|
||||
case SDLK_END: return ImGuiKey_End;
|
||||
case SDLK_INSERT: return ImGuiKey_Insert;
|
||||
case SDLK_DELETE: return ImGuiKey_Delete;
|
||||
case SDLK_BACKSPACE: return ImGuiKey_Backspace;
|
||||
case SDLK_SPACE: return ImGuiKey_Space;
|
||||
case SDLK_RETURN: return ImGuiKey_Enter;
|
||||
case SDLK_ESCAPE: return ImGuiKey_Escape;
|
||||
case SDLK_QUOTE: return ImGuiKey_Apostrophe;
|
||||
case SDLK_COMMA: return ImGuiKey_Comma;
|
||||
case SDLK_MINUS: return ImGuiKey_Minus;
|
||||
case SDLK_PERIOD: return ImGuiKey_Period;
|
||||
case SDLK_SLASH: return ImGuiKey_Slash;
|
||||
case SDLK_SEMICOLON: return ImGuiKey_Semicolon;
|
||||
case SDLK_EQUALS: return ImGuiKey_Equal;
|
||||
case SDLK_LEFTBRACKET: return ImGuiKey_LeftBracket;
|
||||
case SDLK_BACKSLASH: return ImGuiKey_Backslash;
|
||||
case SDLK_RIGHTBRACKET: return ImGuiKey_RightBracket;
|
||||
case SDLK_BACKQUOTE: return ImGuiKey_GraveAccent;
|
||||
case SDLK_CAPSLOCK: return ImGuiKey_CapsLock;
|
||||
case SDLK_SCROLLLOCK: return ImGuiKey_ScrollLock;
|
||||
case SDLK_NUMLOCKCLEAR: return ImGuiKey_NumLock;
|
||||
case SDLK_PRINTSCREEN: return ImGuiKey_PrintScreen;
|
||||
case SDLK_PAUSE: return ImGuiKey_Pause;
|
||||
case SDLK_KP_0: return ImGuiKey_Keypad0;
|
||||
case SDLK_KP_1: return ImGuiKey_Keypad1;
|
||||
case SDLK_KP_2: return ImGuiKey_Keypad2;
|
||||
case SDLK_KP_3: return ImGuiKey_Keypad3;
|
||||
case SDLK_KP_4: return ImGuiKey_Keypad4;
|
||||
case SDLK_KP_5: return ImGuiKey_Keypad5;
|
||||
case SDLK_KP_6: return ImGuiKey_Keypad6;
|
||||
case SDLK_KP_7: return ImGuiKey_Keypad7;
|
||||
case SDLK_KP_8: return ImGuiKey_Keypad8;
|
||||
case SDLK_KP_9: return ImGuiKey_Keypad9;
|
||||
case SDLK_KP_PERIOD: return ImGuiKey_KeypadDecimal;
|
||||
case SDLK_KP_DIVIDE: return ImGuiKey_KeypadDivide;
|
||||
case SDLK_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
|
||||
case SDLK_KP_MINUS: return ImGuiKey_KeypadSubtract;
|
||||
case SDLK_KP_PLUS: return ImGuiKey_KeypadAdd;
|
||||
case SDLK_KP_ENTER: return ImGuiKey_KeypadEnter;
|
||||
case SDLK_KP_EQUALS: return ImGuiKey_KeypadEqual;
|
||||
case SDLK_LCTRL: return ImGuiKey_LeftCtrl;
|
||||
case SDLK_LSHIFT: return ImGuiKey_LeftShift;
|
||||
case SDLK_LALT: return ImGuiKey_LeftAlt;
|
||||
case SDLK_LGUI: return ImGuiKey_LeftSuper;
|
||||
case SDLK_RCTRL: return ImGuiKey_RightCtrl;
|
||||
case SDLK_RSHIFT: return ImGuiKey_RightShift;
|
||||
case SDLK_RALT: return ImGuiKey_RightAlt;
|
||||
case SDLK_RGUI: return ImGuiKey_RightSuper;
|
||||
case SDLK_APPLICATION: return ImGuiKey_Menu;
|
||||
case SDLK_0: return ImGuiKey_0;
|
||||
case SDLK_1: return ImGuiKey_1;
|
||||
case SDLK_2: return ImGuiKey_2;
|
||||
case SDLK_3: return ImGuiKey_3;
|
||||
case SDLK_4: return ImGuiKey_4;
|
||||
case SDLK_5: return ImGuiKey_5;
|
||||
case SDLK_6: return ImGuiKey_6;
|
||||
case SDLK_7: return ImGuiKey_7;
|
||||
case SDLK_8: return ImGuiKey_8;
|
||||
case SDLK_9: return ImGuiKey_9;
|
||||
case SDLK_a: return ImGuiKey_A;
|
||||
case SDLK_b: return ImGuiKey_B;
|
||||
case SDLK_c: return ImGuiKey_C;
|
||||
case SDLK_d: return ImGuiKey_D;
|
||||
case SDLK_e: return ImGuiKey_E;
|
||||
case SDLK_f: return ImGuiKey_F;
|
||||
case SDLK_g: return ImGuiKey_G;
|
||||
case SDLK_h: return ImGuiKey_H;
|
||||
case SDLK_i: return ImGuiKey_I;
|
||||
case SDLK_j: return ImGuiKey_J;
|
||||
case SDLK_k: return ImGuiKey_K;
|
||||
case SDLK_l: return ImGuiKey_L;
|
||||
case SDLK_m: return ImGuiKey_M;
|
||||
case SDLK_n: return ImGuiKey_N;
|
||||
case SDLK_o: return ImGuiKey_O;
|
||||
case SDLK_p: return ImGuiKey_P;
|
||||
case SDLK_q: return ImGuiKey_Q;
|
||||
case SDLK_r: return ImGuiKey_R;
|
||||
case SDLK_s: return ImGuiKey_S;
|
||||
case SDLK_t: return ImGuiKey_T;
|
||||
case SDLK_u: return ImGuiKey_U;
|
||||
case SDLK_v: return ImGuiKey_V;
|
||||
case SDLK_w: return ImGuiKey_W;
|
||||
case SDLK_x: return ImGuiKey_X;
|
||||
case SDLK_y: return ImGuiKey_Y;
|
||||
case SDLK_z: return ImGuiKey_Z;
|
||||
case SDLK_F1: return ImGuiKey_F1;
|
||||
case SDLK_F2: return ImGuiKey_F2;
|
||||
case SDLK_F3: return ImGuiKey_F3;
|
||||
case SDLK_F4: return ImGuiKey_F4;
|
||||
case SDLK_F5: return ImGuiKey_F5;
|
||||
case SDLK_F6: return ImGuiKey_F6;
|
||||
case SDLK_F7: return ImGuiKey_F7;
|
||||
case SDLK_F8: return ImGuiKey_F8;
|
||||
case SDLK_F9: return ImGuiKey_F9;
|
||||
case SDLK_F10: return ImGuiKey_F10;
|
||||
case SDLK_F11: return ImGuiKey_F11;
|
||||
case SDLK_F12: return ImGuiKey_F12;
|
||||
}
|
||||
return ImGuiKey_None;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddKeyEvent(ImGuiMod_Ctrl, (sdl_key_mods & KMOD_CTRL) != 0);
|
||||
io.AddKeyEvent(ImGuiMod_Shift, (sdl_key_mods & KMOD_SHIFT) != 0);
|
||||
io.AddKeyEvent(ImGuiMod_Alt, (sdl_key_mods & KMOD_ALT) != 0);
|
||||
io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & KMOD_GUI) != 0);
|
||||
}
|
||||
|
||||
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
|
||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
|
||||
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case SDL_MOUSEMOTION:
|
||||
{
|
||||
io.AddMousePosEvent((float)event->motion.x, (float)event->motion.y);
|
||||
return true;
|
||||
}
|
||||
case SDL_MOUSEWHEEL:
|
||||
{
|
||||
float wheel_x = (event->wheel.x > 0) ? 1.0f : (event->wheel.x < 0) ? -1.0f : 0.0f;
|
||||
float wheel_y = (event->wheel.y > 0) ? 1.0f : (event->wheel.y < 0) ? -1.0f : 0.0f;
|
||||
io.AddMouseWheelEvent(wheel_x, wheel_y);
|
||||
return true;
|
||||
}
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
{
|
||||
int mouse_button = -1;
|
||||
if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; }
|
||||
if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; }
|
||||
if (event->button.button == SDL_BUTTON_MIDDLE) { mouse_button = 2; }
|
||||
if (event->button.button == SDL_BUTTON_X1) { mouse_button = 3; }
|
||||
if (event->button.button == SDL_BUTTON_X2) { mouse_button = 4; }
|
||||
if (mouse_button == -1)
|
||||
break;
|
||||
io.AddMouseButtonEvent(mouse_button, (event->type == SDL_MOUSEBUTTONDOWN));
|
||||
bd->MouseButtonsDown = (event->type == SDL_MOUSEBUTTONDOWN) ? (bd->MouseButtonsDown | (1 << mouse_button)) : (bd->MouseButtonsDown & ~(1 << mouse_button));
|
||||
return true;
|
||||
}
|
||||
case SDL_TEXTINPUT:
|
||||
{
|
||||
io.AddInputCharactersUTF8(event->text.text);
|
||||
return true;
|
||||
}
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
{
|
||||
ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod);
|
||||
ImGuiKey key = ImGui_ImplSDL2_KeycodeToImGuiKey(event->key.keysym.sym);
|
||||
io.AddKeyEvent(key, (event->type == SDL_KEYDOWN));
|
||||
io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
|
||||
return true;
|
||||
}
|
||||
case SDL_WINDOWEVENT:
|
||||
{
|
||||
// - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right.
|
||||
// - However we won't get a correct LEAVE event for a captured window.
|
||||
// - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late,
|
||||
// causing SDL_WINDOWEVENT_LEAVE on previous frame to interrupt drag operation by clear mouse position. This is why
|
||||
// we delay process the SDL_WINDOWEVENT_LEAVE events by one frame. See issue #5012 for details.
|
||||
Uint8 window_event = event->window.event;
|
||||
if (window_event == SDL_WINDOWEVENT_ENTER)
|
||||
bd->PendingMouseLeaveFrame = 0;
|
||||
if (window_event == SDL_WINDOWEVENT_LEAVE)
|
||||
bd->PendingMouseLeaveFrame = ImGui::GetFrameCount() + 1;
|
||||
if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||
io.AddFocusEvent(true);
|
||||
else if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST)
|
||||
io.AddFocusEvent(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ImGui_ImplSDL2_DisableButton(int button , bool disabled)
|
||||
{
|
||||
if (button < 0 || button > 15)
|
||||
return;
|
||||
disabled_buttons[button] = disabled;
|
||||
}
|
||||
|
||||
|
||||
static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
|
||||
|
||||
// Check and store if we are on a SDL backend that supports global mouse position
|
||||
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
|
||||
bool mouse_can_use_global_state = false;
|
||||
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||
const char* sdl_backend = SDL_GetCurrentVideoDriver();
|
||||
const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
|
||||
for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++)
|
||||
if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0)
|
||||
mouse_can_use_global_state = true;
|
||||
#endif
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)();
|
||||
io.BackendPlatformUserData = (void*)bd;
|
||||
io.BackendPlatformName = "imgui_impl_sdl";
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
|
||||
bd->Window = window;
|
||||
bd->Renderer = renderer;
|
||||
bd->MouseCanUseGlobalState = mouse_can_use_global_state;
|
||||
|
||||
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
|
||||
io.ClipboardUserData = NULL;
|
||||
|
||||
// Load mouse cursors
|
||||
bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
|
||||
bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
|
||||
bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
||||
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
|
||||
|
||||
// Set platform dependent data in viewport
|
||||
#ifdef _WIN32
|
||||
SDL_SysWMinfo info;
|
||||
SDL_VERSION(&info.version);
|
||||
if (SDL_GetWindowWMInfo(window, &info))
|
||||
ImGui::GetMainViewport()->PlatformHandleRaw = (void*)info.info.win.window;
|
||||
#else
|
||||
(void)window;
|
||||
#endif
|
||||
|
||||
// From 2.0.5: Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
|
||||
// Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
|
||||
// (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
|
||||
// It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
|
||||
// you can ignore SDL_MOUSEBUTTONDOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||
#ifdef SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH
|
||||
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||
#endif
|
||||
|
||||
// From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
|
||||
#ifdef SDL_HINT_MOUSE_AUTO_CAPTURE
|
||||
SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
|
||||
{
|
||||
IM_UNUSED(sdl_gl_context); // Viewport branch will need this.
|
||||
return ImGui_ImplSDL2_Init(window, NULL);
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
|
||||
{
|
||||
#if !SDL_HAS_VULKAN
|
||||
IM_ASSERT(0 && "Unsupported");
|
||||
#endif
|
||||
return ImGui_ImplSDL2_Init(window, NULL);
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
|
||||
{
|
||||
#if !defined(_WIN32)
|
||||
IM_ASSERT(0 && "Unsupported");
|
||||
#endif
|
||||
return ImGui_ImplSDL2_Init(window, NULL);
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
|
||||
{
|
||||
return ImGui_ImplSDL2_Init(window, NULL);
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer)
|
||||
{
|
||||
return ImGui_ImplSDL2_Init(window, renderer);
|
||||
}
|
||||
|
||||
void ImGui_ImplSDL2_Shutdown()
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
if (bd->ClipboardTextData)
|
||||
SDL_free(bd->ClipboardTextData);
|
||||
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||
SDL_FreeCursor(bd->MouseCursors[cursor_n]);
|
||||
|
||||
io.BackendPlatformName = NULL;
|
||||
io.BackendPlatformUserData = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_UpdateMouseData()
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below)
|
||||
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside
|
||||
SDL_CaptureMouse((bd->MouseButtonsDown != 0 && ImGui::GetDragDropPayload() == NULL) ? SDL_TRUE : SDL_FALSE);
|
||||
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
||||
const bool is_app_focused = (bd->Window == focused_window);
|
||||
#else
|
||||
const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only
|
||||
#endif
|
||||
if (is_app_focused)
|
||||
{
|
||||
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||
if (io.WantSetMousePos)
|
||||
SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y);
|
||||
|
||||
// (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured)
|
||||
if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0)
|
||||
{
|
||||
int window_x, window_y, mouse_x_global, mouse_y_global;
|
||||
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
|
||||
SDL_GetWindowPosition(bd->Window, &window_x, &window_y);
|
||||
io.AddMousePosEvent((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_UpdateMouseCursor()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||
return;
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
SDL_ShowCursor(SDL_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show OS mouse cursor
|
||||
SDL_SetCursor(bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||
SDL_ShowCursor(SDL_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_UpdateGamepads()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
|
||||
return;
|
||||
|
||||
// Get gamepad
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||
SDL_GameController* game_controller = SDL_GameControllerOpen(0);
|
||||
if (!game_controller)
|
||||
return;
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
uint64_t current_time = SDL_GetTicks64();
|
||||
|
||||
// Simulate analog left stick as d-pad
|
||||
uint32_t down = 0;
|
||||
if (SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_LEFTX) < -ANALOG_THRESHOLD)
|
||||
down |= BUTTON_LEFT;
|
||||
else if (SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_LEFTX) > ANALOG_THRESHOLD)
|
||||
down |= BUTTON_RIGHT;
|
||||
else if (SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_LEFTY) > ANALOG_THRESHOLD)
|
||||
down |= BUTTON_DOWN;
|
||||
else if (SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_LEFTY) < -ANALOG_THRESHOLD)
|
||||
down |= BUTTON_UP;
|
||||
|
||||
uint32_t pressed = down & ~previous_down;
|
||||
if (previous_down == down)
|
||||
{
|
||||
uint64_t delay = 300;
|
||||
if (repeat_count > 0)
|
||||
delay = repeat_delay;
|
||||
if (current_time - previous_time > delay)
|
||||
{
|
||||
pressed = down;
|
||||
previous_time = current_time;
|
||||
repeat_count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_time = current_time;
|
||||
repeat_count = 0;
|
||||
}
|
||||
|
||||
if (pressed & BUTTON_LEFT)
|
||||
io.AddKeyEvent(ImGuiKey_GamepadDpadLeft, true);
|
||||
if (pressed & BUTTON_RIGHT)
|
||||
io.AddKeyEvent(ImGuiKey_GamepadDpadRight, true);
|
||||
if (pressed & BUTTON_UP)
|
||||
io.AddKeyEvent(ImGuiKey_GamepadDpadUp, true);
|
||||
if (pressed & BUTTON_DOWN)
|
||||
io.AddKeyEvent(ImGuiKey_GamepadDpadDown, true);
|
||||
previous_down = down;
|
||||
|
||||
// Update gamepad inputs
|
||||
#define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
|
||||
#define MAP_BUTTON(KEY_NO, BUTTON_NO) { if (!disabled_buttons[BUTTON_NO]) io.AddKeyEvent(KEY_NO, SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0); }
|
||||
#define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); }
|
||||
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
|
||||
MAP_BUTTON(ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START);
|
||||
MAP_BUTTON(ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK);
|
||||
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square
|
||||
MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle
|
||||
MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle
|
||||
MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross
|
||||
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT);
|
||||
MAP_BUTTON(ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
|
||||
MAP_BUTTON(ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP);
|
||||
MAP_BUTTON(ImGuiKey_GamepadDpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
|
||||
MAP_BUTTON(ImGuiKey_GamepadL1, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
|
||||
MAP_BUTTON(ImGuiKey_GamepadR1, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
|
||||
MAP_ANALOG(ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767);
|
||||
MAP_ANALOG(ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767);
|
||||
MAP_BUTTON(ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK);
|
||||
MAP_BUTTON(ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK);
|
||||
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768);
|
||||
MAP_ANALOG(ImGuiKey_GamepadLStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767);
|
||||
MAP_ANALOG(ImGuiKey_GamepadLStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32768);
|
||||
MAP_ANALOG(ImGuiKey_GamepadLStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767);
|
||||
#undef MAP_BUTTON
|
||||
#undef MAP_ANALOG
|
||||
}
|
||||
|
||||
void ImGui_ImplSDL2_NewFrame()
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplSDL2_Init()?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
SDL_GetWindowSize(bd->Window, &w, &h);
|
||||
if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED)
|
||||
w = h = 0;
|
||||
if (bd->Renderer != NULL)
|
||||
SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h);
|
||||
else
|
||||
SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h);
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
if (w > 0 && h > 0)
|
||||
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||
|
||||
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
|
||||
static Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||
Uint64 current_time = SDL_GetPerformanceCounter();
|
||||
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
|
||||
bd->Time = current_time;
|
||||
|
||||
if (bd->PendingMouseLeaveFrame && bd->PendingMouseLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0)
|
||||
{
|
||||
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
|
||||
bd->PendingMouseLeaveFrame = 0;
|
||||
}
|
||||
|
||||
ImGui_ImplSDL2_UpdateMouseData();
|
||||
ImGui_ImplSDL2_UpdateMouseCursor();
|
||||
|
||||
// Update game controllers (if enabled and available)
|
||||
ImGui_ImplSDL2_UpdateGamepads();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// dear imgui: Platform Backend for SDL2
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// Missing features:
|
||||
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct SDL_Window;
|
||||
struct SDL_Renderer;
|
||||
typedef union SDL_Event SDL_Event;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_DisableButton(int button , bool disabled);
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter
|
||||
#endif
|
||||
@@ -0,0 +1,252 @@
|
||||
// dear imgui: Renderer Backend for SDL_Renderer
|
||||
// (Requires: SDL 2.0.17+)
|
||||
|
||||
// Important to understand: SDL_Renderer is an _optional_ component of SDL.
|
||||
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
|
||||
// If your application will want to render any non trivial amount of graphics other than UI,
|
||||
// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might
|
||||
// be difficult to step out of those boundaries.
|
||||
// However, we understand it is a convenient choice to get an app started easily.
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
// Missing features:
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// 2021-12-21: Update SDL_RenderGeometryRaw() format to work with SDL 2.0.19.
|
||||
// 2021-12-03: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2021-10-06: Backup and restore modified ClipRect/Viewport.
|
||||
// 2021-09-21: Initial version.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_sdlrenderer.h"
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||
#include <stddef.h> // intptr_t
|
||||
#else
|
||||
#include <stdint.h> // intptr_t
|
||||
#endif
|
||||
|
||||
// SDL
|
||||
#include <SDL2/SDL.h>
|
||||
#if !SDL_VERSION_ATLEAST(2,0,17)
|
||||
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
|
||||
#endif
|
||||
|
||||
// SDL_Renderer data
|
||||
struct ImGui_ImplSDLRenderer_Data
|
||||
{
|
||||
SDL_Renderer* SDLRenderer;
|
||||
SDL_Texture* FontTexture;
|
||||
ImGui_ImplSDLRenderer_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplSDLRenderer_Data* ImGui_ImplSDLRenderer_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||
}
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplSDLRenderer_Init(SDL_Renderer* renderer)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||
IM_ASSERT(renderer != NULL && "SDL_Renderer not initialized!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplSDLRenderer_Data* bd = IM_NEW(ImGui_ImplSDLRenderer_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_sdlrenderer";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
|
||||
bd->SDLRenderer = renderer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer_Shutdown()
|
||||
{
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplSDLRenderer_DestroyDeviceObjects();
|
||||
|
||||
io.BackendRendererName = NULL;
|
||||
io.BackendRendererUserData = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDLRenderer_SetupRenderState()
|
||||
{
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
|
||||
// Clear out any viewports and cliprect set by the user
|
||||
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
|
||||
SDL_RenderSetViewport(bd->SDLRenderer, NULL);
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, NULL);
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer_NewFrame()
|
||||
{
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplSDLRenderer_Init()?");
|
||||
|
||||
if (!bd->FontTexture)
|
||||
ImGui_ImplSDLRenderer_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
|
||||
// If there's a scale factor set by the user, use that instead
|
||||
// If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
|
||||
// to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
|
||||
float rsx = 1.0f;
|
||||
float rsy = 1.0f;
|
||||
SDL_RenderGetScale(bd->SDLRenderer, &rsx, &rsy);
|
||||
ImVec2 render_scale;
|
||||
render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
|
||||
render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;
|
||||
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y);
|
||||
if (fb_width == 0 || fb_height == 0)
|
||||
return;
|
||||
|
||||
// Backup SDL_Renderer state that will be modified to restore it afterwards
|
||||
struct BackupSDLRendererState
|
||||
{
|
||||
SDL_Rect Viewport;
|
||||
bool ClipEnabled;
|
||||
SDL_Rect ClipRect;
|
||||
};
|
||||
BackupSDLRendererState old = {};
|
||||
old.ClipEnabled = SDL_RenderIsClipEnabled(bd->SDLRenderer) == SDL_TRUE;
|
||||
SDL_RenderGetViewport(bd->SDLRenderer, &old.Viewport);
|
||||
SDL_RenderGetClipRect(bd->SDLRenderer, &old.ClipRect);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = render_scale;
|
||||
|
||||
// Render command lists
|
||||
ImGui_ImplSDLRenderer_SetupRenderState();
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
|
||||
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplSDLRenderer_SetupRenderState();
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
|
||||
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
|
||||
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
|
||||
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
|
||||
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||
continue;
|
||||
|
||||
SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, &r);
|
||||
|
||||
const float* xy = (const float*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, pos));
|
||||
const float* uv = (const float*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, uv));
|
||||
#if SDL_VERSION_ATLEAST(2,0,19)
|
||||
const SDL_Color* color = (const SDL_Color*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.19+
|
||||
#else
|
||||
const int* color = (const int*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.17 and 2.0.18
|
||||
#endif
|
||||
|
||||
// Bind texture, Draw
|
||||
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
|
||||
SDL_RenderGeometryRaw(bd->SDLRenderer, tex,
|
||||
xy, (int)sizeof(ImDrawVert),
|
||||
color, (int)sizeof(ImDrawVert),
|
||||
uv, (int)sizeof(ImDrawVert),
|
||||
cmd_list->VtxBuffer.Size - pcmd->VtxOffset,
|
||||
idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore modified SDL_Renderer state
|
||||
SDL_RenderSetViewport(bd->SDLRenderer, &old.Viewport);
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, old.ClipEnabled ? &old.ClipRect : NULL);
|
||||
}
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
bool ImGui_ImplSDLRenderer_CreateFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
|
||||
// Build texture atlas
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom((void*) pixels, width, height, 32, 4 * width, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
|
||||
bd->FontTexture = SDL_CreateTextureFromSurface(bd->SDLRenderer, surface);
|
||||
if (bd->FontTexture == NULL)
|
||||
{
|
||||
SDL_Log("error creating texture");
|
||||
return false;
|
||||
}
|
||||
SDL_UpdateTexture(bd->FontTexture, NULL, pixels, 4 * width);
|
||||
SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureScaleMode(bd->FontTexture, SDL_ScaleModeLinear);
|
||||
SDL_FreeSurface(surface);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
if (bd->FontTexture)
|
||||
{
|
||||
io.Fonts->SetTexID(0);
|
||||
SDL_DestroyTexture(bd->FontTexture);
|
||||
bd->FontTexture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDLRenderer_CreateDeviceObjects()
|
||||
{
|
||||
return ImGui_ImplSDLRenderer_CreateFontsTexture();
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplSDLRenderer_DestroyFontsTexture();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// dear imgui: Renderer Backend for SDL_Renderer
|
||||
// (Requires: SDL 2.0.17+)
|
||||
|
||||
// Important to understand: SDL_Renderer is an _optional_ component of SDL.
|
||||
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
|
||||
// If your application will want to render any non trivial amount of graphics other than UI,
|
||||
// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might
|
||||
// be difficult to step out of those boundaries.
|
||||
// However, we understand it is a convenient choice to get an app started easily.
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct SDL_Renderer;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_Init(SDL_Renderer* renderer);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_DestroyDeviceObjects();
|
||||
@@ -0,0 +1,627 @@
|
||||
// [DEAR IMGUI]
|
||||
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
//
|
||||
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Before #including,
|
||||
//
|
||||
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||
//
|
||||
// in the file that you want to have the implementation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
//
|
||||
// Has only had a few tests run, may have issues.
|
||||
//
|
||||
// More docs to come.
|
||||
//
|
||||
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||
//
|
||||
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||
//
|
||||
// Please note: better rectangle packers are welcome! Please
|
||||
// implement them to the same API, but with a different init
|
||||
// function.
|
||||
//
|
||||
// Credits
|
||||
//
|
||||
// Library
|
||||
// Sean Barrett
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
// Fabian Giesen
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||
// 0.99 (2019-02-07) warning fixes
|
||||
// 0.11 (2017-03-03) return packing success/fail result
|
||||
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||
// 0.09 (2016-08-27) fix compiler warnings
|
||||
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||
// 0.01: initial release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDE SECTION
|
||||
//
|
||||
|
||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||
|
||||
#define STB_RECT_PACK_VERSION 1
|
||||
|
||||
#ifdef STBRP_STATIC
|
||||
#define STBRP_DEF static
|
||||
#else
|
||||
#define STBRP_DEF extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
typedef int stbrp_coord;
|
||||
|
||||
#define STBRP__MAXVAL 0x7fffffff
|
||||
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||
// are 'num_rects' many of them.
|
||||
//
|
||||
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||
// have the 'was_packed' flag set to 0.
|
||||
//
|
||||
// You should not try to access the 'rects' array from another thread
|
||||
// while this function is running, as the function temporarily reorders
|
||||
// the array while it executes.
|
||||
//
|
||||
// To pack into another rectangle, you need to call stbrp_init_target
|
||||
// again. To continue packing into the same rectangle, you can call
|
||||
// this function again. Calling this multiple times with multiple rect
|
||||
// arrays will probably produce worse packing results than calling it
|
||||
// a single time with the full rectangle array, but the option is
|
||||
// available.
|
||||
//
|
||||
// The function returns 1 if all of the rectangles were successfully
|
||||
// packed and 0 otherwise.
|
||||
|
||||
struct stbrp_rect
|
||||
{
|
||||
// reserved for your use:
|
||||
int id;
|
||||
|
||||
// input:
|
||||
stbrp_coord w, h;
|
||||
|
||||
// output:
|
||||
stbrp_coord x, y;
|
||||
int was_packed; // non-zero if valid packing
|
||||
|
||||
}; // 16 bytes, nominally
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||
// Initialize a rectangle packer to:
|
||||
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||
//
|
||||
// You must call this function every time you start packing into a new target.
|
||||
//
|
||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||
// the call (or calls) finish.
|
||||
//
|
||||
// Note: to guarantee best results, either:
|
||||
// 1. make sure 'num_nodes' >= 'width'
|
||||
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||
//
|
||||
// If you don't do either of the above things, widths will be quantized to multiples
|
||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||
//
|
||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||
// may run out of temporary storage and be unable to pack some rectangles.
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||
// Optionally call this function after init but before doing any packing to
|
||||
// change the handling of the out-of-temp-memory scenario, described above.
|
||||
// If you call init again, this will be reset to the default (false).
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||
// Optionally select which packing heuristic the library should use. Different
|
||||
// heuristics will produce better/worse results for different data sets.
|
||||
// If you call init again, this will be reset to the default.
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// the details of the following structures don't matter to you, but they must
|
||||
// be visible so you can handle the memory allocations for them
|
||||
|
||||
struct stbrp_node
|
||||
{
|
||||
stbrp_coord x,y;
|
||||
stbrp_node *next;
|
||||
};
|
||||
|
||||
struct stbrp_context
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int align;
|
||||
int init_mode;
|
||||
int heuristic;
|
||||
int num_nodes;
|
||||
stbrp_node *active_head;
|
||||
stbrp_node *free_head;
|
||||
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION SECTION
|
||||
//
|
||||
|
||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||
#ifndef STBRP_SORT
|
||||
#include <stdlib.h>
|
||||
#define STBRP_SORT qsort
|
||||
#endif
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
{
|
||||
switch (context->init_mode) {
|
||||
case STBRP__INIT_skyline:
|
||||
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||
context->heuristic = heuristic;
|
||||
break;
|
||||
default:
|
||||
STBRP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||
{
|
||||
if (allow_out_of_mem)
|
||||
// if it's ok to run out of memory, then don't bother aligning them;
|
||||
// this gives better packing, but may fail due to OOM (even though
|
||||
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||
context->align = 1;
|
||||
else {
|
||||
// if it's not ok to run out of memory, then quantize the widths
|
||||
// so that num_nodes is always enough nodes.
|
||||
//
|
||||
// I.e. num_nodes * align >= width
|
||||
// align >= width / num_nodes
|
||||
// align = ceil(width/num_nodes)
|
||||
|
||||
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
nodes[i].next = NULL;
|
||||
context->init_mode = STBRP__INIT_skyline;
|
||||
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||
context->free_head = &nodes[0];
|
||||
context->active_head = &context->extra[0];
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->num_nodes = num_nodes;
|
||||
stbrp_setup_allow_out_of_mem(context, 0);
|
||||
|
||||
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||
context->extra[0].x = 0;
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
context->extra[1].y = (1<<30);
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
// find minimum y position if it starts at x1
|
||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||
{
|
||||
stbrp_node *node = first;
|
||||
int x1 = x0 + width;
|
||||
int min_y, visited_width, waste_area;
|
||||
|
||||
STBRP__NOTUSED(c);
|
||||
|
||||
STBRP_ASSERT(first->x <= x0);
|
||||
|
||||
#if 0
|
||||
// skip in case we're past the node
|
||||
while (node->next->x <= x0)
|
||||
++node;
|
||||
#else
|
||||
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||
#endif
|
||||
|
||||
STBRP_ASSERT(node->x <= x0);
|
||||
|
||||
min_y = 0;
|
||||
waste_area = 0;
|
||||
visited_width = 0;
|
||||
while (node->x < x1) {
|
||||
if (node->y > min_y) {
|
||||
// raise min_y higher.
|
||||
// we've accounted for all waste up to min_y,
|
||||
// but we'll now add more waste for everything we've visted
|
||||
waste_area += visited_width * (node->y - min_y);
|
||||
min_y = node->y;
|
||||
// the first time through, visited_width might be reduced
|
||||
if (node->x < x0)
|
||||
visited_width += node->next->x - x0;
|
||||
else
|
||||
visited_width += node->next->x - node->x;
|
||||
} else {
|
||||
// add waste area
|
||||
int under_width = node->next->x - node->x;
|
||||
if (under_width + visited_width > width)
|
||||
under_width = width - visited_width;
|
||||
waste_area += under_width * (min_y - node->y);
|
||||
visited_width += under_width;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
*pwaste = waste_area;
|
||||
return min_y;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,y;
|
||||
stbrp_node **prev_link;
|
||||
} stbrp__findresult;
|
||||
|
||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||
{
|
||||
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||
stbrp__findresult fr;
|
||||
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||
|
||||
// align to multiple of c->align
|
||||
width = (width + c->align - 1);
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
// if it can't possibly fit, bail immediately
|
||||
if (width > c->width || height > c->height) {
|
||||
fr.prev_link = NULL;
|
||||
fr.x = fr.y = 0;
|
||||
return fr;
|
||||
}
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
int y,waste;
|
||||
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||
// bottom left
|
||||
if (y < best_y) {
|
||||
best_y = y;
|
||||
best = prev;
|
||||
}
|
||||
} else {
|
||||
// best-fit
|
||||
if (y + height <= c->height) {
|
||||
// can only use it if it first vertically
|
||||
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||
|
||||
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||
//
|
||||
// e.g, if fitting
|
||||
//
|
||||
// ____________________
|
||||
// |____________________|
|
||||
//
|
||||
// into
|
||||
//
|
||||
// | |
|
||||
// | ____________|
|
||||
// |____________|
|
||||
//
|
||||
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||
//
|
||||
// This makes BF take about 2x the time
|
||||
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||
tail = c->active_head;
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
// find first node that's admissible
|
||||
while (tail->x < width)
|
||||
tail = tail->next;
|
||||
while (tail) {
|
||||
int xpos = tail->x - width;
|
||||
int y,waste;
|
||||
STBRP_ASSERT(xpos >= 0);
|
||||
// find the left position that matches this
|
||||
while (node->next->x <= xpos) {
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height <= c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
fr.x = best_x;
|
||||
fr.y = best_y;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||
{
|
||||
// find best position according to heuristic
|
||||
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||
stbrp_node *node, *cur;
|
||||
|
||||
// bail if:
|
||||
// 1. it failed
|
||||
// 2. the best node doesn't fit (we don't always check this)
|
||||
// 3. we're out of memory
|
||||
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||
res.prev_link = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
// on success, create new node
|
||||
node = context->free_head;
|
||||
node->x = (stbrp_coord) res.x;
|
||||
node->y = (stbrp_coord) (res.y + height);
|
||||
|
||||
context->free_head = node->next;
|
||||
|
||||
// insert the new node into the right starting point, and
|
||||
// let 'cur' point to the remaining nodes needing to be
|
||||
// stiched back in
|
||||
|
||||
cur = *res.prev_link;
|
||||
if (cur->x < res.x) {
|
||||
// preserve the existing one, so start testing with the next one
|
||||
stbrp_node *next = cur->next;
|
||||
cur->next = node;
|
||||
cur = next;
|
||||
} else {
|
||||
*res.prev_link = node;
|
||||
}
|
||||
|
||||
// from here, traverse cur and free the nodes, until we get to one
|
||||
// that shouldn't be freed
|
||||
while (cur->next && cur->next->x <= res.x + width) {
|
||||
stbrp_node *next = cur->next;
|
||||
// move the current node to the free list
|
||||
cur->next = context->free_head;
|
||||
context->free_head = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
// stitch the list back in
|
||||
node->next = cur;
|
||||
|
||||
if (cur->x < res.x + width)
|
||||
cur->x = (stbrp_coord) (res.x + width);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cur = context->active_head;
|
||||
while (cur->x < context->width) {
|
||||
STBRP_ASSERT(cur->x < cur->next->x);
|
||||
cur = cur->next;
|
||||
}
|
||||
STBRP_ASSERT(cur->next == NULL);
|
||||
|
||||
{
|
||||
int count=0;
|
||||
cur = context->active_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
cur = context->free_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
STBRP_ASSERT(count == context->num_nodes+2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
return 1;
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = i;
|
||||
}
|
||||
|
||||
// sort according to heuristic
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||
} else {
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsort
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||
|
||||
// set was_packed flags and all_rects_packed status
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||
if (!rects[i].was_packed)
|
||||
all_rects_packed = 0;
|
||||
}
|
||||
|
||||
// return the all_rects_packed status
|
||||
return all_rects_packed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -0,0 +1,686 @@
|
||||
/************************************************************************
|
||||
Filename : IniFile.C
|
||||
Version : 0.51
|
||||
Author(s) : Carsten Breuer
|
||||
--[ Description ]-------------------------------------------------------
|
||||
|
||||
This file contains a complete interface to read and write ini files
|
||||
like windows do it. It's also avaiable as a C++ class.
|
||||
|
||||
--[ History ] ----------------------------------------------------------
|
||||
|
||||
0.10: Original file by Carsten Breuer. First beta version.
|
||||
0.20: Some bugs resolved and some suggestions from
|
||||
jim hall (freedos.org) implemented.
|
||||
0.30: Some stuff for unix added. They dont know strupr.
|
||||
Thanks to Dieter Engelbrecht (dieter@wintop.net).
|
||||
0.40: Bug at WriteString fixed.
|
||||
0.50: Problem with file pointer solved
|
||||
0.51: We better do smaller steps now. I have reformated to tab4. Sorry
|
||||
New function DeletepKey added. Thanks for the guy who post this.
|
||||
|
||||
--[ How to compile ]----------------------------------------------------
|
||||
|
||||
This file was developed under DJGPP and Rhide. If you are familiar with
|
||||
Borland C++ 3.1, you will feel like at home ;-)).
|
||||
Both tools are free software.
|
||||
|
||||
Downloads at: http://www.delorie.com/djgpp
|
||||
|
||||
|
||||
--[ Where to get help/information ]-------------------------------------
|
||||
|
||||
The author : C.Breuer@OpenWin.de
|
||||
|
||||
--[ License ] ----------------------------------------------------------
|
||||
|
||||
LGPL (Free for private and comercial use)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
Copyright (c) 2000 Carsten Breuer
|
||||
/************************************************************************/
|
||||
|
||||
/* defines for, or consts and inline functions for C++ */
|
||||
|
||||
/* global includes */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* local includes */
|
||||
#include "inifile.h"
|
||||
|
||||
/* Global Variables */
|
||||
|
||||
struct ENTRY *Entry = NULL;
|
||||
struct ENTRY *CurEntry = NULL;
|
||||
char Result[4096] =
|
||||
{""};
|
||||
FILE *IniFile;
|
||||
|
||||
/* Private functions declarations */
|
||||
void AddpKey(struct ENTRY *Entry, cchr *pKey, cchr *Value);
|
||||
void FreeMem(void *Ptr);
|
||||
void FreeAllMem(void);
|
||||
bool FindpKey(cchr *Section, cchr *pKey, EFIND *List);
|
||||
bool AddSectionAndpKey(cchr *Section, cchr *pKey, cchr *Value);
|
||||
struct ENTRY *MakeNewEntry(void);
|
||||
|
||||
/*=========================================================================
|
||||
strupr -de-
|
||||
-------------------------------------------------------------------------
|
||||
Job : String to Uppercase 22.03.2001 Dieter Engelbrecht dieter@wintop.net
|
||||
/*========================================================================*/
|
||||
#ifdef DONT_HAVE_STRUPR
|
||||
/* DONT_HAVE_STRUPR is set when INI_REMOVE_CR is defined */
|
||||
void strupr(char *str)
|
||||
{
|
||||
// We dont check the ptr because the original also dont do it.
|
||||
while (*str != 0)
|
||||
{
|
||||
if (islower(*str))
|
||||
{
|
||||
*str = toupper(*str);
|
||||
}
|
||||
str++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*=========================================================================
|
||||
OpenIniFile
|
||||
-------------------------------------------------------------------------
|
||||
Job : Opens an ini file or creates a new one if the requested file
|
||||
doesnt exists.
|
||||
|
||||
Att : Be sure to call CloseIniFile to free all mem allocated during
|
||||
operation!
|
||||
/*========================================================================*/
|
||||
bool OpenIniFile(cchr *FileName)
|
||||
{
|
||||
char Str[5120];
|
||||
char *pStr;
|
||||
struct ENTRY *pEntry;
|
||||
|
||||
FreeAllMem();
|
||||
|
||||
if (FileName == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if ((IniFile = fopen(FileName, "r")) == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (fgets(Str, 5120, IniFile) != NULL)
|
||||
{
|
||||
pStr = strchr(Str, '\n');
|
||||
if (pStr != NULL)
|
||||
{
|
||||
*pStr = 0;
|
||||
}
|
||||
pEntry = MakeNewEntry();
|
||||
if (pEntry == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef INI_REMOVE_CR
|
||||
Len = strlen(Str);
|
||||
if (Len > 0)
|
||||
{
|
||||
if (Str[Len - 1] == '\r')
|
||||
{
|
||||
Str[Len - 1] = '\0';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
pEntry->Text = (char *)malloc(strlen(Str) + 1);
|
||||
if (pEntry->Text == NULL)
|
||||
{
|
||||
FreeAllMem();
|
||||
return FALSE;
|
||||
}
|
||||
strcpy(pEntry->Text, Str);
|
||||
pStr = strchr(Str, ';');
|
||||
if (pStr != NULL)
|
||||
{
|
||||
*pStr = 0;
|
||||
} /* Cut all comments */
|
||||
if ((strstr(Str, "[") > 0) && (strstr(Str, "]") > 0)) /* Is Section */
|
||||
{
|
||||
pEntry->Type = tpSECTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strstr(Str, "=") > 0)
|
||||
{
|
||||
pEntry->Type = tpKEYVALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pEntry->Type = tpCOMMENT;
|
||||
}
|
||||
}
|
||||
CurEntry = pEntry;
|
||||
}
|
||||
fclose(IniFile);
|
||||
IniFile = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
CloseIniFile
|
||||
-------------------------------------------------------------------------
|
||||
Job : Frees the memory and closes the ini file without any
|
||||
modifications. If you want to write the file use
|
||||
WriteIniFile instead.
|
||||
/*========================================================================*/
|
||||
void CloseIniFile(void)
|
||||
{
|
||||
FreeAllMem();
|
||||
if (IniFile != NULL)
|
||||
{
|
||||
fclose(IniFile);
|
||||
IniFile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
WriteIniFile
|
||||
-------------------------------------------------------------------------
|
||||
Job : Writes the iniFile to the disk and close it. Frees all memory
|
||||
allocated by WriteIniFile;
|
||||
/*========================================================================*/
|
||||
bool WriteIniFile(const char *FileName)
|
||||
{
|
||||
struct ENTRY *pEntry = Entry;
|
||||
IniFile = NULL;
|
||||
if (IniFile != NULL)
|
||||
{
|
||||
fclose(IniFile);
|
||||
}
|
||||
if ((IniFile = fopen(FileName, "wb")) == NULL)
|
||||
{
|
||||
FreeAllMem();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (pEntry != NULL)
|
||||
{
|
||||
if (pEntry->Type != tpNULL)
|
||||
{
|
||||
fprintf(IniFile, "%s\n", pEntry->Text);
|
||||
pEntry = pEntry->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(IniFile);
|
||||
IniFile = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
WriteString : Writes a string to the ini file
|
||||
*========================================================================*/
|
||||
void WriteString(cchr *Section, cchr *pKey, cchr *Value)
|
||||
{
|
||||
EFIND List;
|
||||
char Str[5120];
|
||||
|
||||
if (ArePtrValid(Section, pKey, Value) == FALSE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (FindpKey(Section, pKey, &List) == TRUE)
|
||||
{
|
||||
sprintf(Str, "%s=%s%s", List.KeyText, Value, List.Comment);
|
||||
FreeMem(List.pKey->Text);
|
||||
List.pKey->Text = (char *)malloc(strlen(Str) + 1);
|
||||
strcpy(List.pKey->Text, Str);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((List.pSec != NULL) && (List.pKey == NULL)) /* section exist, pKey not */
|
||||
{
|
||||
AddpKey(List.pSec, pKey, Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddSectionAndpKey(Section, pKey, Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
WriteBool : Writes a boolean to the ini file
|
||||
*========================================================================*/
|
||||
void WriteBool(cchr *Section, cchr *pKey, bool Value)
|
||||
{
|
||||
char Val[2] = {'0', 0};
|
||||
if (Value != 0)
|
||||
{
|
||||
Val[0] = '1';
|
||||
}
|
||||
WriteString(Section, pKey, Val);
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
WriteInt : Writes an integer to the ini file
|
||||
*========================================================================*/
|
||||
void WriteInt(cchr *Section, cchr *pKey, int Value)
|
||||
{
|
||||
char Val[12]; /* 32bit maximum + sign + \0 */
|
||||
sprintf(Val, "%d", Value);
|
||||
WriteString(Section, pKey, Val);
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
WriteDouble : Writes a double to the ini file
|
||||
*========================================================================*/
|
||||
void WriteDouble(cchr *Section, cchr *pKey, double Value)
|
||||
{
|
||||
char Val[32]; /* DDDDDDDDDDDDDDD+E308\0 */
|
||||
sprintf(Val, "%1.10lE", Value);
|
||||
WriteString(Section, pKey, Val);
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
ReadString : Reads a string from the ini file
|
||||
*========================================================================*/
|
||||
const char *
|
||||
ReadString(cchr *Section, cchr *pKey, cchr *Default)
|
||||
{
|
||||
EFIND List;
|
||||
if (ArePtrValid(Section, pKey, Default) == FALSE)
|
||||
{
|
||||
return Default;
|
||||
}
|
||||
if (FindpKey(Section, pKey, &List) == TRUE)
|
||||
{
|
||||
strcpy(Result, List.ValText);
|
||||
return Result;
|
||||
}
|
||||
return Default;
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
ReadBool : Reads a boolean from the ini file
|
||||
*========================================================================*/
|
||||
bool ReadBool(cchr *Section, cchr *pKey, bool Default)
|
||||
{
|
||||
char Val[2] = {"0"};
|
||||
if (Default != 0)
|
||||
{
|
||||
Val[0] = '1';
|
||||
}
|
||||
return (atoi(ReadString(Section, pKey, Val)) ? 1 : 0); /* Only 0 or 1 allowed */
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
ReadInt : Reads a integer from the ini file
|
||||
*========================================================================*/
|
||||
int ReadInt(cchr *Section, cchr *pKey, int Default)
|
||||
{
|
||||
char Val[12];
|
||||
sprintf(Val, "%d", Default);
|
||||
return (atoi(ReadString(Section, pKey, Val)));
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
ReadDouble : Reads a double from the ini file
|
||||
*========================================================================*/
|
||||
double
|
||||
ReadDouble(cchr *Section, cchr *pKey, double Default)
|
||||
{
|
||||
double Val;
|
||||
sprintf(Result, "%1.10lE", Default);
|
||||
sscanf(ReadString(Section, pKey, Result), "%lE", &Val);
|
||||
return Val;
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
DeleteKey : Deletes a pKey from the ini file.
|
||||
*========================================================================*/
|
||||
|
||||
bool DeleteKey(cchr *Section, cchr *pKey)
|
||||
{
|
||||
EFIND List;
|
||||
struct ENTRY *pPrev;
|
||||
struct ENTRY *pNext;
|
||||
|
||||
if (FindpKey(Section, pKey, &List) == TRUE)
|
||||
{
|
||||
pPrev = List.pKey->pPrev;
|
||||
pNext = List.pKey->pNext;
|
||||
if (pPrev)
|
||||
{
|
||||
pPrev->pNext = pNext;
|
||||
}
|
||||
if (pNext)
|
||||
{
|
||||
pNext->pPrev = pPrev;
|
||||
}
|
||||
FreeMem(List.pKey->Text);
|
||||
FreeMem(List.pKey);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Here we start with our helper functions */
|
||||
/*=========================================================================
|
||||
FreeMem : Frees a pointer. It is set to NULL by Free AllMem
|
||||
*========================================================================*/
|
||||
void FreeMem(void *Ptr)
|
||||
{
|
||||
if (Ptr != NULL)
|
||||
{
|
||||
free(Ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
FreeAllMem : Frees all allocated memory and set the pointer to NULL.
|
||||
Thats IMO one of the most important issues relating
|
||||
to pointers :
|
||||
|
||||
A pointer is valid or NULL.
|
||||
*========================================================================*/
|
||||
void FreeAllMem(void)
|
||||
{
|
||||
struct ENTRY *pEntry;
|
||||
struct ENTRY *pNextEntry;
|
||||
pEntry = Entry;
|
||||
while (1)
|
||||
{
|
||||
if (pEntry == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
pNextEntry = pEntry->pNext;
|
||||
FreeMem(pEntry->Text); /* Frees the pointer if not NULL */
|
||||
FreeMem(pEntry);
|
||||
pEntry = pNextEntry;
|
||||
}
|
||||
Entry = NULL;
|
||||
CurEntry = NULL;
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
FindSection : Searches the chained list for a section. The section
|
||||
must be given without the brackets!
|
||||
Return Value: NULL at an error or a pointer to the ENTRY structure
|
||||
if succeed.
|
||||
*========================================================================*/
|
||||
struct ENTRY *
|
||||
FindSection(cchr *Section)
|
||||
{
|
||||
char Sec[130];
|
||||
char iSec[130];
|
||||
struct ENTRY *pEntry;
|
||||
sprintf(Sec, "[%s]", Section);
|
||||
strupr(Sec);
|
||||
pEntry = Entry; /* Get a pointer to the first Entry */
|
||||
while (pEntry != NULL)
|
||||
{
|
||||
if (pEntry->Type == tpSECTION)
|
||||
{
|
||||
strcpy(iSec, pEntry->Text);
|
||||
strupr(iSec);
|
||||
if (strcmp(Sec, iSec) == 0)
|
||||
{
|
||||
return pEntry;
|
||||
}
|
||||
}
|
||||
pEntry = pEntry->pNext;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
FindpKey : Searches the chained list for a pKey under a given section
|
||||
Return Value: NULL at an error or a pointer to the ENTRY structure
|
||||
if succeed.
|
||||
*========================================================================*/
|
||||
bool FindpKey(cchr *Section, cchr *pKey, EFIND *List)
|
||||
{
|
||||
char Search[130];
|
||||
char Found[130];
|
||||
char Text[5120];
|
||||
char *pText;
|
||||
struct ENTRY *pEntry;
|
||||
List->pSec = NULL;
|
||||
List->pKey = NULL;
|
||||
pEntry = FindSection(Section);
|
||||
if (pEntry == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
List->pSec = pEntry;
|
||||
List->KeyText[0] = 0;
|
||||
List->ValText[0] = 0;
|
||||
List->Comment[0] = 0;
|
||||
pEntry = pEntry->pNext;
|
||||
if (pEntry == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
sprintf(Search, "%s", pKey);
|
||||
strupr(Search);
|
||||
while (pEntry != NULL)
|
||||
{
|
||||
if ((pEntry->Type == tpSECTION) || /* Stop after next section or EOF */
|
||||
(pEntry->Type == tpNULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (pEntry->Type == tpKEYVALUE)
|
||||
{
|
||||
strcpy(Text, pEntry->Text);
|
||||
pText = strchr(Text, ';');
|
||||
if (pText != NULL)
|
||||
{
|
||||
strcpy(List->Comment, Text);
|
||||
*pText = 0;
|
||||
}
|
||||
pText = strchr(Text, '=');
|
||||
if (pText != NULL)
|
||||
{
|
||||
*pText = 0;
|
||||
strcpy(List->KeyText, Text);
|
||||
strcpy(Found, Text);
|
||||
*pText = '=';
|
||||
strupr(Found);
|
||||
/* printf ("%s,%s\n", Search, Found); */
|
||||
if (strcmp(Found, Search) == 0)
|
||||
{
|
||||
strcpy(List->ValText, pText + 1);
|
||||
List->pKey = pEntry;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
pEntry = pEntry->pNext;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
AddItem : Adds an item (pKey or section) to the chaines list
|
||||
*========================================================================*/
|
||||
bool AddItem(char Type, cchr *Text)
|
||||
{
|
||||
struct ENTRY *pEntry = MakeNewEntry();
|
||||
if (pEntry == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
pEntry->Type = Type;
|
||||
pEntry->Text = (char *)malloc(strlen(Text) + 1);
|
||||
if (pEntry->Text == NULL)
|
||||
{
|
||||
free(pEntry);
|
||||
return FALSE;
|
||||
}
|
||||
strcpy(pEntry->Text, Text);
|
||||
pEntry->pNext = NULL;
|
||||
if (CurEntry != NULL)
|
||||
{
|
||||
CurEntry->pNext = pEntry;
|
||||
}
|
||||
CurEntry = pEntry;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
AddItemAt : Adds an item at a selected position. This means, that the
|
||||
chained list will be broken at the selected position and
|
||||
that the new item will be Inserted.
|
||||
Before : A.Next = &B
|
||||
After : A.Next = &NewItem, NewItem.Next = &B
|
||||
*========================================================================*/
|
||||
bool AddItemAt(struct ENTRY *EntryAt, char Mode, cchr *Text)
|
||||
{
|
||||
struct ENTRY *pNewEntry;
|
||||
if (EntryAt == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
pNewEntry = (struct ENTRY *)malloc(sizeof(ENTRY));
|
||||
if (pNewEntry == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
pNewEntry->Text = (char *)malloc(strlen(Text) + 1);
|
||||
if (pNewEntry->Text == NULL)
|
||||
{
|
||||
free(pNewEntry);
|
||||
return FALSE;
|
||||
}
|
||||
strcpy(pNewEntry->Text, Text);
|
||||
if (EntryAt->pNext == NULL) /* No following nodes. */
|
||||
{
|
||||
EntryAt->pNext = pNewEntry;
|
||||
pNewEntry->pNext = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNewEntry->pNext = EntryAt->pNext;
|
||||
EntryAt->pNext = pNewEntry;
|
||||
}
|
||||
pNewEntry->pPrev = EntryAt;
|
||||
pNewEntry->Type = Mode;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
AddSectionAndpKey : Adds a section and then a pKey to the chained list
|
||||
*========================================================================*/
|
||||
bool AddSectionAndpKey(cchr *Section, cchr *pKey, cchr *Value)
|
||||
{
|
||||
char Text[5120];
|
||||
sprintf(Text, "[%s]", Section);
|
||||
if (AddItem(tpSECTION, Text) == FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
sprintf(Text, "%s=%s", pKey, Value);
|
||||
return AddItem(tpKEYVALUE, Text);
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
AddpKey : Adds a pKey to the chained list
|
||||
*========================================================================*/
|
||||
void AddpKey(struct ENTRY *SecEntry, cchr *pKey, cchr *Value)
|
||||
{
|
||||
char Text[5120];
|
||||
sprintf(Text, "%s=%s", pKey, Value);
|
||||
AddItemAt(SecEntry, tpKEYVALUE, Text);
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
MakeNewEntry : Allocates the memory for a new entry. This is only
|
||||
the new empty structure, that must be filled from
|
||||
function like AddItem etc.
|
||||
Info : This is only a internal function. You dont have to call
|
||||
it from outside.
|
||||
*==========================================================================*/
|
||||
struct ENTRY *
|
||||
MakeNewEntry(void)
|
||||
{
|
||||
struct ENTRY *pEntry;
|
||||
pEntry = (struct ENTRY *)malloc(sizeof(ENTRY));
|
||||
if (pEntry == NULL)
|
||||
{
|
||||
FreeAllMem();
|
||||
return NULL;
|
||||
}
|
||||
if (Entry == NULL)
|
||||
{
|
||||
Entry = pEntry;
|
||||
}
|
||||
pEntry->Type = tpNULL;
|
||||
pEntry->pPrev = CurEntry;
|
||||
pEntry->pNext = NULL;
|
||||
pEntry->Text = NULL;
|
||||
if (CurEntry != NULL)
|
||||
{
|
||||
CurEntry->pNext = pEntry;
|
||||
}
|
||||
return pEntry;
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
GetSectionCount : Get the number of sections
|
||||
*========================================================================*/
|
||||
int GetSectionCount()
|
||||
{
|
||||
struct ENTRY *pEntry = Entry;
|
||||
int count = 0;
|
||||
while (pEntry != NULL)
|
||||
{
|
||||
if (pEntry->Type == tpSECTION)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
pEntry = pEntry->pNext;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
GetSections : Retrieve the sections
|
||||
*========================================================================*/
|
||||
void GetSections(char *sections[])
|
||||
{
|
||||
struct ENTRY *pEntry = Entry;
|
||||
int i = 0;
|
||||
|
||||
while (pEntry != NULL)
|
||||
{
|
||||
if (pEntry->Type == tpSECTION)
|
||||
{
|
||||
sprintf(sections[i], pEntry->Text);
|
||||
i++;
|
||||
}
|
||||
pEntry = pEntry->pNext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/************************************************************************
|
||||
T h e O p e n W i n d o w s P r o j e c t
|
||||
------------------------------------------------------------------------
|
||||
Filename : IniFile.h
|
||||
Author(s) : Carsten Breuer
|
||||
------------------------------------------------------------------------
|
||||
Copyright (c) 2000 by Carsten Breuer (C.Breuer@openwin.de)
|
||||
/************************************************************************/
|
||||
|
||||
#ifndef INIFILE_H
|
||||
#define INIFILE_H
|
||||
|
||||
#ifndef CCHR_H
|
||||
#define CCHR_H
|
||||
typedef const char cchr;
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef char bool;
|
||||
#define true 1
|
||||
#define TRUE 1
|
||||
#define false 0
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define tpNULL 0
|
||||
#define tpSECTION 1
|
||||
#define tpKEYVALUE 2
|
||||
#define tpCOMMENT 3
|
||||
|
||||
typedef struct ENTRY
|
||||
{
|
||||
char Type;
|
||||
char *Text;
|
||||
struct ENTRY *pPrev;
|
||||
struct ENTRY *pNext;
|
||||
} ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct ENTRY *pSec;
|
||||
struct ENTRY *pKey;
|
||||
char KeyText[128];
|
||||
char ValText[4096];
|
||||
char Comment[32];
|
||||
} EFIND;
|
||||
|
||||
/* Macros */
|
||||
#define ArePtrValid(Sec, Key, Val) ((Sec != NULL) && (Key != NULL) && (Val != NULL))
|
||||
|
||||
/* Connectors of this file (Prototypes) */
|
||||
|
||||
bool OpenIniFile(cchr *FileName);
|
||||
|
||||
bool ReadBool(cchr *Section, cchr *Key, bool Default);
|
||||
int ReadInt(cchr *Section, cchr *Key, int Default);
|
||||
double ReadDouble(cchr *Section, cchr *Key, double Default);
|
||||
cchr *ReadString(cchr *Section, cchr *Key, cchr *Default);
|
||||
|
||||
void WriteBool(cchr *Section, cchr *Key, bool Value);
|
||||
void WriteInt(cchr *Section, cchr *Key, int Value);
|
||||
void WriteDouble(cchr *Section, cchr *Key, double Value);
|
||||
void WriteString(cchr *Section, cchr *Key, cchr *Value);
|
||||
|
||||
bool DeleteKey(cchr *Section, cchr *Key);
|
||||
|
||||
void CloseIniFile();
|
||||
bool WriteIniFile(cchr *FileName);
|
||||
|
||||
int GetSectionCount();
|
||||
void GetSections(char *sections[]);
|
||||
#endif
|
||||
@@ -0,0 +1,268 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <orbis/libkernel.h>
|
||||
#include <orbis/Bgft.h>
|
||||
#include <orbis/AppInstUtil.h>
|
||||
#include <orbis/UserService.h>
|
||||
#include <curl/curl.h>
|
||||
#include <request.hpp>
|
||||
#include <urn.hpp>
|
||||
#include "installer.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
#include "windows.h"
|
||||
#include "lang.h"
|
||||
#include "rtc.h"
|
||||
#include "fs.h"
|
||||
|
||||
#define BGFT_HEAP_SIZE (1 * 1024 * 1024)
|
||||
|
||||
static OrbisBgftInitParams s_bgft_init_params;
|
||||
|
||||
static bool s_bgft_initialized = false;
|
||||
|
||||
namespace INSTALLER
|
||||
{
|
||||
int Init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (s_bgft_initialized)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
|
||||
memset(&s_bgft_init_params, 0, sizeof(s_bgft_init_params));
|
||||
{
|
||||
s_bgft_init_params.heapSize = BGFT_HEAP_SIZE;
|
||||
s_bgft_init_params.heap = (uint8_t *)malloc(s_bgft_init_params.heapSize);
|
||||
if (!s_bgft_init_params.heap)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
memset(s_bgft_init_params.heap, 0, s_bgft_init_params.heapSize);
|
||||
}
|
||||
|
||||
ret = sceBgftServiceIntInit(&s_bgft_init_params);
|
||||
if (ret)
|
||||
{
|
||||
goto err_bgft_heap_free;
|
||||
}
|
||||
|
||||
s_bgft_initialized = true;
|
||||
|
||||
done:
|
||||
return 0;
|
||||
|
||||
err_bgft_heap_free:
|
||||
if (s_bgft_init_params.heap)
|
||||
{
|
||||
free(s_bgft_init_params.heap);
|
||||
s_bgft_init_params.heap = NULL;
|
||||
}
|
||||
|
||||
memset(&s_bgft_init_params, 0, sizeof(s_bgft_init_params));
|
||||
|
||||
err:
|
||||
s_bgft_initialized = false;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Exit(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!s_bgft_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ret = sceBgftServiceIntTerm();
|
||||
|
||||
if (s_bgft_init_params.heap)
|
||||
{
|
||||
free(s_bgft_init_params.heap);
|
||||
s_bgft_init_params.heap = NULL;
|
||||
}
|
||||
|
||||
memset(&s_bgft_init_params, 0, sizeof(s_bgft_init_params));
|
||||
|
||||
s_bgft_initialized = false;
|
||||
}
|
||||
|
||||
int InstallRemotePkg(const char *filename, pkg_header *header)
|
||||
{
|
||||
std::string full_url = webdav_settings->server + std::string(filename);
|
||||
size_t scheme_pos = full_url.find("://");
|
||||
size_t root_pos = full_url.find("/", scheme_pos+3);
|
||||
std::string host = full_url.substr(0, root_pos);
|
||||
std::string path = full_url.substr(root_pos);
|
||||
|
||||
WebDAV::Urn::Path uri(path);
|
||||
CURL *curl = curl_easy_init();
|
||||
path = uri.quote(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
char url[2000];
|
||||
sprintf(url, "%s%s", host.c_str(), path.c_str());
|
||||
|
||||
int ret;
|
||||
std::string cid = std::string((char *)header->pkg_content_id);
|
||||
cid = cid.substr(cid.find_first_of("-") + 1, 9);
|
||||
int user_id;
|
||||
ret = sceUserServiceGetForegroundUser(&user_id);
|
||||
const char *package_type;
|
||||
uint32_t content_type = BE32(header->pkg_content_type);
|
||||
uint32_t flags = BE32(header->pkg_content_flags);
|
||||
bool is_patch = false;
|
||||
|
||||
switch (content_type)
|
||||
{
|
||||
case PKG_CONTENT_TYPE_GD:
|
||||
package_type = "PS4GD";
|
||||
break;
|
||||
case PKG_CONTENT_TYPE_AC:
|
||||
package_type = "PS4AC";
|
||||
break;
|
||||
case PKG_CONTENT_TYPE_AL:
|
||||
package_type = "PS4AL";
|
||||
break;
|
||||
case PKG_CONTENT_TYPE_DP:
|
||||
package_type = "PS4DP";
|
||||
break;
|
||||
default:
|
||||
package_type = NULL;
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags & PKG_CONTENT_FLAGS_FIRST_PATCH ||
|
||||
flags & PKG_CONTENT_FLAGS_SUBSEQUENT_PATCH ||
|
||||
flags & PKG_CONTENT_FLAGS_DELTA_PATCH ||
|
||||
flags & PKG_CONTENT_FLAGS_CUMULATIVE_PATCH)
|
||||
{
|
||||
is_patch = true;
|
||||
}
|
||||
|
||||
OrbisBgftDownloadParam params;
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
{
|
||||
params.userId = user_id;
|
||||
params.entitlementType = 5;
|
||||
params.id = (char *)header->pkg_content_id;
|
||||
params.contentUrl = url;
|
||||
params.contentName = cid.c_str();
|
||||
params.iconPath = "";
|
||||
params.playgoScenarioId = "0";
|
||||
params.option = ORBIS_BGFT_TASK_OPT_DISABLE_CDN_QUERY_PARAM;
|
||||
params.packageType = package_type;
|
||||
params.packageSubType = "";
|
||||
params.packageSize = BE64(header->pkg_size);
|
||||
}
|
||||
|
||||
int task_id = -1;
|
||||
if (!is_patch)
|
||||
ret = sceBgftServiceIntDownloadRegisterTask(¶ms, &task_id);
|
||||
else
|
||||
ret = sceBgftServiceIntDebugDownloadRegisterPkg(¶ms, &task_id);
|
||||
if (ret)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = sceBgftServiceDownloadStartTask(task_id);
|
||||
if (ret)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
||||
Util::Notify("%s queued", cid.c_str());
|
||||
return 1;
|
||||
|
||||
err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int InstallLocalPkg(const char *filename, pkg_header *header, bool remove_after_install)
|
||||
{
|
||||
int ret;
|
||||
if (strncmp(filename, "/data/", 6) != 0 &&
|
||||
strncmp(filename, "/user/data/", 11) != 0 &&
|
||||
strncmp(filename, "/mnt/usb", 8) != 0)
|
||||
return -1;
|
||||
|
||||
char filepath[1024];
|
||||
snprintf(filepath, 1023, "%s", filename);
|
||||
if (strncmp(filename, "/data/", 6) == 0)
|
||||
snprintf(filepath, 1023, "/user%s", filename);
|
||||
char titleId[18];
|
||||
memset(titleId, 0, sizeof(titleId));
|
||||
int is_app = -1;
|
||||
ret = sceAppInstUtilGetTitleIdFromPkg(filename, titleId, &is_app);
|
||||
if (ret)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
OrbisBgftTaskProgress progress_info;
|
||||
int prog = 0;
|
||||
OrbisBgftDownloadParamEx download_params;
|
||||
memset(&download_params, 0, sizeof(download_params));
|
||||
{
|
||||
download_params.params.entitlementType = 5;
|
||||
download_params.params.id = (char *)header->pkg_content_id;
|
||||
download_params.params.contentUrl = filepath;
|
||||
download_params.params.contentName = (char *)header->pkg_content_id;;
|
||||
download_params.params.iconPath = "";
|
||||
download_params.params.playgoScenarioId = "0";
|
||||
download_params.params.option = ORBIS_BGFT_TASK_OPT_FORCE_UPDATE;
|
||||
download_params.slot = 0;
|
||||
}
|
||||
|
||||
int task_id = -1;
|
||||
ret = sceBgftServiceIntDownloadRegisterTaskByStorageEx(&download_params, &task_id);
|
||||
if (ret)
|
||||
{
|
||||
if (ret == 0x80990088)
|
||||
return -2;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = sceBgftServiceDownloadStartTask(task_id);
|
||||
if (ret)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!remove_after_install)
|
||||
{
|
||||
Util::Notify("%s queued", titleId);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sprintf(activity_message, "%s", lang_strings[STR_WAIT_FOR_INSTALL_MSG]);
|
||||
bytes_to_download = 1;
|
||||
bytes_transfered = 0;
|
||||
while (prog < 99)
|
||||
{
|
||||
memset(&progress_info, 0, sizeof(progress_info));
|
||||
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
|
||||
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
|
||||
return -3;
|
||||
prog = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
|
||||
bytes_to_download = progress_info.length;
|
||||
bytes_transfered = progress_info.transferred;
|
||||
}
|
||||
if (auto_delete_tmp_pkg)
|
||||
FS::Rm(filename);
|
||||
return 1;
|
||||
|
||||
err:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#define SWAP16(x) \
|
||||
((uint16_t)( \
|
||||
(((uint16_t)(x) & UINT16_C(0x00FF)) << 8) | \
|
||||
(((uint16_t)(x) & UINT16_C(0xFF00)) >> 8) \
|
||||
))
|
||||
|
||||
#define SWAP32(x) \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(x) & UINT32_C(0x000000FF)) << 24) | \
|
||||
(((uint32_t)(x) & UINT32_C(0x0000FF00)) << 8) | \
|
||||
(((uint32_t)(x) & UINT32_C(0x00FF0000)) >> 8) | \
|
||||
(((uint32_t)(x) & UINT32_C(0xFF000000)) >> 24) \
|
||||
))
|
||||
|
||||
#define SWAP64(x) \
|
||||
((uint64_t)( \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x00000000000000FF)) << 56) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x000000000000FF00)) << 40) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x0000000000FF0000)) << 24) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x00000000FF000000)) << 8) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x000000FF00000000)) >> 8) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x0000FF0000000000)) >> 24) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x00FF000000000000)) >> 40) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0xFF00000000000000)) >> 56) \
|
||||
))
|
||||
|
||||
#define LE16(x) (x)
|
||||
#define LE32(x) (x)
|
||||
#define LE64(x) (x)
|
||||
|
||||
#define BE16(x) SWAP16(x)
|
||||
#define BE32(x) SWAP32(x)
|
||||
#define BE64(x) SWAP64(x)
|
||||
|
||||
#define PKG_MAGIC 0x7F434E54
|
||||
|
||||
#define PKG_CONTENT_FLAGS_FIRST_PATCH 0x00100000
|
||||
#define PKG_CONTENT_FLAGS_PATCHGO 0x00200000
|
||||
#define PKG_CONTENT_FLAGS_REMASTER 0x00400000
|
||||
#define PKG_CONTENT_FLAGS_PS_CLOUD 0x00800000
|
||||
#define PKG_CONTENT_FLAGS_GD_AC 0x02000000
|
||||
#define PKG_CONTENT_FLAGS_NON_GAME 0x04000000
|
||||
#define PKG_CONTENT_FLAGS_0x8000000 0x08000000 /* has data? */
|
||||
#define PKG_CONTENT_FLAGS_SUBSEQUENT_PATCH 0x40000000
|
||||
#define PKG_CONTENT_FLAGS_DELTA_PATCH 0x41000000
|
||||
#define PKG_CONTENT_FLAGS_CUMULATIVE_PATCH 0x60000000
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t pkg_magic; // 0x000 - 0x7F434E54
|
||||
uint32_t pkg_type; // 0x004
|
||||
uint32_t pkg_0x008; // 0x008 - unknown field
|
||||
uint32_t pkg_file_count; // 0x00C
|
||||
uint32_t pkg_entry_count; // 0x010
|
||||
uint16_t pkg_sc_entry_count; // 0x014
|
||||
uint16_t pkg_entry_count_2; // 0x016 - same as pkg_entry_count
|
||||
uint32_t pkg_table_offset; // 0x018 - file table offset
|
||||
uint32_t pkg_entry_data_size; // 0x01C
|
||||
uint64_t pkg_body_offset; // 0x020 - offset of PKG entries
|
||||
uint64_t pkg_body_size; // 0x028 - length of all PKG entries
|
||||
uint64_t pkg_content_offset; // 0x030
|
||||
uint64_t pkg_content_size; // 0x038
|
||||
unsigned char pkg_content_id[0x24]; // 0x040 - packages' content ID as a 36-byte string
|
||||
unsigned char pkg_padding[0xC]; // 0x064 - padding
|
||||
uint32_t pkg_drm_type; // 0x070 - DRM type
|
||||
uint32_t pkg_content_type; // 0x074 - Content type
|
||||
uint32_t pkg_content_flags; // 0x078 - Content flags
|
||||
uint32_t pkg_promote_size; // 0x07C
|
||||
uint32_t pkg_version_date; // 0x080
|
||||
uint32_t pkg_version_hash; // 0x084
|
||||
uint32_t pkg_0x088; // 0x088
|
||||
uint32_t pkg_0x08C; // 0x08C
|
||||
uint32_t pkg_0x090; // 0x090
|
||||
uint32_t pkg_0x094; // 0x094
|
||||
uint32_t pkg_iro_tag; // 0x098
|
||||
uint32_t pkg_drm_type_version; // 0x09C
|
||||
|
||||
unsigned char digest_entries1[0x20]; // 0x100 - sha256 digest for main entry 1
|
||||
unsigned char digest_entries2[0x20]; // 0x120 - sha256 digest for main entry 2
|
||||
unsigned char digest_table_digest[0x20]; // 0x140 - sha256 digest for digest table
|
||||
unsigned char digest_body_digest[0x20]; // 0x160 - sha256 digest for main table
|
||||
|
||||
uint32_t pfs_image_count; // 0x404 - count of PFS images
|
||||
uint64_t pfs_image_flags; // 0x408 - PFS flags
|
||||
uint64_t pfs_image_offset; // 0x410 - offset to start of external PFS image
|
||||
uint64_t pfs_image_size; // 0x418 - size of external PFS image
|
||||
uint64_t mount_image_offset; // 0x420
|
||||
uint64_t mount_image_size; // 0x428
|
||||
uint64_t pkg_size; // 0x430
|
||||
uint32_t pfs_signed_size; // 0x438
|
||||
uint32_t pfs_cache_size; // 0x43C
|
||||
unsigned char pfs_image_digest[0x20]; // 0x440
|
||||
unsigned char pfs_signed_digest[0x20]; // 0x460
|
||||
uint64_t pfs_split_size_nth_0; // 0x480
|
||||
uint64_t pfs_split_size_nth_1; // 0x488
|
||||
unsigned char pkg_digest[0x20]; // 0xFE0
|
||||
} pkg_header;
|
||||
|
||||
enum pkg_content_type {
|
||||
PKG_CONTENT_TYPE_GD = 0x1A, /* pkg_ps4_app, pkg_ps4_patch, pkg_ps4_remaster */
|
||||
PKG_CONTENT_TYPE_AC = 0x1B, /* pkg_ps4_ac_data, pkg_ps4_sf_theme, pkg_ps4_theme */
|
||||
PKG_CONTENT_TYPE_AL = 0x1C, /* pkg_ps4_ac_nodata */
|
||||
PKG_CONTENT_TYPE_DP = 0x1E, /* pkg_ps4_delta_patch */
|
||||
};
|
||||
|
||||
namespace INSTALLER
|
||||
{
|
||||
int Init(void);
|
||||
void Exit(void);
|
||||
|
||||
int InstallRemotePkg(const char *filename, pkg_header *header);
|
||||
int InstallLocalPkg(const char *filename, pkg_header *header, bool remove_after_install=false);
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
#include <orbis/SystemService.h>
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
#include "lang.h"
|
||||
|
||||
char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE] = {
|
||||
FOREACH_STR(GET_STRING)};
|
||||
|
||||
// This is properly populated so that emulator won't crash if an user launches it without language INI files.
|
||||
char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
|
||||
"Connection Settings", // STR_CONNECTION_SETTINGS
|
||||
"Site", // STR_SITE
|
||||
"Local", // STR_LOCAL
|
||||
"Remote", // STR_REMOTE
|
||||
"Messages", // STR_MESSAGES
|
||||
"Update Software", // STR_UPDATE_SOFTWARE
|
||||
"Connect", // STR_CONNECT_WEBDAV
|
||||
"Disconnect", // STR_DISCONNECT_WEBDAV
|
||||
"Search", // STR_SEARCH
|
||||
"Refresh", // STR_REFRESH
|
||||
"Server", // STR_SERVER
|
||||
"Username", // STR_USERNAME
|
||||
"Password", // STR_PASSWORD
|
||||
"Port", // STR_PORT
|
||||
"Pasv", // STR_PASV
|
||||
"Directory", // STR_DIRECTORY
|
||||
"Filter", // STR_FILTER
|
||||
"Yes", // STR_YES
|
||||
"No", // STR_NO
|
||||
"Cancel", // STR_CANCEL
|
||||
"Continue", // STR_CONTINUE
|
||||
"Close", // STR_CLOSE
|
||||
"Folder", // STR_FOLDER
|
||||
"File", // STR_FILE
|
||||
"Type", // STR_TYPE
|
||||
"Name", // STR_NAME
|
||||
"Size", // STR_SIZE
|
||||
"Date", // STR_DATE
|
||||
"New Folder", // STR_NEW_FOLDER
|
||||
"Rename", // STR_RENAME
|
||||
"Delete", // STR_DELETE
|
||||
"Upload", // STR_UPLOAD
|
||||
"Download", // STR_DOWNLOAD
|
||||
"Select All", // STR_SELECT_ALL
|
||||
"Clear All", // STR_CLEAR_ALL
|
||||
"Uploading", // STR_UPLOADING
|
||||
"Downloading", // STR_DOWNLOADING
|
||||
"Overwrite", // STR_OVERWRITE
|
||||
"Don't Overwrite", // STR_DONT_OVERWRITE
|
||||
"Ask for Confirmation", // STR_ASK_FOR_CONFIRM
|
||||
"Don't Ask for Confirmation", // STR_DONT_ASK_CONFIRM
|
||||
"Always use this option and don't ask again", // STR_ALLWAYS_USE_OPTION
|
||||
"Actions", // STR_ACTIONS
|
||||
"Confirm", // STR_CONFIRM
|
||||
"Overwrite Options", // STR_OVERWRITE_OPTIONS
|
||||
"Properties", // STR_PROPERTIES
|
||||
"Progress", // STR_PROGRESS
|
||||
"Updates", // STR_UPDATES
|
||||
"Are you sure you want to delete this file(s)/folder(s)?", // STR_DEL_CONFIRM_MSG
|
||||
"Canceling. Waiting for last action to complete", // STR_CANCEL_ACTION_MSG
|
||||
"Failed to upload file", // STR_FAIL_UPLOAD_MSG
|
||||
"Failed to download file", // STR_FAIL_DOWNLOAD_MSG
|
||||
"Failed to read contents of directory or folder does not exist.", // STR_FAIL_READ_LOCAL_DIR_MSG
|
||||
"426 Connection closed.", // STR_CONNECTION_CLOSE_ERR_MSG
|
||||
"426 Remote Server has terminated the connection.", // STR_REMOTE_TERM_CONN_MSG
|
||||
"300 Failed Login. Please check your username or password.", // STR_FAIL_LOGIN_MSG
|
||||
"426 Failed. Connection timeout.", // STR_FAIL_TIMEOUT_MSG
|
||||
"Failed to delete directory", // STR_FAIL_DEL_DIR_MSG
|
||||
"Deleting", // STR_DELETING
|
||||
"Failed to delete file", // STR_FAIL_DEL_FILE_MSG
|
||||
"Deleted", // STR_DELETED
|
||||
"Link", // STR_LINK
|
||||
"Share", // STR_SHARE
|
||||
"310 Failed", // STR_FAILED
|
||||
"310 Failed to create file on local", // STR_FAIL_CREATE_LOCAL_FILE_MSG
|
||||
"Install", // STR_INSTALL
|
||||
"Installing", // STR_INSTALLING
|
||||
"Success", // STR_INSTALL_SUCCESS
|
||||
"Failed", // STR_INSTALL_FAILED
|
||||
"Skipped", // STR_INSTALL_SKIPPED
|
||||
"Checking connection to remote HTTP Server", // STR_CHECK_HTTP_MSG
|
||||
"Failed connecting to HTTP Server", // STR_FAILED_HTTP_CHECK
|
||||
"Remote is not a HTTP Server", // STR_REMOTE_NOT_HTTP
|
||||
"Package not in the /data or /mnt/usbX folder", // STR_INSTALL_FROM_DATA_MSG
|
||||
"Package is already installed", // STR_ALREADY_INSTALLED_MSG
|
||||
"Install from URL", // STR_INSTALL_FROM_URL
|
||||
"Could not read package header info", // STR_CANNOT_READ_PKG_HDR_MSG
|
||||
"Favorite URLs", // STR_FAVORITE_URLS
|
||||
"Slot", // STR_SLOT
|
||||
"Edit", // STR_EDIT
|
||||
"One Time Url", // STR_ONETIME_URL
|
||||
"Not a valid Package", // STR_NOT_A_VALID_PACKAGE
|
||||
"Waiting for Package to finish installing", // STR_WAIT_FOR_INSTALL_MSG
|
||||
"Failed to install pkg file. Please delete the tmp pkg manually", // STR_FAIL_INSTALL_TMP_PKG_MSG
|
||||
"Failed to obtain google download URL", // STR_FAIL_TO_OBTAIN_GG_DL_MSG
|
||||
"Auto delete temporary downloaded pkg file after install", // STR_AUTO_DELETE_TMP_PKG
|
||||
"Protocol not supported", // STR_PROTOCOL_NOT_SUPPORTED
|
||||
"Could not resolve hostname" // STR_COULD_NOT_RESOLVE_HOST
|
||||
};
|
||||
|
||||
bool needs_extended_font = false;
|
||||
|
||||
namespace Lang
|
||||
{
|
||||
void SetTranslation(int32_t lang_idx)
|
||||
{
|
||||
char langFile[LANG_STR_SIZE * 2];
|
||||
char identifier[LANG_ID_SIZE], buffer[LANG_STR_SIZE];
|
||||
|
||||
std::string lang = std::string(language);
|
||||
lang = Util::Trim(lang, " ");
|
||||
if (lang.size() > 0)
|
||||
{
|
||||
sprintf(langFile, "/app0/assets/langs/%s.ini", lang.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (lang_idx)
|
||||
{
|
||||
case ORBIS_SYSTEM_PARAM_LANG_ITALIAN:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Italiano.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_SPANISH:
|
||||
case ORBIS_SYSTEM_PARAM_LANG_SPANISH_LA:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Spanish.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_GERMAN:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/German.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_PORTUGUESE_PT:
|
||||
case ORBIS_SYSTEM_PARAM_LANG_PORTUGUESE_BR:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Portuguese_BR.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_RUSSIAN:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Russian.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_DUTCH:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Dutch.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_FRENCH:
|
||||
case ORBIS_SYSTEM_PARAM_LANG_FRENCH_CA:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/French.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_POLISH:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Polish.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_JAPANESE:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Japanese.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_KOREAN:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Korean.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_CHINESE_S:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Simplified Chinese.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_CHINESE_T:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Traditional Chinese.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_INDONESIAN:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Indonesian.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_HUNGARIAN:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Hungarian.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_GREEK:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Greek.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_VIETNAMESE:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Vietnamese.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_TURKISH:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Turkish.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_ARABIC:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Arabic.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_ROMANIAN:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Romanian.ini");
|
||||
break;
|
||||
default:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/English.ini");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FILE *config = fopen(langFile, "r");
|
||||
if (config)
|
||||
{
|
||||
while (EOF != fscanf(config, "%[^=]=%[^\n]\n", identifier, buffer))
|
||||
{
|
||||
for (int i = 0; i < LANG_STRINGS_NUM; i++)
|
||||
{
|
||||
if (strcmp(lang_identifiers[i], identifier) == 0)
|
||||
{
|
||||
char *newline = nullptr, *p = buffer;
|
||||
while ((newline = strstr(p, "\\n")) != NULL)
|
||||
{
|
||||
newline[0] = '\n';
|
||||
int len = strlen(&newline[2]);
|
||||
memmove(&newline[1], &newline[2], len);
|
||||
newline[len + 1] = 0;
|
||||
p++;
|
||||
}
|
||||
strcpy(lang_strings[i], buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(config);
|
||||
}
|
||||
|
||||
char buf[12];
|
||||
int num;
|
||||
sscanf(last_site, "%[^ ] %d", buf, &num);
|
||||
sprintf(display_site, "%s %d", lang_strings[STR_SITE], num);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#ifndef __LANG_H__
|
||||
#define __LANG_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define FOREACH_STR(FUNC) \
|
||||
FUNC(STR_CONNECTION_SETTINGS) \
|
||||
FUNC(STR_SITE) \
|
||||
FUNC(STR_LOCAL) \
|
||||
FUNC(STR_REMOTE) \
|
||||
FUNC(STR_MESSAGES) \
|
||||
FUNC(STR_UPDATE_SOFTWARE) \
|
||||
FUNC(STR_CONNECT_WEBDAV) \
|
||||
FUNC(STR_DISCONNECT_WEBDAV) \
|
||||
FUNC(STR_SEARCH) \
|
||||
FUNC(STR_REFRESH) \
|
||||
FUNC(STR_SERVER) \
|
||||
FUNC(STR_USERNAME) \
|
||||
FUNC(STR_PASSWORD) \
|
||||
FUNC(STR_PORT) \
|
||||
FUNC(STR_PASV) \
|
||||
FUNC(STR_DIRECTORY) \
|
||||
FUNC(STR_FILTER) \
|
||||
FUNC(STR_YES) \
|
||||
FUNC(STR_NO) \
|
||||
FUNC(STR_CANCEL) \
|
||||
FUNC(STR_CONTINUE) \
|
||||
FUNC(STR_CLOSE) \
|
||||
FUNC(STR_FOLDER) \
|
||||
FUNC(STR_FILE) \
|
||||
FUNC(STR_TYPE) \
|
||||
FUNC(STR_NAME) \
|
||||
FUNC(STR_SIZE) \
|
||||
FUNC(STR_DATE) \
|
||||
FUNC(STR_NEW_FOLDER) \
|
||||
FUNC(STR_RENAME) \
|
||||
FUNC(STR_DELETE) \
|
||||
FUNC(STR_UPLOAD) \
|
||||
FUNC(STR_DOWNLOAD) \
|
||||
FUNC(STR_SELECT_ALL) \
|
||||
FUNC(STR_CLEAR_ALL) \
|
||||
FUNC(STR_UPLOADING) \
|
||||
FUNC(STR_DOWNLOADING) \
|
||||
FUNC(STR_OVERWRITE) \
|
||||
FUNC(STR_DONT_OVERWRITE) \
|
||||
FUNC(STR_ASK_FOR_CONFIRM) \
|
||||
FUNC(STR_DONT_ASK_CONFIRM) \
|
||||
FUNC(STR_ALLWAYS_USE_OPTION) \
|
||||
FUNC(STR_ACTIONS) \
|
||||
FUNC(STR_CONFIRM) \
|
||||
FUNC(STR_OVERWRITE_OPTIONS) \
|
||||
FUNC(STR_PROPERTIES) \
|
||||
FUNC(STR_PROGRESS) \
|
||||
FUNC(STR_UPDATES) \
|
||||
FUNC(STR_DEL_CONFIRM_MSG) \
|
||||
FUNC(STR_CANCEL_ACTION_MSG) \
|
||||
FUNC(STR_FAIL_UPLOAD_MSG) \
|
||||
FUNC(STR_FAIL_DOWNLOAD_MSG) \
|
||||
FUNC(STR_FAIL_READ_LOCAL_DIR_MSG) \
|
||||
FUNC(STR_CONNECTION_CLOSE_ERR_MSG) \
|
||||
FUNC(STR_REMOTE_TERM_CONN_MSG) \
|
||||
FUNC(STR_FAIL_LOGIN_MSG) \
|
||||
FUNC(STR_FAIL_TIMEOUT_MSG) \
|
||||
FUNC(STR_FAIL_DEL_DIR_MSG) \
|
||||
FUNC(STR_DELETING) \
|
||||
FUNC(STR_FAIL_DEL_FILE_MSG) \
|
||||
FUNC(STR_DELETED) \
|
||||
FUNC(STR_LINK) \
|
||||
FUNC(STR_SHARE) \
|
||||
FUNC(STR_FAILED) \
|
||||
FUNC(STR_FAIL_CREATE_LOCAL_FILE_MSG) \
|
||||
FUNC(STR_INSTALL) \
|
||||
FUNC(STR_INSTALLING) \
|
||||
FUNC(STR_INSTALL_SUCCESS) \
|
||||
FUNC(STR_INSTALL_FAILED) \
|
||||
FUNC(STR_INSTALL_SKIPPED) \
|
||||
FUNC(STR_CHECK_HTTP_MSG) \
|
||||
FUNC(STR_FAILED_HTTP_CHECK) \
|
||||
FUNC(STR_REMOTE_NOT_HTTP) \
|
||||
FUNC(STR_INSTALL_FROM_DATA_MSG) \
|
||||
FUNC(STR_ALREADY_INSTALLED_MSG) \
|
||||
FUNC(STR_INSTALL_FROM_URL) \
|
||||
FUNC(STR_CANNOT_READ_PKG_HDR_MSG) \
|
||||
FUNC(STR_FAVORITE_URLS) \
|
||||
FUNC(STR_SLOT) \
|
||||
FUNC(STR_EDIT) \
|
||||
FUNC(STR_ONETIME_URL) \
|
||||
FUNC(STR_NOT_A_VALID_PACKAGE) \
|
||||
FUNC(STR_WAIT_FOR_INSTALL_MSG) \
|
||||
FUNC(STR_FAIL_INSTALL_TMP_PKG_MSG) \
|
||||
FUNC(STR_FAIL_TO_OBTAIN_GG_DL_MSG) \
|
||||
FUNC(STR_AUTO_DELETE_TMP_PKG) \
|
||||
FUNC(STR_PROTOCOL_NOT_SUPPORTED) \
|
||||
FUNC(STR_COULD_NOT_RESOLVE_HOST)
|
||||
|
||||
#define GET_VALUE(x) x,
|
||||
#define GET_STRING(x) #x,
|
||||
|
||||
enum
|
||||
{
|
||||
FOREACH_STR(GET_VALUE)
|
||||
};
|
||||
|
||||
#define LANG_STRINGS_NUM 88
|
||||
#define LANG_ID_SIZE LANG_STRINGS_NUM
|
||||
#define LANG_STR_SIZE 256
|
||||
extern char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE];
|
||||
extern char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE];
|
||||
extern bool needs_extended_font;
|
||||
|
||||
namespace Lang
|
||||
{
|
||||
void SetTranslation(int32_t lang_idx);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,314 @@
|
||||
#undef main
|
||||
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <orbis/libkernel.h>
|
||||
#include <orbis/Sysmodule.h>
|
||||
#include <orbis/UserService.h>
|
||||
#include <orbis/SystemService.h>
|
||||
#include <orbis/Pad.h>
|
||||
#include <orbis/AudioOut.h>
|
||||
#include <orbis/Net.h>
|
||||
// #include <dbglogger.h>
|
||||
|
||||
#include "imgui.h"
|
||||
#include "SDL2/SDL.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include "imgui_impl_sdlrenderer.h"
|
||||
#include "config.h"
|
||||
#include "lang.h"
|
||||
#include "gui.h"
|
||||
#include "util.h"
|
||||
#include "installer.h"
|
||||
#include "rtc.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "orbis_jbc.h"
|
||||
}
|
||||
|
||||
#define FRAME_WIDTH 1920
|
||||
#define FRAME_HEIGHT 1080
|
||||
#define NET_HEAP_SIZE (5 * 1024 * 1024)
|
||||
|
||||
// SDL window and software renderer
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
|
||||
ImVec4 ColorFromBytes(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255)
|
||||
{
|
||||
return ImVec4((float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f);
|
||||
};
|
||||
|
||||
void InitImgui()
|
||||
{
|
||||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
(void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||
|
||||
// Setup Dear ImGui style
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
io.Fonts->Clear();
|
||||
io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;
|
||||
|
||||
static const ImWchar ranges[] = { // All languages with chinese included
|
||||
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||
0x0100, 0x024F, // Latin Extended
|
||||
0x0370, 0x03FF, // Greek
|
||||
0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
|
||||
0x0590, 0x05FF, // Hebrew
|
||||
0x1E00, 0x1EFF, // Latin Extended Additional
|
||||
0x1F00, 0x1FFF, // Greek Extended
|
||||
0x2000, 0x206F, // General Punctuation
|
||||
0x2100, 0x214F, // Letterlike Symbols
|
||||
0x2460, 0x24FF, // Enclosed Alphanumerics
|
||||
0x2DE0, 0x2DFF, // Cyrillic Extended-A
|
||||
0x2E80, 0x2EFF, // CJK Radicals Supplement
|
||||
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
||||
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
||||
0x3400, 0x4DBF, // CJK Rare
|
||||
0x4E00, 0x9FFF, // CJK Ideograms
|
||||
0xA640, 0xA69F, // Cyrillic Extended-B
|
||||
0xF900, 0xFAFF, // CJK Compatibility Ideographs
|
||||
0xFF00, 0xFFEF, // Half-width characters
|
||||
0,
|
||||
};
|
||||
|
||||
static const ImWchar arabic[] = { // Arabic
|
||||
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||
0x0100, 0x024F, // Latin Extended
|
||||
0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
|
||||
0x1E00, 0x1EFF, // Latin Extended Additional
|
||||
0x2000, 0x206F, // General Punctuation
|
||||
0x2100, 0x214F, // Letterlike Symbols
|
||||
0x2460, 0x24FF, // Enclosed Alphanumerics
|
||||
0x0600, 0x06FF, // Arabic
|
||||
0x0750, 0x077F, // Arabic Supplement
|
||||
0x0870, 0x089F, // Arabic Extended-B
|
||||
0x08A0, 0x08FF, // Arabic Extended-A
|
||||
0xFB50, 0xFDFF, // Arabic Presentation Forms-A
|
||||
0xFE70, 0xFEFF, // Arabic Presentation Forms-B
|
||||
0,
|
||||
};
|
||||
|
||||
std::string lang = std::string(language);
|
||||
int32_t lang_idx;
|
||||
sceSystemServiceParamGetInt( ORBIS_SYSTEM_SERVICE_PARAM_ID_LANG, &lang_idx );
|
||||
|
||||
lang = Util::Trim(lang, " ");
|
||||
if (lang.compare("Korean") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_KOREAN))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, io.Fonts->GetGlyphRangesKorean());
|
||||
}
|
||||
else if (lang.compare("Simplified Chinese") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_CHINESE_S))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
||||
}
|
||||
else if (lang.compare("Traditional Chinese") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_CHINESE_T))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesChineseFull());
|
||||
}
|
||||
else if (lang.compare("Japanese") == 0 || lang.compare("Ryukyuan") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_JAPANESE))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
|
||||
}
|
||||
else if (lang.compare("Thai") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_THAI))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, io.Fonts->GetGlyphRangesThai());
|
||||
}
|
||||
else if (lang.compare("Vietnamese") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_VIETNAMESE))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, io.Fonts->GetGlyphRangesVietnamese());
|
||||
}
|
||||
else if (lang.compare("Greek") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_GREEK))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, io.Fonts->GetGlyphRangesGreek());
|
||||
}
|
||||
else if (lang.compare("Arabic") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_ARABIC))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, arabic);
|
||||
}
|
||||
else
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto.ttf", 26.0f, NULL, ranges);
|
||||
}
|
||||
Lang::SetTranslation(lang_idx);
|
||||
|
||||
auto &style = ImGui::GetStyle();
|
||||
style.AntiAliasedLinesUseTex = false;
|
||||
style.AntiAliasedLines = true;
|
||||
style.AntiAliasedFill = true;
|
||||
style.WindowRounding = 1.0f;
|
||||
style.FrameRounding = 2.0f;
|
||||
style.GrabRounding = 2.0f;
|
||||
|
||||
ImVec4* colors = style.Colors;
|
||||
const ImVec4 bgColor = ColorFromBytes(37, 37, 38);
|
||||
const ImVec4 bgColorBlur = ColorFromBytes(37, 37, 38, 170);
|
||||
const ImVec4 lightBgColor = ColorFromBytes(82, 82, 85);
|
||||
const ImVec4 veryLightBgColor = ColorFromBytes(90, 90, 95);
|
||||
|
||||
const ImVec4 titleColor = ColorFromBytes(10, 100, 142);
|
||||
const ImVec4 panelColor = ColorFromBytes(51, 51, 55);
|
||||
const ImVec4 panelHoverColor = ColorFromBytes(29, 151, 236);
|
||||
const ImVec4 panelActiveColor = ColorFromBytes(0, 119, 200);
|
||||
|
||||
const ImVec4 textColor = ColorFromBytes(255, 255, 255);
|
||||
const ImVec4 textDisabledColor = ColorFromBytes(151, 151, 151);
|
||||
const ImVec4 borderColor = ColorFromBytes(78, 78, 78);
|
||||
|
||||
colors[ImGuiCol_Text] = textColor;
|
||||
colors[ImGuiCol_TextDisabled] = textDisabledColor;
|
||||
colors[ImGuiCol_TextSelectedBg] = panelActiveColor;
|
||||
colors[ImGuiCol_WindowBg] = bgColor;
|
||||
colors[ImGuiCol_ChildBg] = panelColor;
|
||||
colors[ImGuiCol_PopupBg] = bgColor;
|
||||
colors[ImGuiCol_Border] = borderColor;
|
||||
colors[ImGuiCol_BorderShadow] = borderColor;
|
||||
colors[ImGuiCol_FrameBg] = panelColor;
|
||||
colors[ImGuiCol_FrameBgHovered] = panelHoverColor;
|
||||
colors[ImGuiCol_FrameBgActive] = panelActiveColor;
|
||||
colors[ImGuiCol_TitleBg] = titleColor;
|
||||
colors[ImGuiCol_TitleBgActive] = titleColor;
|
||||
colors[ImGuiCol_TitleBgCollapsed] = titleColor;
|
||||
colors[ImGuiCol_MenuBarBg] = panelColor;
|
||||
colors[ImGuiCol_ScrollbarBg] = panelColor;
|
||||
colors[ImGuiCol_ScrollbarGrab] = lightBgColor;
|
||||
colors[ImGuiCol_ScrollbarGrabHovered] = veryLightBgColor;
|
||||
colors[ImGuiCol_ScrollbarGrabActive] = veryLightBgColor;
|
||||
colors[ImGuiCol_CheckMark] = panelActiveColor;
|
||||
colors[ImGuiCol_SliderGrab] = panelHoverColor;
|
||||
colors[ImGuiCol_SliderGrabActive] = panelActiveColor;
|
||||
colors[ImGuiCol_Button] = panelColor;
|
||||
colors[ImGuiCol_ButtonHovered] = panelHoverColor;
|
||||
colors[ImGuiCol_ButtonActive] = panelHoverColor;
|
||||
colors[ImGuiCol_Header] = panelColor;
|
||||
colors[ImGuiCol_HeaderHovered] = panelHoverColor;
|
||||
colors[ImGuiCol_HeaderActive] = panelActiveColor;
|
||||
colors[ImGuiCol_Separator] = borderColor;
|
||||
colors[ImGuiCol_SeparatorHovered] = borderColor;
|
||||
colors[ImGuiCol_SeparatorActive] = borderColor;
|
||||
colors[ImGuiCol_ResizeGrip] = bgColor;
|
||||
colors[ImGuiCol_ResizeGripHovered] = panelColor;
|
||||
colors[ImGuiCol_ResizeGripActive] = lightBgColor;
|
||||
colors[ImGuiCol_PlotLines] = panelActiveColor;
|
||||
colors[ImGuiCol_PlotLinesHovered] = panelHoverColor;
|
||||
colors[ImGuiCol_PlotHistogram] = panelActiveColor;
|
||||
colors[ImGuiCol_PlotHistogramHovered] = panelHoverColor;
|
||||
colors[ImGuiCol_ModalWindowDimBg] = bgColorBlur;
|
||||
colors[ImGuiCol_DragDropTarget] = bgColor;
|
||||
colors[ImGuiCol_NavHighlight] = bgColor;
|
||||
colors[ImGuiCol_Tab] = bgColor;
|
||||
colors[ImGuiCol_TabActive] = panelActiveColor;
|
||||
colors[ImGuiCol_TabUnfocused] = bgColor;
|
||||
colors[ImGuiCol_TabUnfocusedActive] = panelActiveColor;
|
||||
colors[ImGuiCol_TabHovered] = panelHoverColor;
|
||||
}
|
||||
|
||||
static void terminate()
|
||||
{
|
||||
INSTALLER::Exit();
|
||||
terminate_jbc();
|
||||
sceSystemServiceLoadExec("exit", NULL);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// dbglogger_init();
|
||||
// dbglogger_log("If you see this you've set up dbglogger correctly.");
|
||||
int rc;
|
||||
// No buffering
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// load common modules
|
||||
int ret = sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_SYSTEM_SERVICE);
|
||||
if (ret < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_USER_SERVICE);
|
||||
if (ret < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_BGFT);
|
||||
if (ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_APP_INST_UTIL);
|
||||
if (ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_PAD) < 0)
|
||||
return 0;
|
||||
|
||||
if (sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_AUDIOOUT) < 0 ||
|
||||
sceAudioOutInit() != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_IME_DIALOG) < 0)
|
||||
return 0;
|
||||
|
||||
if(sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_NET) < 0 || sceNetInit() != 0)
|
||||
return 0;
|
||||
|
||||
sceNetPoolCreate("simple", NET_HEAP_SIZE, 0);
|
||||
|
||||
if (INSTALLER::Init() < 0)
|
||||
return 0;
|
||||
|
||||
CONFIG::LoadConfig();
|
||||
|
||||
// Create a window context
|
||||
window = SDL_CreateWindow("main", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, FRAME_WIDTH, FRAME_HEIGHT, 0);
|
||||
if (window == NULL)
|
||||
return 0;
|
||||
|
||||
renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||
if (renderer == NULL)
|
||||
return 0;
|
||||
|
||||
InitImgui();
|
||||
|
||||
// Setup Platform/Renderer backends
|
||||
ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
|
||||
ImGui_ImplSDLRenderer_Init(renderer);
|
||||
ImGui_ImplSDLRenderer_CreateFontsTexture();
|
||||
ImGui_ImplSDL2_DisableButton(SDL_CONTROLLER_BUTTON_X, true);
|
||||
|
||||
if (!initialize_jbc())
|
||||
{
|
||||
terminate();
|
||||
}
|
||||
|
||||
if (load_rtc_module() != 0)
|
||||
return 0;
|
||||
|
||||
atexit(terminate);
|
||||
|
||||
GUI::RenderLoop(renderer);
|
||||
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
ImGui::DestroyContext();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <orbis/libkernel.h>
|
||||
#include <libjbc.h>
|
||||
|
||||
// Variables for (un)jailbreaking
|
||||
jbc_cred g_Cred;
|
||||
jbc_cred g_RootCreds;
|
||||
|
||||
// Verify jailbreak
|
||||
static int is_jailbroken()
|
||||
{
|
||||
FILE *s_FilePointer = fopen("/user/.jailbreak", "w");
|
||||
|
||||
if (!s_FilePointer)
|
||||
return 0;
|
||||
|
||||
fclose(s_FilePointer);
|
||||
remove("/user/.jailbreak");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Jailbreaks creds
|
||||
static int jailbreak()
|
||||
{
|
||||
if (is_jailbroken())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
jbc_get_cred(&g_Cred);
|
||||
g_RootCreds = g_Cred;
|
||||
jbc_jailbreak_cred(&g_RootCreds);
|
||||
jbc_set_cred(&g_RootCreds);
|
||||
|
||||
return (is_jailbroken());
|
||||
}
|
||||
|
||||
// Initialize jailbreak
|
||||
int initialize_jbc()
|
||||
{
|
||||
// Pop notification depending on jailbreak result
|
||||
if (!jailbreak())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Unload libjbc libraries
|
||||
void terminate_jbc()
|
||||
{
|
||||
if (!is_jailbroken())
|
||||
return;
|
||||
|
||||
// Restores original creds
|
||||
jbc_set_cred(&g_Cred);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef __ORBIS_JBC_H__
|
||||
#define __ORBIS_JBC_H__
|
||||
|
||||
int initialize_jbc();
|
||||
void terminate_jbc();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* pugixml parser - version 1.13
|
||||
* --------------------------------------------------------
|
||||
* Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||
* Report bugs and download new versions at https://pugixml.org/
|
||||
*
|
||||
* This library is distributed under the MIT License. See notice at the end
|
||||
* of this file.
|
||||
*
|
||||
* This work is based on the pugxml parser, which is:
|
||||
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||
*/
|
||||
|
||||
#ifndef HEADER_PUGICONFIG_HPP
|
||||
#define HEADER_PUGICONFIG_HPP
|
||||
|
||||
// Uncomment this to enable wchar_t mode
|
||||
// #define PUGIXML_WCHAR_MODE
|
||||
|
||||
// Uncomment this to enable compact mode
|
||||
// #define PUGIXML_COMPACT
|
||||
|
||||
// Uncomment this to disable XPath
|
||||
// #define PUGIXML_NO_XPATH
|
||||
|
||||
// Uncomment this to disable STL
|
||||
// #define PUGIXML_NO_STL
|
||||
|
||||
// Uncomment this to disable exceptions
|
||||
// #define PUGIXML_NO_EXCEPTIONS
|
||||
|
||||
// Set this to control attributes for public classes/functions, i.e.:
|
||||
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||
|
||||
// Tune these constants to adjust memory-related behavior
|
||||
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||
|
||||
// Tune this constant to adjust max nesting for XPath queries
|
||||
// #define PUGIXML_XPATH_DEPTH_LIMIT 1024
|
||||
|
||||
// Uncomment this to switch to header-only version
|
||||
// #define PUGIXML_HEADER_ONLY
|
||||
|
||||
// Uncomment this to enable long long support
|
||||
// #define PUGIXML_HAS_LONG_LONG
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Copyright (c) 2006-2022 Arseny Kapoulkine
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef REMOTECLIENT_H
|
||||
#define REMOTECLIENT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common.h"
|
||||
|
||||
enum ClientType
|
||||
{
|
||||
CLIENT_TYPE_FTP, CLIENT_TYPE_SMB, CLIENT_TYPE_WEBDAV
|
||||
};
|
||||
|
||||
class RemoteClient
|
||||
{
|
||||
public:
|
||||
RemoteClient(){};
|
||||
virtual ~RemoteClient(){};
|
||||
virtual int Connect(const std::string &url, const std::string &username, const std::string &password) = 0;
|
||||
virtual int Mkdir(const std::string &path) = 0;
|
||||
virtual int Rmdir(const std::string &path, bool recursive) = 0;
|
||||
virtual int Size(const std::string &path, int64_t *size) = 0;
|
||||
virtual int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0) = 0;
|
||||
virtual int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0) = 0;
|
||||
virtual int Rename(const std::string &src, const std::string &dst) = 0;
|
||||
virtual int Delete(const std::string &path) = 0;
|
||||
virtual bool FileExists(const std::string &path) = 0;
|
||||
virtual std::vector<DirEntry> ListDir(const std::string &path) = 0;
|
||||
virtual std::string GetPath(std::string path1, std::string path2) = 0;
|
||||
virtual bool IsConnected() = 0;
|
||||
virtual bool Ping() = 0;
|
||||
virtual const char *LastResponse() = 0;
|
||||
virtual int Quit() = 0;
|
||||
virtual ClientType clientType() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <stdlib.h>
|
||||
#include <orbis/libkernel.h>
|
||||
#include <orbis/Sysmodule.h>
|
||||
|
||||
#include "rtc.h"
|
||||
|
||||
int (*sceRtcGetTick)(const OrbisDateTime *inOrbisDateTime, OrbisTick *outTick);
|
||||
int (*sceRtcSetTick)(OrbisDateTime *outOrbisDateTime, const OrbisTick *inputTick);
|
||||
int (*sceRtcConvertLocalTimeToUtc)(const OrbisTick *local_time, OrbisTick *utc);
|
||||
int (*sceRtcConvertUtcToLocalTime)(const OrbisTick *utc, OrbisTick *local_time);
|
||||
int (*sceRtcGetCurrentClockLocalTime)(OrbisDateTime *time);
|
||||
|
||||
void convertUtcToLocalTime(const OrbisDateTime *utc, OrbisDateTime *local_time)
|
||||
{
|
||||
OrbisTick utc_tick;
|
||||
OrbisTick local_tick;
|
||||
sceRtcGetTick(utc, &utc_tick);
|
||||
sceRtcConvertUtcToLocalTime(&utc_tick, &local_tick);
|
||||
sceRtcSetTick(local_time, &local_tick);
|
||||
}
|
||||
|
||||
void convertLocalTimeToUtc(const OrbisDateTime *local_time, OrbisDateTime *utc)
|
||||
{
|
||||
OrbisTick utc_tick;
|
||||
OrbisTick local_tick;
|
||||
sceRtcGetTick(local_time, &local_tick);
|
||||
sceRtcConvertLocalTimeToUtc(&local_tick, &utc_tick);
|
||||
sceRtcSetTick(utc, &utc_tick);
|
||||
}
|
||||
|
||||
int load_rtc_module()
|
||||
{
|
||||
int rtc_handle = sceKernelLoadStartModule("/system/common/lib/libSceRtc.sprx", 0, NULL, 0, NULL, NULL);
|
||||
if (rtc_handle == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(rtc_handle, "sceRtcGetTick", (void **)&sceRtcGetTick);
|
||||
if (sceRtcGetTick == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(rtc_handle, "sceRtcSetTick", (void **)&sceRtcSetTick);
|
||||
if (sceRtcSetTick == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(rtc_handle, "sceRtcConvertLocalTimeToUtc", (void **)&sceRtcConvertLocalTimeToUtc);
|
||||
if (sceRtcConvertLocalTimeToUtc == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(rtc_handle, "sceRtcConvertUtcToLocalTime", (void **)&sceRtcConvertUtcToLocalTime);
|
||||
if (sceRtcConvertUtcToLocalTime == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(rtc_handle, "sceRtcGetCurrentClockLocalTime", (void **)&sceRtcGetCurrentClockLocalTime);
|
||||
if (sceRtcGetCurrentClockLocalTime == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct OrbisTick {
|
||||
uint64_t mytick;
|
||||
} OrbisTick;
|
||||
|
||||
typedef struct OrbisDateTime {
|
||||
unsigned short year;
|
||||
unsigned short month;
|
||||
unsigned short day;
|
||||
unsigned short hour;
|
||||
unsigned short minute;
|
||||
unsigned short second;
|
||||
unsigned int microsecond;
|
||||
} OrbisDateTime;
|
||||
|
||||
extern int (*sceRtcGetTick)(const OrbisDateTime *inOrbisDateTime, OrbisTick *outTick);
|
||||
extern int (*sceRtcSetTick)(OrbisDateTime *outOrbisDateTime, const OrbisTick *inputTick);
|
||||
extern int (*sceRtcConvertLocalTimeToUtc)(const OrbisTick *local_time, OrbisTick *utc);
|
||||
extern int (*sceRtcConvertUtcToLocalTime)(const OrbisTick *utc, OrbisTick *local_time);
|
||||
extern int (*sceRtcGetCurrentClockLocalTime)(OrbisDateTime *time) ;
|
||||
|
||||
int load_rtc_module();
|
||||
void convertUtcToLocalTime(const OrbisDateTime *utc, OrbisDateTime *local_time);
|
||||
void convertLocalTimeToUtc(const OrbisDateTime *local_time, OrbisDateTime *utc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,515 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <orbis/Net.h>
|
||||
#include "fs.h"
|
||||
#include "lang.h"
|
||||
#include "smbclient.h"
|
||||
#include "windows.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
|
||||
|
||||
SmbClient::SmbClient()
|
||||
{
|
||||
}
|
||||
|
||||
SmbClient::~SmbClient()
|
||||
{
|
||||
}
|
||||
|
||||
int SmbClient::Connect(const std::string &url, const std::string &user, const std::string &pass)
|
||||
{
|
||||
struct smb2_url *smb_url;
|
||||
|
||||
smb2 = smb2_init_context();
|
||||
if (smb2 == NULL)
|
||||
{
|
||||
sprintf(response, "Failed to init SMB context");
|
||||
return 0;
|
||||
}
|
||||
smb_url = smb2_parse_url(smb2, url.c_str());
|
||||
if (pass.length() > 0)
|
||||
smb2_set_password(smb2, pass.c_str());
|
||||
smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED);
|
||||
smb2_set_timeout(smb2, 30);
|
||||
|
||||
if (smb2_connect_share(smb2, smb_url->server, smb_url->share, user.c_str()) < 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
smb2_destroy_url(smb_url);
|
||||
max_read_size = smb2_get_max_read_size(smb2);
|
||||
max_write_size = smb2_get_max_write_size(smb2);
|
||||
connected = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SmbLastResponse - return a pointer to the last response received
|
||||
*/
|
||||
const char *SmbClient::LastResponse()
|
||||
{
|
||||
return (const char *)response;
|
||||
}
|
||||
|
||||
/*
|
||||
* IsConnected - return true if connected to remote
|
||||
*/
|
||||
bool SmbClient::IsConnected()
|
||||
{
|
||||
return connected;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ping - return true if connected to remote
|
||||
*/
|
||||
bool SmbClient::Ping()
|
||||
{
|
||||
connected = smb2_echo(smb2) == 0;
|
||||
return connected;
|
||||
}
|
||||
|
||||
/*
|
||||
* SmbQuit - disconnect from remote
|
||||
*
|
||||
* return 1 if successful, 0 otherwise
|
||||
*/
|
||||
int SmbClient::Quit()
|
||||
{
|
||||
smb2_destroy_context(smb2);
|
||||
smb2 = NULL;
|
||||
connected = false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SmbMkdir - create a directory at server
|
||||
*
|
||||
* return 1 if successful, 0 otherwise
|
||||
*/
|
||||
int SmbClient::Mkdir(const std::string &ppath)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
if (smb2_mkdir(smb2, path.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SmbRmdir - remove directory and all files under directory at remote
|
||||
*
|
||||
* return 1 if successful, 0 otherwise
|
||||
*/
|
||||
int SmbClient::_Rmdir(const std::string &ppath)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
if (smb2_rmdir(smb2, path.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SmbRmdir - remove directory and all files under directory at remote
|
||||
*
|
||||
* return 1 if successful, 0 otherwise
|
||||
*/
|
||||
int SmbClient::Rmdir(const std::string &path, bool recursive)
|
||||
{
|
||||
if (stop_activity)
|
||||
return 1;
|
||||
|
||||
std::vector<DirEntry> list = ListDir(path);
|
||||
int ret;
|
||||
for (int i = 0; i < list.size(); i++)
|
||||
{
|
||||
if (stop_activity)
|
||||
return 1;
|
||||
|
||||
if (list[i].isDir && recursive)
|
||||
{
|
||||
if (strcmp(list[i].name, "..") == 0)
|
||||
continue;
|
||||
ret = Rmdir(list[i].path, recursive);
|
||||
if (ret == 0)
|
||||
{
|
||||
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], list[i].path);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(activity_message, "%s %s\n", lang_strings[STR_DELETING], list[i].path);
|
||||
ret = Delete(list[i].path);
|
||||
if (ret == 0)
|
||||
{
|
||||
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], list[i].path);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = _Rmdir(path);
|
||||
if (ret == 0)
|
||||
{
|
||||
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], path.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SmbGet - issue a GET command and write received data to output
|
||||
*
|
||||
* return 1 if successful, 0 otherwise
|
||||
*/
|
||||
|
||||
int SmbClient::Get(const std::string &outputfile, const std::string &ppath, uint64_t offset)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
if (!Size(path.c_str(), &bytes_to_download))
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smb2fh* in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
if (in == NULL)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE* out = FS::Create(outputfile);
|
||||
if (out == NULL)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *buff = (uint8_t*)malloc(max_read_size);
|
||||
int count = 0;
|
||||
bytes_transfered = 0;
|
||||
while ((count = smb2_read(smb2, in, buff, max_read_size)) > 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
FS::Close(out);
|
||||
smb2_close(smb2, in);
|
||||
free((void*)buff);
|
||||
return 0;
|
||||
}
|
||||
FS::Write(out, buff, count);
|
||||
bytes_transfered += count;
|
||||
}
|
||||
FS::Close(out);
|
||||
smb2_close(smb2, in);
|
||||
free((void*)buff);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SmbClient::Copy(const std::string &ppath, int socket_fd)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
if (!IsConnected())
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smb2fh* in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
if (in == NULL)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *buff = (uint8_t*)malloc(max_read_size);
|
||||
int count = 0;
|
||||
while ((count = smb2_read(smb2, in, buff, max_read_size)) > 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
smb2_close(smb2, in);
|
||||
free((void*)buff);
|
||||
return 0;
|
||||
}
|
||||
int ret = sceNetSend(socket_fd, buff, count, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
smb2_close(smb2, in);
|
||||
free((void*)buff);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool SmbClient::FileExists(const std::string &ppath)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
smb2_stat_64 st;
|
||||
int ret = smb2_stat(smb2, path.c_str(), &st);
|
||||
if (ret != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* SmbPut - issue a PUT command and send data from input
|
||||
*
|
||||
* return 1 if successful, 0 otherwise
|
||||
*/
|
||||
int SmbClient::Put(const std::string &inputfile, const std::string &ppath, uint64_t offset)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
|
||||
bytes_to_download = FS::GetSize(inputfile);
|
||||
if (bytes_to_download < 0)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE* in = FS::OpenRead(inputfile);
|
||||
if (in == NULL)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smb2fh* out = smb2_open(smb2, path.c_str(), O_WRONLY | O_CREAT | O_TRUNC);
|
||||
if (out == NULL)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* buff = (uint8_t*)malloc(max_write_size);
|
||||
int count = 0;
|
||||
bytes_transfered = 0;
|
||||
while ((count = FS::Read(in, buff, max_write_size)) > 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
FS::Close(in);
|
||||
smb2_close(smb2, out);
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
smb2_write(smb2, out, buff, count);
|
||||
bytes_transfered += count;
|
||||
}
|
||||
FS::Close(in);
|
||||
smb2_close(smb2, out);
|
||||
free(buff);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int SmbClient::Rename(const std::string &src, const std::string &dst)
|
||||
{
|
||||
std::string path1 = std::string(src);
|
||||
std::string path2 = std::string(dst);
|
||||
path1 = Util::Trim(path1, "/");
|
||||
path2 = Util::Trim(path2, "/");
|
||||
if (smb2_rename(smb2, path1.c_str(), path2.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SmbClient::Delete(const std::string &ppath)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
if (smb2_unlink(smb2, path.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SmbClient::Size(const std::string &ppath, int64_t *size)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
smb2_stat_64 st;
|
||||
if (smb2_stat(smb2, path.c_str(), &st) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
*size = st.smb2_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<DirEntry> SmbClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
if (path.length() > 1 && path[path.length() - 1] == '/')
|
||||
{
|
||||
strlcpy(entry.directory, path.c_str(), path.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
}
|
||||
sprintf(entry.name, "..");
|
||||
sprintf(entry.path, "%s", entry.directory);
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
entry.file_size = 0;
|
||||
entry.isDir = true;
|
||||
out.push_back(entry);
|
||||
|
||||
struct smb2dir *dir;
|
||||
struct smb2dirent *ent;
|
||||
|
||||
std::string ppath = std::string(path);
|
||||
dir = smb2_opendir(smb2, Util::Ltrim(ppath, "/").c_str());
|
||||
if (dir == NULL)
|
||||
{
|
||||
sprintf(status_message, "%s - %s", lang_strings[STR_FAIL_READ_LOCAL_DIR_MSG], smb2_get_error(smb2));
|
||||
return out;
|
||||
}
|
||||
|
||||
while ((ent = smb2_readdir(smb2, dir)))
|
||||
{
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
|
||||
snprintf(entry.directory, 511, "%s", path.c_str());
|
||||
snprintf(entry.name, 255, "%s", ent->name);
|
||||
entry.file_size = ent->st.smb2_size;
|
||||
if (path.length() > 0 && path[path.length() - 1] == '/')
|
||||
{
|
||||
sprintf(entry.path, "%s%s", path.c_str(), ent->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.path, "%s/%s", path.c_str(), ent->name);
|
||||
}
|
||||
|
||||
time_t t = (time_t)ent->st.smb2_mtime;
|
||||
struct tm tm = *localtime(&t);
|
||||
entry.modified.day = tm.tm_mday;
|
||||
entry.modified.month = tm.tm_mon + 1;
|
||||
entry.modified.year = tm.tm_year + 1900;
|
||||
entry.modified.hours = tm.tm_hour;
|
||||
entry.modified.minutes = tm.tm_min;
|
||||
entry.modified.seconds = tm.tm_sec;
|
||||
|
||||
switch (ent->st.smb2_type)
|
||||
{
|
||||
case SMB2_TYPE_LINK:
|
||||
entry.isLink = true;
|
||||
entry.file_size = 0;
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_LINK]);
|
||||
break;
|
||||
case SMB2_TYPE_FILE:
|
||||
if (entry.file_size < 1024)
|
||||
{
|
||||
sprintf(entry.display_size, "%ldB", entry.file_size);
|
||||
}
|
||||
else if (entry.file_size < 1024 * 1024)
|
||||
{
|
||||
sprintf(entry.display_size, "%.2fKB", entry.file_size * 1.0f / 1024);
|
||||
}
|
||||
else if (entry.file_size < 1024 * 1024 * 1024)
|
||||
{
|
||||
sprintf(entry.display_size, "%.2fMB", entry.file_size * 1.0f / (1024 * 1024));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.display_size, "%.2fGB", entry.file_size * 1.0f / (1024 * 1024 * 1024));
|
||||
}
|
||||
break;
|
||||
case SMB2_TYPE_DIRECTORY:
|
||||
entry.isDir = true;
|
||||
entry.file_size = 0;
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
break;
|
||||
}
|
||||
if (strcmp(entry.name, "..") != 0 && strcmp(entry.name, ".") != 0)
|
||||
out.push_back(entry);
|
||||
}
|
||||
smb2_closedir(smb2, dir);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string SmbClient::GetPath(std::string ppath1, std::string ppath2)
|
||||
{
|
||||
std::string path1 = ppath1;
|
||||
std::string path2 = ppath2;
|
||||
path1 = Util::Rtrim(Util::Trim(path1, " "), "/");
|
||||
path2 = Util::Rtrim(Util::Trim(path2, " "), "/");
|
||||
path1 = path1 + "/" + path2;
|
||||
return Util::Ltrim(path1, "/");
|
||||
}
|
||||
|
||||
int SmbClient::Head(const std::string &ppath, void* buffer, uint16_t len)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
if (!Size(path.c_str(), &bytes_to_download))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smb2fh* in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
if (in == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = smb2_read(smb2, in, (uint8_t*)buffer, len);
|
||||
smb2_close(smb2, in);
|
||||
if (count != len)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ClientType SmbClient::clientType()
|
||||
{
|
||||
return CLIENT_TYPE_SMB;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef SMBCLIENT_H
|
||||
#define SMBCLIENT_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <smb2/smb2.h>
|
||||
#include <smb2/libsmb2.h>
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
#define SMB_CLIENT_MAX_FILENAME_LEN 256
|
||||
|
||||
class SmbClient : public RemoteClient
|
||||
{
|
||||
public:
|
||||
SmbClient();
|
||||
~SmbClient();
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
|
||||
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
int Delete(const std::string &path);
|
||||
bool FileExists(const std::string &path);
|
||||
int Copy(const std::string &path, int socket_fd);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
bool IsConnected();
|
||||
bool Ping();
|
||||
const char *LastResponse();
|
||||
int Quit();
|
||||
std::string GetPath(std::string ppath1, std::string ppath2);
|
||||
int Head(const std::string &path, void* buffer, uint16_t len);
|
||||
ClientType clientType();
|
||||
|
||||
private:
|
||||
int _Rmdir(const std::string &path);
|
||||
struct smb2_context *smb2;
|
||||
char response[1024];
|
||||
bool connected = false;
|
||||
uint32_t max_read_size = 0;
|
||||
uint32_t max_write_size = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdarg.h>
|
||||
#include <orbis/libkernel.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
static inline std::string &Ltrim(std::string &str, std::string chars)
|
||||
{
|
||||
str.erase(0, str.find_first_not_of(chars));
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline std::string &Rtrim(std::string &str, std::string chars)
|
||||
{
|
||||
str.erase(str.find_last_not_of(chars) + 1);
|
||||
return str;
|
||||
}
|
||||
|
||||
// trim from both ends (in place)
|
||||
static inline std::string &Trim(std::string &str, std::string chars)
|
||||
{
|
||||
return Ltrim(Rtrim(str, chars), chars);
|
||||
}
|
||||
|
||||
static inline void ReplaceAll(std::string &data, std::string toSearch, std::string replaceStr)
|
||||
{
|
||||
size_t pos = data.find(toSearch);
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
data.replace(pos, toSearch.size(), replaceStr);
|
||||
pos = data.find(toSearch, pos + replaceStr.size());
|
||||
}
|
||||
}
|
||||
|
||||
static inline std::string ToLower(std::string s)
|
||||
{
|
||||
std::transform(s.begin(), s.end(), s.begin(),
|
||||
[](unsigned char c)
|
||||
{ return std::tolower(c); });
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline void Notify(const char *fmt, ...)
|
||||
{
|
||||
OrbisNotificationRequest request;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsprintf(request.message, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
request.type = OrbisNotificationRequestType::NotificationRequest;
|
||||
request.unk3 = 0;
|
||||
request.useIconImageUri = 0;
|
||||
request.targetId = -1;
|
||||
sceKernelSendNotificationRequest(0, &request, sizeof(request), 0);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
/*#***************************************************************************
|
||||
# __ __ _____ _____
|
||||
# Project | | | | | \ / ___|
|
||||
# | |__| | | |\ \ / /
|
||||
# | | | | ) ) ( (
|
||||
# | /\ | | |/ / \ \___
|
||||
# \_/ \_/ |_____/ \_____|
|
||||
#
|
||||
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file LICENSE, which
|
||||
# you should have received as part of this distribution.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the LICENSE file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
############################################################################*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
#include "callback.hpp"
|
||||
|
||||
namespace WebDAV
|
||||
{
|
||||
namespace Callback
|
||||
{
|
||||
namespace Read
|
||||
{
|
||||
size_t stream(char* ptr, size_t item_size, size_t item_count, void* stream)
|
||||
{
|
||||
auto in_stream = reinterpret_cast<std::istream*>(stream);
|
||||
auto read_bytes = static_cast<unsigned long long>(item_size * item_count);
|
||||
auto position = static_cast<unsigned long long>(in_stream->tellg());
|
||||
in_stream->seekg(0, std::ios::end);
|
||||
auto size = static_cast<unsigned long long>(in_stream->tellg());
|
||||
in_stream->seekg(position, std::ios::beg);
|
||||
auto rest_bytes = size - position;
|
||||
read_bytes = std::min<unsigned long long>(read_bytes, rest_bytes);
|
||||
in_stream->read(ptr, read_bytes);
|
||||
return read_bytes;
|
||||
}
|
||||
|
||||
size_t buffer(char* ptr, size_t item_size, size_t item_count, void* buffer)
|
||||
{
|
||||
auto data = (Data*)buffer;
|
||||
auto size = static_cast<unsigned long long>(item_size * item_count);
|
||||
auto rest_bytes = data->size - data->position;
|
||||
auto copied_bytes = std::min<unsigned long long>(size, rest_bytes);
|
||||
memcpy(ptr, data->buffer, copied_bytes);
|
||||
data->position += copied_bytes;
|
||||
return copied_bytes;
|
||||
}
|
||||
} // namespace Read
|
||||
|
||||
namespace Write
|
||||
{
|
||||
size_t stream(char* ptr, size_t item_size, size_t item_count, void* stream)
|
||||
{
|
||||
auto out_stream = reinterpret_cast<std::ostream*>(stream);
|
||||
size_t write_bytes = item_size * item_count;
|
||||
out_stream->write(ptr, write_bytes);
|
||||
return write_bytes;
|
||||
}
|
||||
|
||||
size_t buffer(char* ptr, size_t item_size, size_t item_count, void* buffer)
|
||||
{
|
||||
auto data = reinterpret_cast<Data*>(buffer);
|
||||
auto size = static_cast<unsigned long long>(item_size * item_count);
|
||||
auto rest_bytes = data->size - data->position;
|
||||
auto copied_bytes = std::min<unsigned long long>(size, rest_bytes);
|
||||
memcpy(data->buffer, ptr, copied_bytes);
|
||||
data->position += copied_bytes;
|
||||
return copied_bytes;
|
||||
}
|
||||
} // namespace Write
|
||||
|
||||
namespace Append
|
||||
{
|
||||
size_t buffer(char* ptr, size_t item_size, size_t item_count, void* buffer)
|
||||
{
|
||||
auto data = reinterpret_cast<Data*>(buffer);
|
||||
auto append_size = item_size * item_count;
|
||||
auto new_buffer_size = data->size + append_size;
|
||||
auto new_buffer = new char[new_buffer_size];
|
||||
if (data->size != 0) memcpy(new_buffer, data->buffer, data->size);
|
||||
memcpy(new_buffer + data->size, ptr, append_size);
|
||||
delete[] data->buffer;
|
||||
data->buffer = new_buffer;
|
||||
data->size = new_buffer_size;
|
||||
return append_size;
|
||||
}
|
||||
|
||||
size_t stream(char* ptr, size_t item_size, size_t item_count, void* stream)
|
||||
{
|
||||
auto out_stream = reinterpret_cast<std::ostream*>(stream);
|
||||
size_t write_bytes = item_size * item_count;
|
||||
out_stream->seekp(0, std::ios::end);
|
||||
out_stream->write(ptr, write_bytes);
|
||||
return write_bytes;
|
||||
}
|
||||
} // namespace Append
|
||||
} // namespace Callback
|
||||
} // namespace WebDAV
|
||||
@@ -0,0 +1,67 @@
|
||||
/*#***************************************************************************
|
||||
# __ __ _____ _____
|
||||
# Project | | | | | \ / ___|
|
||||
# | |__| | | |\ \ / /
|
||||
# | | | | ) ) ( (
|
||||
# | /\ | | |/ / \ \___
|
||||
# \_/ \_/ |_____/ \_____|
|
||||
#
|
||||
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file LICENSE, which
|
||||
# you should have received as part of this distribution.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the LICENSE file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
############################################################################*/
|
||||
|
||||
#ifndef WEBDAV_CALLBACK_HPP
|
||||
#define WEBDAV_CALLBACK_HPP
|
||||
|
||||
namespace WebDAV
|
||||
{
|
||||
struct Data
|
||||
{
|
||||
char* buffer;
|
||||
unsigned long long position;
|
||||
unsigned long long size;
|
||||
void reset()
|
||||
{
|
||||
buffer = nullptr;
|
||||
position = 0;
|
||||
size = 0;
|
||||
}
|
||||
~Data()
|
||||
{
|
||||
delete[] buffer;
|
||||
}
|
||||
};
|
||||
|
||||
namespace Callback
|
||||
{
|
||||
namespace Read
|
||||
{
|
||||
size_t stream(char* data, size_t size, size_t count, void* stream);
|
||||
size_t buffer(char* data, size_t size, size_t count, void* buffer);
|
||||
}
|
||||
|
||||
namespace Write
|
||||
{
|
||||
size_t stream(char* data, size_t size, size_t count, void* stream);
|
||||
size_t buffer(char* data, size_t size, size_t count, void* buffer);
|
||||
}
|
||||
|
||||
namespace Append
|
||||
{
|
||||
size_t stream(char* data, size_t size, size_t count, void* stream);
|
||||
size_t buffer(char* data, size_t size, size_t count, void* buffer);
|
||||
}
|
||||
}
|
||||
} // namespace WebDAV
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,975 @@
|
||||
/*#***************************************************************************
|
||||
# __ __ _____ _____
|
||||
# Project | | | | | \ / ___|
|
||||
# | |__| | | |\ \ / /
|
||||
# | | | | ) ) ( (
|
||||
# | /\ | | |/ / \ \___
|
||||
# \_/ \_/ |_____/ \_____|
|
||||
#
|
||||
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file LICENSE, which
|
||||
# you should have received as part of this distribution.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the LICENSE file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
############################################################################*/
|
||||
|
||||
#include <client.hpp>
|
||||
|
||||
#include "callback.hpp"
|
||||
#include "fsinfo.hpp"
|
||||
#include "header.hpp"
|
||||
#include "pugiext.hpp"
|
||||
#include "request.hpp"
|
||||
#include "urn.hpp"
|
||||
#include "util.h"
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
|
||||
namespace WebDAV
|
||||
{
|
||||
using Urn::Path;
|
||||
|
||||
using progress_funptr = int (*)(void *context, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
|
||||
|
||||
static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata)
|
||||
{
|
||||
std::string header(reinterpret_cast<char *>(buffer), size * nitems);
|
||||
dict_t *headers = (dict_t *)userdata;
|
||||
size_t seperator = header.find_first_of(":");
|
||||
|
||||
if (seperator != std::string::npos)
|
||||
{
|
||||
std::string key = header.substr(0, seperator);
|
||||
key = Util::Trim(key, " ");
|
||||
key = Util::ToLower(key);
|
||||
std::string value = header.substr(seperator + 1);
|
||||
value = Util::Trim(value, " ");
|
||||
headers->erase(key);
|
||||
headers->insert(std::make_pair(key, value));
|
||||
}
|
||||
|
||||
return (size * nitems);
|
||||
}
|
||||
|
||||
dict_t
|
||||
Client::options()
|
||||
{
|
||||
return dict_t{
|
||||
{"webdav_hostname", this->webdav_hostname},
|
||||
{"webdav_root", this->webdav_root},
|
||||
{"webdav_username", this->webdav_username},
|
||||
{"webdav_password", this->webdav_password},
|
||||
{"proxy_hostname", this->proxy_hostname},
|
||||
{"proxy_username", this->proxy_username},
|
||||
{"proxy_password", this->proxy_password},
|
||||
{"cert_path", this->cert_path},
|
||||
{"key_path", this->key_path},
|
||||
};
|
||||
}
|
||||
|
||||
long
|
||||
Client::status_code()
|
||||
{
|
||||
return this->http_code;
|
||||
}
|
||||
|
||||
bool
|
||||
Client::sync_download(
|
||||
const std::string &remote_file,
|
||||
const std::string &local_file,
|
||||
callback_t callback,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
bool is_existed = this->check(remote_file);
|
||||
if (!is_existed)
|
||||
return false;
|
||||
|
||||
auto root_urn = Path(this->webdav_root, true);
|
||||
auto file_urn = root_urn + remote_file;
|
||||
|
||||
std::ofstream file_stream(local_file, std::ios::binary);
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + file_urn.quote(request.handle);
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "GET");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HEADER, 0L);
|
||||
request.set(CURLOPT_WRITEDATA, reinterpret_cast<size_t>(&file_stream));
|
||||
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Callback::Write::stream));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
if (progress != nullptr)
|
||||
{
|
||||
request.set(CURLOPT_XFERINFODATA, progress_data);
|
||||
request.set(CURLOPT_XFERINFOFUNCTION, progress);
|
||||
request.set(CURLOPT_NOPROGRESS, 0L);
|
||||
}
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
|
||||
if (callback != nullptr)
|
||||
callback(is_performed);
|
||||
return is_performed;
|
||||
}
|
||||
|
||||
bool
|
||||
Client::sync_download_to(
|
||||
const std::string &remote_file,
|
||||
char *&buffer_ptr,
|
||||
unsigned long long &buffer_size,
|
||||
callback_t callback,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
bool is_existed = this->check(remote_file);
|
||||
if (!is_existed)
|
||||
return false;
|
||||
|
||||
auto root_urn = Path(this->webdav_root, true);
|
||||
auto file_urn = root_urn + remote_file;
|
||||
|
||||
Data data = {nullptr, 0, 0};
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + file_urn.quote(request.handle);
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "GET");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HEADER, 0L);
|
||||
request.set(CURLOPT_WRITEDATA, reinterpret_cast<size_t>(&data));
|
||||
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Callback::Append::buffer));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
if (progress != nullptr)
|
||||
{
|
||||
request.set(CURLOPT_XFERINFODATA, progress_data);
|
||||
request.set(CURLOPT_XFERINFOFUNCTION, progress);
|
||||
request.set(CURLOPT_NOPROGRESS, 0L);
|
||||
}
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
|
||||
if (callback != nullptr)
|
||||
callback(is_performed);
|
||||
if (!is_performed)
|
||||
return false;
|
||||
|
||||
buffer_ptr = data.buffer;
|
||||
buffer_size = data.size;
|
||||
data.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Client::sync_download_range_to(
|
||||
const std::string &remote_file,
|
||||
char *&buffer_ptr,
|
||||
unsigned long long &buffer_size,
|
||||
uint64_t range_from,
|
||||
uint64_t range_to,
|
||||
callback_t callback,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
bool is_existed = this->check(remote_file);
|
||||
if (!is_existed)
|
||||
return false;
|
||||
|
||||
auto root_urn = Path(this->webdav_root, true);
|
||||
auto file_urn = root_urn + remote_file;
|
||||
|
||||
Data data = {nullptr, 0, 0};
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + file_urn.quote(request.handle);
|
||||
struct curl_slist *list = NULL;
|
||||
char range_header[64];
|
||||
sprintf(range_header, "Range: bytes=%lu-%lu", range_from, range_to);
|
||||
list = curl_slist_append(list, range_header);
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "GET");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HEADER, 0L);
|
||||
request.set(CURLOPT_HTTPHEADER, list);
|
||||
request.set(CURLOPT_WRITEDATA, reinterpret_cast<size_t>(&data));
|
||||
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Callback::Append::buffer));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
if (progress != nullptr)
|
||||
{
|
||||
request.set(CURLOPT_XFERINFODATA, progress_data);
|
||||
request.set(CURLOPT_XFERINFOFUNCTION, progress);
|
||||
request.set(CURLOPT_NOPROGRESS, 0L);
|
||||
}
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
if (callback != nullptr)
|
||||
callback(is_performed);
|
||||
if (!is_performed)
|
||||
return false;
|
||||
|
||||
buffer_ptr = data.buffer;
|
||||
buffer_size = data.size;
|
||||
data.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Client::sync_download_to(
|
||||
const std::string &remote_file,
|
||||
std::ostream &stream,
|
||||
callback_t callback,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
bool is_existed = this->check(remote_file);
|
||||
if (!is_existed)
|
||||
return false;
|
||||
|
||||
auto root_urn = Path(this->webdav_root, true);
|
||||
auto file_urn = root_urn + remote_file;
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + file_urn.quote(request.handle);
|
||||
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "GET");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HEADER, 0L);
|
||||
request.set(CURLOPT_WRITEDATA, reinterpret_cast<size_t>(&stream));
|
||||
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Callback::Write::stream));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
if (progress != nullptr)
|
||||
{
|
||||
request.set(CURLOPT_XFERINFODATA, progress_data);
|
||||
request.set(CURLOPT_XFERINFOFUNCTION, progress);
|
||||
request.set(CURLOPT_NOPROGRESS, 0L);
|
||||
}
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
if (callback != nullptr)
|
||||
callback(is_performed);
|
||||
|
||||
return is_performed;
|
||||
}
|
||||
|
||||
bool
|
||||
Client::sync_upload(
|
||||
const std::string &remote_file,
|
||||
const std::string &local_file,
|
||||
callback_t callback,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
bool is_existed = FileInfo::exists(local_file);
|
||||
if (!is_existed)
|
||||
return false;
|
||||
|
||||
auto root_urn = Path(this->webdav_root, true);
|
||||
auto file_urn = root_urn + remote_file;
|
||||
|
||||
std::ifstream file_stream(local_file, std::ios::binary);
|
||||
auto size = FileInfo::size(local_file);
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + file_urn.quote(request.handle);
|
||||
|
||||
Data response = {nullptr, 0, 0};
|
||||
|
||||
request.set(CURLOPT_UPLOAD, 1L);
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_READDATA, reinterpret_cast<size_t>(&file_stream));
|
||||
request.set(CURLOPT_READFUNCTION, reinterpret_cast<size_t>(Callback::Read::stream));
|
||||
request.set(CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(size));
|
||||
request.set(CURLOPT_BUFFERSIZE, static_cast<long>(Client::buffer_size));
|
||||
request.set(CURLOPT_WRITEDATA, reinterpret_cast<size_t>(&response));
|
||||
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Callback::Append::buffer));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
if (progress != nullptr)
|
||||
{
|
||||
request.set(CURLOPT_XFERINFODATA, progress_data);
|
||||
request.set(CURLOPT_XFERINFOFUNCTION, progress);
|
||||
request.set(CURLOPT_NOPROGRESS, 0L);
|
||||
}
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
if (callback != nullptr)
|
||||
callback(is_performed);
|
||||
return is_performed;
|
||||
}
|
||||
|
||||
bool
|
||||
Client::sync_upload_from(
|
||||
const std::string &remote_file,
|
||||
char *buffer_ptr,
|
||||
unsigned long long buffer_size,
|
||||
callback_t callback,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
auto root_urn = Path(this->webdav_root, true);
|
||||
auto file_urn = root_urn + remote_file;
|
||||
|
||||
Data data = {buffer_ptr, 0, buffer_size};
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + file_urn.quote(request.handle);
|
||||
|
||||
Data response = {nullptr, 0, 0};
|
||||
|
||||
request.set(CURLOPT_UPLOAD, 1L);
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_READDATA, reinterpret_cast<size_t>(&data));
|
||||
request.set(CURLOPT_READFUNCTION, reinterpret_cast<size_t>(Callback::Read::buffer));
|
||||
request.set(CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(buffer_size));
|
||||
request.set(CURLOPT_BUFFERSIZE, static_cast<long>(Client::buffer_size));
|
||||
request.set(CURLOPT_WRITEDATA, reinterpret_cast<size_t>(&response));
|
||||
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Callback::Append::buffer));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
if (progress != nullptr)
|
||||
{
|
||||
request.set(CURLOPT_XFERINFODATA, progress_data);
|
||||
request.set(CURLOPT_XFERINFOFUNCTION, progress);
|
||||
request.set(CURLOPT_NOPROGRESS, 0L);
|
||||
}
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
if (callback != nullptr)
|
||||
callback(is_performed);
|
||||
|
||||
data.reset();
|
||||
return is_performed;
|
||||
}
|
||||
|
||||
bool
|
||||
Client::sync_upload_from(
|
||||
const std::string &remote_file,
|
||||
std::istream &stream,
|
||||
callback_t callback,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
auto root_urn = Path(this->webdav_root, true);
|
||||
auto file_urn = root_urn + remote_file;
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + file_urn.quote(request.handle);
|
||||
stream.seekg(0, std::ios::end);
|
||||
size_t stream_size = stream.tellg();
|
||||
stream.seekg(0, std::ios::beg);
|
||||
|
||||
Data response = {nullptr, 0, 0};
|
||||
|
||||
request.set(CURLOPT_UPLOAD, 1L);
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_READDATA, reinterpret_cast<size_t>(&stream));
|
||||
request.set(CURLOPT_READFUNCTION, reinterpret_cast<size_t>(Callback::Read::stream));
|
||||
request.set(CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(stream_size));
|
||||
request.set(CURLOPT_BUFFERSIZE, static_cast<long>(Client::buffer_size));
|
||||
request.set(CURLOPT_WRITEDATA, reinterpret_cast<size_t>(&response));
|
||||
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Callback::Append::buffer));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
if (progress != nullptr)
|
||||
{
|
||||
request.set(CURLOPT_XFERINFODATA, progress_data);
|
||||
request.set(CURLOPT_XFERINFOFUNCTION, progress);
|
||||
request.set(CURLOPT_NOPROGRESS, 0L);
|
||||
}
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
|
||||
if (callback != nullptr)
|
||||
callback(is_performed);
|
||||
return is_performed;
|
||||
}
|
||||
|
||||
Client::Client(const dict_t &options)
|
||||
{
|
||||
this->webdav_hostname = get(options, "webdav_hostname");
|
||||
this->webdav_root = get(options, "webdav_root");
|
||||
this->webdav_username = get(options, "webdav_username");
|
||||
this->webdav_password = get(options, "webdav_password");
|
||||
|
||||
this->proxy_hostname = get(options, "proxy_hostname");
|
||||
this->proxy_username = get(options, "proxy_username");
|
||||
this->proxy_password = get(options, "proxy_password");
|
||||
|
||||
this->cert_path = get(options, "cert_path");
|
||||
this->key_path = get(options, "key_path");
|
||||
|
||||
auto check = get(options, "check_enabled");
|
||||
if (check.length() > 0)
|
||||
this->check_enabled = std::stoi(check);
|
||||
else
|
||||
this->check_enabled = 0;
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
Client::free_size()
|
||||
{
|
||||
Header header =
|
||||
{
|
||||
"Accept: */*",
|
||||
"Depth: 0",
|
||||
"Content-Type: text/xml"};
|
||||
|
||||
pugi::xml_document document;
|
||||
auto propfind = document.append_child("D:propfind");
|
||||
propfind.append_attribute("xmlns:D") = "DAV:";
|
||||
|
||||
auto prop = propfind.append_child("D:prop");
|
||||
prop.append_child("D:quokta-available-bytes");
|
||||
prop.append_child("D:quota-used-bytes");
|
||||
|
||||
auto document_print = pugi::node_to_string(document);
|
||||
size_t size = document_print.length() * sizeof((document_print.c_str())[0]);
|
||||
|
||||
Data data = {nullptr, 0, 0};
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "PROPFIND");
|
||||
request.set(CURLOPT_HTTPHEADER, reinterpret_cast<struct curl_slist *>(header.handle));
|
||||
request.set(CURLOPT_POSTFIELDS, document_print.c_str());
|
||||
request.set(CURLOPT_POSTFIELDSIZE, static_cast<long>(size));
|
||||
request.set(CURLOPT_HEADER, 0);
|
||||
request.set(CURLOPT_WRITEDATA, reinterpret_cast<size_t>(&data));
|
||||
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Callback::Append::buffer));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
|
||||
auto is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
if (!is_performed)
|
||||
return 0;
|
||||
|
||||
document.load_buffer(data.buffer, static_cast<size_t>(data.size));
|
||||
|
||||
pugi::xml_node multistatus = document.select_node("*[local-name()='multistatus']").node();
|
||||
pugi::xml_node response = multistatus.select_node("*[local-name()='response']").node();
|
||||
pugi::xml_node propstat = response.select_node("*[local-name()='propstat']").node();
|
||||
prop = propstat.select_node("*[local-name()='prop']").node();
|
||||
pugi::xml_node quota_available_bytes = prop.select_node("*[local-name()='quota-available-bytes']").node();
|
||||
std::string free_size_text = quota_available_bytes.first_child().value();
|
||||
|
||||
return std::stoll(free_size_text);
|
||||
}
|
||||
|
||||
bool
|
||||
Client::check(const std::string &remote_resource)
|
||||
{
|
||||
if (!this->check_enabled)
|
||||
return true;
|
||||
auto root_urn = Path(this->webdav_root, true);
|
||||
auto resource_urn = root_urn + remote_resource;
|
||||
|
||||
Header header =
|
||||
{
|
||||
"Accept: */*",
|
||||
"Depth: 0"};
|
||||
|
||||
Data data = {nullptr, 0, 0};
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + resource_urn.quote(request.handle);
|
||||
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "PROPFIND");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HTTPHEADER, reinterpret_cast<curl_slist *>(header.handle));
|
||||
request.set(CURLOPT_WRITEDATA, reinterpret_cast<size_t>(&data));
|
||||
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Callback::Append::buffer));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
return is_performed;
|
||||
}
|
||||
|
||||
dict_t
|
||||
Client::info(const std::string &remote_resource)
|
||||
{
|
||||
auto root_urn = Path(this->webdav_root, true);
|
||||
auto target_urn = root_urn + remote_resource;
|
||||
|
||||
Header header =
|
||||
{
|
||||
"Accept: */*",
|
||||
"Depth: 0"};
|
||||
|
||||
Data data = {nullptr, 0, 0};
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + target_urn.quote(request.handle);
|
||||
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "PROPFIND");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HTTPHEADER, reinterpret_cast<curl_slist *>(header.handle));
|
||||
request.set(CURLOPT_WRITEDATA, reinterpret_cast<size_t>(&data));
|
||||
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Callback::Append::buffer));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
|
||||
if (!is_performed)
|
||||
return dict_t{};
|
||||
|
||||
pugi::xml_document document;
|
||||
document.load_buffer(data.buffer, static_cast<size_t>(data.size));
|
||||
|
||||
#ifdef WDC_VERBOSE
|
||||
document.save(std::cout);
|
||||
#endif
|
||||
auto multistatus = document.select_node("*[local-name()='multistatus']").node();
|
||||
auto responses = multistatus.select_nodes("*[local-name()='response']");
|
||||
for (auto response : responses)
|
||||
{
|
||||
pugi::xml_node href = response.node().select_node("*[local-name()='href']").node();
|
||||
std::string encode_file_name = href.first_child().value();
|
||||
std::string resource_path = curl_unescape(encode_file_name.c_str(), static_cast<int>(encode_file_name.length()));
|
||||
auto target_path = target_urn.path();
|
||||
auto target_path_without_sep = target_urn.path();
|
||||
if (!target_path_without_sep.empty() && target_path_without_sep.back() == '/')
|
||||
target_path_without_sep.resize(target_path_without_sep.length() - 1);
|
||||
auto resource_path_without_sep = resource_path.erase(resource_path.find_last_not_of('/') + 1);
|
||||
size_t pos = resource_path_without_sep.find(this->webdav_hostname);
|
||||
if (pos != std::string::npos)
|
||||
resource_path_without_sep.erase(pos, this->webdav_hostname.length());
|
||||
|
||||
if (resource_path_without_sep == target_path_without_sep)
|
||||
{
|
||||
auto propstat = response.node().select_node("*[local-name()='propstat']").node();
|
||||
auto prop = propstat.select_node("*[local-name()='prop']").node();
|
||||
auto creation_date = prop.select_node("*[local-name()='creationdate']").node();
|
||||
auto display_name = prop.select_node("*[local-name()='displayname']").node();
|
||||
auto content_length = prop.select_node("*[local-name()='getcontentlength']").node();
|
||||
auto modified_date = prop.select_node("*[local-name()='getlastmodified']").node();
|
||||
auto resource_type = prop.select_node("*[local-name()='resourcetype']").node();
|
||||
|
||||
std::string name = target_urn.name();
|
||||
dict_t information =
|
||||
{
|
||||
{"created", creation_date.first_child().value()},
|
||||
{"name", Util::Rtrim(name, "/")},
|
||||
{"size", content_length.first_child().value()},
|
||||
{"modified", modified_date.first_child().value()},
|
||||
{"type", resource_type.first_child().name()}};
|
||||
|
||||
return information;
|
||||
}
|
||||
}
|
||||
|
||||
return dict_t{};
|
||||
}
|
||||
|
||||
bool
|
||||
Client::head(const std::string &remote_resource, dict_t *headers)
|
||||
{
|
||||
auto root_urn = Path(this->webdav_root, true);
|
||||
auto target_urn = root_urn + remote_resource;
|
||||
|
||||
Header header =
|
||||
{"Accept: */*"};
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + target_urn.quote(request.handle);
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "HEAD");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HTTPHEADER, reinterpret_cast<curl_slist *>(header.handle));
|
||||
request.set(CURLOPT_HEADERDATA, headers);
|
||||
request.set(CURLOPT_HEADERFUNCTION, header_callback);
|
||||
request.set(CURLOPT_NOBODY, 1L);
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
|
||||
return is_performed;
|
||||
}
|
||||
|
||||
bool
|
||||
Client::is_directory(const std::string &remote_resource)
|
||||
{
|
||||
auto information = this->info(remote_resource);
|
||||
auto resource_type = information["type"];
|
||||
bool is_dir = resource_type == "d:collection" || resource_type == "D:collection";
|
||||
return is_dir;
|
||||
}
|
||||
|
||||
dict_items_t
|
||||
Client::list(const std::string &remote_directory)
|
||||
{
|
||||
bool is_existed = this->check(remote_directory);
|
||||
if (!is_existed)
|
||||
return dict_items_t{};
|
||||
|
||||
auto target_urn = Path(this->webdav_root, true) + remote_directory;
|
||||
target_urn = Path(target_urn.path(), true);
|
||||
|
||||
Header header =
|
||||
{
|
||||
"Accept: */*",
|
||||
"Depth: 1"};
|
||||
|
||||
Data data = {nullptr, 0, 0};
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + target_urn.quote(request.handle);
|
||||
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "PROPFIND");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HTTPHEADER, reinterpret_cast<curl_slist *>(header.handle));
|
||||
request.set(CURLOPT_HEADER, 0);
|
||||
request.set(CURLOPT_WRITEDATA, reinterpret_cast<size_t>(&data));
|
||||
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Callback::Append::buffer));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
|
||||
if (!is_performed)
|
||||
return dict_items_t{};
|
||||
|
||||
dict_items_t resources;
|
||||
|
||||
pugi::xml_document document;
|
||||
document.load_buffer(data.buffer, static_cast<size_t>(data.size));
|
||||
auto multistatus = document.select_node("*[local-name()='multistatus']").node();
|
||||
auto responses = multistatus.select_nodes("*[local-name()='response']");
|
||||
for (auto response : responses)
|
||||
{
|
||||
pugi::xml_node href = response.node().select_node("*[local-name()='href']").node();
|
||||
std::string encode_file_name = href.first_child().value();
|
||||
std::string resource_path = curl_unescape(encode_file_name.c_str(), static_cast<int>(encode_file_name.length()));
|
||||
auto target_path = target_urn.path();
|
||||
|
||||
auto target_path_without_sep = target_urn.path();
|
||||
if (!target_path_without_sep.empty() && target_path_without_sep.back() == '/')
|
||||
target_path_without_sep.resize(target_path_without_sep.length() - 1);
|
||||
auto resource_path_without_sep = resource_path.erase(resource_path.find_last_not_of('/') + 1);
|
||||
size_t pos = resource_path_without_sep.find(this->webdav_hostname);
|
||||
if (pos != std::string::npos)
|
||||
resource_path_without_sep.erase(pos, this->webdav_hostname.length());
|
||||
|
||||
if (resource_path_without_sep == target_path_without_sep)
|
||||
continue;
|
||||
|
||||
auto propstat = response.node().select_node("*[local-name()='propstat']").node();
|
||||
auto prop = propstat.select_node("*[local-name()='prop']").node();
|
||||
auto creation_date = prop.select_node("*[local-name()='creationdate']").node();
|
||||
auto display_name = prop.select_node("*[local-name()='displayname']").node();
|
||||
auto content_length = prop.select_node("*[local-name()='getcontentlength']").node();
|
||||
auto modified_date = prop.select_node("*[local-name()='getlastmodified']").node();
|
||||
auto resource_type = prop.select_node("*[local-name()='resourcetype']").node();
|
||||
|
||||
Path resource_urn(resource_path);
|
||||
std::string name = resource_urn.name();
|
||||
dict_t item = {
|
||||
{"created", creation_date.first_child().value()},
|
||||
{"name", Util::Rtrim(name, "/")},
|
||||
{"size", content_length.first_child().value()},
|
||||
{"modified", modified_date.first_child().value()},
|
||||
{"type", resource_type.first_child().name()}};
|
||||
resources.push_back(item);
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
bool Client::download(
|
||||
const std::string &remote_file,
|
||||
const std::string &local_file,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
return this->sync_download(remote_file, local_file, nullptr, progress_data, std::move(progress));
|
||||
}
|
||||
|
||||
void
|
||||
Client::async_download(
|
||||
const std::string &remote_file,
|
||||
const std::string &local_file,
|
||||
callback_t callback,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
std::thread downloading([=]()
|
||||
{ this->sync_download(remote_file, local_file, callback, progress_data, std::move(progress)); });
|
||||
downloading.detach();
|
||||
}
|
||||
|
||||
bool
|
||||
Client::download_to(
|
||||
const std::string &remote_file,
|
||||
char *&buffer_ptr,
|
||||
unsigned long long &buffer_size,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
return this->sync_download_to(remote_file, buffer_ptr, buffer_size, nullptr, progress_data, std::move(progress));
|
||||
}
|
||||
|
||||
bool
|
||||
Client::download_range_to(
|
||||
const std::string &remote_file,
|
||||
char *&buffer_ptr,
|
||||
unsigned long long &buffer_size,
|
||||
uint64_t range_from,
|
||||
uint64_t range_to,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
return this->sync_download_range_to(remote_file, buffer_ptr, buffer_size, range_from, range_to, nullptr, progress_data, std::move(progress));
|
||||
}
|
||||
|
||||
bool
|
||||
Client::download_to(
|
||||
const std::string &remote_file,
|
||||
std::ostream &stream,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
return this->sync_download_to(remote_file, stream, nullptr, progress_data, std::move(progress));
|
||||
}
|
||||
|
||||
bool
|
||||
Client::create_directory(const std::string &remote_directory, bool recursive)
|
||||
{
|
||||
bool is_existed = this->check(remote_directory);
|
||||
if (is_existed)
|
||||
return true;
|
||||
|
||||
bool resource_is_dir = true;
|
||||
Path directory_urn(remote_directory, resource_is_dir);
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
auto remote_parent_directory = directory_urn.parent().path();
|
||||
if (remote_parent_directory == remote_directory)
|
||||
return false;
|
||||
bool is_created = this->create_directory(remote_parent_directory, true);
|
||||
if (!is_created)
|
||||
return false;
|
||||
}
|
||||
|
||||
Header header =
|
||||
{
|
||||
"Accept: */*",
|
||||
"Connection: Keep-Alive"};
|
||||
|
||||
auto target_urn = Path(this->webdav_root, true) + remote_directory;
|
||||
target_urn = Path(target_urn.path(), true);
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + target_urn.quote(request.handle);
|
||||
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "MKCOL");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HTTPHEADER, reinterpret_cast<curl_slist *>(header.handle));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
return is_performed;
|
||||
}
|
||||
|
||||
bool
|
||||
Client::move(const std::string &remote_source_resource, const std::string &remote_destination_resource)
|
||||
{
|
||||
bool is_existed = this->check(remote_source_resource);
|
||||
if (!is_existed)
|
||||
return false;
|
||||
|
||||
Path root_urn(this->webdav_root, true);
|
||||
|
||||
auto source_resource_urn = root_urn + remote_source_resource;
|
||||
auto destination_resource_urn = root_urn + remote_destination_resource;
|
||||
|
||||
Header header =
|
||||
{
|
||||
"Accept: */*",
|
||||
"Destination: " + destination_resource_urn.path()};
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + source_resource_urn.quote(request.handle);
|
||||
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "MOVE");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HTTPHEADER, reinterpret_cast<curl_slist *>(header.handle));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
return is_performed;
|
||||
}
|
||||
|
||||
bool
|
||||
Client::copy(const std::string &remote_source_resource, const std::string &remote_destination_resource)
|
||||
{
|
||||
bool is_existed = this->check(remote_source_resource);
|
||||
if (!is_existed)
|
||||
return false;
|
||||
|
||||
Path root_urn(this->webdav_root, true);
|
||||
|
||||
auto source_resource_urn = root_urn + remote_source_resource;
|
||||
auto destination_resource_urn = root_urn + remote_destination_resource;
|
||||
|
||||
Header header =
|
||||
{
|
||||
"Accept: */*",
|
||||
"Destination: " + destination_resource_urn.path()};
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + source_resource_urn.quote(request.handle);
|
||||
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "COPY");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HTTPHEADER, reinterpret_cast<curl_slist *>(header.handle));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
return is_performed;
|
||||
}
|
||||
|
||||
bool
|
||||
Client::upload(
|
||||
const std::string &remote_file,
|
||||
const std::string &local_file,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
return this->sync_upload(remote_file, local_file, nullptr, progress_data, std::move(progress));
|
||||
}
|
||||
|
||||
void
|
||||
Client::async_upload(
|
||||
const std::string &remote_file,
|
||||
const std::string &local_file,
|
||||
callback_t callback,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
std::thread uploading([=]()
|
||||
{ this->sync_upload(remote_file, local_file, callback, progress_data, std::move(progress)); });
|
||||
uploading.detach();
|
||||
}
|
||||
|
||||
bool
|
||||
Client::upload_from(
|
||||
const std::string &remote_file,
|
||||
std::istream &stream,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
return this->sync_upload_from(remote_file, stream, nullptr, progress_data, std::move(progress));
|
||||
}
|
||||
|
||||
bool
|
||||
Client::upload_from(
|
||||
const std::string &remote_file,
|
||||
char *buffer_ptr,
|
||||
unsigned long long buffer_size,
|
||||
progress_data_t progress_data,
|
||||
progress_t progress)
|
||||
{
|
||||
return this->sync_upload_from(remote_file, buffer_ptr, buffer_size, nullptr, progress_data, std::move(progress));
|
||||
}
|
||||
|
||||
bool
|
||||
Client::clean(const std::string &remote_resource)
|
||||
{
|
||||
bool is_existed = this->check(remote_resource);
|
||||
if (!is_existed)
|
||||
return true;
|
||||
|
||||
auto root_urn = Path(this->webdav_root, true);
|
||||
auto resource_urn = root_urn + remote_resource;
|
||||
|
||||
Header header =
|
||||
{
|
||||
"Accept: */*",
|
||||
"Connection: Keep-Alive"};
|
||||
|
||||
Request request(this->options());
|
||||
|
||||
auto url = this->webdav_hostname + resource_urn.quote(request.handle);
|
||||
|
||||
request.set(CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
request.set(CURLOPT_URL, url.c_str());
|
||||
request.set(CURLOPT_HTTPHEADER, reinterpret_cast<curl_slist *>(header.handle));
|
||||
#ifdef WDC_VERBOSE
|
||||
request.set(CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
|
||||
bool is_performed = request.perform();
|
||||
this->http_code = request.status_code();
|
||||
return is_performed;
|
||||
}
|
||||
|
||||
class Environment
|
||||
{
|
||||
public:
|
||||
Environment()
|
||||
{
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
}
|
||||
~Environment()
|
||||
{
|
||||
curl_global_cleanup();
|
||||
}
|
||||
};
|
||||
} // namespace WebDAV
|
||||
|
||||
static const WebDAV::Environment env;
|
||||
@@ -0,0 +1,387 @@
|
||||
/*#***************************************************************************
|
||||
# __ __ _____ _____
|
||||
# Project | | | | | \ / ___|
|
||||
# | |__| | | |\ \ / /
|
||||
# | | | | ) ) ( (
|
||||
# | /\ | | |/ / \ \___
|
||||
# \_/ \_/ |_____/ \_____|
|
||||
#
|
||||
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file LICENSE, which
|
||||
# you should have received as part of this distribution.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the LICENSE file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
############################################################################*/
|
||||
|
||||
#ifndef WEBDAV_CLIENT_HPP
|
||||
#define WEBDAV_CLIENT_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <curl/curl.h>
|
||||
|
||||
namespace WebDAV
|
||||
{
|
||||
using progress_data_t = void*;
|
||||
|
||||
using progress_t = int(void* context,
|
||||
curl_off_t dltotal,
|
||||
curl_off_t dlnow,
|
||||
curl_off_t ultotal,
|
||||
curl_off_t ulnow);
|
||||
|
||||
using callback_t = std::function<void(bool)> ;
|
||||
|
||||
using strings_t = std::vector<std::string>;
|
||||
using dict_t = std::map<std::string, std::string>;
|
||||
using dict_items_t = std::vector<dict_t>;
|
||||
|
||||
auto inline get(const dict_t& options, const std::string&& name) -> std::string
|
||||
{
|
||||
auto it = options.find(name);
|
||||
if (it == options.end()) return "";
|
||||
else return it->second;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief WebDAV Client
|
||||
/// \author designerror
|
||||
/// \version 1.1.4
|
||||
/// \date 3/16/2018
|
||||
///
|
||||
class Client
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// \param[in] webdav_hostname
|
||||
/// \param[in] webdav_root
|
||||
/// \param[in] webdav_username
|
||||
/// \param[in] webdav_password
|
||||
/// \param[in] proxy_hostname
|
||||
/// \param[in] proxy_username
|
||||
/// \param[in] proxy_password
|
||||
/// \param[in] cert_path
|
||||
/// \param[in] key_path
|
||||
/// \include client/init.cpp
|
||||
///
|
||||
explicit Client(const dict_t& options);
|
||||
|
||||
///
|
||||
/// Get free size of the WebDAV server
|
||||
/// \return size in bytes
|
||||
/// \include client/size.cpp
|
||||
///
|
||||
auto free_size() -> unsigned long long;
|
||||
|
||||
///
|
||||
/// Check for existence of a remote resource
|
||||
/// \param[in] remote_resource
|
||||
/// \include client/check.cpp
|
||||
///
|
||||
auto check(const std::string& remote_resource = "/") -> bool;
|
||||
|
||||
///
|
||||
/// Get information of a remote resource
|
||||
/// \param[in] remote_resource
|
||||
/// \include client/info.cpp
|
||||
///
|
||||
auto info(const std::string& remote_resource) -> dict_t;
|
||||
|
||||
///
|
||||
/// Get information of a remote resource
|
||||
/// \param[in] remote_resource
|
||||
/// \include client/info.cpp
|
||||
///
|
||||
auto head(const std::string& remote_resource, dict_t *headers) -> bool;
|
||||
|
||||
///
|
||||
/// Clean an remote resource
|
||||
/// \param[in] remote_resource
|
||||
/// \include client/clean.cpp
|
||||
///
|
||||
auto clean(const std::string& remote_resource) -> bool;
|
||||
|
||||
///
|
||||
/// Checks whether the resource directory
|
||||
/// \param[in] remote_resource
|
||||
///
|
||||
auto is_directory(const std::string& remote_resource) -> bool;
|
||||
|
||||
///
|
||||
/// List a remote directory
|
||||
/// \param[in] remote_directory
|
||||
/// \include client/list.cpp
|
||||
///
|
||||
auto list(const std::string& remote_directory = "") -> dict_items_t;
|
||||
|
||||
///
|
||||
/// Create a remote directory
|
||||
/// \param[in] remote_directory
|
||||
/// \param[in] recursive
|
||||
/// \include client/mkdir.cpp
|
||||
///
|
||||
auto create_directory(
|
||||
const std::string& remote_directory,
|
||||
bool recursive = false
|
||||
) -> bool;
|
||||
|
||||
///
|
||||
/// Move a remote resource
|
||||
/// \param[in] remote_source_resource
|
||||
/// \param[in] remote_destination_resource
|
||||
/// \include client/move.cpp
|
||||
///
|
||||
auto move(
|
||||
const std::string& remote_source_resource,
|
||||
const std::string& remote_destination_resource
|
||||
) -> bool;
|
||||
|
||||
///
|
||||
/// Copy a remote resource
|
||||
/// \param[in] remote_source_resource
|
||||
/// \param[in] remote_destination_resource
|
||||
/// \include client/copy.cpp
|
||||
///
|
||||
auto copy(
|
||||
const std::string& remote_source_resource,
|
||||
const std::string& remote_destination_resource
|
||||
) -> bool;
|
||||
|
||||
///
|
||||
/// Download a remote file to a local file
|
||||
/// \param[in] remote_file
|
||||
/// \param[in] local_file
|
||||
/// \param[in] progress
|
||||
/// \snippet client/download.cpp download_to_file
|
||||
///
|
||||
auto download(
|
||||
const std::string& remote_file,
|
||||
const std::string& local_file,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
///
|
||||
/// Download a remote file to a buffer
|
||||
/// \param[in] remote_file
|
||||
/// \param[out] buffer_ptr
|
||||
/// \param[out] buffer_size
|
||||
/// \param[in] progress
|
||||
/// \snippet client/download.cpp download_to_buffer
|
||||
///
|
||||
auto download_to(
|
||||
const std::string& remote_file,
|
||||
char*& buffer_ptr,
|
||||
unsigned long long& buffer_size,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
///
|
||||
/// Download a remote file to a buffer for specified range
|
||||
/// \param[in] remote_file
|
||||
/// \param[out] buffer_ptr
|
||||
/// \param[out] buffer_size
|
||||
/// \param[in] range_from,
|
||||
/// \param[in] range_to
|
||||
/// \param[in] progress
|
||||
/// \snippet client/download.cpp download_to_buffer
|
||||
///
|
||||
auto download_range_to(
|
||||
const std::string& remote_file,
|
||||
char*& buffer_ptr,
|
||||
unsigned long long& buffer_size,
|
||||
uint64_t range_from,
|
||||
uint64_t range_to,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
///
|
||||
/// Download a remote file to a stream
|
||||
/// \param[in] remote_file
|
||||
/// \param[out] stream
|
||||
/// \param[in] progress
|
||||
/// \snippet client/download.cpp download_to_stream
|
||||
///
|
||||
auto download_to(
|
||||
const std::string& remote_file,
|
||||
std::ostream& stream,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
///
|
||||
/// Asynchronously download a remote file to a local file
|
||||
/// \param[in] remote_file
|
||||
/// \param[in] local_file
|
||||
/// \param[in] callback
|
||||
/// \param[in] progress
|
||||
/// \snippet client/download.cpp async_download_to_file
|
||||
///
|
||||
auto async_download(
|
||||
const std::string& remote_file,
|
||||
const std::string& local_file,
|
||||
callback_t callback = nullptr,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> void;
|
||||
|
||||
///
|
||||
/// Upload a remote file from a local file
|
||||
/// \param[in] remote_file
|
||||
/// \param[in] local_file
|
||||
/// \param[in] progress
|
||||
/// \snippet client/upload.cpp upload_from_file
|
||||
///
|
||||
auto upload(
|
||||
const std::string& remote_file,
|
||||
const std::string& local_file,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
///
|
||||
/// Upload a remote file from a buffer
|
||||
/// \param[in] remote_file
|
||||
/// \param[in] buffer_ptr
|
||||
/// \param[in] buffer_size
|
||||
/// \param[in] progress
|
||||
/// \snippet client/upload.cpp upload_from_buffer
|
||||
///
|
||||
auto upload_from(
|
||||
const std::string& remote_file,
|
||||
char* buffer_ptr,
|
||||
unsigned long long buffer_size,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
///
|
||||
/// Upload a remote file from a stream
|
||||
/// \param[in] remote_file
|
||||
/// \param[in] stream
|
||||
/// \param[in] progress
|
||||
/// \snippet client/upload.cpp upload_from_stream
|
||||
///
|
||||
auto upload_from(
|
||||
const std::string& remote_file,
|
||||
std::istream& stream,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
///
|
||||
/// Asynchronously upload a remote file from a local file
|
||||
/// \param[in] remote_file
|
||||
/// \param[in] local_file
|
||||
/// \param[in] callback
|
||||
/// \param[in] progress
|
||||
/// \snippet client/upload.cpp async_upload_from_file
|
||||
///
|
||||
auto async_upload(
|
||||
const std::string& remote_file,
|
||||
const std::string& local_file,
|
||||
callback_t callback = nullptr,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> void;
|
||||
|
||||
long status_code();
|
||||
|
||||
private:
|
||||
|
||||
auto sync_download(
|
||||
const std::string& remote_file,
|
||||
const std::string& local_file,
|
||||
callback_t callback = nullptr,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
auto sync_download_to(
|
||||
const std::string& remote_file,
|
||||
char*& buffer_ptr,
|
||||
unsigned long long& buffer_size,
|
||||
callback_t callback = nullptr,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
auto sync_download_range_to(
|
||||
const std::string& remote_file,
|
||||
char*& buffer_ptr,
|
||||
unsigned long long& buffer_size,
|
||||
uint64_t range_from,
|
||||
uint64_t range_to,
|
||||
callback_t callback = nullptr,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
bool sync_download_to(
|
||||
const std::string& remote_file,
|
||||
std::ostream& stream,
|
||||
callback_t callback = nullptr,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
);
|
||||
|
||||
bool sync_upload(
|
||||
const std::string& remote_file,
|
||||
const std::string& local_file,
|
||||
callback_t callback = nullptr,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
);
|
||||
|
||||
auto sync_upload_from(
|
||||
const std::string& remote_file,
|
||||
char* buffer_ptr,
|
||||
unsigned long long buffer_size,
|
||||
callback_t callback = nullptr,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
auto sync_upload_from(
|
||||
const std::string& remote_file,
|
||||
std::istream& stream,
|
||||
callback_t callback = nullptr,
|
||||
progress_data_t progress_data = nullptr,
|
||||
progress_t progress = nullptr
|
||||
) -> bool;
|
||||
|
||||
enum { buffer_size = 1000 * 1000 };
|
||||
|
||||
std::string webdav_hostname;
|
||||
std::string webdav_root;
|
||||
std::string webdav_username;
|
||||
std::string webdav_password;
|
||||
|
||||
std::string proxy_hostname;
|
||||
std::string proxy_username;
|
||||
std::string proxy_password;
|
||||
|
||||
std::string cert_path;
|
||||
std::string key_path;
|
||||
|
||||
dict_t options();
|
||||
|
||||
long http_code;
|
||||
int check_enabled = 0;
|
||||
};
|
||||
} // namespace WebDAV
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*#***************************************************************************
|
||||
# __ __ _____ _____
|
||||
# Project | | | | | \ / ___|
|
||||
# | |__| | | |\ \ / /
|
||||
# | | | | ) ) ( (
|
||||
# | /\ | | |/ / \ \___
|
||||
# \_/ \_/ |_____/ \_____|
|
||||
#
|
||||
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file LICENSE, which
|
||||
# you should have received as part of this distribution.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the LICENSE file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
############################################################################*/
|
||||
|
||||
#include "fsinfo.hpp"
|
||||
#include <fstream>
|
||||
|
||||
namespace WebDAV
|
||||
{
|
||||
namespace FileInfo
|
||||
{
|
||||
auto exists(const std::string& path) -> bool
|
||||
{
|
||||
std::ifstream file(path);
|
||||
return file.good();
|
||||
}
|
||||
|
||||
auto size(const std::string& path_file) -> unsigned long long
|
||||
{
|
||||
std::ifstream file(path_file, std::ios::binary | std::ios::ate);
|
||||
return static_cast<unsigned long long>(file.tellg());
|
||||
}
|
||||
} // namespace FileInfo
|
||||
} // namespace WebDAV
|
||||
@@ -0,0 +1,38 @@
|
||||
/*#***************************************************************************
|
||||
# __ __ _____ _____
|
||||
# Project | | | | | \ / ___|
|
||||
# | |__| | | |\ \ / /
|
||||
# | | | | ) ) ( (
|
||||
# | /\ | | |/ / \ \___
|
||||
# \_/ \_/ |_____/ \_____|
|
||||
#
|
||||
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file LICENSE, which
|
||||
# you should have received as part of this distribution.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the LICENSE file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
############################################################################*/
|
||||
|
||||
#ifndef WEBDAV_FSINFO_HPP
|
||||
#define WEBDAV_FSINFO_HPP
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
namespace WebDAV
|
||||
{
|
||||
namespace FileInfo
|
||||
{
|
||||
auto exists(const std::string& path) -> bool;
|
||||
auto size(const std::string& path_file) -> unsigned long long;
|
||||
} // namespace FileInfo
|
||||
} // namespace WebDAV
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/*#***************************************************************************
|
||||
# __ __ _____ _____
|
||||
# Project | | | | | \ / ___|
|
||||
# | |__| | | |\ \ / /
|
||||
# | | | | ) ) ( (
|
||||
# | /\ | | |/ / \ \___
|
||||
# \_/ \_/ |_____/ \_____|
|
||||
#
|
||||
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file LICENSE, which
|
||||
# you should have received as part of this distribution.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the LICENSE file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
############################################################################*/
|
||||
|
||||
#include "header.hpp"
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
namespace WebDAV
|
||||
{
|
||||
Header::Header(const std::initializer_list<std::string>& init_list) noexcept : handle(nullptr)
|
||||
{
|
||||
for (auto& item : init_list)
|
||||
{
|
||||
this->append(item);
|
||||
}
|
||||
}
|
||||
|
||||
Header::~Header() noexcept
|
||||
{
|
||||
curl_slist_free_all(reinterpret_cast<curl_slist*>(this->handle));
|
||||
}
|
||||
|
||||
Header::Header(Header&& other) noexcept
|
||||
{
|
||||
handle = other.handle;
|
||||
other.handle = nullptr;
|
||||
}
|
||||
|
||||
auto Header::operator=(Header&& other) noexcept -> Header&
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
Header(std::move(other)).swap(*this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto Header::swap(Header& other) noexcept -> void
|
||||
{
|
||||
using std::swap;
|
||||
swap(handle, other.handle);
|
||||
}
|
||||
|
||||
void
|
||||
Header::append(const std::string& item) noexcept
|
||||
{
|
||||
this->handle = curl_slist_append(reinterpret_cast<curl_slist*>(this->handle), item.c_str());
|
||||
}
|
||||
} // namespace WebDAV
|
||||
@@ -0,0 +1,51 @@
|
||||
/*#***************************************************************************
|
||||
# __ __ _____ _____
|
||||
# Project | | | | | \ / ___|
|
||||
# | |__| | | |\ \ / /
|
||||
# | | | | ) ) ( (
|
||||
# | /\ | | |/ / \ \___
|
||||
# \_/ \_/ |_____/ \_____|
|
||||
#
|
||||
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file LICENSE, which
|
||||
# you should have received as part of this distribution.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the LICENSE file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
############################################################################*/
|
||||
|
||||
#ifndef WEBDAV_HEADER_HPP
|
||||
#define WEBDAV_HEADER_HPP
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
|
||||
namespace WebDAV
|
||||
{
|
||||
class Header final
|
||||
{
|
||||
public:
|
||||
void* handle;
|
||||
|
||||
Header(const std::initializer_list<std::string>& init_list) noexcept;
|
||||
Header(const Header& other) = delete;
|
||||
Header(Header&& other) noexcept;
|
||||
~Header() noexcept;
|
||||
|
||||
auto operator=(const Header& other) -> Header& = delete;
|
||||
auto operator=(Header&& other) noexcept -> Header&;
|
||||
|
||||
void append(const std::string& item) noexcept;
|
||||
|
||||
private:
|
||||
auto swap(Header& other) noexcept -> void;
|
||||
};
|
||||
} // namespace WebDAV
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
/*#***************************************************************************
|
||||
# __ __ _____ _____
|
||||
# Project | | | | | \ / ___|
|
||||
# | |__| | | |\ \ / /
|
||||
# | | | | ) ) ( (
|
||||
# | /\ | | |/ / \ \___
|
||||
# \_/ \_/ |_____/ \_____|
|
||||
#
|
||||
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file LICENSE, which
|
||||
# you should have received as part of this distribution.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the LICENSE file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
############################################################################*/
|
||||
|
||||
#ifndef WEBDAV_PUGIEXT_HPP
|
||||
#define WEBDAV_PUGIEXT_HPP
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
namespace pugi
|
||||
{
|
||||
class PUGIXML_CLASS xml_string_writer: public xml_writer
|
||||
{
|
||||
public:
|
||||
std::string result;
|
||||
|
||||
void write(const void* data, size_t size) final
|
||||
{
|
||||
result += std::string(static_cast<const char*>(data), size);
|
||||
}
|
||||
};
|
||||
|
||||
inline std::string node_to_string(const pugi::xml_node& node)
|
||||
{
|
||||
xml_string_writer writer;
|
||||
node.print(writer);
|
||||
|
||||
return writer.result;
|
||||
}
|
||||
} // namespace pugi
|
||||
|
||||
#endif
|
||||