diff --git a/.gitignore b/.gitignore index 259148f..bd8b478 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +build +.vscode + # Prerequisites *.d diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..eb97384 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,92 @@ +cmake_minimum_required(VERSION 2.8) + +if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) + if(DEFINED ENV{VITASDK}) + set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file") + else() + message(FATAL_ERROR "Please define VITASDK to point to your SDK path!") + endif() +endif() + +project(ftpclient) +include("${VITASDK}/share/vita.cmake" REQUIRED) + +set(VITA_APP_NAME "Ftp Client") +set(VITA_TITLEID "FTPCLIENT") +set(VITA_VERSION "01.00") + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") + +include_directories( + src +) + +add_executable(${PROJECT_NAME} + src/textures.cpp + src/fs.cpp + src/main.cpp + src/inifile.c + src/config.cpp + src/style.cpp + src/ime_dialog.cpp + src/net.cpp + src/ftpclient.cpp + src/vitaaudiolib.c + src/gui.cpp + src/windows.cpp + src/actions.cpp + src/updater.cpp + src/sfo.cpp + src/audio.c + src/ogg.c + src/sha1.c + src/zip.c + src/unzip.c + src/ioapi.c +) + +target_link_libraries(${PROJECT_NAME} + debugnet + vorbisfile + vorbis + ogg + vita2d + png + imgui_vita2d + stdc++ + c + z + SceCommonDialog_stub + SceLibKernel_stub + SceDisplay_stub + SceGxm_stub + SceSysmodule_stub + SceCtrl_stub + SceTouch_stub + SceAudio_stub + SceHid_stub + SceNet_stub + SceNetCtl_stub + SceHttp_stub + SceSsl_stub + ScePspnetAdhoc_stub + ScePromoterUtil_stub + SceShellSvc_stub + m + SceAppMgr_stub + SceAppUtil_stub + SceShaccCg_stub +) + +vita_create_self(eboot.bin ${PROJECT_NAME} UNSAFE) +vita_create_vpk(${PROJECT_NAME}.vpk ${VITA_TITLEID} eboot.bin + VERSION ${VITA_VERSION} + NAME ${VITA_APP_NAME} + FILE sce_sys/icon0.png sce_sys/icon0.png + FILE sce_sys/livearea/contents/bg.png sce_sys/livearea/contents/bg.png + FILE sce_sys/livearea/contents/startup.png sce_sys/livearea/contents/startup.png + FILE sce_sys/livearea/contents/template.xml sce_sys/livearea/contents/template.xml + FILE default_style.ini default_style.ini + FILE head.bin head.bin + FILE music.ogg music.ogg +) diff --git a/default_style.ini b/default_style.ini new file mode 100644 index 0000000..4fe5a94 --- /dev/null +++ b/default_style.ini @@ -0,0 +1,44 @@ +[Style] +Text=1.00,1.00,1.00,1.00 +TextDisabled=0.50,0.50,0.50,1.00 +WindowBackgroud=0.06,0.06,0.06,0.94 +ChildBackground=0.00,0.00,0.00,0.00 +PopupBackground=0.08,0.08,0.08,0.94 +Border=0.43,0.43,0.50,0.50 +BorderShadhow=0.00,0.00,0.00,0.00 +FrameBackground=0.16,0.29,0.48,0.54 +FrameBackgroundHovered=0.26,0.59,0.98,0.40 +FrameBackgroundActive=0.26,0.59,0.98,0.67 +TitleBackground=0.04,0.04,0.04,1.00 +TitleBackgroundActive=0.16,0.29,0.48,1.00 +TitleBackgroundCollapsed=0.00,0.00,0.00,0.51 +MenuBarBackground=0.14,0.14,0.14,1.00 +ScrollbarBackground=0.02,0.02,0.02,0.53 +ScrollbarGrab=0.31,0.31,0.31,1.00 +ScrollbarGrabHovered=0.41,0.41,0.41,1.00 +ScrollbarGrabActive=0.51,0.51,0.51,1.00 +CheckMark=0.26,0.59,0.98,1.00 +SliderGrab=0.24,0.52,0.88,1.00 +SliderGrabActive=0.26,0.59,0.98,1.00 +Button=0.26,0.59,0.98,0.40 +ButtonHovered=0.26,0.59,0.98,1.00 +ButtonActive=0.06,0.53,0.98,1.00 +Header=0.26,0.59,0.98,0.31 +HeaderHovered=0.26,0.59,0.98,0.80 +HeaderActive=0.26,0.59,0.98,1.00 +Separator=0.43,0.43,0.50,0.50 +SeparatorHovered=0.10,0.40,0.75,0.78 +SeparatorActive=0.10,0.40,0.75,1.00 +ResizeGrip=0.26,0.59,0.98,0.25 +ResizeHovered=0.26,0.59,0.98,0.67 +ResizeGripActive=0.26,0.59,0.98,0.95 +Tab=0.18,0.35,0.58,0.86 +TabHovered=0.26,0.59,0.98,0.80 +TabActive=0.31,0.31,0.31,1.00 +TabUnocused=0.07,0.10,0.15,0.97 +TabUnocusedActive=0.14,0.26,0.42,0.76 +TextSelectedBackground=0.26,0.59,0.98,0.35 +NavigationHighlight=0.26,0.59,0.98,1.00 +NavigationWindowingHighlight=1.00,1.00,1.00,0.70 +NavigationWindowingDimBackground=0.80,0.80,0.80,0.20 +ModalWindowDimBackground=0.80,0.80,0.80,0.35 diff --git a/head.bin b/head.bin new file mode 100644 index 0000000..0399fcb Binary files /dev/null and b/head.bin differ diff --git a/music.ogg b/music.ogg new file mode 100755 index 0000000..ad65f61 Binary files /dev/null and b/music.ogg differ diff --git a/sce_sys/icon0.png b/sce_sys/icon0.png new file mode 100644 index 0000000..c3f9163 Binary files /dev/null and b/sce_sys/icon0.png differ diff --git a/sce_sys/livearea/contents/bg.png b/sce_sys/livearea/contents/bg.png new file mode 100644 index 0000000..b4abd5d Binary files /dev/null and b/sce_sys/livearea/contents/bg.png differ diff --git a/sce_sys/livearea/contents/startup.png b/sce_sys/livearea/contents/startup.png new file mode 100644 index 0000000..3152ec5 Binary files /dev/null and b/sce_sys/livearea/contents/startup.png differ diff --git a/sce_sys/livearea/contents/template.xml b/sce_sys/livearea/contents/template.xml new file mode 100644 index 0000000..3fdeadf --- /dev/null +++ b/sce_sys/livearea/contents/template.xml @@ -0,0 +1,11 @@ + + + + + bg.png + + + + startup.png + + diff --git a/src/actions.cpp b/src/actions.cpp new file mode 100644 index 0000000..bfca2fd --- /dev/null +++ b/src/actions.cpp @@ -0,0 +1,87 @@ +#include "fs.h" +#include "config.h" +#include "windows.h" +#include "ftpclient.h" + +namespace Actions { + + void HandleChangeLocalDirectory(FsEntry *entry) + { + if (!entry->isDir) + return; + + if (strcmp(entry->name, "..") == 0) + { + std::string temp_path = std::string(entry->directory); + sprintf(local_directory, "%s", temp_path.substr(0, temp_path.find_last_of("/")).c_str()); + sprintf(local_file_to_select, "%s", temp_path.substr(temp_path.find_last_of("/")+1).c_str()); + } + else + { + sprintf(local_directory, "%s", entry->path); + sprintf(local_file_to_select, ".."); + } + local_files.clear(); + local_files = FS::ListDir(local_directory); + FS::Sort(local_files); + selected_local_file = nullptr; + selected_action = NONE; + } + + void HandleChangeRemoteDirectory(FtpDirEntry *entry) + { + if (!entry->isDir) + return; + + if (strcmp(entry->name, "..") == 0) + { + std::string temp_path = std::string(entry->directory); + if (temp_path.size()>1) + { + if (temp_path.find_last_of("/") == 0) + { + sprintf(remote_directory, "/"); + } + else + { + sprintf(remote_directory, "%s", temp_path.substr(0, temp_path.find_last_of("/")).c_str()); + } + } + sprintf(remote_file_to_select, "%s", temp_path.substr(temp_path.find_last_of("/")+1).c_str()); + } + else + { + sprintf(remote_directory, "%s", entry->path); + sprintf(remote_file_to_select, ".."); + } + remote_files.clear(); + remote_files = ftpclient->ListDir(remote_directory); + sprintf(status_message, "%s", ftpclient->LastResponse()); + FtpClient::Sort(remote_files); + selected_remote_file = nullptr; + selected_action = NONE; + } + + void ConnectFTP() + { + if (ftpclient->Connect(ftp_settings.server_ip, ftp_settings.server_port)) + { + if (ftpclient->Login(ftp_settings.username, ftp_settings.password)) + { + remote_files.clear(); + remote_files = ftpclient->ListDir(remote_directory); + FtpClient::Sort(remote_files); + sprintf(status_message, "%s", ftpclient->LastResponse()); + } + else + { + snprintf(status_message, 1024, "%s", ftpclient->LastResponse()); + } + } + else + { + snprintf(status_message, 1024, "%s", ftpclient->LastResponse()); + } + selected_action = NONE; + } +} diff --git a/src/actions.h b/src/actions.h new file mode 100644 index 0000000..2f559f5 --- /dev/null +++ b/src/actions.h @@ -0,0 +1,26 @@ +#ifndef ACTIONS_H +#define ACTIONS_H + +#include "fs.h" + +enum ACTIONS { + NONE = 0, + CHANGE_LOCAL_DIRECTORY, + COPY_LOCAL, + PASTE_LOCAL, + DELETE_LOCAL, + CHANGE_REMOTE_DIRECTORY, + COPY_REMOTE, + PASTE_REMOTE, + DELETE_REMOTE, + CONNECT_FTP +}; + +namespace Actions { + + void HandleChangeLocalDirectory(FsEntry *entry); + void HandleChangeRemoteDirectory(FtpDirEntry *entry); + void ConnectFTP(); +} + +#endif \ No newline at end of file diff --git a/src/audio.c b/src/audio.c new file mode 100644 index 0000000..027d397 --- /dev/null +++ b/src/audio.c @@ -0,0 +1,107 @@ +#include +#include +#include + +#include "audio.h" +#include "vitaaudiolib.h" +#include "ogg.h" + +enum Audio_FileType { + FILE_TYPE_NONE, + FILE_TYPE_OGG +}; + +typedef struct { + int (* init)(const char *path); + SceUInt32 (* rate)(void); + SceUInt8 (* channels)(void); + void (* decode)(void *buf, unsigned int length, void *userdata); + SceUInt64 (* position)(void); + SceUInt64 (* length)(void); + SceUInt64 (* seek)(SceUInt64 index); + void (* term)(void); +} Audio_Decoder; + +static enum Audio_FileType file_type = FILE_TYPE_NONE; +Audio_Metadata metadata = {0}; +static Audio_Metadata empty_metadata = {0}; +static Audio_Decoder decoder = {0}, empty_decoder = {0}; +SceBool playing = SCE_TRUE, m_paused = SCE_FALSE; + +static void Audio_Decode(void *buf, unsigned int length, void *userdata) { + if (playing == SCE_FALSE || m_paused == SCE_TRUE) { + short *buf_short = (short *)buf; + unsigned int count; + for (count = 0; count < length * 2; count++) + *(buf_short + count) = 0; + } + else + (* decoder.decode)(buf, length, userdata); +} + +int Audio_Init(const char *path) { + playing = SCE_TRUE; + m_paused = SCE_FALSE; + + file_type = FILE_TYPE_OGG; + decoder.init = OGG_Init; + decoder.rate = OGG_GetSampleRate; + decoder.channels = OGG_GetChannels; + decoder.decode = OGG_Decode; + decoder.position = OGG_GetPosition; + decoder.length = OGG_GetLength; + decoder.seek = OGG_Seek; + decoder.term = OGG_Term; + + (* decoder.init)(path); + vitaAudioInit((* decoder.rate)(), (* decoder.channels)() == 2? SCE_AUDIO_OUT_MODE_STEREO : SCE_AUDIO_OUT_MODE_MONO); + vitaAudioSetChannelCallback(0, Audio_Decode, NULL); + return 0; +} + +SceBool Audio_IsPaused(void) { + return m_paused; +} + +void Audio_Pause(void) { + m_paused = !m_paused; +} + +void Audio_Stop(void) { + playing = !playing; +} + +SceUInt64 Audio_GetPosition(void) { + return (* decoder.position)(); +} + +SceUInt64 Audio_GetLength(void) { + return (* decoder.length)(); +} + +SceUInt64 Audio_GetPositionSeconds(void) { + return (Audio_GetPosition() / (* decoder.rate)()); +} + +SceUInt64 Audio_GetLengthSeconds(void) { + return (Audio_GetLength() / (* decoder.rate)()); +} + +SceUInt64 Audio_Seek(SceUInt64 index) { + return (* decoder.seek)(index); +} + +void Audio_Term(void) { + playing = SCE_TRUE; + m_paused = SCE_FALSE; + + vitaAudioSetChannelCallback(0, NULL, NULL); // Clear channel callback + vitaAudioEndPre(); + sceKernelDelayThread(100 * 1000); + vitaAudioEnd(); + (* decoder.term)(); + + // Clear metadata struct + metadata = empty_metadata; + decoder = empty_decoder; +} diff --git a/src/audio.h b/src/audio.h new file mode 100644 index 0000000..ec99ad7 --- /dev/null +++ b/src/audio.h @@ -0,0 +1,35 @@ +#ifndef _ELEVENMPV_AUDIO_H_ +#define _ELEVENMPV_AUDIO_H_ + +#include +#include + +#define R_FAILED(res) ((res)<0) + +extern SceBool playing, paused; + +typedef struct { + SceBool has_meta; + char title[64]; + char album[64]; + char artist[64]; + char year[64]; + char comment[64]; + char genre[64]; + vita2d_texture *cover_image; +} Audio_Metadata; + +extern Audio_Metadata metadata; + +int Audio_Init(const char *path); +SceBool Audio_IsPaused(void); +void Audio_Pause(void); +void Audio_Stop(void); +SceUInt64 Audio_GetPosition(void); +SceUInt64 Audio_GetLength(void); +SceUInt64 Audio_GetPositionSeconds(void); +SceUInt64 Audio_GetLengthSeconds(void); +SceUInt64 Audio_Seek(SceUInt64 index); +void Audio_Term(void); + +#endif diff --git a/src/certs.h b/src/certs.h new file mode 100644 index 0000000..41b85c4 --- /dev/null +++ b/src/certs.h @@ -0,0 +1,383 @@ +/* Generated by bin2c, do not edit manually */ + +/* Contents of file DigiCert High Assurance EV Root CA.pem */ +static long int DigiCert_High_Assurance_EV_Root_CA_pem_size = 1390; +static char DigiCert_High_Assurance_EV_Root_CA_pem[1390] = { + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0D, 0x0A, 0x4D, 0x49, 0x49, + 0x44, 0x78, 0x54, 0x43, 0x43, 0x41, 0x71, 0x32, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x51, 0x41, 0x71, 0x78, 0x63, 0x4A, 0x6D, 0x6F, 0x4C, 0x51, 0x4A, 0x75, 0x50, 0x43, 0x33, 0x6E, + 0x79, 0x72, 0x6B, 0x59, 0x6C, 0x64, 0x7A, 0x41, 0x4E, 0x42, 0x67, 0x6B, 0x71, 0x68, 0x6B, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x73, 0x0D, 0x0A, 0x4D, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4A, 0x56, 0x55, + 0x7A, 0x45, 0x56, 0x4D, 0x42, 0x4D, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4D, 0x4D, 0x52, + 0x47, 0x6C, 0x6E, 0x61, 0x55, 0x4E, 0x6C, 0x63, 0x6E, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6A, 0x4D, + 0x52, 0x6B, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4C, 0x45, 0x78, 0x42, 0x33, 0x0D, + 0x0A, 0x64, 0x33, 0x63, 0x75, 0x5A, 0x47, 0x6C, 0x6E, 0x61, 0x57, 0x4E, 0x6C, 0x63, 0x6E, 0x51, + 0x75, 0x59, 0x32, 0x39, 0x74, 0x4D, 0x53, 0x73, 0x77, 0x4B, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x44, 0x45, 0x79, 0x4A, 0x45, 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, + 0x49, 0x61, 0x57, 0x64, 0x6F, 0x49, 0x45, 0x46, 0x7A, 0x63, 0x33, 0x56, 0x79, 0x59, 0x57, 0x35, + 0x6A, 0x0D, 0x0A, 0x5A, 0x53, 0x42, 0x46, 0x56, 0x69, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, + 0x45, 0x4E, 0x42, 0x4D, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x32, 0x4D, 0x54, 0x45, 0x78, 0x4D, + 0x44, 0x41, 0x77, 0x4D, 0x44, 0x41, 0x77, 0x4D, 0x46, 0x6F, 0x58, 0x44, 0x54, 0x4D, 0x78, 0x4D, + 0x54, 0x45, 0x78, 0x4D, 0x44, 0x41, 0x77, 0x4D, 0x44, 0x41, 0x77, 0x4D, 0x46, 0x6F, 0x77, 0x62, + 0x44, 0x45, 0x4C, 0x0D, 0x0A, 0x4D, 0x41, 0x6B, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4D, + 0x43, 0x56, 0x56, 0x4D, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x6F, + 0x54, 0x44, 0x45, 0x52, 0x70, 0x5A, 0x32, 0x6C, 0x44, 0x5A, 0x58, 0x4A, 0x30, 0x49, 0x45, 0x6C, + 0x75, 0x59, 0x7A, 0x45, 0x5A, 0x4D, 0x42, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4D, + 0x51, 0x64, 0x33, 0x64, 0x33, 0x0D, 0x0A, 0x4C, 0x6D, 0x52, 0x70, 0x5A, 0x32, 0x6C, 0x6A, 0x5A, + 0x58, 0x4A, 0x30, 0x4C, 0x6D, 0x4E, 0x76, 0x62, 0x54, 0x45, 0x72, 0x4D, 0x43, 0x6B, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x78, 0x4D, 0x69, 0x52, 0x47, 0x6C, 0x6E, 0x61, 0x55, 0x4E, 0x6C, 0x63, + 0x6E, 0x51, 0x67, 0x53, 0x47, 0x6C, 0x6E, 0x61, 0x43, 0x42, 0x42, 0x63, 0x33, 0x4E, 0x31, 0x63, + 0x6D, 0x46, 0x75, 0x59, 0x32, 0x55, 0x67, 0x0D, 0x0A, 0x52, 0x56, 0x59, 0x67, 0x55, 0x6D, 0x39, + 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, + 0x4A, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x63, 0x4E, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, + 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6F, 0x43, 0x67, 0x67, 0x45, + 0x42, 0x41, 0x4D, 0x62, 0x4D, 0x35, 0x58, 0x50, 0x6D, 0x0D, 0x0A, 0x2B, 0x39, 0x53, 0x37, 0x35, + 0x53, 0x30, 0x74, 0x4D, 0x71, 0x62, 0x66, 0x35, 0x59, 0x45, 0x2F, 0x79, 0x63, 0x30, 0x6C, 0x53, + 0x62, 0x5A, 0x78, 0x4B, 0x73, 0x50, 0x56, 0x6C, 0x44, 0x52, 0x6E, 0x6F, 0x67, 0x6F, 0x63, 0x73, + 0x46, 0x39, 0x70, 0x70, 0x6B, 0x43, 0x78, 0x78, 0x4C, 0x65, 0x79, 0x6A, 0x39, 0x43, 0x59, 0x70, + 0x4B, 0x6C, 0x42, 0x57, 0x54, 0x72, 0x54, 0x33, 0x4A, 0x54, 0x57, 0x0D, 0x0A, 0x50, 0x4E, 0x74, + 0x30, 0x4F, 0x4B, 0x52, 0x4B, 0x7A, 0x45, 0x30, 0x6C, 0x67, 0x76, 0x64, 0x4B, 0x70, 0x56, 0x4D, + 0x53, 0x4F, 0x4F, 0x37, 0x7A, 0x53, 0x57, 0x31, 0x78, 0x6B, 0x58, 0x35, 0x6A, 0x74, 0x71, 0x75, + 0x6D, 0x58, 0x38, 0x4F, 0x6B, 0x68, 0x50, 0x68, 0x50, 0x59, 0x6C, 0x47, 0x2B, 0x2B, 0x4D, 0x58, + 0x73, 0x32, 0x7A, 0x69, 0x53, 0x34, 0x77, 0x62, 0x6C, 0x43, 0x4A, 0x45, 0x4D, 0x0D, 0x0A, 0x78, + 0x43, 0x68, 0x42, 0x56, 0x66, 0x76, 0x4C, 0x57, 0x6F, 0x6B, 0x56, 0x66, 0x6E, 0x48, 0x6F, 0x4E, + 0x62, 0x39, 0x4E, 0x63, 0x67, 0x6B, 0x39, 0x76, 0x6A, 0x6F, 0x34, 0x55, 0x46, 0x74, 0x33, 0x4D, + 0x52, 0x75, 0x4E, 0x73, 0x38, 0x63, 0x6B, 0x52, 0x5A, 0x71, 0x6E, 0x72, 0x47, 0x30, 0x41, 0x46, + 0x46, 0x6F, 0x45, 0x74, 0x37, 0x6F, 0x54, 0x36, 0x31, 0x45, 0x4B, 0x6D, 0x45, 0x46, 0x42, 0x0D, + 0x0A, 0x49, 0x6B, 0x35, 0x6C, 0x59, 0x59, 0x65, 0x42, 0x51, 0x56, 0x43, 0x6D, 0x65, 0x56, 0x79, + 0x4A, 0x33, 0x68, 0x6C, 0x4B, 0x56, 0x39, 0x55, 0x75, 0x35, 0x6C, 0x30, 0x63, 0x55, 0x79, 0x78, + 0x2B, 0x6D, 0x4D, 0x30, 0x61, 0x42, 0x68, 0x61, 0x6B, 0x61, 0x48, 0x50, 0x51, 0x4E, 0x41, 0x51, + 0x54, 0x58, 0x4B, 0x46, 0x78, 0x30, 0x31, 0x70, 0x38, 0x56, 0x64, 0x74, 0x65, 0x5A, 0x4F, 0x45, + 0x33, 0x0D, 0x0A, 0x68, 0x7A, 0x42, 0x57, 0x42, 0x4F, 0x55, 0x52, 0x74, 0x43, 0x6D, 0x41, 0x45, + 0x76, 0x46, 0x35, 0x4F, 0x59, 0x69, 0x69, 0x41, 0x68, 0x46, 0x38, 0x4A, 0x32, 0x61, 0x33, 0x69, + 0x4C, 0x64, 0x34, 0x38, 0x73, 0x6F, 0x4B, 0x71, 0x44, 0x69, 0x72, 0x43, 0x6D, 0x54, 0x43, 0x76, + 0x32, 0x5A, 0x64, 0x6C, 0x59, 0x54, 0x42, 0x6F, 0x53, 0x55, 0x65, 0x68, 0x31, 0x30, 0x61, 0x55, + 0x41, 0x73, 0x67, 0x0D, 0x0A, 0x45, 0x73, 0x78, 0x42, 0x75, 0x32, 0x34, 0x4C, 0x55, 0x54, 0x69, + 0x34, 0x53, 0x38, 0x73, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4E, 0x6A, 0x4D, 0x47, 0x45, + 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2F, 0x42, 0x41, 0x51, + 0x44, 0x41, 0x67, 0x47, 0x47, 0x4D, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, + 0x42, 0x2F, 0x77, 0x51, 0x46, 0x0D, 0x0A, 0x4D, 0x41, 0x4D, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, + 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4F, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4C, 0x45, 0x2B, 0x77, + 0x32, 0x6B, 0x44, 0x2B, 0x4C, 0x39, 0x48, 0x41, 0x64, 0x53, 0x59, 0x4A, 0x68, 0x6F, 0x49, 0x41, + 0x75, 0x39, 0x6A, 0x5A, 0x43, 0x76, 0x44, 0x4D, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x49, + 0x77, 0x51, 0x59, 0x4D, 0x42, 0x61, 0x41, 0x0D, 0x0A, 0x46, 0x4C, 0x45, 0x2B, 0x77, 0x32, 0x6B, + 0x44, 0x2B, 0x4C, 0x39, 0x48, 0x41, 0x64, 0x53, 0x59, 0x4A, 0x68, 0x6F, 0x49, 0x41, 0x75, 0x39, + 0x6A, 0x5A, 0x43, 0x76, 0x44, 0x4D, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x41, + 0x63, 0x47, 0x67, 0x61, 0x58, 0x33, 0x4E, 0x65, 0x63, 0x0D, 0x0A, 0x6E, 0x7A, 0x79, 0x49, 0x5A, + 0x67, 0x59, 0x49, 0x56, 0x79, 0x48, 0x62, 0x49, 0x55, 0x66, 0x34, 0x4B, 0x6D, 0x65, 0x71, 0x76, + 0x78, 0x67, 0x79, 0x64, 0x6B, 0x41, 0x51, 0x56, 0x38, 0x47, 0x4B, 0x38, 0x33, 0x72, 0x5A, 0x45, + 0x57, 0x57, 0x4F, 0x4E, 0x66, 0x71, 0x65, 0x2F, 0x45, 0x57, 0x31, 0x6E, 0x74, 0x6C, 0x4D, 0x4D, + 0x55, 0x75, 0x34, 0x6B, 0x65, 0x68, 0x44, 0x4C, 0x49, 0x36, 0x7A, 0x0D, 0x0A, 0x65, 0x4D, 0x37, + 0x62, 0x34, 0x31, 0x4E, 0x35, 0x63, 0x64, 0x62, 0x6C, 0x49, 0x5A, 0x51, 0x42, 0x32, 0x6C, 0x57, + 0x48, 0x6D, 0x69, 0x52, 0x6B, 0x39, 0x6F, 0x70, 0x6D, 0x7A, 0x4E, 0x36, 0x63, 0x4E, 0x38, 0x32, + 0x6F, 0x4E, 0x4C, 0x46, 0x70, 0x6D, 0x79, 0x50, 0x49, 0x6E, 0x6E, 0x67, 0x69, 0x4B, 0x33, 0x42, + 0x44, 0x34, 0x31, 0x56, 0x48, 0x4D, 0x57, 0x45, 0x5A, 0x37, 0x31, 0x6A, 0x46, 0x0D, 0x0A, 0x68, + 0x53, 0x39, 0x4F, 0x4D, 0x50, 0x61, 0x67, 0x4D, 0x52, 0x59, 0x6A, 0x79, 0x4F, 0x66, 0x69, 0x5A, + 0x52, 0x59, 0x7A, 0x79, 0x37, 0x38, 0x61, 0x47, 0x36, 0x41, 0x39, 0x2B, 0x4D, 0x70, 0x65, 0x69, + 0x7A, 0x47, 0x4C, 0x59, 0x41, 0x69, 0x4A, 0x4C, 0x51, 0x77, 0x47, 0x58, 0x46, 0x4B, 0x33, 0x78, + 0x50, 0x6B, 0x4B, 0x6D, 0x4E, 0x45, 0x56, 0x58, 0x35, 0x38, 0x53, 0x76, 0x6E, 0x77, 0x32, 0x0D, + 0x0A, 0x59, 0x7A, 0x69, 0x39, 0x52, 0x4B, 0x52, 0x2F, 0x35, 0x43, 0x59, 0x72, 0x43, 0x73, 0x53, + 0x58, 0x61, 0x51, 0x33, 0x70, 0x6A, 0x4F, 0x4C, 0x41, 0x45, 0x46, 0x65, 0x34, 0x79, 0x48, 0x59, + 0x53, 0x6B, 0x56, 0x58, 0x79, 0x53, 0x47, 0x6E, 0x59, 0x76, 0x43, 0x6F, 0x43, 0x57, 0x77, 0x39, + 0x45, 0x31, 0x43, 0x41, 0x78, 0x32, 0x2F, 0x53, 0x36, 0x63, 0x43, 0x5A, 0x64, 0x6B, 0x47, 0x43, + 0x65, 0x0D, 0x0A, 0x76, 0x45, 0x73, 0x58, 0x43, 0x53, 0x2B, 0x30, 0x79, 0x78, 0x35, 0x44, 0x61, + 0x4D, 0x6B, 0x48, 0x4A, 0x38, 0x48, 0x53, 0x58, 0x50, 0x66, 0x71, 0x49, 0x62, 0x6C, 0x6F, 0x45, + 0x70, 0x77, 0x38, 0x6E, 0x4C, 0x2B, 0x65, 0x2F, 0x49, 0x42, 0x63, 0x6D, 0x32, 0x50, 0x4E, 0x37, + 0x45, 0x65, 0x71, 0x4A, 0x53, 0x64, 0x6E, 0x6F, 0x44, 0x66, 0x7A, 0x41, 0x49, 0x4A, 0x39, 0x56, + 0x4E, 0x65, 0x70, 0x0D, 0x0A, 0x2B, 0x4F, 0x6B, 0x75, 0x45, 0x36, 0x4E, 0x33, 0x36, 0x42, 0x39, + 0x4B, 0x0D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0D, 0x0A +}; + +/* Contents of file DigiCert SHA2 High Assurance Server CA.pem */ +static long int DigiCert_SHA2_High_Assurance_Server_CA_pem_size = 1716; +static char DigiCert_SHA2_High_Assurance_Server_CA_pem[1716] = { + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0D, 0x0A, 0x4D, 0x49, 0x49, + 0x45, 0x73, 0x54, 0x43, 0x43, 0x41, 0x35, 0x6D, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x51, 0x42, 0x4F, 0x48, 0x6E, 0x70, 0x4E, 0x78, 0x63, 0x38, 0x76, 0x4E, 0x74, 0x77, 0x43, 0x74, + 0x43, 0x75, 0x46, 0x30, 0x56, 0x6E, 0x7A, 0x41, 0x4E, 0x42, 0x67, 0x6B, 0x71, 0x68, 0x6B, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x73, 0x0D, 0x0A, 0x4D, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4A, 0x56, 0x55, + 0x7A, 0x45, 0x56, 0x4D, 0x42, 0x4D, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4D, 0x4D, 0x52, + 0x47, 0x6C, 0x6E, 0x61, 0x55, 0x4E, 0x6C, 0x63, 0x6E, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6A, 0x4D, + 0x52, 0x6B, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4C, 0x45, 0x78, 0x42, 0x33, 0x0D, + 0x0A, 0x64, 0x33, 0x63, 0x75, 0x5A, 0x47, 0x6C, 0x6E, 0x61, 0x57, 0x4E, 0x6C, 0x63, 0x6E, 0x51, + 0x75, 0x59, 0x32, 0x39, 0x74, 0x4D, 0x53, 0x73, 0x77, 0x4B, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x44, 0x45, 0x79, 0x4A, 0x45, 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, + 0x49, 0x61, 0x57, 0x64, 0x6F, 0x49, 0x45, 0x46, 0x7A, 0x63, 0x33, 0x56, 0x79, 0x59, 0x57, 0x35, + 0x6A, 0x0D, 0x0A, 0x5A, 0x53, 0x42, 0x46, 0x56, 0x69, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, + 0x45, 0x4E, 0x42, 0x4D, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x7A, 0x4D, 0x54, 0x41, 0x79, 0x4D, + 0x6A, 0x45, 0x79, 0x4D, 0x44, 0x41, 0x77, 0x4D, 0x46, 0x6F, 0x58, 0x44, 0x54, 0x49, 0x34, 0x4D, + 0x54, 0x41, 0x79, 0x4D, 0x6A, 0x45, 0x79, 0x4D, 0x44, 0x41, 0x77, 0x4D, 0x46, 0x6F, 0x77, 0x63, + 0x44, 0x45, 0x4C, 0x0D, 0x0A, 0x4D, 0x41, 0x6B, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4D, + 0x43, 0x56, 0x56, 0x4D, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x6F, + 0x54, 0x44, 0x45, 0x52, 0x70, 0x5A, 0x32, 0x6C, 0x44, 0x5A, 0x58, 0x4A, 0x30, 0x49, 0x45, 0x6C, + 0x75, 0x59, 0x7A, 0x45, 0x5A, 0x4D, 0x42, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4D, + 0x51, 0x64, 0x33, 0x64, 0x33, 0x0D, 0x0A, 0x4C, 0x6D, 0x52, 0x70, 0x5A, 0x32, 0x6C, 0x6A, 0x5A, + 0x58, 0x4A, 0x30, 0x4C, 0x6D, 0x4E, 0x76, 0x62, 0x54, 0x45, 0x76, 0x4D, 0x43, 0x30, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x78, 0x4D, 0x6D, 0x52, 0x47, 0x6C, 0x6E, 0x61, 0x55, 0x4E, 0x6C, 0x63, + 0x6E, 0x51, 0x67, 0x55, 0x30, 0x68, 0x42, 0x4D, 0x69, 0x42, 0x49, 0x61, 0x57, 0x64, 0x6F, 0x49, + 0x45, 0x46, 0x7A, 0x63, 0x33, 0x56, 0x79, 0x0D, 0x0A, 0x59, 0x57, 0x35, 0x6A, 0x5A, 0x53, 0x42, + 0x54, 0x5A, 0x58, 0x4A, 0x32, 0x5A, 0x58, 0x49, 0x67, 0x51, 0x30, 0x45, 0x77, 0x67, 0x67, 0x45, + 0x69, 0x4D, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, + 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, + 0x4B, 0x41, 0x6F, 0x49, 0x42, 0x41, 0x51, 0x43, 0x32, 0x0D, 0x0A, 0x34, 0x43, 0x2F, 0x43, 0x4A, + 0x41, 0x62, 0x49, 0x62, 0x51, 0x52, 0x66, 0x31, 0x2B, 0x38, 0x4B, 0x5A, 0x41, 0x61, 0x79, 0x66, + 0x53, 0x49, 0x6D, 0x5A, 0x52, 0x61, 0x75, 0x51, 0x6B, 0x43, 0x62, 0x7A, 0x74, 0x79, 0x66, 0x6E, + 0x33, 0x59, 0x48, 0x50, 0x73, 0x4D, 0x77, 0x56, 0x59, 0x63, 0x5A, 0x75, 0x55, 0x2B, 0x55, 0x44, + 0x6C, 0x71, 0x55, 0x48, 0x31, 0x56, 0x57, 0x74, 0x4D, 0x49, 0x43, 0x0D, 0x0A, 0x4B, 0x71, 0x2F, + 0x51, 0x6D, 0x4F, 0x34, 0x4C, 0x51, 0x4E, 0x66, 0x45, 0x30, 0x44, 0x74, 0x79, 0x79, 0x42, 0x53, + 0x65, 0x37, 0x35, 0x43, 0x78, 0x45, 0x61, 0x6D, 0x75, 0x30, 0x73, 0x69, 0x34, 0x51, 0x7A, 0x72, + 0x5A, 0x43, 0x77, 0x76, 0x56, 0x31, 0x5A, 0x58, 0x31, 0x51, 0x4B, 0x2F, 0x49, 0x48, 0x65, 0x31, + 0x4E, 0x6E, 0x46, 0x39, 0x58, 0x74, 0x34, 0x5A, 0x51, 0x61, 0x4A, 0x6E, 0x31, 0x0D, 0x0A, 0x69, + 0x74, 0x72, 0x53, 0x78, 0x77, 0x55, 0x66, 0x71, 0x4A, 0x66, 0x4A, 0x33, 0x4B, 0x53, 0x78, 0x67, + 0x6F, 0x51, 0x74, 0x78, 0x71, 0x32, 0x6C, 0x6E, 0x4D, 0x63, 0x5A, 0x67, 0x71, 0x61, 0x46, 0x44, + 0x31, 0x35, 0x45, 0x57, 0x43, 0x6F, 0x33, 0x6A, 0x2F, 0x30, 0x31, 0x38, 0x51, 0x73, 0x49, 0x4A, + 0x7A, 0x4A, 0x61, 0x39, 0x62, 0x75, 0x4C, 0x6E, 0x71, 0x53, 0x39, 0x55, 0x64, 0x41, 0x6E, 0x0D, + 0x0A, 0x34, 0x74, 0x30, 0x37, 0x51, 0x6A, 0x4F, 0x6A, 0x42, 0x53, 0x6A, 0x45, 0x75, 0x79, 0x6A, + 0x4D, 0x6D, 0x71, 0x77, 0x72, 0x49, 0x77, 0x31, 0x34, 0x78, 0x6E, 0x76, 0x6D, 0x58, 0x6E, 0x47, + 0x33, 0x53, 0x6A, 0x34, 0x49, 0x2B, 0x34, 0x47, 0x33, 0x46, 0x68, 0x61, 0x68, 0x6E, 0x53, 0x4D, + 0x53, 0x54, 0x65, 0x58, 0x58, 0x6B, 0x67, 0x69, 0x73, 0x64, 0x61, 0x53, 0x63, 0x75, 0x73, 0x30, + 0x58, 0x0D, 0x0A, 0x73, 0x68, 0x35, 0x45, 0x4E, 0x57, 0x56, 0x2F, 0x55, 0x79, 0x55, 0x35, 0x30, + 0x52, 0x77, 0x4B, 0x6D, 0x6D, 0x4D, 0x62, 0x47, 0x5A, 0x4A, 0x30, 0x61, 0x41, 0x6F, 0x33, 0x77, + 0x73, 0x4A, 0x53, 0x53, 0x4D, 0x73, 0x35, 0x57, 0x71, 0x4B, 0x32, 0x34, 0x56, 0x33, 0x42, 0x33, + 0x61, 0x41, 0x67, 0x75, 0x43, 0x47, 0x69, 0x6B, 0x79, 0x5A, 0x76, 0x46, 0x45, 0x6F, 0x68, 0x51, + 0x63, 0x66, 0x74, 0x0D, 0x0A, 0x62, 0x5A, 0x76, 0x79, 0x53, 0x43, 0x2F, 0x7A, 0x41, 0x2F, 0x57, + 0x69, 0x61, 0x4A, 0x4A, 0x54, 0x4C, 0x31, 0x37, 0x6A, 0x41, 0x67, 0x4D, 0x42, 0x41, 0x41, 0x47, + 0x6A, 0x67, 0x67, 0x46, 0x4A, 0x4D, 0x49, 0x49, 0x42, 0x52, 0x54, 0x41, 0x53, 0x42, 0x67, 0x4E, + 0x56, 0x48, 0x52, 0x4D, 0x42, 0x41, 0x66, 0x38, 0x45, 0x43, 0x44, 0x41, 0x47, 0x41, 0x51, 0x48, + 0x2F, 0x41, 0x67, 0x45, 0x41, 0x0D, 0x0A, 0x4D, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, + 0x77, 0x45, 0x42, 0x2F, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x68, 0x6A, 0x41, 0x64, 0x42, + 0x67, 0x4E, 0x56, 0x48, 0x53, 0x55, 0x45, 0x46, 0x6A, 0x41, 0x55, 0x42, 0x67, 0x67, 0x72, 0x42, + 0x67, 0x45, 0x46, 0x42, 0x51, 0x63, 0x44, 0x41, 0x51, 0x59, 0x49, 0x4B, 0x77, 0x59, 0x42, 0x42, + 0x51, 0x55, 0x48, 0x41, 0x77, 0x49, 0x77, 0x0D, 0x0A, 0x4E, 0x41, 0x59, 0x49, 0x4B, 0x77, 0x59, + 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, 0x51, 0x45, 0x45, 0x4B, 0x44, 0x41, 0x6D, 0x4D, 0x43, 0x51, + 0x47, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x7A, 0x41, 0x42, 0x68, 0x68, 0x68, + 0x6F, 0x64, 0x48, 0x52, 0x77, 0x4F, 0x69, 0x38, 0x76, 0x62, 0x32, 0x4E, 0x7A, 0x63, 0x43, 0x35, + 0x6B, 0x61, 0x57, 0x64, 0x70, 0x59, 0x32, 0x56, 0x79, 0x0D, 0x0A, 0x64, 0x43, 0x35, 0x6A, 0x62, + 0x32, 0x30, 0x77, 0x53, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, 0x45, 0x51, 0x77, 0x51, + 0x6A, 0x42, 0x41, 0x6F, 0x44, 0x36, 0x67, 0x50, 0x49, 0x59, 0x36, 0x61, 0x48, 0x52, 0x30, 0x63, + 0x44, 0x6F, 0x76, 0x4C, 0x32, 0x4E, 0x79, 0x62, 0x44, 0x51, 0x75, 0x5A, 0x47, 0x6C, 0x6E, 0x61, + 0x57, 0x4E, 0x6C, 0x63, 0x6E, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x0D, 0x0A, 0x4C, 0x30, 0x52, + 0x70, 0x5A, 0x32, 0x6C, 0x44, 0x5A, 0x58, 0x4A, 0x30, 0x53, 0x47, 0x6C, 0x6E, 0x61, 0x45, 0x46, + 0x7A, 0x63, 0x33, 0x56, 0x79, 0x59, 0x57, 0x35, 0x6A, 0x5A, 0x55, 0x56, 0x57, 0x55, 0x6D, 0x39, + 0x76, 0x64, 0x45, 0x4E, 0x42, 0x4C, 0x6D, 0x4E, 0x79, 0x62, 0x44, 0x41, 0x39, 0x42, 0x67, 0x4E, + 0x56, 0x48, 0x53, 0x41, 0x45, 0x4E, 0x6A, 0x41, 0x30, 0x4D, 0x44, 0x49, 0x47, 0x0D, 0x0A, 0x42, + 0x46, 0x55, 0x64, 0x49, 0x41, 0x41, 0x77, 0x4B, 0x6A, 0x41, 0x6F, 0x42, 0x67, 0x67, 0x72, 0x42, + 0x67, 0x45, 0x46, 0x42, 0x51, 0x63, 0x43, 0x41, 0x52, 0x59, 0x63, 0x61, 0x48, 0x52, 0x30, 0x63, + 0x48, 0x4D, 0x36, 0x4C, 0x79, 0x39, 0x33, 0x64, 0x33, 0x63, 0x75, 0x5A, 0x47, 0x6C, 0x6E, 0x61, + 0x57, 0x4E, 0x6C, 0x63, 0x6E, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4C, 0x30, 0x4E, 0x51, 0x0D, + 0x0A, 0x55, 0x7A, 0x41, 0x64, 0x42, 0x67, 0x4E, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, + 0x55, 0x55, 0x57, 0x6A, 0x2F, 0x6B, 0x4B, 0x38, 0x43, 0x42, 0x33, 0x55, 0x38, 0x7A, 0x4E, 0x6C, + 0x6C, 0x5A, 0x47, 0x4B, 0x69, 0x45, 0x72, 0x68, 0x5A, 0x63, 0x6A, 0x73, 0x77, 0x48, 0x77, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x6A, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6F, 0x41, 0x55, 0x73, 0x54, 0x37, + 0x44, 0x0D, 0x0A, 0x61, 0x51, 0x50, 0x34, 0x76, 0x30, 0x63, 0x42, 0x31, 0x4A, 0x67, 0x6D, 0x47, + 0x67, 0x67, 0x43, 0x37, 0x32, 0x4E, 0x6B, 0x4B, 0x38, 0x4D, 0x77, 0x44, 0x51, 0x59, 0x4A, 0x4B, + 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x63, 0x4E, 0x41, 0x51, 0x45, 0x4C, 0x42, 0x51, 0x41, 0x44, 0x67, + 0x67, 0x45, 0x42, 0x41, 0x42, 0x69, 0x4B, 0x6C, 0x59, 0x6B, 0x44, 0x35, 0x6D, 0x33, 0x66, 0x58, + 0x50, 0x77, 0x64, 0x0D, 0x0A, 0x61, 0x4F, 0x70, 0x4B, 0x6A, 0x34, 0x50, 0x57, 0x55, 0x53, 0x2B, + 0x4E, 0x61, 0x30, 0x51, 0x57, 0x6E, 0x71, 0x78, 0x6A, 0x39, 0x64, 0x4A, 0x75, 0x62, 0x49, 0x53, + 0x5A, 0x69, 0x36, 0x71, 0x42, 0x63, 0x59, 0x52, 0x62, 0x37, 0x54, 0x52, 0x4F, 0x73, 0x4C, 0x64, + 0x35, 0x6B, 0x69, 0x6E, 0x4D, 0x4C, 0x59, 0x42, 0x71, 0x38, 0x49, 0x34, 0x67, 0x34, 0x58, 0x6D, + 0x6B, 0x2F, 0x67, 0x4E, 0x48, 0x0D, 0x0A, 0x45, 0x2B, 0x72, 0x31, 0x68, 0x73, 0x70, 0x5A, 0x63, + 0x58, 0x33, 0x30, 0x42, 0x4A, 0x5A, 0x72, 0x30, 0x31, 0x6C, 0x59, 0x50, 0x66, 0x37, 0x54, 0x4D, + 0x53, 0x56, 0x63, 0x47, 0x44, 0x69, 0x45, 0x6F, 0x2B, 0x61, 0x66, 0x67, 0x76, 0x32, 0x4D, 0x57, + 0x35, 0x67, 0x78, 0x54, 0x73, 0x31, 0x34, 0x6E, 0x68, 0x72, 0x39, 0x68, 0x63, 0x74, 0x4A, 0x71, + 0x76, 0x49, 0x6E, 0x69, 0x35, 0x6C, 0x79, 0x0D, 0x0A, 0x2F, 0x44, 0x36, 0x71, 0x31, 0x55, 0x45, + 0x4C, 0x32, 0x74, 0x55, 0x32, 0x6F, 0x62, 0x38, 0x63, 0x62, 0x6B, 0x64, 0x4A, 0x66, 0x31, 0x37, + 0x5A, 0x53, 0x48, 0x77, 0x44, 0x32, 0x66, 0x32, 0x4C, 0x53, 0x61, 0x43, 0x59, 0x4A, 0x6B, 0x4A, + 0x41, 0x36, 0x39, 0x61, 0x53, 0x45, 0x61, 0x52, 0x6B, 0x43, 0x6C, 0x64, 0x55, 0x78, 0x50, 0x55, + 0x64, 0x31, 0x67, 0x4A, 0x65, 0x61, 0x36, 0x7A, 0x75, 0x0D, 0x0A, 0x78, 0x49, 0x43, 0x61, 0x45, + 0x6E, 0x4C, 0x36, 0x56, 0x70, 0x50, 0x58, 0x2F, 0x37, 0x38, 0x77, 0x68, 0x51, 0x59, 0x77, 0x76, + 0x77, 0x74, 0x2F, 0x54, 0x76, 0x39, 0x58, 0x42, 0x5A, 0x30, 0x6B, 0x37, 0x59, 0x58, 0x44, 0x4B, + 0x2F, 0x75, 0x6D, 0x64, 0x61, 0x69, 0x73, 0x4C, 0x52, 0x62, 0x76, 0x66, 0x58, 0x6B, 0x6E, 0x73, + 0x75, 0x76, 0x43, 0x6E, 0x51, 0x73, 0x48, 0x36, 0x71, 0x71, 0x46, 0x0D, 0x0A, 0x30, 0x77, 0x47, + 0x6A, 0x49, 0x43, 0x68, 0x42, 0x57, 0x55, 0x4D, 0x6F, 0x30, 0x6F, 0x48, 0x6A, 0x71, 0x76, 0x62, + 0x73, 0x65, 0x7A, 0x74, 0x33, 0x74, 0x6B, 0x42, 0x69, 0x67, 0x41, 0x56, 0x42, 0x52, 0x51, 0x48, + 0x76, 0x46, 0x77, 0x59, 0x2B, 0x33, 0x73, 0x41, 0x7A, 0x6D, 0x32, 0x66, 0x54, 0x59, 0x53, 0x35, + 0x79, 0x68, 0x2B, 0x52, 0x70, 0x2F, 0x42, 0x49, 0x41, 0x56, 0x30, 0x41, 0x65, 0x0D, 0x0A, 0x63, + 0x50, 0x55, 0x65, 0x79, 0x62, 0x51, 0x3D, 0x0D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, + 0x2D, 0x2D, 0x0D, 0x0A +}; + +static long int Baltimore_CyberTrust_Root_pem_size = 1282; +static char Baltimore_CyberTrust_Root_pem[1282] = { + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0D, 0x0A, 0x4D, 0x49, 0x49, + 0x44, 0x64, 0x7A, 0x43, 0x43, 0x41, 0x6C, 0x2B, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x45, 0x41, 0x67, 0x41, 0x41, 0x75, 0x54, 0x41, 0x4E, 0x42, 0x67, 0x6B, 0x71, 0x68, 0x6B, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x61, 0x4D, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4A, 0x4A, 0x0D, 0x0A, 0x52, + 0x54, 0x45, 0x53, 0x4D, 0x42, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4D, 0x4A, 0x51, + 0x6D, 0x46, 0x73, 0x64, 0x47, 0x6C, 0x74, 0x62, 0x33, 0x4A, 0x6C, 0x4D, 0x52, 0x4D, 0x77, 0x45, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4C, 0x45, 0x77, 0x70, 0x44, 0x65, 0x57, 0x4A, 0x6C, 0x63, + 0x6C, 0x52, 0x79, 0x64, 0x58, 0x4E, 0x30, 0x4D, 0x53, 0x49, 0x77, 0x49, 0x41, 0x59, 0x44, 0x0D, + 0x0A, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x6C, 0x43, 0x59, 0x57, 0x78, 0x30, 0x61, 0x57, 0x31, + 0x76, 0x63, 0x6D, 0x55, 0x67, 0x51, 0x33, 0x6C, 0x69, 0x5A, 0x58, 0x4A, 0x55, 0x63, 0x6E, 0x56, + 0x7A, 0x64, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x4D, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, + 0x77, 0x4D, 0x44, 0x55, 0x78, 0x4D, 0x6A, 0x45, 0x34, 0x4E, 0x44, 0x59, 0x77, 0x4D, 0x46, 0x6F, + 0x58, 0x0D, 0x0A, 0x44, 0x54, 0x49, 0x31, 0x4D, 0x44, 0x55, 0x78, 0x4D, 0x6A, 0x49, 0x7A, 0x4E, + 0x54, 0x6B, 0x77, 0x4D, 0x46, 0x6F, 0x77, 0x57, 0x6A, 0x45, 0x4C, 0x4D, 0x41, 0x6B, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4D, 0x43, 0x53, 0x55, 0x55, 0x78, 0x45, 0x6A, 0x41, 0x51, 0x42, + 0x67, 0x4E, 0x56, 0x42, 0x41, 0x6F, 0x54, 0x43, 0x55, 0x4A, 0x68, 0x62, 0x48, 0x52, 0x70, 0x62, + 0x57, 0x39, 0x79, 0x0D, 0x0A, 0x5A, 0x54, 0x45, 0x54, 0x4D, 0x42, 0x45, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x78, 0x4D, 0x4B, 0x51, 0x33, 0x6C, 0x69, 0x5A, 0x58, 0x4A, 0x55, 0x63, 0x6E, 0x56, + 0x7A, 0x64, 0x44, 0x45, 0x69, 0x4D, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4D, + 0x5A, 0x51, 0x6D, 0x46, 0x73, 0x64, 0x47, 0x6C, 0x74, 0x62, 0x33, 0x4A, 0x6C, 0x49, 0x45, 0x4E, + 0x35, 0x59, 0x6D, 0x56, 0x79, 0x0D, 0x0A, 0x56, 0x48, 0x4A, 0x31, 0x63, 0x33, 0x51, 0x67, 0x55, + 0x6D, 0x39, 0x76, 0x64, 0x44, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4A, 0x4B, + 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x63, 0x4E, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, + 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6F, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, + 0x4B, 0x4D, 0x45, 0x75, 0x79, 0x4B, 0x72, 0x0D, 0x0A, 0x6D, 0x44, 0x31, 0x58, 0x36, 0x43, 0x5A, + 0x79, 0x6D, 0x72, 0x56, 0x35, 0x31, 0x43, 0x6E, 0x69, 0x34, 0x65, 0x69, 0x56, 0x67, 0x4C, 0x47, + 0x77, 0x34, 0x31, 0x75, 0x4F, 0x4B, 0x79, 0x6D, 0x61, 0x5A, 0x4E, 0x2B, 0x68, 0x58, 0x65, 0x32, + 0x77, 0x43, 0x51, 0x56, 0x74, 0x32, 0x79, 0x67, 0x75, 0x7A, 0x6D, 0x4B, 0x69, 0x59, 0x76, 0x36, + 0x30, 0x69, 0x4E, 0x6F, 0x53, 0x36, 0x7A, 0x6A, 0x72, 0x0D, 0x0A, 0x49, 0x5A, 0x33, 0x41, 0x51, + 0x53, 0x73, 0x42, 0x55, 0x6E, 0x75, 0x49, 0x64, 0x39, 0x4D, 0x63, 0x6A, 0x38, 0x65, 0x36, 0x75, + 0x59, 0x69, 0x31, 0x61, 0x67, 0x6E, 0x6E, 0x63, 0x2B, 0x67, 0x52, 0x51, 0x4B, 0x66, 0x52, 0x7A, + 0x4D, 0x70, 0x69, 0x6A, 0x53, 0x33, 0x6C, 0x6A, 0x77, 0x75, 0x6D, 0x55, 0x4E, 0x4B, 0x6F, 0x55, + 0x4D, 0x4D, 0x6F, 0x36, 0x76, 0x57, 0x72, 0x4A, 0x59, 0x65, 0x4B, 0x0D, 0x0A, 0x6D, 0x70, 0x59, + 0x63, 0x71, 0x57, 0x65, 0x34, 0x50, 0x77, 0x7A, 0x56, 0x39, 0x2F, 0x6C, 0x53, 0x45, 0x79, 0x2F, + 0x43, 0x47, 0x39, 0x56, 0x77, 0x63, 0x50, 0x43, 0x50, 0x77, 0x42, 0x4C, 0x4B, 0x42, 0x73, 0x75, + 0x61, 0x34, 0x64, 0x6E, 0x4B, 0x4D, 0x33, 0x70, 0x33, 0x31, 0x76, 0x6A, 0x73, 0x75, 0x66, 0x46, + 0x6F, 0x52, 0x45, 0x4A, 0x49, 0x45, 0x39, 0x4C, 0x41, 0x77, 0x71, 0x53, 0x75, 0x0D, 0x0A, 0x58, + 0x6D, 0x44, 0x2B, 0x74, 0x71, 0x59, 0x46, 0x2F, 0x4C, 0x54, 0x64, 0x42, 0x31, 0x6B, 0x43, 0x31, + 0x46, 0x6B, 0x59, 0x6D, 0x47, 0x50, 0x31, 0x70, 0x57, 0x50, 0x67, 0x6B, 0x41, 0x78, 0x39, 0x58, + 0x62, 0x49, 0x47, 0x65, 0x76, 0x4F, 0x46, 0x36, 0x75, 0x76, 0x55, 0x41, 0x36, 0x35, 0x65, 0x68, + 0x44, 0x35, 0x66, 0x2F, 0x78, 0x58, 0x74, 0x61, 0x62, 0x7A, 0x35, 0x4F, 0x54, 0x5A, 0x79, 0x0D, + 0x0A, 0x64, 0x63, 0x39, 0x33, 0x55, 0x6B, 0x33, 0x7A, 0x79, 0x5A, 0x41, 0x73, 0x75, 0x54, 0x33, + 0x6C, 0x79, 0x53, 0x4E, 0x54, 0x50, 0x78, 0x38, 0x6B, 0x6D, 0x43, 0x46, 0x63, 0x42, 0x35, 0x6B, + 0x70, 0x76, 0x63, 0x59, 0x36, 0x37, 0x4F, 0x64, 0x75, 0x68, 0x6A, 0x70, 0x72, 0x6C, 0x33, 0x52, + 0x6A, 0x4D, 0x37, 0x31, 0x6F, 0x47, 0x44, 0x48, 0x77, 0x65, 0x49, 0x31, 0x32, 0x76, 0x2F, 0x79, + 0x65, 0x0D, 0x0A, 0x6A, 0x6C, 0x30, 0x71, 0x68, 0x71, 0x64, 0x4E, 0x6B, 0x4E, 0x77, 0x6E, 0x47, + 0x6A, 0x6B, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4E, 0x46, 0x4D, 0x45, 0x4D, 0x77, 0x48, + 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4F, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4F, 0x57, 0x64, 0x57, + 0x54, 0x43, 0x43, 0x52, 0x31, 0x6A, 0x4D, 0x72, 0x50, 0x6F, 0x49, 0x56, 0x44, 0x61, 0x47, 0x65, + 0x7A, 0x71, 0x31, 0x0D, 0x0A, 0x42, 0x45, 0x33, 0x77, 0x4D, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x45, 0x77, 0x45, 0x42, 0x2F, 0x77, 0x51, 0x49, 0x4D, 0x41, 0x59, 0x42, 0x41, 0x66, 0x38, + 0x43, 0x41, 0x51, 0x4D, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, + 0x2F, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4D, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x33, 0x0D, 0x0A, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, + 0x34, 0x49, 0x42, 0x41, 0x51, 0x43, 0x46, 0x44, 0x46, 0x32, 0x4F, 0x35, 0x47, 0x39, 0x52, 0x61, + 0x45, 0x49, 0x46, 0x6F, 0x4E, 0x32, 0x37, 0x54, 0x79, 0x63, 0x6C, 0x68, 0x41, 0x4F, 0x39, 0x39, + 0x32, 0x54, 0x39, 0x4C, 0x64, 0x63, 0x77, 0x34, 0x36, 0x51, 0x51, 0x46, 0x2B, 0x76, 0x61, 0x4B, + 0x53, 0x6D, 0x32, 0x65, 0x54, 0x39, 0x32, 0x0D, 0x0A, 0x39, 0x68, 0x6B, 0x54, 0x49, 0x37, 0x67, + 0x51, 0x43, 0x76, 0x6C, 0x59, 0x70, 0x4E, 0x52, 0x68, 0x63, 0x4C, 0x30, 0x45, 0x59, 0x57, 0x6F, + 0x53, 0x69, 0x68, 0x66, 0x56, 0x43, 0x72, 0x33, 0x46, 0x76, 0x44, 0x42, 0x38, 0x31, 0x75, 0x6B, + 0x4D, 0x4A, 0x59, 0x32, 0x47, 0x51, 0x45, 0x2F, 0x73, 0x7A, 0x4B, 0x4E, 0x2B, 0x4F, 0x4D, 0x59, + 0x33, 0x45, 0x55, 0x2F, 0x74, 0x33, 0x57, 0x67, 0x78, 0x0D, 0x0A, 0x6A, 0x6B, 0x7A, 0x53, 0x73, + 0x77, 0x46, 0x30, 0x37, 0x72, 0x35, 0x31, 0x58, 0x67, 0x64, 0x49, 0x47, 0x6E, 0x39, 0x77, 0x2F, + 0x78, 0x5A, 0x63, 0x68, 0x4D, 0x42, 0x35, 0x68, 0x62, 0x67, 0x46, 0x2F, 0x58, 0x2B, 0x2B, 0x5A, + 0x52, 0x47, 0x6A, 0x44, 0x38, 0x41, 0x43, 0x74, 0x50, 0x68, 0x53, 0x4E, 0x7A, 0x6B, 0x45, 0x31, + 0x61, 0x6B, 0x78, 0x65, 0x68, 0x69, 0x2F, 0x6F, 0x43, 0x72, 0x30, 0x0D, 0x0A, 0x45, 0x70, 0x6E, + 0x33, 0x6F, 0x30, 0x57, 0x43, 0x34, 0x7A, 0x78, 0x65, 0x39, 0x5A, 0x32, 0x65, 0x74, 0x63, 0x69, + 0x65, 0x66, 0x43, 0x37, 0x49, 0x70, 0x4A, 0x35, 0x4F, 0x43, 0x42, 0x52, 0x4C, 0x62, 0x66, 0x31, + 0x77, 0x62, 0x57, 0x73, 0x61, 0x59, 0x37, 0x31, 0x6B, 0x35, 0x68, 0x2B, 0x33, 0x7A, 0x76, 0x44, + 0x79, 0x6E, 0x79, 0x36, 0x37, 0x47, 0x37, 0x66, 0x79, 0x55, 0x49, 0x68, 0x7A, 0x0D, 0x0A, 0x6B, + 0x73, 0x4C, 0x69, 0x34, 0x78, 0x61, 0x4E, 0x6D, 0x6A, 0x49, 0x43, 0x71, 0x34, 0x34, 0x59, 0x33, + 0x65, 0x6B, 0x51, 0x45, 0x65, 0x35, 0x2B, 0x4E, 0x61, 0x75, 0x51, 0x72, 0x7A, 0x34, 0x77, 0x6C, + 0x48, 0x72, 0x51, 0x4D, 0x7A, 0x32, 0x6E, 0x5A, 0x51, 0x2F, 0x31, 0x2F, 0x49, 0x36, 0x65, 0x59, + 0x73, 0x39, 0x48, 0x52, 0x43, 0x77, 0x42, 0x58, 0x62, 0x73, 0x64, 0x74, 0x54, 0x4C, 0x53, 0x0D, + 0x0A, 0x52, 0x39, 0x49, 0x34, 0x4C, 0x74, 0x44, 0x2B, 0x67, 0x64, 0x77, 0x79, 0x61, 0x68, 0x36, + 0x31, 0x37, 0x6A, 0x7A, 0x56, 0x2F, 0x4F, 0x65, 0x42, 0x48, 0x52, 0x6E, 0x44, 0x4A, 0x45, 0x4C, + 0x71, 0x59, 0x7A, 0x6D, 0x70, 0x0D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x0D, 0x0A +}; + +static long int Cloudflare_Inc_ECC_CA_3_pem_size = 1402; +static char Cloudflare_Inc_ECC_CA_3_pem[1402] = { + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0D, 0x0A, 0x4D, 0x49, 0x49, + 0x44, 0x7A, 0x54, 0x43, 0x43, 0x41, 0x72, 0x57, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x51, 0x43, 0x6A, 0x65, 0x48, 0x5A, 0x46, 0x35, 0x66, 0x74, 0x49, 0x77, 0x69, 0x54, 0x76, 0x30, + 0x62, 0x37, 0x52, 0x51, 0x4D, 0x50, 0x44, 0x41, 0x4E, 0x42, 0x67, 0x6B, 0x71, 0x68, 0x6B, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x61, 0x0D, 0x0A, 0x4D, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4A, 0x4A, 0x52, + 0x54, 0x45, 0x53, 0x4D, 0x42, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4D, 0x4A, 0x51, + 0x6D, 0x46, 0x73, 0x64, 0x47, 0x6C, 0x74, 0x62, 0x33, 0x4A, 0x6C, 0x4D, 0x52, 0x4D, 0x77, 0x45, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4C, 0x45, 0x77, 0x70, 0x44, 0x65, 0x57, 0x4A, 0x6C, 0x0D, + 0x0A, 0x63, 0x6C, 0x52, 0x79, 0x64, 0x58, 0x4E, 0x30, 0x4D, 0x53, 0x49, 0x77, 0x49, 0x41, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x6C, 0x43, 0x59, 0x57, 0x78, 0x30, 0x61, 0x57, 0x31, + 0x76, 0x63, 0x6D, 0x55, 0x67, 0x51, 0x33, 0x6C, 0x69, 0x5A, 0x58, 0x4A, 0x55, 0x63, 0x6E, 0x56, + 0x7A, 0x64, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x4D, 0x42, 0x34, 0x58, 0x44, 0x54, 0x49, + 0x77, 0x0D, 0x0A, 0x4D, 0x44, 0x45, 0x79, 0x4E, 0x7A, 0x45, 0x79, 0x4E, 0x44, 0x67, 0x77, 0x4F, + 0x46, 0x6F, 0x58, 0x44, 0x54, 0x49, 0x30, 0x4D, 0x54, 0x49, 0x7A, 0x4D, 0x54, 0x49, 0x7A, 0x4E, + 0x54, 0x6B, 0x31, 0x4F, 0x56, 0x6F, 0x77, 0x53, 0x6A, 0x45, 0x4C, 0x4D, 0x41, 0x6B, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4D, 0x43, 0x56, 0x56, 0x4D, 0x78, 0x47, 0x54, 0x41, 0x58, 0x42, + 0x67, 0x4E, 0x56, 0x0D, 0x0A, 0x42, 0x41, 0x6F, 0x54, 0x45, 0x45, 0x4E, 0x73, 0x62, 0x33, 0x56, + 0x6B, 0x5A, 0x6D, 0x78, 0x68, 0x63, 0x6D, 0x55, 0x73, 0x49, 0x45, 0x6C, 0x75, 0x59, 0x79, 0x34, + 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x4D, 0x54, 0x46, 0x30, 0x4E, + 0x73, 0x62, 0x33, 0x56, 0x6B, 0x5A, 0x6D, 0x78, 0x68, 0x63, 0x6D, 0x55, 0x67, 0x53, 0x57, 0x35, + 0x6A, 0x49, 0x45, 0x56, 0x44, 0x0D, 0x0A, 0x51, 0x79, 0x42, 0x44, 0x51, 0x53, 0x30, 0x7A, 0x4D, + 0x46, 0x6B, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, 0x43, 0x41, + 0x51, 0x59, 0x49, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, + 0x67, 0x41, 0x45, 0x75, 0x61, 0x31, 0x4E, 0x5A, 0x70, 0x6B, 0x55, 0x43, 0x30, 0x62, 0x73, 0x48, + 0x34, 0x48, 0x52, 0x4B, 0x6C, 0x41, 0x65, 0x0D, 0x0A, 0x6E, 0x51, 0x4D, 0x56, 0x4C, 0x7A, 0x51, + 0x53, 0x66, 0x53, 0x32, 0x57, 0x75, 0x49, 0x67, 0x34, 0x6D, 0x34, 0x56, 0x66, 0x6A, 0x37, 0x2B, + 0x37, 0x54, 0x65, 0x39, 0x68, 0x52, 0x73, 0x54, 0x4A, 0x63, 0x39, 0x51, 0x6B, 0x54, 0x2B, 0x44, + 0x75, 0x48, 0x4D, 0x35, 0x73, 0x73, 0x31, 0x46, 0x78, 0x4C, 0x32, 0x72, 0x75, 0x54, 0x41, 0x55, + 0x4A, 0x64, 0x39, 0x4E, 0x79, 0x59, 0x71, 0x53, 0x62, 0x0D, 0x0A, 0x31, 0x36, 0x4F, 0x43, 0x41, + 0x57, 0x67, 0x77, 0x67, 0x67, 0x46, 0x6B, 0x4D, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, + 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, 0x6C, 0x7A, 0x6A, 0x66, 0x71, 0x36, 0x37, 0x42, 0x31, 0x44, + 0x70, 0x52, 0x6E, 0x69, 0x4C, 0x52, 0x46, 0x2B, 0x74, 0x6B, 0x6B, 0x45, 0x49, 0x65, 0x57, 0x48, + 0x7A, 0x41, 0x66, 0x42, 0x67, 0x4E, 0x56, 0x48, 0x53, 0x4D, 0x45, 0x0D, 0x0A, 0x47, 0x44, 0x41, + 0x57, 0x67, 0x42, 0x54, 0x6C, 0x6E, 0x56, 0x6B, 0x77, 0x67, 0x6B, 0x64, 0x59, 0x7A, 0x4B, 0x7A, + 0x36, 0x43, 0x46, 0x51, 0x32, 0x68, 0x6E, 0x73, 0x36, 0x74, 0x51, 0x52, 0x4E, 0x38, 0x44, 0x41, + 0x4F, 0x42, 0x67, 0x4E, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4D, + 0x43, 0x41, 0x59, 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6C, 0x0D, 0x0A, 0x42, + 0x42, 0x59, 0x77, 0x46, 0x41, 0x59, 0x49, 0x4B, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, + 0x77, 0x45, 0x47, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77, 0x4D, 0x43, 0x4D, + 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2F, 0x77, 0x51, 0x49, 0x4D, + 0x41, 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, 0x41, 0x77, 0x4E, 0x41, 0x59, 0x49, 0x0D, + 0x0A, 0x4B, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, 0x51, 0x45, 0x45, 0x4B, 0x44, 0x41, + 0x6D, 0x4D, 0x43, 0x51, 0x47, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x7A, 0x41, + 0x42, 0x68, 0x68, 0x68, 0x6F, 0x64, 0x48, 0x52, 0x77, 0x4F, 0x69, 0x38, 0x76, 0x62, 0x32, 0x4E, + 0x7A, 0x63, 0x43, 0x35, 0x6B, 0x61, 0x57, 0x64, 0x70, 0x59, 0x32, 0x56, 0x79, 0x64, 0x43, 0x35, + 0x6A, 0x0D, 0x0A, 0x62, 0x32, 0x30, 0x77, 0x4F, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, + 0x44, 0x4D, 0x77, 0x4D, 0x54, 0x41, 0x76, 0x6F, 0x43, 0x32, 0x67, 0x4B, 0x34, 0x59, 0x70, 0x61, + 0x48, 0x52, 0x30, 0x63, 0x44, 0x6F, 0x76, 0x4C, 0x32, 0x4E, 0x79, 0x62, 0x44, 0x4D, 0x75, 0x5A, + 0x47, 0x6C, 0x6E, 0x61, 0x57, 0x4E, 0x6C, 0x63, 0x6E, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4C, + 0x30, 0x39, 0x74, 0x0D, 0x0A, 0x62, 0x6D, 0x6C, 0x79, 0x62, 0x32, 0x39, 0x30, 0x4D, 0x6A, 0x41, + 0x79, 0x4E, 0x53, 0x35, 0x6A, 0x63, 0x6D, 0x77, 0x77, 0x62, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x67, 0x42, 0x47, 0x59, 0x77, 0x5A, 0x44, 0x41, 0x33, 0x42, 0x67, 0x6C, 0x67, 0x68, 0x6B, 0x67, + 0x42, 0x68, 0x76, 0x31, 0x73, 0x41, 0x51, 0x45, 0x77, 0x4B, 0x6A, 0x41, 0x6F, 0x42, 0x67, 0x67, + 0x72, 0x42, 0x67, 0x45, 0x46, 0x0D, 0x0A, 0x42, 0x51, 0x63, 0x43, 0x41, 0x52, 0x59, 0x63, 0x61, + 0x48, 0x52, 0x30, 0x63, 0x48, 0x4D, 0x36, 0x4C, 0x79, 0x39, 0x33, 0x64, 0x33, 0x63, 0x75, 0x5A, + 0x47, 0x6C, 0x6E, 0x61, 0x57, 0x4E, 0x6C, 0x63, 0x6E, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4C, + 0x30, 0x4E, 0x51, 0x55, 0x7A, 0x41, 0x4C, 0x42, 0x67, 0x6C, 0x67, 0x68, 0x6B, 0x67, 0x42, 0x68, + 0x76, 0x31, 0x73, 0x41, 0x51, 0x49, 0x77, 0x0D, 0x0A, 0x43, 0x41, 0x59, 0x47, 0x5A, 0x34, 0x45, + 0x4D, 0x41, 0x51, 0x49, 0x42, 0x4D, 0x41, 0x67, 0x47, 0x42, 0x6D, 0x65, 0x42, 0x44, 0x41, 0x45, + 0x43, 0x41, 0x6A, 0x41, 0x49, 0x42, 0x67, 0x5A, 0x6E, 0x67, 0x51, 0x77, 0x42, 0x41, 0x67, 0x4D, + 0x77, 0x44, 0x51, 0x59, 0x4A, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x63, 0x4E, 0x41, 0x51, 0x45, + 0x4C, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x0D, 0x0A, 0x41, 0x41, 0x55, 0x6B, 0x48, + 0x64, 0x30, 0x62, 0x73, 0x43, 0x72, 0x72, 0x6D, 0x4E, 0x61, 0x46, 0x34, 0x7A, 0x6C, 0x4E, 0x58, + 0x6D, 0x74, 0x58, 0x6E, 0x59, 0x4A, 0x58, 0x2F, 0x4F, 0x76, 0x6F, 0x4D, 0x61, 0x4A, 0x58, 0x6B, + 0x47, 0x55, 0x46, 0x76, 0x68, 0x5A, 0x45, 0x4F, 0x46, 0x70, 0x33, 0x41, 0x72, 0x6E, 0x50, 0x45, + 0x45, 0x4C, 0x47, 0x34, 0x5A, 0x4B, 0x6B, 0x34, 0x30, 0x55, 0x6E, 0x0D, 0x0A, 0x2B, 0x41, 0x42, + 0x48, 0x4C, 0x47, 0x69, 0x6F, 0x56, 0x70, 0x6C, 0x54, 0x56, 0x49, 0x2B, 0x74, 0x6E, 0x6B, 0x44, + 0x42, 0x30, 0x41, 0x2B, 0x32, 0x31, 0x77, 0x30, 0x4C, 0x4F, 0x45, 0x68, 0x73, 0x55, 0x43, 0x78, + 0x4A, 0x6B, 0x41, 0x5A, 0x62, 0x5A, 0x42, 0x32, 0x4C, 0x7A, 0x45, 0x67, 0x77, 0x4C, 0x74, 0x34, + 0x49, 0x34, 0x70, 0x74, 0x4A, 0x49, 0x73, 0x43, 0x53, 0x44, 0x42, 0x46, 0x65, 0x0D, 0x0A, 0x6C, + 0x70, 0x4B, 0x55, 0x31, 0x66, 0x77, 0x67, 0x33, 0x46, 0x5A, 0x73, 0x35, 0x5A, 0x4B, 0x54, 0x76, + 0x33, 0x6F, 0x63, 0x77, 0x44, 0x66, 0x6A, 0x68, 0x55, 0x6B, 0x56, 0x2B, 0x69, 0x76, 0x68, 0x64, + 0x44, 0x6B, 0x59, 0x44, 0x37, 0x66, 0x61, 0x38, 0x36, 0x4A, 0x58, 0x57, 0x47, 0x42, 0x50, 0x7A, + 0x49, 0x36, 0x55, 0x41, 0x50, 0x78, 0x47, 0x65, 0x7A, 0x51, 0x78, 0x50, 0x6B, 0x31, 0x48, 0x0D, + 0x0A, 0x67, 0x6F, 0x45, 0x36, 0x79, 0x2F, 0x53, 0x4A, 0x58, 0x51, 0x37, 0x76, 0x54, 0x51, 0x31, + 0x75, 0x6E, 0x42, 0x75, 0x43, 0x4A, 0x4E, 0x30, 0x79, 0x4A, 0x56, 0x30, 0x52, 0x65, 0x46, 0x45, + 0x51, 0x50, 0x61, 0x41, 0x31, 0x49, 0x77, 0x51, 0x76, 0x5A, 0x57, 0x2B, 0x63, 0x77, 0x64, 0x46, + 0x44, 0x31, 0x39, 0x41, 0x65, 0x38, 0x7A, 0x46, 0x6E, 0x57, 0x53, 0x66, 0x64, 0x61, 0x39, 0x4A, + 0x31, 0x0D, 0x0A, 0x43, 0x5A, 0x4D, 0x52, 0x4A, 0x43, 0x51, 0x55, 0x7A, 0x79, 0x6D, 0x2B, 0x35, + 0x69, 0x50, 0x44, 0x75, 0x49, 0x39, 0x79, 0x50, 0x2B, 0x6B, 0x48, 0x79, 0x43, 0x52, 0x45, 0x55, + 0x33, 0x71, 0x7A, 0x75, 0x57, 0x46, 0x6C, 0x6F, 0x55, 0x77, 0x4F, 0x78, 0x6B, 0x67, 0x41, 0x79, + 0x58, 0x56, 0x6A, 0x42, 0x59, 0x64, 0x77, 0x52, 0x56, 0x4B, 0x44, 0x30, 0x35, 0x57, 0x64, 0x52, + 0x65, 0x72, 0x77, 0x0D, 0x0A, 0x36, 0x44, 0x45, 0x64, 0x66, 0x67, 0x6B, 0x66, 0x43, 0x76, 0x34, + 0x2B, 0x33, 0x61, 0x6F, 0x38, 0x58, 0x6E, 0x54, 0x53, 0x72, 0x4C, 0x45, 0x3D, 0x0D, 0x0A, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0D, 0x0A +}; diff --git a/src/config.cpp b/src/config.cpp new file mode 100644 index 0000000..e8b10eb --- /dev/null +++ b/src/config.cpp @@ -0,0 +1,128 @@ +#include +#include +#include +#include + +#include "config.h" +#include "fs.h" +#include "style.h" + + +extern "C" { + #include "inifile.h" +} + +bool swap_xo; +std::vector bg_music_list; +bool enable_backgrou_music; +FtpSettings ftp_settings; +char local_directory[MAX_PATH_LENGTH]; +char remote_directory[MAX_PATH_LENGTH]; + +namespace CONFIG { + + void LoadConfig() + { + const char* bg_music_list_str; + + if (!FS::FolderExists(DATA_PATH)) + { + FS::MkDirs(DATA_PATH); + } + + OpenIniFile (CONFIG_INI_FILE); + + // Load styles + if (!FS::FolderExists(STYLES_FOLDER)) + { + FS::MkDirs(STYLES_FOLDER); + } + + char* style_value = ReadString(CONFIG_GLOBAL, CONFIG_STYLE_NAME, CONFIG_DEFAULT_STYLE_NAME); + sprintf(style_name, "%s", style_value); + WriteString(CONFIG_GLOBAL, CONFIG_STYLE_NAME, style_name); + Style::SetStylePath(style_name); + + // Load global config + swap_xo = ReadBool(CONFIG_GLOBAL, CONFIG_SWAP_XO, false); + WriteBool(CONFIG_GLOBAL, CONFIG_SWAP_XO, swap_xo); + + bg_music_list_str = ReadString(CONFIG_GLOBAL, CONFIG_BACKGROUD_MUSIC, "ux0:/app/FTPCLIENT/music.ogg"); + ParseMultiValueString(bg_music_list_str, bg_music_list, false); + WriteString(CONFIG_GLOBAL, CONFIG_BACKGROUD_MUSIC, bg_music_list_str); + + enable_backgrou_music = ReadBool(CONFIG_GLOBAL, CONFIG_ENABLE_BACKGROUND_MUSIC, true); + WriteBool(CONFIG_GLOBAL, CONFIG_ENABLE_BACKGROUND_MUSIC, enable_backgrou_music); + + sprintf(ftp_settings.server_ip, "%s", ReadString(CONFIG_GLOBAL, CONFIG_FTP_SERVER_IP, "192.168.100.14")); + WriteString(CONFIG_GLOBAL, CONFIG_FTP_SERVER_IP, ftp_settings.server_ip); + + ftp_settings.server_port = ReadInt(CONFIG_GLOBAL, CONFIG_FTP_SERVER_PORT, 21); + WriteInt(CONFIG_GLOBAL, CONFIG_FTP_SERVER_PORT, ftp_settings.server_port); + + ftp_settings.pasv_mode = ReadBool(CONFIG_GLOBAL, CONFIG_FTP_TRANSFER_MODE, true); + WriteBool(CONFIG_GLOBAL, CONFIG_FTP_TRANSFER_MODE, ftp_settings.pasv_mode); + + sprintf(ftp_settings.username, "%s", ReadString(CONFIG_GLOBAL, CONFIG_FTP_SERVER_USER, "demo")); + WriteString(CONFIG_GLOBAL, CONFIG_FTP_SERVER_USER, ftp_settings.username); + + sprintf(ftp_settings.password, "%s", ReadString(CONFIG_GLOBAL, CONFIG_FTP_SERVER_PASSWORD, "12345678")); + WriteString(CONFIG_GLOBAL, CONFIG_FTP_SERVER_PASSWORD, ftp_settings.password); + + sprintf(local_directory, "%s", ReadString(CONFIG_GLOBAL, CONFIG_LOCAL_DIRECTORY, "ux0:")); + 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); + + WriteIniFile(CONFIG_INI_FILE); + CloseIniFile(); + } + + void ParseMultiValueString(const char* prefix_list, std::vector &prefixes, bool toLower) + { + std::string prefix = ""; + int length = strlen(prefix_list); + for (int i=0; i &multi_values) + { + std::string vts = std::string(""); + if (multi_values.size() > 0) + { + for (int i=0; i &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); + } +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..8b6513e --- /dev/null +++ b/src/config.h @@ -0,0 +1,80 @@ +#ifndef LAUNCHER_CONFIG_H +#define LAUNCHER_CONFIG_H + +#include +#include +#include +#include "fs.h" + +#define APP_ID "FTPCLIENT" +#define DATA_PATH "ux0:data/" APP_ID +#define CONFIG_INI_FILE DATA_PATH "/config.ini" + +#define CONFIG_GLOBAL "Global" + +#define CONFIG_STYLE_NAME "style" +#define CONFIG_DEFAULT_STYLE_NAME "Default" +#define CONFIG_SWAP_XO "swap_xo" + +#define CONFIG_BACKGROUD_MUSIC "backgroud_music" +#define CONFIG_ENABLE_BACKGROUND_MUSIC "enable_backgroud_music" + +#define CONFIG_FTP_SERVER_IP "ftp_server_ip" +#define CONFIG_FTP_SERVER_PORT "ftp_server_port" +#define CONFIG_FTP_SERVER_USER "ftp_server_user" +#define CONFIG_FTP_SERVER_PASSWORD "ftp_server_password" +#define CONFIG_FTP_TRANSFER_MODE "ftp_transfer_mode" + +#define CONFIG_LOCAL_DIRECTORY "local_directory" +#define CONFIG_REMOTE_DIRECTORY "remote_directory" + +struct FtpSettings { + char server_ip[16]; + char username[33]; + char password[25]; + int server_port; + bool pasv_mode; +}; + +extern bool swap_xo; +extern std::vector bg_music_list; +extern bool enable_backgrou_music; +extern FtpSettings ftp_settings; +extern char local_directory[]; +extern char remote_directory[]; + +namespace CONFIG { + void LoadConfig(); + void RemoveFromMultiValues(std::vector &multi_values, std::string value); + void ParseMultiValueString(const char* prefix_list, std::vector &prefixes, bool toLower); + std::string GetMultiValueString(std::vector &multi_values); + + 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()); + } + } +} +#endif diff --git a/src/crypt.h b/src/crypt.h new file mode 100644 index 0000000..d1d155c --- /dev/null +++ b/src/crypt.h @@ -0,0 +1,137 @@ +/* crypt.h -- base code for traditional PKWARE encryption + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + Modifications for Info-ZIP crypting + Copyright (C) 2003 Terry Thorsen + + This code is a modified version of crypting code in Info-ZIP distribution + + Copyright (C) 1990-2000 Info-ZIP. All rights reserved. + + See the Info-ZIP LICENSE file version 2000-Apr-09 or later for terms of use + which also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + Mar 8th, 2016 - Lucio Cosmo + Fixed support for 64bit builds for archives with "PKWARE" password. + Changed long, unsigned long, unsigned to unsigned int in + access functions to crctables and pkeys + +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((unsigned int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned int* pkeys) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned int)(*(pkeys+2)) & 0xffff) | 2; + return (unsigned int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned int* pkeys,const unsigned int* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned int* pkeys,const unsigned int* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != 0) + { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned int* pkeys, + const unsigned int* pcrc_32_tab, + unsigned int crcForCrypting) +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize < RAND_HEAD_LEN) + return 0; + + /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the + * output of rand() to get less predictability, since rand() is + * often poorly implemented. + */ + if (++calls == 1) + { + srand((unsigned)(time(NULL) ^ ZCR_SEED2)); + } + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + c = (rand() >> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/src/fs.cpp b/src/fs.cpp new file mode 100644 index 0000000..6fb8c50 --- /dev/null +++ b/src/fs.cpp @@ -0,0 +1,376 @@ +#include "fs.h" + +#include +#include +#include +#include +#include "string.h" +#include "stdio.h" +#include "debugnet.h" +#include + +#define ERRNO_EEXIST (int)(0x80010000 + SCE_NET_EEXIST) +#define ERRNO_ENOENT (int)(0x80010000 + SCE_NET_ENOENT) + +namespace FS { + int hasEndSlash(const char *path) + { + return path[strlen(path) - 1] == '/'; + } + + void MkDirs(const std::string& ppath, bool prev = false) + { + 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 = sceIoMkdir(path.c_str(), 0777); + *ptr = last; + ++ptr; + } + } + + void Rm(const std::string& file) + { + int err = sceIoRemove(file.c_str()); + } + + void RmDir(const std::string& path) + { + sceIoRmdir(path.c_str()); + } + + int64_t GetSize(const std::string& path) + { + SceIoStat stat; + int err = sceIoGetstat(path.c_str(), &stat); + if (err < 0) + { + return -1; + } + return stat.st_size; + } + + bool FileExists(const std::string& path) + { + SceIoStat stat; + return sceIoGetstat(path.c_str(), &stat) >= 0; + } + + bool FolderExists(const std::string& path) + { + SceIoStat stat; + sceIoGetstat(path.c_str(), &stat); + return stat.st_mode & SCE_S_IFDIR; + } + + void Rename(const std::string& from, const std::string& to) + { + // try to remove first because sceIoRename does not overwrite + sceIoRemove(to.c_str()); + int res = sceIoRename(from.c_str(), to.c_str()); + } + + void* Create(const std::string& path) + { + SceUID fd = sceIoOpen( + path.c_str(), SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); + + return (void*)(intptr_t)fd; + } + + void* OpenRW(const std::string& path) + { + SceUID fd = sceIoOpen(path.c_str(), SCE_O_RDWR, 0777); + return (void*)(intptr_t)fd; + } + + void* OpenRead(const std::string& path) + { + SceUID fd = sceIoOpen(path.c_str(), SCE_O_RDONLY, 0777); + return (void*)(intptr_t)fd; + } + + void* Append(const std::string& path) + { + SceUID fd = + sceIoOpen(path.c_str(), SCE_O_WRONLY | SCE_O_CREAT | SCE_O_APPEND, 0777); + return (void*)(intptr_t)fd; + } + + int64_t Seek(void* f, uint64_t offset) + { + auto const pos = sceIoLseek((intptr_t)f, offset, SCE_SEEK_SET); + return pos; + } + + int Read(void* f, void* buffer, uint32_t size) + { + const auto read = sceIoRead((SceUID)(intptr_t)f, buffer, size); + return read; + } + + int Write(void* f, const void* buffer, uint32_t size) + { + int write = sceIoWrite((SceUID)(intptr_t)f, buffer, size); + return write; + } + + void Close(void* f) + { + SceUID fd = (SceUID)(intptr_t)f; + int err = sceIoClose(fd); + } + + std::vector Load(const std::string& path) + { + SceUID fd = sceIoOpen(path.c_str(), SCE_O_RDONLY, 0777); + if (fd < 0) + return std::vector(0); + + const auto size = sceIoLseek(fd, 0, SCE_SEEK_END); + sceIoLseek(fd, 0, SCE_SEEK_SET); + + std::vector data(size); + + const auto read = sceIoRead(fd, data.data(), data.size()); + sceIoClose(fd); + if (read < 0) + return std::vector(0); + + data.resize(read); + + return data; + } + + void Save(const std::string& path, const void* data, uint32_t size) + { + SceUID fd = sceIoOpen( + path.c_str(), SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); + if (fd < 0) + return; + + const char* data8 = static_cast(data); + while (size != 0) + { + int written = sceIoWrite(fd, data8, size); + sceIoClose(fd); + if (written <= 0) + return; + data8 += written; + size -= written; + } + } + + std::vector ListDir(const std::string& ppath) + { + std::vector out; + FsEntry entry; + std::string path = ppath; + if (path.find_last_of("/") == path.size()-1) + { + path = path.substr(0, path.size()-1); + } + memset(&entry, 0, sizeof(FsEntry)); + sprintf(entry.directory, "%s", path.c_str()); + sprintf(entry.name, ".."); + sprintf(entry.display_size, "Folder"); + sprintf(entry.path, "%s", path.c_str()); + entry.file_size = 0; + entry.isDir = true; + out.push_back(entry); + + const auto fd = sceIoDopen(path.c_str()); + if (static_cast(fd) == 0x80010002) + return {}; + if (fd < 0) + return out; + + while (true) + { + SceIoDirent dirent; + FsEntry entry; + const auto ret = sceIoDread(fd, &dirent); + if (ret < 0) { + sceIoDclose(fd); + return out; + } + else if (ret == 0) + break; + else + { + 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(), entry.name); + } + else + { + sprintf(entry.path, "%s/%s", path.c_str(), entry.name); + } + + if (SCE_S_ISDIR(dirent.d_stat.st_mode)) + { + entry.isDir = true; + entry.file_size = 0; + sprintf(entry.display_size, "Folder"); + } + else + { + entry.file_size = dirent.d_stat.st_size; + debugNetPrintf(DEBUG, "name %s, size %lld\n", entry.name, entry.file_size); + if (entry.file_size < 1024) + { + sprintf(entry.display_size, "%lldB", 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); + } + } + sceIoDclose(fd); + + return out; + } + + std::vector ListFiles(const std::string& path) + { + const auto fd = sceIoDopen(path.c_str()); + if (static_cast(fd) == 0x80010002) + return {}; + if (fd < 0) + return std::vector(0); + + std::vector out; + while (true) + { + SceIoDirent dirent; + const auto ret = sceIoDread(fd, &dirent); + if (ret < 0) { + sceIoDclose(fd); + return out; + } + else if (ret == 0) + break; + + if (SCE_S_ISDIR(dirent.d_stat.st_mode)) + { + std::vector files = FS::ListFiles(path + "/" + dirent.d_name); + for (std::vector::iterator it=files.begin(); it!=files.end(); ) + { + out.push_back(std::string(dirent.d_name) + "/" + *it); + ++it; + } + } + else + { + out.push_back(dirent.d_name); + } + } + sceIoDclose(fd); + return out; + } + + int RmRecursive(const std::string& path) + { + SceUID dfd = sceIoDopen(path.c_str()); + if (dfd >= 0) { + int res = 0; + + do + { + SceIoDirent dir; + memset(&dir, 0, sizeof(SceIoDirent)); + res = sceIoDread(dfd, &dir); + if (res > 0) + { + int path_length = strlen(path.c_str()) + strlen(dir.d_name) + 2; + char *new_path = malloc(path_length); + snprintf(new_path, path_length, "%s%s%s", path.c_str(), hasEndSlash(path.c_str()) ? "" : "/", dir.d_name); + + if (SCE_S_ISDIR(dir.d_stat.st_mode)) + { + int ret = RmRecursive(new_path); + if (ret <= 0) { + free(new_path); + sceIoDclose(dfd); + return ret; + } + } + else { + int ret = sceIoRemove(new_path); + if (ret < 0) + { + free(new_path); + sceIoDclose(dfd); + return ret; + } + } + + free(new_path); + } + } while (res > 0); + + sceIoDclose(dfd); + + int ret = sceIoRmdir(path.c_str()); + if (ret < 0) + return ret; + + } else { + int ret = sceIoRemove(path.c_str()); + if (ret < 0) + return ret; + } + + return 1; + } + + int FsEntryComparator(const void *v1, const void *v2) + { + const FsEntry *p1 = (FsEntry *)v1; + const FsEntry *p2 = (FsEntry *)v2; + if (strcasecmp(p1->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 &list) + { + qsort(&list[0], list.size(), sizeof(FsEntry), FsEntryComparator); + } + +} diff --git a/src/fs.h b/src/fs.h new file mode 100644 index 0000000..548db67 --- /dev/null +++ b/src/fs.h @@ -0,0 +1,63 @@ +#ifndef LAUNCHER_FS_H +#define LAUNCHER_FS_H + +#pragma once + +#include +#include + +#include +#define MAX_PATH_LENGTH 1024 + +struct FsEntry { + char directory[512]; + char name[256]; + char display_size[16]; + char path[1024]; + int64_t file_size; + bool isDir; +}; + +namespace FS { + void MkDirs(const std::string& path, bool prev=false); + void MkPrevDirs(const std::string& path); + + void Rm(const std::string& file); + void RmDir(const std::string& path); + int RmRecursive(const std::string& path); + + int64_t GetSize(const char* 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) + void* Create(const std::string& path); + + // open existing file in read/write, fails if file does not exist + void* OpenRW(const std::string& path); + + // open existing file in read/write, fails if file does not exist + void* OpenRead(const std::string& path); + + // open file for writing, next write will append data to end of it + void* Append(const std::string& path); + + void Close(void* f); + + int64_t Seek(void* f, uint64_t offset); + int Read(void* f, void* buffer, uint32_t size); + int Write(void* f, const void* buffer, uint32_t size); + + std::vector Load(const std::string& path); + void Save(const std::string& path, const void* data, uint32_t size); + + std::vector ListDir(const std::string& path); + + void Sort(std::vector &list); + +} + +#endif \ No newline at end of file diff --git a/src/ftpclient.cpp b/src/ftpclient.cpp new file mode 100644 index 0000000..4be05d3 --- /dev/null +++ b/src/ftpclient.cpp @@ -0,0 +1,1527 @@ +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +#define FTP_CLIENT_BUFSIZ 16384 +#define ACCEPT_TIMEOUT 30 + +/* io types */ +#define FTP_CLIENT_CONTROL 0 +#define FTP_CLIENT_READ 1 +#define FTP_CLIENT_WRITE 2 + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) + +FtpClient::FtpClient() +{ + mp_ftphandle = static_cast(calloc(1,sizeof(ftphandle))); + if (mp_ftphandle == NULL) perror("calloc"); + mp_ftphandle->buf = static_cast(malloc(FTP_CLIENT_BUFSIZ)); + if (mp_ftphandle->buf == NULL) + { + perror("calloc"); + free(mp_ftphandle); + } + ClearHandle(); +} + +FtpClient::~FtpClient() +{ + free(mp_ftphandle->buf); + free(mp_ftphandle); +} + +int FtpClient::Connect(const char *host, unsigned short port) +{ + int sControl; + SceNetInAddr dst_addr; /* destination address */ + SceNetSockaddrIn server_addr; + int on = 1; /* used in Setsockopt function */ + int32_t retval; /* return value */ + + mp_ftphandle->dir = FTP_CLIENT_CONTROL; + mp_ftphandle->ctrl = NULL; + mp_ftphandle->xfered = 0; + mp_ftphandle->xfered1 = 0; + mp_ftphandle->offset = 0; + mp_ftphandle->handle = 0; + memset(&mp_ftphandle->response, 0, sizeof(mp_ftphandle->response)); + + memset(&server_addr, 0, sizeof(server_addr)); + sceNetInetPton(SCE_NET_AF_INET, host, (void*)&dst_addr); + server_addr.sin_addr = dst_addr; + server_addr.sin_port = sceNetHtons(port); + server_addr.sin_family = SCE_NET_AF_INET; + + sControl = sceNetSocket("ftp_control", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, SCE_NET_IPPROTO_TCP); + if (mp_ftphandle->handle < 0) + { + //debugNetPrintf(ERROR, "sceNetSocket error\n"); + return 0; + } + + retval = sceNetSetsockopt(sControl, SCE_NET_SOL_SOCKET, SCE_NET_SO_REUSEADDR, (const void*)&on, sizeof(on)); + if (retval == -1) + { + //debugNetPrintf(ERROR, "sceNetSetsockopt error\n"); + return 0; + } + + retval = sceNetConnect(sControl, (SceNetSockaddr *)&server_addr, sizeof(server_addr)); + if (retval == -1) + { + //debugNetPrintf(ERROR, "sceNetConnect error\n"); + sprintf(mp_ftphandle->response, "Connection timeout\n"); + sceNetSocketClose(sControl); + return 0; + } + mp_ftphandle->handle = sControl; + + if (ReadResponse('2', mp_ftphandle) == 0) + { + sceNetSocketClose(mp_ftphandle->handle); + mp_ftphandle->handle = 0; + return 0; + } + + return 1; +} + +/* + * FtpSendCmd - send a command and wait for expected response + * + * return 1 if proper response received, 0 otherwise + */ +int FtpClient::FtpSendCmd(const char *cmd, char expected_resp, ftphandle *nControl) +{ + char buf[512]; + int x; + + if (!nControl->handle) return 0; + if (nControl->dir != FTP_CLIENT_CONTROL) return 0; + + sprintf(buf, "%s\r\n", cmd); + x = sceNetSend(nControl->handle, buf, strlen(buf), 0); + if (x <= 0) + { + //debugNetPrintf(ERROR, "sceNetSend error\n"); + return 0; + } + + return ReadResponse(expected_resp, nControl); +} + +/* + * read a response from the server + * + * return 0 if first char doesn't match + * return 1 if first char matches + */ +int FtpClient::ReadResponse(char c, ftphandle *nControl) +{ + char match[5]; + + if (Readline(nControl->response, 512, nControl) == -1) + { + //debugNetPrintf(ERROR,"Readline error\n"); + return 0; + } + + if (nControl->response[3] == '-') + { + strncpy(match, nControl->response, 3); + match[3] = ' '; + match[4] = '\0'; + do + { + if (Readline(nControl->response, 512, nControl) == -1) + { + //debugNetPrintf(ERROR,"Readline error\n"); + return 0; + } + } while (strncmp(nControl->response, match, 4)); + } + + if (nControl->response[0] == c) return 1; + return 0; +} + +/* + * read a line of text + * + * return -1 on error or bytecount + */ +int FtpClient::Readline(char *buf, int max, ftphandle *nControl) +{ + int x, retval = 0; + char *end, *bp = buf; + int eof = 0; + + if (max == 0) return 0; + + do + { + if (nControl->cavail > 0) + { + x = (max >= nControl->cavail) ? nControl->cavail : max-1; + end = static_cast(memccpy(bp, nControl->cget, '\n', x)); + if (end != NULL) x = end - bp; + retval += x; + bp += x; + *bp = '\0'; + max -= x; + nControl->cget += x; + nControl->cavail -= x; + if (end != NULL) + { + bp -= 2; + if (strcmp(bp, "\r\n") == 0) + { + *bp++ = '\n'; + *bp++ = '\0'; + --retval; + } + break; + } + } + + if (max == 1) + { + *buf = '\0'; + break; + } + + if (nControl->cput == nControl->cget) + { + nControl->cput = nControl->cget = nControl->buf; + nControl->cavail = 0; + nControl->cleft = FTP_CLIENT_BUFSIZ; + } + + if (eof) + { + if (retval == 0) retval = -1; + break; + } + + x = sceNetRecv(nControl->handle, nControl->cput, nControl->cleft, 0); + + if ( x == -1) + { + //debugNetPrintf(ERROR,"sceNetRecv error\n"); + retval = -1; + break; + } + + if (x == 0) eof = 1; + nControl->cleft -= x; + nControl->cavail += x; + nControl->cput += x; + } while (1); + //debugNetPrintf(DEBUG,"Response = %s\n", buf); + return retval; +} + +/* + * FtpLogin - log in to remote server + * + * return 1 if logged in, 0 otherwise + */ +int FtpClient::Login(const char *user, const char *pass) +{ + char tempbuf[128]; + + if (((strlen(user) + 7) > sizeof(tempbuf)) || ((strlen(pass) + 7) > sizeof(tempbuf))) return 0; + sprintf(tempbuf, "USER %s", user); + if (!FtpSendCmd(tempbuf, '3', mp_ftphandle)) + { + if (mp_ftphandle->ctrl != NULL) return 1; + if (*LastResponse() == '2') return 1; + return 0; + } + sprintf(tempbuf,"PASS %s",pass); + return FtpSendCmd(tempbuf, '2', mp_ftphandle); +} + +/* + * FtpLastResponse - return a pointer to the last response received + */ +char* FtpClient::LastResponse() +{ + if ((mp_ftphandle) && (mp_ftphandle->dir == FTP_CLIENT_CONTROL)) return mp_ftphandle->response; + return NULL; +} + +void FtpClient::ClearHandle() +{ + mp_ftphandle->dir = FTP_CLIENT_CONTROL; + mp_ftphandle->ctrl = NULL; + mp_ftphandle->cmode = FtpClient::pasv; + mp_ftphandle->cbarg = NULL; + mp_ftphandle->cbbytes = 0; + mp_ftphandle->xfered = 0; + mp_ftphandle->xfered1 = 0; + mp_ftphandle->offset = 0; + mp_ftphandle->handle = 0; + mp_ftphandle->xfercb = NULL; + mp_ftphandle->correctpasv = false; + memset(&mp_ftphandle->response, 0, sizeof(mp_ftphandle->response)); +} + +void FtpClient::SetConnmode(connmode mode) +{ + mp_ftphandle->cmode = mode; +} + +/* + * FtpAccess - return a handle for a data stream + * + * return 1 if successful, 0 otherwise + */ +int FtpClient::FtpAccess(const char *path, accesstype type, transfermode mode, ftphandle *nControl, ftphandle **nData) +{ + char buf[512]; + int dir; + + if ((path == NULL) && ((type == FtpClient::filewrite) + || (type == FtpClient::fileread) + || (type == FtpClient::filereadappend) + || (type == FtpClient::filewriteappend))) + { + sprintf(nControl->response,"Missing path argument for file transfer\n"); + return 0; + } + sprintf(buf, "TYPE %c", mode); + if (!FtpSendCmd(buf, '2', nControl)) return 0; + + switch (type) + { + case FtpClient::dir: + strcpy(buf,"NLST"); + dir = FTP_CLIENT_READ; + break; + case FtpClient::dirverbose: + strcpy(buf,"LIST"); + dir = FTP_CLIENT_READ; + break; + case FtpClient::filereadappend: + case FtpClient::fileread: + strcpy(buf,"RETR"); + dir = FTP_CLIENT_READ; + break; + case FtpClient::filewriteappend: + case FtpClient::filewrite: + strcpy(buf,"STOR"); + dir = FTP_CLIENT_WRITE; + break; + default: + sprintf(nControl->response, "Invalid open type %d\n", type); + return 0; + } + if (path != NULL) + { + int i = strlen(buf); + buf[i++] = ' '; + if ((strlen(path) + i) >= sizeof(buf)) return 0; + strcpy(&buf[i],path); + } + + if (nControl->cmode == FtpClient::pasv) + { + if (FtpOpenPasv(nControl, nData, mode, dir, buf) == -1) return 0; + } + + if (nControl->cmode == FtpClient::port) + { + if (FtpOpenPort(nControl, nData, mode, dir, buf) == -1) return 0; + if (!FtpAcceptConnection(*nData,nControl)) + { + FtpClose(*nData); + *nData = NULL; + return 0; + } + } + + return 1; +} + +/* + * FtpAcceptConnection - accept connection from server + * + * return 1 if successful, 0 otherwise + */ +int FtpClient::FtpAcceptConnection(ftphandle *nData, ftphandle *nControl) +{ + int sData; + SceNetSockaddr addr; + uint32_t l; + int i; + struct timeval tv; + fd_set mask; + int rv = 0; + + FD_ZERO(&mask); + FD_SET(nControl->handle, &mask); + FD_SET(nData->handle, &mask); + tv.tv_usec = 0; + tv.tv_sec = ACCEPT_TIMEOUT; + i = nControl->handle; + if (i < nData->handle) i = nData->handle; + + if (FD_ISSET(nData->handle, &mask)) + { + l = sizeof(addr); + sData = sceNetAccept(nData->handle, &addr, &l); + i = errno; + sceNetSocketClose(nData->handle); + if (sData > 0) + { + rv = 1; + nData->handle = sData; + nData->ctrl = nControl; + } + else + { + strncpy(nControl->response, strerror(i), sizeof(nControl->response)); + nData->handle = 0; + rv = 0; + } + } + else if (FD_ISSET(nControl->handle, &mask)) + { + sceNetSocketClose(nData->handle); + nData->handle = 0; + ReadResponse('2', nControl); + rv = 0; + } + + return rv; +} + +/* + * FtpOpenPasv - Establishes a PASV connection for data transfer + * + * return 1 if successful, -1 otherwise + */ +int FtpClient::FtpOpenPasv(ftphandle *nControl, ftphandle **nData, transfermode mode, int dir, char *cmd) +{ + int sData; + union { + SceNetSockaddr sa; + SceNetSockaddrIn in; + } sin; + SceNetLinger lng = {0, 0}; + unsigned int l; + int on=1; + ftphandle *ctrl; + char *cp; + int v[6]; + int ret; + + if (nControl->dir != FTP_CLIENT_CONTROL) return -1; + if ((dir != FTP_CLIENT_READ) && (dir != FTP_CLIENT_WRITE)) + { + sprintf(nControl->response, "Invalid direction %d\n", dir); + return -1; + } + if ((mode != FtpClient::ascii) && (mode != FtpClient::image)) + { + sprintf(nControl->response, "Invalid mode %c\n", mode); + return -1; + } + l = sizeof(sin); + + memset(&sin, 0, l); + sin.in.sin_family = SCE_NET_AF_INET; + if (!FtpSendCmd("PASV", '2' , nControl)) return -1; + cp = strchr(nControl->response,'('); + if (cp == NULL) return -1; + cp++; + sscanf(cp, "%u,%u,%u,%u,%u,%u", &v[2], &v[3], &v[4], &v[5], &v[0], &v[1]); + if (nControl->correctpasv) if (!CorrectPasvResponse(v)) return -1; + sin.sa.sa_data[2] = v[2]; + sin.sa.sa_data[3] = v[3]; + sin.sa.sa_data[4] = v[4]; + sin.sa.sa_data[5] = v[5]; + sin.sa.sa_data[0] = v[0]; + sin.sa.sa_data[1] = v[1]; + + if (mp_ftphandle->offset != 0) + { + char buf[512]; + sprintf(buf, "REST %lld", mp_ftphandle->offset); + if (!FtpSendCmd(buf,'3',nControl)) return 0; + } + + sData = sceNetSocket("ftp_data", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, SCE_NET_IPPROTO_TCP); + if (sData == -1) + { + //debugNetPrintf(ERROR, "sceNetSocket data error\n"); + return -1; + } + + if (sceNetSetsockopt(sData, SCE_NET_SOL_SOCKET, SCE_NET_SO_REUSEADDR, (const void*)&on, sizeof(on)) == -1) + { + //debugNetPrintf(ERROR, "sceNetSetsockopt SCE_NET_SO_REUSEADDR error\n"); + sceNetSocketClose(sData); + return -1; + } + + if (sceNetSetsockopt(sData, SCE_NET_SOL_SOCKET, SCE_NET_SO_LINGER, &lng, sizeof(lng)) == -1) + { + //debugNetPrintf(ERROR, "sceNetSetsockopt data SCE_NET_SO_LINGER error\n"); + sceNetSocketClose(sData); + return -1; + } + + if (nControl->dir != FTP_CLIENT_CONTROL) return -1; + memcpy(cmd + strlen(cmd), "\r\n\0", 3); + ret = sceNetSend(nControl->handle, cmd, strlen(cmd), 0); + if (ret <= 0) + { + //debugNetPrintf(ERROR, "sceNetSend error\n"); + return -1; + } + + //debugNetPrintf(DEBUG, "Start sceNetConnect\n"); + if (sceNetConnect(sData, &sin.sa, sizeof(sin.sa)) == -1) + { + //debugNetPrintf(ERROR, "sceNetConnect data error\n"); + sceNetSocketClose(sData); + return -1; + } + + if (!ReadResponse('1', nControl)) + { + sceNetSocketClose(sData); + return -1; + } + ctrl = static_cast(calloc(1,sizeof(ftphandle))); + if (ctrl == NULL) + { + //debugNetPrintf(ERROR, "calloc ctrl error\n"); + sceNetSocketClose(sData); + return -1; + } + if ((mode == 'A') && ((ctrl->buf = static_cast(malloc(FTP_CLIENT_BUFSIZ))) == NULL)) + { + //debugNetPrintf(ERROR, "calloc ctrl-buf error\n"); + sceNetSocketClose(sData); + free(ctrl); + return -1; + } + ctrl->handle = sData; + ctrl->dir = dir; + ctrl->ctrl = (nControl->cmode == FtpClient::pasv) ? nControl : NULL; + ctrl->xfered = 0; + ctrl->xfered1 = 0; + ctrl->cbarg = nControl->cbarg; + ctrl->cbbytes = nControl->cbbytes; + if (ctrl->cbbytes) + { + ctrl->xfercb = nControl->xfercb; + } + else + { + ctrl->xfercb = NULL; + } + *nData = ctrl; + + return 1; +} + +/* + * FtpOpenPort - Establishes a PORT connection for data transfer + * + * return 1 if successful, -1 otherwise + */ +int FtpClient::FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode mode, int dir, char *cmd) +{ + int sData; + union { + SceNetSockaddr sa; + SceNetSockaddrIn in; + } sin; + SceNetLinger lng = { 0, 0 }; + uint32_t l; + int on=1; + ftphandle *ctrl; + char buf[512]; + + if (nControl->dir != FTP_CLIENT_CONTROL) return -1; + if ((dir != FTP_CLIENT_READ) && (dir != FTP_CLIENT_WRITE)) + { + sprintf(nControl->response, "Invalid direction %d\n", dir); + return -1; + } + if ((mode != FtpClient::ascii) && (mode != FtpClient::image)) + { + sprintf(nControl->response, "Invalid mode %c\n", mode); + return -1; + } + l = sizeof(sin.sa); + + if (sceNetGetsockname(nControl->handle, &sin.sa, &l) < 0) + { + //debugNetPrintf(ERROR, "sceNetGetsockname error\n"); + return -1; + } + + sData = sceNetSocket("ftp_data", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, SCE_NET_IPPROTO_TCP); + if (sData == -1) + { + //debugNetPrintf(ERROR, "sceNetSocket error\n"); + return -1; + } + if (sceNetSetsockopt(sData, SCE_NET_SOL_SOCKET, SCE_NET_SO_REUSEADDR, (const void*)&on, sizeof(on)) == -1) + { + //debugNetPrintf(ERROR, "sceNetSetsockopt SCE_NET_SO_REUSEADDR error\n"); + sceNetSocketClose(sData); + return -1; + } + + if (sceNetSetsockopt(sData, SCE_NET_SOL_SOCKET, SCE_NET_SO_LINGER, &lng, sizeof(lng)) == -1) + { + //debugNetPrintf(ERROR, "sceNetSetsockopt data SCE_NET_SO_LINGER error\n"); + sceNetSocketClose(sData); + return -1; + } + + sin.in.sin_port = 0; + if (sceNetBind(sData, &sin.sa, sizeof(sin)) == -1) + { + //debugNetPrintf(ERROR, "sceNetBind data error\n"); + sceNetSocketClose(sData); + return -1; + } + if (sceNetListen(sData, 1) < 0) + { + //debugNetPrintf(ERROR, "sceNetListen data error\n"); + sceNetSocketClose(sData); + return -1; + } + if (sceNetGetsockname(sData, &sin.sa, &l) < 0) return 0; + sprintf(buf, "PORT %hhu,%hhu,%hhu,%hhu,%hhu,%hhu", + (unsigned char) sin.sa.sa_data[2], + (unsigned char) sin.sa.sa_data[3], + (unsigned char) sin.sa.sa_data[4], + (unsigned char) sin.sa.sa_data[5], + (unsigned char) sin.sa.sa_data[0], + (unsigned char) sin.sa.sa_data[1]); + if (!FtpSendCmd(buf, '2', nControl)) + { + sceNetSocketClose(sData); + return -1; + } + + if (mp_ftphandle->offset != 0) + { + char buf[512]; + sprintf(buf, "REST %lld", mp_ftphandle->offset); + if (!FtpSendCmd(buf,'3',nControl)) + { + sceNetSocketClose(sData); + return 0; + } + } + + ctrl = static_cast(calloc(1,sizeof(ftphandle))); + if (ctrl == NULL) + { + //debugNetPrintf(ERROR, "calloc ctrl error\n"); + sceNetSocketClose(sData); + return -1; + } + if ((mode == 'A') && ((ctrl->buf = static_cast(malloc(FTP_CLIENT_BUFSIZ))) == NULL)) + { + //debugNetPrintf(ERROR, "calloc buf error\n"); + sceNetSocketClose(sData); + free(ctrl); + return -1; + } + + if (!FtpSendCmd(cmd, '1', nControl)) + { + FtpClose(*nData); + *nData = NULL; + return -1; + } + + ctrl->handle = sData; + ctrl->dir = dir; + ctrl->ctrl = (nControl->cmode == FtpClient::pasv) ? nControl : NULL; + ctrl->xfered = 0; + ctrl->xfered1 = 0; + ctrl->cbarg = nControl->cbarg; + ctrl->cbbytes = nControl->cbbytes; + if (ctrl->cbbytes) + { + ctrl->xfercb = nControl->xfercb; + } + else + { + ctrl->xfercb = NULL; + } + *nData = ctrl; + + return 1; +} + +int FtpClient::CorrectPasvResponse(int *v) +{ + SceNetSockaddr ipholder; + uint32_t ipholder_size = sizeof(ipholder); + + if (sceNetGetpeername(mp_ftphandle->handle, &ipholder, &ipholder_size) == -1) + { + //debugNetPrintf(ERROR, "sceNetGetpeername error\n"); + sceNetSocketClose(mp_ftphandle->handle); + return 0; + } + + for (int i = 2; i < 6; i++) v[i] = ipholder.sa_data[i]; + + return 1; +} + +/* + * FtpXfer - issue a command and transfer data + * + * return 1 if successful, 0 otherwise + */ +int FtpClient::FtpXfer(const char *localfile, const char *path, ftphandle *nControl, accesstype type, transfermode mode) +{ + int l,c; + char *dbuf; + FILE *local = NULL; + ftphandle *nData; + + if (localfile != NULL) + { + char ac[3] = " "; + if ((type == FtpClient::dir) || (type == FtpClient::dirverbose)) { ac[0] = 'w'; ac[1] = '\0'; } + if (type == FtpClient::fileread) { ac[0] = 'w'; ac[1] = '\0'; } + if (type == FtpClient::filewriteappend) { ac[0] = 'r'; ac[1] = '\0'; } + if (type == FtpClient::filereadappend) { ac[0] = 'a'; ac[1] = '\0'; } + if (type == FtpClient::filewrite) { ac[0] = 'r'; ac[1] = '\0'; } + if (mode == FtpClient::image) ac[1] = 'b'; + + local = fopen(localfile, ac); + if (local == NULL) + { + strncpy(nControl->response, strerror(errno), sizeof(nControl->response)); + return 0; + } + if (type == FtpClient::filewriteappend) fseek(local,mp_ftphandle->offset,SEEK_SET); + } + if (local == NULL) local = ((type == FtpClient::filewrite) + || (type == FtpClient::filewriteappend)) ? stdin : stdout; + if (!FtpAccess(path, type, mode, nControl, &nData)) { + if (localfile != NULL) fclose(local); + return 0; + } + + dbuf = static_cast(malloc(FTP_CLIENT_BUFSIZ)); + if ((type == FtpClient::filewrite) || (type == FtpClient::filewriteappend)) + { + while ((l = fread(dbuf, 1, FTP_CLIENT_BUFSIZ, local)) > 0) + { + if ((c = FtpWrite(dbuf, l, nData)) < l) + { + //debugNetPrintf(ERROR, "short write: passed %d, wrote %d\n", l, c); + break; + } + } + } + else + { + while ((l = FtpRead(dbuf, FTP_CLIENT_BUFSIZ, nData)) > 0) + { + if (fwrite(dbuf, 1, l, local) <= 0) + { + //debugNetPrintf(ERROR, "localfile write\n"); + break; + } + } + } + free(dbuf); + fflush(local); + if (localfile != NULL) fclose(local); + return FtpClose(nData); +} + +/* + * FtpWrite - write to a data connection + */ +int FtpClient::FtpWrite(void *buf, int len, ftphandle *nData) +{ + int i; + + if (nData->dir != FTP_CLIENT_WRITE) return 0; + if (nData->buf) i = Writeline(static_cast(buf), len, nData); + else + { + i = sceNetSend(nData->handle, buf, len, 0); + } + if (i == -1) return 0; + nData->xfered += i; + + if (nData->xfercb && nData->cbbytes) + { + nData->xfered1 += i; + if (nData->xfered1 >= nData->cbbytes) + { + if (nData->xfercb(nData->xfered, nData->cbarg) == 0) return 0; + nData->xfered1 = 0; + } + } + + return i; +} + +/* + * FtpRead - read from a data connection + */ +int FtpClient::FtpRead(void *buf, int max, ftphandle *nData) +{ + int i; + + if (nData->dir != FTP_CLIENT_READ) + return 0; + if (nData->buf) i = Readline(static_cast(buf), max, nData); + else + { + i = sceNetRecv(nData->handle, buf, max, 0); + } + if (i == -1) return 0; + nData->xfered += i; + if (nData->xfercb && nData->cbbytes) + { + nData->xfered1 += i; + if (nData->xfered1 >= nData->cbbytes) + { + if (nData->xfercb(nData->xfered, nData->cbarg) == 0) return 0; + nData->xfered1 = 0; + } + } + return i; +} + +/* + * write lines of text + * + * return -1 on error or bytecount + */ +int FtpClient::Writeline(char *buf, int len, ftphandle *nData) +{ + int x, nb=0, w; + char *ubp = buf, *nbp; + char lc=0; + + if (nData->dir != FTP_CLIENT_WRITE) + return -1; + nbp = nData->buf; + for (x=0; x < len; x++) + { + if ((*ubp == '\n') && (lc != '\r')) + { + if (nb == FTP_CLIENT_BUFSIZ) + { + w = sceNetSend(nData->handle, nbp, FTP_CLIENT_BUFSIZ, 0); + if (w != FTP_CLIENT_BUFSIZ) + { + //debugNetPrintf(ERROR, "write(1) returned %d, errno = %d\n", w, errno); + return(-1); + } + nb = 0; + } + nbp[nb++] = '\r'; + } + if (nb == FTP_CLIENT_BUFSIZ) + { + w = sceNetSend(nData->handle, nbp, FTP_CLIENT_BUFSIZ, 0); + if (w != FTP_CLIENT_BUFSIZ) + { + //debugNetPrintf(ERROR, "write(2) returned %d, errno = %d\n", w, errno); + return(-1); + } + nb = 0; + } + nbp[nb++] = lc = *ubp++; + } + if (nb) + { + w = sceNetSend(nData->handle, nbp, nb, 0); + if (w != nb) + { + //debugNetPrintf(ERROR, "write(3) returned %d, errno = %d\n", w, errno); + return(-1); + } + } + return len; +} + +/* + * FtpClose - close a data connection + */ +int FtpClient::FtpClose(ftphandle *nData) +{ + ftphandle *ctrl; + + if (nData->dir == FTP_CLIENT_WRITE) + { + if (nData->buf != NULL) Writeline(NULL, 0, nData); + } + else if (nData->dir != FTP_CLIENT_READ) return 0; + if (nData->buf) free(nData->buf); + sceNetShutdown(nData->handle, 2); + sceNetSocketClose(nData->handle); + + ctrl = nData->ctrl; + free(nData); + if (ctrl) return ReadResponse('2', ctrl); + return 1; +} + +/* + * FtpQuit - disconnect from remote + * + * return 1 if successful, 0 otherwise + */ +int FtpClient::Quit() +{ + if (mp_ftphandle->handle == 0) + { + strcpy(mp_ftphandle->response, "error: no anwser from server\n"); + return 0; + } + FtpSendCmd("QUIT", '2' , mp_ftphandle); + sceNetSocketClose(mp_ftphandle->handle); + + return 1; +} + +ftphandle* FtpClient::RawOpen(const char *path, accesstype type, transfermode mode) +{ + int ret; + ftphandle* datahandle; + ret = FtpAccess(path, type, mode, mp_ftphandle, &datahandle); + if (ret) return datahandle; + else return NULL; +} + +int FtpClient::RawClose(ftphandle* handle) +{ + return FtpClose(handle); +} + +int FtpClient::RawWrite(void* buf, int len, ftphandle* handle) +{ + return FtpWrite(buf, len, handle); +} + +int FtpClient::RawRead(void* buf, int max, ftphandle* handle) +{ + return FtpRead(buf, max, handle); +} + +/* + * FtpSite - send a SITE command + * + * return 1 if command successful, 0 otherwise + */ +int FtpClient::Site(const char *cmd) +{ + char buf[512]; + + if ((strlen(cmd) + 7) > sizeof(buf)) return 0; + sprintf(buf,"SITE %s",cmd); + if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0; + return 1; +} + +/* + * FtpRaw - send a raw string string + * + * return 1 if command successful, 0 otherwise + */ + +int FtpClient::Raw(const char *cmd) +{ + char buf[512]; + strncpy(buf, cmd, 512); + if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0; + return 1; +} + +/* + * FtpSysType - send a SYST command + * + * Fills in the user buffer with the remote system type. If more + * information from the response is required, the user can parse + * it out of the response buffer returned by FtpLastResponse(). + * + * return 1 if command successful, 0 otherwise + */ +int FtpClient::SysType(char *buf, int max) +{ + int l = max; + char *b = buf; + char *s; + if (!FtpSendCmd("SYST",'2',mp_ftphandle)) return 0; + s = &mp_ftphandle->response[4]; + while ((--l) && (*s != ' ')) *b++ = *s++; + *b++ = '\0'; + return 1; +} + +/* + * FtpMkdir - create a directory at server + * + * return 1 if successful, 0 otherwise + */ +int FtpClient::Mkdir(const char *path) +{ + char buf[512]; + + if ((strlen(path) + 6) > sizeof(buf)) return 0; + sprintf(buf,"MKD %s",path); + if (!FtpSendCmd(buf,'2', mp_ftphandle)) return 0; + return 1; +} + +/* + * FtpChdir - change path at remote + * + * return 1 if successful, 0 otherwise + */ +int FtpClient::Chdir(const char *path) +{ + char buf[512]; + + if ((strlen(path) + 6) > sizeof(buf)) return 0; + sprintf(buf,"CWD %s",path); + if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0; + return 1; +} + +/* + * FtpCDUp - move to parent directory at remote + * + * return 1 if successful, 0 otherwise + */ +int FtpClient::Cdup() +{ + if (!FtpSendCmd("CDUP",'2',mp_ftphandle)) return 0; + return 1; +} + +/* + * FtpRmdir - remove directory at remote + * + * return 1 if successful, 0 otherwise + */ +int FtpClient::Rmdir(const char *path) +{ + char buf[512]; + + if ((strlen(path) + 6) > sizeof(buf)) return 0; + sprintf(buf,"RMD %s",path); + if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0; + return 1; +} + +/* + * FtpPwd - get working directory at remote + * + * return 1 if successful, 0 otherwise + */ +int FtpClient::Pwd(char *path, int max) +{ + int l = max; + char *b = path; + char *s; + + if (!FtpSendCmd("PWD",'2',mp_ftphandle)) return 0; + s = strchr(mp_ftphandle->response, '"'); + if (s == NULL) return 0; + s++; + while ((--l) && (*s) && (*s != '"')) *b++ = *s++; + *b = '\0'; + return 1; +} + +/* + * FtpSize - determine the size of a remote file + * + * return 1 if successful, 0 otherwise + */ +int FtpClient::Size(const char *path, int64_t *size, transfermode mode) +{ + char cmd[512]; + int resp,sz,rv=1; + + if ((strlen(path) + 7) > sizeof(cmd)) return 0; + + sprintf(cmd, "TYPE %c", mode); + if (!FtpSendCmd(cmd, '2', mp_ftphandle)) return 0; + + sprintf(cmd,"SIZE %s",path); + if (!FtpSendCmd(cmd,'2',mp_ftphandle)) rv = 0; + else + { + if (sscanf(mp_ftphandle->response, "%d %d", &resp, &sz) == 2) *size = sz; + else rv = 0; + } + return rv; +} + +/* + * FtpModDate - determine the modification date of a remote file + * + * return 1 if successful, 0 otherwise + */ +int FtpClient::ModDate(const char *path, char *dt, int max) +{ + char buf[512]; + int rv = 1; + + if ((strlen(path) + 7) > sizeof(buf)) return 0; + sprintf(buf,"MDTM %s",path); + if (!FtpSendCmd(buf,'2',mp_ftphandle)) rv = 0; + else strncpy(dt, &mp_ftphandle->response[4], max); + return rv; +} + +/* + * FtpGet - issue a GET command and write received data to output + * + * return 1 if successful, 0 otherwise + */ + +int FtpClient::Get(const char *outputfile, const char *path, transfermode mode, int64_t offset) +{ + mp_ftphandle->offset = offset; + if (offset == 0) return FtpXfer(outputfile, path, mp_ftphandle, FtpClient::fileread, mode); + else return FtpXfer(outputfile, path, mp_ftphandle, FtpClient::filereadappend, mode); +} + +/* + * FtpPut - issue a PUT command and send data from input + * + * return 1 if successful, 0 otherwise + */ + +int FtpClient::Put(const char *inputfile, const char *path, transfermode mode, int64_t offset) +{ + mp_ftphandle->offset = offset; + if (offset == 0) return FtpXfer(inputfile, path, mp_ftphandle, FtpClient::filewrite, mode); + else return FtpXfer(inputfile, path, mp_ftphandle, FtpClient::filewriteappend, mode); +} + + +int FtpClient::Rename(const char *src, const char *dst) +{ + char cmd[512]; + + if (((strlen(src) + 7) > sizeof(cmd)) || ((strlen(dst) + 7) > sizeof(cmd))) return 0; + sprintf(cmd,"RNFR %s",src); + if (!FtpSendCmd(cmd,'3',mp_ftphandle)) return 0; + sprintf(cmd,"RNTO %s",dst); + if (!FtpSendCmd(cmd,'2',mp_ftphandle)) return 0; + + return 1; +} + +int FtpClient::Delete(const char *path) +{ + char cmd[512]; + + if ((strlen(path) + 7) > sizeof(cmd)) return 0; + sprintf(cmd,"DELE %s",path); + if (!FtpSendCmd(cmd,'2', mp_ftphandle)) return 0; + return 1; +} + +/** + * @brief Parse directory entry + * @param[in] line NULL-terminated string + * @param[out] dirEntry Pointer to a directory entry + * @return -1 on error or 1 on success + **/ + +int FtpClient::ParseDirEntry(char *line, FtpDirEntry *dirEntry) +{ + unsigned int i; + size_t n; + char *p; + char *token; + + //Abbreviated months + static const char months[13][4] = + { + " ", + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + }; + + //Read first field + token = strtok_r(line, " \t", &p); + + //Invalid directory entry? + if(token == NULL) + return -1; + + //MS-DOS listing format? + if(isdigit(token[0])) + { + //Check modification date format + if(strlen(token) == 8 && token[2] == '-' && token[5] == '-') + { + //The format of the date is mm-dd-yy + dirEntry->modified.month = (uint8_t) strtoul(token, NULL, 10); + dirEntry->modified.day = (uint8_t) strtoul(token + 3, NULL, 10); + dirEntry->modified.year = (uint16_t) strtoul(token + 6, NULL, 10) + 2000; + } + else if(strlen(token) == 10 && token[2] == '/' && token[5] == '/') + { + //The format of the date is mm/dd/yyyy + dirEntry->modified.month = (uint8_t) strtoul(token, NULL, 10); + dirEntry->modified.day = (uint8_t) strtoul(token + 3, NULL, 10); + dirEntry->modified.year = (uint16_t) strtoul(token + 6, NULL, 10); + } + else + { + //Invalid time format + return -1; + } + + //Read modification time + token = strtok_r(NULL, " ", &p); + //Invalid directory entry? + if(token == NULL) + return -1; + + //Check modification time format + if(strlen(token) >= 5 && token[2] == ':') + { + //The format of the time hh:mm + dirEntry->modified.hours = (uint8_t) strtoul(token, NULL, 10); + dirEntry->modified.minutes = (uint8_t) strtoul(token + 3, NULL, 10); + + //The PM period covers the 12 hours from noon to midnight + if(strstr(token, "PM") != NULL) + { + dirEntry->modified.hours += 12; + } + } + else + { + //Invalid time format + return -1; + } + + //Read next field + token = strtok_r(NULL, " ", &p); + //Invalid directory entry? + if(token == NULL) + return -1; + + //Check whether the current entry is a directory + if(!strcmp(token, "")) + { + //Update attributes + dirEntry->isDir |= true; + } + else + { + //Save the size of the file + dirEntry->size = strtoul(token, NULL, 10); + } + + //Read filename field + token = strtok_r(NULL, "\r\n", &p); + //Invalid directory entry? + if(token == NULL) + return -1; + + //Retrieve the length of the filename + n = strlen(token); + //Limit the number of characters to copy + n = MIN(n, FTP_CLIENT_MAX_FILENAME_LEN); + + //Copy the filename + strncpy(dirEntry->name, token, n); + //Properly terminate the string with a NULL character + dirEntry->name[n] = '\0'; + } + //Unix listing format? + else + { + //Check file permissions + if(strchr(token, 'd') != NULL) + { + dirEntry->isDir = true; + } + + //Read next field + token = strtok_r(NULL, " ", &p); + //Invalid directory entry? + if(token == NULL) + return -1; + + //Discard owner field + token = strtok_r(NULL, " ", &p); + //Invalid directory entry? + if(token == NULL) + return -1; + + //Discard group field + token = strtok_r(NULL, " ", &p); + //Invalid directory entry? + if(token == NULL) + return -1; + + //Read size field + token = strtok_r(NULL, " ", &p); + //Invalid directory entry? + if(token == NULL) + return -1; + + //Save the size of the file + dirEntry->size = strtoul(token, NULL, 10); + + //Read modification time (month) + token = strtok_r(NULL, " ", &p); + //Invalid directory entry? + if(token == NULL) + return -1; + + //Decode the 3-letter month name + for(i = 1; i <= 12; i++) + { + //Compare month name + if(!strcmp(token, months[i])) + { + //Save month number + dirEntry->modified.month = i; + break; + } + } + + //Read modification time (day) + token = strtok_r(NULL, " ", &p); + //Invalid directory entry? + if(token == NULL) + return -1; + + //Save day number + dirEntry->modified.day = (uint8_t) strtoul(token, NULL, 10); + + //Read next field + token = strtok_r(NULL, " ", &p); + //Invalid directory entry? + if(token == NULL) + return -1; + + //Check modification time format + if(strlen(token) == 4) + { + //The format of the year is yyyy + dirEntry->modified.year = (uint16_t) strtoul(token, NULL, 10); + + } + else if(strlen(token) == 5) + { + //The format of the time hh:mm + token[2] = '\0'; + dirEntry->modified.hours = (uint8_t) strtoul(token, NULL, 10); + dirEntry->modified.minutes = (uint8_t) strtoul(token + 3, NULL, 10); + } + else + { + //Invalid time format + return -1; + } + + //Read filename field + token = strtok_r(NULL, "\r\n", &p); + //Invalid directory entry? + if(token == NULL) + return -1; + + //Retrieve the length of the filename + n = strlen(token); + //Limit the number of characters to copy + n = MIN(n, FTP_CLIENT_MAX_FILENAME_LEN); + + //Copy the filename + strncpy(dirEntry->name, token, n); + //Properly terminate the string with a NULL character + dirEntry->name[n] = '\0'; + } + + //The directory entry is valid + return 1; + } + +std::vector FtpClient::ListFiles(const char *path, bool includeSubDir) +{ + std::vector out; + std::vector list = ListDir(path); + for (int i=0; i files = ListFiles(new_path.c_str(), includeSubDir); + for (std::vector::iterator it=files.begin(); it!=files.end(); ) + { + out.push_back(std::string(list[i].name) + "/" + *it); + ++it; + } + } + else + { + out.push_back(std::string(list[i].name)); + } + } + return out; +} + +std::vector FtpClient::ListDir(const char *path) +{ + std::vector out; + FtpDirEntry entry; + memset(&entry, 0, sizeof(FtpDirEntry)); + if (path[strlen(path)-1] == '/' && strlen(path)>1) + { + strlcpy(entry.directory, path, strlen(path)-1); + } + else + { + sprintf(entry.directory, "%s", path); + } + sprintf(entry.name, ".."); + sprintf(entry.path, "%s", entry.directory); + sprintf(entry.display_size, "Folder"); + entry.size = 0; + entry.isDir = true; + out.push_back(entry); + + ftphandle *nData; + char buf[1024]; + int ret; + mp_ftphandle->offset = 0; + + nData = RawOpen(path, FtpClient::dirverbose, FtpClient::ascii); + if (nData != NULL) + { + ret = FtpRead(buf, 1024, nData); + while (ret > 0) + { + FtpDirEntry entry; + memset(&entry, 0, sizeof(entry)); + if (ParseDirEntry(buf, &entry) > 0) + { + sprintf(entry.directory, "%s", path); + if (strlen(path)>0 && path[strlen(path) - 1] == '/') + { + sprintf(entry.path, "%s%s", path, entry.name); + } + else + { + sprintf(entry.path, "%s/%s", path, entry.name); + } + + if (entry.isDir) + { + sprintf(entry.display_size, "Folder"); + } + else + { + if (entry.size < 1024) + { + sprintf(entry.display_size, "%dB", entry.size); + } + else if (entry.size < 1024*1024) + { + sprintf(entry.display_size, "%.2fKB", entry.size*1.0f/1024); + } + else if (entry.size < 1024*1024*1024) + { + sprintf(entry.display_size, "%.2f%MB", entry.size*1.0f/(1024*1024)); + } + else + { + sprintf(entry.display_size, "%.2fGB", entry.size*1.0f/(1024*1024*1024)); + } + } + out.push_back(entry); + } + ret = FtpRead(buf, 1024, nData); + } + FtpClose(nData); + } + else + { + sprintf(mp_ftphandle->response, "300 Connection timeout"); + } + + return out; +} + +void FtpClient::SetCallbackXferFunction(FtpCallbackXfer pointer) +{ + mp_ftphandle->xfercb = pointer; +} + +void FtpClient::SetCallbackArg(void *arg) +{ + mp_ftphandle->cbarg = arg; +} + +void FtpClient::SetCallbackBytes(int64_t bytes) +{ + mp_ftphandle->cbbytes = bytes; +} + +static int FtpClient::FtpDirEntryComparator(const void *v1, const void *v2) +{ + const FtpDirEntry *p1 = (FtpDirEntry *)v1; + const FtpDirEntry *p2 = (FtpDirEntry *)v2; + if (strcasecmp(p1->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 FtpClient::Sort(std::vector &list) +{ + qsort(&list[0], list.size(), sizeof(FtpDirEntry), FtpClient::FtpDirEntryComparator); +} diff --git a/src/ftpclient.h b/src/ftpclient.h new file mode 100644 index 0000000..070b368 --- /dev/null +++ b/src/ftpclient.h @@ -0,0 +1,144 @@ +#ifndef FTPCLIENT_H +#define FTPCLIENT_H + +#include +#include +#include +#include + +#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; +}; + +/** + * @brief Date and time representation +**/ + +typedef struct +{ + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t dayOfWeek; + uint8_t hours; + uint8_t minutes; + uint8_t seconds; + uint16_t milliseconds; +} DateTime; + +/** + * @brief Directory entry + **/ +typedef struct +{ + char directory [512]; + char name[FTP_CLIENT_MAX_FILENAME_LEN + 1]; + char display_size[16]; + char path[1024]; + bool isDir; + uint32_t size; + DateTime modified; +} FtpDirEntry; + +class FtpClient { +public: + enum accesstype + { + dir = 1, + dirverbose, + 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 char *host, unsigned short port); + void SetConnmode(connmode mode); + int FtpSendCmd(const char *cmd, char expected_resp, ftphandle *nControl); + int Login(const char *user, const char *pass); + int Site(const char *cmd); + int Raw(const char *cmd); + int SysType(char *buf, int max); + int Mkdir(const char *path); + int Chdir(const char *path); + int Cdup(); + int Rmdir(const char *path); + int Pwd(char *path, int max); + int Size(const char *path, int64_t *size, transfermode mode); + int ModDate(const char *path, char *dt, int max); + int Get(const char *outputfile, const char *path, transfermode mode, int64_t offset = 0); + int Put(const char *inputfile, const char *path, transfermode mode, int64_t offset = 0); + int Rename(const char *src, const char *dst); + int Delete(const char *path); + ftphandle* RawOpen(const char *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); + std::vector ListFiles(const char *path, bool includeSubDir=false); + std::vector ListDir(const char *path); + void SetCallbackXferFunction(FtpCallbackXfer pointer); + void SetCallbackArg(void *arg); + void SetCallbackBytes(int64_t bytes); + char* LastResponse(); + int Quit(); + static void Sort(std::vector &list); + +private: + ftphandle* mp_ftphandle; + + 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, char *cmd); + int FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode mode, int dir, char *cmd); + int FtpAcceptConnection(ftphandle *nData, ftphandle *nControl); + int CorrectPasvResponse(int *v); + int FtpAccess(const char *path, accesstype type, transfermode mode, ftphandle *nControl, ftphandle **nData); + int FtpXfer(const char *localfile, const char *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, FtpDirEntry *dirEntry); + static int FtpDirEntryComparator(const void *v1, const void *v2); +}; + +#endif \ No newline at end of file diff --git a/src/gui.cpp b/src/gui.cpp new file mode 100644 index 0000000..3a8d9d7 --- /dev/null +++ b/src/gui.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include "windows.h" +#include "gui.h" +#include "textures.h" + +bool done = false; +int gui_mode = GUI_MODE_BROWSER; + +namespace GUI { + int RenderLoop(void) { + ImGuiIO& io = ImGui::GetIO(); (void)io; + + Windows::Init(); + while (!done) { + vita2d_start_drawing(); + vita2d_clear_screen(); + + if (gui_mode < GUI_MODE_IME) + { + ImGui_ImplVita2D_NewFrame(); + } + + if (gui_mode == GUI_MODE_BROWSER) + { + Windows::MainWindow(); + } else if (gui_mode == GUI_MODE_IME) + { + Windows::HandleImeInput(); + } + + if (gui_mode < GUI_MODE_IME) + { + ImGui::Render(); + ImGui_ImplVita2D_RenderDrawData(ImGui::GetDrawData()); + } + + vita2d_end_drawing(); + vita2d_common_dialog_update(); + vita2d_swap_buffers(); + sceDisplayWaitVblankStart(); + } + + return 0; + } +} diff --git a/src/gui.h b/src/gui.h new file mode 100644 index 0000000..48b11fe --- /dev/null +++ b/src/gui.h @@ -0,0 +1,15 @@ +#ifndef LAUNCHER_GUI_H +#define LAUNCHER_GUI_H + +#include + +#define GUI_MODE_BROWSER 0 +#define GUI_MODE_IME 1 + +extern int gui_mode; + +namespace GUI { + int RenderLoop(void); +} + +#endif diff --git a/src/ime_dialog.cpp b/src/ime_dialog.cpp new file mode 100644 index 0000000..120fc9b --- /dev/null +++ b/src/ime_dialog.cpp @@ -0,0 +1,180 @@ +/* + 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 . +*/ + +#include +#include "ime_dialog.h" + +static int ime_dialog_running = 0; +static int ime_dialog_option = 0; + +static const char *ime_initial_text = NULL; +static uint16_t ime_title_utf16[SCE_IME_DIALOG_MAX_TITLE_LENGTH]; +static uint16_t ime_initial_text_utf16[SCE_IME_DIALOG_MAX_TEXT_LENGTH]; +static uint16_t ime_input_text_utf16[SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1]; +static uint8_t ime_input_text_utf8[SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1]; + +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 *initial_text, int max_text_length, int type, int option, int password) + { + if (ime_dialog_running) + return IME_DIALOG_ALREADY_RUNNING; + + ime_initial_text = initial_text; + + // Convert UTF8 to UTF16 + memset(ime_title_utf16, 0, sizeof(ime_title_utf16)); + memset(ime_initial_text_utf16, 0, sizeof(ime_initial_text_utf16)); + utf8_to_utf16((uint8_t *)title, ime_title_utf16); + utf8_to_utf16((uint8_t *)initial_text, ime_initial_text_utf16); + + SceImeDialogParam param; + sceImeDialogParamInit(¶m); + + param.supportedLanguages = 0x0001FFFF; + param.languagesForced = SCE_TRUE; + param.type = type; + param.option = option; + if (option == SCE_IME_OPTION_MULTILINE) + param.dialogMode = SCE_IME_DIALOG_DIALOG_MODE_WITH_CANCEL; + param.textBoxMode = password ? SCE_IME_DIALOG_TEXTBOX_MODE_PASSWORD : SCE_IME_DIALOG_TEXTBOX_MODE_DEFAULT; + param.title = ime_title_utf16; + param.maxTextLength = max_text_length; + param.initialText = ime_initial_text_utf16; + param.inputTextBuffer = ime_input_text_utf16; + + int res = sceImeDialogInit(¶m); + if (res >= 0) + { + ime_dialog_running = 1; + ime_dialog_option = option; + } + + return res; + } + + int isImeDialogRunning() + { + return ime_dialog_running; + } + + uint16_t *getImeDialogInputTextUTF16() + { + return ime_input_text_utf16; + } + + uint8_t *getImeDialogInputTextUTF8() + { + return ime_input_text_utf8; + } + + const char *getImeDialogInitialText() + { + return ime_initial_text; + } + + int updateImeDialog() + { + if (!ime_dialog_running) + return IME_DIALOG_RESULT_NONE; + + SceCommonDialogStatus status = sceImeDialogGetStatus(); + if (status == IME_DIALOG_RESULT_FINISHED) + { + SceImeDialogResult result; + memset(&result, 0, sizeof(SceImeDialogResult)); + sceImeDialogGetResult(&result); + + if ((ime_dialog_option == SCE_IME_OPTION_MULTILINE && result.button == SCE_IME_DIALOG_BUTTON_CLOSE) || + (ime_dialog_option != SCE_IME_OPTION_MULTILINE && result.button == SCE_IME_DIALOG_BUTTON_ENTER)) + { + // Convert UTF16 to UTF8 + utf16_to_utf8(ime_input_text_utf16, ime_input_text_utf8); + } + else + { + status = IME_DIALOG_RESULT_CANCELED; + } + + sceImeDialogTerm(); + + ime_dialog_running = 0; + } + + return status; + } + +} // namespace Dialog \ No newline at end of file diff --git a/src/ime_dialog.h b/src/ime_dialog.h new file mode 100644 index 0000000..62ccbbc --- /dev/null +++ b/src/ime_dialog.h @@ -0,0 +1,41 @@ +/* + 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 . +*/ + +#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 + +typedef void (*ime_callback_t) (int ime_result); + +namespace Dialog +{ + int initImeDialog(const char *title, const char *initial_text, int max_text_length, int type, int option, int password); + uint16_t *getImeDialogInputTextUTF16(); + uint8_t *getImeDialogInputTextUTF8(); + const char *getImeDialogInitialText(); + int isImeDialogRunning(); + int updateImeDialog(); +} + +#endif diff --git a/src/inifile.c b/src/inifile.c new file mode 100644 index 0000000..73f2f56 --- /dev/null +++ b/src/inifile.c @@ -0,0 +1,710 @@ +/************************************************************************ + 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 +#include +#include + +/* 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; + } +} + diff --git a/src/inifile.h b/src/inifile.h new file mode 100644 index 0000000..764786f --- /dev/null +++ b/src/inifile.h @@ -0,0 +1,75 @@ +/************************************************************************ + 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 + + diff --git a/src/ioapi.c b/src/ioapi.c new file mode 100644 index 0000000..8c18eb8 --- /dev/null +++ b/src/ioapi.c @@ -0,0 +1,307 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#include "ioapi.h" + +#include +#include +#include + +voidpf call_zopen64(const zlib_filefunc64_32_def* pfilefunc, const void* filename, int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file))(pfilefunc->zfile_func64.opaque, filename, mode); + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque, (const char*)filename, mode); +} + +voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, int number_disk, int mode)) +{ + if (pfilefunc->zfile_func64.zopendisk64_file != NULL) + return (*(pfilefunc->zfile_func64.zopendisk64_file))(pfilefunc->zfile_func64.opaque, filestream, number_disk, mode); + return (*(pfilefunc->zopendisk32_file))(pfilefunc->zfile_func64.opaque, filestream, number_disk, mode); +} + +long call_zseek64(const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, ZPOS64_T offset, int origin) +{ + uLong offsetTruncated; + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file))(pfilefunc->zfile_func64.opaque, filestream, offset, origin); + offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque, filestream, offsetTruncated, origin); +} + +ZPOS64_T call_ztell64(const zlib_filefunc64_32_def* pfilefunc, voidpf filestream) +{ + uLong tell_uLong; + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file))(pfilefunc->zfile_func64.opaque, filestream); + tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque, filestream); + if ((tell_uLong) == 0xffffffff) + return (ZPOS64_T)-1; + return tell_uLong; +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32, const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zfile_func64.zopendisk64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zopendisk32_file = p_filefunc32->zopendisk_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +typedef struct +{ + SceUID fd; + int error; + int filenameLength; + void* filename; +} FILE_IOPOSIX; + +static voidpf file_build_ioposix(SceUID fd, const char* filename) +{ + FILE_IOPOSIX* ioposix = NULL; + if (fd < 0) + return NULL; + ioposix = (FILE_IOPOSIX*)malloc(sizeof(FILE_IOPOSIX)); + ioposix->fd = fd; + ioposix->error = 0; + ioposix->filenameLength = strlen(filename) + 1; + ioposix->filename = (char*)malloc(ioposix->filenameLength * sizeof(char)); + strncpy(ioposix->filename, filename, ioposix->filenameLength); + return (voidpf)ioposix; +} + +static voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char* filename, int mode) +{ + SceUID fd = -1; + int mode_fopen = 0; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) + mode_fopen = SCE_O_RDONLY; + else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = SCE_O_RDWR; + else if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = SCE_O_WRONLY | SCE_O_CREAT; + + if ((filename != NULL) && (mode_fopen != 0)) + { + fd = sceIoOpen(filename, mode_fopen, 0777); + return file_build_ioposix(fd, filename); + } + + return NULL; +} + +static voidpf ZCALLBACK fopendisk_file_func(voidpf opaque, voidpf stream, int number_disk, int mode) +{ + FILE_IOPOSIX* ioposix = NULL; + char* diskFilename = NULL; + voidpf ret = NULL; + int i = 0; + + if (stream == NULL) + return NULL; + ioposix = (FILE_IOPOSIX*)stream; + diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char)); + strncpy(diskFilename, ioposix->filename, ioposix->filenameLength); + for (i = ioposix->filenameLength - 1; i >= 0; i -= 1) + { + if (diskFilename[i] != '.') + continue; + snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02d", number_disk + 1); + break; + } + if (i >= 0) + ret = fopen_file_func(opaque, diskFilename, mode); + free(diskFilename); + return ret; +} + +static uLong ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uLong size) +{ + FILE_IOPOSIX* ioposix = NULL; + uLong ret; + if (stream == NULL) + return -1; + ioposix = (FILE_IOPOSIX*)stream; + ret = (uLong)sceIoRead(ioposix->fd, buf, (size_t)size); + ioposix->error = (int)ret; + return ret; +} + +static uLong ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + FILE_IOPOSIX* ioposix = NULL; + uLong ret; + if (stream == NULL) + return -1; + ioposix = (FILE_IOPOSIX*)stream; + ret = (uLong)sceIoWrite(ioposix->fd, buf, (size_t)size); + ioposix->error = (int)ret; + return ret; +} + +static long ZCALLBACK ftell_file_func(voidpf opaque, voidpf stream) +{ + FILE_IOPOSIX* ioposix = NULL; + long ret = -1; + if (stream == NULL) + return ret; + ioposix = (FILE_IOPOSIX*)stream; + ret = (long)sceIoLseek32(ioposix->fd, 0, SCE_SEEK_CUR); + ioposix->error = (int)ret; + return ret; +} + +static ZPOS64_T ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream) +{ + FILE_IOPOSIX* ioposix = NULL; + ZPOS64_T ret = -1; + if (stream == NULL) + return ret; + ioposix = (FILE_IOPOSIX*)stream; + ret = (ZPOS64_T)sceIoLseek(ioposix->fd, 0, SCE_SEEK_CUR); + ioposix->error = (int)ret; + return ret; +} + +static long ZCALLBACK fseek_file_func(voidpf opaque, voidpf stream, uLong offset, int origin) +{ + FILE_IOPOSIX* ioposix = NULL; + int fseek_origin = 0; + long ret = 0; + + if (stream == NULL) + return -1; + ioposix = (FILE_IOPOSIX*)stream; + + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR: + fseek_origin = SCE_SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END: + fseek_origin = SCE_SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET: + fseek_origin = SCE_SEEK_SET; + break; + default: + return -1; + } + if (sceIoLseek32(ioposix->fd, offset, fseek_origin) < 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + FILE_IOPOSIX* ioposix = NULL; + int fseek_origin = 0; + long ret = 0; + + if (stream == NULL) + return -1; + ioposix = (FILE_IOPOSIX*)stream; + + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR: + fseek_origin = SCE_SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END: + fseek_origin = SCE_SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET: + fseek_origin = SCE_SEEK_SET; + break; + default: + return -1; + } + if (sceIoLseek(ioposix->fd, offset, fseek_origin) < 0) + ret = -1; + return ret; +} + +static int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream) +{ + FILE_IOPOSIX* ioposix = NULL; + int ret = -1; + if (stream == NULL) + return ret; + ioposix = (FILE_IOPOSIX*)stream; + if (ioposix->filename != NULL) + free(ioposix->filename); + ret = sceIoClose(ioposix->fd); + ioposix->error = ret; + free(ioposix); + return ret; +} + +static int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream) +{ + FILE_IOPOSIX* ioposix = NULL; + int ret = -1; + if (stream == NULL) + return ret; + ioposix = (FILE_IOPOSIX*)stream; + ret = 0; + if (ioposix->error < 0) + ret = ioposix->error & 0xFF; + return ret; +} + +void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zopendisk_file = fopendisk_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = (void(*))fopen_file_func; + pzlib_filefunc_def->zopendisk64_file = fopendisk_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} \ No newline at end of file diff --git a/src/ioapi.h b/src/ioapi.h new file mode 100644 index 0000000..fff05f8 --- /dev/null +++ b/src/ioapi.h @@ -0,0 +1,179 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) +# ifndef __USE_FILE_OFFSET64 +# define __USE_FILE_OFFSET64 +# endif +# ifndef __USE_LARGEFILE64 +# define __USE_LARGEFILE64 +# endif +# ifndef _LARGEFILE64_SOURCE +# define _LARGEFILE64_SOURCE +# endif +# ifndef _FILE_OFFSET_BIT +# define _FILE_OFFSET_BIT 64 +# endif +#endif + +#include "zlib.h" + +#include +#include + +#if defined(USE_FILE32API) +# define fopen64 fopen +# define ftello64 ftell +# define fseeko64 fseek +#else +# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) +# define fopen64 fopen +# define ftello64 ftello +# define fseeko64 fseeko +# endif +# ifdef _MSC_VER +# define fopen64 fopen +# if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) +# define ftello64 _ftelli64 +# define fseeko64 _fseeki64 +# else /* old MSC */ +# define ftello64 ftell +# define fseeko64 fseek +# endif +# endif +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +# ifdef HAVE_STDINT_H +# include "stdint.h" +typedef uint64_t ZPOS64_T; +# else +# if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +# else +typedef unsigned long long int ZPOS64_T; +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + +#ifndef ZCALLBACK +# if (defined(WIN32) || defined(_WIN32) || defined(WINDOWS) || defined(_WINDOWS)) && defined(CALLBACK) \ + && defined(USEWINDOWS_CALLBACK) +# define ZCALLBACK CALLBACK +# else +# define ZCALLBACK +# endif +#endif + +typedef voidpf(ZCALLBACK* open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef voidpf(ZCALLBACK* opendisk_file_func) OF((voidpf opaque, voidpf stream, int number_disk, int mode)); +typedef uLong(ZCALLBACK* read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong(ZCALLBACK* write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int(ZCALLBACK* close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int(ZCALLBACK* testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long(ZCALLBACK* tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long(ZCALLBACK* seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + opendisk_file_func zopendisk_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T(ZCALLBACK* tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long(ZCALLBACK* seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf(ZCALLBACK* open64_file_func) OF((voidpf opaque, const void* filename, int mode)); +typedef voidpf(ZCALLBACK* opendisk64_file_func) OF((voidpf opaque, voidpf stream, int number_disk, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + opendisk64_file_func zopendisk64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen_filefunc OF((zlib_filefunc_def * pzlib_filefunc_def)); +void fill_fopen64_filefunc OF((zlib_filefunc64_def * pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + opendisk_file_func zopendisk32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + +#define ZREAD64(filefunc, filestream, buf, size) \ + ((*((filefunc).zfile_func64.zread_file))((filefunc).zfile_func64.opaque, filestream, buf, size)) +#define ZWRITE64(filefunc, filestream, buf, size) \ + ((*((filefunc).zfile_func64.zwrite_file))((filefunc).zfile_func64.opaque, filestream, buf, size)) +/*#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))*/ +/*#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))*/ +#define ZCLOSE64(filefunc, filestream) ((*((filefunc).zfile_func64.zclose_file))((filefunc).zfile_func64.opaque, filestream)) +#define ZERROR64(filefunc, filestream) ((*((filefunc).zfile_func64.zerror_file))((filefunc).zfile_func64.opaque, filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc, const void* filename, int mode)); +voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, int number_disk, int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32 + OF((zlib_filefunc64_32_def * p_filefunc64_32, const zlib_filefunc_def* p_filefunc32)); + +#define ZOPEN64(filefunc, filename, mode) (call_zopen64((&(filefunc)), (filename), (mode))) +#define ZOPENDISK64(filefunc, filestream, diskn, mode) (call_zopendisk64((&(filefunc)), (filestream), (diskn), (mode))) +#define ZTELL64(filefunc, filestream) (call_ztell64((&(filefunc)), (filestream))) +#define ZSEEK64(filefunc, filestream, pos, mode) (call_zseek64((&(filefunc)), (filestream), (pos), (mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..e6f0a28 --- /dev/null +++ b/src/log.h @@ -0,0 +1,10 @@ +#ifndef LOG_H +#define LOG_H + +namespace Log { + void Init(void); + void Error(const char *data, ...); + void Exit(void); +} + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..807c137 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,155 @@ +// ImGui - standalone example application for SDL2 + OpenGL +// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. +// (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) + +// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** +// **Prefer using the code in the sdl_opengl3_example/ folder** +// See imgui_impl_sdl.cpp for details. + +#include +#include +#include + +#include "textures.h" +#include "config.h" +#include "style.h" +#include "gui.h" +#include "fs.h" +#include "net.h" +#include "ftpclient.h" + +#include "debugnet.h" + +extern "C" { + #include "audio.h" +} +namespace Services +{ + int InitImGui(void) + { + + // Setup ImGui binding + ImGui::CreateContext(); + + ImGuiIO &io = ImGui::GetIO(); + (void)io; + io.MouseDrawCursor = false; + io.KeyRepeatRate = 0.005f; + ImGui::StyleColorsDark(); + auto &style = ImGui::GetStyle(); + style.AntiAliasedLinesUseTex = false; + style.AntiAliasedLines = true; + style.AntiAliasedFill = true; + + Style::LoadStyle(style_path); + + ImGui_ImplVita2D_Init(); + + ImGui_ImplVita2D_TouchUsage(true); + ImGui_ImplVita2D_UseIndirectFrontTouch(false); + ImGui_ImplVita2D_UseRearTouch(false); + ImGui_ImplVita2D_GamepadUsage(true); + ImGui_ImplVita2D_MouseStickUsage(false); + ImGui_ImplVita2D_DisableButtons(SCE_CTRL_SQUARE); + ImGui_ImplVita2D_SwapXO(swap_xo); + ImGui_ImplVita2D_SetAnalogRepeatDelay(1000); + + Textures::Init(); + + return 0; + } + + void ExitImGui(void) + { + Textures::Exit(); + + // Cleanup + ImGui_ImplVita2D_Shutdown(); + ImGui::DestroyContext(); + } + + void initSceAppUtil() + { + // Init SceAppUtil + SceAppUtilInitParam init_param; + SceAppUtilBootParam boot_param; + memset(&init_param, 0, sizeof(SceAppUtilInitParam)); + memset(&boot_param, 0, sizeof(SceAppUtilBootParam)); + sceAppUtilInit(&init_param, &boot_param); + + // Set common dialog config + SceCommonDialogConfigParam config; + sceCommonDialogConfigParamInit(&config); + sceAppUtilSystemParamGetInt(SCE_SYSTEM_PARAM_ID_LANG, (int *)&config.language); + sceAppUtilSystemParamGetInt(SCE_SYSTEM_PARAM_ID_ENTER_BUTTON, (int *)&config.enterButtonAssign); + sceCommonDialogSetConfigParam(&config); + + uint32_t scepaf_argp[] = { 0x400000, 0xEA60, 0x40000, 0, 0 }; + + SceSysmoduleOpt option; + option.flags = 0; + option.result = (int *)&option.flags; + sceSysmoduleLoadModuleInternalWithArg(SCE_SYSMODULE_INTERNAL_PAF, sizeof(scepaf_argp), scepaf_argp, &option); + sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_PROMOTER_UTIL); + scePromoterUtilityInit(); + } + + int Init(void) + { + // Allow writing to ux0:app/VITASHELL + sceAppMgrUmount("app0:"); + sceAppMgrUmount("savedata0:"); + + vita2d_init(); + vita2d_set_clear_color(RGBA8(0x00, 0x00, 0x00, 0xFF)); + + initSceAppUtil(); + + CONFIG::LoadConfig(); + + return 0; + } + + void Exit(void) + { + // Shutdown AppUtil + sceAppUtilShutdown(); + scePromoterUtilityExit(); + sceSysmoduleUnloadModuleInternal(SCE_SYSMODULE_INTERNAL_PROMOTER_UTIL); + vita2d_fini(); + } +} // namespace Services + +#define ip_server "192.168.100.14" +#define port_server 18194 + +unsigned int _newlib_heap_size_user = 128 * 1024 * 1024; + +int main(int, char **) +{ + debugNetInit(ip_server,port_server, DEBUG); + + Net::Init(); + Services::Init(); + Services::InitImGui(); + + if (enable_backgrou_music) + { + srand(time(NULL)); + int index = rand() % bg_music_list.size(); + Audio_Init(bg_music_list[index].c_str()); + } + + debugNetPrintf(DEBUG, "Finished Windows::Init()"); + GUI::RenderLoop(); + + if (enable_backgrou_music) + { + Audio_Term(); + } + Services::ExitImGui(); + Services::Exit(); + Net::Exit(); + + return 0; +} diff --git a/src/net.cpp b/src/net.cpp new file mode 100644 index 0000000..f520b07 --- /dev/null +++ b/src/net.cpp @@ -0,0 +1,282 @@ +/* + 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 . +*/ +#include +#include +#include "certs.h" +//#include "debugnet.h" + +#define VITALAUNCHER_USER_AGENT "VitaLauncher/1.00 libhttp/1.1" +#define NET_MEMORY_SIZE (4 * 1024 * 1024) + +char *net_memory = nullptr; +static SceHttpsData* caList[4]; + +namespace Net +{ + void Init() + { + sceSysmoduleLoadModule(SCE_SYSMODULE_NET); + sceSysmoduleLoadModule(SCE_SYSMODULE_HTTPS); + sceSysmoduleLoadModule(SCE_SYSMODULE_PSPNET_ADHOC); + net_memory = (char*)malloc(NET_MEMORY_SIZE); + + SceNetInitParam param; + param.memory = net_memory; + param.size = NET_MEMORY_SIZE; + param.flags = 0; + + sceNetInit(¶m); + sceNetCtlInit(); + + sceSslInit(300 * 1024); + sceHttpInit(40 * 1024); + + sceHttpsDisableOption(SCE_HTTPS_FLAG_SERVER_VERIFY); + + sceNetAdhocInit(); + + SceNetAdhocctlAdhocId adhocId; + memset(&adhocId, 0, sizeof(SceNetAdhocctlAdhocId)); + adhocId.type = SCE_NET_ADHOCCTL_ADHOCTYPE_RESERVED; + memcpy(&adhocId.data[0], "SMLA00001", SCE_NET_ADHOCCTL_ADHOCID_LEN); + sceNetAdhocctlInit(&adhocId); + + caList[0] = (SceHttpsData*) malloc(sizeof(SceHttpsData)); + caList[1] = (SceHttpsData*) malloc(sizeof(SceHttpsData)); + caList[2] = (SceHttpsData*) malloc(sizeof(SceHttpsData)); + caList[3] = (SceHttpsData*) malloc(sizeof(SceHttpsData)); + caList[0]->ptr = DigiCert_High_Assurance_EV_Root_CA_pem; + caList[0]->size = DigiCert_High_Assurance_EV_Root_CA_pem_size; + caList[1]->ptr = DigiCert_SHA2_High_Assurance_Server_CA_pem; + caList[1]->size = DigiCert_SHA2_High_Assurance_Server_CA_pem_size; + caList[2]->ptr = Baltimore_CyberTrust_Root_pem; + caList[2]->size = Baltimore_CyberTrust_Root_pem_size; + caList[3]->ptr = Cloudflare_Inc_ECC_CA_3_pem; + caList[3]->size = Cloudflare_Inc_ECC_CA_3_pem_size; + int res = sceHttpsLoadCert(4, (const SceHttpsData**)caList, NULL, NULL); + + } + + void Exit() + { + sceNetAdhocctlTerm(); + sceNetAdhocTerm(); + sceSslTerm(); + sceHttpTerm(); + sceNetCtlTerm(); + sceNetTerm(); + free(net_memory); + free(caList[0]); + free(caList[1]); + free(caList[2]); + free(caList[3]); + sceSysmoduleUnloadModule(SCE_SYSMODULE_PSPNET_ADHOC); + sceSysmoduleUnloadModule(SCE_SYSMODULE_HTTPS); + sceSysmoduleUnloadModule(SCE_SYSMODULE_NET); + } + + int GetDownloadFileSize(const char *src, uint64_t *size) + { + int res; + int statusCode; + int tmplId = -1, connId = -1, reqId = -1; + + + res = sceHttpCreateTemplate(VITALAUNCHER_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE); + if (res < 0) + goto ERROR_EXIT; + + tmplId = res; + + res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE); + if (res < 0) + goto ERROR_EXIT; + + connId = res; + + res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0); + if (res < 0) + goto ERROR_EXIT; + + reqId = res; + + res = sceHttpSendRequest(reqId, NULL, 0); + if (res < 0) + goto ERROR_EXIT; + + res = sceHttpGetStatusCode(reqId, &statusCode); + if (res < 0) + goto ERROR_EXIT; + + if (statusCode == 200) { + res = sceHttpGetResponseContentLength(reqId, size); + } + + ERROR_EXIT: + if (reqId >= 0) + sceHttpDeleteRequest(reqId); + + if (connId >= 0) + sceHttpDeleteConnection(connId); + + if (tmplId >= 0) + sceHttpDeleteTemplate(tmplId); + + return res; + } + + int GetFieldFromHeader(const char *src, const char *field, const char **data, unsigned int *valueLen) + { + int res; + char *header; + unsigned int headerSize; + int tmplId = -1, connId = -1, reqId = -1; + + res = sceHttpCreateTemplate(VITALAUNCHER_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE); + if (res < 0) + goto ERROR_EXIT; + + tmplId = res; + + res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE); + if (res < 0) + goto ERROR_EXIT; + + connId = res; + + res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0); + if (res < 0) + goto ERROR_EXIT; + + reqId = res; + + res = sceHttpSendRequest(reqId, NULL, 0); + if (res < 0) + goto ERROR_EXIT; + + res = sceHttpGetAllResponseHeaders(reqId, &header, &headerSize); + if (res < 0) + goto ERROR_EXIT; + + res = sceHttpParseResponseHeader(header, headerSize, field, data, valueLen); + if (res < 0) { + *data = ""; + *valueLen = 0; + res = 0; + } + + ERROR_EXIT: + if (reqId >= 0) + sceHttpDeleteRequest(reqId); + + if (connId >= 0) + sceHttpDeleteConnection(connId); + + if (tmplId >= 0) + sceHttpDeleteTemplate(tmplId); + + return res; + } + + int DownloadFile(const char *src, const char *dst) + { + int res; + int statusCode; + int tmplId = -1, connId = -1, reqId = -1; + SceUID fd = -1; + int ret = 1; + + res = sceHttpCreateTemplate(VITALAUNCHER_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE); + if (res < 0) + goto ERROR_EXIT; + + tmplId = res; + + res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE); + if (res < 0) + goto ERROR_EXIT; + + connId = res; + + res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0); + if (res < 0) + goto ERROR_EXIT; + + reqId = res; + + res = sceHttpSendRequest(reqId, NULL, 0); + if (res < 0) + goto ERROR_EXIT; + + res = sceHttpGetStatusCode(reqId, &statusCode); + if (res < 0) + goto ERROR_EXIT; + + if (statusCode == 200) { + res = sceIoOpen(dst, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); + if (res < 0) + goto ERROR_EXIT; + + fd = res; + + uint8_t buf[4096]; + + while (1) { + int read = sceHttpReadData(reqId, buf, sizeof(buf)); + + if (read < 0) { + res = read; + break; + } + + if (read == 0) + break; + + int written = sceIoWrite(fd, buf, read); + + if (written < 0) { + res = written; + break; + } + } + } + else + { + res = -1; + } + + + ERROR_EXIT: + if (fd >= 0) + sceIoClose(fd); + + if (reqId >= 0) + sceHttpDeleteRequest(reqId); + + if (connId >= 0) + sceHttpDeleteConnection(connId); + + if (tmplId >= 0) + sceHttpDeleteTemplate(tmplId); + + if (res < 0) + return res; + + return ret; + } +} \ No newline at end of file diff --git a/src/net.h b/src/net.h new file mode 100644 index 0000000..8ea010d --- /dev/null +++ b/src/net.h @@ -0,0 +1,38 @@ +/* + 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 . +*/ + +/* + * network_download + * same as network_update.h // network_update.c + * just modified to download any file from url, destination and successStep (0 for no step) + */ + +#ifndef __NETWORK_DOWNLOAD_H__ +#define __NETWORK_DOWNLOAD_H__ + +#define NET_MEMORY_SIZE (4 * 1024 * 1024) +extern char *net_memory; + +namespace Net { + void Init(); + void Exit(); + int GetDownloadFileSize(const char *src, uint64_t *size); + int GetFieldFromHeader(const char *src, const char *field, const char **data, unsigned int *valueLen); + int DownloadFile(const char *src, const char *dst); +} +#endif diff --git a/src/ogg.c b/src/ogg.c new file mode 100644 index 0000000..10f16e9 --- /dev/null +++ b/src/ogg.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include + +#include "audio.h" + +static OggVorbis_File ogg; +static SceUID ogg_file = 0; +static vorbis_info *ogg_info = NULL; +static ogg_int64_t samples_read = 0, max_lenth = 0; + +static size_t ogg_callback_read(void *ptr, size_t size, size_t count, void *stream) { + return sceIoRead(*(SceUID *)stream, ptr, size * count); +} + +static int ogg_callback_seek(void *stream, ogg_int64_t offset, int whence) { + return sceIoLseek32(*(SceUID *)stream, (unsigned int) offset, whence); +} + +static int ogg_callback_close(void *stream) { + return sceIoClose(*(SceUID *)stream); +} + +static long ogg_callback_tell(void *stream) { + return sceIoLseek32(*(SceUID *)stream, 0, SCE_SEEK_CUR); +} + +int OGG_Init(const char *path) { + if (R_FAILED(ogg_file = sceIoOpen(path, SCE_O_RDONLY, 0777))) + return -1; + + ov_callbacks ogg_callbacks; + ogg_callbacks.read_func = ogg_callback_read; + ogg_callbacks.seek_func = ogg_callback_seek; + ogg_callbacks.close_func = ogg_callback_close; + ogg_callbacks.tell_func = ogg_callback_tell; + + if (R_FAILED(ov_open_callbacks(&ogg_file, &ogg, NULL, 0, ogg_callbacks))) { + sceIoClose(ogg_file); + return -1; + } + + if ((ogg_info = ov_info(&ogg, -1)) == NULL) + return -1; + + max_lenth = ov_pcm_total(&ogg, -1); + + vorbis_comment *comment = ov_comment(&ogg, -1); + if (comment != NULL) { + metadata.has_meta = SCE_TRUE; + + char *value = NULL; + + if ((value = vorbis_comment_query(comment, "title", 0)) != NULL) + snprintf(metadata.title, 31, "%s\n", value); + + if ((value = vorbis_comment_query(comment, "album", 0)) != NULL) + snprintf(metadata.album, 31, "%s\n", value); + + if ((value = vorbis_comment_query(comment, "artist", 0)) != NULL) + snprintf(metadata.artist, 31, "%s\n", value); + + if ((value = vorbis_comment_query(comment, "year", 0)) != NULL) + snprintf(metadata.year, 5, "%s\n", value); + + if ((value = vorbis_comment_query(comment, "comment", 0)) != NULL) + snprintf(metadata.comment, 31, "%s\n", value); + + if ((value = vorbis_comment_query(comment, "genre", 0)) != NULL) + snprintf(metadata.genre, 31, "%s\n", value); + } + + return 0; +} + +SceUInt32 OGG_GetSampleRate(void) { + return ogg_info->rate; +} + +SceUInt8 OGG_GetChannels(void) { + return ogg_info->channels; +} + +static SceUInt64 OGG_FillBuffer(char *out) { + SceUInt64 samples_read = 0; + int samples_to_read = (sizeof(SceInt16) * ogg_info->channels) * 960; + + while(samples_to_read > 0) { + static int current_section; + int samples_just_read = ov_read(&ogg, out, samples_to_read > 960 ? 960 : samples_to_read, 0, 2, 1, ¤t_section); + + if (samples_just_read < 0) + return samples_just_read; + else if (samples_just_read == 0) + break; + + samples_read += samples_just_read; + samples_to_read -= samples_just_read; + out += samples_just_read; + } + + return samples_read / sizeof(SceInt16); +} + +SceUInt64 OGG_Seek(SceUInt64 index) { + ogg_int64_t seek_sample = (max_lenth * (index / 450.0)); + + if (ov_pcm_seek(&ogg, seek_sample) >= 0) { + samples_read = seek_sample; + return samples_read; + } + + return -1; +} + +void OGG_Decode(void *buf, unsigned int length, void *userdata) { + OGG_FillBuffer((char *)buf); + samples_read = ov_pcm_tell(&ogg); + + if (samples_read >= max_lenth) + OGG_Seek(0); +} + +SceUInt64 OGG_GetPosition(void) { + return samples_read; +} + +SceUInt64 OGG_GetLength(void) { + return max_lenth; +} + +void OGG_Term(void) { + samples_read = 0; + + if (metadata.has_meta) + metadata.has_meta = SCE_FALSE; + + ov_clear(&ogg); + sceIoClose(ogg_file); +} diff --git a/src/ogg.h b/src/ogg.h new file mode 100644 index 0000000..c8f2a9a --- /dev/null +++ b/src/ogg.h @@ -0,0 +1,15 @@ +#ifndef _ELEVENMPV_AUDIO_OGG_H_ +#define _ELEVENMPV_AUDIO_OGG_H_ + +#include + +int OGG_Init(const char *path); +SceUInt32 OGG_GetSampleRate(void); +SceUInt8 OGG_GetChannels(void); +void OGG_Decode(void *buf, unsigned int length, void *userdata); +SceUInt64 OGG_GetPosition(void); +SceUInt64 OGG_GetLength(void); +SceUInt64 OGG_Seek(SceUInt64 index); +void OGG_Term(void); + +#endif diff --git a/src/sfo.cpp b/src/sfo.cpp new file mode 100644 index 0000000..e00a987 --- /dev/null +++ b/src/sfo.cpp @@ -0,0 +1,32 @@ +#include +#include "sfo.h" + +#include + +static constexpr uint32_t SFO_MAGIC = 0x46535000; + +namespace SFO { + const char* GetString(const char* buffer, size_t size, const char *name) + { + if (size < sizeof(SfoHeader)) + throw std::runtime_error("truncated param.sfo"); + + const SfoHeader* header = reinterpret_cast(buffer); + const SfoEntry* entries = + reinterpret_cast(buffer + sizeof(SfoHeader)); + + if (header->magic != SFO_MAGIC) + throw std::runtime_error("can't parse SFO, invalid magic"); + + if (size < sizeof(SfoHeader) + header->count * sizeof(SfoEntry)) + throw std::runtime_error("truncated param.sfo"); + + for (uint32_t i = 0; i < header->count; i++) { + const char* key = reinterpret_cast(buffer + header->keyofs + entries[i].nameofs); + if (strcmp(key, name) == 0) + return reinterpret_cast(buffer + header->valofs + entries[i].dataofs); + } + + return {}; + } +} \ No newline at end of file diff --git a/src/sfo.h b/src/sfo.h new file mode 100644 index 0000000..5662d0e --- /dev/null +++ b/src/sfo.h @@ -0,0 +1,32 @@ +#ifndef LAUNCHER_SFO_H +#define LAUNCHER_SFO_H + +#pragma once + +#include +#include + +struct SfoHeader +{ + uint32_t magic; + uint32_t version; + uint32_t keyofs; + uint32_t valofs; + uint32_t count; +} __attribute__((packed)); + +struct SfoEntry +{ + uint16_t nameofs; + uint8_t alignment; + uint8_t type; + uint32_t valsize; + uint32_t totalsize; + uint32_t dataofs; +} __attribute__((packed)); + +namespace SFO { + const char* GetString(const char* buffer, size_t size, const char *name); +} + +#endif \ No newline at end of file diff --git a/src/sha1.c b/src/sha1.c new file mode 100644 index 0000000..ca99e2e --- /dev/null +++ b/src/sha1.c @@ -0,0 +1,149 @@ +/********************************************************************* +* Filename: sha1.c +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Implementation of the SHA1 hashing algorithm. + Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + This implementation uses little endian byte order. +*********************************************************************/ + +/*************************** HEADER FILES ***************************/ +#include +#include +#include "sha1.h" + +/****************************** MACROS ******************************/ +#define ROTLEFT(a, b) ((a << b) | (a >> (32 - b))) + +/*********************** FUNCTION DEFINITIONS ***********************/ +void sha1_transform(SHA1_CTX *ctx, const BYTE data[]) +{ + WORD a, b, c, d, e, i, j, t, m[80]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) + (data[j + 1] << 16) + (data[j + 2] << 8) + (data[j + 3]); + for ( ; i < 80; ++i) { + m[i] = (m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16]); + m[i] = (m[i] << 1) | (m[i] >> 31); + } + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + + for (i = 0; i < 20; ++i) { + t = ROTLEFT(a, 5) + ((b & c) ^ (~b & d)) + e + ctx->k[0] + m[i]; + e = d; + d = c; + c = ROTLEFT(b, 30); + b = a; + a = t; + } + for ( ; i < 40; ++i) { + t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[1] + m[i]; + e = d; + d = c; + c = ROTLEFT(b, 30); + b = a; + a = t; + } + for ( ; i < 60; ++i) { + t = ROTLEFT(a, 5) + ((b & c) ^ (b & d) ^ (c & d)) + e + ctx->k[2] + m[i]; + e = d; + d = c; + c = ROTLEFT(b, 30); + b = a; + a = t; + } + for ( ; i < 80; ++i) { + t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[3] + m[i]; + e = d; + d = c; + c = ROTLEFT(b, 30); + b = a; + a = t; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; +} + +void sha1_init(SHA1_CTX *ctx) +{ + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xc3d2e1f0; + ctx->k[0] = 0x5a827999; + ctx->k[1] = 0x6ed9eba1; + ctx->k[2] = 0x8f1bbcdc; + ctx->k[3] = 0xca62c1d6; +} + +void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len) +{ + size_t i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + sha1_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +void sha1_final(SHA1_CTX *ctx, BYTE hash[]) +{ + WORD i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) + ctx->data[i++] = 0x00; + } + else { + ctx->data[i++] = 0x80; + while (i < 64) + ctx->data[i++] = 0x00; + sha1_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + ctx->bitlen += ctx->datalen * 8; + ctx->data[63] = ctx->bitlen; + ctx->data[62] = ctx->bitlen >> 8; + ctx->data[61] = ctx->bitlen >> 16; + ctx->data[60] = ctx->bitlen >> 24; + ctx->data[59] = ctx->bitlen >> 32; + ctx->data[58] = ctx->bitlen >> 40; + ctx->data[57] = ctx->bitlen >> 48; + ctx->data[56] = ctx->bitlen >> 56; + sha1_transform(ctx, ctx->data); + + // Since this implementation uses little endian byte ordering and MD uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + } +} diff --git a/src/sha1.h b/src/sha1.h new file mode 100644 index 0000000..2f8c1ba --- /dev/null +++ b/src/sha1.h @@ -0,0 +1,36 @@ +/********************************************************************* +* Filename: sha1.h +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Defines the API for the corresponding SHA1 implementation. +*********************************************************************/ + +#ifndef SHA1_H +#define SHA1_H + +/*************************** HEADER FILES ***************************/ +#include +#include + +/****************************** MACROS ******************************/ +#define SHA1_BLOCK_SIZE 20 // SHA1 outputs a 20 byte digest + +/**************************** DATA TYPES ****************************/ +typedef uint8_t BYTE; // 8-bit byte +typedef uint32_t WORD; // 32-bit word, change to "long" for 16-bit machines + +typedef struct { + BYTE data[64]; + WORD datalen; + unsigned long long bitlen; + WORD state[5]; + WORD k[4]; +} SHA1_CTX; + +/*********************** FUNCTION DECLARATIONS **********************/ +void sha1_init(SHA1_CTX *ctx); +void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len); +void sha1_final(SHA1_CTX *ctx, BYTE hash[]); + +#endif // SHA1_H diff --git a/src/style.cpp b/src/style.cpp new file mode 100644 index 0000000..9693c93 --- /dev/null +++ b/src/style.cpp @@ -0,0 +1,113 @@ +#include +#include +#include +#include + +#include "style.h" +#include "config.h" +#include "fs.h" + +extern "C" { + #include "inifile.h" +} + +char style_path[128]; +char style_name[64]; + +namespace Style { + void LoadStyle(const char *style_path) + { + ImGuiStyle* style = &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + OpenIniFile(style_path); + + colors[ImGuiCol_Text] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_Text, DEFAULT_COLOR)); + colors[ImGuiCol_TextDisabled] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_TextDisabled, DEFAULT_COLOR)); + colors[ImGuiCol_WindowBg] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_WindowBg, DEFAULT_COLOR)); + colors[ImGuiCol_ChildBg] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_ChildBg, DEFAULT_COLOR)); + colors[ImGuiCol_PopupBg] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_PopupBg, DEFAULT_COLOR)); + colors[ImGuiCol_Border] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_Border, DEFAULT_COLOR)); + colors[ImGuiCol_BorderShadow] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_BorderShadow, DEFAULT_COLOR)); + colors[ImGuiCol_FrameBg] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_FrameBg, DEFAULT_COLOR)); + colors[ImGuiCol_FrameBgHovered] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_FrameBgHovered, DEFAULT_COLOR)); + colors[ImGuiCol_FrameBgActive] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_FrameBgActive, DEFAULT_COLOR)); + colors[ImGuiCol_TitleBg] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_TitleBg, DEFAULT_COLOR)); + colors[ImGuiCol_TitleBgActive] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_TitleBgActive, DEFAULT_COLOR)); + colors[ImGuiCol_TitleBgCollapsed] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_TitleBgCollapsed, DEFAULT_COLOR)); + colors[ImGuiCol_MenuBarBg] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_MenuBarBg, DEFAULT_COLOR)); + colors[ImGuiCol_ScrollbarBg] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_ScrollbarBg, DEFAULT_COLOR)); + colors[ImGuiCol_ScrollbarGrab] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_ScrollbarGrab, DEFAULT_COLOR)); + colors[ImGuiCol_ScrollbarGrabHovered] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_ScrollbarGrabHovered, DEFAULT_COLOR)); + colors[ImGuiCol_ScrollbarGrabActive] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_ScrollbarGrabActive, DEFAULT_COLOR)); + colors[ImGuiCol_CheckMark] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_CheckMark, DEFAULT_COLOR)); + colors[ImGuiCol_SliderGrab] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_SliderGrab, DEFAULT_COLOR)); + colors[ImGuiCol_SliderGrabActive] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_SliderGrabActive, DEFAULT_COLOR)); + colors[ImGuiCol_Button] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_Button, DEFAULT_COLOR)); + colors[ImGuiCol_ButtonHovered] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_ButtonHovered, DEFAULT_COLOR)); + colors[ImGuiCol_ButtonActive] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_ButtonActive, DEFAULT_COLOR)); + colors[ImGuiCol_Header] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_Header, DEFAULT_COLOR)); + colors[ImGuiCol_HeaderHovered] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_HeaderHovered, DEFAULT_COLOR)); + colors[ImGuiCol_HeaderActive] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_HeaderActive, DEFAULT_COLOR)); + colors[ImGuiCol_Separator] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_Separator, DEFAULT_COLOR)); + colors[ImGuiCol_SeparatorHovered] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_SeparatorHovered, DEFAULT_COLOR)); + colors[ImGuiCol_SeparatorActive] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_SeparatorActive, DEFAULT_COLOR)); + colors[ImGuiCol_ResizeGrip] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_ResizeGrip, DEFAULT_COLOR)); + colors[ImGuiCol_ResizeGripHovered] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_ResizeGripHovered, DEFAULT_COLOR)); + colors[ImGuiCol_ResizeGripActive] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_ResizeGripActive, DEFAULT_COLOR)); + colors[ImGuiCol_Tab] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_Tab, DEFAULT_COLOR)); + colors[ImGuiCol_TabHovered] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_TabHovered, DEFAULT_COLOR)); + colors[ImGuiCol_TabActive] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_TabActive, DEFAULT_COLOR)); + colors[ImGuiCol_TabUnfocused] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_TabUnfocused, DEFAULT_COLOR)); + colors[ImGuiCol_TabUnfocusedActive] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_TabUnfocusedActive, DEFAULT_COLOR)); + colors[ImGuiCol_TextSelectedBg] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_TextSelectedBg, DEFAULT_COLOR)); + colors[ImGuiCol_NavHighlight] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_NavHighlight, DEFAULT_COLOR)); + colors[ImGuiCol_NavWindowingHighlight] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_NavWindowingHighlight, DEFAULT_COLOR)); + colors[ImGuiCol_NavWindowingDimBg] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_NavWindowingDimBg, DEFAULT_COLOR)); + colors[ImGuiCol_ModalWindowDimBg] = GetColor(ReadString(CONFIG_STYLE, CONFIG_STYLE_ModalWindowDimBg, DEFAULT_COLOR)); + + CloseIniFile(); + } + + ImVec4 GetColor(const char *color) + { + std::vector rgba; + + std::string color_code = ""; + int length = strlen(color); + for (int i=0; i +#include +#include +extern "C" { + #include "inifile.h" +} + +#define DEFAULT_STYLE_PATH "ux0:app/SMLA00001/default_style.ini" +#define STYLES_FOLDER "ux0:data/SMLA00001/styles" + +#define CONFIG_STYLE "Style" +#define DEFAULT_COLOR "1.00,1.00,1.00,1.00" + +#define CONFIG_STYLE_Text "Text" +#define CONFIG_STYLE_TextDisabled "TextDisabled" +#define CONFIG_STYLE_WindowBg "WindowBackgroud" +#define CONFIG_STYLE_ChildBg "ChildBackground" +#define CONFIG_STYLE_PopupBg "PopupBackground" +#define CONFIG_STYLE_Border "Border" +#define CONFIG_STYLE_BorderShadow "BorderShadhow" +#define CONFIG_STYLE_FrameBg "FrameBackground" +#define CONFIG_STYLE_FrameBgHovered "FrameBackgroundHovered" +#define CONFIG_STYLE_FrameBgActive "FrameBackgroundActive" +#define CONFIG_STYLE_TitleBg "TitleBackground" +#define CONFIG_STYLE_TitleBgActive "TitleBackgroundActive" +#define CONFIG_STYLE_TitleBgCollapsed "TitleBackgroundCollapsed" +#define CONFIG_STYLE_MenuBarBg "MenuBarBackground" +#define CONFIG_STYLE_ScrollbarBg "ScrollbarBackground" +#define CONFIG_STYLE_ScrollbarGrab "ScrollbarGrab" +#define CONFIG_STYLE_ScrollbarGrabHovered "ScrollbarGrabHovered" +#define CONFIG_STYLE_ScrollbarGrabActive "ScrollbarGrabActive" +#define CONFIG_STYLE_CheckMark "CheckMark" +#define CONFIG_STYLE_SliderGrab "SliderGrab" +#define CONFIG_STYLE_SliderGrabActive "SliderGrabActive" +#define CONFIG_STYLE_Button "Button" +#define CONFIG_STYLE_ButtonHovered "ButtonHovered" +#define CONFIG_STYLE_ButtonActive "ButtonActive" +#define CONFIG_STYLE_Header "Header" +#define CONFIG_STYLE_HeaderHovered "HeaderHovered" +#define CONFIG_STYLE_HeaderActive "HeaderActive" +#define CONFIG_STYLE_Separator "Separator" +#define CONFIG_STYLE_SeparatorHovered "SeparatorHovered" +#define CONFIG_STYLE_SeparatorActive "SeparatorActive" +#define CONFIG_STYLE_ResizeGrip "ResizeGrip" +#define CONFIG_STYLE_ResizeGripHovered "ResizeHovered" +#define CONFIG_STYLE_ResizeGripActive "ResizeGripActive" +#define CONFIG_STYLE_Tab "Tab" +#define CONFIG_STYLE_TabHovered "TabHovered" +#define CONFIG_STYLE_TabActive "TabActive" +#define CONFIG_STYLE_TabUnfocused "TabUnfocused" +#define CONFIG_STYLE_TabUnfocusedActive "TabUnfocusedActive" +#define CONFIG_STYLE_PlotLines "PlotLines" +#define CONFIG_STYLE_PlotLinesHovered "PlotLinesHovered" +#define CONFIG_STYLE_PlotHistogram "PlotHistogram" +#define CONFIG_STYLE_PlotHistogramHovered "PlotHistogramHovered" +#define CONFIG_STYLE_TextSelectedBg "TextSelectedBackground" +#define CONFIG_STYLE_DragDropTarget "DragDropTarget" +#define CONFIG_STYLE_NavHighlight "NavigationHighlight" +#define CONFIG_STYLE_NavWindowingHighlight "NavigationWindowingHighlight" +#define CONFIG_STYLE_NavWindowingDimBg "NavigationWindowingDimBackground" +#define CONFIG_STYLE_ModalWindowDimBg "ModalWindowDimBackground" + +extern char style_name[]; +extern char style_path[]; + +namespace Style { + void LoadStyle(const char *style_path); + void SetStylePath(const char *style_name); + ImVec4 GetColor(const char *color); +} +#endif \ No newline at end of file diff --git a/src/textures.cpp b/src/textures.cpp new file mode 100644 index 0000000..458763f --- /dev/null +++ b/src/textures.cpp @@ -0,0 +1,85 @@ +#include +#include + +#include "textures.h" + +Tex no_icon; +Tex favorite_icon; +Tex square_icon; +Tex triangle_icon; +Tex circle_icon; +Tex cross_icon; +Tex start_icon; +Tex folder_icon; +Tex selected_icon; +Tex redbar_icon; +Tex greenbar_icon; + +namespace Textures { + + void LoadFonts() + { + // Build and load the texture atlas into a texture + uint32_t* pixels = NULL; + int width, height; + ImGuiIO& io = ImGui::GetIO(); + io.Fonts->AddFontFromFileTTF( + "ux0:app/SMLA00001/Ubuntu-R.ttf", + 16.0f, + 0, + io.Fonts->GetGlyphRangesDefault()); + } + + bool LoadImageFile(const std::string filename, Tex *texture) + { + // Load from file + vita2d_texture *image = vita2d_load_PNG_file(filename.c_str()); + if (image == NULL) { + return false; + } + int image_width = vita2d_texture_get_width(image); + int image_height = vita2d_texture_get_height(image); + + texture->id = image; + texture->width = image_width; + texture->height = image_height; + + return true; + } + + void Init(void) { + Textures::LoadImageFile("ux0:app/SMLA00001/noicon.png", &no_icon); + Textures::LoadImageFile("ux0:app/SMLA00001/favorite.png", &favorite_icon); + Textures::LoadImageFile("ux0:app/SMLA00001/square.png", &square_icon); + Textures::LoadImageFile("ux0:app/SMLA00001/triangle.png", &triangle_icon); + Textures::LoadImageFile("ux0:app/SMLA00001/circle.png", &circle_icon); + Textures::LoadImageFile("ux0:app/SMLA00001/cross.png", &cross_icon); + Textures::LoadImageFile("ux0:app/SMLA00001/start.png", &start_icon); + Textures::LoadImageFile("ux0:app/SMLA00001/folder.png", &folder_icon); + Textures::LoadImageFile("ux0:app/SMLA00001/selected.png", &selected_icon); + Textures::LoadImageFile("ux0:app/SMLA00001/redbar.png", &redbar_icon); + Textures::LoadImageFile("ux0:app/SMLA00001/greenbar.png", &greenbar_icon); + } + + void Exit(void) { + vita2d_free_texture(no_icon.id); + vita2d_free_texture(favorite_icon.id); + vita2d_free_texture(square_icon.id); + vita2d_free_texture(triangle_icon.id); + vita2d_free_texture(circle_icon.id); + vita2d_free_texture(cross_icon.id); + vita2d_free_texture(start_icon.id); + vita2d_free_texture(folder_icon.id); + vita2d_free_texture(selected_icon.id); + vita2d_free_texture(redbar_icon.id); + vita2d_free_texture(greenbar_icon.id); + } + + void Free(Tex *texture) { + if (texture->id != no_icon.id) + { + vita2d_free_texture(texture->id); + } + } + +} diff --git a/src/textures.h b/src/textures.h new file mode 100644 index 0000000..2247167 --- /dev/null +++ b/src/textures.h @@ -0,0 +1,33 @@ +#ifndef LAUNCHER_TEXTURES_H +#define LAUNCHER_TEXTURES_H + +#include +#include + +typedef struct { + vita2d_texture *id=0; + int width; + int height; +} Tex; + +extern Tex no_icon; +extern Tex favorite_icon; +extern Tex square_icon; +extern Tex triangle_icon; +extern Tex circle_icon; +extern Tex cross_icon; +extern Tex start_icon; +extern Tex folder_icon; +extern Tex selected_icon; +extern Tex redbar_icon; +extern Tex greenbar_icon; + +namespace Textures { + void LoadFonts(Tex *font_texture); + bool LoadImageFile(const std::string filename, Tex *texture); + void Init(void); + void Exit(void); + void Free(Tex *texture); +} + +#endif diff --git a/src/unzip.c b/src/unzip.c new file mode 100644 index 0000000..da49cb4 --- /dev/null +++ b/src/unzip.c @@ -0,0 +1,1963 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + Modifications for AES, PKWARE disk spanning + Copyright (C) 2010-2014 Nathan Moinvaziri + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. + + Mar 8th, 2016 - Lucio Cosmo + Fixed support for 64bit builds for archives with "PKWARE" password. + Changed long, unsigned long, unsigned to unsigned int in + access functions to crctables and pkeys +*/ + +#include +#include +#include +#include + +/*#ifndef NOUNCRYPT +# define NOUNCRYPT +#endif*/ + +#include "unzip.h" +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H +extern int errno; +#else +# include +#endif + +#ifdef HAVE_AES +# define AES_METHOD (99) +# define AES_PWVERIFYSIZE (2) +# define AES_MAXSALTLENGTH (16) +# define AES_AUTHCODESIZE (10) +# define AES_HEADERSIZE (11) +# define AES_KEYSIZE(mode) (64 + (mode * 64)) + +# include "aes/aes.h" +# include "aes/fileenc.h" +#endif +#ifndef NOUNCRYPT +# include "crypt.h" +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#define DISKHEADERMAGIC (0x08074b50) +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x06064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x07064b50) + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZECENTRALHEADERLOCATOR (0x14) /* 20 */ +#define SIZEZIPLOCALHEADER (0x1e) + +#ifndef BUFREADCOMMENT +# define BUFREADCOMMENT (0x400) +#endif + +#ifndef UNZ_BUFSIZE +# define UNZ_BUFSIZE (64 * 1024) +#endif +#ifndef UNZ_MAXFILENAMEINZIP +# define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) \ + { \ + if (p) \ + free(p); \ + } +#endif + +const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile; /* relative offset of local header 8 bytes */ + ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */ +#ifdef HAVE_AES + uLong aes_encryption_mode; + uLong aes_compression_method; + uLong aes_version; +#endif +} unz_file_info64_internal; + +/* file_in_zip_read_info_s contain internal information about a file in zipfile */ +typedef struct +{ + Bytef* read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif +#ifdef HAVE_AES + fcrypt_ctx aes_ctx; +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek */ + uLong stream_initialised; /* flag set if stream structure is initialised */ + + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + unsigned int size_local_extrafield; /* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read */ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed; /* number of byte to be obtained after decomp */ + + zlib_filefunc64_32_def z_filefunc; + + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */ + int raw; +} file_in_zip64_read_info_s; + +/* unz64_s contain internal information about the zipfile */ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structure of the current zipfile */ + voidpf filestream_with_CD; /* io structure of the disk with the central directory */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + uLong number_disk; /* number of the current disk, used for spanning ZIP*/ + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; + /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; + /* structure about the current file if we are decompressing it */ + int isZip64; /* is the current file zip64 */ +#ifndef NOUNCRYPT + unsigned int keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned int* pcrc_32_tab; +#endif +} unz64_s; + +/* Translate date/time from Dos format to tm_unz (readable more easily) */ +local void unz64local_DosDateToTmuDate(ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate = (ZPOS64_T)(ulDosDate >> 16); + + ptm->tm_mday = (unsigned int)(uDate & 0x1f); + ptm->tm_mon = (unsigned int)((((uDate)&0x1E0) / 0x20) - 1); + ptm->tm_year = (unsigned int)(((uDate & 0x0FE00) / 0x0200) + 1980); + ptm->tm_hour = (unsigned int)((ulDosDate & 0xF800) / 0x800); + ptm->tm_min = (unsigned int)((ulDosDate & 0x7E0) / 0x20); + ptm->tm_sec = (unsigned int)(2 * (ulDosDate & 0x1f)); + +#define unz64local_in_range(min, max, value) ((min) <= (value) && (value) <= (max)) + if (!unz64local_in_range(0, 11, ptm->tm_mon) || !unz64local_in_range(1, 31, ptm->tm_mday) + || !unz64local_in_range(0, 23, ptm->tm_hour) || !unz64local_in_range(0, 59, ptm->tm_min) + || !unz64local_in_range(0, 59, ptm->tm_sec)) + /* Invalid date stored, so don't return it. */ + memset(ptm, 0, sizeof(tm_unz)); +#undef unz64local_in_range +} + +/* Read a byte from a gz_stream; Return EOF for end of file. */ +local int unz64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int* pi)); +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int* pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def, filestream, &c, 1); + if (err == 1) + { + *pi = (int)c; + return UNZ_OK; + } + *pi = 0; + if (ZERROR64(*pzlib_filefunc_def, filestream)) + return UNZ_ERRNO; + return UNZ_EOF; +} + +local int unz64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)); +local int unz64local_getShort(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (uLong)i; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((uLong)i) << 8; + + if (err == UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)); +local int unz64local_getLong(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (uLong)i; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((uLong)i) << 8; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((uLong)i) << 16; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong)i) << 24; + + if (err == UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T* pX)); +local int unz64local_getLong64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T* pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (ZPOS64_T)i; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i) << 8; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i) << 16; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i) << 24; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i) << 32; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i) << 40; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i) << 48; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i) << 56; + + if (err == UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* Locate the Central directory of a zip file (at the end, just before the global comment) */ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T file_size; + ZPOS64_T back_read = 4; + ZPOS64_T max_back = 0xffff; /* maximum size of global comment */ + ZPOS64_T pos_found = 0; + uLong read_size; + ZPOS64_T read_pos; + int i; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT + 4); + if (buf == NULL) + return 0; + + if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0) + { + TRYFREE(buf); + return 0; + } + + file_size = ZTELL64(*pzlib_filefunc_def, filestream); + + if (max_back > file_size) + max_back = file_size; + + while (back_read < max_back) + { + if (back_read + BUFREADCOMMENT > max_back) + back_read = max_back; + else + back_read += BUFREADCOMMENT; + + read_pos = file_size - back_read; + read_size = ((BUFREADCOMMENT + 4) < (file_size - read_pos)) ? (BUFREADCOMMENT + 4) : (uLong)(file_size - read_pos); + + if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + break; + if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size) + break; + + for (i = (int)read_size - 3; (i--) > 0;) + if (((*(buf + i)) == (ENDHEADERMAGIC & 0xff)) && ((*(buf + i + 1)) == (ENDHEADERMAGIC >> 8 & 0xff)) + && ((*(buf + i + 2)) == (ENDHEADERMAGIC >> 16 & 0xff)) && ((*(buf + i + 3)) == (ENDHEADERMAGIC >> 24 & 0xff))) + { + pos_found = read_pos + i; + break; + } + + if (pos_found != 0) + break; + } + TRYFREE(buf); + return pos_found; +} + +/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ +local ZPOS64_T unz64local_SearchCentralDir64 + OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, const ZPOS64_T endcentraloffset)); +local ZPOS64_T unz64local_SearchCentralDir64( + const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, const ZPOS64_T endcentraloffset) +{ + ZPOS64_T offset; + uLong uL; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0) + return 0; + + /* read locator signature */ + if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) + return 0; + if (uL != ZIP64ENDLOCHEADERMAGIC) + return 0; + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) + return 0; + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def, filestream, &offset) != UNZ_OK) + return 0; + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) + return 0; + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def, filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0) + return 0; + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) + return 0; + if (uL != ZIP64ENDHEADERMAGIC) + return 0; + + return offset; +} + +local unzFile unzOpenInternal(const void* path, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + unz64_s us; + unz64_s* s; + ZPOS64_T central_pos; + ZPOS64_T central_pos64; + uLong uL; + ZPOS64_T uL64; + voidpf filestream = NULL; + ZPOS64_T number_entry_CD; + int err = UNZ_OK; + + if (unz_copyright[0] != ' ') + return NULL; + + us.filestream = NULL; + us.filestream_with_CD = NULL; + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def == NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + + us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); + + if (us.filestream == NULL) + return NULL; + + us.filestream_with_CD = us.filestream; + us.isZip64 = 0; + + /* Search for end of central directory header */ + central_pos = unz64local_SearchCentralDir(&us.z_filefunc, us.filestream); + if (central_pos) + { + if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + us.number_disk = uL; + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + us.gi.number_disk_with_CD = uL; + /* total number of entries in the central directory on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + us.gi.number_entry = uL; + /* total number of entries in the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + number_entry_CD = uL; + if (number_entry_CD != us.gi.number_entry) + err = UNZ_BADZIPFILE; + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + us.size_central_dir = uL; + /* offset of start of central directory with respect to the starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + us.offset_central_dir = uL; + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &us.gi.size_comment) != UNZ_OK) + err = UNZ_ERRNO; + + if (err == UNZ_OK) + { + /* Search for Zip64 end of central directory header */ + central_pos64 = unz64local_SearchCentralDir64(&us.z_filefunc, us.filestream, central_pos); + if (central_pos64) + { + central_pos = central_pos64; + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream, &uL64) != UNZ_OK) + err = UNZ_ERRNO; + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &us.number_disk) != UNZ_OK) + err = UNZ_ERRNO; + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &us.gi.number_disk_with_CD) != UNZ_OK) + err = UNZ_ERRNO; + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.gi.number_entry) != UNZ_OK) + err = UNZ_ERRNO; + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream, &number_entry_CD) != UNZ_OK) + err = UNZ_ERRNO; + if (number_entry_CD != us.gi.number_entry) + err = UNZ_BADZIPFILE; + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.size_central_dir) != UNZ_OK) + err = UNZ_ERRNO; + /* offset of start of central directory with respect to the starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.offset_central_dir) != UNZ_OK) + err = UNZ_ERRNO; + } + else if ((us.gi.number_entry == 0xffff) || (us.size_central_dir == 0xffff) || (us.offset_central_dir == 0xffffffff)) + err = UNZ_BADZIPFILE; + } + } + else + err = UNZ_ERRNO; + + if ((err == UNZ_OK) && (central_pos < us.offset_central_dir + us.size_central_dir)) + err = UNZ_BADZIPFILE; + + if (err != UNZ_OK) + { + ZCLOSE64(us.z_filefunc, us.filestream); + return NULL; + } + + if (us.gi.number_disk_with_CD == 0) + { + /* If there is only one disk open another stream so we don't have to seek between the CD + and the file headers constantly */ + filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); + if (filestream != NULL) + us.filestream = filestream; + } + + /* Hack for zip files that have no respect for zip64 + if ((central_pos > 0xffffffff) && (us.offset_central_dir < 0xffffffff)) + us.offset_central_dir = central_pos - us.size_central_dir;*/ + + us.byte_before_the_zipfile = central_pos - (us.offset_central_dir + us.size_central_dir); + us.central_pos = central_pos; + us.pfile_in_zip_read = NULL; + + s = (unz64_s*)ALLOC(sizeof(unz64_s)); + if (s != NULL) + { + *s = us; + unzGoToFirstFile((unzFile)s); + } + return (unzFile)s; +} + +extern unzFile ZEXPORT unzOpen2(const char* path, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def); + return unzOpenInternal(path, &zlib_filefunc64_32_def_fill); + } + return unzOpenInternal(path, NULL); +} + +extern unzFile ZEXPORT unzOpen2_64(const void* path, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return unzOpenInternal(path, &zlib_filefunc64_32_def_fill); + } + return unzOpenInternal(path, NULL); +} + +extern unzFile ZEXPORT unzOpen(const char* path) +{ + return unzOpenInternal(path, NULL); +} + +extern unzFile ZEXPORT unzOpen64(const void* path) +{ + return unzOpenInternal(path, NULL); +} + +extern int ZEXPORT unzClose(unzFile file) +{ + unz64_s* s; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD)) + ZCLOSE64(s->z_filefunc, s->filestream); + if (s->filestream_with_CD != NULL) + ZCLOSE64(s->z_filefunc, s->filestream_with_CD); + + s->filestream = NULL; + s->filestream_with_CD = NULL; + TRYFREE(s); + return UNZ_OK; +} + +/* Goto to the next available disk for spanned archives */ +local int unzGoToNextDisk OF((unzFile file)); +local int unzGoToNextDisk(unzFile file) +{ + unz64_s* s; + uLong number_disk_next = 0; + + s = (unz64_s*)file; + if (s == NULL) + return UNZ_PARAMERROR; + number_disk_next = s->number_disk; + + if ((s->pfile_in_zip_read != NULL) && (s->pfile_in_zip_read->rest_read_uncompressed > 0)) + /* We are currently reading a file and we need the next sequential disk */ + number_disk_next += 1; + else + /* Goto the disk for the current file */ + number_disk_next = s->cur_file_info.disk_num_start; + + if (number_disk_next != s->number_disk) + { + /* Switch disks */ + if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD)) + ZCLOSE64(s->z_filefunc, s->filestream); + + if (number_disk_next == s->gi.number_disk_with_CD) + { + s->filestream = s->filestream_with_CD; + } + else + { + s->filestream = ZOPENDISK64( + s->z_filefunc, s->filestream_with_CD, number_disk_next, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); + } + + if (s->filestream == NULL) + return UNZ_ERRNO; + + s->number_disk = number_disk_next; + } + + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + pglobal_info32->number_disk_with_CD = s->gi.number_disk_with_CD; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + *pglobal_info = s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalComment(unzFile file, char* comment, uLong comment_size) +{ + unz64_s* s; + uLong bytes_to_read = comment_size; + if (file == NULL) + return (int)UNZ_PARAMERROR; + s = (unz64_s*)file; + + if (bytes_to_read > s->gi.size_comment) + bytes_to_read = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, s->central_pos + 22, ZLIB_FILEFUNC_SEEK_SET) != 0) + return UNZ_ERRNO; + + if (bytes_to_read > 0) + { + *comment = 0; + if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, bytes_to_read) != bytes_to_read) + return UNZ_ERRNO; + } + + if ((comment != NULL) && (comment_size > s->gi.size_comment)) + *(comment + s->gi.size_comment) = 0; + return (int)bytes_to_read; +} + +/* Get Info about the current file in the zipfile, with internal only info */ +local int unz64local_GetCurrentFileInfoInternal( + unzFile file, unz_file_info64* pfile_info, unz_file_info64_internal* pfile_info_internal, char* filename, + uLong filename_size, void* extrafield, uLong extrafield_size, char* comment, uLong comment_size) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + ZPOS64_T bytes_to_read; + int err = UNZ_OK; + uLong uMagic; + long lSeek = 0; + ZPOS64_T current_pos = 0; + uLong acc = 0; + uLong uL; + ZPOS64_T uL64; + + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + + if (ZSEEK64( + s->z_filefunc, s->filestream_with_CD, s->pos_in_central_dir + s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) + != 0) + err = UNZ_ERRNO; + + /* Check the magic */ + if (err == UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uMagic) != UNZ_OK) + err = UNZ_ERRNO; + else if (uMagic != CENTRALHEADERMAGIC) + err = UNZ_BADZIPFILE; + } + + /* Read central directory header */ + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.version) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.version_needed) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.flag) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.compression_method) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.dosDate) != UNZ_OK) + err = UNZ_ERRNO; + unz64local_DosDateToTmuDate(file_info.dosDate, &file_info.tmu_date); + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.crc) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + file_info.compressed_size = uL; + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + file_info.uncompressed_size = uL; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_filename) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_extra) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_comment) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.internal_fa) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.external_fa) != UNZ_OK) + err = UNZ_ERRNO; + /* Relative offset of local header */ + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + + file_info.size_file_extra_internal = 0; + file_info.disk_offset = uL; + file_info_internal.offset_curfile = uL; +#ifdef HAVE_AES + file_info_internal.aes_compression_method = 0; + file_info_internal.aes_encryption_mode = 0; + file_info_internal.aes_version = 0; +#endif + + lSeek += file_info.size_filename; + + if ((err == UNZ_OK) && (filename != NULL)) + { + if (file_info.size_filename < filename_size) + { + *(filename + file_info.size_filename) = 0; + bytes_to_read = file_info.size_filename; + } + else + bytes_to_read = filename_size; + + if ((file_info.size_filename > 0) && (filename_size > 0)) + if (ZREAD64(s->z_filefunc, s->filestream_with_CD, filename, (uLong)bytes_to_read) != bytes_to_read) + err = UNZ_ERRNO; + lSeek -= (uLong)bytes_to_read; + } + + /* Read extrafield */ + if ((err == UNZ_OK) && (extrafield != NULL)) + { + if (file_info.size_file_extra < extrafield_size) + bytes_to_read = file_info.size_file_extra; + else + bytes_to_read = extrafield_size; + + if (lSeek != 0) + { + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) == 0) + lSeek = 0; + else + err = UNZ_ERRNO; + } + + if ((file_info.size_file_extra > 0) && (extrafield_size > 0)) + if (ZREAD64(s->z_filefunc, s->filestream_with_CD, extrafield, (uLong)bytes_to_read) != bytes_to_read) + err = UNZ_ERRNO; + lSeek += file_info.size_file_extra - (uLong)bytes_to_read; + } + else + lSeek += file_info.size_file_extra; + + if ((err == UNZ_OK) && (file_info.size_file_extra != 0)) + { + if (lSeek != 0) + { + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) == 0) + lSeek = 0; + else + err = UNZ_ERRNO; + } + + /* We are going to parse the extra field so we need to move back */ + current_pos = ZTELL64(s->z_filefunc, s->filestream_with_CD); + if (current_pos < file_info.size_file_extra) + err = UNZ_ERRNO; + current_pos -= file_info.size_file_extra; + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, current_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = UNZ_ERRNO; + + while ((err != UNZ_ERRNO) && (acc < file_info.size_file_extra)) + { + uLong headerid; + uLong datasize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &headerid) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &datasize) != UNZ_OK) + err = UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerid == 0x0001) + { + /* Subtract size of ZIP64 field, since ZIP64 is handled internally */ + file_info.size_file_extra_internal += 2 + 2 + datasize; + + if (file_info.uncompressed_size == 0xffffffff) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &file_info.uncompressed_size) != UNZ_OK) + err = UNZ_ERRNO; + } + if (file_info.compressed_size == 0xffffffff) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &file_info.compressed_size) != UNZ_OK) + err = UNZ_ERRNO; + } + if (file_info_internal.offset_curfile == 0xffffffff) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &uL64) != UNZ_OK) + err = UNZ_ERRNO; + file_info_internal.offset_curfile = uL64; + file_info.disk_offset = uL64; + } + if (file_info.disk_num_start == 0xffffffff) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK) + err = UNZ_ERRNO; + } + } +#ifdef HAVE_AES + /* AES header */ + else if (headerid == 0x9901) + { + /* Subtract size of AES field, since AES is handled internally */ + file_info.size_file_extra_internal += 2 + 2 + datasize; + + /* Verify version info */ + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + /* Support AE-1 and AE-2 */ + if (uL != 1 && uL != 2) + err = UNZ_ERRNO; + file_info_internal.aes_version = uL; + if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + if ((char)uL != 'A') + err = UNZ_ERRNO; + if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + if ((char)uL != 'E') + err = UNZ_ERRNO; + /* Get AES encryption strength and actual compression method */ + if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + file_info_internal.aes_encryption_mode = uL; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + file_info_internal.aes_compression_method = uL; + } +#endif + else + { + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, datasize, ZLIB_FILEFUNC_SEEK_CUR) != 0) + err = UNZ_ERRNO; + } + + acc += 2 + 2 + datasize; + } + } + + if (file_info.disk_num_start == s->gi.number_disk_with_CD) + file_info_internal.byte_before_the_zipfile = s->byte_before_the_zipfile; + else + file_info_internal.byte_before_the_zipfile = 0; + + if ((err == UNZ_OK) && (comment != NULL)) + { + if (file_info.size_file_comment < comment_size) + { + *(comment + file_info.size_file_comment) = 0; + bytes_to_read = file_info.size_file_comment; + } + else + bytes_to_read = comment_size; + + if (lSeek != 0) + { + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) != 0) + err = UNZ_ERRNO; + } + + if ((file_info.size_file_comment > 0) && (comment_size > 0)) + if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, (uLong)bytes_to_read) != bytes_to_read) + err = UNZ_ERRNO; + lSeek += file_info.size_file_comment - (uLong)bytes_to_read; + } + else + lSeek += file_info.size_file_comment; + + if ((err == UNZ_OK) && (pfile_info != NULL)) + *pfile_info = file_info; + + if ((err == UNZ_OK) && (pfile_info_internal != NULL)) + *pfile_info_internal = file_info_internal; + + return err; +} + +extern int ZEXPORT unzGetCurrentFileInfo( + unzFile file, unz_file_info* pfile_info, char* filename, uLong filename_size, void* extrafield, uLong extrafield_size, + char* comment, uLong comment_size) +{ + unz_file_info64 file_info64; + int err; + + err = unz64local_GetCurrentFileInfoInternal( + file, &file_info64, NULL, filename, filename_size, extrafield, extrafield_size, comment, comment_size); + + if ((err == UNZ_OK) && (pfile_info != NULL)) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra - file_info64.size_file_extra_internal; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + } + return err; +} + +extern int ZEXPORT unzGetCurrentFileInfo64( + unzFile file, unz_file_info64* pfile_info, char* filename, uLong filename_size, void* extrafield, uLong extrafield_size, + char* comment, uLong comment_size) +{ + return unz64local_GetCurrentFileInfoInternal( + file, pfile_info, NULL, filename, filename_size, extrafield, extrafield_size, comment, comment_size); +} + +/* Read the local header of the current zipfile. Check the coherency of the local header and info in the + end of central directory about this file store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) */ +local int unz64local_CheckCurrentFileCoherencyHeader( + unz64_s* s, unsigned int* piSizeVar, ZPOS64_T* poffset_local_extrafield, unsigned int* psize_local_extrafield) +{ + uLong uMagic, uL, uFlags; + uLong size_filename; + uLong size_extra_field; + int err = UNZ_OK; + int compression_method = 0; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + err = unzGoToNextDisk((unzFile)s); + if (err != UNZ_OK) + return err; + + if (ZSEEK64( + s->z_filefunc, s->filestream, + s->cur_file_info_internal.offset_curfile + s->cur_file_info_internal.byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET) + != 0) + return UNZ_ERRNO; + + if (err == UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream, &uMagic) != UNZ_OK) + err = UNZ_ERRNO; + else if (uMagic != LOCALHEADERMAGIC) + err = UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream, &uFlags) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + else if ((err == UNZ_OK) && (uL != s->cur_file_info.compression_method)) + err = UNZ_BADZIPFILE; + + compression_method = (int)s->cur_file_info.compression_method; +#ifdef HAVE_AES + if (compression_method == AES_METHOD) + compression_method = (int)s->cur_file_info_internal.aes_compression_method; +#endif + + if ((err == UNZ_OK) && (compression_method != 0) && +#ifdef HAVE_BZIP2 + (compression_method != Z_BZIP2ED) && +#endif + (compression_method != Z_DEFLATED)) + err = UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* date/time */ + err = UNZ_ERRNO; + if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* crc */ + err = UNZ_ERRNO; + else if ((err == UNZ_OK) && (uL != s->cur_file_info.crc) && ((uFlags & 8) == 0)) + err = UNZ_BADZIPFILE; + if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* size compr */ + err = UNZ_ERRNO; + else if ((uL != 0xffffffff) && (err == UNZ_OK) && (uL != s->cur_file_info.compressed_size) && ((uFlags & 8) == 0)) + err = UNZ_BADZIPFILE; + if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* size uncompr */ + err = UNZ_ERRNO; + else if ((uL != 0xffffffff) && (err == UNZ_OK) && (uL != s->cur_file_info.uncompressed_size) && ((uFlags & 8) == 0)) + err = UNZ_BADZIPFILE; + if (unz64local_getShort(&s->z_filefunc, s->filestream, &size_filename) != UNZ_OK) + err = UNZ_ERRNO; + else if ((err == UNZ_OK) && (size_filename != s->cur_file_info.size_filename)) + err = UNZ_BADZIPFILE; + + *piSizeVar += (unsigned int)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream, &size_extra_field) != UNZ_OK) + err = UNZ_ERRNO; + *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (unsigned int)size_extra_field; + + *piSizeVar += (unsigned int)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int* method, int* level, int raw, const char* password) +{ + int err = UNZ_OK; + int compression_method; + unsigned int iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; + unsigned int size_local_extrafield; +#ifndef NOUNCRYPT + char source[12]; +#else + if (password != NULL) + return UNZ_PARAMERROR; +#endif + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s, &iSizeVar, &offset_local_extrafield, &size_local_extrafield) != UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info == NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer = (Bytef*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield = 0; + pfile_in_zip_read_info->raw = raw; + + if (pfile_in_zip_read_info->read_buffer == NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised = 0; + + compression_method = (int)s->cur_file_info.compression_method; +#ifdef HAVE_AES + if (compression_method == AES_METHOD) + compression_method = (int)s->cur_file_info_internal.aes_compression_method; +#endif + + if (method != NULL) + *method = compression_method; + + if (level != NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6: + *level = 1; + break; + case 4: + *level = 2; + break; + case 2: + *level = 9; + break; + } + } + + if ((compression_method != 0) && +#ifdef HAVE_BZIP2 + (compression_method != Z_BZIP2ED) && +#endif + (compression_method != Z_DEFLATED)) + err = UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait = s->cur_file_info.crc; + pfile_in_zip_read_info->crc32 = 0; + pfile_in_zip_read_info->total_out_64 = 0; + pfile_in_zip_read_info->compression_method = compression_method; + pfile_in_zip_read_info->filestream = s->filestream; + pfile_in_zip_read_info->z_filefunc = s->z_filefunc; + if (s->number_disk == s->gi.number_disk_with_CD) + pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile; + else + pfile_in_zip_read_info->byte_before_the_zipfile = 0; + pfile_in_zip_read_info->stream.total_out = 0; + pfile_in_zip_read_info->stream.total_in = 0; + pfile_in_zip_read_info->stream.next_in = NULL; + + if (!raw) + { + if (compression_method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void* (*)(void*, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err = BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised = Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw = 1; +#endif + } + else if (compression_method == Z_DEFLATED) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)s; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err = inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised = Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + } + + pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size; + pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size; + pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; + pfile_in_zip_read_info->stream.avail_in = (unsigned int)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + +#ifndef NOUNCRYPT + s->pcrc_32_tab = NULL; + + if ((password != NULL) && ((s->cur_file_info.flag & 1) != 0)) + { + if (ZSEEK64( + s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) + != 0) + return UNZ_INTERNALERROR; +# ifdef HAVE_AES + if (s->cur_file_info.compression_method == AES_METHOD) + { + unsigned char passverify[AES_PWVERIFYSIZE]; + unsigned char saltvalue[AES_MAXSALTLENGTH]; + unsigned int saltlength; + + if ((s->cur_file_info_internal.aes_encryption_mode < 1) || (s->cur_file_info_internal.aes_encryption_mode > 3)) + return UNZ_INTERNALERROR; + + saltlength = SALT_LENGTH(s->cur_file_info_internal.aes_encryption_mode); + + if (ZREAD64(s->z_filefunc, s->filestream, saltvalue, saltlength) != saltlength) + return UNZ_INTERNALERROR; + if (ZREAD64(s->z_filefunc, s->filestream, passverify, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE) + return UNZ_INTERNALERROR; + + fcrypt_init( + s->cur_file_info_internal.aes_encryption_mode, password, strlen(password), saltvalue, passverify, + &s->pfile_in_zip_read->aes_ctx); + + s->pfile_in_zip_read->rest_read_compressed -= saltlength + AES_PWVERIFYSIZE; + s->pfile_in_zip_read->rest_read_compressed -= AES_AUTHCODESIZE; + + s->pfile_in_zip_read->pos_in_zipfile += saltlength + AES_PWVERIFYSIZE; + } + else +# endif + { + int i; + s->pcrc_32_tab = (const unsigned int*)get_crc_table(); + init_keys(password, s->keys, s->pcrc_32_tab); + + if (ZREAD64(s->z_filefunc, s->filestream, source, 12) < 12) + return UNZ_INTERNALERROR; + + for (i = 0; i < 12; i++) + zdecode(s->keys, s->pcrc_32_tab, source[i]); + + s->pfile_in_zip_read->rest_read_compressed -= 12; + + s->pfile_in_zip_read->pos_in_zipfile += 12; + } + } +#endif + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile(unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/* Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if some bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ +extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len) +{ + int err = UNZ_OK; + unsigned int read = 0; + unz64_s* s; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + + if (s->pfile_in_zip_read == NULL) + return UNZ_PARAMERROR; + if (s->pfile_in_zip_read->read_buffer == NULL) + return UNZ_END_OF_LIST_OF_FILE; + if (len == 0) + return 0; + + s->pfile_in_zip_read->stream.next_out = (Bytef*)buf; + s->pfile_in_zip_read->stream.avail_out = (unsigned int)len; + + if (s->pfile_in_zip_read->raw) + { + if (len > s->pfile_in_zip_read->rest_read_compressed + s->pfile_in_zip_read->stream.avail_in) + s->pfile_in_zip_read->stream.avail_out = (unsigned int)s->pfile_in_zip_read->rest_read_compressed + + s->pfile_in_zip_read->stream.avail_in; + } + else + { + if (len > s->pfile_in_zip_read->rest_read_uncompressed) + s->pfile_in_zip_read->stream.avail_out = (unsigned int)s->pfile_in_zip_read->rest_read_uncompressed; + } + + while (s->pfile_in_zip_read->stream.avail_out > 0) + { + if (s->pfile_in_zip_read->stream.avail_in == 0) + { + uLong bytes_to_read = UNZ_BUFSIZE; + uLong bytes_not_read = 0; + uLong bytes_read = 0; + uLong total_bytes_read = 0; + + if (s->pfile_in_zip_read->stream.next_in != NULL) + bytes_not_read = s->pfile_in_zip_read->read_buffer + UNZ_BUFSIZE - s->pfile_in_zip_read->stream.next_in; + bytes_to_read -= bytes_not_read; + if (bytes_not_read > 0) + sceClibMemcpy(s->pfile_in_zip_read->read_buffer, s->pfile_in_zip_read->stream.next_in, bytes_not_read); + if (s->pfile_in_zip_read->rest_read_compressed < bytes_to_read) + bytes_to_read = (unsigned int)s->pfile_in_zip_read->rest_read_compressed; + + while (total_bytes_read != bytes_to_read) + { + if (ZSEEK64( + s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream, + s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET) + != 0) + return UNZ_ERRNO; + + bytes_read = ZREAD64( + s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream, + s->pfile_in_zip_read->read_buffer + bytes_not_read + total_bytes_read, bytes_to_read - total_bytes_read); + + total_bytes_read += bytes_read; + s->pfile_in_zip_read->pos_in_zipfile += bytes_read; + + if (bytes_read == 0) + { + if (ZERROR64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream)) + return UNZ_ERRNO; + + err = unzGoToNextDisk(file); + if (err != UNZ_OK) + return err; + + s->pfile_in_zip_read->pos_in_zipfile = 0; + s->pfile_in_zip_read->filestream = s->filestream; + } + } + +#ifndef NOUNCRYPT + if ((s->cur_file_info.flag & 1) != 0) + { +# ifdef HAVE_AES + if (s->cur_file_info.compression_method == AES_METHOD) + { + fcrypt_decrypt(s->pfile_in_zip_read->read_buffer, bytes_to_read, &s->pfile_in_zip_read->aes_ctx); + } + else +# endif + if (s->pcrc_32_tab != NULL) + { + unsigned int i; + for (i = 0; i < total_bytes_read; i++) + s->pfile_in_zip_read->read_buffer[i] = zdecode( + s->keys, s->pcrc_32_tab, s->pfile_in_zip_read->read_buffer[i]); + } + } +#endif + + s->pfile_in_zip_read->rest_read_compressed -= total_bytes_read; + s->pfile_in_zip_read->stream.next_in = (Bytef*)s->pfile_in_zip_read->read_buffer; + s->pfile_in_zip_read->stream.avail_in = (unsigned int)(bytes_not_read + total_bytes_read); + } + + if ((s->pfile_in_zip_read->compression_method == 0) || (s->pfile_in_zip_read->raw)) + { + unsigned int copy, i; + + if ((s->pfile_in_zip_read->stream.avail_in == 0) && (s->pfile_in_zip_read->rest_read_compressed == 0)) + return (read == 0) ? UNZ_EOF : read; + + if (s->pfile_in_zip_read->stream.avail_out < s->pfile_in_zip_read->stream.avail_in) + copy = s->pfile_in_zip_read->stream.avail_out; + else + copy = s->pfile_in_zip_read->stream.avail_in; + + for (i = 0; i < copy; i++) + *(s->pfile_in_zip_read->stream.next_out + i) = *(s->pfile_in_zip_read->stream.next_in + i); + + s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + copy; + s->pfile_in_zip_read->rest_read_uncompressed -= copy; + s->pfile_in_zip_read->crc32 = crc32(s->pfile_in_zip_read->crc32, s->pfile_in_zip_read->stream.next_out, copy); + + s->pfile_in_zip_read->stream.avail_in -= copy; + s->pfile_in_zip_read->stream.avail_out -= copy; + s->pfile_in_zip_read->stream.next_out += copy; + s->pfile_in_zip_read->stream.next_in += copy; + s->pfile_in_zip_read->stream.total_out += copy; + read += copy; + } + else if (s->pfile_in_zip_read->compression_method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong total_out_before, total_out_after; + const Bytef* buf_before; + uLong out_bytes; + + s->pfile_in_zip_read->bstream.next_in = (char*)s->pfile_in_zip_read->stream.next_in; + s->pfile_in_zip_read->bstream.avail_in = s->pfile_in_zip_read->stream.avail_in; + s->pfile_in_zip_read->bstream.total_in_lo32 = (unsigned int)s->pfile_in_zip_read->stream.total_in; + s->pfile_in_zip_read->bstream.total_in_hi32 = s->pfile_in_zip_read->stream.total_in >> 32; + + s->pfile_in_zip_read->bstream.next_out = (char*)s->pfile_in_zip_read->stream.next_out; + s->pfile_in_zip_read->bstream.avail_out = s->pfile_in_zip_read->stream.avail_out; + s->pfile_in_zip_read->bstream.total_out_lo32 = (unsigned int)s->pfile_in_zip_read->stream.total_out; + s->pfile_in_zip_read->bstream.total_out_hi32 = s->pfile_in_zip_read->stream.total_out >> 32; + + total_out_before = s->pfile_in_zip_read->bstream.total_out_lo32 + + (((uLong)s->pfile_in_zip_read->bstream.total_out_hi32) << 32); + buf_before = (const Bytef*)s->pfile_in_zip_read->bstream.next_out; + + err = BZ2_bzDecompress(&s->pfile_in_zip_read->bstream); + + total_out_after = s->pfile_in_zip_read->bstream.total_out_lo32 + + (((uLong)s->pfile_in_zip_read->bstream.total_out_hi32) << 32); + + out_bytes = total_out_after - total_out_before; + + s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + out_bytes; + s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes; + s->pfile_in_zip_read->crc32 = crc32(s->pfile_in_zip_read->crc32, buf_before, (unsigned int)(out_bytes)); + + read += (unsigned int)(total_out_after - total_out_before); + + s->pfile_in_zip_read->stream.next_in = (Bytef*)s->pfile_in_zip_read->bstream.next_in; + s->pfile_in_zip_read->stream.avail_in = s->pfile_in_zip_read->bstream.avail_in; + s->pfile_in_zip_read->stream.total_in = s->pfile_in_zip_read->bstream.total_in_lo32; + s->pfile_in_zip_read->stream.next_out = (Bytef*)s->pfile_in_zip_read->bstream.next_out; + s->pfile_in_zip_read->stream.avail_out = s->pfile_in_zip_read->bstream.avail_out; + s->pfile_in_zip_read->stream.total_out = s->pfile_in_zip_read->bstream.total_out_lo32; + + if (err == BZ_STREAM_END) + return (read == 0) ? UNZ_EOF : read; + if (err != BZ_OK) + break; +#endif + } + else + { + ZPOS64_T total_out_before, total_out_after; + const Bytef* buf_before; + ZPOS64_T out_bytes; + int flush = Z_SYNC_FLUSH; + + total_out_before = s->pfile_in_zip_read->stream.total_out; + buf_before = s->pfile_in_zip_read->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err = inflate(&s->pfile_in_zip_read->stream, flush); + + if ((err >= 0) && (s->pfile_in_zip_read->stream.msg != NULL)) + err = Z_DATA_ERROR; + + total_out_after = s->pfile_in_zip_read->stream.total_out; + out_bytes = total_out_after - total_out_before; + + s->pfile_in_zip_read->total_out_64 += out_bytes; + s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes; + s->pfile_in_zip_read->crc32 = crc32(s->pfile_in_zip_read->crc32, buf_before, (unsigned int)(out_bytes)); + + read += (unsigned int)(total_out_after - total_out_before); + + if (err == Z_STREAM_END) + return (read == 0) ? UNZ_EOF : read; + if (err != Z_OK) + break; + } + } + + if (err == Z_OK) + return read; + return err; +} + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file) +{ + unz64_s* s; + s = (unz64_s*)file; + if (file == NULL) + return 0; /* UNZ_PARAMERROR */ + if (s->pfile_in_zip_read == NULL) + return 0; /* UNZ_PARAMERROR */ + return s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile; +} + +extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + unsigned int read_now; + ZPOS64_T size_to_read; + + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + if (s->pfile_in_zip_read == NULL) + return UNZ_PARAMERROR; + + size_to_read = s->pfile_in_zip_read->size_local_extrafield - s->pfile_in_zip_read->pos_local_extrafield; + + if (buf == NULL) + return (int)size_to_read; + + if (len > size_to_read) + read_now = (unsigned int)size_to_read; + else + read_now = (unsigned int)len; + + if (read_now == 0) + return 0; + + if (ZSEEK64( + s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream, + s->pfile_in_zip_read->offset_local_extrafield + s->pfile_in_zip_read->pos_local_extrafield, ZLIB_FILEFUNC_SEEK_SET) + != 0) + return UNZ_ERRNO; + + if (ZREAD64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream, buf, read_now) != read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +extern int ZEXPORT unzCloseCurrentFile(unzFile file) +{ + int err = UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + pfile_in_zip_read_info = s->pfile_in_zip_read; + + if (pfile_in_zip_read_info == NULL) + return UNZ_PARAMERROR; + +#ifdef HAVE_AES + if (s->cur_file_info.compression_method == AES_METHOD) + { + unsigned char authcode[AES_AUTHCODESIZE]; + unsigned char rauthcode[AES_AUTHCODESIZE]; + + if (ZREAD64(s->z_filefunc, s->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE) + return UNZ_ERRNO; + + if (fcrypt_end(rauthcode, &s->pfile_in_zip_read->aes_ctx) != AES_AUTHCODESIZE) + err = UNZ_CRCERROR; + if (memcmp(authcode, rauthcode, AES_AUTHCODESIZE) != 0) + err = UNZ_CRCERROR; + } + /* AES zip version AE-1 will expect a valid crc as well */ + if ((s->cur_file_info.compression_method != AES_METHOD) || (s->cur_file_info_internal.aes_version == 0x0001)) +#endif + { + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err = UNZ_CRCERROR; + } + } + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read = NULL; + + return err; +} + +extern int ZEXPORT unzGoToFirstFile2( + unzFile file, unz_file_info64* pfile_info, char* filename, uLong filename_size, void* extrafield, uLong extrafield_size, + char* comment, uLong comment_size) +{ + int err = UNZ_OK; + unz64_s* s; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + s->pos_in_central_dir = s->offset_central_dir; + s->num_file = 0; + err = unz64local_GetCurrentFileInfoInternal( + file, &s->cur_file_info, &s->cur_file_info_internal, filename, filename_size, extrafield, extrafield_size, comment, + comment_size); + s->current_file_ok = (err == UNZ_OK); + if ((err == UNZ_OK) && (pfile_info != NULL)) + sceClibMemcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64)); + return err; +} + +extern int ZEXPORT unzGoToFirstFile(unzFile file) +{ + return unzGoToFirstFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0); +} + +extern int ZEXPORT unzGoToNextFile2( + unzFile file, unz_file_info64* pfile_info, char* filename, uLong filename_size, void* extrafield, uLong extrafield_size, + char* comment, uLong comment_size) +{ + unz64_s* s; + int err; + + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file + 1 == s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + + s->cur_file_info.size_file_comment; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal( + file, &s->cur_file_info, &s->cur_file_info_internal, filename, filename_size, extrafield, extrafield_size, comment, + comment_size); + s->current_file_ok = (err == UNZ_OK); + if ((err == UNZ_OK) && (pfile_info != NULL)) + sceClibMemcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64)); + return err; +} + +extern int ZEXPORT unzGoToNextFile(unzFile file) +{ + return unzGoToNextFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0); +} + +extern int ZEXPORT unzLocateFile(unzFile file, const char* filename, unzFileNameComparer filename_compare_func) +{ + unz64_s* s; + int err; + unz_file_info64 cur_file_info_saved; + unz_file_info64_internal cur_file_info_internal_saved; + ZPOS64_T num_file_saved; + ZPOS64_T pos_in_central_dir_saved; + char current_filename[UNZ_MAXFILENAMEINZIP + 1]; + + if (file == NULL) + return UNZ_PARAMERROR; + if (strlen(filename) >= UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_file_saved = s->num_file; + pos_in_central_dir_saved = s->pos_in_central_dir; + cur_file_info_saved = s->cur_file_info; + cur_file_info_internal_saved = s->cur_file_info_internal; + + err = unzGoToFirstFile2(file, NULL, current_filename, sizeof(current_filename) - 1, NULL, 0, NULL, 0); + + while (err == UNZ_OK) + { + if (filename_compare_func != NULL) + err = filename_compare_func(file, current_filename, filename); + else + err = strcmp(current_filename, filename); + if (err == 0) + return UNZ_OK; + err = unzGoToNextFile2(file, NULL, current_filename, sizeof(current_filename) - 1, NULL, 0, NULL, 0); + } + + /* We failed, so restore the state of the 'current file' to where we were. */ + s->num_file = num_file_saved; + s->pos_in_central_dir = pos_in_central_dir_saved; + s->cur_file_info = cur_file_info_saved; + s->cur_file_info_internal = cur_file_info_internal_saved; + return err; +} + +extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file, &file_pos64); + if (err == UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + + if (file_pos == NULL) + return UNZ_PARAMERROR; + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file, &file_pos64); +} + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file == NULL || file_pos == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file == NULL || file_pos == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern uLong ZEXPORT unzGetOffset(unzFile file) +{ + ZPOS64_T offset64; + + if (file == NULL) + return 0; /* UNZ_PARAMERROR; */ + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file == NULL) + return 0; /* UNZ_PARAMERROR; */ + s = (unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file == s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern int ZEXPORT unzSetOffset(unzFile file, uLong pos) +{ + return unzSetOffset64(file, pos); +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + + err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0); + + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern z_off_t ZEXPORT unztell(unzFile file) +{ + unz64_s* s; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + if (s->pfile_in_zip_read == NULL) + return UNZ_PARAMERROR; + return (z_off_t)s->pfile_in_zip_read->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64(unzFile file) +{ + unz64_s* s; + if (file == NULL) + return (ZPOS64_T)-1; + s = (unz64_s*)file; + if (s->pfile_in_zip_read == NULL) + return (ZPOS64_T)-1; + return s->pfile_in_zip_read->total_out_64; +} + +extern int ZEXPORT unzseek(unzFile file, z_off_t offset, int origin) +{ + return unzseek64(file, (ZPOS64_T)offset, origin); +} + +extern int ZEXPORT unzseek64(unzFile file, ZPOS64_T offset, int origin) +{ + unz64_s* s; + ZPOS64_T stream_pos_begin; + ZPOS64_T stream_pos_end; + int isWithinBuffer; + ZPOS64_T position; + + if (file == NULL) + return UNZ_PARAMERROR; + + s = (unz64_s*)file; + + if (s->pfile_in_zip_read == NULL) + return UNZ_ERRNO; + if (s->pfile_in_zip_read->compression_method != 0) + return UNZ_ERRNO; + + if (origin == SEEK_SET) + position = offset; + else if (origin == SEEK_CUR) + position = s->pfile_in_zip_read->total_out_64 + offset; + else if (origin == SEEK_END) + position = s->cur_file_info.compressed_size + offset; + else + return UNZ_PARAMERROR; + + if (position > s->cur_file_info.compressed_size) + return UNZ_PARAMERROR; + + stream_pos_end = s->pfile_in_zip_read->pos_in_zipfile; + stream_pos_begin = stream_pos_end; + + if (stream_pos_begin > UNZ_BUFSIZE) + stream_pos_begin -= UNZ_BUFSIZE; + else + stream_pos_begin = 0; + + isWithinBuffer = s->pfile_in_zip_read->stream.avail_in != 0 + && (s->pfile_in_zip_read->rest_read_compressed != 0 || s->cur_file_info.compressed_size < UNZ_BUFSIZE) + && position >= stream_pos_begin && position < stream_pos_end; + + if (isWithinBuffer) + { + s->pfile_in_zip_read->stream.next_in += position - s->pfile_in_zip_read->total_out_64; + s->pfile_in_zip_read->stream.avail_in = (unsigned int)(stream_pos_end - position); + } + else + { + s->pfile_in_zip_read->stream.avail_in = 0; + s->pfile_in_zip_read->stream.next_in = 0; + + s->pfile_in_zip_read->pos_in_zipfile = s->pfile_in_zip_read->offset_local_extrafield + position; + s->pfile_in_zip_read->rest_read_compressed = s->cur_file_info.compressed_size - position; + } + + s->pfile_in_zip_read->rest_read_uncompressed -= (position - s->pfile_in_zip_read->total_out_64); + s->pfile_in_zip_read->stream.total_out = (uLong)position; + s->pfile_in_zip_read->total_out_64 = position; + + return UNZ_OK; +} + +extern int ZEXPORT unzeof(unzFile file) +{ + unz64_s* s; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + if (s->pfile_in_zip_read == NULL) + return UNZ_PARAMERROR; + if (s->pfile_in_zip_read->rest_read_uncompressed == 0) + return 1; + return 0; +} diff --git a/src/unzip.h b/src/unzip.h new file mode 100644 index 0000000..ee1eb24 --- /dev/null +++ b/src/unzip.h @@ -0,0 +1,327 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef _UNZ_H +#define _UNZ_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +# include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +# include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +# include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ +{ + int unused; +} unzFile__; +typedef unzFile__* unzFile; +#else +typedef voidp unzFile; +#endif + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + unsigned int tm_sec; /* seconds after the minute - [0,59] */ + unsigned int tm_min; /* minutes after the hour - [0,59] */ + unsigned int tm_hour; /* hours since midnight - [0,23] */ + unsigned int tm_mday; /* day of the month - [1,31] */ + unsigned int tm_mon; /* months since January - [0,11] */ + unsigned int tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in the central dir on this disk */ + uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in the central dir on this disk */ + uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; + ZPOS64_T disk_offset; + uLong size_file_extra_internal; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; + uLong disk_offset; +} unz_file_info; + +/***************************************************************************/ +/* Opening and close a zip file */ + +extern unzFile ZEXPORT unzOpen OF((const char* path)); +extern unzFile ZEXPORT unzOpen64 OF((const void* path)); +/* Open a Zip file. + + path should contain the full pathname (by example, on a Windows XP computer + "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". + return NULL if zipfile cannot be opened or doesn't exist + return unzFile handle if no error + + NOTE: The "64" function take a const void* pointer, because the path is just the value passed to the + open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* does not describe the reality */ + +extern unzFile ZEXPORT unzOpen2 OF((const char* path, zlib_filefunc_def* pzlib_filefunc_def)); +/* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write operations */ +extern unzFile ZEXPORT unzOpen2_64 OF((const void* path, zlib_filefunc64_def* pzlib_filefunc_def)); +/* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write 64-bit operations */ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile, + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + + return UNZ_OK if there is no error */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info* pglobal_info)); +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, unz_global_info64* pglobal_info)); +/* Write info about the ZipFile in the *pglobal_info structure. + + return UNZ_OK if no error */ + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char* comment, uLong comment_size)); +/* Get the global comment string of the ZipFile, in the comment buffer. + + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 */ + +/***************************************************************************/ +/* Reading the content of the current zipfile, you can open it, read data from it, and close it + (you can close it before reading all the file) */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* Open for reading data the current file in the zipfile. + + return UNZ_OK if no error */ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password)); +/* Open for reading data the current file in the zipfile. + password is a crypting password + + return UNZ_OK if no error */ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw)); +/* Same as unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 *method will receive method of compression, *level will receive level of compression + + NOTE: you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL */ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password)); +/* Same as unzOpenCurrentFile, but takes extra parameter password for encrypted files */ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); +/* Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ + +extern int ZEXPORT unzGetCurrentFileInfo + OF((unzFile file, unz_file_info* pfile_info, char* filename, uLong filename_size, void* extrafield, uLong extrafield_size, + char* comment, uLong comment_size)); +extern int ZEXPORT unzGetCurrentFileInfo64 + OF((unzFile file, unz_file_info64* pfile_info, char* filename, uLong filename_size, void* extrafield, uLong extrafield_size, + char* comment, uLong comment_size)); +/* Get Info about the current file + + pfile_info if != NULL, the *pfile_info structure will contain somes info about the current file + filename if != NULL, the file name string will be copied in filename + filename_size is the size of the filename buffer + extrafield if != NULL, the extra field information from the central header will be copied in to + extrafield_size is the size of the extraField buffer + comment if != NULL, the comment string of the file will be copied in to + comment_size is the size of the comment buffer */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); +/* Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf == NULL, it return the size of the local extra field + if buf != NULL, len is the size of the buffer, the extra header is copied in buf. + + return number of bytes copied in buf, or (if <0) the error code */ + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* Close the file in zip opened with unzOpenCurrentFile + + return UNZ_CRCERROR if all the file was read but the CRC is not good */ + +/***************************************************************************/ +/* Browse the directory of the zipfile */ + +typedef int (*unzFileNameComparer)(unzFile file, const char* filename1, const char* filename2); +typedef int (*unzIteratorFunction)(unzFile file); +typedef int (*unzIteratorFunction2)( + unzFile file, unz_file_info64* pfile_info, char* filename, uLong filename_size, void* extrafield, uLong extrafield_size, + char* comment, uLong comment_size); + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* Set the current file of the zipfile to the first file. + + return UNZ_OK if no error */ + +extern int ZEXPORT unzGoToFirstFile2 + OF((unzFile file, unz_file_info64* pfile_info, char* filename, uLong filename_size, void* extrafield, uLong extrafield_size, + char* comment, uLong comment_size)); +/* Set the current file of the zipfile to the first file and retrieves the current info on success. + Not as seek intensive as unzGoToFirstFile + unzGetCurrentFileInfo. + + return UNZ_OK if no error */ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* Set the current file of the zipfile to the next file. + + return UNZ_OK if no error + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */ + +extern int ZEXPORT unzGoToNextFile2 + OF((unzFile file, unz_file_info64* pfile_info, char* filename, uLong filename_size, void* extrafield, uLong extrafield_size, + char* comment, uLong comment_size)); +/* Set the current file of the zipfile to the next file and retrieves the current + info on success. Does less seeking around than unzGotoNextFile + unzGetCurrentFileInfo. + + return UNZ_OK if no error + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */ + +extern int ZEXPORT unzLocateFile OF((unzFile file, const char* filename, unzFileNameComparer filename_compare_func)); +/* Try locate the file szFileName in the zipfile. For custom filename comparison pass in comparison function. + + return UNZ_OK if the file is found (it becomes the current file) + return UNZ_END_OF_LIST_OF_FILE if the file is not found */ + +/***************************************************************************/ +/* Raw access to zip file */ + +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos OF((unzFile file, unz_file_pos* file_pos)); +extern int ZEXPORT unzGoToFilePos OF((unzFile file, unz_file_pos* file_pos)); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64 OF((unzFile file, unz64_file_pos* file_pos)); +extern int ZEXPORT unzGoToFilePos64 OF((unzFile file, const unz64_file_pos* file_pos)); + +extern uLong ZEXPORT unzGetOffset OF((unzFile file)); +extern ZPOS64_T ZEXPORT unzGetOffset64 OF((unzFile file)); +/* Get the current file offset */ + +extern int ZEXPORT unzSetOffset OF((unzFile file, uLong pos)); +extern int ZEXPORT unzSetOffset64 OF((unzFile file, ZPOS64_T pos)); +/* Set the current file offset */ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* return current position in uncompressed data */ + +extern int ZEXPORT unzseek OF((unzFile file, z_off_t offset, int origin)); +extern int ZEXPORT unzseek64 OF((unzFile file, ZPOS64_T offset, int origin)); +/* Seek within the uncompressed data if compression method is storage */ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* return 1 if the end of file was reached, 0 elsewhere */ + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* _UNZ_H */ diff --git a/src/updater.cpp b/src/updater.cpp new file mode 100644 index 0000000..3db8ae3 --- /dev/null +++ b/src/updater.cpp @@ -0,0 +1,266 @@ +#include "config.h" +#include "updater.h" +#include "sfo.h" +#include "fs.h" +#include "net.h" +#include "gui.h" + +#define ITLS_ENSO_APP_ID "SKGTLSE12" + +char updater_message[256]; + +namespace Updater { + static void fpkg_hmac(const uint8_t *data, unsigned int len, uint8_t hmac[16]) + { + SHA1_CTX ctx; + uint8_t sha1[20]; + uint8_t buf[64]; + + sha1_init(&ctx); + sha1_update(&ctx, data, len); + sha1_final(&ctx, sha1); + + memset(buf, 0, 64); + memcpy(&buf[0], &sha1[4], 8); + memcpy(&buf[8], &sha1[4], 8); + memcpy(&buf[16], &sha1[12], 4); + buf[20] = sha1[16]; + buf[21] = sha1[1]; + buf[22] = sha1[2]; + buf[23] = sha1[3]; + memcpy(&buf[24], &buf[16], 8); + + sha1_init(&ctx); + sha1_update(&ctx, buf, 64); + sha1_final(&ctx, sha1); + memcpy(hmac, sha1, 16); + } + + int MakeHeadBin() + { + uint8_t hmac[16]; + uint32_t off; + uint32_t len; + uint32_t out; + + SceIoStat stat; + memset(&stat, 0, sizeof(SceIoStat)); + + if (FS::FileExists(HEAD_BIN)) + return 0; + + // Read param.sfo + const auto sfo = FS::Load(PACKAGE_DIR "/sce_sys/param.sfo"); + + // Get title id + char titleid[12]; + memset(titleid, 0, sizeof(titleid)); + snprintf(titleid, 12, "%s", SFO::GetString(sfo.data(), sfo.size(), "TITLE_ID")); + + // Enforce TITLE_ID format + if (strlen(titleid) != 9) + return -1; + + // Get content id + char contentid[48]; + memset(contentid, 0, sizeof(contentid)); + snprintf(contentid, 48, "%s", SFO::GetString(sfo.data(), sfo.size(), "CONTENT_ID")); + + // Free sfo buffer + sfo.clear(); + + // Allocate head.bin buffer + std::vector head_bin_data = FS::Load(HEAD_BIN_PATH); + uint8_t *head_bin = malloc(head_bin_data.size()); + memcpy(head_bin, head_bin_data.data(), head_bin_data.size()); + + // Write full title id + char full_title_id[48]; + snprintf(full_title_id, sizeof(full_title_id), "EP9000-%s_00-0000000000000000", titleid); + strncpy((char *)&head_bin[0x30], strlen(contentid) > 0 ? contentid : full_title_id, 48); + + // hmac of pkg header + len = ntohl(*(uint32_t *)&head_bin[0xD0]); + fpkg_hmac(&head_bin[0], len, hmac); + memcpy(&head_bin[len], hmac, 16); + + // hmac of pkg info + off = ntohl(*(uint32_t *)&head_bin[0x8]); + len = ntohl(*(uint32_t *)&head_bin[0x10]); + out = ntohl(*(uint32_t *)&head_bin[0xD4]); + fpkg_hmac(&head_bin[off], len-64, hmac); + memcpy(&head_bin[out], hmac, 16); + + // hmac of everything + len = ntohl(*(uint32_t *)&head_bin[0xE8]); + fpkg_hmac(&head_bin[0], len, hmac); + memcpy(&head_bin[len], hmac, 16); + + // Make dir + sceIoMkdir(PACKAGE_DIR "/sce_sys/package", 0777); + + // Write head.bin + FS::Save(HEAD_BIN, head_bin, head_bin_data.size()); + + free(head_bin); + + return 0; + } + + int CheckAppExist(const char *titleid) + { + int res; + int ret; + + ret = scePromoterUtilityCheckExist(titleid, &res); + if (res < 0) + return res; + + return ret >= 0; + } + + int PromoteApp(const char *path) + { + int res; + + sceShellUtilLock(SCE_SHELL_UTIL_LOCK_TYPE_PS_BTN); + + res = scePromoterUtilityPromotePkgWithRif(path, 1); + sceShellUtilUnlock(SCE_SHELL_UTIL_LOCK_TYPE_PS_BTN); + + return res; + } + + int InstallPackage(char *file, char *package_name) + { + int res; + + // Recursively clean up pkg directory + sprintf(updater_message, "Removing temp pkg directory"); + FS::RmRecursive(PACKAGE_DIR); + + sprintf(updater_message, "Extracting vpk package"); + ExtractFile(file, PACKAGE_DIR "/", nullptr); + + // Make head.bin + res = MakeHeadBin(); + if (res < 0) + return res; + + // Promote app + sprintf(updater_message, "Starting to install %s", package_name); + res = PromoteApp(PACKAGE_DIR); + if (res < 0) + { + sprintf(updater_message, "Failed to install %s", package_name); + return res; + } + return 0; + } + + void ExtractFile(char *file, char *dir, std::vector *files_to_extract) + { + unz_global_info global_info; + unz_file_info file_info; + unzFile zipfile = unzOpen(file); + unzGetGlobalInfo(zipfile, &global_info); + unzGoToFirstFile(zipfile); + uint64_t curr_extracted_bytes = 0; + uint64_t curr_file_bytes = 0; + int num_files = global_info.number_entry; + char fname[512]; + char ext_fname[512]; + char read_buffer[8192]; + + for (int zip_idx = 0; zip_idx < num_files; ++zip_idx) + { + unzGetCurrentFileInfo(zipfile, &file_info, fname, 512, NULL, 0, NULL, 0); + sprintf(ext_fname, "%s%s", dir, fname); + const size_t filename_length = strlen(ext_fname); + if (ext_fname[filename_length - 1] != '/' && ( files_to_extract == nullptr || + (files_to_extract != nullptr && std::find(files_to_extract->begin(), files_to_extract->end(), fname) != files_to_extract->end()))) + { + snprintf(updater_message, 255, "Extracting %s", fname); + curr_file_bytes = 0; + unzOpenCurrentFile(zipfile); + FS::MkDirs(ext_fname, true); + FILE *f = fopen(ext_fname, "wb"); + while (curr_file_bytes < file_info.uncompressed_size) + { + int rbytes = unzReadCurrentFile(zipfile, read_buffer, 8192); + if (rbytes > 0) + { + fwrite(read_buffer, 1, rbytes, f); + curr_extracted_bytes += rbytes; + curr_file_bytes += rbytes; + } + } + fclose(f); + unzCloseCurrentFile(zipfile); + } + if ((zip_idx + 1) < num_files) + { + unzGoToNextFile(zipfile); + } + } + unzClose(zipfile); + } + + void StartUpdaterThread() + { + updater_thid = sceKernelCreateThread("updater_thread", (SceKernelThreadEntry)UpdaterThread, 0x10000100, 0x4000, 0, 0, NULL); + if (updater_thid >= 0) + sceKernelStartThread(updater_thid, 0, NULL); + } + + int UpdaterThread(SceSize args, void *argp) + { + int itls_enso_installed = CheckAppExist(ITLS_ENSO_APP_ID); + int vita_updated = 0; + if (itls_enso_installed) + { + } + + if (!itls_enso_installed) + { + sprintf(updater_message, "iTLS-Enso is not installed.\nIt's required to download icons and updates"); + sceKernelDelayThread(4000000); + } + handle_updates = false; + Windows::SetModalMode(false); + return sceKernelExitDeleteThread(0); + } + + void StartInstallerThread() + { + int itls_enso_installed = CheckAppExist(ITLS_ENSO_APP_ID); + + if (!itls_enso_installed) + { + handle_updates = true; + installer_thid = sceKernelCreateThread("installer_thread", (SceKernelThreadEntry)InstallerThread, 0x10000100, 0x4000, 0, 0, NULL); + if (installer_thid >= 0) + sceKernelStartThread(installer_thid, 0, NULL); + } + } + + int InstallerThread(SceSize args, void *argp) + { + sceKernelDelayThread(1500000); + + int itls_enso_installed = CheckAppExist(ITLS_ENSO_APP_ID); + if (itls_enso_installed) + { + } + + ERROR_EXIT: + if (!itls_enso_installed) + { + sprintf(updater_message, "iTLS-Enso is not installed.\nIt's required to download icons and updates"); + sceKernelDelayThread(4000000); + } + handle_updates = false; + Windows::SetModalMode(false); + return sceKernelExitDeleteThread(0); + } +} \ No newline at end of file diff --git a/src/updater.h b/src/updater.h new file mode 100644 index 0000000..854ce82 --- /dev/null +++ b/src/updater.h @@ -0,0 +1,39 @@ +#ifndef __UPDATER_H__ +#define __UPDATER_H__ +#include +#include "zip.h" +#include "unzip.h" +#include "windows.h" + +extern "C" { + #include "sha1.h" +} + +#define ntohl __builtin_bswap32 + +#define HEAD_BIN_PATH "ux0:app/FTPCLIENT/head.bin" +#define PACKAGE_DIR "ux0:data/FTPCLIENT/tmp/pkg" +#define HEAD_BIN PACKAGE_DIR "/sce_sys/package/head.bin" + +typedef struct { + char *file; +} InstallArguments; + +extern char updater_message[]; +static SceUID updater_thid = -1; +static SceUID installer_thid = -1; + +namespace Updater { + int PromoteApp(const char *path); + int CheckAppExist(const char *titleid); + + int MakeHeadBin(); + + int InstallPackage(char *file); + void StartUpdaterThread(); + int UpdaterThread(SceSize args, void *argp); + void ExtractFile(char *file, char *dir, std::vector *files_to_extract); + void StartInstallerThread(); + int InstallerThread(SceSize args, void *argp); +} +#endif diff --git a/src/vitaaudiolib.c b/src/vitaaudiolib.c new file mode 100644 index 0000000..3d78171 --- /dev/null +++ b/src/vitaaudiolib.c @@ -0,0 +1,164 @@ +#include +#include + +#include "vitaaudiolib.h" + +static int audio_ready = 0; +static short vitaAudioSoundBuffer[VITA_NUM_AUDIO_CHANNELS][2][VITA_NUM_AUDIO_SAMPLES][2]; +static VITA_audio_channelinfo vitaAudioStatus[VITA_NUM_AUDIO_CHANNELS]; +static volatile int audio_terminate = 0; + +void vitaAudioSetVolume(int channel, int left, int right) { + vitaAudioStatus[channel].volumeleft = left; + vitaAudioStatus[channel].volumeright = right; +} + +void vitaAudioSetChannelCallback(int channel, vitaAudioCallback_t callback, void *userdata) { + volatile VITA_audio_channelinfo *pci = &vitaAudioStatus[channel]; + + if (callback == 0) + pci->callback = 0; + else + pci->callback = callback; +} + +int vitaAudioOutBlocking(unsigned int channel, unsigned int vol1, unsigned int vol2, const void *buf) { + if (!audio_ready) + return(-1); + + if (channel >= VITA_NUM_AUDIO_CHANNELS) + return(-1); + + if (vol1 > SCE_AUDIO_OUT_MAX_VOL) + vol1 = SCE_AUDIO_OUT_MAX_VOL; + + if (vol2 > SCE_AUDIO_OUT_MAX_VOL) + vol2 = SCE_AUDIO_OUT_MAX_VOL; + + int vol[2] = {vol1, vol2}; + sceAudioOutSetVolume(vitaAudioStatus[channel].handle, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vol); + return sceAudioOutOutput(vitaAudioStatus[channel].handle, buf); +} + +static int vitaAudioChannelThread(unsigned int args, void *argp) { + volatile int bufidx = 0; + + int channel = *(int *) argp; + + while (audio_terminate == 0) { + void *bufptr = &vitaAudioSoundBuffer[channel][bufidx]; + vitaAudioCallback_t callback; + callback = vitaAudioStatus[channel].callback; + + if (callback) + callback(bufptr, VITA_NUM_AUDIO_SAMPLES, vitaAudioStatus[channel].userdata); + else { + unsigned int *ptr = bufptr; + int i; + for (i = 0; i < VITA_NUM_AUDIO_SAMPLES; ++i) + *(ptr++) = 0; + } + + vitaAudioOutBlocking(channel, vitaAudioStatus[channel].volumeleft, vitaAudioStatus[channel].volumeright, bufptr); + bufidx = (bufidx ? 0:1); + } + + sceKernelExitThread(0); + return(0); +} + +int vitaAudioInit(int frequency, SceAudioOutMode mode) { + int i, ret; + int failed = 0; + char str[32]; + + audio_terminate = 0; + audio_ready = 0; + + for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++) { + vitaAudioStatus[i].handle = -1; + vitaAudioStatus[i].threadhandle = -1; + vitaAudioStatus[i].volumeright = SCE_AUDIO_OUT_MAX_VOL; + vitaAudioStatus[i].volumeleft = SCE_AUDIO_OUT_MAX_VOL; + vitaAudioStatus[i].callback = 0; + vitaAudioStatus[i].userdata = 0; + } + + for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++) { + if ((vitaAudioStatus[i].handle = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_BGM, VITA_NUM_AUDIO_SAMPLES, frequency, mode)) < 0) + failed = 1; + } + + if (failed) { + for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++) { + if (vitaAudioStatus[i].handle != -1) + sceAudioOutReleasePort(vitaAudioStatus[i].handle); + + vitaAudioStatus[i].handle = -1; + } + + return 0; + } + + audio_ready = 1; + strcpy(str, "audiot0"); + + for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++) { + str[6]= '0' + i; + vitaAudioStatus[i].threadhandle = sceKernelCreateThread(str, (SceKernelThreadEntry)&vitaAudioChannelThread, 0x40, 0x10000, 0, 0, NULL); + + if (vitaAudioStatus[i].threadhandle < 0) { + vitaAudioStatus[i].threadhandle = -1; + failed = 1; + break; + } + + ret = sceKernelStartThread(vitaAudioStatus[i].threadhandle, sizeof(i), &i); + + if (ret != 0) { + failed = 1; + break; + } + } + + if (failed) { + audio_terminate = 1; + + for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++) { + if (vitaAudioStatus[i].threadhandle != -1) + sceKernelDeleteThread(vitaAudioStatus[i].threadhandle); + + vitaAudioStatus[i].threadhandle = -1; + } + + audio_ready = 0; + return 0; + } + + return 1; +} + +void vitaAudioEndPre(void) { + audio_ready = 0; + audio_terminate = 1; +} + +void vitaAudioEnd(void) { + int i = 0; + audio_ready = 0; + audio_terminate = 1; + + for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++) { + if (vitaAudioStatus[i].threadhandle != -1) + sceKernelDeleteThread(vitaAudioStatus[i].threadhandle); + + vitaAudioStatus[i].threadhandle = -1; + } + + for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++) { + if (vitaAudioStatus[i].handle != -1) { + sceAudioOutReleasePort(vitaAudioStatus[i].handle); + vitaAudioStatus[i].handle = -1; + } + } +} diff --git a/src/vitaaudiolib.h b/src/vitaaudiolib.h new file mode 100644 index 0000000..b22ceff --- /dev/null +++ b/src/vitaaudiolib.h @@ -0,0 +1,37 @@ +#ifndef _ELEVENMPV_AUDIO_LIB_H_ +#define _ELEVENMPV_AUDIO_LIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define VITA_NUM_AUDIO_CHANNELS 1 +#define VITA_NUM_AUDIO_SAMPLES 960 + +typedef void (* vitaAudioCallback_t)(void *stream, unsigned int length, void *userdata); + +typedef struct { + int threadhandle; + int handle; + int volumeleft; + int volumeright; + vitaAudioCallback_t callback; + void *userdata; +} VITA_audio_channelinfo; + +typedef int (* vitaAudioThreadfunc_t)(int args, void *argp); + +void vitaAudioSetVolume(int channel, int left, int right); +void vitaAudioSetChannelCallback(int channel, vitaAudioCallback_t callback, void *userdata); +int vitaAudioOutBlocking(unsigned int channel, unsigned int vol1, unsigned int vol2, const void *buf); +int vitaAudioInit(int frequency, SceAudioOutMode mode); +void vitaAudioEndPre(void); +void vitaAudioEnd(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/windows.cpp b/src/windows.cpp new file mode 100644 index 0000000..ad00ea8 --- /dev/null +++ b/src/windows.cpp @@ -0,0 +1,343 @@ +#include +#include +#include +#include "windows.h" +#include "textures.h" +#include "fs.h" +#include "style.h" +#include "config.h" +#include "ime_dialog.h" +#include "gui.h" +#include "net.h" +#include "ftpclient.h" +#include "updater.h" +#include "actions.h" + +#include "debugnet.h" + +extern "C" { + #include "inifile.h" +} + +static SceCtrlData pad_prev; +bool paused = false; +int view_mode; +static float scroll_direction = 0.0f; +static char cb_style_name[64]; +static char cb_startup_category[10]; +static char cb_category_name[16] = "all"; +static std::vector styles; +static ime_callback_t ime_callback = nullptr; +static ime_callback_t ime_after_update = nullptr; +static ime_callback_t ime_before_update = nullptr; + +static std::vector *ime_multi_field; +static char* ime_single_field; + +bool handle_updates = false; +float previous_right = 0.0f; +float previous_left = 0.0f; +FtpClient *ftpclient; +int64_t bytes_transfered; +int64_t bytes_to_download; +std::vector local_files; +std::vector remote_files; +FsEntry *selected_local_file; +FtpDirEntry *selected_remote_file; +ACTIONS selected_action; +char status_message[1024]; +char local_file_to_select[256]; +char remote_file_to_select[256]; + +namespace Windows { + + static int FtpCallback(int64_t xfered, void* arg) + { + bytes_transfered = xfered; + return 1; + } + + void Init() + { + ftpclient = new FtpClient(); + ftpclient->SetConnmode(ftp_settings.pasv_mode ? FtpClient::pasv : FtpClient::port); + ftpclient->SetCallbackBytes(1); + ftpclient->SetCallbackXferFunction(FtpCallback); + + local_files.clear(); + local_files = FS::ListDir(local_directory); + FS::Sort(local_files); + + sprintf(local_file_to_select, ".."); + sprintf(remote_file_to_select, ".."); + sprintf(status_message, ""); + } + + void HandleLauncherWindowInput() + { + ImGuiIO& io = ImGui::GetIO(); (void)io; + SceCtrlData pad; + + sceCtrlReadBufferPositiveExt2(0, &pad, 1); + + pad_prev = pad; + previous_right = io.NavInputs[ImGuiNavInput_DpadRight]; + previous_left = io.NavInputs[ImGuiNavInput_DpadLeft]; + } + + void SetModalMode(bool modal) + { + paused = modal; + } + + void ConnectionPanel() + { + ImGuiStyle* style = &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + BeginGroupPanel("Connection Settings", ImVec2(945, 100)); + ImGui::SetCursorPosY(ImGui::GetCursorPosY()+3); + char id[256]; + std::string hidden_password = std::string("********"); + + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "Server:"); ImGui::SameLine(); + ImGui::Selectable(ftp_settings.server_ip, false, ImGuiSelectableFlags_DontClosePopups, ImVec2(140, 0)); ImGui::SameLine(); + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "Username:"); ImGui::SameLine(); + sprintf(id, "%s##username", ftp_settings.username); + ImGui::Selectable(id, false, ImGuiSelectableFlags_DontClosePopups, ImVec2(120, 0)); ImGui::SameLine(); + + ImGui::SetCursorPosX(ImGui::GetCursorPosX()+10); + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "Password:"); ImGui::SameLine(); + sprintf(id, "%s##password", hidden_password.c_str()); + ImGui::Selectable(id, false, ImGuiSelectableFlags_DontClosePopups, ImVec2(100, 0)); ImGui::SameLine(); + + ImGui::SetCursorPosX(ImGui::GetCursorPosX()+10); + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "Port:"); ImGui::SameLine(); + sprintf(id, "%d##ServerPort", ftp_settings.server_port); + ImGui::Selectable(id, false, ImGuiSelectableFlags_DontClosePopups, ImVec2(30, 0)); ImGui::SameLine(); + + ImGui::SetCursorPosX(ImGui::GetCursorPosX()+10); + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "Pasv:"); ImGui::SameLine(); + ImGui::Checkbox("##PasvMode", &ftp_settings.pasv_mode); ImGui::SameLine(); + + ImGui::SetCursorPosX(ImGui::GetCursorPosX()+10); + if (ImGui::Button("Connect")) + { + selected_action = CONNECT_FTP; + } + ImGui::Dummy(ImVec2(1,2)); + EndGroupPanel(); + } + + void BrowserPanel() + { + ImGuiStyle* style = &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + BeginGroupPanel("Local", ImVec2(452, 400)); + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "Directory:"); ImGui::SameLine(); + ImGui::Selectable(local_directory, false, ImGuiSelectableFlags_DontClosePopups, ImVec2(360, 0)); + ImGui::BeginChild(ImGui::GetID("Local##ChildWindow"), ImVec2(452,340)); + ImGui::Separator(); + ImGui::Columns(2, "Local##Columns", true); + int i = 0; + for (std::vector::iterator it=local_files.begin(); it!=local_files.end(); ) + { + ImGui::SetColumnWidth(-1,343); + ImGui::PushID(i); + if (ImGui::Selectable(it->name, false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(452, 0))) + { + selected_local_file = &*it; + selected_action = CHANGE_LOCAL_DIRECTORY; + } + ImGui::PopID(); + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) + { + if (strcmp(local_file_to_select, it->name)==0) + { + SetNavFocusHere(); + sprintf(local_file_to_select, ""); + } + } + ImGui::NextColumn(); + ImGui::SetColumnWidth(-1,90); + ImGui::Text(it->display_size); + ImGui::NextColumn(); + ImGui::Separator(); + ++it; + i++; + } + ImGui::Columns(1); + ImGui::EndChild(); + EndGroupPanel(); + ImGui::SameLine(); + + BeginGroupPanel("Remote", ImVec2(452, 400)); + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "Directory:"); ImGui::SameLine(); + ImGui::Selectable(remote_directory, false, ImGuiSelectableFlags_DontClosePopups, ImVec2(360, 0)); + ImGui::BeginChild(ImGui::GetID("Remote##ChildWindow"), ImVec2(452,340)); + ImGui::Separator(); + ImGui::Columns(2, "Remote##Columns", true); + i=99999; + for (std::vector::iterator it=remote_files.begin(); it!=remote_files.end(); ) + { + ImGui::SetColumnWidth(-1,343); + ImGui::PushID(i); + if (ImGui::Selectable(it->name, false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(452, 0))) + { + selected_remote_file = &*it; + selected_action = CHANGE_REMOTE_DIRECTORY; + } + ImGui::PopID(); + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) + { + if (strcmp(remote_file_to_select, it->name)==0) + { + SetNavFocusHere(); + sprintf(remote_file_to_select, ""); + } + } + ImGui::NextColumn(); + ImGui::SetColumnWidth(-1,90); + ImGui::Text(it->display_size); + ImGui::NextColumn(); + ImGui::Separator(); + ++it; + i++; + } + ImGui::Columns(1); + ImGui::EndChild(); + EndGroupPanel(); + } + + void StatusPanel() + { + BeginGroupPanel("Status", ImVec2(945, 100)); + ImVec2 pos = ImGui::GetCursorPos(); + ImGui::Dummy(ImVec2(925,50)); + ImGui::SetCursorPos(pos); + ImGui::PushTextWrapPos(925); + ImGui::Text(status_message); + ImGui::PopTextWrapPos(); + EndGroupPanel(); + } + + void ShowSettingsActionsDialog() + { + + } + + void MainWindow() + { + Windows::SetupWindow(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + + ImGui::SetMouseCursor(ImGuiMouseCursor_None); + + if (ImGui::Begin("Ftp Client", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollbar)) + { + ConnectionPanel(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY()+3); + BrowserPanel(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY()+3); + StatusPanel(); + ShowSettingsActionsDialog(); + } + ImGui::End(); + + switch (selected_action) + { + case CHANGE_LOCAL_DIRECTORY: + Actions::HandleChangeLocalDirectory(selected_local_file); + break; + case CHANGE_REMOTE_DIRECTORY: + Actions::HandleChangeRemoteDirectory(selected_remote_file); + break; + case CONNECT_FTP: + Actions::ConnectFTP(); + break; + default: + break; + } + Windows::EndSetupWindow(); + } + + void HandleImeInput() + { + int ime_result = Dialog::updateImeDialog(); + + if (ime_result == IME_DIALOG_RESULT_FINISHED || ime_result == IME_DIALOG_RESULT_CANCELED) + { + if (ime_result == IME_DIALOG_RESULT_FINISHED) + { + if (ime_before_update != nullptr) + { + ime_before_update(ime_result); + } + + if (ime_callback != nullptr) + { + ime_callback(ime_result); + } + + if (ime_after_update != nullptr) + { + ime_after_update(ime_result); + } + } + + gui_mode = GUI_MODE_BROWSER; + } + } + + void SingleValueImeCallback(int ime_result) + { + if (ime_result == IME_DIALOG_RESULT_FINISHED) + { + char *new_value = (char *)Dialog::getImeDialogInputTextUTF8(); + sprintf(ime_single_field, "%s", new_value); + } + } + + void MultiValueImeCallback(int ime_result) + { + if (ime_result == IME_DIALOG_RESULT_FINISHED) + { + char *new_value = (char *)Dialog::getImeDialogInputTextUTF8(); + char *initial_value = (char *)Dialog::getImeDialogInitialText(); + if (strlen(initial_value) == 0) + { + ime_multi_field->push_back(new_value); + } + else + { + for (int i=0; i < ime_multi_field->size(); i++) + { + if (strcmp((*ime_multi_field)[i].c_str(), initial_value)==0) + { + (*ime_multi_field)[i] = new_value; + } + } + } + + } + } + + void NullAfterValueChangeCallback(int ime_result) {} + + void HandleUpdates() + { + SetModalMode(true); + + ImGui::OpenPopup("Updates"); + ImGui::SetNextWindowPos(ImVec2(300, 200)); + ImGui::SetNextWindowSize(ImVec2(400,90)); + if (ImGui::BeginPopupModal("Updates", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar)) + { + ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(400,140)); + ImGui::Text("%s", updater_message); + ImGui::EndPopup(); + } + } + +} diff --git a/src/windows.h b/src/windows.h new file mode 100644 index 0000000..eeaf8bc --- /dev/null +++ b/src/windows.h @@ -0,0 +1,172 @@ +#ifndef LAUNCHER_WINDOWS_H +#define LAUNCHER_WINDOWS_H + +#define IMGUI_DEFINE_MATH_OPERATORS +#include +#include +#include "fs.h" +#include "ftpclient.h" +#include "actions.h" + +extern int view_mode; +extern bool handle_updates; +extern FtpClient *ftpclient; +extern int64_t bytes_transfered; +extern int64_t bytes_to_download; +extern std::vector local_files; +extern std::vector remote_files; +extern FsEntry *selected_local_file; +extern FtpDirEntry *selected_remote_file; +extern ACTIONS selected_action; +extern char status_message[]; +extern char local_file_to_select[]; +extern char remote_file_to_select[]; + +static ImVector s_GroupPanelLabelStack; + +namespace Windows { + + inline void SetupWindow(void) { + ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiCond_Once); + ImGui::SetNextWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y), ImGuiCond_Once); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + }; + + inline void EndSetupWindow(void) { + ImGui::PopStyleVar(); + }; + + inline void SetNavFocusHere() + { + GImGui->NavId = GImGui->CurrentWindow->DC.LastItemId; + } + + inline void ClearNavFocus() + { + GImGui->NavId = 0; + } + + inline void BeginGroupPanel(const char* name, const ImVec2& size) + { + ImGui::BeginGroup(); + + auto cursorPos = ImGui::GetCursorScreenPos(); + auto itemSpacing = ImGui::GetStyle().ItemSpacing; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); + + auto frameHeight = ImGui::GetFrameHeight(); + ImGui::BeginGroup(); + + ImVec2 effectiveSize = size; + if (size.x < 0.0f) + effectiveSize.x = ImGui::GetContentRegionAvailWidth(); + else + effectiveSize.x = size.x; + ImGui::Dummy(ImVec2(effectiveSize.x, 0.0f)); + + ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f)); + ImGui::SameLine(0.0f, 0.0f); + ImGui::BeginGroup(); + ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f)); + ImGui::SameLine(0.0f, 0.0f); + ImGui::TextUnformatted(name); + auto labelMin = ImGui::GetItemRectMin(); + auto labelMax = ImGui::GetItemRectMax(); + ImGui::SameLine(0.0f, 0.0f); + ImGui::Dummy(ImVec2(0.0, frameHeight + itemSpacing.y)); + ImGui::BeginGroup(); + + ImGui::PopStyleVar(2); + + #if IMGUI_VERSION_NUM >= 17301 + ImGui::GetCurrentWindow()->ContentRegionRect.Max.x -= frameHeight * 0.5f; + ImGui::GetCurrentWindow()->WorkRect.Max.x -= frameHeight * 0.5f; + ImGui::GetCurrentWindow()->InnerRect.Max.x -= frameHeight * 0.5f; + #else + ImGui::GetCurrentWindow()->ContentsRegionRect.Max.x -= frameHeight * 0.5f; + #endif + ImGui::GetCurrentWindow()->Size.x -= frameHeight; + + auto itemWidth = ImGui::CalcItemWidth(); + ImGui::PushItemWidth(ImMax(0.0f, itemWidth - frameHeight)); + + s_GroupPanelLabelStack.push_back(ImRect(labelMin, labelMax)); + } + + inline void EndGroupPanel() + { + ImGui::PopItemWidth(); + + auto itemSpacing = ImGui::GetStyle().ItemSpacing; + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); + + auto frameHeight = ImGui::GetFrameHeight(); + + ImGui::EndGroup(); + ImGui::EndGroup(); + + ImGui::SameLine(0.0f, 0.0f); + ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f)); + ImGui::Dummy(ImVec2(0.0, frameHeight - frameHeight * 0.5f - itemSpacing.y)); + + ImGui::EndGroup(); + + auto itemMin = ImGui::GetItemRectMin(); + auto itemMax = ImGui::GetItemRectMax(); + + auto labelRect = s_GroupPanelLabelStack.back(); + s_GroupPanelLabelStack.pop_back(); + + ImVec2 halfFrame = ImVec2(frameHeight * 0.25f, frameHeight) * 0.5f; + ImRect frameRect = ImRect(itemMin + halfFrame, itemMax - ImVec2(halfFrame.x, 0.0f)); + labelRect.Min.x -= itemSpacing.x; + labelRect.Max.x += itemSpacing.x; + for (int i = 0; i < 4; ++i) + { + switch (i) + { + // left half-plane + case 0: ImGui::PushClipRect(ImVec2(-FLT_MAX, -FLT_MAX), ImVec2(labelRect.Min.x, FLT_MAX), true); break; + // right half-plane + case 1: ImGui::PushClipRect(ImVec2(labelRect.Max.x, -FLT_MAX), ImVec2(FLT_MAX, FLT_MAX), true); break; + // top + case 2: ImGui::PushClipRect(ImVec2(labelRect.Min.x, -FLT_MAX), ImVec2(labelRect.Max.x, labelRect.Min.y), true); break; + // bottom + case 3: ImGui::PushClipRect(ImVec2(labelRect.Min.x, labelRect.Max.y), ImVec2(labelRect.Max.x, FLT_MAX), true); break; + } + + ImGui::GetWindowDrawList()->AddRect( + frameRect.Min, frameRect.Max, + ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Border)), + halfFrame.x); + + ImGui::PopClipRect(); + } + + ImGui::PopStyleVar(2); + + #if IMGUI_VERSION_NUM >= 17301 + ImGui::GetCurrentWindow()->ContentRegionRect.Max.x += frameHeight * 0.5f; + ImGui::GetCurrentWindow()->WorkRect.Max.x += frameHeight * 0.5f; + ImGui::GetCurrentWindow()->InnerRect.Max.x += frameHeight * 0.5f; + #else + ImGui::GetCurrentWindow()->ContentsRegionRect.Max.x += frameHeight * 0.5f; + #endif + ImGui::GetCurrentWindow()->Size.x += frameHeight; + + ImGui::Dummy(ImVec2(0.0f, 0.0f)); + + ImGui::EndGroup(); + } + + void Init(); + void HandleLauncherWindowInput(); + void MainWindow(); + void HandleImeInput(); + void SetModalMode(bool modal); +} + +#endif diff --git a/src/zip.c b/src/zip.c new file mode 100644 index 0000000..bacc0af --- /dev/null +++ b/src/zip.c @@ -0,0 +1,2053 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + Modifications for AES, PKWARE disk spanning + Copyright (C) 2010-2014 Nathan Moinvaziri + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#include "zip.h" + +#include "zlib.h" + +#include +#include +#include +#include + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H +extern int errno; +#else +# include +#endif + +#ifdef HAVE_AES +# define AES_METHOD (99) +# define AES_PWVERIFYSIZE (2) +# define AES_AUTHCODESIZE (10) +# define AES_MAXSALTLENGTH (16) +# define AES_VERSION (0x0001) +# define AES_ENCRYPTIONMODE (0x03) + +# include "aes/aes.h" +# include "aes/entropy.h" +# include "aes/fileenc.h" +# include "aes/prng.h" +#endif + +#ifndef NOCRYPT +# define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +# include "crypt.h" +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#define SIZEDATA_INDATABLOCK (4096 - (4 * 4)) + +#define DISKHEADERMAGIC (0x08074b50) +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x06064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x07064b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ +#define SIZECENTRALHEADERLOCATOR (0x14) /* 20 */ +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + +#ifndef BUFREADCOMMENT +# define BUFREADCOMMENT (0x400) +#endif +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform dependent */ +#endif + +#ifndef Z_BUFSIZE +# define Z_BUFSIZE (64 * 1024) +#endif +#ifndef Z_MAXFILENAMEINZIP +# define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) \ + { \ + if (p) \ + free(p); \ + } +#endif + +/* NOT sure that this work on ALL platform */ +#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif + +const char zip_copyright[] = " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignment */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif +#ifdef HAVE_AES + fcrypt_ctx aes_ctx; + prng_ctx aes_rng[1]; +#endif + int stream_initialised; /* 1 is stream is initialized */ + unsigned int pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T pos_local_header; /* offset of the local header of the file currently writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralextra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralextrafree; /* Extra bytes allocated to the central header but that are not used */ + uLong size_comment; + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method written to file.*/ + int compression_method; /* compression method to use */ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE]; /* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int zip64; /* Add ZIP64 extended information in the extra field */ + uLong number_disk; /* number of current disk used for spanning ZIP */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T total_compressed; + ZPOS64_T total_uncompressed; +#ifndef NOCRYPT + unsigned int keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned int* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structure of the zipfile */ + voidpf filestream_with_CD; /* io structure of the zipfile with the central dir */ + linkedlist_data central_dir; /* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + int append; /* append mode */ + curfile64_info ci; /* info on the file currently writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writting_offset; + ZPOS64_T number_entry; + ZPOS64_T disk_size; /* size of each disk */ + uLong number_disk; /* number of the current disk, used for spanning ZIP */ + uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP */ +#ifndef NO_ADDFILEINEXISTINGZIP + char* globalcomment; +#endif +} zip64_internal; + +/* Allocate a new data block */ +local linkedlist_datablock_internal* allocate_new_datablock OF(()); +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + + ldi = (linkedlist_datablock_internal*)ALLOC(sizeof(linkedlist_datablock_internal)); + + if (ldi != NULL) + { + ldi->next_datablock = NULL; + ldi->filled_in_this_block = 0; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK; + } + return ldi; +} + +/* Free data block in linked list */ +local void free_datablock OF((linkedlist_datablock_internal * ldi)); +local void free_datablock(linkedlist_datablock_internal* ldi) +{ + while (ldi != NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +/* Initialize linked list */ +local void init_linkedlist OF((linkedlist_data * ll)); +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +/* Free entire linked list and all data blocks */ +local void free_linkedlist OF((linkedlist_data * ll)); +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + +/* Add data to linked list data block */ +local int add_data_in_datablock OF((linkedlist_data * ll, const void* buf, uLong len)); +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll == NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len > 0) + { + unsigned int copy_this; + unsigned int i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block == 0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (unsigned int)ldi->avail_in_this_block; + else + copy_this = (unsigned int)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i = 0; i < copy_this; i++) + *(to_copy + i) = *(from_copy + i); + + ldi->filled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this; + len -= copy_this; + } + return ZIP_OK; +} + +local uLong zip64local_TmzDateToDosDate OF((const tm_zip* ptm)); +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + uLong year; +#define zip64local_in_range(min, max, value) ((min) <= (value) && (value) <= (max)) + /* Years supported: + * [00, 79] (assumed to be between 2000 and 2079) + * [80, 207] (assumed to be between 1980 and 2107, typical output of old + software that does 'year-1900' to get a double digit year) + * [1980, 2107] + Due to the date format limitations, only years between 1980 and 2107 can be stored. + */ + if (!(zip64local_in_range(1980, 2107, ptm->tm_year) || zip64local_in_range(0, 207, ptm->tm_year)) + || !zip64local_in_range(0, 11, ptm->tm_mon) || !zip64local_in_range(1, 31, ptm->tm_mday) + || !zip64local_in_range(0, 23, ptm->tm_hour) || !zip64local_in_range(0, 59, ptm->tm_min) + || !zip64local_in_range(0, 59, ptm->tm_sec)) + return 0; +#undef zip64local_in_range + + year = (uLong)ptm->tm_year; + if (year >= 1980) /* range [1980, 2107] */ + year -= 1980; + else if (year >= 80) /* range [80, 99] */ + year -= 80; + else /* range [00, 79] */ + year += 20; + + return (uLong)(((ptm->tm_mday) + (32 * (ptm->tm_mon + 1)) + (512 * year)) << 16) + | ((ptm->tm_sec / 2) + (32 * ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + +/* Inputs a long in LSB order to the given file: nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) */ +local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); +local int zip64local_putValue(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) +{ + unsigned char buf[8]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { + /* Data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE64(*pzlib_filefunc_def, filestream, buf, nbByte) != (uLong)nbByte) + return ZIP_ERRNO; + + return ZIP_OK; +} + +local ZPOS64_T zip64local_getValue_frommemory OF((void* src, int nbByte)); +local ZPOS64_T zip64local_getValue_frommemory(void* src, int nbByte) +{ + ZPOS64_T x = 0; + unsigned char* buf = (unsigned char*)src; + int n; + for (n = 0; n < nbByte; n++) + { + x <<= 8; + x |= buf[nbByte - n - 1]; + } + return x; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory(void* dest, ZPOS64_T x, int nbByte) +{ + unsigned char* buf = (unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { + /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int* pi)); +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int* pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def, filestream, &c, 1); + if (err == 1) + { + *pi = (int)c; + return ZIP_OK; + } + if (ZERROR64(*pzlib_filefunc_def, filestream)) + return ZIP_ERRNO; + return ZIP_EOF; +} + +local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)); +local int zip64local_getShort(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (uLong)i; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong)i) << 8; + + if (err == ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)); +local int zip64local_getLong(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (uLong)i; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong)i) << 8; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong)i) << 16; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong)i) << 24; + + if (err == ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T* pX)); +local int zip64local_getLong64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T* pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (ZPOS64_T)i; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i) << 8; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i) << 16; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i) << 24; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i) << 32; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i) << 40; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i) << 48; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i) << 56; + + if (err == ZIP_OK) + *pX = x; + else + *pX = 0; + + return err; +} + +/* Gets the amount of bytes left to write to the current disk for spanning archives */ +local int zipGetDiskSizeAvailable OF((zipFile file, ZPOS64_T* size_available)); +local int zipGetDiskSizeAvailable(zipFile file, ZPOS64_T* size_available) +{ + zip64_internal* zi; + ZPOS64_T current_disk_size; + + zi = (zip64_internal*)file; + ZSEEK64(zi->z_filefunc, zi->filestream, 0, ZLIB_FILEFUNC_SEEK_END); + current_disk_size = ZTELL64(zi->z_filefunc, zi->filestream); + *size_available = zi->disk_size - current_disk_size; + return ZIP_OK; +} + +/* Goes to a specific disk number for spanning archives */ +local int zipGoToSpecificDisk OF((zipFile file, int number_disk, int open_existing)); +local int zipGoToSpecificDisk(zipFile file, int number_disk, int open_existing) +{ + zip64_internal* zi; + int err = ZIP_OK; + + zi = (zip64_internal*)file; + if (zi->disk_size == 0) + return err; + + if ((zi->filestream != NULL) && (zi->filestream != zi->filestream_with_CD)) + ZCLOSE64(zi->z_filefunc, zi->filestream); + + zi->filestream = ZOPENDISK64( + zi->z_filefunc, zi->filestream_with_CD, number_disk, + (open_existing == 1) ? (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING) + : (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE)); + + if (zi->filestream == NULL) + err = ZIP_ERRNO; + + return err; +} + +/* Goes to the first disk in a spanned archive */ +local int zipGoToFirstDisk OF((zipFile file)); +local int zipGoToFirstDisk(zipFile file) +{ + zip64_internal* zi; + int number_disk_next; + int err = ZIP_OK; + + zi = (zip64_internal*)file; + + if (zi->disk_size == 0) + return err; + number_disk_next = 0; + if (zi->number_disk_with_CD > 0) + number_disk_next = zi->number_disk_with_CD - 1; + err = zipGoToSpecificDisk(file, number_disk_next, (zi->append == APPEND_STATUS_ADDINZIP)); + if ((err == ZIP_ERRNO) && (zi->append == APPEND_STATUS_ADDINZIP)) + err = zipGoToSpecificDisk(file, number_disk_next, 0); + if (err == ZIP_OK) + zi->number_disk = number_disk_next; + ZSEEK64(zi->z_filefunc, zi->filestream, 0, ZLIB_FILEFUNC_SEEK_END); + return err; +} + +/* Goes to the next disk in a spanned archive */ +local int zipGoToNextDisk OF((zipFile file)); +local int zipGoToNextDisk(zipFile file) +{ + zip64_internal* zi; + ZPOS64_T size_available_in_disk; + int err = ZIP_OK; + int number_disk_next; + + zi = (zip64_internal*)file; + + if (zi->disk_size == 0) + return err; + + number_disk_next = zi->number_disk + 1; + + do + { + err = zipGoToSpecificDisk(file, number_disk_next, (zi->append == APPEND_STATUS_ADDINZIP)); + if ((err == ZIP_ERRNO) && (zi->append == APPEND_STATUS_ADDINZIP)) + err = zipGoToSpecificDisk(file, number_disk_next, 0); + if (err != ZIP_OK) + break; + err = zipGetDiskSizeAvailable(file, &size_available_in_disk); + if (err != ZIP_OK) + break; + zi->number_disk = number_disk_next; + zi->number_disk_with_CD = zi->number_disk + 1; + + number_disk_next += 1; + } while (size_available_in_disk <= 0); + + return err; +} + +/* Locate the Central directory of a zipfile (at the end, just before the global comment) */ +local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T file_size; + ZPOS64_T back_read = 4; + ZPOS64_T max_back = 0xffff; /* maximum size of global comment */ + ZPOS64_T pos_found = 0; + uLong read_size; + ZPOS64_T read_pos; + int i; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT + 4); + if (buf == NULL) + return 0; + + if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0) + { + TRYFREE(buf); + return 0; + } + + file_size = ZTELL64(*pzlib_filefunc_def, filestream); + + if (max_back > file_size) + max_back = file_size; + + while (back_read < max_back) + { + if (back_read + BUFREADCOMMENT > max_back) + back_read = max_back; + else + back_read += BUFREADCOMMENT; + + read_pos = file_size - back_read; + read_size = ((BUFREADCOMMENT + 4) < (file_size - read_pos)) ? (BUFREADCOMMENT + 4) : (uLong)(file_size - read_pos); + + if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + break; + if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size) + break; + + for (i = (int)read_size - 3; (i--) > 0;) + if ((*(buf + i)) == (ENDHEADERMAGIC & 0xff) && (*(buf + i + 1)) == (ENDHEADERMAGIC >> 8 & 0xff) + && (*(buf + i + 2)) == (ENDHEADERMAGIC >> 16 & 0xff) && (*(buf + i + 3)) == (ENDHEADERMAGIC >> 24 & 0xff)) + { + pos_found = read_pos + i; + break; + } + + if (pos_found != 0) + break; + } + TRYFREE(buf); + return pos_found; +} + +/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ +local ZPOS64_T zip64local_SearchCentralDir64 + OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, const ZPOS64_T endcentraloffset)); +local ZPOS64_T zip64local_SearchCentralDir64( + const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, const ZPOS64_T endcentraloffset) +{ + ZPOS64_T offset; + uLong uL; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0) + return 0; + + /* Read locator signature */ + if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) + return 0; + if (uL != ZIP64ENDLOCHEADERMAGIC) + return 0; + /* Number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) + return 0; + /* Relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def, filestream, &offset) != ZIP_OK) + return 0; + /* Total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) + return 0; + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def, filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0) + return 0; + /* The signature */ + if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) + return 0; + if (uL != ZIP64ENDHEADERMAGIC) + return 0; + + return offset; +} + +extern zipFile ZEXPORT zipOpen4( + const void* pathname, int append, ZPOS64_T disk_size, const char** globalcomment, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; +#ifndef NO_ADDFILEINEXISTINGZIP + ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T number_entry_CD; /* total number of entries in the central dir */ + ZPOS64_T number_entry; + ZPOS64_T central_pos; + ZPOS64_T size_central_dir_to_read; + uLong uL; + uLong size_comment; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read; +#endif + int err = ZIP_OK; + int mode; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def == NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + if (append == APPEND_STATUS_CREATE) + mode = (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE); + else + mode = (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING); + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, pathname, mode); + if (ziinit.filestream == NULL) + return NULL; + + if (append == APPEND_STATUS_CREATEAFTER) + { + /* Don't support spanning ZIP with APPEND_STATUS_CREATEAFTER */ + if (disk_size > 0) + return NULL; + + ZSEEK64(ziinit.z_filefunc, ziinit.filestream, 0, SEEK_END); + } + + ziinit.filestream_with_CD = ziinit.filestream; + ziinit.append = append; + ziinit.number_disk = 0; + ziinit.number_disk_with_CD = 0; + ziinit.disk_size = disk_size; + ziinit.begin_pos = ZTELL64(ziinit.z_filefunc, ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi == NULL) + { + ZCLOSE64(ziinit.z_filefunc, ziinit.filestream); + return NULL; + } + +#ifndef NO_ADDFILEINEXISTINGZIP + /* Add file in a zipfile */ + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + /* Read and Cache Central Directory Records */ + central_pos = zip64local_SearchCentralDir(&ziinit.z_filefunc, ziinit.filestream); + /* Disable to allow appending to empty ZIP archive (must be standard zip, not zip64) + if (central_pos == 0) + err = ZIP_ERRNO; + */ + + if (err == ZIP_OK) + { + /* Read end of central directory info */ + if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + + /* The signature, already checked */ + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + /* Number of this disk */ + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk) != ZIP_OK) + err = ZIP_ERRNO; + /* Number of the disk with the start of the central directory */ + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk_with_CD) != ZIP_OK) + err = ZIP_ERRNO; + /* Total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + else + number_entry = uL; + /* Total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + else + number_entry_CD = uL; + if (number_entry_CD != number_entry) + err = ZIP_BADZIPFILE; + /* Size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + else + size_central_dir = uL; + /* Offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + else + offset_central_dir = uL; + /* Zipfile global comment length */ + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &size_comment) != ZIP_OK) + err = ZIP_ERRNO; + + if ((err == ZIP_OK) && ((number_entry_CD == 0xffff) || (offset_central_dir == 0xffffffff))) + { + /* Format should be Zip64, as the central directory or file size is too large */ + central_pos = zip64local_SearchCentralDir64(&ziinit.z_filefunc, ziinit.filestream, central_pos); + + if (central_pos) + { + ZPOS64_T sizeEndOfCentralDirectory; + + if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + + /* The signature, already checked */ + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + /* Size of zip64 end of central directory record */ + if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &sizeEndOfCentralDirectory) != ZIP_OK) + err = ZIP_ERRNO; + /* Version made by */ + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + /* Version needed to extract */ + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + /* Number of this disk */ + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk) != ZIP_OK) + err = ZIP_ERRNO; + /* Number of the disk with the start of the central directory */ + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk_with_CD) != ZIP_OK) + err = ZIP_ERRNO; + /* Total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &number_entry) != ZIP_OK) + err = ZIP_ERRNO; + /* Total number of entries in the central directory */ + if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &number_entry_CD) != ZIP_OK) + err = ZIP_ERRNO; + if (number_entry_CD != number_entry) + err = ZIP_BADZIPFILE; + /* Size of the central directory */ + if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &size_central_dir) != ZIP_OK) + err = ZIP_ERRNO; + /* Offset of start of central directory with respect to the starting disk number */ + if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &offset_central_dir) != ZIP_OK) + err = ZIP_ERRNO; + } + else + err = ZIP_BADZIPFILE; + } + } + + if ((err == ZIP_OK) && (central_pos < offset_central_dir + size_central_dir)) + err = ZIP_BADZIPFILE; + + if (err != ZIP_OK) + { + ZCLOSE64(ziinit.z_filefunc, ziinit.filestream); + TRYFREE(zi); + return NULL; + } + + if (size_comment > 0) + { + ziinit.globalcomment = (char*)ALLOC(size_comment + 1); + if (ziinit.globalcomment) + { + size_comment = ZREAD64(ziinit.z_filefunc, ziinit.filestream, ziinit.globalcomment, size_comment); + ziinit.globalcomment[size_comment] = 0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir + size_central_dir); + ziinit.add_position_when_writting_offset = byte_before_the_zipfile; + + /* Store central directory in memory */ + size_central_dir_to_read = size_central_dir; + buf_size = SIZEDATA_INDATABLOCK; + buf_read = (void*)ALLOC(buf_size); + + if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) + != 0) + err = ZIP_ERRNO; + + while ((size_central_dir_to_read > 0) && (err == ZIP_OK)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(ziinit.z_filefunc, ziinit.filestream, buf_read, (uLong)read_this) != read_this) + err = ZIP_ERRNO; + + if (err == ZIP_OK) + err = add_data_in_datablock(&ziinit.central_dir, buf_read, (uLong)read_this); + + size_central_dir_to_read -= read_this; + } + TRYFREE(buf_read); + + ziinit.begin_pos = byte_before_the_zipfile; + ziinit.number_entry = number_entry_CD; + + if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) + != 0) + err = ZIP_ERRNO; + } + + if (globalcomment) + *globalcomment = ziinit.globalcomment; +#endif + + if (err != ZIP_OK) + { +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +#endif + TRYFREE(zi); + return NULL; + } + + *zi = ziinit; + zipGoToFirstDisk((zipFile)zi); + return (zipFile)zi; +} + +extern zipFile ZEXPORT + zipOpen2(const char* pathname, int append, const char** globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def); + return zipOpen4(pathname, append, 0, globalcomment, &zlib_filefunc64_32_def_fill); + } + return zipOpen4(pathname, append, 0, globalcomment, NULL); +} + +extern zipFile ZEXPORT + zipOpen2_64(const void* pathname, int append, const char** globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen4(pathname, append, 0, globalcomment, &zlib_filefunc64_32_def_fill); + } + return zipOpen4(pathname, append, 0, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen3( + const char* pathname, int append, ZPOS64_T disk_size, const char** globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def); + return zipOpen4(pathname, append, disk_size, globalcomment, &zlib_filefunc64_32_def_fill); + } + return zipOpen4(pathname, append, disk_size, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen3_64( + const void* pathname, int append, ZPOS64_T disk_size, const char** globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen4(pathname, append, disk_size, globalcomment, &zlib_filefunc64_32_def_fill); + } + return zipOpen4(pathname, append, disk_size, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen(const char* pathname, int append) +{ + return zipOpen3((const void*)pathname, append, 0, NULL, NULL); +} + +extern zipFile ZEXPORT zipOpen64(const void* pathname, int append) +{ + return zipOpen3(pathname, append, 0, NULL, NULL); +} + +extern int ZEXPORT zipOpenNewFileInZip4_64( + zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, const char* comment, + int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase, int zip64) +{ + zip64_internal* zi; + unsigned int size_filename; + unsigned int size_comment = 0; + unsigned int i; + int err = ZIP_OK; + ZPOS64_T size_available; + ZPOS64_T size_needed; + +#ifdef NOCRYPT + (crcForCrypting); + if (password != NULL) + return ZIP_PARAMERROR; +#endif + + if (file == NULL) + return ZIP_PARAMERROR; + + if ((method != 0) && +#ifdef HAVE_BZIP2 + (method != Z_BZIP2ED) && +#endif + (method != Z_DEFLATED)) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip(file); + if (err != ZIP_OK) + return err; + } + + if (filename == NULL) + filename = "-"; + if (comment != NULL) + size_comment = (unsigned int)strlen(comment); + + size_filename = (unsigned int)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else + zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + zi->ci.method = method; + zi->ci.compression_method = method; + zi->ci.crc32 = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.flag = flagBase; + if ((level == 8) || (level == 9)) + zi->ci.flag |= 2; + if (level == 2) + zi->ci.flag |= 4; + if (level == 1) + zi->ci.flag |= 6; + if (password != NULL) + { + zi->ci.flag |= 1; +#ifdef HAVE_AES + zi->ci.method = AES_METHOD; +#endif + } + + if (zi->disk_size > 0) + { + if ((zi->number_disk == 0) && (zi->number_entry == 0)) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)DISKHEADERMAGIC, 4); + + /* Make sure enough space available on current disk for local header */ + zipGetDiskSizeAvailable((zipFile)zi, &size_available); + size_needed = 30 + size_filename + size_extrafield_local; + if (zi->ci.zip64) + size_needed += 20; +#ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + size_needed += 11; +#endif + if (size_available < size_needed) + zipGoToNextDisk((zipFile)zi); + } + + zi->ci.pos_local_header = ZTELL64(zi->z_filefunc, zi->filestream); + zi->ci.size_comment = size_comment; + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global; + zi->ci.size_centralextra = size_extrafield_global; + zi->ci.size_centralextrafree = 32; /* Extra space reserved for ZIP64 extra info */ +#ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + zi->ci.size_centralextrafree += 11; /* Extra space reserved for AES extra info */ +#endif + zi->ci.central_header = (char*)ALLOC((unsigned int)zi->ci.size_centralheader + zi->ci.size_centralextrafree + size_comment); + zi->ci.number_disk = zi->number_disk; + + /* Write central directory header */ + zip64local_putValue_inmemory(zi->ci.central_header, (uLong)CENTRALHEADERMAGIC, 4); + zip64local_putValue_inmemory(zi->ci.central_header + 4, (uLong)versionMadeBy, 2); + zip64local_putValue_inmemory(zi->ci.central_header + 6, (uLong)20, 2); + zip64local_putValue_inmemory(zi->ci.central_header + 8, (uLong)zi->ci.flag, 2); + zip64local_putValue_inmemory(zi->ci.central_header + 10, (uLong)zi->ci.method, 2); + zip64local_putValue_inmemory(zi->ci.central_header + 12, (uLong)zi->ci.dosDate, 4); + zip64local_putValue_inmemory(zi->ci.central_header + 16, (uLong)0, 4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header + 20, (uLong)0, 4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header + 24, (uLong)0, 4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header + 28, (uLong)size_filename, 2); + zip64local_putValue_inmemory(zi->ci.central_header + 30, (uLong)size_extrafield_global, 2); + zip64local_putValue_inmemory(zi->ci.central_header + 32, (uLong)size_comment, 2); + zip64local_putValue_inmemory(zi->ci.central_header + 34, (uLong)zi->ci.number_disk, 2); /*disk nm start*/ + + if (zipfi == NULL) + zip64local_putValue_inmemory(zi->ci.central_header + 36, (uLong)0, 2); + else + zip64local_putValue_inmemory(zi->ci.central_header + 36, (uLong)zipfi->internal_fa, 2); + if (zipfi == NULL) + zip64local_putValue_inmemory(zi->ci.central_header + 38, (uLong)0, 4); + else + zip64local_putValue_inmemory(zi->ci.central_header + 38, (uLong)zipfi->external_fa, 4); + if (zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header + 42, (uLong)0xffffffff, 4); + else + zip64local_putValue_inmemory( + zi->ci.central_header + 42, (uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset, 4); + + for (i = 0; i < size_filename; i++) + zi->ci.central_header[SIZECENTRALHEADER + i] = filename[i]; + for (i = 0; i < size_extrafield_global; i++) + zi->ci.central_header[SIZECENTRALHEADER + size_filename + i] = ((const char*)extrafield_global)[i]; + /* Store comment at the end for later repositioning */ + for (i = 0; i < size_comment; i++) + zi->ci.central_header[zi->ci.size_centralheader + zi->ci.size_centralextrafree + i] = comment[i]; + + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + zi->ci.zip64 = zip64; + zi->ci.total_compressed = 0; + zi->ci.total_uncompressed = 0; + zi->ci.pos_zip64extrainfo = 0; + + /* Write the local header */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)LOCALHEADERMAGIC, 4); + + if (err == ZIP_OK) + { + if (zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)45, 2); /* version needed to extract */ + else + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)20, 2); /* version needed to extract */ + } + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.flag, 2); + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.method, 2); + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.dosDate, 4); + + /* CRC & compressed size & uncompressed size will be filled in later and rewritten later */ + + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); /* crc 32, unknown */ + if (err == ZIP_OK) + { + if (zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xFFFFFFFF, 4); /* compressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); /* compressed size, unknown */ + } + if (err == ZIP_OK) + { + if (zi->ci.zip64) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xFFFFFFFF, 4); + else /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); + } + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_filename, 2); + if (err == ZIP_OK) + { + ZPOS64_T size_extrafield = size_extrafield_local; + if (zi->ci.zip64) + size_extrafield += 20; +#ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + size_extrafield += 11; +#endif + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_extrafield, 2); + } + if ((err == ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, filename, size_filename) != size_filename) + err = ZIP_ERRNO; + } + if ((err == ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + /* Write the Zip64 extended info */ + if ((err == ZIP_OK) && (zi->ci.zip64)) + { + short headerid = 1; + short datasize = 16; + ZPOS64_T compressed_size = 0; + ZPOS64_T uncompressed_size = 0; + + /* Remember position of Zip64 extended info for the local file header. + (needed when we update size after done with file) */ + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc, zi->filestream); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)headerid, 2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)datasize, 2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)uncompressed_size, 8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)compressed_size, 8); + } +#ifdef HAVE_AES + /* Write the AES extended info */ + if ((err == ZIP_OK) && (zi->ci.method == AES_METHOD)) + { + int headerid = 0x9901; + short datasize = 7; + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, headerid, 2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, datasize, 2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, AES_VERSION, 2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 'A', 1); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 'E', 1); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, AES_ENCRYPTIONMODE, 1); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->ci.compression_method, 2); + } +#endif + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (unsigned int)0; + zi->ci.bstream.avail_out = (unsigned int)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + zi->ci.stream.avail_in = (unsigned int)0; + zi->ci.stream.avail_out = (unsigned int)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + + if ((err == ZIP_OK) && (!zi->ci.raw)) + { + if (method == Z_DEFLATED) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)zi; + + if (windowBits > 0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + + if (err == Z_OK) + zi->ci.stream_initialised = Z_DEFLATED; + } + else if (method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0, 35); + if (err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + } + +#ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err == Z_OK) && ((zi->ci.flag & 1) != 0)) + { +# ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + { + unsigned char passverify[AES_PWVERIFYSIZE]; + unsigned char saltvalue[AES_MAXSALTLENGTH]; + unsigned int saltlength; + + if ((AES_ENCRYPTIONMODE < 1) || (AES_ENCRYPTIONMODE > 3)) + return Z_ERRNO; + + saltlength = SALT_LENGTH(AES_ENCRYPTIONMODE); + + prng_init(entropy_fun, zi->ci.aes_rng); + prng_rand(saltvalue, saltlength, zi->ci.aes_rng); + prng_end(zi->ci.aes_rng); + + fcrypt_init(AES_ENCRYPTIONMODE, password, strlen(password), saltvalue, passverify, &zi->ci.aes_ctx); + + if (ZWRITE64(zi->z_filefunc, zi->filestream, saltvalue, saltlength) != saltlength) + err = ZIP_ERRNO; + if (ZWRITE64(zi->z_filefunc, zi->filestream, passverify, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE) + err = ZIP_ERRNO; + + zi->ci.crypt_header_size = saltlength + AES_PWVERIFYSIZE + AES_AUTHCODESIZE; + } + else +# endif + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + + zi->ci.pcrc_32_tab = (const unsigned int*)get_crc_table(); + /*init_keys(password, zi->ci.keys, zi->ci.pcrc_32_tab);*/ + + sizeHead = crypthead(password, bufHead, RAND_HEAD_LEN, zi->ci.keys, zi->ci.pcrc_32_tab, crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE64(zi->z_filefunc, zi->filestream, bufHead, sizeHead) != sizeHead) + err = ZIP_ERRNO; + } + } +#endif + + if (err == Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip4( + zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, const char* comment, + int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase) +{ + return zipOpenNewFileInZip4_64( + file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, + method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3( + zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, const char* comment, + int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting) +{ + return zipOpenNewFileInZip4_64( + file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, + method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64( + zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, const char* comment, + int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, + int zip64) +{ + return zipOpenNewFileInZip4_64( + file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, + method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2( + zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, const char* comment, + int method, int level, int raw) +{ + return zipOpenNewFileInZip4_64( + file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, + method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64( + zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, const char* comment, + int method, int level, int raw, int zip64) +{ + return zipOpenNewFileInZip4_64( + file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, + method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64( + zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, const char* comment, + int method, int level, int zip64) +{ + return zipOpenNewFileInZip4_64( + file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, + method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip( + zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, const char* comment, + int method, int level) +{ + return zipOpenNewFileInZip4_64( + file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, + method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); +} + +/* Flushes the write buffer to disk */ +local int zip64FlushWriteBuffer OF((zip64_internal * zi)); +local int zip64FlushWriteBuffer(zip64_internal* zi) +{ + int err = ZIP_OK; + unsigned int written = 0; + unsigned int total_written = 0; + unsigned int write = 0; + unsigned int max_write = 0; + ZPOS64_T size_available = 0; + + if ((zi->ci.flag & 1) != 0) + { +#ifndef NOCRYPT +# ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + { + fcrypt_encrypt(zi->ci.buffered_data, zi->ci.pos_in_buffered_data, &zi->ci.aes_ctx); + } + else +# endif + { + unsigned int i; + int t; + for (i = 0; i < zi->ci.pos_in_buffered_data; i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i], t); + } +#endif + } + + write = zi->ci.pos_in_buffered_data; + + do + { + max_write = write; + + if (zi->disk_size > 0) + { + err = zipGetDiskSizeAvailable((zipFile)zi, &size_available); + if (err != ZIP_OK) + return err; + + if (size_available == 0) + { + err = zipGoToNextDisk((zipFile)zi); + if (err != ZIP_OK) + return err; + } + + if (size_available < (ZPOS64_T)max_write) + max_write = (unsigned int)size_available; + } + + written = ZWRITE64(zi->z_filefunc, zi->filestream, zi->ci.buffered_data + total_written, max_write); + + if (ZERROR64(zi->z_filefunc, zi->filestream)) + { + err = ZIP_ERRNO; + break; + } + + total_written += written; + write -= written; + } while (write > 0); + + zi->ci.total_compressed += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if (zi->ci.compression_method == Z_BZIP2ED) + { + zi->ci.total_uncompressed += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.total_uncompressed += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip(zipFile file, const void* buf, unsigned int len) +{ + zip64_internal* zi; + int err = ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32, buf, (unsigned int)len); + +#ifdef HAVE_BZIP2 + if ((zi->ci.compression_method == Z_BZIP2ED) && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err == BZ_RUN_OK) && (zi->ci.bstream.avail_in > 0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (unsigned int)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + else + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; + uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + + err = BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (unsigned int)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo); + } + } + + if (err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err == ZIP_OK) && (zi->ci.stream.avail_in > 0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (unsigned int)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + if (err != ZIP_OK) + break; + + if ((zi->ci.compression_method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong total_out_before = zi->ci.stream.total_out; + err = deflate(&zi->ci.stream, Z_NO_FLUSH); + zi->ci.pos_in_buffered_data += (unsigned int)(zi->ci.stream.total_out - total_out_before); + } + else + { + unsigned int copy_this, i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + + for (i = 0; i < copy_this; i++) + *(((char*)zi->ci.stream.next_out) + i) = *(((const char*)zi->ci.stream.next_in) + i); + + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out -= copy_this; + zi->ci.stream.next_in += copy_this; + zi->ci.stream.next_out += copy_this; + zi->ci.stream.total_in += copy_this; + zi->ci.stream.total_out += copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64(file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + uLong i = 0; + short datasize = 0; + int err = ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if (!zi->ci.raw) + { + if (zi->ci.compression_method == Z_DEFLATED) + { + while (err == ZIP_OK) + { + uLong total_out_before; + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (unsigned int)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + total_out_before = zi->ci.stream.total_out; + err = deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (unsigned int)(zi->ci.stream.total_out - total_out_before); + } + } + else if (zi->ci.compression_method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err == BZ_FINISH_OK) + { + uLong total_out_before; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (unsigned int)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + total_out_before = zi->ci.bstream.total_out_lo32; + err = BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if (err == BZ_STREAM_END) + err = Z_STREAM_END; + zi->ci.pos_in_buffered_data += (unsigned int)(zi->ci.bstream.total_out_lo32 - total_out_before); + } + + if (err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + } + + if (err == Z_STREAM_END) + err = ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data > 0) && (err == ZIP_OK)) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + } + +#ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + { + unsigned char authcode[AES_AUTHCODESIZE]; + + fcrypt_end(authcode, &zi->ci.aes_ctx); + + if (ZWRITE64(zi->z_filefunc, zi->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE) + err = ZIP_ERRNO; + } +#endif + + if (!zi->ci.raw) + { + if (zi->ci.compression_method == Z_DEFLATED) + { + int tmp_err = deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } +#ifdef HAVE_BZIP2 + else if (zi->ci.compression_method == Z_BZIP2ED) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err == ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.total_uncompressed; + } + + compressed_size = zi->ci.total_compressed; +#ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +#endif + + /* Update current item crc and sizes */ + if (compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + /* Do not change "version made by" upper byte since it might have been set by the user */ + uLong versionMadeBy = (uLong)zip64local_getValue_frommemory(zi->ci.central_header + 4, 2); /* version made by */ + if ((versionMadeBy & 0xff) < 45) + zip64local_putValue_inmemory( + zi->ci.central_header + 4, (uLong)((versionMadeBy & 0xff00) | (uLong)45), 2); /* version made by */ + zip64local_putValue_inmemory(zi->ci.central_header + 6, (uLong)45, 2); /* version needed */ + } + zip64local_putValue_inmemory(zi->ci.central_header + 16, crc32, 4); /* crc */ + if (compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header + 20, invalidValue, 4); /* compr size */ + else + zip64local_putValue_inmemory(zi->ci.central_header + 20, compressed_size, 4); /* compr size */ + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header + 36, (uLong)Z_ASCII, 2); /* internal file attrib */ + if (uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header + 24, invalidValue, 4); /* uncompr size */ + else + zip64local_putValue_inmemory(zi->ci.central_header + 24, uncompressed_size, 4); /* uncompr size */ + + /* Add ZIP64 extra info field for uncompressed size */ + if (uncompressed_size >= 0xffffffff) + datasize += 8; + /* Add ZIP64 extra info field for compressed size */ + if (compressed_size >= 0xffffffff) + datasize += 8; + /* Add ZIP64 extra info field for relative offset to local file header of current file */ + if (zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + /* Add Extra Information Header for 'ZIP64 information' */ + if (datasize > 0) + { + char* p = zi->ci.central_header + zi->ci.size_centralheader; + + if ((uLong)(datasize + 4) > zi->ci.size_centralextrafree) + return ZIP_BADZIPFILE; + + zip64local_putValue_inmemory(p, 0x0001, 2); + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); + p += 2; + + if (uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + if (compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + if (zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); + p += 8; + } + + zi->ci.size_centralextrafree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + zi->ci.size_centralextra += datasize + 4; + + zip64local_putValue_inmemory(zi->ci.central_header + 30, (uLong)zi->ci.size_centralextra, 2); + } + +#ifdef HAVE_AES + /* Write the AES extended info */ + if (zi->ci.method == AES_METHOD) + { + char* p = zi->ci.central_header + zi->ci.size_centralheader; + + datasize = 7; + + if ((uLong)(datasize + 4) > zi->ci.size_centralextrafree) + return ZIP_BADZIPFILE; + + zip64local_putValue_inmemory(p, 0x9901, 2); + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); + p += 2; + zip64local_putValue_inmemory(p, AES_VERSION, 2); + p += 2; + zip64local_putValue_inmemory(p, 'A', 1); + p += 1; + zip64local_putValue_inmemory(p, 'E', 1); + p += 1; + zip64local_putValue_inmemory(p, AES_ENCRYPTIONMODE, 1); + p += 1; + zip64local_putValue_inmemory(p, zi->ci.compression_method, 2); + p += 2; + + zi->ci.size_centralextrafree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + zi->ci.size_centralextra += datasize + 4; + + zip64local_putValue_inmemory(zi->ci.central_header + 30, (uLong)zi->ci.size_centralextra, 2); + } +#endif + /* Restore comment to correct position */ + for (i = 0; i < zi->ci.size_comment; i++) + zi->ci.central_header[zi->ci.size_centralheader + i] = zi->ci.central_header + [zi->ci.size_centralheader + zi->ci.size_centralextrafree + + i]; + zi->ci.size_centralheader += zi->ci.size_comment; + + if (err == ZIP_OK) + err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); + + free(zi->ci.central_header); + + if (err == ZIP_OK) + { + /* Update the LocalFileHeader with the new values. */ + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); + uLong cur_number_disk = zi->number_disk; + + /* Local file header is stored on previous disk, switch to make edits */ + if (zi->ci.number_disk != cur_number_disk) + err = zipGoToSpecificDisk(file, zi->ci.number_disk, 1); + + if (ZSEEK64(zi->z_filefunc, zi->filestream, zi->ci.pos_local_header + 14, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, crc32, 4); /* crc 32, unknown */ + + if (uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff) + { + if (zi->ci.pos_zip64extrainfo > 0) + { + /* Update the size in the ZIP64 extended field. */ + if (ZSEEK64(zi->z_filefunc, zi->filestream, zi->ci.pos_zip64extrainfo + 4, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + + if (err == ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + if (err == ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + else + err = ZIP_BADZIPFILE; /* Caller passed zip64 = 0, so no room for zip64 info -> fatal */ + } + else + { + if (err == ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 4); + if (err == ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 4); + } + + /* Now switch back again to the disk we were on before */ + if (zi->ci.number_disk != cur_number_disk) + err = zipGoToSpecificDisk(file, cur_number_disk, 1); + + if (ZSEEK64(zi->z_filefunc, zi->filestream, cur_pos_inzip, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + } + + zi->number_entry++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip(zipFile file) +{ + return zipCloseFileInZipRaw(file, 0, 0); +} + +extern int ZEXPORT zipClose(zipFile file, const char* global_comment) +{ + return zipClose_64(file, global_comment); +} + +extern int ZEXPORT zipClose_64(zipFile file, const char* global_comment) +{ + return zipClose2_64(file, global_comment, VERSIONMADEBY); +} + +extern int ZEXPORT zipClose2_64(zipFile file, const char* global_comment, uLong versionMadeBy) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + unsigned int size_global_comment = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos = 0; + uLong write = 0; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + err = zipCloseFileInZip(file); + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment == NULL) + global_comment = zi->globalcomment; +#endif + + if (zi->filestream != zi->filestream_with_CD) + { + if (ZCLOSE64(zi->z_filefunc, zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + if (zi->disk_size > 0) + zi->number_disk_with_CD = zi->number_disk + 1; + zi->filestream = zi->filestream_with_CD; + } + + centraldir_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); + + if (err == ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block; + while (ldi != NULL) + { + if ((err == ZIP_OK) && (ldi->filled_in_this_block > 0)) + { + write = ZWRITE64(zi->z_filefunc, zi->filestream, ldi->data, ldi->filled_in_this_block); + if (write != ldi->filled_in_this_block) + err = ZIP_ERRNO; + } + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + + free_linkedlist(&(zi->central_dir)); + + pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + + /* Write the ZIP64 central directory header */ + if (pos >= 0xffffffff || zi->number_entry > 0xffff) + { + ZPOS64_T zip64eocd_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); + uLong zip64datasize = 44; + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ZIP64ENDHEADERMAGIC, 4); + + /* Size of this 'zip64 end of central directory' */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)zip64datasize, 8); + /* Version made by */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)versionMadeBy, 2); + /* version needed */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)45, 2); + /* Number of this disk */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); + /* Number of the disk with the start of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); + /* Total number of entries in the central dir on this disk */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + /* Total number of entries in the central dir */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + /* Size of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)size_centraldir, 8); + + if (err == ZIP_OK) + { + /* Offset of start of central directory with respect to the starting disk number */ + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)pos, 8); + } + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ZIP64ENDLOCHEADERMAGIC, 4); + + /* Number of the disk with the start of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); + /* Relative offset to the Zip64EndOfCentralDirectory */ + if (err == ZIP_OK) + { + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, pos, 8); + } + /* Number of the disk with the start of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD + 1, 4); + } + + /* Write the central directory header */ + + /* Signature */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ENDHEADERMAGIC, 4); + /* Number of this disk */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 2); + /* Number of the disk with the start of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 2); + /* Total number of entries in the central dir on this disk */ + if (err == ZIP_OK) + { + if (zi->number_entry >= 0xffff) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffff, 2); /* use value in ZIP64 record */ + else + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_entry, 2); + } + /* Total number of entries in the central dir */ + if (err == ZIP_OK) + { + if (zi->number_entry >= 0xffff) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffff, 2); /* use value in ZIP64 record */ + else + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_entry, 2); + } + /* Size of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_centraldir, 4); + /* Offset of start of central directory with respect to the starting disk number */ + if (err == ZIP_OK) + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if (pos >= 0xffffffff) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffffffff, 4); + else + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)pos, 4); + } + + /* Write global comment */ + + if (global_comment != NULL) + size_global_comment = (unsigned int)strlen(global_comment); + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_global_comment, 2); + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + + if ((ZCLOSE64(zi->z_filefunc, zi->filestream) != 0) && (err == ZIP_OK)) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} diff --git a/src/zip.h b/src/zip.h new file mode 100644 index 0000000..b528aa9 --- /dev/null +++ b/src/zip.h @@ -0,0 +1,213 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef _ZIP_H +#define _ZIP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +# include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +# include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +# include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ +{ + int unused; +} zipFile__; +typedef zipFile__* zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + unsigned int tm_sec; /* seconds after the minute - [0,59] */ + unsigned int tm_min; /* minutes after the hour - [0,59] */ + unsigned int tm_hour; /* hours since midnight - [0,23] */ + unsigned int tm_mday; /* day of the month - [1,31] */ + unsigned int tm_mon; /* months since January - [0,11] */ + unsigned int tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +/***************************************************************************/ +/* Writing a zip file */ + +extern zipFile ZEXPORT zipOpen OF((const char* pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void* pathname, int append)); +/* Create a zipfile. + + pathname should contain the full pathname (by example, on a Windows XP computer + "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". + + return NULL if zipfile cannot be opened + return zipFile handle if no error + + If the file pathname exist and append == APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. (useful if the file contain a self extractor code) + If the file pathname exist and append == APPEND_STATUS_ADDINZIP, we will add files in existing + zip (be sure you don't add file that doesn't exist) + + NOTE: There is no delete function into a zipfile. If you want delete file into a zipfile, + you must open a zipfile, and create another. Of course, you can use RAW reading and writing to copy + the file you did not want delete. */ + +extern zipFile ZEXPORT zipOpen2 + OF((const char* pathname, int append, const char** globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 + OF((const void* pathname, int append, const char** globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen3 OF( + (const char* pathname, int append, ZPOS64_T disk_size, const char** globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); +/* Same as zipOpen2 but allows specification of spanned zip size */ + +extern zipFile ZEXPORT zipOpen3_64 OF(( + const void* pathname, int append, ZPOS64_T disk_size, const char** globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip + OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, + const char* comment, int method, int level)); +/* Open a file in the ZIP for writing. + + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + extrafield_local buffer to store the local header extra field data, can be NULL + size_extrafield_local size of extrafield_local buffer + extrafield_global buffer to store the global header extra field data, can be NULL + size_extrafield_global size of extrafield_local buffer + comment buffer for comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. */ + +extern int ZEXPORT zipOpenNewFileInZip64 + OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, + const char* comment, int method, int level, int zip64)); +/* Same as zipOpenNewFileInZip with zip64 support */ + +extern int ZEXPORT zipOpenNewFileInZip2 + OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, + const char* comment, int method, int level, int raw)); +/* Same as zipOpenNewFileInZip, except if raw=1, we write raw file */ + +extern int ZEXPORT zipOpenNewFileInZip2_64 + OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, + const char* comment, int method, int level, int raw, int zip64)); +/* Same as zipOpenNewFileInZip3 with zip64 support */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF(( + zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, const char* comment, + int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting)); +/* Same as zipOpenNewFileInZip2, except + windowBits, memLevel, strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) */ + +extern int ZEXPORT zipOpenNewFileInZip3_64 + OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, + const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, + uLong crcForCrypting, int zip64)); +/* Same as zipOpenNewFileInZip3 with zip64 support */ + +extern int ZEXPORT zipOpenNewFileInZip4 + OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, + const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, + uLong crcForCrypting, uLong versionMadeBy, uLong flagBase)); +/* Same as zipOpenNewFileInZip3 except versionMadeBy & flag fields */ + +extern int ZEXPORT zipOpenNewFileInZip4_64 + OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, + unsigned int size_extrafield_local, const void* extrafield_global, unsigned int size_extrafield_global, + const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, + uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64)); +/* Same as zipOpenNewFileInZip4 with zip64 support */ + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, const void* buf, unsigned len)); +/* Write data in the zipfile */ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* Close the current file in the zipfile */ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, uLong uncompressed_size, uLong crc32)); +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, ZPOS64_T uncompressed_size, uLong crc32)); +/* Close the current file in the zipfile, for file opened with parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size */ + +extern int ZEXPORT zipClose OF((zipFile file, const char* global_comment)); +/* Close the zipfile */ + +extern int ZEXPORT zipClose_64 OF((zipFile file, const char* global_comment)); + +extern int ZEXPORT zipClose2_64 OF((zipFile file, const char* global_comment, uLong versionMadeBy)); +/* Same as zipClose_64 except versionMadeBy field */ + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* _ZIP_H */