From 253067c782955380bbf66ac0475dc954375b1ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 17 Aug 2013 13:40:51 +0200 Subject: Move all the things (YES. Move them.) Also, implemented some basic modlist logic, to be wired up. --- CMakeLists.txt | 128 +- backend/BaseInstance.cpp | 181 --- backend/BaseInstance.h | 143 -- backend/BaseInstance_p.h | 14 - backend/BaseUpdate.cpp | 13 - backend/BaseUpdate.h | 50 - backend/CMakeLists.txt | 120 -- backend/IconListModel.cpp | 163 -- backend/IconListModel.h | 33 - backend/InstanceFactory.cpp | 113 -- backend/InstanceFactory.h | 81 - backend/InstanceVersion.h | 69 - backend/LegacyForge.cpp | 57 - backend/LegacyForge.h | 25 - backend/LegacyInstance.cpp | 229 --- backend/LegacyInstance.h | 85 - backend/LegacyInstance_p.h | 10 - backend/LegacyUpdate.cpp | 381 ----- backend/LegacyUpdate.h | 68 - backend/MinecraftProcess.cpp | 169 -- backend/MinecraftProcess.h | 88 - backend/MinecraftVersion.h | 78 - backend/Mod.cpp | 264 --- backend/Mod.h | 69 - backend/ModList.cpp | 418 ----- backend/ModList.h | 75 - backend/NostalgiaInstance.cpp | 12 - backend/NostalgiaInstance.h | 10 - backend/OneSixAssets.cpp | 162 -- backend/OneSixAssets.h | 22 - backend/OneSixInstance.cpp | 211 --- backend/OneSixInstance.h | 32 - backend/OneSixInstance_p.h | 9 - backend/OneSixUpdate.cpp | 169 -- backend/OneSixUpdate.h | 55 - backend/OneSixVersion.cpp | 132 -- backend/OneSixVersion.h | 212 --- backend/VersionFactory.cpp | 195 --- backend/VersionFactory.h | 24 - backend/libmmc_config.h | 24 - backend/lists/InstVersionList.cpp | 129 -- backend/lists/InstVersionList.h | 122 -- backend/lists/InstanceList.cpp | 232 --- backend/lists/InstanceList.h | 92 -- backend/lists/LwjglVersionList.cpp | 206 --- backend/lists/LwjglVersionList.h | 119 -- backend/lists/MinecraftVersionList.cpp | 300 ---- backend/lists/MinecraftVersionList.h | 84 - backend/net/DownloadJob.cpp | 138 -- backend/net/DownloadJob.h | 51 - backend/net/JobQueue.h | 180 -- backend/net/NetWorker.cpp | 12 - backend/net/NetWorker.h | 20 - backend/tasks/LoginTask.cpp | 111 -- backend/tasks/LoginTask.h | 59 - backend/tasks/Task.cpp | 85 - backend/tasks/Task.h | 67 - depends/classparser/CMakeLists.txt | 41 + depends/classparser/include/classparser_config.h | 23 + depends/classparser/include/javautils.h | 29 + depends/classparser/src/annotations.cpp | 83 + depends/classparser/src/annotations.h | 252 +++ depends/classparser/src/classfile.h | 153 ++ depends/classparser/src/constants.h | 212 +++ depends/classparser/src/errors.h | 6 + depends/classparser/src/javaendian.h | 62 + depends/classparser/src/javautils.cpp | 81 + depends/classparser/src/membuffer.h | 64 + depends/groupview/CMakeLists.txt | 41 + .../include/categorizedsortfilterproxymodel.h | 175 ++ depends/groupview/include/categorizedview.h | 332 ++++ depends/groupview/include/categorydrawer.h | 179 ++ depends/groupview/include/groupview_config.h | 27 + .../src/categorizedsortfilterproxymodel.cpp | 168 ++ .../src/categorizedsortfilterproxymodel_p.h | 48 + depends/groupview/src/categorizedview.cpp | 1713 ++++++++++++++++++++ depends/groupview/src/categorizedview_p.h | 159 ++ depends/groupview/src/categorydrawer.cpp | 231 +++ depends/launcher/CMakeLists.txt | 23 + depends/launcher/MCFrame.java | 123 ++ depends/launcher/MultiMCLauncher.java | 331 ++++ depends/launcher/UseJava.cmake | 881 ++++++++++ depends/launcher/UseJavaClassFilelist.cmake | 52 + depends/launcher/UseJavaSymlinks.cmake | 32 + depends/launcher/net/minecraft/Launcher.java | 154 ++ .../org/simplericity/macify/eawt/Application.java | 176 ++ .../macify/eawt/ApplicationAdapter.java | 48 + .../simplericity/macify/eawt/ApplicationEvent.java | 25 + .../macify/eawt/ApplicationListener.java | 27 + .../macify/eawt/DefaultApplication.java | 418 +++++ depends/patchlib/CMakeLists.txt | 14 + depends/patchlib/LICENSE-bzip2 | 42 + depends/patchlib/blocksort.c | 1095 +++++++++++++ depends/patchlib/bspatch.c | 303 ++++ depends/patchlib/bspatch.h | 27 + depends/patchlib/bzlib.c | 1579 ++++++++++++++++++ depends/patchlib/bzlib.h | 283 ++++ depends/patchlib/bzlib_private.h | 510 ++++++ depends/patchlib/compress.c | 672 ++++++++ depends/patchlib/crctable.c | 104 ++ depends/patchlib/decompress.c | 646 ++++++++ depends/patchlib/huffman.c | 205 +++ depends/patchlib/randtable.c | 84 + depends/quazip/CMakeLists.txt | 28 + depends/quazip/JlCompress.cpp | 516 ++++++ depends/quazip/JlCompress.h | 123 ++ depends/quazip/crypt.h | 135 ++ depends/quazip/ioapi.h | 77 + depends/quazip/qioapi.cpp | 146 ++ depends/quazip/quaadler32.cpp | 28 + depends/quazip/quaadler32.h | 29 + depends/quazip/quachecksum32.h | 54 + depends/quazip/quacrc32.cpp | 28 + depends/quazip/quacrc32.h | 26 + depends/quazip/quagzipfile.cpp | 141 ++ depends/quazip/quagzipfile.h | 35 + depends/quazip/quaziodevice.cpp | 283 ++++ depends/quazip/quaziodevice.h | 27 + depends/quazip/quazip.cpp | 554 +++++++ depends/quazip/quazip.h | 411 +++++ depends/quazip/quazip_global.h | 55 + depends/quazip/quazipdir.cpp | 507 ++++++ depends/quazip/quazipdir.h | 171 ++ depends/quazip/quazipfile.cpp | 488 ++++++ depends/quazip/quazipfile.h | 442 +++++ depends/quazip/quazipfileinfo.h | 66 + depends/quazip/quazipnewinfo.cpp | 51 + depends/quazip/quazipnewinfo.h | 102 ++ depends/quazip/unzip.c | 1603 ++++++++++++++++++ depends/quazip/unzip.h | 356 ++++ depends/quazip/zip.c | 1281 +++++++++++++++ depends/quazip/zip.h | 245 +++ depends/settings/CMakeLists.txt | 51 + depends/settings/include/basicsettingsobject.h | 44 + depends/settings/include/inifile.h | 38 + depends/settings/include/inisettingsobject.h | 60 + depends/settings/include/keyring.h | 92 ++ depends/settings/include/libsettings_config.h | 27 + depends/settings/include/overridesetting.h | 43 + depends/settings/include/setting.h | 114 ++ depends/settings/include/settingsobject.h | 192 +++ depends/settings/src/basicsettingsobject.cpp | 46 + depends/settings/src/inifile.cpp | 86 + depends/settings/src/inisettingsobject.cpp | 62 + depends/settings/src/keyring.cpp | 63 + depends/settings/src/overridesetting.cpp | 30 + depends/settings/src/setting.cpp | 54 + depends/settings/src/settingsobject.cpp | 144 ++ depends/settings/src/stubkeyring.cpp | 104 ++ depends/settings/src/stubkeyring.h | 41 + depends/util/CMakeLists.txt | 51 + depends/util/include/apputils.h | 21 + depends/util/include/cmdutils.h | 259 +++ depends/util/include/libutil_config.h | 27 + depends/util/include/osutils.h | 29 + depends/util/include/pathutils.h | 37 + depends/util/include/siglist.h | 129 ++ depends/util/include/siglist_impl.h | 156 ++ depends/util/include/userutils.h | 19 + depends/util/src/cmdutils.cpp | 484 ++++++ depends/util/src/osutils.cpp | 19 + depends/util/src/pathutils.cpp | 94 ++ depends/util/src/userutils.cpp | 123 ++ gui/IconPickerDialog.cpp | 2 +- gui/LegacyModEditDialog.cpp | 36 + gui/LegacyModEditDialog.h | 59 + gui/LegacyModEditDialog.ui | 281 ++++ gui/consolewindow.h | 2 +- gui/instancemodel.cpp | 4 +- gui/instancemodel.h | 2 +- gui/legacymodeditdialog.cpp | 35 - gui/legacymodeditdialog.h | 62 - gui/legacymodeditdialog.ui | 281 ---- gui/lwjglselectdialog.cpp | 2 +- gui/mainwindow.cpp | 31 +- gui/mainwindow.h | 6 +- gui/modeditdialog.cpp | 2 +- gui/modeditdialog.h | 2 +- gui/modeditdialog.ui | 2 +- gui/newinstancedialog.cpp | 12 +- gui/newinstancedialog.h | 2 +- gui/taskdialog.cpp | 2 +- gui/versionselectdialog.cpp | 6 +- gui/versionselectdialog.h | 2 +- java/annotations.cpp | 83 - java/annotations.h | 252 --- java/classfile.h | 153 -- java/constants.h | 212 --- java/errors.h | 6 - java/javaendian.h | 62 - java/javautils.cpp | 81 - java/javautils.h | 28 - java/membuffer.h | 64 - java/test.cpp | 35 - launcher/CMakeLists.txt | 23 - launcher/MCFrame.java | 123 -- launcher/MultiMCLauncher.java | 331 ---- launcher/UseJava.cmake | 881 ---------- launcher/UseJavaClassFilelist.cmake | 52 - launcher/UseJavaSymlinks.cmake | 32 - launcher/net/minecraft/Launcher.java | 154 -- .../org/simplericity/macify/eawt/Application.java | 176 -- .../macify/eawt/ApplicationAdapter.java | 48 - .../simplericity/macify/eawt/ApplicationEvent.java | 25 - .../macify/eawt/ApplicationListener.java | 27 - .../macify/eawt/DefaultApplication.java | 418 ----- libgroupview/CMakeLists.txt | 41 - .../include/categorizedsortfilterproxymodel.h | 175 -- libgroupview/include/categorizedview.h | 332 ---- libgroupview/include/categorydrawer.h | 179 -- libgroupview/include/libgroupview_config.h | 27 - .../src/categorizedsortfilterproxymodel.cpp | 168 -- .../src/categorizedsortfilterproxymodel_p.h | 48 - libgroupview/src/categorizedview.cpp | 1713 -------------------- libgroupview/src/categorizedview_p.h | 159 -- libgroupview/src/categorydrawer.cpp | 231 --- libsettings/CMakeLists.txt | 51 - libsettings/include/basicsettingsobject.h | 44 - libsettings/include/inifile.h | 38 - libsettings/include/inisettingsobject.h | 60 - libsettings/include/keyring.h | 92 -- libsettings/include/libsettings_config.h | 27 - libsettings/include/overridesetting.h | 43 - libsettings/include/setting.h | 114 -- libsettings/include/settingsobject.h | 192 --- libsettings/src/basicsettingsobject.cpp | 46 - libsettings/src/inifile.cpp | 86 - libsettings/src/inisettingsobject.cpp | 62 - libsettings/src/keyring.cpp | 63 - libsettings/src/overridesetting.cpp | 30 - libsettings/src/setting.cpp | 54 - libsettings/src/settingsobject.cpp | 144 -- libsettings/src/stubkeyring.cpp | 104 -- libsettings/src/stubkeyring.h | 41 - libutil/CMakeLists.txt | 51 - libutil/include/apputils.h | 21 - libutil/include/cmdutils.h | 259 --- libutil/include/libutil_config.h | 27 - libutil/include/osutils.h | 29 - libutil/include/pathutils.h | 37 - libutil/include/siglist.h | 129 -- libutil/include/siglist_impl.h | 156 -- libutil/include/userutils.h | 19 - libutil/src/cmdutils.cpp | 484 ------ libutil/src/osutils.cpp | 19 - libutil/src/pathutils.cpp | 94 -- libutil/src/userutils.cpp | 123 -- logic/BaseInstance.cpp | 181 +++ logic/BaseInstance.h | 145 ++ logic/BaseInstance_p.h | 14 + logic/BaseUpdate.cpp | 13 + logic/BaseUpdate.h | 49 + logic/CMakeLists.txt | 24 + logic/IconListModel.cpp | 163 ++ logic/IconListModel.h | 33 + logic/InstanceFactory.cpp | 113 ++ logic/InstanceFactory.h | 80 + logic/InstanceVersion.h | 68 + logic/LegacyForge.cpp | 57 + logic/LegacyForge.h | 25 + logic/LegacyInstance.cpp | 274 ++++ logic/LegacyInstance.h | 95 ++ logic/LegacyInstance_p.h | 15 + logic/LegacyUpdate.cpp | 381 +++++ logic/LegacyUpdate.h | 67 + logic/MinecraftProcess.cpp | 169 ++ logic/MinecraftProcess.h | 86 + logic/MinecraftVersion.h | 76 + logic/Mod.cpp | 264 +++ logic/Mod.h | 71 + logic/ModList.cpp | 472 ++++++ logic/ModList.h | 67 + logic/NostalgiaInstance.cpp | 12 + logic/NostalgiaInstance.h | 10 + logic/OneSixAssets.cpp | 162 ++ logic/OneSixAssets.h | 22 + logic/OneSixInstance.cpp | 218 +++ logic/OneSixInstance.h | 34 + logic/OneSixInstance_p.h | 9 + logic/OneSixUpdate.cpp | 169 ++ logic/OneSixUpdate.h | 54 + logic/OneSixVersion.cpp | 132 ++ logic/OneSixVersion.h | 212 +++ logic/VersionFactory.cpp | 195 +++ logic/VersionFactory.h | 24 + logic/lists/InstVersionList.cpp | 129 ++ logic/lists/InstVersionList.h | 121 ++ logic/lists/InstanceList.cpp | 232 +++ logic/lists/InstanceList.h | 91 ++ logic/lists/LwjglVersionList.cpp | 206 +++ logic/lists/LwjglVersionList.h | 117 ++ logic/lists/MinecraftVersionList.cpp | 300 ++++ logic/lists/MinecraftVersionList.h | 83 + logic/net/DownloadJob.cpp | 138 ++ logic/net/DownloadJob.h | 51 + logic/net/JobQueue.h | 180 ++ logic/net/NetWorker.cpp | 12 + logic/net/NetWorker.h | 20 + logic/tasks/LoginTask.cpp | 111 ++ logic/tasks/LoginTask.h | 58 + logic/tasks/Task.cpp | 85 + logic/tasks/Task.h | 65 + main.cpp | 6 +- patchlib/CMakeLists.txt | 14 - patchlib/LICENSE-bzip2 | 42 - patchlib/blocksort.c | 1095 ------------- patchlib/bspatch.c | 303 ---- patchlib/bspatch.h | 27 - patchlib/bzlib.c | 1579 ------------------ patchlib/bzlib.h | 283 ---- patchlib/bzlib_private.h | 510 ------ patchlib/compress.c | 672 -------- patchlib/crctable.c | 104 -- patchlib/decompress.c | 646 -------- patchlib/huffman.c | 205 --- patchlib/randtable.c | 84 - quazip/CMakeLists.txt | 28 - quazip/JlCompress.cpp | 516 ------ quazip/JlCompress.h | 123 -- quazip/crypt.h | 135 -- quazip/ioapi.h | 77 - quazip/qioapi.cpp | 146 -- quazip/quaadler32.cpp | 28 - quazip/quaadler32.h | 29 - quazip/quachecksum32.h | 54 - quazip/quacrc32.cpp | 28 - quazip/quacrc32.h | 26 - quazip/quagzipfile.cpp | 141 -- quazip/quagzipfile.h | 35 - quazip/quaziodevice.cpp | 283 ---- quazip/quaziodevice.h | 27 - quazip/quazip.cpp | 554 ------- quazip/quazip.h | 411 ----- quazip/quazip_global.h | 55 - quazip/quazipdir.cpp | 507 ------ quazip/quazipdir.h | 171 -- quazip/quazipfile.cpp | 488 ------ quazip/quazipfile.h | 442 ----- quazip/quazipfileinfo.h | 66 - quazip/quazipnewinfo.cpp | 51 - quazip/quazipnewinfo.h | 102 -- quazip/unzip.c | 1603 ------------------ quazip/unzip.h | 356 ---- quazip/zip.c | 1281 --------------- quazip/zip.h | 245 --- 345 files changed, 29446 insertions(+), 29377 deletions(-) delete mode 100644 backend/BaseInstance.cpp delete mode 100644 backend/BaseInstance.h delete mode 100644 backend/BaseInstance_p.h delete mode 100644 backend/BaseUpdate.cpp delete mode 100644 backend/BaseUpdate.h delete mode 100644 backend/CMakeLists.txt delete mode 100644 backend/IconListModel.cpp delete mode 100644 backend/IconListModel.h delete mode 100644 backend/InstanceFactory.cpp delete mode 100644 backend/InstanceFactory.h delete mode 100644 backend/InstanceVersion.h delete mode 100644 backend/LegacyForge.cpp delete mode 100644 backend/LegacyForge.h delete mode 100644 backend/LegacyInstance.cpp delete mode 100644 backend/LegacyInstance.h delete mode 100644 backend/LegacyInstance_p.h delete mode 100644 backend/LegacyUpdate.cpp delete mode 100644 backend/LegacyUpdate.h delete mode 100644 backend/MinecraftProcess.cpp delete mode 100644 backend/MinecraftProcess.h delete mode 100644 backend/MinecraftVersion.h delete mode 100644 backend/Mod.cpp delete mode 100644 backend/Mod.h delete mode 100644 backend/ModList.cpp delete mode 100644 backend/ModList.h delete mode 100644 backend/NostalgiaInstance.cpp delete mode 100644 backend/NostalgiaInstance.h delete mode 100644 backend/OneSixAssets.cpp delete mode 100644 backend/OneSixAssets.h delete mode 100644 backend/OneSixInstance.cpp delete mode 100644 backend/OneSixInstance.h delete mode 100644 backend/OneSixInstance_p.h delete mode 100644 backend/OneSixUpdate.cpp delete mode 100644 backend/OneSixUpdate.h delete mode 100644 backend/OneSixVersion.cpp delete mode 100644 backend/OneSixVersion.h delete mode 100644 backend/VersionFactory.cpp delete mode 100644 backend/VersionFactory.h delete mode 100644 backend/libmmc_config.h delete mode 100644 backend/lists/InstVersionList.cpp delete mode 100644 backend/lists/InstVersionList.h delete mode 100644 backend/lists/InstanceList.cpp delete mode 100644 backend/lists/InstanceList.h delete mode 100644 backend/lists/LwjglVersionList.cpp delete mode 100644 backend/lists/LwjglVersionList.h delete mode 100644 backend/lists/MinecraftVersionList.cpp delete mode 100644 backend/lists/MinecraftVersionList.h delete mode 100644 backend/net/DownloadJob.cpp delete mode 100644 backend/net/DownloadJob.h delete mode 100644 backend/net/JobQueue.h delete mode 100644 backend/net/NetWorker.cpp delete mode 100644 backend/net/NetWorker.h delete mode 100644 backend/tasks/LoginTask.cpp delete mode 100644 backend/tasks/LoginTask.h delete mode 100644 backend/tasks/Task.cpp delete mode 100644 backend/tasks/Task.h create mode 100644 depends/classparser/CMakeLists.txt create mode 100644 depends/classparser/include/classparser_config.h create mode 100644 depends/classparser/include/javautils.h create mode 100644 depends/classparser/src/annotations.cpp create mode 100644 depends/classparser/src/annotations.h create mode 100644 depends/classparser/src/classfile.h create mode 100644 depends/classparser/src/constants.h create mode 100644 depends/classparser/src/errors.h create mode 100644 depends/classparser/src/javaendian.h create mode 100644 depends/classparser/src/javautils.cpp create mode 100644 depends/classparser/src/membuffer.h create mode 100644 depends/groupview/CMakeLists.txt create mode 100644 depends/groupview/include/categorizedsortfilterproxymodel.h create mode 100644 depends/groupview/include/categorizedview.h create mode 100644 depends/groupview/include/categorydrawer.h create mode 100644 depends/groupview/include/groupview_config.h create mode 100644 depends/groupview/src/categorizedsortfilterproxymodel.cpp create mode 100644 depends/groupview/src/categorizedsortfilterproxymodel_p.h create mode 100644 depends/groupview/src/categorizedview.cpp create mode 100644 depends/groupview/src/categorizedview_p.h create mode 100644 depends/groupview/src/categorydrawer.cpp create mode 100644 depends/launcher/CMakeLists.txt create mode 100644 depends/launcher/MCFrame.java create mode 100644 depends/launcher/MultiMCLauncher.java create mode 100644 depends/launcher/UseJava.cmake create mode 100644 depends/launcher/UseJavaClassFilelist.cmake create mode 100644 depends/launcher/UseJavaSymlinks.cmake create mode 100644 depends/launcher/net/minecraft/Launcher.java create mode 100644 depends/launcher/org/simplericity/macify/eawt/Application.java create mode 100644 depends/launcher/org/simplericity/macify/eawt/ApplicationAdapter.java create mode 100644 depends/launcher/org/simplericity/macify/eawt/ApplicationEvent.java create mode 100644 depends/launcher/org/simplericity/macify/eawt/ApplicationListener.java create mode 100644 depends/launcher/org/simplericity/macify/eawt/DefaultApplication.java create mode 100644 depends/patchlib/CMakeLists.txt create mode 100644 depends/patchlib/LICENSE-bzip2 create mode 100644 depends/patchlib/blocksort.c create mode 100644 depends/patchlib/bspatch.c create mode 100644 depends/patchlib/bspatch.h create mode 100644 depends/patchlib/bzlib.c create mode 100644 depends/patchlib/bzlib.h create mode 100644 depends/patchlib/bzlib_private.h create mode 100644 depends/patchlib/compress.c create mode 100644 depends/patchlib/crctable.c create mode 100644 depends/patchlib/decompress.c create mode 100644 depends/patchlib/huffman.c create mode 100644 depends/patchlib/randtable.c create mode 100644 depends/quazip/CMakeLists.txt create mode 100644 depends/quazip/JlCompress.cpp create mode 100644 depends/quazip/JlCompress.h create mode 100644 depends/quazip/crypt.h create mode 100644 depends/quazip/ioapi.h create mode 100644 depends/quazip/qioapi.cpp create mode 100644 depends/quazip/quaadler32.cpp create mode 100644 depends/quazip/quaadler32.h create mode 100644 depends/quazip/quachecksum32.h create mode 100644 depends/quazip/quacrc32.cpp create mode 100644 depends/quazip/quacrc32.h create mode 100644 depends/quazip/quagzipfile.cpp create mode 100644 depends/quazip/quagzipfile.h create mode 100644 depends/quazip/quaziodevice.cpp create mode 100644 depends/quazip/quaziodevice.h create mode 100644 depends/quazip/quazip.cpp create mode 100644 depends/quazip/quazip.h create mode 100644 depends/quazip/quazip_global.h create mode 100644 depends/quazip/quazipdir.cpp create mode 100644 depends/quazip/quazipdir.h create mode 100644 depends/quazip/quazipfile.cpp create mode 100644 depends/quazip/quazipfile.h create mode 100644 depends/quazip/quazipfileinfo.h create mode 100644 depends/quazip/quazipnewinfo.cpp create mode 100644 depends/quazip/quazipnewinfo.h create mode 100644 depends/quazip/unzip.c create mode 100644 depends/quazip/unzip.h create mode 100644 depends/quazip/zip.c create mode 100644 depends/quazip/zip.h create mode 100644 depends/settings/CMakeLists.txt create mode 100644 depends/settings/include/basicsettingsobject.h create mode 100644 depends/settings/include/inifile.h create mode 100644 depends/settings/include/inisettingsobject.h create mode 100644 depends/settings/include/keyring.h create mode 100644 depends/settings/include/libsettings_config.h create mode 100644 depends/settings/include/overridesetting.h create mode 100644 depends/settings/include/setting.h create mode 100644 depends/settings/include/settingsobject.h create mode 100644 depends/settings/src/basicsettingsobject.cpp create mode 100644 depends/settings/src/inifile.cpp create mode 100644 depends/settings/src/inisettingsobject.cpp create mode 100644 depends/settings/src/keyring.cpp create mode 100644 depends/settings/src/overridesetting.cpp create mode 100644 depends/settings/src/setting.cpp create mode 100644 depends/settings/src/settingsobject.cpp create mode 100644 depends/settings/src/stubkeyring.cpp create mode 100644 depends/settings/src/stubkeyring.h create mode 100644 depends/util/CMakeLists.txt create mode 100644 depends/util/include/apputils.h create mode 100644 depends/util/include/cmdutils.h create mode 100644 depends/util/include/libutil_config.h create mode 100644 depends/util/include/osutils.h create mode 100644 depends/util/include/pathutils.h create mode 100644 depends/util/include/siglist.h create mode 100644 depends/util/include/siglist_impl.h create mode 100644 depends/util/include/userutils.h create mode 100644 depends/util/src/cmdutils.cpp create mode 100644 depends/util/src/osutils.cpp create mode 100644 depends/util/src/pathutils.cpp create mode 100644 depends/util/src/userutils.cpp create mode 100644 gui/LegacyModEditDialog.cpp create mode 100644 gui/LegacyModEditDialog.h create mode 100644 gui/LegacyModEditDialog.ui delete mode 100644 gui/legacymodeditdialog.cpp delete mode 100644 gui/legacymodeditdialog.h delete mode 100644 gui/legacymodeditdialog.ui delete mode 100644 java/annotations.cpp delete mode 100644 java/annotations.h delete mode 100644 java/classfile.h delete mode 100644 java/constants.h delete mode 100644 java/errors.h delete mode 100644 java/javaendian.h delete mode 100644 java/javautils.cpp delete mode 100644 java/javautils.h delete mode 100644 java/membuffer.h delete mode 100644 java/test.cpp delete mode 100644 launcher/CMakeLists.txt delete mode 100644 launcher/MCFrame.java delete mode 100644 launcher/MultiMCLauncher.java delete mode 100644 launcher/UseJava.cmake delete mode 100644 launcher/UseJavaClassFilelist.cmake delete mode 100644 launcher/UseJavaSymlinks.cmake delete mode 100644 launcher/net/minecraft/Launcher.java delete mode 100644 launcher/org/simplericity/macify/eawt/Application.java delete mode 100644 launcher/org/simplericity/macify/eawt/ApplicationAdapter.java delete mode 100644 launcher/org/simplericity/macify/eawt/ApplicationEvent.java delete mode 100644 launcher/org/simplericity/macify/eawt/ApplicationListener.java delete mode 100644 launcher/org/simplericity/macify/eawt/DefaultApplication.java delete mode 100644 libgroupview/CMakeLists.txt delete mode 100644 libgroupview/include/categorizedsortfilterproxymodel.h delete mode 100644 libgroupview/include/categorizedview.h delete mode 100644 libgroupview/include/categorydrawer.h delete mode 100644 libgroupview/include/libgroupview_config.h delete mode 100644 libgroupview/src/categorizedsortfilterproxymodel.cpp delete mode 100644 libgroupview/src/categorizedsortfilterproxymodel_p.h delete mode 100644 libgroupview/src/categorizedview.cpp delete mode 100644 libgroupview/src/categorizedview_p.h delete mode 100644 libgroupview/src/categorydrawer.cpp delete mode 100644 libsettings/CMakeLists.txt delete mode 100644 libsettings/include/basicsettingsobject.h delete mode 100644 libsettings/include/inifile.h delete mode 100644 libsettings/include/inisettingsobject.h delete mode 100644 libsettings/include/keyring.h delete mode 100644 libsettings/include/libsettings_config.h delete mode 100644 libsettings/include/overridesetting.h delete mode 100644 libsettings/include/setting.h delete mode 100644 libsettings/include/settingsobject.h delete mode 100644 libsettings/src/basicsettingsobject.cpp delete mode 100644 libsettings/src/inifile.cpp delete mode 100644 libsettings/src/inisettingsobject.cpp delete mode 100644 libsettings/src/keyring.cpp delete mode 100644 libsettings/src/overridesetting.cpp delete mode 100644 libsettings/src/setting.cpp delete mode 100644 libsettings/src/settingsobject.cpp delete mode 100644 libsettings/src/stubkeyring.cpp delete mode 100644 libsettings/src/stubkeyring.h delete mode 100644 libutil/CMakeLists.txt delete mode 100644 libutil/include/apputils.h delete mode 100644 libutil/include/cmdutils.h delete mode 100644 libutil/include/libutil_config.h delete mode 100644 libutil/include/osutils.h delete mode 100644 libutil/include/pathutils.h delete mode 100644 libutil/include/siglist.h delete mode 100644 libutil/include/siglist_impl.h delete mode 100644 libutil/include/userutils.h delete mode 100644 libutil/src/cmdutils.cpp delete mode 100644 libutil/src/osutils.cpp delete mode 100644 libutil/src/pathutils.cpp delete mode 100644 libutil/src/userutils.cpp create mode 100644 logic/BaseInstance.cpp create mode 100644 logic/BaseInstance.h create mode 100644 logic/BaseInstance_p.h create mode 100644 logic/BaseUpdate.cpp create mode 100644 logic/BaseUpdate.h create mode 100644 logic/CMakeLists.txt create mode 100644 logic/IconListModel.cpp create mode 100644 logic/IconListModel.h create mode 100644 logic/InstanceFactory.cpp create mode 100644 logic/InstanceFactory.h create mode 100644 logic/InstanceVersion.h create mode 100644 logic/LegacyForge.cpp create mode 100644 logic/LegacyForge.h create mode 100644 logic/LegacyInstance.cpp create mode 100644 logic/LegacyInstance.h create mode 100644 logic/LegacyInstance_p.h create mode 100644 logic/LegacyUpdate.cpp create mode 100644 logic/LegacyUpdate.h create mode 100644 logic/MinecraftProcess.cpp create mode 100644 logic/MinecraftProcess.h create mode 100644 logic/MinecraftVersion.h create mode 100644 logic/Mod.cpp create mode 100644 logic/Mod.h create mode 100644 logic/ModList.cpp create mode 100644 logic/ModList.h create mode 100644 logic/NostalgiaInstance.cpp create mode 100644 logic/NostalgiaInstance.h create mode 100644 logic/OneSixAssets.cpp create mode 100644 logic/OneSixAssets.h create mode 100644 logic/OneSixInstance.cpp create mode 100644 logic/OneSixInstance.h create mode 100644 logic/OneSixInstance_p.h create mode 100644 logic/OneSixUpdate.cpp create mode 100644 logic/OneSixUpdate.h create mode 100644 logic/OneSixVersion.cpp create mode 100644 logic/OneSixVersion.h create mode 100644 logic/VersionFactory.cpp create mode 100644 logic/VersionFactory.h create mode 100644 logic/lists/InstVersionList.cpp create mode 100644 logic/lists/InstVersionList.h create mode 100644 logic/lists/InstanceList.cpp create mode 100644 logic/lists/InstanceList.h create mode 100644 logic/lists/LwjglVersionList.cpp create mode 100644 logic/lists/LwjglVersionList.h create mode 100644 logic/lists/MinecraftVersionList.cpp create mode 100644 logic/lists/MinecraftVersionList.h create mode 100644 logic/net/DownloadJob.cpp create mode 100644 logic/net/DownloadJob.h create mode 100644 logic/net/JobQueue.h create mode 100644 logic/net/NetWorker.cpp create mode 100644 logic/net/NetWorker.h create mode 100644 logic/tasks/LoginTask.cpp create mode 100644 logic/tasks/LoginTask.h create mode 100644 logic/tasks/Task.cpp create mode 100644 logic/tasks/Task.h delete mode 100644 patchlib/CMakeLists.txt delete mode 100644 patchlib/LICENSE-bzip2 delete mode 100644 patchlib/blocksort.c delete mode 100644 patchlib/bspatch.c delete mode 100644 patchlib/bspatch.h delete mode 100644 patchlib/bzlib.c delete mode 100644 patchlib/bzlib.h delete mode 100644 patchlib/bzlib_private.h delete mode 100644 patchlib/compress.c delete mode 100644 patchlib/crctable.c delete mode 100644 patchlib/decompress.c delete mode 100644 patchlib/huffman.c delete mode 100644 patchlib/randtable.c delete mode 100644 quazip/CMakeLists.txt delete mode 100644 quazip/JlCompress.cpp delete mode 100644 quazip/JlCompress.h delete mode 100644 quazip/crypt.h delete mode 100644 quazip/ioapi.h delete mode 100644 quazip/qioapi.cpp delete mode 100644 quazip/quaadler32.cpp delete mode 100644 quazip/quaadler32.h delete mode 100644 quazip/quachecksum32.h delete mode 100644 quazip/quacrc32.cpp delete mode 100644 quazip/quacrc32.h delete mode 100644 quazip/quagzipfile.cpp delete mode 100644 quazip/quagzipfile.h delete mode 100644 quazip/quaziodevice.cpp delete mode 100644 quazip/quaziodevice.h delete mode 100644 quazip/quazip.cpp delete mode 100644 quazip/quazip.h delete mode 100644 quazip/quazip_global.h delete mode 100644 quazip/quazipdir.cpp delete mode 100644 quazip/quazipdir.h delete mode 100644 quazip/quazipfile.cpp delete mode 100644 quazip/quazipfile.h delete mode 100644 quazip/quazipfileinfo.h delete mode 100644 quazip/quazipnewinfo.cpp delete mode 100644 quazip/quazipnewinfo.h delete mode 100644 quazip/unzip.c delete mode 100644 quazip/unzip.h delete mode 100644 quazip/zip.c delete mode 100644 quazip/zip.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d907e152..84d8a6f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,33 +43,28 @@ find_package(ZLIB REQUIRED) ######## Included Libs ######## # Add quazip -add_subdirectory(quazip) -include_directories(quazip ${ZLIB_INCLUDE_DIRS}) +add_subdirectory(depends/quazip) +include_directories(depends/quazip ${ZLIB_INCLUDE_DIRS}) # Add bspatch -add_subdirectory(patchlib) -include_directories(patchlib) +add_subdirectory(depends/patchlib) +include_directories(depends/patchlib) # Add the java launcher -add_subdirectory(launcher) - +add_subdirectory(depends/launcher) ######## MultiMC Libs ######## # Add the util library. -add_subdirectory(libutil) +add_subdirectory(depends/util) include_directories(${LIBUTIL_INCLUDE_DIR}) # Add the settings library. -add_subdirectory(libsettings) +add_subdirectory(depends/settings) include_directories(${LIBSETTINGS_INCLUDE_DIR}) -# Add the instance library. -add_subdirectory(backend) -include_directories(${LIBMULTIMC_INCLUDE_DIR}) - # Add the group view library. -add_subdirectory(libgroupview) +add_subdirectory(depends/groupview) include_directories(${LIBGROUPVIEW_INCLUDE_DIR}) @@ -164,7 +159,6 @@ AppSettings.h gui/mainwindow.h gui/modeditdialog.h -gui/legacymodeditdialog.h gui/settingsdialog.h gui/newinstancedialog.h gui/logindialog.h @@ -178,14 +172,51 @@ gui/versionselectdialog.h gui/lwjglselectdialog.h gui/instancesettings.h gui/IconPickerDialog.h - -java/annotations.h -java/classfile.h -java/constants.h -java/javaendian.h -java/errors.h -java/javautils.h -java/membuffer.h +gui/LegacyModEditDialog.h + +# Base classes and infrastructure +logic/InstanceVersion.h +logic/MinecraftVersion.h +logic/InstanceFactory.h +logic/BaseUpdate.h +logic/BaseInstance.h +logic/BaseInstance_p.h +logic/MinecraftProcess.h +logic/Mod.h +logic/ModList.h + +# network stuffs +logic/net/DownloadJob.h +logic/net/JobQueue.h +logic/net/NetWorker.h + +# legacy instances +logic/LegacyInstance.h +logic/LegacyInstance_p.h +logic/LegacyUpdate.h +logic/LegacyForge.h + +# 1.6 instances +logic/OneSixAssets.h +logic/OneSixInstance.h +logic/OneSixInstance_p.h +logic/OneSixUpdate.h +logic/OneSixVersion.h +logic/VersionFactory.h + +# Nostalgia +logic/NostalgiaInstance.h + +# Lists +logic/lists/InstanceList.h +logic/lists/InstVersionList.h +logic/lists/MinecraftVersionList.h +logic/lists/LwjglVersionList.h +logic/IconListModel.h + +# Tasks +logic/tasks/Task.h +logic/tasks/LoginTask.h ) @@ -197,7 +228,6 @@ AppSettings.cpp gui/mainwindow.cpp gui/modeditdialog.cpp -gui/legacymodeditdialog.cpp gui/settingsdialog.cpp gui/newinstancedialog.cpp gui/logindialog.cpp @@ -211,9 +241,45 @@ gui/versionselectdialog.cpp gui/lwjglselectdialog.cpp gui/instancesettings.cpp gui/IconPickerDialog.cpp - -java/javautils.cpp -java/annotations.cpp +gui/LegacyModEditDialog.cpp + +# Base classes and infrastructure +logic/InstanceFactory.cpp +logic/BaseUpdate.cpp +logic/BaseInstance.cpp +logic/MinecraftProcess.cpp +logic/Mod.cpp +logic/ModList.cpp + +# network stuffs - to be moved into a depend lib ~_~ +logic/net/NetWorker.cpp +logic/net/DownloadJob.cpp + +# legacy instances +logic/LegacyInstance.cpp +logic/LegacyUpdate.cpp +logic/LegacyForge.cpp + +# 1.6 instances +logic/OneSixAssets.cpp +logic/OneSixInstance.cpp +logic/OneSixVersion.cpp +logic/OneSixUpdate.cpp +logic/VersionFactory.cpp + +# Nostalgia +logic/NostalgiaInstance.cpp + +# Lists +logic/lists/InstanceList.cpp +logic/lists/InstVersionList.cpp +logic/lists/MinecraftVersionList.cpp +logic/lists/LwjglVersionList.cpp +logic/IconListModel.cpp + +# Tasks +logic/tasks/Task.cpp +logic/tasks/LoginTask.cpp ) @@ -221,7 +287,6 @@ java/annotations.cpp SET(MULTIMC_UIS gui/mainwindow.ui gui/modeditdialog.ui -gui/legacymodeditdialog.ui gui/settingsdialog.ui gui/newinstancedialog.ui gui/logindialog.ui @@ -233,6 +298,7 @@ gui/versionselectdialog.ui gui/lwjglselectdialog.ui gui/instancesettings.ui gui/IconPickerDialog.ui +gui/LegacyModEditDialog.ui ) @@ -270,11 +336,9 @@ ADD_EXECUTABLE(MultiMC MACOSX_BUNDLE WIN32 ${MULTIMC_SOURCES} ${MULTIMC_HEADERS} ${MULTIMC_UI} ${MULTIMC_QRC} ${MULTIMC_RCS}) # Link -QT5_USE_MODULES(MultiMC Widgets Network WebKitWidgets) -TARGET_LINK_LIBRARIES(MultiMC quazip patchlib -libUtil libSettings backend libGroupView -${MultiMC_LINK_ADDITIONAL_LIBS}) -ADD_DEPENDENCIES(MultiMC MultiMCLauncher libUtil libSettings backend libGroupView) +QT5_USE_MODULES(MultiMC Widgets Network WebKitWidgets Xml) +TARGET_LINK_LIBRARIES(MultiMC quazip patchlib libUtil libSettings libGroupView ${MultiMC_LINK_ADDITIONAL_LIBS}) +ADD_DEPENDENCIES(MultiMC MultiMCLauncher libUtil libSettings libGroupView) option(BUILD_KEYRING_TEST "Build the simple keyring test binary" OFF) diff --git a/backend/BaseInstance.cpp b/backend/BaseInstance.cpp deleted file mode 100644 index 951b403a..00000000 --- a/backend/BaseInstance.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "BaseInstance.h" -#include "BaseInstance_p.h" - -#include - -#include "inisettingsobject.h" -#include "setting.h" -#include "overridesetting.h" - -#include "pathutils.h" -#include - - -BaseInstance::BaseInstance( BaseInstancePrivate* d_in, - const QString& rootDir, - SettingsObject* settings_obj, - QObject* parent - ) -:inst_d(d_in), QObject(parent) -{ - I_D(BaseInstance); - d->m_settings = settings_obj; - d->m_rootDir = rootDir; - - settings().registerSetting(new Setting("name", "Unnamed Instance")); - settings().registerSetting(new Setting("iconKey", "default")); - settings().registerSetting(new Setting("notes", "")); - settings().registerSetting(new Setting("lastLaunchTime", 0)); - - // Java Settings - settings().registerSetting(new Setting("OverrideJava", false)); - settings().registerSetting(new OverrideSetting("JavaPath", globalSettings->getSetting("JavaPath"))); - settings().registerSetting(new OverrideSetting("JvmArgs", globalSettings->getSetting("JvmArgs"))); - - // Custom Commands - settings().registerSetting(new Setting("OverrideCommands", false)); - settings().registerSetting(new OverrideSetting("PreLaunchCommand", globalSettings->getSetting("PreLaunchCommand"))); - settings().registerSetting(new OverrideSetting("PostExitCommand", globalSettings->getSetting("PostExitCommand"))); - - // Window Size - settings().registerSetting(new Setting("OverrideWindow", false)); - settings().registerSetting(new OverrideSetting("LaunchMaximized", globalSettings->getSetting("LaunchMaximized"))); - settings().registerSetting(new OverrideSetting("MinecraftWinWidth", globalSettings->getSetting("MinecraftWinWidth"))); - settings().registerSetting(new OverrideSetting("MinecraftWinHeight", globalSettings->getSetting("MinecraftWinHeight"))); - - // Memory - settings().registerSetting(new Setting("OverrideMemory", false)); - settings().registerSetting(new OverrideSetting("MinMemAlloc", globalSettings->getSetting("MinMemAlloc"))); - settings().registerSetting(new OverrideSetting("MaxMemAlloc", globalSettings->getSetting("MaxMemAlloc"))); - - // Auto login - settings().registerSetting(new Setting("OverrideLogin", false)); - settings().registerSetting(new OverrideSetting("AutoLogin", globalSettings->getSetting("AutoLogin"))); - - // Console - settings().registerSetting(new Setting("OverrideConsole", false)); - settings().registerSetting(new OverrideSetting("ShowConsole", globalSettings->getSetting("ShowConsole"))); - settings().registerSetting(new OverrideSetting("AutoCloseConsole", globalSettings->getSetting("AutoCloseConsole"))); -} - -QString BaseInstance::id() const -{ - return QFileInfo(instanceRoot()).fileName(); -} - -QString BaseInstance::instanceType() const -{ - I_D(BaseInstance); - return d->m_settings->get("InstanceType").toString(); -} - - -QString BaseInstance::instanceRoot() const -{ - I_D(BaseInstance); - return d->m_rootDir; -} - -QString BaseInstance::minecraftRoot() const -{ - QFileInfo mcDir(PathCombine(instanceRoot(), "minecraft")); - QFileInfo dotMCDir(PathCombine(instanceRoot(), ".minecraft")); - - if (dotMCDir.exists() && !mcDir.exists()) - return dotMCDir.filePath(); - else - return mcDir.filePath(); -} - -InstanceList *BaseInstance::instList() const -{ - if (parent()->inherits("InstanceList")) - return (InstanceList *)parent(); - else - return NULL; -} - -InstVersionList *BaseInstance::versionList() const -{ - return &MinecraftVersionList::getMainList(); -} - -SettingsObject &BaseInstance::settings() const -{ - I_D(BaseInstance); - return *d->m_settings; -} - -qint64 BaseInstance::lastLaunch() const -{ - I_D(BaseInstance); - return d->m_settings->get ( "lastLaunchTime" ).value(); -} -void BaseInstance::setLastLaunch ( qint64 val ) -{ - I_D(BaseInstance); - d->m_settings->set ( "lastLaunchTime", val ); - emit propertiesChanged ( this ); -} - -void BaseInstance::setGroup ( QString val ) -{ - I_D(BaseInstance); - d->m_group = val; - emit propertiesChanged ( this ); -} -QString BaseInstance::group() const -{ - I_D(BaseInstance); - return d->m_group; -} - -void BaseInstance::setNotes ( QString val ) -{ - I_D(BaseInstance); - d->m_settings->set ( "notes", val ); -} -QString BaseInstance::notes() const -{ - I_D(BaseInstance); - return d->m_settings->get ( "notes" ).toString(); -} - -void BaseInstance::setIconKey ( QString val ) -{ - I_D(BaseInstance); - d->m_settings->set ( "iconKey", val ); - emit propertiesChanged ( this ); -} -QString BaseInstance::iconKey() const -{ - I_D(BaseInstance); - return d->m_settings->get ( "iconKey" ).toString(); -} - -void BaseInstance::setName ( QString val ) -{ - I_D(BaseInstance); - d->m_settings->set ( "name", val ); - emit propertiesChanged ( this ); -} -QString BaseInstance::name() const -{ - I_D(BaseInstance); - return d->m_settings->get ( "name" ).toString(); -} diff --git a/backend/BaseInstance.h b/backend/BaseInstance.h deleted file mode 100644 index 05f3ce00..00000000 --- a/backend/BaseInstance.h +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include - -#include "inifile.h" -#include "lists/InstVersionList.h" - -#include "libmmc_config.h" - -class BaseUpdate; -class MinecraftProcess; -class OneSixUpdate; -class InstanceList; -class BaseInstancePrivate; - -/*! - * \brief Base class for instances. - * This class implements many functions that are common between instances and - * provides a standard interface for all instances. - * - * To create a new instance type, create a new class inheriting from this class - * and implement the pure virtual functions. - */ -class LIBMULTIMC_EXPORT BaseInstance : public QObject -{ - Q_OBJECT -protected: - /// no-touchy! - BaseInstance(BaseInstancePrivate * d, const QString &rootDir, SettingsObject * settings, QObject *parent = 0); -public: - /// virtual destructor to make sure the destruction is COMPLETE - virtual ~BaseInstance() {}; - - /// The instance's ID. The ID SHALL be determined by MMC internally. The ID IS guaranteed to be unique. - QString id() const; - - /// get the type of this instance - QString instanceType() const; - - /// Path to the instance's root directory. - QString instanceRoot() const; - - /// Path to the instance's minecraft directory. - QString minecraftRoot() const; - - QString name() const; - void setName(QString val); - - QString iconKey() const; - void setIconKey(QString val); - - QString notes() const; - void setNotes(QString val); - - QString group() const; - void setGroup(QString val); - - virtual QString intendedVersionId() const = 0; - virtual bool setIntendedVersionId(QString version) = 0; - - /*! - * The instance's current version. - * This value represents the instance's current version. If this value is - * different from the intendedVersion, the instance should be updated. - * \warning Don't change this value unless you know what you're doing. - */ - virtual QString currentVersionId() const = 0; - //virtual void setCurrentVersionId(QString val) = 0; - - /*! - * Whether or not Minecraft should be downloaded when the instance is launched. - */ - virtual bool shouldUpdate() const = 0; - virtual void setShouldUpdate(bool val) = 0; - - /** - * Gets the time that the instance was last launched. - * Stored in milliseconds since epoch. - */ - qint64 lastLaunch() const; - /// Sets the last launched time to 'val' milliseconds since epoch - void setLastLaunch(qint64 val = QDateTime::currentMSecsSinceEpoch()); - - /*! - * \brief Gets the instance list that this instance is a part of. - * Returns NULL if this instance is not in a list - * (the parent is not an InstanceList). - * \return A pointer to the InstanceList containing this instance. - */ - InstanceList *instList() const; - - /*! - * \brief Gets a pointer to this instance's version list. - * \return A pointer to the available version list for this instance. - */ - virtual InstVersionList *versionList() const; - - /*! - * \brief Gets this instance's settings object. - * This settings object stores instance-specific settings. - * \return A pointer to this instance's settings object. - */ - virtual SettingsObject &settings() const; - - /// returns a valid update task if update is needed, NULL otherwise - virtual BaseUpdate* doUpdate() = 0; - - /// returns a valid minecraft process, ready for launch - virtual MinecraftProcess* prepareForLaunch(QString user, QString session) = 0; - - /// do any necessary cleanups after the instance finishes. also runs before 'prepareForLaunch' - virtual void cleanupAfterRun() = 0; -signals: - /*! - * \brief Signal emitted when properties relevant to the instance view change - */ - void propertiesChanged(BaseInstance * inst); - -protected: - QSharedPointer inst_d; -}; - -// pointer for lazy people -typedef QSharedPointer InstancePtr; - diff --git a/backend/BaseInstance_p.h b/backend/BaseInstance_p.h deleted file mode 100644 index a30916a4..00000000 --- a/backend/BaseInstance_p.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include -#include - -class BaseInstance; - -#define I_D(Class) Class##Private * const d = (Class##Private * const) inst_d.data() - -struct BaseInstancePrivate -{ - QString m_rootDir; - QString m_group; - SettingsObject *m_settings; -}; \ No newline at end of file diff --git a/backend/BaseUpdate.cpp b/backend/BaseUpdate.cpp deleted file mode 100644 index b086ab14..00000000 --- a/backend/BaseUpdate.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "BaseUpdate.h" - -BaseUpdate::BaseUpdate ( BaseInstance* inst, QObject* parent ) : Task ( parent ) -{ - m_inst = inst; -} - -void BaseUpdate::updateDownloadProgress(qint64 current, qint64 total) -{ - // The progress on the current file is current / total - float currentDLProgress = (float) current / (float) total; - setProgress((int)(currentDLProgress * 100)); // convert to percentage -} \ No newline at end of file diff --git a/backend/BaseUpdate.h b/backend/BaseUpdate.h deleted file mode 100644 index b7d2017e..00000000 --- a/backend/BaseUpdate.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -#include "net/DownloadJob.h" - -#include "tasks/Task.h" -#include "libmmc_config.h" - -class MinecraftVersion; -class BaseInstance; - -/*! - * The game update task is the task that handles downloading instances' files. - */ -class LIBMULTIMC_EXPORT BaseUpdate : public Task -{ - Q_OBJECT -public: - explicit BaseUpdate(BaseInstance *inst, QObject *parent = 0); - - virtual void executeTask() = 0; - -protected slots: - //virtual void error(const QString &msg); - void updateDownloadProgress(qint64 current, qint64 total); - -protected: - JobListQueue download_queue; - BaseInstance *m_inst; -}; - - diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt deleted file mode 100644 index 7a92d5cf..00000000 --- a/backend/CMakeLists.txt +++ /dev/null @@ -1,120 +0,0 @@ -project(libMultiMC) - -set(CMAKE_AUTOMOC ON) - -# Find Qt -find_package(Qt5Core REQUIRED) -find_package(Qt5Network REQUIRED) -find_package(Qt5Xml REQUIRED) - -# Include Qt headers. -include_directories(${Qt5Base_INCLUDE_DIRS}) -include_directories(${Qt5Network_INCLUDE_DIRS}) - -# Include utility library. -include_directories(${CMAKE_SOURCE_DIR}/libutil/include) - -# Include settings library. -include_directories(${CMAKE_SOURCE_DIR}/libsettings/include) - -SET(LIBINST_HEADERS -libmmc_config.h - -# Base classes and infrastructure -InstanceVersion.h -MinecraftVersion.h -InstanceFactory.h -BaseUpdate.h -BaseInstance.h -BaseInstance_p.h -MinecraftProcess.h -Mod.h -ModList.h - -# network stuffs -net/DownloadJob.h -net/JobQueue.h -net/NetWorker.h - -# legacy instances -LegacyInstance.h -LegacyInstance_p.h -LegacyUpdate.h -LegacyForge.h - -# 1.6 instances -OneSixAssets.h -OneSixInstance.h -OneSixInstance_p.h -OneSixUpdate.h -OneSixVersion.h -VersionFactory.h - -# Nostalgia -NostalgiaInstance.h - -# Lists -lists/InstanceList.h -lists/InstVersionList.h -lists/MinecraftVersionList.h -lists/LwjglVersionList.h -IconListModel.h - -# Tasks -tasks/Task.h -tasks/LoginTask.h -) - -SET(LIBINST_SOURCES -# Base classes and infrastructure -InstanceFactory.cpp -BaseUpdate.cpp -BaseInstance.cpp -MinecraftProcess.cpp -Mod.cpp -ModList.cpp - -# network stuffs -net/NetWorker.cpp -net/DownloadJob.cpp - -# legacy instances -LegacyInstance.cpp -LegacyUpdate.cpp -LegacyForge.cpp - -# 1.6 instances -OneSixAssets.cpp -OneSixInstance.cpp -OneSixVersion.cpp -OneSixUpdate.cpp -VersionFactory.cpp - -# Nostalgia -NostalgiaInstance.cpp - -# Lists -lists/InstanceList.cpp -lists/InstVersionList.cpp -lists/MinecraftVersionList.cpp -lists/LwjglVersionList.cpp -IconListModel.cpp - -# Tasks -tasks/Task.cpp -tasks/LoginTask.cpp -) - -# Set the include dir path. -SET(LIBMULTIMC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE) - -# Include self. -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${CMAKE_BINARY_DIR}/include) - -add_definitions(-DLIBMULTIMC_LIBRARY) - -add_library(backend SHARED ${LIBINST_SOURCES} ${LIBINST_HEADERS}) -qt5_use_modules(backend Core Network Xml) -target_link_libraries(backend libUtil libSettings quazip) - diff --git a/backend/IconListModel.cpp b/backend/IconListModel.cpp deleted file mode 100644 index 2d2fb6cf..00000000 --- a/backend/IconListModel.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include "IconListModel.h" -#include -#include -#include -#include - -#define MAX_SIZE 1024 -IconList* IconList::m_Instance = 0; -QMutex IconList::mutex; - -struct entry -{ - QString key; - QString name; - QIcon icon; - bool is_builtin; -}; - -class Private : public QObject -{ - Q_OBJECT -public: - QMap index; - QVector icons; - Private() - { - } -}; - - -IconList::IconList() : QAbstractListModel(), d(new Private()) -{ - QDir instance_icons(":/icons/instances/"); - auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name); - for(auto file_info: file_info_list) - { - QString key = file_info.baseName(); - addIcon(key, key, file_info.absoluteFilePath(), true); - } - - // FIXME: get from settings - ensurePathExists("icons/"); - QDir user_icons("icons/"); - file_info_list = user_icons.entryInfoList(QDir::Files, QDir::Name); - for(auto file_info: file_info_list) - { - QString filename = file_info.absoluteFilePath(); - QString key = file_info.baseName(); - addIcon(key, key, filename); - } -} - -IconList::~IconList() -{ - delete d; - d = nullptr; -} - -QVariant IconList::data ( const QModelIndex& index, int role ) const -{ - if(!index.isValid()) - return QVariant(); - - int row = index.row(); - - if(row < 0 || row >= d->icons.size()) - return QVariant(); - - switch(role) - { - case Qt::DecorationRole: - return d->icons[row].icon; - case Qt::DisplayRole: - return d->icons[row].name; - case Qt::UserRole: - return d->icons[row].key; - default: - return QVariant(); - } -} - -int IconList::rowCount ( const QModelIndex& parent ) const -{ - return d->icons.size(); -} - -bool IconList::addIcon ( QString key, QString name, QString path, bool is_builtin ) -{ - auto iter = d->index.find(key); - if(iter != d->index.end()) - { - if(d->icons[*iter].is_builtin) return false; - - QIcon icon(path); - if(icon.isNull()) return false; - - // replace the icon - d->icons[*iter] = {key, name, icon, is_builtin}; - return true; - } - else - { - QIcon icon(path); - if(icon.isNull()) return false; - - // add a new icon - d->icons.push_back({key, name, icon, is_builtin}); - d->index[key] = d->icons.size() - 1; - return true; - } -} - - -QIcon IconList::getIcon ( QString key ) -{ - int icon_index = getIconIndex(key); - - if(icon_index != -1) - return d->icons[icon_index].icon; - - // Fallback for icons that don't exist. - icon_index = getIconIndex("infinity"); - - if(icon_index != -1) - return d->icons[icon_index].icon; - return QIcon(); -} - -int IconList::getIconIndex ( QString key ) -{ - if(key == "default") - key = "infinity"; - - auto iter = d->index.find(key); - if(iter != d->index.end()) - return *iter; - - - return -1; -} - - -void IconList::drop() -{ - mutex.lock(); - delete m_Instance; - m_Instance = 0; - mutex.unlock(); -} - -IconList* IconList::instance() -{ - if ( !m_Instance ) - { - mutex.lock(); - if ( !m_Instance ) - m_Instance = new IconList; - mutex.unlock(); - } - return m_Instance; -} - -#include "IconListModel.moc" \ No newline at end of file diff --git a/backend/IconListModel.h b/backend/IconListModel.h deleted file mode 100644 index 31b05e64..00000000 --- a/backend/IconListModel.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include -#include - -class Private; - -class IconList : public QAbstractListModel -{ -public: - static IconList* instance(); - static void drop(); - QIcon getIcon ( QString key ); - int getIconIndex ( QString key ); - - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const; - - bool addIcon(QString key, QString name, QString path, bool is_builtin = false); - - -private: - virtual ~IconList(); - IconList(); - // hide copy constructor - IconList ( const IconList & ) = delete; - // hide assign op - IconList& operator= ( const IconList & ) = delete; - static IconList* m_Instance; - static QMutex mutex; - Private* d; -}; diff --git a/backend/InstanceFactory.cpp b/backend/InstanceFactory.cpp deleted file mode 100644 index f3511157..00000000 --- a/backend/InstanceFactory.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "InstanceFactory.h" - -#include -#include - -#include "BaseInstance.h" -#include "LegacyInstance.h" -#include "OneSixInstance.h" -#include "NostalgiaInstance.h" -#include "InstanceVersion.h" -#include "MinecraftVersion.h" - -#include "inifile.h" -#include -#include - -#include "pathutils.h" - -InstanceFactory InstanceFactory::loader; - -InstanceFactory::InstanceFactory() : - QObject(NULL) -{ - -} - -InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst, const QString &instDir) -{ - auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg")); - - m_settings->registerSetting(new Setting("InstanceType", "Legacy")); - - QString inst_type = m_settings->get("InstanceType").toString(); - - //FIXME: replace with a map lookup, where instance classes register their types - if(inst_type == "Legacy") - { - inst = new LegacyInstance(instDir, m_settings, this); - } - else if(inst_type == "OneSix") - { - inst = new OneSixInstance(instDir, m_settings, this); - } - else if(inst_type == "Nostalgia") - { - inst = new NostalgiaInstance(instDir, m_settings, this); - } - else - { - return InstanceFactory::UnknownLoadError; - } - return NoLoadError; -} - - -InstanceFactory::InstCreateError InstanceFactory::createInstance( BaseInstance*& inst, InstVersionPtr version, const QString& instDir ) -{ - QDir rootDir(instDir); - - qDebug(instDir.toUtf8()); - if (!rootDir.exists() && !rootDir.mkpath(".")) - { - return InstanceFactory::CantCreateDir; - } - auto mcVer = version.dynamicCast(); - if(!mcVer) - return InstanceFactory::NoSuchVersion; - - auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg")); - m_settings->registerSetting(new Setting("InstanceType", "Legacy")); - - switch(mcVer->type) - { - case MinecraftVersion::Legacy: - m_settings->set("InstanceType", "Legacy"); - inst = new LegacyInstance(instDir, m_settings, this); - inst->setIntendedVersionId(version->descriptor); - break; - case MinecraftVersion::OneSix: - m_settings->set("InstanceType", "OneSix"); - inst = new OneSixInstance(instDir, m_settings, this); - inst->setIntendedVersionId(version->descriptor); - break; - case MinecraftVersion::Nostalgia: - m_settings->set("InstanceType", "Nostalgia"); - inst = new NostalgiaInstance(instDir, m_settings, this); - inst->setIntendedVersionId(version->descriptor); - break; - default: - { - delete m_settings; - return InstanceFactory::NoSuchVersion; - } - } - - //FIXME: really, how do you even know? - return InstanceFactory::NoCreateError; -} diff --git a/backend/InstanceFactory.h b/backend/InstanceFactory.h deleted file mode 100644 index e1100504..00000000 --- a/backend/InstanceFactory.h +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -#include "libmmc_config.h" -#include "InstanceVersion.h" - -class InstVersion; -class BaseInstance; - -/*! - * The \bInstanceFactory\b is a singleton that manages loading and creating instances. - */ -class LIBMULTIMC_EXPORT InstanceFactory : public QObject -{ - Q_OBJECT -public: - /*! - * \brief Gets a reference to the instance loader. - */ - static InstanceFactory &get() { return loader; } - - enum InstLoadError - { - NoLoadError = 0, - UnknownLoadError, - NotAnInstance - }; - - enum InstCreateError - { - NoCreateError = 0, - NoSuchVersion, - UnknownCreateError, - InstExists, - CantCreateDir - }; - - /*! - * \brief Creates a stub instance - * - * \param inst Pointer to store the created instance in. - * \param instDir The instance's directory. - * \return An InstCreateError error code. - * - InstExists if the given instance directory is already an instance. - * - CantCreateDir if the given instance directory cannot be created. - */ - InstCreateError createInstance(BaseInstance *&inst, InstVersionPtr version, const QString &instDir); - - /*! - * \brief Loads an instance from the given directory. - * Checks the instance's INI file to figure out what the instance's type is first. - * \param inst Pointer to store the loaded instance in. - * \param instDir The instance's directory. - * \return An InstLoadError error code. - * - NotAnInstance if the given instance directory isn't a valid instance. - */ - InstLoadError loadInstance(BaseInstance *&inst, const QString &instDir); - -private: - InstanceFactory(); - - static InstanceFactory loader; -}; diff --git a/backend/InstanceVersion.h b/backend/InstanceVersion.h deleted file mode 100644 index aeff9842..00000000 --- a/backend/InstanceVersion.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once -#include "libmmc_config.h" -#include - -/*! - * An abstract base class for versions. - */ -struct LIBMULTIMC_EXPORT InstVersion -{ - /*! - * Checks if this version is less (older) than the given version. - * \param other The version to compare this one to. - * \return True if this version is older than the given version. - */ - virtual bool operator<(const InstVersion &rhs) const - { - return timestamp < rhs.timestamp; - } - - /*! - * Checks if this version is greater (newer) than the given version. - * \param other The version to compare this one to. - * \return True if this version is newer than the given version. - */ - virtual bool operator>( const InstVersion& rhs ) const - { - return timestamp > rhs.timestamp; - } - - /*! - * A string used to identify this version in config files. - * This should be unique within the version list or shenanigans will occur. - */ - QString descriptor; - /*! - * The name of this version as it is displayed to the user. - * For example: "1.5.1" - */ - QString name; - /*! - * Gets the version's timestamp. - * This is primarily used for sorting versions in a list. - */ - qint64 timestamp; - - virtual QString typeString() const - { - return "InstVersion"; - } -}; - -typedef QSharedPointer InstVersionPtr; - -Q_DECLARE_METATYPE( InstVersionPtr ) \ No newline at end of file diff --git a/backend/LegacyForge.cpp b/backend/LegacyForge.cpp deleted file mode 100644 index adcf487c..00000000 --- a/backend/LegacyForge.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright 2012 MultiMC Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "LegacyForge.h" - -MinecraftForge::MinecraftForge ( const QString& file ) : Mod ( file ) -{ - -} -bool MinecraftForge::FixVersionIfNeeded ( QString newVersion ) -{/* - wxString reportedVersion = GetModVersion(); - if(reportedVersion == "..." || reportedVersion.empty()) - { - std::auto_ptr in(new wxFFileInputStream("forge.zip")); - wxTempFileOutputStream out("forge.zip"); - wxTextOutputStream textout(out); - wxZipInputStream inzip(*in); - wxZipOutputStream outzip(out); - std::auto_ptr entry; - // preserve metadata - outzip.CopyArchiveMetaData(inzip); - // copy all entries - while (entry.reset(inzip.GetNextEntry()), entry.get() != NULL) - if (!outzip.CopyEntry(entry.release(), inzip)) - return false; - // release last entry - in.reset(); - outzip.PutNextEntry("forgeversion.properties"); - - wxStringTokenizer tokenizer(newVersion,"."); - wxString verFile; - verFile << wxString("forge.major.number=") << tokenizer.GetNextToken() << "\n"; - verFile << wxString("forge.minor.number=") << tokenizer.GetNextToken() << "\n"; - verFile << wxString("forge.revision.number=") << tokenizer.GetNextToken() << "\n"; - verFile << wxString("forge.build.number=") << tokenizer.GetNextToken() << "\n"; - auto buf = verFile.ToUTF8(); - outzip.Write(buf.data(), buf.length()); - // check if we succeeded - return inzip.Eof() && outzip.Close() && out.Commit(); - } - */ - return true; -} diff --git a/backend/LegacyForge.h b/backend/LegacyForge.h deleted file mode 100644 index 00a054b8..00000000 --- a/backend/LegacyForge.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright 2012 MultiMC Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#pragma once -#include "Mod.h" - -class MinecraftForge : public Mod -{ -public: - MinecraftForge ( const QString& file ); - bool FixVersionIfNeeded(QString newVersion); -}; diff --git a/backend/LegacyInstance.cpp b/backend/LegacyInstance.cpp deleted file mode 100644 index 9102c9c7..00000000 --- a/backend/LegacyInstance.cpp +++ /dev/null @@ -1,229 +0,0 @@ -#include "LegacyInstance.h" -#include "LegacyInstance_p.h" -#include "MinecraftProcess.h" -#include "LegacyUpdate.h" -#include -#include -#include -#include -#include -#include - -#define LAUNCHER_FILE "MultiMCLauncher.jar" - -LegacyInstance::LegacyInstance(const QString& rootDir, SettingsObject* settings, QObject* parent) - :BaseInstance( new LegacyInstancePrivate(),rootDir, settings, parent) -{ - settings->registerSetting(new Setting("NeedsRebuild", true)); - settings->registerSetting(new Setting("ShouldUpdate", false)); - settings->registerSetting(new Setting("JarVersion", "Unknown")); - settings->registerSetting(new Setting("LwjglVersion", "2.9.0")); - settings->registerSetting(new Setting("IntendedJarVersion", "")); -} - -BaseUpdate* LegacyInstance::doUpdate() -{ - return new LegacyUpdate(this, this); -} - -MinecraftProcess* LegacyInstance::prepareForLaunch(QString user, QString session) -{ - MinecraftProcess * proc = new MinecraftProcess(this); - - // FIXME: extract the icon - // QImage(":/icons/instances/" + iconKey()).save(PathCombine(minecraftRoot(), "icon.png")); - - // extract the legacy launcher - QFile(":/launcher/launcher.jar").copy(PathCombine(minecraftRoot(), LAUNCHER_FILE)); - - // set the process arguments - { - QStringList args; - - // window size - QString windowSize; - if (settings().get("LaunchMaximized").toBool()) - windowSize = "max"; - else - windowSize = QString("%1x%2"). - arg(settings().get("MinecraftWinWidth").toInt()). - arg(settings().get("MinecraftWinHeight").toInt()); - - // window title - QString windowTitle; - windowTitle.append("MultiMC: ").append(name()); - - // Java arguments - args.append(Util::Commandline::splitArgs(settings().get("JvmArgs").toString())); - -#ifdef OSX - // OSX dock icon and name - args << "-Xdock:icon=icon.png"; - args << QString("-Xdock:name=\"%1\"").arg(windowTitle); -#endif - - QString lwjgl = QDir(globalSettings->get("LWJGLDir").toString() + "/" + lwjglVersion()).absolutePath(); - - // launcher arguments - args << QString("-Xms%1m").arg(settings().get("MinMemAlloc").toInt()); - args << QString("-Xmx%1m").arg(settings().get("MaxMemAlloc").toInt()); - args << "-jar" << LAUNCHER_FILE; - args << user; - args << session; - args << windowTitle; - args << windowSize; - args << lwjgl; - proc->setMinecraftArguments(args); - } - - // set the process work path - proc->setMinecraftWorkdir(minecraftRoot()); - - return proc; -} - -void LegacyInstance::cleanupAfterRun() -{ - //FIXME: delete the launcher and icons and whatnot. -} - - -QString LegacyInstance::instModsDir() const -{ - return PathCombine(instanceRoot(), "instMods"); -} - -QString LegacyInstance::binDir() const -{ - return PathCombine(minecraftRoot(), "bin"); -} - -QString LegacyInstance::savesDir() const -{ - return PathCombine(minecraftRoot(), "saves"); -} - -QString LegacyInstance::mlModsDir() const -{ - return PathCombine(minecraftRoot(), "mods"); -} - -QString LegacyInstance::coreModsDir() const -{ - return PathCombine(minecraftRoot(), "coremods"); -} - -QString LegacyInstance::resourceDir() const -{ - return PathCombine(minecraftRoot(), "resources"); -} - -QString LegacyInstance::mcJar() const -{ - return PathCombine(binDir(), "minecraft.jar"); -} - -QString LegacyInstance::mcBackup() const -{ - return PathCombine(binDir(), "mcbackup.jar"); -} - -QString LegacyInstance::modListFile() const -{ - return PathCombine(instanceRoot(), "modlist"); -} - -bool LegacyInstance::shouldUpdateCurrentVersion() const -{ - QFileInfo jar(mcJar()); - return jar.lastModified().toUTC().toMSecsSinceEpoch() != lastCurrentVersionUpdate(); -} - -void LegacyInstance::updateCurrentVersion(bool keepCurrent) -{ - QFileInfo jar(mcJar()); - - if(!jar.exists()) - { - setLastCurrentVersionUpdate(0); - setCurrentVersionId("Unknown"); - return; - } - - qint64 time = jar.lastModified().toUTC().toMSecsSinceEpoch(); - - setLastCurrentVersionUpdate(time); - if (!keepCurrent) - { - // TODO: Implement GetMinecraftJarVersion function. - QString newVersion = "Unknown";//javautils::GetMinecraftJarVersion(jar.absoluteFilePath()); - setCurrentVersionId(newVersion); - } -} -qint64 LegacyInstance::lastCurrentVersionUpdate() const -{ - I_D(LegacyInstance); - return d->m_settings->get ( "lastVersionUpdate" ).value(); -} -void LegacyInstance::setLastCurrentVersionUpdate ( qint64 val ) -{ - I_D(LegacyInstance); - d->m_settings->set ( "lastVersionUpdate", val ); -} -bool LegacyInstance::shouldRebuild() const -{ - I_D(LegacyInstance); - return d->m_settings->get ( "NeedsRebuild" ).toBool(); -} -void LegacyInstance::setShouldRebuild ( bool val ) -{ - I_D(LegacyInstance); - d->m_settings->set ( "NeedsRebuild", val ); -} -QString LegacyInstance::currentVersionId() const -{ - I_D(LegacyInstance); - return d->m_settings->get ( "JarVersion" ).toString(); -} - -void LegacyInstance::setCurrentVersionId ( QString val ) -{ - I_D(LegacyInstance); - d->m_settings->set ( "JarVersion", val ); -} - -QString LegacyInstance::lwjglVersion() const -{ - I_D(LegacyInstance); - return d->m_settings->get ( "LwjglVersion" ).toString(); -} -void LegacyInstance::setLWJGLVersion ( QString val ) -{ - I_D(LegacyInstance); - d->m_settings->set ( "LwjglVersion", val ); -} -QString LegacyInstance::intendedVersionId() const -{ - I_D(LegacyInstance); - return d->m_settings->get ( "IntendedJarVersion" ).toString(); -} -bool LegacyInstance::setIntendedVersionId ( QString version ) -{ - settings().set("IntendedJarVersion", version); - setShouldUpdate(true); - return true; -} -bool LegacyInstance::shouldUpdate() const -{ - I_D(LegacyInstance); - QVariant var = settings().get ( "ShouldUpdate" ); - if ( !var.isValid() || var.toBool() == false ) - { - return intendedVersionId() != currentVersionId(); - } - return true; -} -void LegacyInstance::setShouldUpdate ( bool val ) -{ - settings().set ( "ShouldUpdate", val ); -} diff --git a/backend/LegacyInstance.h b/backend/LegacyInstance.h deleted file mode 100644 index 6c9a295f..00000000 --- a/backend/LegacyInstance.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include "BaseInstance.h" - -class BaseUpdate; - -class LIBMULTIMC_EXPORT LegacyInstance : public BaseInstance -{ - Q_OBJECT -public: - - explicit LegacyInstance(const QString &rootDir, SettingsObject * settings, QObject *parent = 0); - - /// Path to the instance's minecraft.jar - QString mcJar() const; - - //! Path to the instance's mcbackup.jar - QString mcBackup() const; - - //! Path to the instance's modlist file. - QString modListFile() const; - - ////// Directories ////// - QString savesDir() const; - QString instModsDir() const; - QString binDir() const; - QString mlModsDir() const; - QString coreModsDir() const; - QString resourceDir() const; - - /*! - * \brief Checks whether or not the currentVersion of the instance needs to be updated. - * If this returns true, updateCurrentVersion is called. In the - * standard instance, this is determined by checking a timestamp - * stored in the instance config file against the last modified time of Minecraft.jar. - * \return True if updateCurrentVersion() should be called. - */ - bool shouldUpdateCurrentVersion() const; - - /*! - * \brief Updates the current version. - * This function should first set the current version timestamp - * (setCurrentVersionTimestamp()) to the current time. Next, if - * keepCurrent is false, this function should check what the - * instance's current version is and call setCurrentVersion() to - * update it. This function will automatically be called when the - * instance is loaded if shouldUpdateCurrentVersion returns true. - * \param keepCurrent If true, only the version timestamp will be updated. - */ - void updateCurrentVersion(bool keepCurrent = false); - - /*! - * Gets the last time that the current version was checked. - * This is checked against the last modified time on the jar file to see if - * the current version needs to be checked again. - */ - qint64 lastCurrentVersionUpdate() const; - void setLastCurrentVersionUpdate(qint64 val); - - /*! - * Whether or not the instance's minecraft.jar needs to be rebuilt. - * If this is true, when the instance launches, its jar mods will be - * re-added to a fresh minecraft.jar file. - */ - bool shouldRebuild() const; - void setShouldRebuild(bool val); - - virtual QString currentVersionId() const; - virtual void setCurrentVersionId(QString val); - - //! The version of LWJGL that this instance uses. - QString lwjglVersion() const; - /// st the version of LWJGL libs this instance will use - void setLWJGLVersion(QString val); - - virtual QString intendedVersionId() const; - virtual bool setIntendedVersionId ( QString version ); - - virtual bool shouldUpdate() const; - virtual void setShouldUpdate(bool val); - virtual BaseUpdate* doUpdate(); - - virtual MinecraftProcess* prepareForLaunch( QString user, QString session ); - virtual void cleanupAfterRun(); -}; \ No newline at end of file diff --git a/backend/LegacyInstance_p.h b/backend/LegacyInstance_p.h deleted file mode 100644 index ac367e20..00000000 --- a/backend/LegacyInstance_p.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include -#include -#include "BaseInstance_p.h" - -class BaseInstance; - -struct LegacyInstancePrivate: public BaseInstancePrivate -{ -}; \ No newline at end of file diff --git a/backend/LegacyUpdate.cpp b/backend/LegacyUpdate.cpp deleted file mode 100644 index a748bad3..00000000 --- a/backend/LegacyUpdate.cpp +++ /dev/null @@ -1,381 +0,0 @@ -#include "LegacyUpdate.h" -#include "lists/LwjglVersionList.h" -#include "lists/MinecraftVersionList.h" -#include "BaseInstance.h" -#include "LegacyInstance.h" -#include "net/NetWorker.h" -#include -#include -#include - - -LegacyUpdate::LegacyUpdate ( BaseInstance* inst, QObject* parent ) : BaseUpdate ( inst, parent ) {} - -void LegacyUpdate::executeTask() -{ - lwjglStart(); -} - -void LegacyUpdate::lwjglStart() -{ - LegacyInstance * inst = (LegacyInstance *) m_inst; - - lwjglVersion = inst->lwjglVersion(); - lwjglTargetPath = PathCombine("lwjgl", lwjglVersion ); - lwjglNativesPath = PathCombine( lwjglTargetPath, "natives/"); - - // if the 'done' file exists, we don't have to download this again - QFileInfo doneFile(PathCombine(lwjglTargetPath, "done")); - if(doneFile.exists()) - { - jarStart(); - return; - } - - auto &list = LWJGLVersionList::get(); - if(!list.isLoaded()) - { - emitFailed("Too soon! Let the LWJGL list load :)"); - return; - } - - setStatus("Downloading new LWJGL."); - auto version = list.getVersion(lwjglVersion); - if(!version) - { - emitFailed("Game update failed: the selected LWJGL version is invalid."); - return; - } - - QString url = version->url(); - QUrl realUrl(url); - QString hostname = realUrl.host(); - auto &worker = NetWorker::spawn(); - QNetworkRequest req(realUrl); - req.setRawHeader("Host", hostname.toLatin1()); - req.setHeader(QNetworkRequest::UserAgentHeader, "Wget/1.14 (linux-gnu)"); - QNetworkReply * rep = worker.get ( req ); - - m_reply = QSharedPointer (rep, &QObject::deleteLater); - connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); - connect(&worker, SIGNAL(finished(QNetworkReply*)), SLOT(lwjglFinished(QNetworkReply*))); - //connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError))); -} - -void LegacyUpdate::lwjglFinished(QNetworkReply* reply) -{ - if(m_reply != reply) - { - return; - } - if(reply->error() != QNetworkReply::NoError) - { - emitFailed( "Failed to download: "+ - reply->errorString()+ - "\nSometimes you have to wait a bit if you download many LWJGL versions in a row. YMMV"); - return; - } - auto &worker = NetWorker::spawn(); - //Here i check if there is a cookie for me in the reply and extract it - QList cookies = qvariant_cast>(reply->header(QNetworkRequest::SetCookieHeader)); - if(cookies.count() != 0) - { - //you must tell which cookie goes with which url - worker.cookieJar()->setCookiesFromUrl(cookies, QUrl("sourceforge.net")); - } - - //here you can check for the 302 or whatever other header i need - QVariant newLoc = reply->header(QNetworkRequest::LocationHeader); - if(newLoc.isValid()) - { - auto &worker = NetWorker::spawn(); - QString redirectedTo = reply->header(QNetworkRequest::LocationHeader).toString(); - QUrl realUrl(redirectedTo); - QString hostname = realUrl.host(); - QNetworkRequest req(redirectedTo); - req.setRawHeader("Host", hostname.toLatin1()); - req.setHeader(QNetworkRequest::UserAgentHeader, "Wget/1.14 (linux-gnu)"); - QNetworkReply * rep = worker.get(req); - connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); - m_reply = QSharedPointer (rep, &QObject::deleteLater); - return; - } - QFile saveMe("lwjgl.zip"); - saveMe.open(QIODevice::WriteOnly); - saveMe.write(m_reply->readAll()); - saveMe.close(); - setStatus("Installing new LWJGL..."); - extractLwjgl(); - jarStart(); -} -void LegacyUpdate::extractLwjgl() -{ - // make sure the directories are there - - bool success = ensurePathExists(lwjglNativesPath); - - if(!success) - { - emitFailed("Failed to extract the lwjgl libs - error when creating required folders."); - return; - } - - QuaZip zip("lwjgl.zip"); - if(!zip.open(QuaZip::mdUnzip)) - { - emitFailed("Failed to extract the lwjgl libs - not a valid archive."); - return; - } - - // and now we are going to access files inside it - QuaZipFile file(&zip); - const QString jarNames[] = { "jinput.jar", "lwjgl_util.jar", "lwjgl.jar" }; - for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) - { - if(!file.open(QIODevice::ReadOnly)) - { - zip.close(); - emitFailed("Failed to extract the lwjgl libs - error while reading archive."); - return; - } - QuaZipFileInfo info; - QString name = file.getActualFileName(); - if(name.endsWith('/')) - { - file.close(); - continue; - } - QString destFileName; - // Look for the jars - for (int i = 0; i < 3; i++) - { - if (name.endsWith(jarNames[i])) - { - destFileName = PathCombine(lwjglTargetPath, jarNames[i]); - } - } - // Not found? look for the natives - if(destFileName.isEmpty()) - { -#ifdef Q_OS_WIN32 - QString nativesDir = "windows"; -#elif Q_OS_MAC - QString nativesDir = "macosx"; -#else - QString nativesDir = "linux"; -#endif - if (name.contains(nativesDir)) - { - int lastSlash = name.lastIndexOf('/'); - int lastBackSlash = name.lastIndexOf('/'); - if(lastSlash != -1) - name = name.mid(lastSlash+1); - else if(lastBackSlash != -1) - name = name.mid(lastBackSlash+1); - destFileName = PathCombine(lwjglNativesPath, name); - } - } - // Now if destFileName is still empty, go to the next file. - if (!destFileName.isEmpty()) - { - setStatus("Installing new LWJGL - Extracting " + name); - QFile output(destFileName); - output.open(QIODevice::WriteOnly); - output.write(file.readAll()); // FIXME: wste of memory!? - output.close(); - } - file.close(); // do not forget to close! - } - zip.close(); - m_reply.clear(); - QFile doneFile(PathCombine(lwjglTargetPath, "done")); - doneFile.open(QIODevice::WriteOnly); - doneFile.write("done."); - doneFile.close(); -} - -void LegacyUpdate::lwjglFailed() -{ - emitFailed("Bad stuff happened while trying to get the lwjgl libs..."); -} - -void LegacyUpdate::jarStart() -{ - setStatus("Checking ..."); - LegacyInstance * inst = (LegacyInstance *) m_inst; - QString current_version_id = inst->currentVersionId(); - QString intended_version_id = inst->intendedVersionId(); - bool shouldUpdate = inst->shouldUpdate(); - if(!shouldUpdate) - { - emitSucceeded(); - return; - } - - // nuke the backup file, we are replacing the base jar anyway - QFile mc_backup(inst->mcBackup()); - if (mc_backup.exists()) - { - mc_backup.remove(); - } - - // Get a pointer to the version object that corresponds to the instance's version. - auto targetVersion = MinecraftVersionList::getMainList().findVersion(intended_version_id); - - if(!targetVersion) - { - emitFailed("Not a valid version:" + intended_version_id); - return; - } - - // Make directories - QDir binDir(inst->binDir()); - if (!binDir.exists() && !binDir.mkpath(".")) - { - emitFailed("Failed to create bin folder."); - return; - } - - // Build a list of URLs that will need to be downloaded. - setStatus("Downloading new minecraft.jar"); - - // This will be either 'minecraft' or the version number, depending on where - // we're downloading from. - QString jarFilename = "minecraft"; - QString download_path = PathCombine(inst->minecraftRoot(), "bin/minecraft.jar"); - - QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/"); - urlstr += targetVersion->descriptor + "/" + targetVersion->descriptor + ".jar"; - auto dljob = DownloadJob::create(QUrl(urlstr), download_path); - - legacyDownloadJob.reset(new JobList()); - legacyDownloadJob->add(dljob); - connect(legacyDownloadJob.data(), SIGNAL(finished()), SLOT(jarFinished())); - connect(legacyDownloadJob.data(), SIGNAL(failed()), SLOT(jarFailed())); - connect(legacyDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); - download_queue.enqueue(legacyDownloadJob); -} - -void LegacyUpdate::jarFinished() -{ - // process the jar - emitSucceeded(); -} - -void LegacyUpdate::jarFailed() -{ - // bad, bad - emitFailed("Failed to download the minecraft jar. Try again later."); -} - -void LegacyUpdate::ModTheJar() -{ - /* - LegacyInstance * inst = (LegacyInstance *) m_inst; - // Get the mod list - auto modList = inst->getJarModList(); - - QFileInfo mcBin(inst->binDir()); - QFileInfo mcJar(inst->mcJar()); - QFileInfo mcBackup(inst->mcBackup()); - - // Nothing to do if there are no jar mods to install, no backup and just the mc jar - if(mcJar.isFile() && !mcBackup.exists() && modList->empty()) - { - inst->setShouldRebuild(false); - emitSucceeded(); - return; - } - - setStatus("Installing mods - backing up minecraft.jar..."); - if (!mcBackup.exists() && !QFile::copy(mcJar.absoluteFilePath(), mcBackup.absoluteFilePath()) ) - { - emitFailed("Failed to back up minecraft.jar"); - return; - } - - if (mcJar.isFile() && !QFile::remove(mcJar.absoluteFilePath())) - { - emitFailed("Failed to delete old minecraft.jar"); - return; - } - - setStatus("Installing mods - Opening minecraft.jar"); - - wxFFileOutputStream jarStream(mcJar.absoluteFilePath()); - wxZipOutputStream zipOut(jarStream); - - // Files already added to the jar. - // These files will be skipped. - QSet addedFiles; - - // Modify the jar - setStatus("Installing mods - Adding mod files..."); - for (ModList::const_reverse_iterator iter = modList->rbegin(); iter != modList->rend(); iter++) - { - wxFileName modFileName = iter->GetFileName(); - setStatus("Installing mods - Adding " + modFileName.GetFullName()); - if (iter->GetModType() == Mod::ModType::MOD_ZIPFILE) - { - wxFFileInputStream modStream(modFileName.GetFullPath()); - wxZipInputStream zipStream(modStream); - std::unique_ptr entry; - while (entry.reset(zipStream.GetNextEntry()), entry.get() != NULL) - { - if (entry->IsDir()) - continue; - - wxString name = entry->GetName(); - if (addedFiles.count(name) == 0) - { - if (!zipOut.CopyEntry(entry.release(), zipStream)) - break; - addedFiles.insert(name); - } - } - } - else - { - wxFileName destFileName = modFileName; - destFileName.MakeRelativeTo(m_inst->GetInstModsDir().GetFullPath()); - wxString destFile = destFileName.GetFullPath(); - - if (addedFiles.count(destFile) == 0) - { - wxFFileInputStream input(modFileName.GetFullPath()); - zipOut.PutNextEntry(destFile); - zipOut.Write(input); - - addedFiles.insert(destFile); - } - } - } - - { - wxFFileInputStream inStream(mcBackup.GetFullPath()); - wxZipInputStream zipIn(inStream); - - std::auto_ptr entry; - while (entry.reset(zipIn.GetNextEntry()), entry.get() != NULL) - { - wxString name = entry->GetName(); - - if (!name.Matches("META-INF*") && - addedFiles.count(name) == 0) - { - if (!zipOut.CopyEntry(entry.release(), zipIn)) - break; - addedFiles.insert(name); - } - } - } - - // Recompress the jar - TaskStep(); // STEP 3 - SetStatus(_("Installing mods - Recompressing jar...")); - - inst->SetNeedsRebuild(false); - inst->UpdateVersion(true); - return (ExitCode)1; - */ -} \ No newline at end of file diff --git a/backend/LegacyUpdate.h b/backend/LegacyUpdate.h deleted file mode 100644 index a48189a6..00000000 --- a/backend/LegacyUpdate.h +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -#include "net/DownloadJob.h" -#include "tasks/Task.h" -#include "libmmc_config.h" -#include "BaseUpdate.h" - -class MinecraftVersion; -class BaseInstance; - -class LIBMULTIMC_EXPORT LegacyUpdate : public BaseUpdate -{ - Q_OBJECT -public: - explicit LegacyUpdate(BaseInstance *inst, QObject *parent = 0); - virtual void executeTask(); - -private slots: - void lwjglStart(); - void lwjglFinished( QNetworkReply* ); - void lwjglFailed(); - - void jarStart(); - void jarFinished(); - void jarFailed(); - - void extractLwjgl(); - - void ModTheJar(); -private: - - QSharedPointer m_reply; - - // target version, determined during this task - // MinecraftVersion *targetVersion; - QString lwjglURL; - QString lwjglVersion; - - QString lwjglTargetPath; - QString lwjglNativesPath; -private: - JobListPtr legacyDownloadJob; - JobListQueue download_queue; - - // target version, determined during this task - QSharedPointer targetVersion; -}; - - diff --git a/backend/MinecraftProcess.cpp b/backend/MinecraftProcess.cpp deleted file mode 100644 index d34be835..00000000 --- a/backend/MinecraftProcess.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "MinecraftProcess.h" - -#include -#include -#include -//#include -#include - -#include "BaseInstance.h" - -#include "osutils.h" -#include "pathutils.h" -#include "cmdutils.h" - -#define IBUS "@im=ibus" - -// constructor -MinecraftProcess::MinecraftProcess( BaseInstance* inst ) : - m_instance(inst) -{ - connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(finish(int, QProcess::ExitStatus))); - - // prepare the process environment - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - -#ifdef LINUX - // Strip IBus - if (env.value("XMODIFIERS").contains(IBUS)) - env.insert("XMODIFIERS", env.value("XMODIFIERS").replace(IBUS, "")); -#endif - - // export some infos - env.insert("INST_NAME", inst->name()); - env.insert("INST_ID", inst->id()); - env.insert("INST_DIR", QDir(inst->instanceRoot()).absolutePath()); - - this->setProcessEnvironment(env); - m_prepostlaunchprocess.setProcessEnvironment(env); - - // std channels - connect(this, SIGNAL(readyReadStandardError()), SLOT(on_stdErr())); - connect(this, SIGNAL(readyReadStandardOutput()), SLOT(on_stdOut())); -} - -void MinecraftProcess::setMinecraftArguments ( QStringList args ) -{ - m_args = args; -} - -void MinecraftProcess::setMinecraftWorkdir ( QString path ) -{ - QDir mcDir(path); - this->setWorkingDirectory(mcDir.absolutePath()); - m_prepostlaunchprocess.setWorkingDirectory(mcDir.absolutePath()); -} - - -// console window -void MinecraftProcess::on_stdErr() -{ - QByteArray data = readAllStandardError(); - QString str = m_err_leftover + QString::fromLocal8Bit(data); - m_err_leftover.clear(); - QStringList lines = str.split("\n"); - bool complete = str.endsWith("\n"); - - for(int i = 0; i < lines.size() - 1; i++) - { - QString & line = lines[i]; - MessageLevel::Enum level = MessageLevel::Error; - if(line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || line.contains("[FINER]") || line.contains("[FINEST]") ) - level = MessageLevel::Message; - if(line.contains("[SEVERE]") || line.contains("[WARNING]") || line.contains("[STDERR]")) - level = MessageLevel::Error; - emit log(lines[i].toLocal8Bit(), level); - } - if(!complete) - m_err_leftover = lines.last(); -} - -void MinecraftProcess::on_stdOut() -{ - QByteArray data = readAllStandardOutput(); - QString str = m_out_leftover + QString::fromLocal8Bit(data); - m_out_leftover.clear(); - QStringList lines = str.split("\n"); - bool complete = str.endsWith("\n"); - - for(int i = 0; i < lines.size() - 1; i++) - { - QString & line = lines[i]; - emit log(lines[i].toLocal8Bit(), MessageLevel::Message); - } - if(!complete) - m_out_leftover = lines.last(); -} - -// exit handler -void MinecraftProcess::finish(int code, ExitStatus status) -{ - if (status != NormalExit) - { - //TODO: error handling - } - - emit log("Minecraft exited."); - - m_prepostlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(code)); - - // run post-exit - if (!m_instance->settings().get("PostExitCommand").toString().isEmpty()) - { - m_prepostlaunchprocess.start(m_instance->settings().get("PostExitCommand").toString()); - m_prepostlaunchprocess.waitForFinished(); - if (m_prepostlaunchprocess.exitStatus() != NormalExit) - { - //TODO: error handling - } - } - m_instance->cleanupAfterRun(); - emit ended(); -} - -void MinecraftProcess::launch() -{ - if (!m_instance->settings().get("PreLaunchCommand").toString().isEmpty()) - { - m_prepostlaunchprocess.start(m_instance->settings().get("PreLaunchCommand").toString()); - m_prepostlaunchprocess.waitForFinished(); - if (m_prepostlaunchprocess.exitStatus() != NormalExit) - { - //TODO: error handling - return; - } - } - - m_instance->setLastLaunch(); - - emit log(QString("Minecraft folder is: '%1'").arg(workingDirectory())); - QString JavaPath = m_instance->settings().get("JavaPath").toString(); - emit log(QString("Java path: '%1'").arg(JavaPath)); - emit log(QString("Arguments: '%1'").arg(m_args.join("' '"))); - start(JavaPath, m_args); - if (!waitForStarted()) - { - emit log("Could not launch minecraft!"); - return; - //TODO: error handling - } -} - - diff --git a/backend/MinecraftProcess.h b/backend/MinecraftProcess.h deleted file mode 100644 index 756d2de5..00000000 --- a/backend/MinecraftProcess.h +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include - -#include "BaseInstance.h" - -#include "libmmc_config.h" - -/** - * @brief the MessageLevel Enum - * defines what level a message is - */ -namespace MessageLevel { -enum LIBMULTIMC_EXPORT Enum { - MultiMC, /**< MultiMC Messages */ - Debug, /**< Debug Messages */ - Info, /**< Info Messages */ - Message, /**< Standard Messages */ - Warning, /**< Warnings */ - Error, /**< Errors */ - Fatal /**< Fatal Errors */ -}; -} - -/** - * @file data/minecraftprocess.h - * @brief The MinecraftProcess class - */ -class LIBMULTIMC_EXPORT MinecraftProcess : public QProcess -{ - Q_OBJECT -public: - /** - * @brief MinecraftProcess constructor - * @param inst the Instance pointer to launch - */ - MinecraftProcess(BaseInstance *inst); - - /** - * @brief launch minecraft - */ - void launch(); - - void setMinecraftWorkdir(QString path); - - void setMinecraftArguments(QStringList args); - -signals: - /** - * @brief emitted when mc has finished and the PostLaunchCommand was run - */ - void ended(); - - /** - * @brief emitted when we want to log something - * @param text the text to log - * @param level the level to log at - */ - void log(QString text, MessageLevel::Enum level=MessageLevel::MultiMC); - -protected: - BaseInstance *m_instance; - QStringList m_args; - QString m_err_leftover; - QString m_out_leftover; - QProcess m_prepostlaunchprocess; - -protected slots: - void finish(int, QProcess::ExitStatus status); - void on_stdErr(); - void on_stdOut(); -}; diff --git a/backend/MinecraftVersion.h b/backend/MinecraftVersion.h deleted file mode 100644 index 5cd29925..00000000 --- a/backend/MinecraftVersion.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright 2013 Andrew Okin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "libmmc_config.h" - -#include "InstanceVersion.h" -#include - -struct LIBMULTIMC_EXPORT MinecraftVersion : public InstVersion -{ - // From InstVersion: - /* - QString m_descriptor; - QString m_name; - qint64 m_timestamp; - */ - - /// The URL that this version will be downloaded from. maybe. - QString download_url; - - /// This version's type. Used internally to identify what kind of version this is. - enum VersionType - { - OneSix, - Legacy, - Nostalgia - } type; - - /// is this the latest version? - bool is_latest = false; - - /// is this a snapshot? - bool is_snapshot = false; - - virtual QString typeString() const - { - QStringList pre_final; - if(is_latest == true) - { - pre_final.append("Latest"); - } - switch (type) - { - case OneSix: - pre_final.append("OneSix"); - break; - case Legacy: - pre_final.append("Legacy"); - break; - case Nostalgia: - pre_final.append("Nostalgia"); - break; - - default: - pre_final.append(QString("Type(%1)").arg(type)); - break; - } - if(is_snapshot == true) - { - pre_final.append("Snapshot"); - } - return pre_final.join(' '); - } -}; diff --git a/backend/Mod.cpp b/backend/Mod.cpp deleted file mode 100644 index 652bbda7..00000000 --- a/backend/Mod.cpp +++ /dev/null @@ -1,264 +0,0 @@ -// -// Copyright 2012 MultiMC Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "Mod.h" -#include -#include - -Mod::Mod( const QFileInfo& file ) -{ - repath(file); -} - -void Mod::repath ( const QFileInfo& file ) -{ - m_file = file; - m_name = file.baseName(); - m_id = file.fileName(); - - m_type = Mod::MOD_UNKNOWN; - if (m_file.isDir()) - m_type = MOD_FOLDER; - else if (m_file.isFile()) - { - QString ext = m_file.suffix().toLower(); - if (ext == "zip" || ext == "jar") - m_type = MOD_ZIPFILE; - else - m_type = MOD_SINGLEFILE; - } - - /* - switch (modType) - { - case MOD_ZIPFILE: - { - wxFFileInputStream fileIn(modFile.GetFullPath()); - wxZipInputStream zipIn(fileIn); - - std::auto_ptr entry; - - bool is_forge = false; - while(true) - { - entry.reset(zipIn.GetNextEntry()); - if (entry.get() == nullptr) - break; - if(entry->GetInternalName().EndsWith("mcmod.info")) - break; - if(entry->GetInternalName().EndsWith("forgeversion.properties")) - { - is_forge = true; - break; - } - } - - if (entry.get() != nullptr) - { - // Read the info file into text - wxString infoFileData; - wxStringOutputStream stringOut(&infoFileData); - zipIn.Read(stringOut); - if(!is_forge) - ReadModInfoData(infoFileData); - else - ReadForgeInfoData(infoFileData); - } - } - break; - - case MOD_FOLDER: - { - wxString infoFile = Path::Combine(modFile, "mcmod.info"); - if (!wxFileExists(infoFile)) - { - infoFile = wxEmptyString; - - wxDir modDir(modFile.GetFullPath()); - - if (!modDir.IsOpened()) - { - wxLogError(_("Can't fine mod info file. Failed to open mod folder.")); - break; - } - - wxString currentFile; - if (modDir.GetFirst(¤tFile)) - { - do - { - if (currentFile.EndsWith("mcmod.info")) - { - infoFile = Path::Combine(modFile.GetFullPath(), currentFile); - break; - } - } while (modDir.GetNext(¤tFile)); - } - } - - if (infoFile != wxEmptyString && wxFileExists(infoFile)) - { - wxString infoStr; - wxFFileInputStream fileIn(infoFile); - wxStringOutputStream strOut(&infoStr); - fileIn.Read(strOut); - ReadModInfoData(infoStr); - } - } - break; - } -*/ -} - - -/* -void ReadModInfoData(QString info) -{ - using namespace boost::property_tree; - - // Read the data - ptree ptRoot; - - std::stringstream stringIn(cStr(info)); - try - { - read_json(stringIn, ptRoot); - - ptree pt = ptRoot.get_child(ptRoot.count("modlist") == 1 ? "modlist" : "").begin()->second; - - modID = wxStr(pt.get("modid")); - modName = wxStr(pt.get("name")); - modVersion = wxStr(pt.get("version")); - } - catch (json_parser_error e) - { - // Silently fail... - } - catch (ptree_error e) - { - // Silently fail... - } -} -*/ - -// FIXME: abstraction violated. -/* -void Mod::ReadForgeInfoData(QString infoFileData) -{ - using namespace boost::property_tree; - - // Read the data - ptree ptRoot; - modName = "Minecraft Forge"; - modID = "Forge"; - std::stringstream stringIn(cStr(infoFileData)); - try - { - read_ini(stringIn, ptRoot); - wxString major, minor, revision, build; - // BUG: boost property tree is bad. won't let us get a key with dots in it - // Likely cause = treating the dots as path separators. - for (auto iter = ptRoot.begin(); iter != ptRoot.end(); iter++) - { - auto &item = *iter; - std::string key = item.first; - std::string value = item.second.get_value(); - if(key == "forge.major.number") - major = value; - if(key == "forge.minor.number") - minor = value; - if(key == "forge.revision.number") - revision = value; - if(key == "forge.build.number") - build = value; - } - modVersion.Empty(); - modVersion << major << "." << minor << "." << revision << "." << build; - } - catch (json_parser_error e) - { - std::cerr << e.what(); - } - catch (ptree_error e) - { - std::cerr << e.what(); - } -} -*/ - -bool Mod::replace ( Mod& with ) -{ - if(!destroy()) - return false; - bool success = false; - auto t = with.type(); - if(t == MOD_ZIPFILE || t == MOD_SINGLEFILE) - { - success = QFile::copy(with.m_file.filePath(), m_file.path()); - } - if(t == MOD_FOLDER) - { - success = copyPath(with.m_file.filePath(), m_file.path()); - } - if(success) - { - m_id = with.m_id; - m_mcversion = with.m_mcversion; - m_type = with.m_type; - m_name = with.m_name; - m_version = with.m_version; - } - return success; -} - -bool Mod::destroy() -{ - if(m_type == MOD_FOLDER) - { - QDir d(m_file.filePath()); - if(d.removeRecursively()) - { - m_type = MOD_UNKNOWN; - return true; - } - return false; - } - else if (m_type == MOD_SINGLEFILE || m_type == MOD_ZIPFILE) - { - QFile f(m_file.filePath()); - if(f.remove()) - { - m_type = MOD_UNKNOWN; - return true; - } - return false; - } - return true; -} - - -QString Mod::version() const -{ - switch(type()) - { - case MOD_ZIPFILE: - return m_version; - case MOD_FOLDER: - return "Folder"; - case MOD_SINGLEFILE: - return "File"; - } -} diff --git a/backend/Mod.h b/backend/Mod.h deleted file mode 100644 index d9d90426..00000000 --- a/backend/Mod.h +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright 2012 MultiMC Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#pragma once -#include - -class Mod -{ -public: - enum ModType - { - MOD_UNKNOWN, //!< Indicates an unspecified mod type. - MOD_ZIPFILE, //!< The mod is a zip file containing the mod's class files. - MOD_SINGLEFILE, //!< The mod is a single file (not a zip file). - MOD_FOLDER, //!< The mod is in a folder on the filesystem. - }; - - Mod(const QFileInfo &file); - - QFileInfo filename() const { return m_file; } - QString id() const { return m_id; } - ModType type() const { return m_type; } - QString mcversion() const; - bool valid() {return m_type != MOD_UNKNOWN;} - - QString version() const; - - // delete all the files of this mod - bool destroy(); - // replace this mod with a copy of the other - bool replace(Mod & with); - // change the mod's filesystem path (used by mod lists for *MAGIC* purposes) - void repath(const QFileInfo &file); - - - bool operator ==(const Mod &other) const - { - return filename() == other.filename(); - } - -protected: - - //FIXME: what do do with those? HMM... - /* - void ReadModInfoData(QString info); - void ReadForgeInfoData(QString infoFileData); - */ - - QFileInfo m_file; - QString m_id; - QString m_name; - QString m_version; - QString m_mcversion; - - ModType m_type; -}; diff --git a/backend/ModList.cpp b/backend/ModList.cpp deleted file mode 100644 index 851eb940..00000000 --- a/backend/ModList.cpp +++ /dev/null @@ -1,418 +0,0 @@ -// -// Copyright 2012 MultiMC Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "ModList.h" -#include "LegacyInstance.h" -#include - -ModList::ModList ( const QString& dir ) : QObject(), m_dir(dir) -{ - m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs | QDir::NoSymLinks); - m_dir.setSorting(QDir::Name); - update(); -} - -bool ModList::update() -{ - if (!isValid()) - return false; - - bool initial = mods.empty(); - - bool listChanged = false; - - auto list = m_dir.entryInfoList(); - for(auto entry: list) - { - Mod mod(entry); - if (initial || !mods.contains(mod)) - { - mods.push_back(mod); - listChanged = true; - } - } - return listChanged; -} - -bool ModList::isValid() -{ - return m_dir.exists() && m_dir.isReadable(); -} - -bool ModList::installMod ( const QFileInfo& filename, size_t index ) -{ - if(!filename.exists() || !filename.isReadable()) - { - return false; - } - Mod m(filename); - if(!m.valid()) - return false; - - // if it's already there, replace the original mod (in place) - int idx = mods.indexOf(m); - if(idx != -1) - { - if(mods[idx].replace(m)) - { - emit changed(); - return true; - } - return false; - } - - auto type = m.type(); - if(type == Mod::MOD_UNKNOWN) - return false; - if(type == Mod::MOD_SINGLEFILE || type == Mod::MOD_ZIPFILE) - { - QString newpath = PathCombine(m_dir.path(), filename.fileName()); - if(!QFile::copy(filename.filePath(), newpath)) - return false; - m.repath(newpath); - mods.append(m); - emit changed(); - return true; - } - else if(type == Mod::MOD_FOLDER) - { - QString newpath = PathCombine(m_dir.path(), filename.fileName()); - if(!copyPath(filename.filePath(), newpath)) - return false; - m.repath(newpath); - mods.append(m); - emit changed(); - return true; - } - return false; -} - -bool ModList::deleteMod ( size_t index ) -{ - if(index >= mods.size()) - return false; - Mod & m = mods[index]; - if(m.destroy()) - { - mods.erase(mods.begin() + index); - emit changed(); - return true; - } - return false; -} - - -/* -ModList::ModList(const QString &dir) - : modsFolder(dir) -{ - -} - -bool ModList::update(bool quickLoad) -{ - bool listChanged = false; - - // Check for mods in the list whose files do not exist and remove them from the list. - // If doing a quickLoad, erase the whole list. - for (size_t i = 0; i < size(); i++) - { - if (quickLoad || !at(i).GetFileName().FileExists()) - { - erase(begin() + i); - i--; - listChanged = true; - } - } - - // Add any mods in the mods folder that aren't already in the list. - if (LoadModListFromDir(QString(), quickLoad)) - listChanged = true; - - return listChanged; -} - -bool ModList::LoadModListFromDir(const QString& loadFrom, bool quickLoad) -{ - QString dir(loadFrom.isEmpty() ? modsFolder : loadFrom); - - QDir modDir(dir); - if (!modDir.exists()) - return false; - - bool listChanged = false; - - auto list = modDir.entryInfoList(QDir::Readable|QDir::NoDotAndDotDot, QDir::Name); - for(auto currentFile: list) - { - if (currentFile.isFile()) - { - if (quickLoad || FindByFilename(currentFile.absoluteFilePath()) == nullptr) - { - Mod mod(currentFile.absoluteFilePath()); - push_back(mod); - listChanged = true; - } - } - else if (currentFile.isDir()) - { - if (LoadModListFromDir(currentFile.absoluteFilePath())) - listChanged = true; - } - } - - return listChanged; -} - -Mod *ModList::FindByFilename(const QString& filename) -{ - // Search the list for a mod with the given filename. - for (auto iter = begin(); iter != end(); ++iter) - { - if (iter->GetFileName() == QFileInfo(filename)) - return &(*iter); - } - - // If nothing is found, return nullptr. - return nullptr; -} - -int ModList::FindIndexByFilename(const QString& filename) -{ - // Search the list for a mod with the given filename. - int i = 0; - for (auto iter = begin(); iter != end(); ++iter, i++) - { - if (iter->GetFileName() == QFileInfo(filename)) - return i; - } - - // If nothing is found, return nullptr. - return -1; -} - -Mod* ModList::FindByID(const QString& modID, const QString& modVersion) -{ - // Search the list for a mod that matches - for (auto iter = begin(); iter != end(); ++iter) - { - QString ID = iter->GetModID(); - QString version = iter->GetModVersion(); - if ( ID == modID && version == modVersion) - return &(*iter); - } - - // If nothing is found, return nullptr. - return nullptr; -} - -void ModList::LoadFromFile(const QString& file) -{ - if (!wxFileExists(file)) - return; - - wxFFileInputStream inputStream(file); - wxArrayString modListFile = ReadAllLines(inputStream); - - for (wxArrayString::iterator iter = modListFile.begin(); iter != modListFile.end(); iter++) - { - // Normalize the path to the instMods dir. - wxFileName modFile(*iter); - modFile.Normalize(wxPATH_NORM_ALL, modsFolder); - modFile.MakeRelativeTo(); - // if the file is gone, do not load it - if(!modFile.Exists()) - { - continue; - } - - if (FindByFilename(modFile.GetFullPath()) == nullptr) - { - push_back(Mod(modFile)); - } - } -} - -void ModList::SaveToFile(const QString& file) -{ - QString text; - for (iterator iter = begin(); iter != end(); ++iter) - { - wxFileName modFile = iter->GetFileName(); - modFile.MakeRelativeTo(modsFolder); - text.append(modFile.GetFullPath()); - text.append("\n"); - } - - wxTempFileOutputStream out(file); - WriteAllText(out, text); - out.Commit(); -} - -bool ModList::InsertMod(size_t index, const QString &filename, const QString& saveToFile) -{ - QFileInfo source(filename); - QFileInfo dest(PathCombine(modsFolder, source.fileName())); - - if (source != dest) - { - QFile::copy(source.absoluteFilePath(), dest.absoluteFilePath()); - } - - int oldIndex = FindIndexByFilename(dest.absoluteFilePath()); - - if (oldIndex != -1) - { - erase(begin() + oldIndex); - } - - if (index >= size()) - push_back(Mod(dest)); - else - insert(begin() + index, Mod(dest)); - - if (!saveToFile.isEmpty()) - SaveToFile(saveToFile); - - return true; -} - -bool ModList::DeleteMod(size_t index, const QString& saveToFile) -{ - Mod *mod = &at(index); - if(mod->GetModType() == Mod::MOD_FOLDER) - { - QDir dir(mod->GetFileName().absoluteFilePath()); - if(dir.removeRecursively()) - { - erase(begin() + index); - - if (!saveToFile.isEmpty()) - SaveToFile(saveToFile); - - return true; - } - else - { - // wxLogError(_("Failed to delete mod.")); - } - } - else if (QFile(mod->GetFileName().absoluteFilePath()).remove()) - { - erase(begin() + index); - - if (!saveToFile.isEmpty()) - SaveToFile(saveToFile); - - return true; - } - else - { - // wxLogError(_("Failed to delete mod.")); - } - return false; -} - -bool JarModList::InsertMod(size_t index, const QString &filename, const QString& saveToFile) -{ - QString saveFile = saveToFile; - if (saveToFile.isEmpty()) - saveFile = m_inst->GetModListFile().GetFullPath(); - - if (ModList::InsertMod(index, filename, saveFile)) - { - m_inst->setLWJGLVersion(true); - return true; - } - return false; -} - -bool JarModList::DeleteMod(size_t index, const QString& saveToFile) -{ - QString saveFile = saveToFile; - if (saveToFile.IsEmpty()) - saveFile = m_inst->GetModListFile().GetFullPath(); - - if (ModList::DeleteMod(index, saveFile)) - { - m_inst->SetNeedsRebuild(); - return true; - } - return false; -} - -bool JarModList::UpdateModList(bool quickLoad) -{ - if (ModList::UpdateModList(quickLoad)) - { - m_inst->SetNeedsRebuild(); - return true; - } - return false; -} - -bool FolderModList::LoadModListFromDir(const QString& loadFrom, bool quickLoad) -{ - QString dir(loadFrom.IsEmpty() ? modsFolder : loadFrom); - - if (!wxDirExists(dir)) - return false; - - bool listChanged = false; - wxDir modDir(dir); - - if (!modDir.IsOpened()) - { - wxLogError(_("Failed to open directory: ") + dir); - return false; - } - - QString currentFile; - if (modDir.GetFirst(¤tFile)) - { - do - { - wxFileName modFile(Path::Combine(dir, currentFile)); - - if (wxFileExists(modFile.GetFullPath()) || wxDirExists(modFile.GetFullPath())) - { - if (quickLoad || FindByFilename(modFile.GetFullPath()) == nullptr) - { - Mod mod(modFile.GetFullPath()); - push_back(mod); - listChanged = true; - } - } - } while (modDir.GetNext(¤tFile)); - } - - return listChanged; -} - -bool ModNameSort (const Mod & i,const Mod & j) -{ - if(i.GetModType() == j.GetModType()) - return (i.GetName().toLower() < j.GetName().toLower()); - return (i.GetModType() < j.GetModType()); -} - -bool FolderModList::UpdateModList ( bool quickLoad ) -{ - bool changed = ModList::UpdateModList(quickLoad); - std::sort(begin(),end(),ModNameSort); - return changed; -} -*/ diff --git a/backend/ModList.h b/backend/ModList.h deleted file mode 100644 index bf65a080..00000000 --- a/backend/ModList.h +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright 2012 MultiMC Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -#pragma once - -class LegacyInstance; -class BaseInstance; -#include -#include -#include - -#include "Mod.h" - -/** - * A basic mod list. - * Backed by a folder. - */ -class ModList : public QObject -{ - Q_OBJECT -public: - ModList(const QString& dir = QString()); - - size_t size() { return mods.size(); }; - Mod& operator[](size_t index) { return mods[index]; }; - - /// Reloads the mod list and returns true if the list changed. - virtual bool update(); - - /// Adds the given mod to the list at the given index. - virtual bool installMod(const QFileInfo& filename, size_t index = 0); - - /// Deletes the mod at the given index. - virtual bool deleteMod(size_t index); - - /** - * move the mod at index to the position N - * 0 is the beginning of the list, length() is the end of the list. - */ - virtual bool moveMod(size_t from, size_t to) { return false; }; - - virtual bool isValid(); - -signals: - virtual void changed(); -protected: - QDir m_dir; - QList mods; -}; - -/** - * A jar mod list. - * Backed by a folder and a file which specifies the load order. - */ -class JarModList : public ModList -{ - Q_OBJECT -public: - JarModList(const QString& dir, const QString& list_file, LegacyInstance * inst) - : ModList(dir), m_listfile(list_file), m_inst(inst) {} - - virtual bool update(); - virtual bool installMod(const QString &filename, size_t index); - virtual bool deleteMod(size_t index); - virtual bool moveMod(size_t from, size_t to); -protected: - QString m_listfile; - LegacyInstance * m_inst; -}; diff --git a/backend/NostalgiaInstance.cpp b/backend/NostalgiaInstance.cpp deleted file mode 100644 index 0a7f3c5a..00000000 --- a/backend/NostalgiaInstance.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "NostalgiaInstance.h" - -NostalgiaInstance::NostalgiaInstance ( const QString& rootDir, SettingsObject* settings, QObject* parent ) - : OneSixInstance ( rootDir, settings, parent ) -{ - -} - -/* -ADD MORE - IF REQUIRED -*/ diff --git a/backend/NostalgiaInstance.h b/backend/NostalgiaInstance.h deleted file mode 100644 index 7c48713b..00000000 --- a/backend/NostalgiaInstance.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "OneSixInstance.h" - -class LIBMULTIMC_EXPORT NostalgiaInstance : public OneSixInstance -{ - Q_OBJECT -public: - explicit NostalgiaInstance(const QString &rootDir, SettingsObject * settings, QObject *parent = 0); -}; diff --git a/backend/OneSixAssets.cpp b/backend/OneSixAssets.cpp deleted file mode 100644 index db9e7421..00000000 --- a/backend/OneSixAssets.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include -#include -#include -#include "OneSixAssets.h" -#include "net/DownloadJob.h" - -inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname) -{ - QDomNodeList elementList = parent.elementsByTagName(tagname); - if (elementList.count()) - return elementList.at(0).toElement(); - else - return QDomElement(); -} - -class ThreadedDeleter : public QThread -{ - Q_OBJECT -public: - void run() - { - QDirIterator iter(m_base, QDirIterator::Subdirectories); - QStringList nuke_list; - int base_length = m_base.length(); - while (iter.hasNext()) - { - QString filename = iter.next(); - QFileInfo current(filename); - // we keep the dirs... whatever - if(current.isDir()) - continue; - QString trimmedf = filename; - trimmedf.remove(0, base_length + 1); - if(m_whitelist.contains(trimmedf)) - { - // qDebug() << trimmedf << " gets to live"; - } - else - { - // DO NOT TOLERATE JUNK - // qDebug() << trimmedf << " dies"; - QFile f (filename); - f.remove(); - } - } - }; - QString m_base; - QStringList m_whitelist; -}; - -class NukeAndPaveJob: public Job -{ - Q_OBJECT -public: - - explicit NukeAndPaveJob(QString base, QStringList whitelist) - :Job() - { - QDir dir(base); - deleterThread.m_base = dir.absolutePath(); - deleterThread.m_whitelist = whitelist; - }; -public slots: - virtual void start() - { - connect(&deleterThread, SIGNAL(finished()), SLOT(threadFinished())); - deleterThread.start(); - }; - void threadFinished() - { - emit finish(); - } -private: - ThreadedDeleter deleterThread; -}; - - - -void OneSixAssets::fetchFinished() -{ - QString prefix ( "http://s3.amazonaws.com/Minecraft.Resources/" ); - QString fprefix ( "assets/" ); - QStringList nuke_whitelist; - - JobPtr firstJob = index_job->getFirstJob(); - auto DlJob = firstJob.dynamicCast(); - QByteArray ba = DlJob->m_data; - - QString xmlErrorMsg; - QDomDocument doc; - if ( !doc.setContent ( ba, false, &xmlErrorMsg ) ) - { - qDebug() << "Failed to process s3.amazonaws.com/Minecraft.Resources. XML error:" << - xmlErrorMsg << ba; - } - //QRegExp etag_match(".*([a-f0-9]{32}).*"); - QDomNodeList contents = doc.elementsByTagName ( "Contents" ); - - JobList *job = new JobList(); - connect ( job, SIGNAL ( finished() ), SIGNAL(finished()) ); - connect ( job, SIGNAL ( failed() ), SIGNAL(failed()) ); - - for ( int i = 0; i < contents.length(); i++ ) - { - QDomElement element = contents.at ( i ).toElement(); - - if ( element.isNull() ) - continue; - - QDomElement keyElement = getDomElementByTagName ( element, "Key" ); - QDomElement lastmodElement = getDomElementByTagName ( element, "LastModified" ); - QDomElement etagElement = getDomElementByTagName ( element, "ETag" ); - QDomElement sizeElement = getDomElementByTagName ( element, "Size" ); - - if ( keyElement.isNull() || lastmodElement.isNull() || etagElement.isNull() || sizeElement.isNull() ) - continue; - - QString keyStr = keyElement.text(); - QString lastModStr = lastmodElement.text(); - QString etagStr = etagElement.text(); - QString sizeStr = sizeElement.text(); - - //Filter folder keys - if ( sizeStr == "0" ) - continue; - - QString filename = fprefix + keyStr; - QFile check_file ( filename ); - QString client_etag = "nonsense"; - // if there already is a file and md5 checking is in effect and it can be opened - if ( check_file.exists() && check_file.open ( QIODevice::ReadOnly ) ) - { - // check the md5 against the expected one - client_etag = QCryptographicHash::hash ( check_file.readAll(), QCryptographicHash::Md5 ).toHex().constData(); - check_file.close(); - } - - QString trimmedEtag = etagStr.remove ( '"' ); - nuke_whitelist.append ( keyStr ); - if(trimmedEtag != client_etag) - job->add ( DownloadJob::create ( QUrl ( prefix + keyStr ), filename ) ); - - } - job->add ( JobPtr ( new NukeAndPaveJob ( fprefix, nuke_whitelist ) ) ); - files_job.reset ( job ); - dl.enqueue ( files_job ); -} -void OneSixAssets::fetchStarted() -{ - qDebug() << "Started downloading!"; -} -void OneSixAssets::start() -{ - JobList *job = new JobList(); - job->add ( DownloadJob::create ( QUrl ( "http://s3.amazonaws.com/Minecraft.Resources/" ) ) ); - connect ( job, SIGNAL ( finished() ), SLOT ( fetchFinished() ) ); - connect ( job, SIGNAL ( started() ), SLOT ( fetchStarted() ) ); - index_job.reset ( job ); - dl.enqueue ( index_job ); -} - -#include "OneSixAssets.moc" \ No newline at end of file diff --git a/backend/OneSixAssets.h b/backend/OneSixAssets.h deleted file mode 100644 index 8c345daa..00000000 --- a/backend/OneSixAssets.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "net/DownloadJob.h" - -class Private; - -class OneSixAssets : public QObject -{ - Q_OBJECT -signals: - void failed(); - void finished(); - -public slots: - void fetchFinished(); - void fetchStarted(); -public: - void start(); -private: - JobListQueue dl; - JobListPtr index_job; - JobListPtr files_job; -}; diff --git a/backend/OneSixInstance.cpp b/backend/OneSixInstance.cpp deleted file mode 100644 index 46866b0e..00000000 --- a/backend/OneSixInstance.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "OneSixInstance.h" -#include "OneSixInstance_p.h" -#include "OneSixUpdate.h" -#include "MinecraftProcess.h" -#include "VersionFactory.h" - -#include -#include -#include -#include - -OneSixInstance::OneSixInstance ( const QString& rootDir, SettingsObject* setting_obj, QObject* parent ) -: BaseInstance ( new OneSixInstancePrivate(), rootDir, setting_obj, parent ) -{ - I_D(OneSixInstance); - d->m_settings->registerSetting(new Setting("IntendedVersion", "")); - d->m_settings->registerSetting(new Setting("ShouldUpdate", false)); - reloadFullVersion(); -} - -BaseUpdate* OneSixInstance::doUpdate() -{ - return new OneSixUpdate(this); -} - -QString replaceTokensIn(QString text, QMap with) -{ - QString result; - QRegExp token_regexp("\\$\\{(.+)\\}"); - token_regexp.setMinimal(true); - QStringList list; - int tail = 0; - int head = 0; - while ((head = token_regexp.indexIn(text, head)) != -1) - { - result.append(text.mid(tail, head-tail)); - QString key = token_regexp.cap(1); - auto iter = with.find(key); - if(iter != with.end()) - { - result.append(*iter); - } - head += token_regexp.matchedLength(); - tail = head; - } - result.append(text.mid(tail)); - return result; -} - -QStringList OneSixInstance::processMinecraftArgs( QString user, QString session ) -{ - I_D(OneSixInstance); - auto version = d->version; - QString args_pattern = version->minecraftArguments; - - QMap token_mapping; - token_mapping["auth_username"] = user; - token_mapping["auth_session"] = session; - //FIXME: user and player name are DIFFERENT! - token_mapping["auth_player_name"] = user; - //FIXME: WTF is this. I just plugged in a random UUID here. - token_mapping["auth_uuid"] = "7d4bacf0-fd62-11e2-b778-0800200c9a66"; // obviously fake. - - // this is for offline: - /* - map["auth_player_name"] = "Player"; - map["auth_player_name"] = "00000000-0000-0000-0000-000000000000"; - */ - - token_mapping["profile_name"] = name(); - token_mapping["version_name"] = version->id; - - QString absRootDir = QDir(minecraftRoot()).absolutePath(); - token_mapping["game_directory"] = absRootDir; - QString absAssetsDir = QDir("assets/").absolutePath(); - token_mapping["game_assets"] = absAssetsDir; - - QStringList parts = args_pattern.split(' ',QString::SkipEmptyParts); - for (int i = 0; i < parts.length(); i++) - { - parts[i] = replaceTokensIn(parts[i], token_mapping); - } - return parts; -} - -MinecraftProcess* OneSixInstance::prepareForLaunch ( QString user, QString session ) -{ - I_D(OneSixInstance); - cleanupAfterRun(); - auto version = d->version; - if(!version) - return nullptr; - auto libs_to_extract = version->getActiveNativeLibs(); - QString natives_dir_raw = PathCombine(instanceRoot(), "natives/"); - bool success = ensurePathExists(natives_dir_raw); - if(!success) - { - // FIXME: handle errors - return nullptr; - } - - for(auto lib: libs_to_extract) - { - QString path = "libraries/" + lib->storagePath(); - qDebug() << "Will extract " << path.toLocal8Bit(); - if(JlCompress::extractWithExceptions(path, natives_dir_raw, lib->extract_excludes).isEmpty()) - { - return nullptr; - } - } - - QStringList args; - args.append(Util::Commandline::splitArgs(settings().get("JvmArgs").toString())); - args << QString("-Xms%1m").arg(settings().get("MinMemAlloc").toInt()); - args << QString("-Xmx%1m").arg(settings().get("MaxMemAlloc").toInt()); - QDir natives_dir(natives_dir_raw); - args << QString("-Djava.library.path=%1").arg( natives_dir.absolutePath() ); - QString classPath; - { - auto libs = version->getActiveNormalLibs(); - for (auto lib: libs) - { - QFileInfo fi(QString("libraries/") + lib->storagePath()); - classPath.append(fi.absoluteFilePath()); - //FIXME: make separator tweakable - classPath.append(':'); - } - QString targetstr = "versions/" + version->id + "/" + version->id + ".jar"; - QFileInfo fi(targetstr); - classPath.append(fi.absoluteFilePath()); - } - if(classPath.size()) - { - args << "-cp"; - args << classPath; - } - args << version->mainClass; - args.append(processMinecraftArgs(user, session)); - - // create the process and set its parameters - MinecraftProcess * proc = new MinecraftProcess(this); - proc->setMinecraftArguments(args); - proc->setMinecraftWorkdir(minecraftRoot()); - return proc; -} - -void OneSixInstance::cleanupAfterRun() -{ - QString target_dir = PathCombine(instanceRoot(), "natives/"); - QDir dir(target_dir); - dir.removeRecursively(); -} - -bool OneSixInstance::setIntendedVersionId ( QString version ) -{ - settings().set("IntendedVersion", version); - setShouldUpdate(true); - return true; -} - -QString OneSixInstance::intendedVersionId() const -{ - return settings().get("IntendedVersion").toString(); -} - -void OneSixInstance::setShouldUpdate ( bool val ) -{ - settings().set ( "ShouldUpdate", val ); -} - -bool OneSixInstance::shouldUpdate() const -{ - I_D(OneSixInstance); - QVariant var = settings().get ( "ShouldUpdate" ); - if ( !var.isValid() || var.toBool() == false ) - { - return intendedVersionId() != currentVersionId(); - } - return true; -} - -QString OneSixInstance::currentVersionId() const -{ - return intendedVersionId(); -} - -bool OneSixInstance::reloadFullVersion() -{ - I_D(OneSixInstance); - - QString verpath = PathCombine(instanceRoot(), "version.json"); - QFile versionfile(verpath); - if(versionfile.exists() && versionfile.open(QIODevice::ReadOnly)) - { - FullVersionFactory fvf; - auto version = fvf.parse(versionfile.readAll()); - versionfile.close(); - if(version) - { - d->version = version; - return true; - } - }; - return false; -} - -QSharedPointer< FullVersion > OneSixInstance::getFullVersion() -{ - I_D(OneSixInstance); - return d->version; -} diff --git a/backend/OneSixInstance.h b/backend/OneSixInstance.h deleted file mode 100644 index 12ad9e40..00000000 --- a/backend/OneSixInstance.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "BaseInstance.h" -#include -class FullVersion; -class BaseUpdate; - -class LIBMULTIMC_EXPORT OneSixInstance : public BaseInstance -{ - Q_OBJECT -public: - explicit OneSixInstance(const QString &rootDir, SettingsObject * settings, QObject *parent = 0); - virtual BaseUpdate* doUpdate(); - virtual MinecraftProcess* prepareForLaunch ( QString user, QString session ); - virtual void cleanupAfterRun(); - - virtual QString intendedVersionId() const; - virtual bool setIntendedVersionId ( QString version ); - - virtual QString currentVersionId() const; - // virtual void setCurrentVersionId ( QString val ) {}; - - virtual bool shouldUpdate() const; - virtual void setShouldUpdate(bool val); - - /// reload the full version json file. return true on success! - bool reloadFullVersion(); - /// get the current full version info - QSharedPointer getFullVersion(); -private: - QStringList processMinecraftArgs( QString user, QString session ); -}; \ No newline at end of file diff --git a/backend/OneSixInstance_p.h b/backend/OneSixInstance_p.h deleted file mode 100644 index 1037e03c..00000000 --- a/backend/OneSixInstance_p.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "BaseInstance_p.h" -#include "OneSixVersion.h" - -struct OneSixInstancePrivate: public BaseInstancePrivate -{ - QSharedPointer version; -}; \ No newline at end of file diff --git a/backend/OneSixUpdate.cpp b/backend/OneSixUpdate.cpp deleted file mode 100644 index 2bb2f496..00000000 --- a/backend/OneSixUpdate.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "OneSixUpdate.h" - -#include - -#include -#include -#include -#include - -#include - -#include "BaseInstance.h" -#include "lists/MinecraftVersionList.h" -#include "VersionFactory.h" -#include "OneSixVersion.h" -#include "OneSixInstance.h" - -#include "pathutils.h" - - -OneSixUpdate::OneSixUpdate(BaseInstance *inst, QObject *parent):BaseUpdate(inst, parent){} - -void OneSixUpdate::executeTask() -{ - QString intendedVersion = m_inst->intendedVersionId(); - - // Make directories - QDir mcDir(m_inst->minecraftRoot()); - if (!mcDir.exists() && !mcDir.mkpath(".")) - { - emitFailed("Failed to create bin folder."); - return; - } - - // Get a pointer to the version object that corresponds to the instance's version. - targetVersion = MinecraftVersionList::getMainList().findVersion(intendedVersion).dynamicCast(); - if(targetVersion == nullptr) - { - // don't do anything if it was invalid - emitSucceeded(); - return; - } - - if(m_inst->shouldUpdate()) - { - versionFileStart(); - } - else - { - jarlibStart(); - } -} - -void OneSixUpdate::versionFileStart() -{ - setStatus("Getting the version files from Mojang."); - - QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/"); - urlstr += targetVersion->descriptor + "/" + targetVersion->descriptor + ".json"; - auto dljob = DownloadJob::create(QUrl(urlstr)); - specificVersionDownloadJob.reset(new JobList()); - specificVersionDownloadJob->add(dljob); - connect(specificVersionDownloadJob.data(), SIGNAL(finished()), SLOT(versionFileFinished())); - connect(specificVersionDownloadJob.data(), SIGNAL(failed()), SLOT(versionFileFailed())); - connect(specificVersionDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); - download_queue.enqueue(specificVersionDownloadJob); -} - -void OneSixUpdate::versionFileFinished() -{ - JobPtr firstJob = specificVersionDownloadJob->getFirstJob(); - auto DlJob = firstJob.dynamicCast(); - - QString version_id = targetVersion->descriptor; - QString inst_dir = m_inst->instanceRoot(); - // save the version file in $instanceId/version.json - { - QString version1 = PathCombine(inst_dir, "/version.json"); - ensurePathExists(version1); - // FIXME: detect errors here, download to a temp file, swap - QFile vfile1 (version1); - vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly ); - vfile1.write(DlJob->m_data); - vfile1.close(); - } - - // the version is downloaded safely. update is 'done' at this point - m_inst->setShouldUpdate(false); - // save the version file in versions/$version/$version.json - /* - //QString version2 = QString("versions/") + version_id + "/" + version_id + ".json"; - //ensurePathExists(version2); - //QFile vfile2 (version2); - //vfile2.open(QIODevice::Truncate | QIODevice::WriteOnly ); - //vfile2.write(DlJob->m_data); - //vfile2.close(); - */ - - jarlibStart(); -} - -void OneSixUpdate::versionFileFailed() -{ - emitFailed("Failed to download the version description. Try again."); -} - -void OneSixUpdate::jarlibStart() -{ - OneSixInstance * inst = (OneSixInstance *) m_inst; - bool successful = inst->reloadFullVersion(); - if(!successful) - { - emitFailed("Failed to load the version description file (version.json). It might be corrupted, missing or simply too new."); - return; - } - - QSharedPointer version = inst->getFullVersion(); - - // download the right jar, save it in versions/$version/$version.jar - QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/"); - urlstr += version->id + "/" + version->id + ".jar"; - QString targetstr ("versions/"); - targetstr += version->id + "/" + version->id + ".jar"; - - auto dljob = DownloadJob::create(QUrl(urlstr), targetstr); - jarlibDownloadJob.reset(new JobList()); - jarlibDownloadJob->add(dljob); - - auto libs = version->getActiveNativeLibs(); - libs.append(version->getActiveNormalLibs()); - - for(auto lib: libs) - { - QString download_path = lib->downloadPath(); - QString storage_path = "libraries/" + lib->storagePath(); - jarlibDownloadJob->add(DownloadJob::create(download_path, storage_path)); - } - connect(jarlibDownloadJob.data(), SIGNAL(finished()), SLOT(jarlibFinished())); - connect(jarlibDownloadJob.data(), SIGNAL(failed()), SLOT(jarlibFailed())); - connect(jarlibDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); - - download_queue.enqueue(jarlibDownloadJob); -} - -void OneSixUpdate::jarlibFinished() -{ - emitSucceeded(); -} - -void OneSixUpdate::jarlibFailed() -{ - emitFailed("Failed to download the binary garbage. Try again. Maybe. IF YOU DARE"); -} - diff --git a/backend/OneSixUpdate.h b/backend/OneSixUpdate.h deleted file mode 100644 index 75575166..00000000 --- a/backend/OneSixUpdate.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include "net/DownloadJob.h" - -#include "tasks/Task.h" -#include "libmmc_config.h" -#include "BaseUpdate.h" - -class MinecraftVersion; -class BaseInstance; - -class LIBMULTIMC_EXPORT OneSixUpdate : public BaseUpdate -{ - Q_OBJECT -public: - explicit OneSixUpdate(BaseInstance *inst, QObject *parent = 0); - virtual void executeTask(); - -private slots: - void versionFileStart(); - void versionFileFinished(); - void versionFileFailed(); - - void jarlibStart(); - void jarlibFinished(); - void jarlibFailed(); - -private: - JobListPtr specificVersionDownloadJob; - JobListPtr jarlibDownloadJob; - JobListQueue download_queue; - - // target version, determined during this task - QSharedPointer targetVersion; -}; - - diff --git a/backend/OneSixVersion.cpp b/backend/OneSixVersion.cpp deleted file mode 100644 index 2b2f79f5..00000000 --- a/backend/OneSixVersion.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "OneSixVersion.h" - -RuleAction RuleAction_fromString(QString name) -{ - if(name == "allow") - return Allow; - if(name == "disallow") - return Disallow; - return Defer; -} - -OpSys OpSys_fromString(QString name) -{ - if(name == "linux") - return Os_Linux; - if(name == "windows") - return Os_Windows; - if(name == "osx") - return Os_OSX; - return Os_Other; -} - -void Library::finalize() -{ - QStringList parts = m_name.split ( ':' ); - QString relative = parts[0]; - relative.replace ( '.','/' ); - relative += '/' + parts[1] + '/' + parts[2] + '/' + parts[1] + '-' + parts[2]; - if ( !m_is_native ) - relative += ".jar"; - else - { - if ( m_native_suffixes.contains ( currentSystem ) ) - { - relative += "-" + m_native_suffixes[currentSystem] + ".jar"; - } - else - { - // really, bad. - relative += ".jar"; - } - } - m_storage_path = relative; - m_download_path = m_base_url + relative; - - if ( m_rules.empty() ) - { - m_is_active = true; - } - else - { - RuleAction result = Disallow; - for ( auto rule: m_rules ) - { - RuleAction temp = rule->apply ( this ); - if ( temp != Defer ) - result = temp; - } - m_is_active = ( result == Allow ); - } - if ( m_is_native ) - { - m_is_active = m_is_active && m_native_suffixes.contains ( currentSystem ); - } -} - -void Library::setName ( QString name ) -{ - m_name = name; -} -void Library::setBaseUrl ( QString base_url ) -{ - m_base_url = base_url; -} -void Library::setIsNative() -{ - m_is_native = true; -} -void Library::addNative ( OpSys os, QString suffix ) -{ - m_is_native = true; - m_native_suffixes[os] = suffix; -} -void Library::setRules ( QList< QSharedPointer< Rule > > rules ) -{ - m_rules = rules; -} -bool Library::isActive() -{ - return m_is_active; -} -bool Library::isNative() -{ - return m_is_native; -} -QString Library::downloadPath() -{ - return m_download_path; -} -QString Library::storagePath() -{ - return m_storage_path; -} - - -QList > FullVersion::getActiveNormalLibs() -{ - QList > output; - for ( auto lib: libraries ) - { - if (lib->isActive() && !lib->isNative()) - { - output.append(lib); - } - } - return output; -} - -QList > FullVersion::getActiveNativeLibs() -{ - QList > output; - for ( auto lib: libraries ) - { - if (lib->isActive() && lib->isNative()) - { - output.append(lib); - } - } - return output; -} - - diff --git a/backend/OneSixVersion.h b/backend/OneSixVersion.h deleted file mode 100644 index e4f75542..00000000 --- a/backend/OneSixVersion.h +++ /dev/null @@ -1,212 +0,0 @@ -#pragma once -#include - -class Library; - -enum OpSys -{ - Os_Windows, - Os_Linux, - Os_OSX, - Os_Other -}; - -OpSys OpSys_fromString(QString); - -#ifdef Q_OS_WIN32 - #define currentSystem Os_Windows -#elif Q_OS_MAC - #define currentSystem Os_OSX -#else - #define currentSystem Os_Linux -#endif - -enum RuleAction -{ - Allow, - Disallow, - Defer -}; - -RuleAction RuleAction_fromString(QString); - -class Rule -{ -protected: - RuleAction m_result; - virtual bool applies(Library * parent) = 0; -public: - Rule(RuleAction result) - :m_result(result) {} - virtual ~Rule(){}; - RuleAction apply(Library * parent) - { - if(applies(parent)) - return m_result; - else - return Defer; - }; -}; - -class OsRule : public Rule -{ -private: - // the OS - OpSys m_system; - // the OS version regexp - QString m_version_regexp; -protected: - virtual bool applies ( Library* ) - { - return (m_system == currentSystem); - } - OsRule(RuleAction result, OpSys system, QString version_regexp) - : Rule(result), m_system(system), m_version_regexp(version_regexp) {} -public: - static QSharedPointer create(RuleAction result, OpSys system, QString version_regexp) - { - return QSharedPointer (new OsRule(result, system, version_regexp)); - } -}; - -class ImplicitRule : public Rule -{ -protected: - virtual bool applies ( Library* ) - { - return true; - } - ImplicitRule(RuleAction result) - : Rule(result) {} -public: - static QSharedPointer create(RuleAction result) - { - return QSharedPointer (new ImplicitRule(result)); - } -}; - -class Library -{ -private: - // basic values used internally (so far) - QString m_name; - QString m_base_url; - QList > m_rules; - - // derived values used for real things - /// where to store the lib locally - QString m_storage_path; - /// where to download the lib from - QString m_download_path; - /// is this lib actually active on the current OS? - bool m_is_active; - /// is the library a native? - bool m_is_native; - /// native suffixes per OS - QMap m_native_suffixes; -public: - QStringList extract_excludes; - -public: - /// Constructor - Library(QString name) - { - m_is_native = false; - m_is_native = false; - m_name = name; - m_base_url = "https://s3.amazonaws.com/Minecraft.Download/libraries/"; - } - - /** - * finalize the library, processing the input values into derived values and state - * - * This SHALL be called after all the values are parsed or after any further change. - */ - void finalize(); - - /// Set the library composite name - void setName(QString name); - /// Set the url base for downloads - void setBaseUrl(QString base_url); - /// Call this to mark the library as 'native' (it's a zip archive with DLLs) - void setIsNative(); - /// Attach a name suffix to the specified OS native - void addNative(OpSys os, QString suffix); - /// Set the load rules - void setRules(QList > rules); - - /// Returns true if the library should be loaded (or extracted, in case of natives) - bool isActive(); - /// Returns true if the library is native - bool isNative(); - /// Get the URL to download the library from - QString downloadPath(); - /// Get the relative path where the library should be saved - QString storagePath(); -}; - - -class FullVersion -{ -public: - /// the ID - determines which jar to use! ACTUALLY IMPORTANT! - QString id; - /// Last updated time - as a string - QString time; - /// Release time - as a string - QString releaseTime; - /// Release type - "release" or "snapshot" - QString type; - /** - * DEPRECATED: Old versions of the new vanilla launcher used this - * ex: "username_session_version" - */ - QString processArguments; - /** - * arguments that should be used for launching minecraft - * - * ex: "--username ${auth_player_name} --session ${auth_session} - * --version ${version_name} --gameDir ${game_directory} --assetsDir ${game_assets}" - */ - QString minecraftArguments; - /** - * the minimum launcher version required by this version ... current is 4 (at point of writing) - */ - int minimumLauncherVersion; - /** - * The main class to load first - */ - QString mainClass; - - /// the list of libs - both active and inactive, native and java - QList > libraries; - - /* - FIXME: add support for those rules here? Looks like a pile of quick hacks to me though. - - "rules": [ - { - "action": "allow" - }, - { - "action": "disallow", - "os": { - "name": "osx", - "version": "^10\\.5\\.\\d$" - } - } - ], - "incompatibilityReason": "There is a bug in LWJGL which makes it incompatible with OSX 10.5.8. Please go to New Profile and use 1.5.2 for now. Sorry!" - } - */ - // QList rules; - -public: - FullVersion() - { - minimumLauncherVersion = 0xDEADBEEF; - } - - QList > getActiveNormalLibs(); - QList > getActiveNativeLibs(); -}; \ No newline at end of file diff --git a/backend/VersionFactory.cpp b/backend/VersionFactory.cpp deleted file mode 100644 index 9eccce26..00000000 --- a/backend/VersionFactory.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "VersionFactory.h" -#include "OneSixVersion.h" - -// Library rules (if any) -QList > FullVersionFactory::parse4rules(QJsonObject & baseObj) -{ - QList > rules; - auto rulesVal = baseObj.value("rules"); - if(rulesVal.isArray()) - { - QJsonArray ruleList = rulesVal.toArray(); - for(auto ruleVal : ruleList) - { - QSharedPointer rule; - if(!ruleVal.isObject()) - continue; - auto ruleObj = ruleVal.toObject(); - auto actionVal = ruleObj.value("action"); - if(!actionVal.isString()) - continue; - auto action = RuleAction_fromString(actionVal.toString()); - if(action == Defer) - continue; - - auto osVal = ruleObj.value("os"); - if(!osVal.isObject()) - { - // add a new implicit action rule - rules.append(ImplicitRule::create(action)); - } - else - { - auto osObj = osVal.toObject(); - auto osNameVal = osObj.value("name"); - if(!osNameVal.isString()) - continue; - OpSys requiredOs = OpSys_fromString(osNameVal.toString()); - QString versionRegex = osObj.value("version").toString(); - // add a new OS rule - rules.append(OsRule::create(action, requiredOs, versionRegex)); - } - } - } - return rules; -} - - -QSharedPointer FullVersionFactory::parse4(QJsonObject root, QSharedPointer fullVersion) -{ - fullVersion->id = root.value("id").toString(); - - fullVersion->mainClass = root.value("mainClass").toString(); - auto procArgsValue = root.value("processArguments"); - if(procArgsValue.isString()) - { - fullVersion->processArguments = procArgsValue.toString(); - QString toCompare = fullVersion->processArguments.toLower(); - if(toCompare == "legacy") - { - fullVersion->minecraftArguments = " ${auth_player_name} ${auth_session}"; - } - else if(toCompare == "username_session") - { - fullVersion->minecraftArguments = "--username ${auth_player_name} --session ${auth_session}"; - } - else if(toCompare == "username_session_version") - { - fullVersion->minecraftArguments = "--username ${auth_player_name} --session ${auth_session} --version ${profile_name}"; - } - } - - auto minecraftArgsValue = root.value("minecraftArguments"); - if(minecraftArgsValue.isString()) - { - fullVersion->minecraftArguments = minecraftArgsValue.toString(); - } - - auto minecraftTypeValue = root.value("type"); - if(minecraftTypeValue.isString()) - { - fullVersion->type = minecraftTypeValue.toString(); - } - - fullVersion->releaseTime = root.value("releaseTime").toString(); - fullVersion->time = root.value("time").toString(); - - // Iterate through the list, if it's a list. - auto librariesValue = root.value("libraries"); - if(!librariesValue.isArray()) - return fullVersion; - - QJsonArray libList = root.value("libraries").toArray(); - for (auto libVal : libList) - { - if (!libVal.isObject()) - { - continue; - } - - QJsonObject libObj = libVal.toObject(); - - // Library name - auto nameVal = libObj.value("name"); - if(!nameVal.isString()) - continue; - QSharedPointer library(new Library(nameVal.toString())); - - auto urlVal = libObj.value("url"); - if(urlVal.isString()) - { - library->setBaseUrl(urlVal.toString()); - } - - // Extract excludes (if any) - auto extractVal = libObj.value("extract"); - if(extractVal.isObject()) - { - QStringList excludes; - auto extractObj = extractVal.toObject(); - auto excludesVal = extractObj.value("exclude"); - if(!excludesVal.isArray()) - goto SKIP_EXTRACTS; - auto excludesList = excludesVal.toArray(); - for(auto excludeVal : excludesList) - { - if(excludeVal.isString()) - excludes.append(excludeVal.toString()); - } - library->extract_excludes = excludes; - } - SKIP_EXTRACTS: - - auto nativesVal = libObj.value("natives"); - if(nativesVal.isObject()) - { - library->setIsNative(); - auto nativesObj = nativesVal.toObject(); - auto iter = nativesObj.begin(); - while(iter != nativesObj.end()) - { - auto osType = OpSys_fromString(iter.key()); - if(osType == Os_Other) - continue; - if(!iter.value().isString()) - continue; - library->addNative(osType, iter.value().toString()); - iter++; - } - } - library->setRules(parse4rules(libObj)); - library->finalize(); - fullVersion->libraries.append(library); - } - return fullVersion; -} - -QSharedPointer FullVersionFactory::parse(QByteArray data) -{ - QSharedPointer readVersion(new FullVersion()); - - QJsonParseError jsonError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); - - if (jsonError.error != QJsonParseError::NoError) - { - error_string = QString( "Error reading version file :") + " " + jsonError.errorString(); - m_error = FullVersionFactory::ParseError; - return QSharedPointer(); - } - - if(!jsonDoc.isObject()) - { - error_string = "Error reading version file."; - m_error = FullVersionFactory::ParseError; - return QSharedPointer(); - } - QJsonObject root = jsonDoc.object(); - - int launcher_ver = readVersion->minimumLauncherVersion = root.value("minimumLauncherVersion").toDouble(); - // ADD MORE HERE :D - if(launcher_ver > 0 && launcher_ver <= 7) - return parse4(root, readVersion); - else - { - error_string = "Version file was for an unrecognized launcher version. RIP"; - m_error = FullVersionFactory::UnsupportedVersion; - return QSharedPointer(); - } -} - - -FullVersionFactory::FullVersionFactory() -{ - m_error = FullVersionFactory::AllOK; -} diff --git a/backend/VersionFactory.h b/backend/VersionFactory.h deleted file mode 100644 index 82c5278a..00000000 --- a/backend/VersionFactory.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include - -struct FullVersion; -class Rule; - -class FullVersionFactory -{ -public: - enum Error - { - AllOK, // all parsed OK - ParseError, // the file was corrupted somehow - UnsupportedVersion // the file was meant for a launcher version we don't support (yet) - } m_error; - QString error_string; - -public: - FullVersionFactory(); - QSharedPointer parse(QByteArray data); -private: - QSharedPointer parse4(QJsonObject root, QSharedPointer product); - QList > parse4rules(QJsonObject & baseObj); -}; \ No newline at end of file diff --git a/backend/libmmc_config.h b/backend/libmmc_config.h deleted file mode 100644 index 6d967f5f..00000000 --- a/backend/libmmc_config.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#ifdef LIBMULTIMC_LIBRARY -# define LIBMULTIMC_EXPORT Q_DECL_EXPORT -#else -# define LIBMULTIMC_EXPORT Q_DECL_IMPORT -#endif diff --git a/backend/lists/InstVersionList.cpp b/backend/lists/InstVersionList.cpp deleted file mode 100644 index 855fce45..00000000 --- a/backend/lists/InstVersionList.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "InstVersionList.h" -#include "InstanceVersion.h" - -InstVersionList::InstVersionList(QObject *parent) : - QAbstractListModel(parent) -{ -} - -InstVersionPtr InstVersionList::findVersion( const QString& descriptor ) -{ - for (int i = 0; i < count(); i++) - { - if (at(i)->descriptor == descriptor) - return at(i); - } - return InstVersionPtr(); -} - -InstVersionPtr InstVersionList::getLatestStable() const -{ - if (count() <= 0) - return InstVersionPtr(); - else - return at(0); -} - -QVariant InstVersionList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (index.row() > count()) - return QVariant(); - - - InstVersionPtr version = at(index.row()); - - switch (role) - { - case Qt::DisplayRole: - switch (index.column()) - { - case NameColumn: - return version->name; - - case TypeColumn: - return version->typeString(); - - case TimeColumn: - return version->timestamp; - - default: - return QVariant(); - } - - case Qt::ToolTipRole: - return version->descriptor; - - case VersionPointerRole: - return qVariantFromValue(version); - - default: - return QVariant(); - } -} - -QVariant InstVersionList::headerData(int section, Qt::Orientation orientation, int role) const -{ - switch (role) - { - case Qt::DisplayRole: - switch (section) - { - case NameColumn: - return "Name"; - - case TypeColumn: - return "Type"; - - case TimeColumn: - return "Time"; - - default: - return QVariant(); - } - - case Qt::ToolTipRole: - switch (section) - { - case NameColumn: - return "The name of the version."; - - case TypeColumn: - return "The version's type."; - - default: - return QVariant(); - } - - default: - return QVariant(); - } -} - -int InstVersionList::rowCount(const QModelIndex &parent) const -{ - // Return count - return count(); -} - -int InstVersionList::columnCount(const QModelIndex &parent) const -{ - return 2; -} diff --git a/backend/lists/InstVersionList.h b/backend/lists/InstVersionList.h deleted file mode 100644 index ff6938b4..00000000 --- a/backend/lists/InstVersionList.h +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -#include "libmmc_config.h" -#include "InstanceVersion.h" - -class Task; - -/*! - * \brief Class that each instance type's version list derives from. - * Version lists are the lists that keep track of the available game versions - * for that instance. This list will not be loaded on startup. It will be loaded - * when the list's load function is called. Before using the version list, you - * should check to see if it has been loaded yet and if not, load the list. - * - * Note that this class also inherits from QAbstractListModel. Methods from that - * class determine how this version list shows up in a list view. Said methods - * all have a default implementation, but they can be overridden by plugins to - * change the behavior of the list. - */ -class LIBMULTIMC_EXPORT InstVersionList : public QAbstractListModel -{ - Q_OBJECT -public: - enum ModelRoles - { - VersionPointerRole = 0x34B1CB48 - }; - - enum VListColumns - { - // First column - Name - NameColumn = 0, - - // Second column - Type - TypeColumn, - - // Third column - Timestamp - TimeColumn - }; - - explicit InstVersionList(QObject *parent = 0); - - /*! - * \brief Gets a task that will reload the version list. - * Simply execute the task to load the list. - * The task returned by this function should reset the model when it's done. - * \return A pointer to a task that reloads the version list. - */ - virtual Task *getLoadTask() = 0; - - //! Checks whether or not the list is loaded. If this returns false, the list should be loaded. - virtual bool isLoaded() = 0; - - //! Gets the version at the given index. - virtual const InstVersionPtr at(int i) const = 0; - - //! Returns the number of versions in the list. - virtual int count() const = 0; - - - //////// List Model Functions //////// - virtual QVariant data(const QModelIndex &index, int role) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; - virtual int rowCount(const QModelIndex &parent) const; - virtual int columnCount(const QModelIndex &parent) const; - - - /*! - * \brief Finds a version by its descriptor. - * \param The descriptor of the version to find. - * \return A const pointer to the version with the given descriptor. NULL if - * one doesn't exist. - */ - virtual InstVersionPtr findVersion(const QString &descriptor); - - /*! - * \brief Gets the latest stable version of this instance type. - * This is the version that will be selected by default. - * By default, this is simply the first version in the list. - */ - virtual InstVersionPtr getLatestStable() const; - - /*! - * Sorts the version list. - */ - virtual void sort() = 0; - -protected slots: - /*! - * Updates this list with the given list of versions. - * This is done by copying each version in the given list and inserting it - * into this one. - * We need to do this so that we can set the parents of the versions are set to this - * version list. This can't be done in the load task, because the versions the load - * task creates are on the load task's thread and Qt won't allow their parents - * to be set to something created on another thread. - * To get around that problem, we invoke this method on the GUI thread, which - * then copies the versions and sets their parents correctly. - * \param versions List of versions whose parents should be set. - */ - virtual void updateListData(QList versions) = 0; -}; diff --git a/backend/lists/InstanceList.cpp b/backend/lists/InstanceList.cpp deleted file mode 100644 index 101d52c5..00000000 --- a/backend/lists/InstanceList.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lists/InstanceList.h" -#include "BaseInstance.h" -#include "InstanceFactory.h" - -#include "pathutils.h" - -const static int GROUP_FILE_FORMAT_VERSION = 1; - -InstanceList::InstanceList(const QString &instDir, QObject *parent) : - QObject(parent), m_instDir("instances") -{ - -} - -void InstanceList::loadGroupList(QMap & groupMap) -{ - QString groupFileName = m_instDir + "/instgroups.json"; - - // if there's no group file, fail - if(!QFileInfo(groupFileName).exists()) - return; - - QFile groupFile(groupFileName); - - // if you can't open the file, fail - if (!groupFile.open(QIODevice::ReadOnly)) - { - // An error occurred. Ignore it. - qDebug("Failed to read instance group file."); - return; - } - - QTextStream in(&groupFile); - QString jsonStr = in.readAll(); - groupFile.close(); - - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonStr.toUtf8(), &error); - - // if the json was bad, fail - if (error.error != QJsonParseError::NoError) - { - qWarning(QString("Failed to parse instance group file: %1 at offset %2"). - arg(error.errorString(), QString::number(error.offset)).toUtf8()); - return; - } - - // if the root of the json wasn't an object, fail - if (!jsonDoc.isObject()) - { - qWarning("Invalid group file. Root entry should be an object."); - return; - } - - QJsonObject rootObj = jsonDoc.object(); - - // Make sure the format version matches, otherwise fail. - if (rootObj.value("formatVersion").toVariant().toInt() != GROUP_FILE_FORMAT_VERSION) - return; - - // Get the groups. if it's not an object, fail - if (!rootObj.value("groups").isObject()) - { - qWarning("Invalid group list JSON: 'groups' should be an object."); - return; - } - - // Iterate through all the groups. - QJsonObject groupMapping = rootObj.value("groups").toObject(); - for (QJsonObject::iterator iter = groupMapping.begin(); iter != groupMapping.end(); iter++) - { - QString groupName = iter.key(); - - // If not an object, complain and skip to the next one. - if (!iter.value().isObject()) - { - qWarning(QString("Group '%1' in the group list should " - "be an object.").arg(groupName).toUtf8()); - continue; - } - - QJsonObject groupObj = iter.value().toObject(); - if (!groupObj.value("instances").isArray()) - { - qWarning(QString("Group '%1' in the group list is invalid. " - "It should contain an array " - "called 'instances'.").arg(groupName).toUtf8()); - continue; - } - - // Iterate through the list of instances in the group. - QJsonArray instancesArray = groupObj.value("instances").toArray(); - - for (QJsonArray::iterator iter2 = instancesArray.begin(); - iter2 != instancesArray.end(); iter2++) - { - groupMap[(*iter2).toString()] = groupName; - } - } -} - -InstanceList::InstListError InstanceList::loadList() -{ - // load the instance groups - QMap groupMap; - loadGroupList(groupMap); - - m_instances.clear(); - QDir dir(m_instDir); - QDirIterator iter(dir); - while (iter.hasNext()) - { - QString subDir = iter.next(); - if (!QFileInfo(PathCombine(subDir, "instance.cfg")).exists()) - continue; - - BaseInstance *instPtr = NULL; - auto &loader = InstanceFactory::get(); - auto error = loader.loadInstance(instPtr, subDir); - - switch(error) - { - case InstanceFactory::NoLoadError: - break; - case InstanceFactory::NotAnInstance: - break; - } - - if (error != InstanceFactory::NoLoadError && - error != InstanceFactory::NotAnInstance) - { - QString errorMsg = QString("Failed to load instance %1: "). - arg(QFileInfo(subDir).baseName()).toUtf8(); - - switch (error) - { - default: - errorMsg += QString("Unknown instance loader error %1"). - arg(error); - break; - } - qDebug(errorMsg.toUtf8()); - } - else if (!instPtr) - { - qDebug(QString("Error loading instance %1. Instance loader returned null."). - arg(QFileInfo(subDir).baseName()).toUtf8()); - } - else - { - QSharedPointer inst(instPtr); - auto iter = groupMap.find(inst->id()); - if(iter != groupMap.end()) - { - inst->setGroup((*iter)); - } - qDebug(QString("Loaded instance %1").arg(inst->name()).toUtf8()); - inst->setParent(this); - m_instances.append(inst); - connect(instPtr, SIGNAL(propertiesChanged(BaseInstance*)),this, SLOT(propertiesChanged(BaseInstance*))); - } - } - emit invalidated(); - return NoError; -} - -/// Clear all instances. Triggers notifications. -void InstanceList::clear() -{ - m_instances.clear(); - emit invalidated(); -}; - -/// Add an instance. Triggers notifications, returns the new index -int InstanceList::add(InstancePtr t) -{ - m_instances.append(t); - emit instanceAdded(count() - 1); - return count() - 1; -} - -InstancePtr InstanceList::getInstanceById(QString instId) -{ - QListIterator iter(m_instances); - InstancePtr inst; - while(iter.hasNext()) - { - inst = iter.next(); - if (inst->id() == instId) - break; - } - if (inst->id() != instId) - return InstancePtr(); - else - return iter.peekPrevious(); -} - -void InstanceList::propertiesChanged(BaseInstance * inst) -{ - for(int i = 0; i < m_instances.count(); i++) - { - if(inst == m_instances[i].data()) - { - emit instanceChanged(i); - break; - } - } -} diff --git a/backend/lists/InstanceList.h b/backend/lists/InstanceList.h deleted file mode 100644 index 8c9965e5..00000000 --- a/backend/lists/InstanceList.h +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "BaseInstance.h" -#include "libmmc_config.h" - -class BaseInstance; - -class LIBMULTIMC_EXPORT InstanceList : public QObject -{ - Q_OBJECT -private: - /*! - * \brief Get the instance groups - */ - void loadGroupList(QMap & groupList); - -public: - explicit InstanceList(const QString &instDir, QObject *parent = 0); - - /*! - * \brief Error codes returned by functions in the InstanceList class. - * NoError Indicates that no error occurred. - * UnknownError indicates that an unspecified error occurred. - */ - enum InstListError - { - NoError = 0, - UnknownError - }; - - QString instDir() const { return m_instDir; } - - /*! - * \brief Loads the instance list. Triggers notifications. - */ - InstListError loadList(); - - /*! - * \brief Get the instance at index - */ - InstancePtr at(int i) const - { - return m_instances.at(i); - }; - - /*! - * \brief Get the count of loaded instances - */ - int count() const - { - return m_instances.count(); - }; - - /// Clear all instances. Triggers notifications. - void clear(); - - /// Add an instance. Triggers notifications, returns the new index - int add(InstancePtr t); - - /// Get an instance by ID - InstancePtr getInstanceById (QString id); - -signals: - void instanceAdded(int index); - void instanceChanged(int index); - void invalidated(); - -private slots: - void propertiesChanged(BaseInstance * inst); - -protected: - QString m_instDir; - QList< InstancePtr > m_instances; -}; diff --git a/backend/lists/LwjglVersionList.cpp b/backend/lists/LwjglVersionList.cpp deleted file mode 100644 index 068394e8..00000000 --- a/backend/lists/LwjglVersionList.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "LwjglVersionList.h" -#include - -#include - -#include - -#include - -#define RSS_URL "http://sourceforge.net/api/file/index/project-id/58488/mtime/desc/rss" - -LWJGLVersionList mainVersionList; - -LWJGLVersionList &LWJGLVersionList::get() -{ - return mainVersionList; -} - - -LWJGLVersionList::LWJGLVersionList(QObject *parent) : - QAbstractListModel(parent) -{ - setLoading(false); -} - -QVariant LWJGLVersionList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (index.row() > count()) - return QVariant(); - - const PtrLWJGLVersion version = at(index.row()); - - switch (role) - { - case Qt::DisplayRole: - return version->name(); - - case Qt::ToolTipRole: - return version->url(); - - default: - return QVariant(); - } -} - -QVariant LWJGLVersionList::headerData(int section, Qt::Orientation orientation, int role) const -{ - switch (role) - { - case Qt::DisplayRole: - return "Version"; - - case Qt::ToolTipRole: - return "LWJGL version name."; - - default: - return QVariant(); - } -} - -int LWJGLVersionList::columnCount(const QModelIndex &parent) const -{ - return 1; -} - -bool LWJGLVersionList::isLoading() const -{ - return m_loading; -} - -void LWJGLVersionList::loadList() -{ - Q_ASSERT_X(!m_loading, "loadList", "list is already loading (m_loading is true)"); - - setLoading(true); - auto & worker = NetWorker::spawn(); - reply = worker.get(QNetworkRequest(QUrl(RSS_URL))); - connect(reply, SIGNAL(finished()), SLOT(netRequestComplete())); -} - -inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname) -{ - QDomNodeList elementList = parent.elementsByTagName(tagname); - if (elementList.count()) - return elementList.at(0).toElement(); - else - return QDomElement(); -} - -void LWJGLVersionList::netRequestComplete() -{ - if (reply->error() == QNetworkReply::NoError) - { - QRegExp lwjglRegex("lwjgl-(([0-9]\\.?)+)\\.zip"); - Q_ASSERT_X(lwjglRegex.isValid(), "load LWJGL list", - "LWJGL regex is invalid"); - - QDomDocument doc; - - QString xmlErrorMsg; - int errorLine; - if (!doc.setContent(reply->readAll(), false, &xmlErrorMsg, &errorLine)) - { - failed("Failed to load LWJGL list. XML error: " + xmlErrorMsg + " at line " + QString::number(errorLine)); - setLoading(false); - return; - } - - QDomNodeList items = doc.elementsByTagName("item"); - - QList tempList; - - for (int i = 0; i < items.length(); i++) - { - Q_ASSERT_X(items.at(i).isElement(), "load LWJGL list", - "XML element isn't an element... wat?"); - - QDomElement linkElement = getDomElementByTagName(items.at(i).toElement(), "link"); - if (linkElement.isNull()) - { - qWarning() << "Link element" << i << "in RSS feed doesn't exist! Skipping."; - continue; - } - - QString link = linkElement.text(); - - // Make sure it's a download link. - if (link.endsWith("/download") && link.contains(lwjglRegex)) - { - QString name = link.mid(lwjglRegex.indexIn(link) + 6); - // Subtract 4 here to remove the .zip file extension. - name = name.left(lwjglRegex.matchedLength() - 10); - - QUrl url(link); - if (!url.isValid()) - { - qWarning() << "LWJGL version URL isn't valid:" << link << "Skipping."; - continue; - } - - tempList.append(LWJGLVersion::Create(name, link)); - } - } - - beginResetModel(); - m_vlist.swap(tempList); - endResetModel(); - - qDebug("Loaded LWJGL list."); - finished(); - } - else - { - failed("Failed to load LWJGL list. Network error: " + reply->errorString()); - } - - setLoading(false); - reply->deleteLater(); -} - -const PtrLWJGLVersion LWJGLVersionList::getVersion(const QString &versionName) -{ - for (int i = 0; i < count(); i++) - { - QString name = at(i)->name(); - if ( name == versionName) - return at(i); - } - return PtrLWJGLVersion(); -} - - -void LWJGLVersionList::failed(QString msg) -{ - qWarning() << msg; - emit loadListFailed(msg); -} - -void LWJGLVersionList::finished() -{ - emit loadListFinished(); -} - -void LWJGLVersionList::setLoading(bool loading) -{ - m_loading = loading; - emit loadingStateUpdated(m_loading); -} diff --git a/backend/lists/LwjglVersionList.h b/backend/lists/LwjglVersionList.h deleted file mode 100644 index 2360f181..00000000 --- a/backend/lists/LwjglVersionList.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -#include - -#include "libmmc_config.h" - -class LWJGLVersion; -typedef QSharedPointer PtrLWJGLVersion; - -class LIBMULTIMC_EXPORT LWJGLVersion : public QObject -{ - Q_OBJECT - - LWJGLVersion(const QString &name, const QString &url, QObject *parent = 0) : - QObject(parent), m_name(name), m_url(url) { } -public: - - static PtrLWJGLVersion Create(const QString &name, const QString &url, QObject *parent = 0) - { - return PtrLWJGLVersion(new LWJGLVersion(name, url, parent)); - }; - - QString name() const { return m_name; } - - QString url() const { return m_url; } - -protected: - QString m_name; - QString m_url; -}; - -class LIBMULTIMC_EXPORT LWJGLVersionList : public QAbstractListModel -{ - Q_OBJECT -public: - explicit LWJGLVersionList(QObject *parent = 0); - - static LWJGLVersionList &get(); - - bool isLoaded() { return m_vlist.length() > 0; } - - const PtrLWJGLVersion getVersion(const QString &versionName); - PtrLWJGLVersion at(int index) { return m_vlist[index]; } - const PtrLWJGLVersion at(int index) const { return m_vlist[index]; } - - int count() const { return m_vlist.length(); } - - virtual QVariant data(const QModelIndex &index, int role) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; - virtual int rowCount(const QModelIndex &parent) const { return count(); } - virtual int columnCount(const QModelIndex &parent) const; - - virtual bool isLoading() const; - virtual bool errored() const { return m_errored; } - - virtual QString lastErrorMsg() const { return m_lastErrorMsg; } - -public slots: - /*! - * Loads the version list. - * This is done asynchronously. On success, the loadListFinished() signal will - * be emitted. The list model will be reset as well, resulting in the modelReset() - * signal being emitted. Note that the model will be reset before loadListFinished() is emitted. - * If loading the list failed, the loadListFailed(QString msg), - * signal will be emitted. - */ - virtual void loadList(); - -signals: - /*! - * Emitted when the list either starts or finishes loading. - * \param loading Whether or not the list is loading. - */ - void loadingStateUpdated(bool loading); - - void loadListFinished(); - - void loadListFailed(QString msg); - -private: - QList m_vlist; - - QNetworkReply *m_netReply; - QNetworkReply *reply; - - bool m_loading; - bool m_errored; - QString m_lastErrorMsg; - - void failed(QString msg); - - void finished(); - - void setLoading(bool loading); - -private slots: - virtual void netRequestComplete(); -}; - diff --git a/backend/lists/MinecraftVersionList.cpp b/backend/lists/MinecraftVersionList.cpp deleted file mode 100644 index 2e5f0cd7..00000000 --- a/backend/lists/MinecraftVersionList.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* Copyright 2013 Andrew Okin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "MinecraftVersionList.h" -#include - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#define MCVLIST_URLBASE "http://s3.amazonaws.com/Minecraft.Download/versions/" -#define ASSETS_URLBASE "http://assets.minecraft.net/" -#define MCN_URLBASE "http://sonicrules.org/mcnweb.py" - -MinecraftVersionList mcVList; - -MinecraftVersionList::MinecraftVersionList(QObject *parent) : - InstVersionList(parent) -{ - -} - -Task *MinecraftVersionList::getLoadTask() -{ - return new MCVListLoadTask(this); -} - -bool MinecraftVersionList::isLoaded() -{ - return m_loaded; -} - -const InstVersionPtr MinecraftVersionList::at(int i) const -{ - return m_vlist.at(i); -} - -int MinecraftVersionList::count() const -{ - return m_vlist.count(); -} - -bool cmpVersions(InstVersionPtr first, InstVersionPtr second) -{ - const InstVersion & left = *first; - const InstVersion & right = *second; - return left > right; -} - -void MinecraftVersionList::sort() -{ - beginResetModel(); - qSort(m_vlist.begin(), m_vlist.end(), cmpVersions); - endResetModel(); -} - -InstVersionPtr MinecraftVersionList::getLatestStable() const -{ - for (int i = 0; i < m_vlist.length(); i++) - { - auto ver = m_vlist.at(i).dynamicCast(); - if (ver->is_latest && !ver->is_snapshot) - { - return m_vlist.at(i); - } - } - return InstVersionPtr(); -} - -MinecraftVersionList &MinecraftVersionList::getMainList() -{ - return mcVList; -} - -void MinecraftVersionList::updateListData(QList versions) -{ - beginResetModel(); - m_vlist = versions; - m_loaded = true; - endResetModel(); - // NOW SORT!! - sort(); -} - -inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname) -{ - QDomNodeList elementList = parent.elementsByTagName(tagname); - if (elementList.count()) - return elementList.at(0).toElement(); - else - return QDomElement(); -} - -inline QDateTime timeFromS3Time(QString str) -{ - return QDateTime::fromString(str, Qt::ISODate); -} - - -MCVListLoadTask::MCVListLoadTask(MinecraftVersionList *vlist) -{ - m_list = vlist; - m_currentStable = NULL; - vlistReply = nullptr; - legacyWhitelist.insert("1.5.2"); - legacyWhitelist.insert("1.5.1"); - legacyWhitelist.insert("1.5"); - legacyWhitelist.insert("1.4.7"); - legacyWhitelist.insert("1.4.6"); - legacyWhitelist.insert("1.4.5"); - legacyWhitelist.insert("1.4.4"); - legacyWhitelist.insert("1.4.2"); - legacyWhitelist.insert("1.3.2"); - legacyWhitelist.insert("1.3.1"); - legacyWhitelist.insert("1.2.5"); - legacyWhitelist.insert("1.2.4"); - legacyWhitelist.insert("1.2.3"); - legacyWhitelist.insert("1.2.2"); - legacyWhitelist.insert("1.2.1"); - legacyWhitelist.insert("1.1"); - legacyWhitelist.insert("1.0.1"); - legacyWhitelist.insert("1.0"); -} - -MCVListLoadTask::~MCVListLoadTask() -{ -} - -void MCVListLoadTask::executeTask() -{ - setStatus("Loading instance version list..."); - auto & worker = NetWorker::spawn(); - vlistReply = worker.get(QNetworkRequest(QUrl(QString(MCVLIST_URLBASE) + "versions.json"))); - connect(vlistReply, SIGNAL(finished()), this, SLOT(list_downloaded())); -} - - -void MCVListLoadTask::list_downloaded() -{ - if(vlistReply->error() != QNetworkReply::QNetworkReply::NoError) - { - vlistReply->deleteLater(); - emitFailed("Failed to load Minecraft main version list" + vlistReply->errorString()); - return; - } - - QJsonParseError jsonError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(vlistReply->readAll(), &jsonError); - vlistReply->deleteLater(); - - if (jsonError.error != QJsonParseError::NoError) - { - emitFailed("Error parsing version list JSON:" + jsonError.errorString()); - return; - } - - if(!jsonDoc.isObject()) - { - emitFailed("Error parsing version list JSON: jsonDoc is not an object"); - return; - } - - QJsonObject root = jsonDoc.object(); - - // Get the ID of the latest release and the latest snapshot. - if(!root.value("latest").isObject()) - { - emitFailed("Error parsing version list JSON: version list is missing 'latest' object"); - return; - } - - QJsonObject latest = root.value("latest").toObject(); - - QString latestReleaseID = latest.value("release").toString(""); - QString latestSnapshotID = latest.value("snapshot").toString(""); - if(latestReleaseID.isEmpty()) - { - emitFailed("Error parsing version list JSON: latest release field is missing"); - return; - } - if(latestSnapshotID.isEmpty()) - { - emitFailed("Error parsing version list JSON: latest snapshot field is missing"); - return; - } - - // Now, get the array of versions. - if(!root.value("versions").isArray()) - { - emitFailed("Error parsing version list JSON: version list object is missing 'versions' array"); - return; - } - QJsonArray versions = root.value("versions").toArray(); - - QList tempList; - for (int i = 0; i < versions.count(); i++) - { - bool is_snapshot = false; - bool is_latest = false; - - // Load the version info. - if(!versions[i].isObject()) - { - //FIXME: log this somewhere - continue; - } - QJsonObject version = versions[i].toObject(); - QString versionID = version.value("id").toString(""); - QString versionTimeStr = version.value("releaseTime").toString(""); - QString versionTypeStr = version.value("type").toString(""); - if(versionID.isEmpty() || versionTimeStr.isEmpty() || versionTypeStr.isEmpty()) - { - //FIXME: log this somewhere - continue; - } - - // Parse the timestamp. - QDateTime versionTime = timeFromS3Time(versionTimeStr); - if(!versionTime.isValid()) - { - //FIXME: log this somewhere - continue; - } - // Parse the type. - MinecraftVersion::VersionType versionType; - // OneSix or Legacy. use filter to determine type - if (versionTypeStr == "release") - { - versionType = legacyWhitelist.contains(versionID)?MinecraftVersion::Legacy:MinecraftVersion::OneSix; - is_latest = (versionID == latestReleaseID); - is_snapshot = false; - } - else if(versionTypeStr == "snapshot") // It's a snapshot... yay - { - versionType = legacyWhitelist.contains(versionID)?MinecraftVersion::Legacy:MinecraftVersion::OneSix; - is_latest = (versionID == latestSnapshotID); - is_snapshot = true; - } - else if(versionTypeStr == "old_alpha") - { - versionType = MinecraftVersion::Nostalgia; - is_latest = false; - is_snapshot = false; - } - else if(versionTypeStr == "old_beta") - { - versionType = MinecraftVersion::Legacy; - is_latest = false; - is_snapshot = false; - } - else - { - //FIXME: log this somewhere - continue; - } - // Get the download URL. - QString dlUrl = QString(MCVLIST_URLBASE) + versionID + "/"; - - // Now, we construct the version object and add it to the list. - QSharedPointer mcVersion(new MinecraftVersion()); - mcVersion->name = mcVersion->descriptor = versionID; - mcVersion->timestamp = versionTime.toMSecsSinceEpoch(); - mcVersion->download_url = dlUrl; - mcVersion->is_latest = is_latest; - mcVersion->is_snapshot = is_snapshot; - mcVersion->type = versionType; - tempList.append(mcVersion); - } - m_list->updateListData(tempList); - - emitSucceeded(); - return; -} - -// FIXME: we should have a local cache of the version list and a local cache of version data -bool MCVListLoadTask::loadFromVList() -{ -} diff --git a/backend/lists/MinecraftVersionList.h b/backend/lists/MinecraftVersionList.h deleted file mode 100644 index d3b18691..00000000 --- a/backend/lists/MinecraftVersionList.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright 2013 Andrew Okin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -#include "InstVersionList.h" -#include "tasks/Task.h" -#include "MinecraftVersion.h" -#include "libmmc_config.h" - -class MCVListLoadTask; -class QNetworkReply; - -class LIBMULTIMC_EXPORT MinecraftVersionList : public InstVersionList -{ - Q_OBJECT -public: - friend class MCVListLoadTask; - - explicit MinecraftVersionList(QObject *parent = 0); - - virtual Task *getLoadTask(); - virtual bool isLoaded(); - virtual const InstVersionPtr at(int i) const; - virtual int count() const; - virtual void sort(); - - virtual InstVersionPtr getLatestStable() const; - - /*! - * Gets the main version list instance. - */ - static MinecraftVersionList &getMainList(); - - -protected: - QList m_vlist; - - bool m_loaded; - -protected slots: - virtual void updateListData(QList versions); -}; - -class MCVListLoadTask : public Task -{ - Q_OBJECT - -public: - explicit MCVListLoadTask(MinecraftVersionList *vlist); - ~MCVListLoadTask(); - - virtual void executeTask(); - -protected slots: - void list_downloaded(); - -protected: - //! Loads versions from Mojang's official version list. - bool loadFromVList(); - - QNetworkReply *vlistReply; - MinecraftVersionList *m_list; - MinecraftVersion *m_currentStable; - QSet legacyWhitelist; -}; - diff --git a/backend/net/DownloadJob.cpp b/backend/net/DownloadJob.cpp deleted file mode 100644 index ef842dfd..00000000 --- a/backend/net/DownloadJob.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "DownloadJob.h" -#include "pathutils.h" -#include "NetWorker.h" - -DownloadJob::DownloadJob (QUrl url, - QString target_path, - QString expected_md5 ) - :Job() -{ - m_url = url; - m_target_path = target_path; - m_expected_md5 = expected_md5; - - m_check_md5 = m_expected_md5.size(); - m_save_to_file = m_target_path.size(); - m_status = Job_NotStarted; - m_opened_for_saving = false; -} - -JobPtr DownloadJob::create (QUrl url, - QString target_path, - QString expected_md5 ) -{ - return JobPtr ( new DownloadJob ( url, target_path, expected_md5 ) ); -} - -void DownloadJob::start() -{ - if ( m_save_to_file ) - { - QString filename = m_target_path; - m_output_file.setFileName ( filename ); - // if there already is a file and md5 checking is in effect and it can be opened - if ( m_output_file.exists() && m_output_file.open ( QIODevice::ReadOnly ) ) - { - // check the md5 against the expected one - QString hash = QCryptographicHash::hash ( m_output_file.readAll(), QCryptographicHash::Md5 ).toHex().constData(); - m_output_file.close(); - // skip this file if they match - if ( m_check_md5 && hash == m_expected_md5 ) - { - qDebug() << "Skipping " << m_url.toString() << ": md5 match."; - emit finish(); - return; - } - else - { - m_expected_md5 = hash; - } - } - if(!ensurePathExists(filename)) - { - emit fail(); - return; - } - } - qDebug() << "Downloading " << m_url.toString(); - QNetworkRequest request ( m_url ); - request.setRawHeader(QString("If-None-Match").toLatin1(), m_expected_md5.toLatin1()); - - auto &worker = NetWorker::spawn(); - QNetworkReply * rep = worker.get ( request ); - - m_reply = QSharedPointer ( rep, &QObject::deleteLater ); - connect ( rep, SIGNAL ( downloadProgress ( qint64,qint64 ) ), SLOT ( downloadProgress ( qint64,qint64 ) ) ); - connect ( rep, SIGNAL ( finished() ), SLOT ( downloadFinished() ) ); - connect ( rep, SIGNAL ( error ( QNetworkReply::NetworkError ) ), SLOT ( downloadError ( QNetworkReply::NetworkError ) ) ); - connect ( rep, SIGNAL ( readyRead() ), SLOT ( downloadReadyRead() ) ); -} - -void DownloadJob::downloadProgress ( qint64 bytesReceived, qint64 bytesTotal ) -{ - emit progress ( bytesReceived, bytesTotal ); -} - -void DownloadJob::downloadError ( QNetworkReply::NetworkError error ) -{ - // error happened during download. - // TODO: log the reason why - m_status = Job_Failed; -} - -void DownloadJob::downloadFinished() -{ - // if the download succeeded - if ( m_status != Job_Failed ) - { - // nothing went wrong... - m_status = Job_Finished; - // save the data to the downloadable if we aren't saving to file - if ( !m_save_to_file ) - { - m_data = m_reply->readAll(); - } - else - { - m_output_file.close(); - } - - //TODO: check md5 here! - m_reply.clear(); - emit finish(); - return; - } - // else the download failed - else - { - if ( m_save_to_file ) - { - m_output_file.close(); - m_output_file.remove(); - } - m_reply.clear(); - emit fail(); - return; - } -} - -void DownloadJob::downloadReadyRead() -{ - if( m_save_to_file ) - { - if(!m_opened_for_saving) - { - if ( !m_output_file.open ( QIODevice::WriteOnly ) ) - { - /* - * Can't open the file... the job failed - */ - m_reply->abort(); - emit fail(); - return; - } - m_opened_for_saving = true; - } - m_output_file.write ( m_reply->readAll() ); - } -} diff --git a/backend/net/DownloadJob.h b/backend/net/DownloadJob.h deleted file mode 100644 index cbde3852..00000000 --- a/backend/net/DownloadJob.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#include "JobQueue.h" -#include - -/** - * A single file for the downloader/cache to process. - */ -class LIBUTIL_EXPORT DownloadJob : public Job -{ - Q_OBJECT -public: - DownloadJob(QUrl url, - QString rel_target_path = QString(), - QString expected_md5 = QString() - ); - static JobPtr create(QUrl url, QString rel_target_path = QString(), QString expected_md5 = QString()); -public slots: - virtual void start(); - -private slots: - void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);; - void downloadError(QNetworkReply::NetworkError error); - void downloadFinished(); - void downloadReadyRead(); - -public: - /// the network reply - QSharedPointer m_reply; - /// source URL - QUrl m_url; - - /// if true, check the md5sum against a provided md5sum - /// also, if a file exists, perform an md5sum first and don't download only if they don't match - bool m_check_md5; - /// the expected md5 checksum - QString m_expected_md5; - - /// save to file? - bool m_save_to_file; - /// is the saving file already open? - bool m_opened_for_saving; - /// if saving to file, use the one specified in this string - QString m_target_path; - /// this is the output file, if any - QFile m_output_file; - /// if not saving to file, downloaded data is placed here - QByteArray m_data; - - /// The file's status - JobStatus m_status; -}; diff --git a/backend/net/JobQueue.h b/backend/net/JobQueue.h deleted file mode 100644 index 26f49307..00000000 --- a/backend/net/JobQueue.h +++ /dev/null @@ -1,180 +0,0 @@ -#pragma once -#include -#include "libutil_config.h" - -enum JobStatus -{ - Job_NotStarted, - Job_InProgress, - Job_Finished, - Job_Failed -}; - -class JobList; - -class LIBUTIL_EXPORT Job : public QObject -{ - Q_OBJECT -protected: - explicit Job(): QObject(0){}; -public: - virtual ~Job() {}; -signals: - void finish(); - void fail(); - void progress(qint64 current, qint64 total); -public slots: - virtual void start() = 0; -}; -typedef QSharedPointer JobPtr; - -/** - * A list of jobs, to be processed one by one. - */ -class LIBUTIL_EXPORT JobList : public QObject -{ - friend class JobListQueue; - Q_OBJECT -public: - - JobList() : QObject(0) - { - m_status = Job_NotStarted; - current_job_idx = 0; - } - JobStatus getStatus() - { - return m_status; - } - void add(JobPtr dlable) - { - if(m_status == Job_NotStarted) - m_jobs.append(dlable); - //else there's a bug. TODO: catch the bugs - } - JobPtr getFirstJob() - { - if(m_jobs.size()) - return m_jobs[0]; - else - return JobPtr(); - } - void start() - { - current_job_idx = 0; - auto job = m_jobs[current_job_idx]; - - connect(job.data(), SIGNAL(progress(qint64,qint64)), SLOT(currentJobProgress(qint64,qint64))); - connect(job.data(), SIGNAL(finish()), SLOT(currentJobFinished())); - connect(job.data(), SIGNAL(fail()), SLOT(currentJobFailed())); - job->start(); - emit started(); - } -private slots: - void currentJobFinished() - { - if(current_job_idx == m_jobs.size() - 1) - { - m_status = Job_Finished; - emit finished(); - } - else - { - current_job_idx++; - auto job = m_jobs[current_job_idx]; - connect(job.data(), SIGNAL(progress(qint64,qint64)), SLOT(currentJobProgress(qint64,qint64))); - connect(job.data(), SIGNAL(finish()), SLOT(currentJobFinished())); - connect(job.data(), SIGNAL(fail()), SLOT(currentJobFailed())); - job->start(); - } - } - void currentJobFailed() - { - m_status = Job_Failed; - emit failed(); - } - void currentJobProgress(qint64 current, qint64 total) - { - if(!total) - return; - - int total_jobs = m_jobs.size(); - - if(!total_jobs) - return; - - float job_chunk = 1000.0 / float(total_jobs); - float cur = current; - float tot = total; - float last_chunk = (cur / tot) * job_chunk; - - float list_total = job_chunk * current_job_idx + last_chunk; - emit progress(qint64(list_total), 1000LL); - } -private: - QVector m_jobs; - /// The overall status of this job list - JobStatus m_status; - int current_job_idx; -signals: - void progress(qint64 current, qint64 total); - void started(); - void finished(); - void failed(); -}; -typedef QSharedPointer JobListPtr; - - -/** - * A queue of job lists! The job lists fail or finish as units. - */ -class LIBUTIL_EXPORT JobListQueue : public QObject -{ - Q_OBJECT -public: - JobListQueue(QObject *p = 0): - QObject(p), - currentIndex(0), - is_running(false){} - - void enqueue(JobListPtr job) - { - jobs.enqueue(job); - - // finish or fail, we should catch that and start the next one - connect(job.data(),SIGNAL(finished()), SLOT(startNextJob())); - connect(job.data(),SIGNAL(failed()), SLOT(startNextJob())); - - if(!is_running) - { - QTimer::singleShot(0, this, SLOT(startNextJob())); - } - } - -private slots: - void startNextJob() - { - if (jobs.isEmpty()) - { - currentJobList.clear(); - currentIndex = 0; - is_running = false; - emit finishedAllJobs(); - return; - } - - currentJobList = jobs.dequeue(); - is_running = true; - currentIndex = 0; - currentJobList->start(); - } - -signals: - void finishedAllJobs(); - -private: - JobListPtr currentJobList; - QQueue jobs; - unsigned currentIndex; - bool is_running; -}; diff --git a/backend/net/NetWorker.cpp b/backend/net/NetWorker.cpp deleted file mode 100644 index 1eef13d9..00000000 --- a/backend/net/NetWorker.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "NetWorker.h" -#include - -NetWorker& NetWorker::spawn() -{ - static QThreadStorage storage; - if (!storage.hasLocalData()) - { - storage.setLocalData(new NetWorker()); - } - return *storage.localData(); -} diff --git a/backend/net/NetWorker.h b/backend/net/NetWorker.h deleted file mode 100644 index 98374e3b..00000000 --- a/backend/net/NetWorker.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - _.ooo-._ - .OOOP _ '. - dOOOO (_) \ - OOOOOb | - OOOOOOb. | - OOOOOOOOb | - YOO(_)OOO / - 'OOOOOY _.' - '""""'' -*/ - -#pragma once -#include -class NetWorker : public QNetworkAccessManager -{ - Q_OBJECT -public: - static NetWorker &spawn(); -}; \ No newline at end of file diff --git a/backend/tasks/LoginTask.cpp b/backend/tasks/LoginTask.cpp deleted file mode 100644 index 48202044..00000000 --- a/backend/tasks/LoginTask.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "LoginTask.h" -#include - -#include - -#include -#include - -#include -#include - -LoginTask::LoginTask( const UserInfo& uInfo, QObject* parent ) : Task(parent), uInfo(uInfo){} - -void LoginTask::executeTask() -{ - setStatus("Logging in..."); - auto & worker = NetWorker::spawn(); - connect(&worker, SIGNAL(finished(QNetworkReply*)), this, SLOT(processNetReply(QNetworkReply*))); - - QUrl loginURL("https://login.minecraft.net/"); - QNetworkRequest netRequest(loginURL); - netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); - - QUrlQuery params; - params.addQueryItem("user", uInfo.username); - params.addQueryItem("password", uInfo.password); - params.addQueryItem("version", "13"); - - netReply = worker.post(netRequest, params.query(QUrl::EncodeSpaces).toUtf8()); -} - -void LoginTask::processNetReply(QNetworkReply *reply) -{ - if(netReply != reply) - return; - // Check for errors. - switch (reply->error()) - { - case QNetworkReply::NoError: - { - // Check the response code. - int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - - if (responseCode == 200) - { - QString responseStr(reply->readAll()); - - QStringList strings = responseStr.split(":"); - if (strings.count() >= 4) - { - bool parseSuccess; - qint64 latestVersion = strings[0].toLongLong(&parseSuccess); - if (parseSuccess) - { - // strings[1] is the download ticket. It isn't used anymore. - QString username = strings[2]; - QString sessionID = strings[3]; - - result = {username, sessionID, latestVersion}; - emitSucceeded(); - } - else - { - emitFailed("Failed to parse Minecraft version string."); - } - } - else - { - if (responseStr.toLower() == "bad login") - emitFailed("Invalid username or password."); - else if (responseStr.toLower() == "old version") - emitFailed("Launcher outdated, please update."); - else - emitFailed("Login failed: " + responseStr); - } - } - else if (responseCode == 503) - { - emitFailed("The login servers are currently unavailable. Check http://help.mojang.com/ for more info."); - } - else - { - emitFailed(QString("Login failed: Unknown HTTP error %1 occurred.").arg(QString::number(responseCode))); - } - break; - } - - case QNetworkReply::OperationCanceledError: - emitFailed("Login canceled."); - break; - - default: - emitFailed("Login failed: " + reply->errorString()); - break; - } -} diff --git a/backend/tasks/LoginTask.h b/backend/tasks/LoginTask.h deleted file mode 100644 index 77d65255..00000000 --- a/backend/tasks/LoginTask.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LOGINTASK_H -#define LOGINTASK_H - -#include "Task.h" -#include -#include "libmmc_config.h" - -struct UserInfo -{ - QString username; - QString password; -}; - -struct LoginResponse -{ - QString username; - QString sessionID; - qint64 latestVersion; -}; - -class QNetworkReply; - -class LIBMULTIMC_EXPORT LoginTask : public Task -{ - Q_OBJECT -public: - explicit LoginTask(const UserInfo& uInfo, QObject *parent = 0); - LoginResponse getResult() - { - return result; - }; - -protected slots: - void processNetReply(QNetworkReply* reply); - -protected: - void executeTask(); - - LoginResponse result; - QNetworkReply* netReply; - UserInfo uInfo; -}; - -#endif // LOGINTASK_H diff --git a/backend/tasks/Task.cpp b/backend/tasks/Task.cpp deleted file mode 100644 index 7c148591..00000000 --- a/backend/tasks/Task.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Task.h" - -Task::Task(QObject *parent) : - QObject(parent) -{ - -} - -QString Task::getStatus() const -{ - return status; -} - -void Task::setStatus(const QString &status) -{ - this->status = status; - emitStatusChange(status); -} - -int Task::getProgress() const -{ - return progress; -} - -void Task::setProgress(int progress) -{ - this->progress = progress; - emitProgressChange(progress); -} - -void Task::startTask() -{ - emitStarted(); - executeTask(); -} - -void Task::emitStarted() -{ - running = true; - emit started(); -} - -void Task::emitFailed(QString reason) -{ - running = false; - emit failed(reason); -} - -void Task::emitSucceeded() -{ - running = false; - emit succeeded(); -} - - -bool Task::isRunning() const -{ - return running; -} - - -void Task::emitStatusChange(const QString &status) -{ - emit statusChanged(status); -} - -void Task::emitProgressChange(int progress) -{ - emit progressChanged(progress); -} diff --git a/backend/tasks/Task.h b/backend/tasks/Task.h deleted file mode 100644 index 15219931..00000000 --- a/backend/tasks/Task.h +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef TASK_H -#define TASK_H - -#include -#include - -#include "libmmc_config.h" - -class LIBMULTIMC_EXPORT Task : public QObject -{ - Q_OBJECT -public: - explicit Task(QObject *parent = 0); - - QString getStatus() const; - int getProgress() const; - bool isRunning() const; - -public slots: - void startTask(); - -protected slots: - void setStatus(const QString& status); - void setProgress(int progress); - -signals: - void started(); - void failed(QString reason); - void succeeded(); - - void statusChanged(Task* task, const QString& status); - void progressChanged(Task* task, int progress); - - void statusChanged(const QString& status); - void progressChanged(int progress); - -protected: - virtual void executeTask() = 0; - - virtual void emitStarted(); - virtual void emitFailed(QString reason); - virtual void emitSucceeded(); - - virtual void emitStatusChange(const QString &status); - virtual void emitProgressChange(int progress); - - QString status; - int progress; - bool running = false; -}; - -#endif // TASK_H diff --git a/depends/classparser/CMakeLists.txt b/depends/classparser/CMakeLists.txt new file mode 100644 index 00000000..5a48e002 --- /dev/null +++ b/depends/classparser/CMakeLists.txt @@ -0,0 +1,41 @@ +project(classparser) + +set(CMAKE_AUTOMOC ON) + +# Find Qt +find_package(Qt5Core REQUIRED) + +# Include Qt headers. +include_directories(${Qt5Base_INCLUDE_DIRS}) + +SET(CLASSPARSER_HEADERS +include/classparser_config.h + +# Public headers +include/javautils.h + +# Private headers +src/annotations.h +src/classfile.h +src/constants.h +src/errors.h +src/javaendian.h +src/membuffer.h +) + +SET(CLASSPARSER_SOURCES +src/javautils.cpp +src/annotations.cpp +) + +# Set the include dir path. +SET(LIBGROUPVIEW_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE) + +# Include self. +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(${CMAKE_BINARY_DIR}/include) + +add_definitions(-DCLASSPARSER_LIBRARY) + +add_library(classparser SHARED ${CLASSPARSER_SOURCES} ${CLASSPARSER_HEADERS}) +qt5_use_modules(classparser Core) diff --git a/depends/classparser/include/classparser_config.h b/depends/classparser/include/classparser_config.h new file mode 100644 index 00000000..fe6a2ab9 --- /dev/null +++ b/depends/classparser/include/classparser_config.h @@ -0,0 +1,23 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifdef CLASSPARSER_LIBRARY +# define CLASSPARSER_EXPORT Q_DECL_EXPORT +#else +# define CLASSPARSER_EXPORT Q_DECL_IMPORT +#endif + diff --git a/depends/classparser/include/javautils.h b/depends/classparser/include/javautils.h new file mode 100644 index 00000000..63e5ec26 --- /dev/null +++ b/depends/classparser/include/javautils.h @@ -0,0 +1,29 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include +#include "classparser_config.h" + +#define MCVer_Unknown "Unknown" + +namespace javautils +{ + /** + * @brief Get the version from a minecraft.jar by parsing its class files. Expensive! + */ + QString GetMinecraftJarVersion(QString jar); +} diff --git a/depends/classparser/src/annotations.cpp b/depends/classparser/src/annotations.cpp new file mode 100644 index 00000000..fc0c98fa --- /dev/null +++ b/depends/classparser/src/annotations.cpp @@ -0,0 +1,83 @@ +#include "classfile.h" +#include "annotations.h" +#include + +namespace java +{ + std::string annotation::toString() + { + std::ostringstream ss; + ss << "Annotation type : " << type_index << " - " << pool[type_index].str_data << std::endl; + ss << "Contains " << name_val_pairs.size() << " pairs:" << std::endl; + for(unsigned i = 0; i < name_val_pairs.size(); i++) + { + std::pair &val = name_val_pairs[i]; + auto name_idx = val.first; + ss << pool[name_idx].str_data << "(" << name_idx << ")" << " = " << val.second->toString() << std::endl; + } + return ss.str(); + } + + annotation * annotation::read (util::membuffer& input, constant_pool& pool) + { + uint16_t type_index = 0; + input.read_be(type_index); + annotation * ann = new annotation(type_index,pool); + + uint16_t num_pairs = 0; + input.read_be(num_pairs); + while(num_pairs) + { + uint16_t name_idx = 0; + // read name index + input.read_be(name_idx); + auto elem = element_value::readElementValue(input,pool); + // read value + ann->add_pair(name_idx, elem); + num_pairs --; + } + return ann; + } + + element_value* element_value::readElementValue ( util::membuffer& input, java::constant_pool& pool ) + { + element_value_type type = INVALID; + input.read(type); + uint16_t index = 0; + uint16_t index2 = 0; + std::vector vals; + switch (type) + { + case PRIMITIVE_BYTE: + case PRIMITIVE_CHAR: + case PRIMITIVE_DOUBLE: + case PRIMITIVE_FLOAT: + case PRIMITIVE_INT: + case PRIMITIVE_LONG: + case PRIMITIVE_SHORT: + case PRIMITIVE_BOOLEAN: + case STRING: + input.read_be(index); + return new element_value_simple(type, index, pool); + case ENUM_CONSTANT: + input.read_be(index); + input.read_be(index2); + return new element_value_enum(type, index, index2, pool); + case CLASS: // Class + input.read_be(index); + return new element_value_class(type, index, pool); + case ANNOTATION: // Annotation + // FIXME: runtime visibility info needs to be passed from parent + return new element_value_annotation(ANNOTATION, annotation::read(input, pool), pool); + case ARRAY: // Array + input.read_be(index); + for (int i = 0; i < index; i++) + { + vals.push_back(element_value::readElementValue(input, pool)); + } + return new element_value_array(ARRAY, vals, pool); + default: + throw new java::classfile_exception(); + } + } +} \ No newline at end of file diff --git a/depends/classparser/src/annotations.h b/depends/classparser/src/annotations.h new file mode 100644 index 00000000..b115dc0b --- /dev/null +++ b/depends/classparser/src/annotations.h @@ -0,0 +1,252 @@ +#pragma once +#include "classfile.h" +#include +#include + +namespace java +{ + enum element_value_type : uint8_t + { + INVALID = 0, + STRING = 's', + ENUM_CONSTANT = 'e', + CLASS = 'c', + ANNOTATION = '@', + ARRAY = '[', // one array dimension + PRIMITIVE_INT = 'I', // integer + PRIMITIVE_BYTE = 'B', // signed byte + PRIMITIVE_CHAR = 'C', // Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16 + PRIMITIVE_DOUBLE = 'D', // double-precision floating-point value + PRIMITIVE_FLOAT = 'F', // single-precision floating-point value + PRIMITIVE_LONG = 'J', // long integer + PRIMITIVE_SHORT = 'S', // signed short + PRIMITIVE_BOOLEAN = 'Z' // true or false + }; + /** + * The element_value structure is a discriminated union representing the value of an element-value pair. + * It is used to represent element values in all attributes that describe annotations + * - RuntimeVisibleAnnotations + * - RuntimeInvisibleAnnotations + * - RuntimeVisibleParameterAnnotations + * - RuntimeInvisibleParameterAnnotations). + * + * The element_value structure has the following format: + */ + class element_value + { + protected: + element_value_type type; + constant_pool & pool; + + public: + element_value(element_value_type type, constant_pool & pool): type(type), pool(pool) {}; + + element_value_type getElementValueType() + { + return type; + } + + virtual std::string toString() = 0; + + static element_value * readElementValue(util::membuffer & input, constant_pool & pool); + }; + + /** + * Each value of the annotations table represents a single runtime-visible annotation on a program element. + * The annotation structure has the following format: + */ + class annotation + { + public: + typedef std::vector< std::pair > value_list; + protected: + /** + * The value of the type_index item must be a valid index into the constant_pool table. + * The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure + * representing a field descriptor representing the annotation type corresponding + * to the annotation represented by this annotation structure. + */ + uint16_t type_index; + /** + * map between element_name_index and value. + * + * The value of the element_name_index item must be a valid index into the constant_pool table. + * The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure representing + * a valid field descriptor (§4.3.2) that denotes the name of the annotation type element represented + * by this element_value_pairs entry. + */ + value_list name_val_pairs; + /** + * Reference to the parent constant pool + */ + constant_pool & pool; + public: + annotation(uint16_t type_index, constant_pool& pool):type_index(type_index), pool(pool) {}; + ~annotation() + { + for(unsigned i = 0 ; i < name_val_pairs.size(); i++) + { + delete name_val_pairs[i].second; + } + } + void add_pair(uint16_t key, element_value * value) + { + name_val_pairs.push_back(std::make_pair(key, value)); + }; + value_list::const_iterator begin() + { + return name_val_pairs.cbegin(); + } + value_list::const_iterator end() + { + return name_val_pairs.cend(); + } + std::string toString(); + static annotation * read(util::membuffer & input, constant_pool & pool); + }; + typedef std::vector annotation_table; + + + /// type for simple value annotation elements + class element_value_simple : public element_value + { + protected: + /// index of the constant in the constant pool + uint16_t index; + public: + element_value_simple(element_value_type type, uint16_t index , constant_pool& pool): + element_value(type, pool), index(index) + { + // TODO: verify consistency + }; + uint16_t getIndex() + { + return index; + } + virtual std::string toString() + { + return pool[index].toString(); + }; + }; + /// The enum_const_value item is used if the tag item is 'e'. + class element_value_enum : public element_value + { + protected: + /** + * The value of the type_name_index item must be a valid index into the constant_pool table. + * The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure + * representing a valid field descriptor (§4.3.2) that denotes the internal form of the binary + * name (§4.2.1) of the type of the enum constant represented by this element_value structure. + */ + uint16_t typeIndex; + /** + * The value of the const_name_index item must be a valid index into the constant_pool table. + * The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure + * representing the simple name of the enum constant represented by this element_value structure. + */ + uint16_t valueIndex; + public: + element_value_enum(element_value_type type, uint16_t typeIndex, uint16_t valueIndex, constant_pool& pool): + element_value(type, pool), typeIndex(typeIndex), valueIndex(valueIndex) + { + // TODO: verify consistency + } + uint16_t getValueIndex() + { + return valueIndex; + } + uint16_t getTypeIndex() + { + return typeIndex; + } + virtual std::string toString() + { + return "enum value"; + }; + }; + + class element_value_class : public element_value + { + protected: + /** + * The class_info_index item must be a valid index into the constant_pool table. + * The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure + * representing the return descriptor (§4.3.3) of the type that is reified by the class + * represented by this element_value structure. + * + * For example, 'V' for Void.class, 'Ljava/lang/Object;' for Object, etc. + * + * Or in plain english, you can store type information in annotations. Yay. + */ + uint16_t classIndex; + public: + element_value_class(element_value_type type, uint16_t classIndex, constant_pool& pool): + element_value(type, pool), classIndex(classIndex) + { + // TODO: verify consistency + } + uint16_t getIndex() + { + return classIndex; + } + virtual std::string toString() + { + return "class"; + }; + }; + + /// nested annotations... yay + class element_value_annotation : public element_value + { + private: + annotation * nestedAnnotation; + public: + element_value_annotation(element_value_type type, annotation * nestedAnnotation, constant_pool& pool): + element_value(type, pool), nestedAnnotation(nestedAnnotation) + {}; + ~element_value_annotation() + { + if(nestedAnnotation) + { + delete nestedAnnotation; + nestedAnnotation = nullptr; + } + } + virtual std::string toString() + { + return "nested annotation"; + }; + }; + + /// and arrays! + class element_value_array : public element_value + { + public: + typedef std::vector elem_vec; + protected: + elem_vec values; + public: + element_value_array ( element_value_type type, std::vector & values, constant_pool& pool ): + element_value(type, pool), values(values) + {}; + ~element_value_array () + { + for(unsigned i = 0; i < values.size();i++) + { + delete values[i]; + } + }; + elem_vec::const_iterator begin() + { + return values.cbegin(); + } + elem_vec::const_iterator end() + { + return values.cend(); + } + virtual std::string toString() + { + return "array"; + }; + }; +} \ No newline at end of file diff --git a/depends/classparser/src/classfile.h b/depends/classparser/src/classfile.h new file mode 100644 index 00000000..33207e99 --- /dev/null +++ b/depends/classparser/src/classfile.h @@ -0,0 +1,153 @@ +#pragma once +#include "membuffer.h" +#include "constants.h" +#include "annotations.h" +#include +namespace java +{ + /** + * Class representing a Java .class file + */ + class classfile : public util::membuffer + { + public: + classfile(char * data, std::size_t size) : membuffer(data, size) + { + valid = false; + is_synthetic = false; + read_be(magic); + if(magic != 0xCAFEBABE) + throw new classfile_exception(); + read_be(minor_version); + read_be(major_version); + constants.load(*this); + read_be(access_flags); + read_be(this_class); + read_be(super_class); + + // Interfaces + uint16_t iface_count = 0; + read_be(iface_count); + while (iface_count) + { + uint16_t iface; + read_be(iface); + interfaces.push_back(iface); + iface_count --; + } + + // Fields + // read fields (and attributes from inside fields) (and possible inner classes. yay for recursion!) + // for now though, we will ignore all attributes + /* + * field_info + * { + * u2 access_flags; + * u2 name_index; + * u2 descriptor_index; + * u2 attributes_count; + * attribute_info attributes[attributes_count]; + * } + */ + uint16_t field_count = 0; + read_be(field_count); + while (field_count) + { + // skip field stuff + skip(6); + // and skip field attributes + uint16_t attr_count = 0; + read_be(attr_count); + while(attr_count) + { + skip(2); + uint32_t attr_length = 0; + read_be(attr_length); + skip(attr_length); + attr_count --; + } + field_count --; + } + + // class methods + /* + * method_info + * { + * u2 access_flags; + * u2 name_index; + * u2 descriptor_index; + * u2 attributes_count; + * attribute_info attributes[attributes_count]; + * } + */ + uint16_t method_count = 0; + read_be(method_count); + while( method_count ) + { + skip(6); + // and skip method attributes + uint16_t attr_count = 0; + read_be(attr_count); + while(attr_count) + { + skip(2); + uint32_t attr_length = 0; + read_be(attr_length); + skip(attr_length); + attr_count --; + } + method_count --; + } + + // class attributes + // there are many kinds of attributes. this is just the generic wrapper structure. + // type is decided by attribute name. extensions to the standard are *possible* + // class annotations are one kind of a attribute (one per class) + /* + * attribute_info + * { + * u2 attribute_name_index; + * u4 attribute_length; + * u1 info[attribute_length]; + * } + */ + uint16_t class_attr_count = 0; + read_be(class_attr_count); + while(class_attr_count) + { + uint16_t name_idx = 0; + read_be(name_idx); + uint32_t attr_length = 0; + read_be(attr_length); + + auto name = constants[name_idx]; + if(name.str_data == "RuntimeVisibleAnnotations") + { + uint16_t num_annotations = 0; + read_be(num_annotations); + while (num_annotations) + { + visible_class_annotations.push_back(annotation::read(*this, constants)); + num_annotations --; + } + } + else skip(attr_length); + class_attr_count --; + } + valid = true; + }; + bool valid; + bool is_synthetic; + uint32_t magic; + uint16_t minor_version; + uint16_t major_version; + constant_pool constants; + uint16_t access_flags; + uint16_t this_class; + uint16_t super_class; + // interfaces this class implements ? must be. investigate. + std::vector interfaces; + // FIXME: doesn't free up memory on delete + java::annotation_table visible_class_annotations; + }; +} \ No newline at end of file diff --git a/depends/classparser/src/constants.h b/depends/classparser/src/constants.h new file mode 100644 index 00000000..61aa5687 --- /dev/null +++ b/depends/classparser/src/constants.h @@ -0,0 +1,212 @@ +#pragma once +#include "errors.h" +#include + +namespace java +{ + class constant + { + public: + enum type_t : uint8_t + { + j_hole = 0, // HACK: this is a hole in the array, because java is crazy + j_string_data = 1, + j_int = 3, + j_float = 4, + j_long = 5, + j_double = 6, + j_class = 7, + j_string = 8, + j_fieldref = 9, + j_methodref = 10, + j_interface_methodref = 11, + j_nameandtype = 12 + } type; + + constant(util::membuffer & buf ) + { + buf.read(type); + // invalid constant type! + if(type > j_nameandtype || type == (type_t)0 || type == (type_t)2) + throw new classfile_exception(); + + // load data depending on type + switch(type) + { + case j_float: + case j_int: + buf.read_be(int_data); // same as float data really + break; + case j_double: + case j_long: + buf.read_be(long_data); // same as double + break; + case j_class: + buf.read_be(ref_type.class_idx); + break; + case j_fieldref: + case j_methodref: + case j_interface_methodref: + buf.read_be(ref_type.class_idx); + buf.read_be(ref_type.name_and_type_idx); + break; + case j_string: + buf.read_be(index); + break; + case j_string_data: + // HACK HACK: for now, we call these UTF-8 and do no further processing. + // Later, we should do some decoding. It's really modified UTF-8 + // * U+0000 is represented as 0xC0,0x80 invalid character + // * any single zero byte ends the string + // * characters above U+10000 are encoded like in CESU-8 + buf.read_jstr(str_data); + break; + case j_nameandtype: + buf.read_be(name_and_type.name_index); + buf.read_be(name_and_type.descriptor_index); + break; + } + } + + constant(int fake) + { + type = j_hole; + } + + std::string toString() + { + std::ostringstream ss; + switch(type) + { + case j_hole: + ss << "Fake legacy entry"; + break; + case j_float: + ss << "Float: " << float_data; + break; + case j_double: + ss << "Double: " << double_data; + break; + case j_int: + ss << "Int: " << int_data; + break; + case j_long: + ss << "Long: " << long_data; + break; + case j_string_data: + ss << "StrData: " << str_data; + break; + case j_string: + ss << "Str: " << index; + break; + case j_fieldref: + ss << "FieldRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx; + break; + case j_methodref: + ss << "MethodRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx; + break; + case j_interface_methodref: + ss << "IfMethodRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx; + break; + case j_class: + ss << "Class: " << ref_type.class_idx; + break; + case j_nameandtype: + ss << "NameAndType: " << name_and_type.name_index << " " << name_and_type.descriptor_index; + break; + } + return ss.str(); + } + + std::string str_data; /** String data in 'modified utf-8'.*/ + // store everything here. + union + { + int32_t int_data; + int64_t long_data; + float float_data; + double double_data; + uint16_t index; + struct + { + /** + * Class reference: + * an index within the constant pool to a UTF-8 string containing + * the fully qualified class name (in internal format) + * Used for j_class, j_fieldref, j_methodref and j_interface_methodref + */ + uint16_t class_idx; + // used for j_fieldref, j_methodref and j_interface_methodref + uint16_t name_and_type_idx; + } ref_type; + struct + { + uint16_t name_index; + uint16_t descriptor_index; + } name_and_type; + }; + }; + + /** + * A helper class that represents the custom container used in Java class file for storage of constants + */ + class constant_pool + { + public: + /** + * Create a pool of constants + */ + constant_pool(){} + /** + * Load a java constant pool + */ + void load(util::membuffer & buf) + { + uint16_t length = 0; + buf.read_be(length); + length --; + uint16_t index = 1; + const constant * last_constant = nullptr; + while(length) + { + const constant & cnst = constant(buf); + constants.push_back(cnst); + last_constant = &constants[constants.size() - 1]; + if(last_constant->type == constant::j_double || last_constant->type == constant::j_long) + { + // push in a fake constant to preserve indexing + constants.push_back(constant(0)); + length-=2; + index+=2; + } + else + { + length--; + index++; + } + } + } + typedef std::vector container_type; + /** + * Access constants based on jar file index numbers (index of the first element is 1) + */ + java::constant & operator[](std::size_t constant_index) + { + if(constant_index == 0 || constant_index > constants.size()) + { + throw new classfile_exception(); + } + return constants[constant_index - 1]; + }; + container_type::const_iterator begin() const + { + return constants.begin(); + }; + container_type::const_iterator end() const + { + return constants.end(); + } + private: + container_type constants; + }; +} diff --git a/depends/classparser/src/errors.h b/depends/classparser/src/errors.h new file mode 100644 index 00000000..c02b07c8 --- /dev/null +++ b/depends/classparser/src/errors.h @@ -0,0 +1,6 @@ +#pragma once +#include +namespace java +{ + class classfile_exception : public std::exception {}; +} diff --git a/depends/classparser/src/javaendian.h b/depends/classparser/src/javaendian.h new file mode 100644 index 00000000..fa6207fe --- /dev/null +++ b/depends/classparser/src/javaendian.h @@ -0,0 +1,62 @@ +#pragma once +#include + +/** + * Swap bytes between big endian and local number representation + */ +namespace util +{ +#ifdef MULTIMC_BIG_ENDIAN +inline uint64_t bigswap(uint64_t x) +{ + return x; +}; +inline uint32_t bigswap(uint32_t x) +{ + return x; +}; +inline uint16_t bigswap(uint16_t x) +{ + return x; +}; +inline int64_t bigswap(int64_t x) +{ + return x; +}; +inline int32_t bigswap(int32_t x) +{ + return x; +}; +inline int16_t bigswap(int16_t x) +{ + return x; +}; +#else +inline uint64_t bigswap(uint64_t x) +{ + return (x>>56) | ((x<<40) & 0x00FF000000000000) | ((x<<24) & 0x0000FF0000000000) | ((x<<8) & 0x000000FF00000000) | + ((x>>8) & 0x00000000FF000000) | ((x>>24) & 0x0000000000FF0000) | ((x>>40) & 0x000000000000FF00) | (x<<56); +}; +inline uint32_t bigswap(uint32_t x) +{ + return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24); +}; +inline uint16_t bigswap(uint16_t x) +{ + return (x>>8) | (x<<8); +}; +inline int64_t bigswap(int64_t x) +{ + return (x>>56) | ((x<<40) & 0x00FF000000000000) | ((x<<24) & 0x0000FF0000000000) | ((x<<8) & 0x000000FF00000000) | + ((x>>8) & 0x00000000FF000000) | ((x>>24) & 0x0000000000FF0000) | ((x>>40) & 0x000000000000FF00) | (x<<56); +}; +inline int32_t bigswap(int32_t x) +{ + return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24); +}; +inline int16_t bigswap(int16_t x) +{ + return (x>>8) | (x<<8); +}; +#endif +} diff --git a/depends/classparser/src/javautils.cpp b/depends/classparser/src/javautils.cpp new file mode 100644 index 00000000..4a359031 --- /dev/null +++ b/depends/classparser/src/javautils.cpp @@ -0,0 +1,81 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "multimc_pragma.h" +#include "classfile.h" +#include "javautils.h" + +#include +#include + +namespace javautils +{ + +QString GetMinecraftJarVersion(QString jarName) +{ + QString version = MCVer_Unknown; + + // check if minecraft.jar exists + QFile jar(jarName); + if (!jar.exists()) + return version; + + // open minecraft.jar + QuaZip zip(&jar); + if (!zip.open(QuaZip::mdUnzip)) + return version; + + // open Minecraft.class + zip.setCurrentFile("net/minecraft/client/Minecraft.class", QuaZip::csSensitive); + QuaZipFile Minecraft(&zip); + if (!Minecraft.open(QuaZipFile::ReadOnly)) + return version; + + // read Minecraft.class + qint64 size = Minecraft.size(); + char *classfile = new char[size]; + Minecraft.read(classfile, size); + + // parse Minecraft.class + try { + char *temp = classfile; + java::classfile MinecraftClass(temp, size); + java::constant_pool constants = MinecraftClass.constants; + for(java::constant_pool::container_type::const_iterator iter=constants.begin(); + iter != constants.end(); iter++) + { + const java::constant & constant = *iter; + if (constant.type != java::constant::j_string_data) + continue; + const std::string & str = constant.str_data; + if (str.compare(0, 20, "Minecraft Minecraft ") == 0) + { + version = str.substr(20).data(); + break; + } + } + } catch(java::classfile_exception &) {} + + // clean up + delete[] classfile; + Minecraft.close(); + zip.close(); + jar.close(); + + return version; +} + +} diff --git a/depends/classparser/src/membuffer.h b/depends/classparser/src/membuffer.h new file mode 100644 index 00000000..2ea3a69b --- /dev/null +++ b/depends/classparser/src/membuffer.h @@ -0,0 +1,64 @@ +#pragma once +#include +#include +#include +#include +#include "javaendian.h" + +namespace util +{ + class membuffer + { + public: + membuffer(char * buffer, std::size_t size) + { + current = start = buffer; + end = start + size; + } + ~membuffer() + { + // maybe? possibly? left out to avoid confusion. for now. + //delete start; + } + /** + * Read some value. That's all ;) + */ + template + void read(T& val) + { + val = *(T *)current; + current += sizeof(T); + } + /** + * Read a big-endian number + * valid for 2-byte, 4-byte and 8-byte variables + */ + template + void read_be(T& val) + { + val = util::bigswap(*(T *)current); + current += sizeof(T); + } + /** + * Read a string in the format: + * 2B length (big endian, unsigned) + * length bytes data + */ + void read_jstr(std::string & str) + { + uint16_t length = 0; + read_be(length); + str.append(current,length); + current += length; + } + /** + * Skip N bytes + */ + void skip (std::size_t N) + { + current += N; + } + private: + char * start, *end, *current; + }; +} diff --git a/depends/groupview/CMakeLists.txt b/depends/groupview/CMakeLists.txt new file mode 100644 index 00000000..3fa2b044 --- /dev/null +++ b/depends/groupview/CMakeLists.txt @@ -0,0 +1,41 @@ +project(libGroupView) + +set(CMAKE_AUTOMOC ON) + +# Find Qt +find_package(Qt5Core REQUIRED) +find_package(Qt5Widgets REQUIRED) + +# Include Qt headers. +include_directories(${Qt5Base_INCLUDE_DIRS}) + +SET(LIBGROUPVIEW_HEADERS +include/groupview_config.h + +# Public headers +include/categorizedsortfilterproxymodel.h +include/categorizedview.h +include/categorydrawer.h + +# Private headers +src/categorizedsortfilterproxymodel_p.h +src/categorizedview_p.h +) + +SET(LIBGROUPVIEW_SOURCES +src/categorizedsortfilterproxymodel.cpp +src/categorizedview.cpp +src/categorydrawer.cpp +) + +# Set the include dir path. +SET(LIBGROUPVIEW_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE) + +# Include self. +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(${CMAKE_BINARY_DIR}/include) + +add_definitions(-DLIBGROUPVIEW_LIBRARY) + +add_library(libGroupView SHARED ${LIBGROUPVIEW_SOURCES} ${LIBGROUPVIEW_HEADERS}) +qt5_use_modules(libGroupView Core Widgets) diff --git a/depends/groupview/include/categorizedsortfilterproxymodel.h b/depends/groupview/include/categorizedsortfilterproxymodel.h new file mode 100644 index 00000000..d90fb254 --- /dev/null +++ b/depends/groupview/include/categorizedsortfilterproxymodel.h @@ -0,0 +1,175 @@ +/* + * This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López + * Copyright (C) 2007 John Tapsell + * + * This library 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 library 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 library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KCATEGORIZEDSORTFILTERPROXYMODEL_H +#define KCATEGORIZEDSORTFILTERPROXYMODEL_H + +#include + +#include + +class QItemSelection; + + +/** + * This class lets you categorize a view. It is meant to be used along with + * KCategorizedView class. + * + * In general terms all you need to do is to reimplement subSortLessThan() and + * compareCategories() methods. In order to make categorization work, you need + * to also call setCategorizedModel() class to enable it, since the categorization + * is disabled by default. + * + * @see KCategorizedView + * + * @author Rafael Fernández López + */ +class LIBGROUPVIEW_EXPORT KCategorizedSortFilterProxyModel + : public QSortFilterProxyModel +{ +public: + enum AdditionalRoles + { + // Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM)) + // to define additional roles. + CategoryDisplayRole = 0x17CE990A, ///< This role is used for asking the category to a given index + + CategorySortRole = 0x27857E60 ///< This role is used for sorting categories. You can return a + ///< string or a long long value. Strings will be sorted alphabetically + ///< while long long will be sorted by their value. Please note that this + ///< value won't be shown on the view, is only for sorting purposes. What will + ///< be shown as "Category" on the view will be asked with the role + ///< CategoryDisplayRole. + }; + + KCategorizedSortFilterProxyModel ( QObject *parent = 0 ); + virtual ~KCategorizedSortFilterProxyModel(); + + /** + * Overridden from QSortFilterProxyModel. Sorts the source model using + * @p column for the given @p order. + */ + virtual void sort ( int column, Qt::SortOrder order = Qt::AscendingOrder ); + + /** + * @return whether the model is categorized or not. Disabled by default. + */ + bool isCategorizedModel() const; + + /** + * Enables or disables the categorization feature. + * + * @param categorizedModel whether to enable or disable the categorization feature. + */ + void setCategorizedModel ( bool categorizedModel ); + + /** + * @return the column being used for sorting. + */ + int sortColumn() const; + + /** + * @return the sort order being used for sorting. + */ + Qt::SortOrder sortOrder() const; + + /** + * Set if the sorting using CategorySortRole will use a natural comparison + * in the case that strings were returned. If enabled, QString::localeAwareCompare + * will be used for sorting. + * + * @param sortCategoriesByNaturalComparison whether to sort using a natural comparison or not. + */ + void setSortCategoriesByNaturalComparison ( bool sortCategoriesByNaturalComparison ); + + /** + * @return whether it is being used a natural comparison for sorting. Enabled by default. + */ + bool sortCategoriesByNaturalComparison() const; + +protected: + /** + * Overridden from QSortFilterProxyModel. If you are subclassing + * KCategorizedSortFilterProxyModel, you will probably not need to reimplement this + * method. + * + * It calls compareCategories() to sort by category. If the both items are in the + * same category (i.e. compareCategories returns 0), then subSortLessThan is called. + * + * @return Returns true if the item @p left is less than the item @p right when sorting. + * + * @warning You usually won't need to reimplement this method when subclassing + * from KCategorizedSortFilterProxyModel. + */ + virtual bool lessThan ( const QModelIndex &left, const QModelIndex &right ) const; + + /** + * This method has a similar purpose as lessThan() has on QSortFilterProxyModel. + * It is used for sorting items that are in the same category. + * + * @return Returns true if the item @p left is less than the item @p right when sorting. + */ + virtual bool subSortLessThan ( const QModelIndex &left, const QModelIndex &right ) const; + + /** + * This method compares the category of the @p left index with the category + * of the @p right index. + * + * Internally and if not reimplemented, this method will ask for @p left and + * @p right models for role CategorySortRole. In order to correctly sort + * categories, the data() metod of the model should return a qlonglong (or numeric) value, or + * a QString object. QString objects will be sorted with QString::localeAwareCompare if + * sortCategoriesByNaturalComparison() is true. + * + * @note Please have present that: + * QString(QChar(QChar::ObjectReplacementCharacter)) > + * QString(QChar(QChar::ReplacementCharacter)) > + * [ all possible strings ] > + * QString(); + * + * This means that QString() will be sorted the first one, while + * QString(QChar(QChar::ObjectReplacementCharacter)) and + * QString(QChar(QChar::ReplacementCharacter)) will be sorted in last + * position. + * + * @warning Please note that data() method of the model should return always + * information of the same type. If you return a QString for an index, + * you should return always QStrings for all indexes for role CategorySortRole + * in order to correctly sort categories. You can't mix by returning + * a QString for one index, and a qlonglong for other. + * + * @note If you need a more complex layout, you will have to reimplement this + * method. + * + * @return A negative value if the category of @p left should be placed before the + * category of @p right. 0 if @p left and @p right are on the same category, and + * a positive value if the category of @p left should be placed after the + * category of @p right. + */ + virtual int compareCategories ( const QModelIndex &left, const QModelIndex &right ) const; + +private: + class Private; + Private *const d; +}; + + +#endif // KCATEGORIZEDSORTFILTERPROXYMODEL_H diff --git a/depends/groupview/include/categorizedview.h b/depends/groupview/include/categorizedview.h new file mode 100644 index 00000000..81b1dbb1 --- /dev/null +++ b/depends/groupview/include/categorizedview.h @@ -0,0 +1,332 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007, 2009 Rafael Fernández López + * + * This library 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 library 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 library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KCATEGORIZEDVIEW_H +#define KCATEGORIZEDVIEW_H + +#include + +#include + +class KCategoryDrawer; + +/** + * @short Item view for listing items in a categorized fashion optionally + * + * KCategorizedView basically has the same functionality as QListView, only that it also lets you + * layout items in a way that they are categorized visually. + * + * For it to work you will need to set a KCategorizedSortFilterProxyModel and a KCategoryDrawer + * with methods setModel() and setCategoryDrawer() respectively. Also, the model will need to be + * flagged as categorized with KCategorizedSortFilterProxyModel::setCategorizedModel(true). + * + * The way it works (if categorization enabled): + * + * - When sorting, it does more things than QListView does. It will ask the model for the + * special role CategorySortRole (@see KCategorizedSortFilterProxyModel). This can return + * a QString or an int in order to tell the view the order of categories. In this sense, for + * instance, if we are sorting by name ascending, "A" would be before than "B". If we are + * sorting by size ascending, 512 bytes would be before 1024 bytes. This way categories are + * also sorted. + * + * - When the view has to paint, it will ask the model with the role CategoryDisplayRole + * (@see KCategorizedSortFilterProxyModel). It will for instance return "F" for "foo.pdf" if + * we are sorting by name ascending, or "Small" if a certain item has 100 bytes, for example. + * + * For drawing categories, KCategoryDrawer will be used. You can inherit this class to do your own + * drawing. + * + * @note All examples cited before talk about filesystems and such, but have present that this + * is a completely generic class, and it can be used for whatever your purpose is. For + * instance when talking about animals, you can separate them by "Mammal" and "Oviparous". In + * this very case, for example, the CategorySortRole and the CategoryDisplayRole could be the + * same ("Mammal" and "Oviparous"). + * + * @note There is a really performance boost if CategorySortRole returns an int instead of a QString. + * Have present that this role is asked (n * log n) times when sorting and compared. Comparing + * ints is always faster than comparing strings, whithout mattering how fast the string + * comparison is. Consider thinking of a way of returning ints instead of QStrings if your + * model can contain a high number of items. + * + * @warning Note that for really drawing items in blocks you will need some things to be done: + * - The model set to this view has to be (or inherit if you want to do special stuff + * in it) KCategorizedSortFilterProxyModel. + * - This model needs to be set setCategorizedModel to true. + * - Set a category drawer by calling setCategoryDrawer. + * + * @see KCategorizedSortFilterProxyModel, KCategoryDrawer + * + * @author Rafael Fernández López + */ +class LIBGROUPVIEW_EXPORT KCategorizedView + : public QListView +{ + Q_OBJECT + Q_PROPERTY ( int categorySpacing READ categorySpacing WRITE setCategorySpacing ) + Q_PROPERTY ( bool alternatingBlockColors READ alternatingBlockColors WRITE setAlternatingBlockColors ) + Q_PROPERTY ( bool collapsibleBlocks READ collapsibleBlocks WRITE setCollapsibleBlocks ) + +public: + KCategorizedView ( QWidget *parent = 0 ); + + ~KCategorizedView(); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void setModel ( QAbstractItemModel *model ); + + /** + * Calls to setGridSizeOwn(). + */ + void setGridSize ( const QSize &size ); + + /** + * @warning note that setGridSize is not virtual in the base class (QListView), so if you are + * calling to this method, make sure you have a KCategorizedView pointer around. This + * means that something like: + * @code + * QListView *lv = new KCategorizedView(); + * lv->setGridSize(mySize); + * @endcode + * + * will not call to the expected setGridSize method. Instead do something like this: + * + * @code + * QListView *lv; + * ... + * KCategorizedView *cv = qobject_cast(lv); + * if (cv) { + * cv->setGridSizeOwn(mySize); + * } else { + * lv->setGridSize(mySize); + * } + * @endcode + * + * @note this method will call to QListView::setGridSize among other operations. + * + * @since 4.4 + */ + void setGridSizeOwn ( const QSize &size ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual QRect visualRect ( const QModelIndex &index ) const; + + /** + * Returns the current category drawer. + */ + KCategoryDrawer *categoryDrawer() const; + + /** + * The category drawer that will be used for drawing categories. + */ + void setCategoryDrawer ( KCategoryDrawer *categoryDrawer ); + + /** + * @return Category spacing. The spacing between categories. + * + * @since 4.4 + */ + int categorySpacing() const; + + /** + * Stablishes the category spacing. This is the spacing between categories. + * + * @since 4.4 + */ + void setCategorySpacing ( int categorySpacing ); + + /** + * @return Whether blocks should be drawn with alternating colors. + * + * @since 4.4 + */ + bool alternatingBlockColors() const; + + /** + * Sets whether blocks should be drawn with alternating colors. + * + * @since 4.4 + */ + void setAlternatingBlockColors ( bool enable ); + + /** + * @return Whether blocks can be collapsed or not. + * + * @since 4.4 + */ + bool collapsibleBlocks() const; + + /** + * Sets whether blocks can be collapsed or not. + * + * @since 4.4 + */ + void setCollapsibleBlocks ( bool enable ); + + /** + * @return Block of indexes that are into @p category. + * + * @since 4.5 + */ + QModelIndexList block ( const QString &category ); + + /** + * @return Block of indexes that are represented by @p representative. + * + * @since 4.5 + */ + QModelIndexList block ( const QModelIndex &representative ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual QModelIndex indexAt ( const QPoint &point ) const; + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void reset(); + + /** + * Signify that all item delegates size hints return the same fixed size + */ + void setUniformItemWidths(bool enable); + + /** + * Do all item delegate size hints return the same fixed size? + */ + bool uniformItemWidths() const; + +protected: + /** + * Reimplemented from QWidget. + */ + virtual void paintEvent ( QPaintEvent *event ); + + /** + * Reimplemented from QWidget. + */ + virtual void resizeEvent ( QResizeEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void setSelection ( const QRect &rect, + QItemSelectionModel::SelectionFlags flags ); + + /** + * Reimplemented from QWidget. + */ + virtual void mouseMoveEvent ( QMouseEvent *event ); + + /** + * Reimplemented from QWidget. + */ + virtual void mousePressEvent ( QMouseEvent *event ); + + /** + * Reimplemented from QWidget. + */ + virtual void mouseReleaseEvent ( QMouseEvent *event ); + + /** + * Reimplemented from QWidget. + */ + virtual void leaveEvent ( QEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void startDrag ( Qt::DropActions supportedActions ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dragMoveEvent ( QDragMoveEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dragEnterEvent ( QDragEnterEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dragLeaveEvent ( QDragLeaveEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dropEvent ( QDropEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual QModelIndex moveCursor ( CursorAction cursorAction, + Qt::KeyboardModifiers modifiers ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void rowsAboutToBeRemoved ( const QModelIndex &parent, + int start, + int end ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void updateGeometries(); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void currentChanged ( const QModelIndex ¤t, + const QModelIndex &previous ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dataChanged ( const QModelIndex &topLeft, + const QModelIndex &bottomRight ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void rowsInserted ( const QModelIndex &parent, + int start, + int end ); + +protected Q_SLOTS: + /** + * @internal + * Reposition items as needed. + */ + virtual void slotLayoutChanged(); + virtual void slotCollapseOrExpandClicked ( QModelIndex ); + +private: + class Private; + Private *const d; +}; + +#endif // KCATEGORIZEDVIEW_H diff --git a/depends/groupview/include/categorydrawer.h b/depends/groupview/include/categorydrawer.h new file mode 100644 index 00000000..f37422ec --- /dev/null +++ b/depends/groupview/include/categorydrawer.h @@ -0,0 +1,179 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007, 2009 Rafael Fernández López + * + * This library 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 library 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 library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KCATEGORYDRAWER_H +#define KCATEGORYDRAWER_H + +#include + +#include +#include + +class QPainter; +class QModelIndex; +class QStyleOption; +class KCategorizedView; + + +/** + * @since 4.5 + */ +class LIBGROUPVIEW_EXPORT KCategoryDrawer + : public QObject +{ + friend class KCategorizedView; + Q_OBJECT + + +public: + KCategoryDrawer ( KCategorizedView *view ); + virtual ~KCategoryDrawer(); + + /** + * @return The view this category drawer is associated with. + */ + KCategorizedView *view() const; + + /** + * This method purpose is to draw a category represented by the given + * @param index with the given @param sortRole sorting role + * + * @note This method will be called one time per category, always with the + * first element in that category + */ + virtual void drawCategory ( const QModelIndex &index, + int sortRole, + const QStyleOption &option, + QPainter *painter ) const; + + /** + * @return The category height for the category representated by index @p index with + * style options @p option. + */ + virtual int categoryHeight ( const QModelIndex &index, const QStyleOption &option ) const; + + //TODO KDE5: make virtual as leftMargin + /** + * @note 0 by default + * + * @since 4.4 + */ + int leftMargin() const; + + /** + * @note call to this method on the KCategoryDrawer constructor to set the left margin + * + * @since 4.4 + */ + void setLeftMargin ( int leftMargin ); + + //TODO KDE5: make virtual as rightMargin + /** + * @note 0 by default + * + * @since 4.4 + */ + int rightMargin() const; + + /** + * @note call to this method on the KCategoryDrawer constructor to set the right margin + * + * @since 4.4 + */ + void setRightMargin ( int rightMargin ); + + KCategoryDrawer &operator= ( const KCategoryDrawer &cd ); +protected: + /** + * Method called when the mouse button has been pressed. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + * + * @warning You explicitly have to determine whether the event has been accepted or not. You + * have to call event->accept() or event->ignore() at all possible case branches in + * your code. + */ + virtual void mouseButtonPressed ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); + + /** + * Method called when the mouse button has been released. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + * + * @warning You explicitly have to determine whether the event has been accepted or not. You + * have to call event->accept() or event->ignore() at all possible case branches in + * your code. + */ + virtual void mouseButtonReleased ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); + + /** + * Method called when the mouse has been moved. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + */ + virtual void mouseMoved ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); + + /** + * Method called when the mouse button has been double clicked. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + * + * @warning You explicitly have to determine whether the event has been accepted or not. You + * have to call event->accept() or event->ignore() at all possible case branches in + * your code. + */ + virtual void mouseButtonDoubleClicked ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); + + /** + * Method called when the mouse button has left this block. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + */ + virtual void mouseLeft ( const QModelIndex &index, const QRect &blockRect ); + +private: + class Private; + Private *const d; +Q_SIGNALS: + /** + * This signal becomes emitted when collapse or expand has been clicked. + */ + void collapseOrExpandClicked ( const QModelIndex &index ); + + /** + * Emit this signal on your subclass implementation to notify that something happened. Usually + * this will be triggered when you have received an event, and its position matched some "hot spot". + * + * You give this action the integer you want, and having connected this signal to your code, + * the connected slot can perform the needed changes (view, model, selection model, delegate...) + */ + void actionRequested ( int action, const QModelIndex &index ); +}; + +#endif // KCATEGORYDRAWER_H diff --git a/depends/groupview/include/groupview_config.h b/depends/groupview/include/groupview_config.h new file mode 100644 index 00000000..86bed139 --- /dev/null +++ b/depends/groupview/include/groupview_config.h @@ -0,0 +1,27 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#ifndef LIBINSTANCE_CONFIG_H +//#define LIBINSTANCE_CONFIG_H + +#include + +#ifdef LIBGROUPVIEW_LIBRARY +# define LIBGROUPVIEW_EXPORT Q_DECL_EXPORT +#else +# define LIBGROUPVIEW_EXPORT Q_DECL_IMPORT +#endif + +//#endif // LIBINSTANCE_CONFIG_H diff --git a/depends/groupview/src/categorizedsortfilterproxymodel.cpp b/depends/groupview/src/categorizedsortfilterproxymodel.cpp new file mode 100644 index 00000000..09da9dd3 --- /dev/null +++ b/depends/groupview/src/categorizedsortfilterproxymodel.cpp @@ -0,0 +1,168 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López + * Copyright (C) 2007 John Tapsell + * + * This library 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 library 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 library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "categorizedsortfilterproxymodel.h" +#include "categorizedsortfilterproxymodel_p.h" + +#include + +#include +#include +#include + +KCategorizedSortFilterProxyModel::KCategorizedSortFilterProxyModel ( QObject *parent ) + : QSortFilterProxyModel ( parent ) + , d ( new Private() ) +{ +} + +KCategorizedSortFilterProxyModel::~KCategorizedSortFilterProxyModel() +{ + delete d; +} + +void KCategorizedSortFilterProxyModel::sort ( int column, Qt::SortOrder order ) +{ + d->sortColumn = column; + d->sortOrder = order; + + QSortFilterProxyModel::sort ( column, order ); +} + +bool KCategorizedSortFilterProxyModel::isCategorizedModel() const +{ + return d->categorizedModel; +} + +void KCategorizedSortFilterProxyModel::setCategorizedModel ( bool categorizedModel ) +{ + if ( categorizedModel == d->categorizedModel ) + { + return; + } + + d->categorizedModel = categorizedModel; + + invalidate(); +} + +int KCategorizedSortFilterProxyModel::sortColumn() const +{ + return d->sortColumn; +} + +Qt::SortOrder KCategorizedSortFilterProxyModel::sortOrder() const +{ + return d->sortOrder; +} + +void KCategorizedSortFilterProxyModel::setSortCategoriesByNaturalComparison ( bool sortCategoriesByNaturalComparison ) +{ + if ( sortCategoriesByNaturalComparison == d->sortCategoriesByNaturalComparison ) + { + return; + } + + d->sortCategoriesByNaturalComparison = sortCategoriesByNaturalComparison; + + invalidate(); +} + +bool KCategorizedSortFilterProxyModel::sortCategoriesByNaturalComparison() const +{ + return d->sortCategoriesByNaturalComparison; +} + +bool KCategorizedSortFilterProxyModel::lessThan ( const QModelIndex &left, const QModelIndex &right ) const +{ + if ( d->categorizedModel ) + { + int compare = compareCategories ( left, right ); + + if ( compare > 0 ) // left is greater than right + { + return false; + } + else if ( compare < 0 ) // left is less than right + { + return true; + } + } + + return subSortLessThan ( left, right ); +} + +bool KCategorizedSortFilterProxyModel::subSortLessThan ( const QModelIndex &left, const QModelIndex &right ) const +{ + return QSortFilterProxyModel::lessThan ( left, right ); +} + +int KCategorizedSortFilterProxyModel::compareCategories ( const QModelIndex &left, const QModelIndex &right ) const +{ + QVariant l = ( left.model() ? left.model()->data ( left, CategorySortRole ) : QVariant() ); + QVariant r = ( right.model() ? right.model()->data ( right, CategorySortRole ) : QVariant() ); + + Q_ASSERT ( l.isValid() ); + Q_ASSERT ( r.isValid() ); + Q_ASSERT ( l.type() == r.type() ); + + if ( l.type() == QVariant::String ) + { + QString lstr = l.toString(); + QString rstr = r.toString(); + + /* + if ( d->sortCategoriesByNaturalComparison ) + { + return KStringHandler::naturalCompare ( lstr, rstr ); + } + else + { + */ + if ( lstr < rstr ) + { + return -1; + } + + if ( lstr > rstr ) + { + return 1; + } + + return 0; + //} + } + + qlonglong lint = l.toLongLong(); + qlonglong rint = r.toLongLong(); + + if ( lint < rint ) + { + return -1; + } + + if ( lint > rint ) + { + return 1; + } + + return 0; +} diff --git a/depends/groupview/src/categorizedsortfilterproxymodel_p.h b/depends/groupview/src/categorizedsortfilterproxymodel_p.h new file mode 100644 index 00000000..d7e7c9a0 --- /dev/null +++ b/depends/groupview/src/categorizedsortfilterproxymodel_p.h @@ -0,0 +1,48 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López + * Copyright (C) 2007 John Tapsell + * + * This library 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 library 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 library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KCATEGORIZEDSORTFILTERPROXYMODEL_P_H +#define KCATEGORIZEDSORTFILTERPROXYMODEL_P_H + +class KCategorizedSortFilterProxyModel; + +class KCategorizedSortFilterProxyModel::Private +{ +public: + Private() + : sortColumn ( 0 ) + , sortOrder ( Qt::AscendingOrder ) + , categorizedModel ( false ) + , sortCategoriesByNaturalComparison ( true ) + { + } + + ~Private() + { + } + + int sortColumn; + Qt::SortOrder sortOrder; + bool categorizedModel; + bool sortCategoriesByNaturalComparison; +}; + +#endif diff --git a/depends/groupview/src/categorizedview.cpp b/depends/groupview/src/categorizedview.cpp new file mode 100644 index 00000000..f4449949 --- /dev/null +++ b/depends/groupview/src/categorizedview.cpp @@ -0,0 +1,1713 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007, 2009 Rafael Fernández López + * + * This library 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 library 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 library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * IMPLEMENTATION NOTES: + * + * QListView::setRowHidden() and QListView::isRowHidden() are not taken into + * account. This methods should actually not exist. This effect should be handled + * by an hypothetical QSortFilterProxyModel which filters out the desired rows. + * + * In case this needs to be implemented, contact me, but I consider this a faulty + * design. + */ + +#include "categorizedview.h" +#include "categorizedview_p.h" + +#include // trunc on C99 compliant systems +//#include // trunc for not C99 compliant systems + +#include +#include +#include + +#include "categorydrawer.h" +#include "categorizedsortfilterproxymodel.h" + +//BEGIN: Private part + +struct KCategorizedView::Private::Item +{ + Item() + : topLeft ( QPoint() ) + , size ( QSize() ) + { + } + + QPoint topLeft; + QSize size; +}; + +struct KCategorizedView::Private::Block +{ + Block() + : topLeft ( QPoint() ) + , height ( -1 ) + , firstIndex ( QModelIndex() ) + , quarantineStart ( QModelIndex() ) + , items ( QList() ) + , outOfQuarantine ( false ) + , alternate ( false ) + , collapsed ( false ) + { + } + + bool operator!= ( const Block &rhs ) const + { + return firstIndex != rhs.firstIndex; + } + + static bool lessThan ( const Block &left, const Block &right ) + { + Q_ASSERT ( left.firstIndex.isValid() ); + Q_ASSERT ( right.firstIndex.isValid() ); + return left.firstIndex.row() < right.firstIndex.row(); + } + + QPoint topLeft; + int height; + QPersistentModelIndex firstIndex; + // if we have n elements on this block, and we inserted an element at position i. The quarantine + // will start at index (i, column, parent). This means that for all elements j where i <= j <= n, the + // visual rect position of item j will have to be recomputed (cannot use the cached point). The quarantine + // will only affect the current block, since the rest of blocks can be affected only in the way + // that the whole block will have different offset, but items will keep the same relative position + // in terms of their parent blocks. + QPersistentModelIndex quarantineStart; + QList items; + + // this affects the whole block, not items separately. items contain the topLeft point relative + // to the block. Because of insertions or removals a whole block can be moved, so the whole block + // will enter in quarantine, what is faster than moving all items in absolute terms. + bool outOfQuarantine; + + // should we alternate its color ? is just a hint, could not be used + bool alternate; + bool collapsed; +}; + +KCategorizedView::Private::Private ( KCategorizedView *q ) + : q ( q ) + , proxyModel ( 0 ) + , categoryDrawer ( 0 ) + , categorySpacing ( 5 ) + , alternatingBlockColors ( false ) + , collapsibleBlocks ( false ) + , hoveredBlock ( new Block() ) + , hoveredIndex ( QModelIndex() ) + , pressedPosition ( QPoint() ) + , rubberBandRect ( QRect() ) + , constantItemWidth( 0 ) +{ +} + +KCategorizedView::Private::~Private() +{ + delete hoveredBlock; +} + +bool KCategorizedView::Private::isCategorized() const +{ + return proxyModel && categoryDrawer && proxyModel->isCategorizedModel(); +} + +QStyleOptionViewItemV4 KCategorizedView::Private::blockRect ( const QModelIndex &representative ) +{ + QStyleOptionViewItemV4 option ( q->viewOptions() ); + const int height = categoryDrawer->categoryHeight ( representative, option ); + const QString categoryDisplay = representative.data ( KCategorizedSortFilterProxyModel::CategoryDisplayRole ).toString(); + QPoint pos = blockPosition ( categoryDisplay ); + pos.ry() -= height; + option.rect.setTopLeft ( pos ); + option.rect.setWidth ( viewportWidth() + categoryDrawer->leftMargin() + categoryDrawer->rightMargin() ); + option.rect.setHeight ( height + blockHeight ( categoryDisplay ) ); + option.rect = mapToViewport ( option.rect ); + + return option; +} + +QPair KCategorizedView::Private::intersectingIndexesWithRect ( const QRect &_rect ) const +{ + const int rowCount = proxyModel->rowCount(); + + const QRect rect = _rect.normalized(); + + // binary search to find out the top border + int bottom = 0; + int top = rowCount - 1; + while ( bottom <= top ) + { + const int middle = ( bottom + top ) / 2; + const QModelIndex index = proxyModel->index ( middle, q->modelColumn(), q->rootIndex() ); + QRect itemRect = q->visualRect ( index ); + const int verticalOff = q->verticalOffset(); + const int horizontalOff = q->horizontalOffset(); + itemRect.topLeft().ry() += verticalOff; + itemRect.topLeft().rx() += horizontalOff; + itemRect.bottomRight().ry() += verticalOff; + itemRect.bottomRight().rx() += horizontalOff; + if ( itemRect.bottomRight().y() <= rect.topLeft().y() ) + { + bottom = middle + 1; + } + else + { + top = middle - 1; + } + } + + const QModelIndex bottomIndex = proxyModel->index ( bottom, q->modelColumn(), q->rootIndex() ); + + // binary search to find out the bottom border + bottom = 0; + top = rowCount - 1; + while ( bottom <= top ) + { + const int middle = ( bottom + top ) / 2; + const QModelIndex index = proxyModel->index ( middle, q->modelColumn(), q->rootIndex() ); + QRect itemRect = q->visualRect ( index ); + const int verticalOff = q->verticalOffset(); + const int horizontalOff = q->horizontalOffset(); + itemRect.topLeft().ry() += verticalOff; + itemRect.topLeft().rx() += horizontalOff; + itemRect.bottomRight().ry() += verticalOff; + itemRect.bottomRight().rx() += horizontalOff; + if ( itemRect.topLeft().y() <= rect.bottomRight().y() ) + { + bottom = middle + 1; + } + else + { + top = middle - 1; + } + } + + const QModelIndex topIndex = proxyModel->index ( top, q->modelColumn(), q->rootIndex() ); + + return qMakePair ( bottomIndex, topIndex ); +} + +QPoint KCategorizedView::Private::blockPosition ( const QString &category ) +{ + Block &block = blocks[category]; + + if ( block.outOfQuarantine && !block.topLeft.isNull() ) + { + return block.topLeft; + } + + QPoint res ( categorySpacing, 0 ); + + const QModelIndex index = block.firstIndex; + + for ( QHash::Iterator it = blocks.begin(); it != blocks.end(); ++it ) + { + Block &block = *it; + const QModelIndex categoryIndex = block.firstIndex; + if ( index.row() < categoryIndex.row() ) + { + continue; + } + res.ry() += categoryDrawer->categoryHeight ( categoryIndex, q->viewOptions() ) + categorySpacing; + if ( index.row() == categoryIndex.row() ) + { + continue; + } + res.ry() += blockHeight ( it.key() ); + } + + block.outOfQuarantine = true; + block.topLeft = res; + + return res; +} + +int KCategorizedView::Private::blockHeight ( const QString &category ) +{ + Block &block = blocks[category]; + + if ( block.collapsed ) + { + return 0; + } + + if ( block.height > -1 ) + { + return block.height; + } + + const QModelIndex firstIndex = block.firstIndex; + const QModelIndex lastIndex = proxyModel->index ( firstIndex.row() + block.items.count() - 1, q->modelColumn(), q->rootIndex() ); + const QRect topLeft = q->visualRect ( firstIndex ); + QRect bottomRight = q->visualRect ( lastIndex ); + + if ( hasGrid() ) + { + bottomRight.setHeight ( qMax ( bottomRight.height(), q->gridSize().height() ) ); + } + else + { + if ( !q->uniformItemSizes() ) + { + bottomRight.setHeight ( highestElementInLastRow ( block ) + q->spacing() * 2 ); + } + } + + const int height = bottomRight.bottomRight().y() - topLeft.topLeft().y() + 1; + block.height = height; + + return height; +} + +int KCategorizedView::Private::viewportWidth() const +{ + return q->viewport()->width() - categorySpacing * 2 - categoryDrawer->leftMargin() - categoryDrawer->rightMargin(); +} + +void KCategorizedView::Private::regenerateAllElements() +{ + for ( QHash::Iterator it = blocks.begin(); it != blocks.end(); ++it ) + { + Block &block = *it; + block.outOfQuarantine = false; + block.quarantineStart = block.firstIndex; + block.height = -1; + } +} + +void KCategorizedView::Private::rowsInserted ( const QModelIndex &parent, int start, int end ) +{ + if ( !isCategorized() ) + { + return; + } + + for ( int i = start; i <= end; ++i ) + { + const QModelIndex index = proxyModel->index ( i, q->modelColumn(), parent ); + + Q_ASSERT ( index.isValid() ); + + const QString category = categoryForIndex ( index ); + + Block &block = blocks[category]; + + //BEGIN: update firstIndex + // save as firstIndex in block if + // - it forced the category creation (first element on this category) + // - it is before the first row on that category + const QModelIndex firstIndex = block.firstIndex; + if ( !firstIndex.isValid() || index.row() < firstIndex.row() ) + { + block.firstIndex = index; + } + //END: update firstIndex + + Q_ASSERT ( block.firstIndex.isValid() ); + + const int firstIndexRow = block.firstIndex.row(); + + block.items.insert ( index.row() - firstIndexRow, Private::Item() ); + block.height = -1; + + q->visualRect ( index ); + q->viewport()->update(); + } + + //BEGIN: update the items that are in quarantine in affected categories + { + const QModelIndex lastIndex = proxyModel->index ( end, q->modelColumn(), parent ); + const QString category = categoryForIndex ( lastIndex ); + Private::Block &block = blocks[category]; + block.quarantineStart = block.firstIndex; + } + //END: update the items that are in quarantine in affected categories + + //BEGIN: mark as in quarantine those categories that are under the affected ones + { + const QModelIndex firstIndex = proxyModel->index ( start, q->modelColumn(), parent ); + const QString category = categoryForIndex ( firstIndex ); + const QModelIndex firstAffectedCategory = blocks[category].firstIndex; + //BEGIN: order for marking as alternate those blocks that are alternate + QList blockList = blocks.values(); + qSort ( blockList.begin(), blockList.end(), Block::lessThan ); + QList firstIndexesRows; + foreach ( const Block &block, blockList ) + { + firstIndexesRows << block.firstIndex.row(); + } + //END: order for marking as alternate those blocks that are alternate + for ( QHash::Iterator it = blocks.begin(); it != blocks.end(); ++it ) + { + Private::Block &block = *it; + if ( block.firstIndex.row() > firstAffectedCategory.row() ) + { + block.outOfQuarantine = false; + block.alternate = firstIndexesRows.indexOf ( block.firstIndex.row() ) % 2; + } + else if ( block.firstIndex.row() == firstAffectedCategory.row() ) + { + block.alternate = firstIndexesRows.indexOf ( block.firstIndex.row() ) % 2; + } + } + } + //END: mark as in quarantine those categories that are under the affected ones +} + +QRect KCategorizedView::Private::mapToViewport ( const QRect &rect ) const +{ + const int dx = -q->horizontalOffset(); + const int dy = -q->verticalOffset(); + return rect.adjusted ( dx, dy, dx, dy ); +} + +QRect KCategorizedView::Private::mapFromViewport ( const QRect &rect ) const +{ + const int dx = q->horizontalOffset(); + const int dy = q->verticalOffset(); + return rect.adjusted ( dx, dy, dx, dy ); +} + +int KCategorizedView::Private::highestElementInLastRow ( const Block &block ) const +{ + //Find the highest element in the last row + const QModelIndex lastIndex = proxyModel->index ( block.firstIndex.row() + block.items.count() - 1, q->modelColumn(), q->rootIndex() ); + const QRect prevRect = q->visualRect ( lastIndex ); + int res = prevRect.height(); + QModelIndex prevIndex = proxyModel->index ( lastIndex.row() - 1, q->modelColumn(), q->rootIndex() ); + if ( !prevIndex.isValid() ) + { + return res; + } + Q_FOREVER + { + const QRect tempRect = q->visualRect ( prevIndex ); + if ( tempRect.topLeft().y() < prevRect.topLeft().y() ) + { + break; + } + res = qMax ( res, tempRect.height() ); + if ( prevIndex == block.firstIndex ) + { + break; + } + prevIndex = proxyModel->index ( prevIndex.row() - 1, q->modelColumn(), q->rootIndex() ); + } + + return res; +} + +bool KCategorizedView::Private::hasGrid() const +{ + const QSize gridSize = q->gridSize(); + return gridSize.isValid() && !gridSize.isNull(); +} + +QString KCategorizedView::Private::categoryForIndex ( const QModelIndex &index ) const +{ + const QModelIndex categoryIndex = index.model()->index ( index.row(), proxyModel->sortColumn(), index.parent() ); + return categoryIndex.data ( KCategorizedSortFilterProxyModel::CategoryDisplayRole ).toString(); +} + +void KCategorizedView::Private::leftToRightVisualRect ( const QModelIndex &index, Item &item, + const Block &block, const QPoint &blockPos ) const +{ + const int firstIndexRow = block.firstIndex.row(); + + if ( hasGrid() ) + { + const int relativeRow = index.row() - firstIndexRow; + const int maxItemsPerRow = qMax ( viewportWidth() / q->gridSize().width(), 1 ); + if ( q->layoutDirection() == Qt::LeftToRight ) + { + item.topLeft.rx() = ( relativeRow % maxItemsPerRow ) * q->gridSize().width() + blockPos.x() + categoryDrawer->leftMargin(); + } + else + { + item.topLeft.rx() = viewportWidth() - ( ( relativeRow % maxItemsPerRow ) + 1 ) * q->gridSize().width() + categoryDrawer->leftMargin() + categorySpacing; + } + item.topLeft.ry() = ( relativeRow / maxItemsPerRow ) * q->gridSize().height(); + } + else + { + if ( q->uniformItemSizes() /*|| q->uniformItemWidths()*/ ) + { + const int relativeRow = index.row() - firstIndexRow; + const QSize itemSize = q->sizeHintForIndex ( index ); + //HACK: Why is the -2 needed? + const int maxItemsPerRow = qMax ( ( viewportWidth() - q->spacing() - 2 ) / ( itemSize.width() + q->spacing() ), 1 ); + if ( q->layoutDirection() == Qt::LeftToRight ) + { + item.topLeft.rx() = ( relativeRow % maxItemsPerRow ) * itemSize.width() + blockPos.x() + categoryDrawer->leftMargin(); + } + else + { + item.topLeft.rx() = viewportWidth() - ( relativeRow % maxItemsPerRow ) * itemSize.width() + categoryDrawer->leftMargin() + categorySpacing; + } + item.topLeft.ry() = ( relativeRow / maxItemsPerRow ) * itemSize.height(); + } + else + { + const QSize currSize = q->sizeHintForIndex ( index ); + if ( index != block.firstIndex ) + { + const int viewportW = viewportWidth() - q->spacing(); + QModelIndex prevIndex = proxyModel->index ( index.row() - 1, q->modelColumn(), q->rootIndex() ); + QRect prevRect = q->visualRect ( prevIndex ); + prevRect = mapFromViewport ( prevRect ); + if ( ( prevRect.bottomRight().x() + 1 ) + currSize.width() - blockPos.x() + q->spacing() > viewportW ) + { + // we have to check the whole previous row, and see which one was the + // highest. + Q_FOREVER + { + prevIndex = proxyModel->index ( prevIndex.row() - 1, q->modelColumn(), q->rootIndex() ); + QRect tempRect = q->visualRect ( prevIndex ); + tempRect = mapFromViewport ( tempRect ); + if ( tempRect.topLeft().y() < prevRect.topLeft().y() ) + { + break; + } + if ( tempRect.bottomRight().y() > prevRect.bottomRight().y() ) + { + prevRect = tempRect; + } + if ( prevIndex == block.firstIndex ) + { + break; + } + } + if ( q->layoutDirection() == Qt::LeftToRight ) + { + item.topLeft.rx() = categoryDrawer->leftMargin() + blockPos.x() + q->spacing(); + } + else + { + item.topLeft.rx() = viewportWidth() - currSize.width() + categoryDrawer->leftMargin() + categorySpacing; + } + item.topLeft.ry() = ( prevRect.bottomRight().y() + 1 ) + q->spacing() - blockPos.y(); + } + else + { + if ( q->layoutDirection() == Qt::LeftToRight ) + { + item.topLeft.rx() = ( prevRect.bottomRight().x() + 1 ) + q->spacing(); + } + else + { + item.topLeft.rx() = ( prevRect.bottomLeft().x() - 1 ) - q->spacing() - item.size.width() + categoryDrawer->leftMargin() + categorySpacing; + } + item.topLeft.ry() = prevRect.topLeft().y() - blockPos.y(); + } + } + else + { + if ( q->layoutDirection() == Qt::LeftToRight ) + { + item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin() + q->spacing(); + } + else + { + item.topLeft.rx() = viewportWidth() - currSize.width() + categoryDrawer->leftMargin() + categorySpacing; + } + item.topLeft.ry() = q->spacing(); + } + } + } + item.size = q->sizeHintForIndex ( index ); +} + +void KCategorizedView::Private::topToBottomVisualRect ( const QModelIndex &index, Item &item, + const Block &block, const QPoint &blockPos ) const +{ + const int firstIndexRow = block.firstIndex.row(); + + if ( hasGrid() ) + { + const int relativeRow = index.row() - firstIndexRow; + item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin(); + item.topLeft.ry() = relativeRow * q->gridSize().height(); + } + else + { + if ( q->uniformItemSizes() ) + { + const int relativeRow = index.row() - firstIndexRow; + const QSize itemSize = q->sizeHintForIndex ( index ); + item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin(); + item.topLeft.ry() = relativeRow * itemSize.height(); + } + else + { + if ( index != block.firstIndex ) + { + QModelIndex prevIndex = proxyModel->index ( index.row() - 1, q->modelColumn(), q->rootIndex() ); + QRect prevRect = q->visualRect ( prevIndex ); + prevRect = mapFromViewport ( prevRect ); + item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin() + q->spacing(); + item.topLeft.ry() = ( prevRect.bottomRight().y() + 1 ) + q->spacing() - blockPos.y(); + } + else + { + item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin() + q->spacing(); + item.topLeft.ry() = q->spacing(); + } + } + } + item.size = q->sizeHintForIndex ( index ); + item.size.setWidth ( viewportWidth() ); +} + +void KCategorizedView::Private::_k_slotCollapseOrExpandClicked ( QModelIndex ) +{ +} + +//END: Private part + +//BEGIN: Public part + +KCategorizedView::KCategorizedView ( QWidget *parent ) + : QListView ( parent ) + , d ( new Private ( this ) ) +{ +} + +KCategorizedView::~KCategorizedView() +{ + delete d; +} + +void KCategorizedView::setModel ( QAbstractItemModel *model ) +{ + if ( d->proxyModel == model ) + { + return; + } + + d->blocks.clear(); + + if ( d->proxyModel ) + { + disconnect ( d->proxyModel, SIGNAL ( layoutChanged() ), this, SLOT ( slotLayoutChanged() ) ); + } + + d->proxyModel = dynamic_cast ( model ); + + if ( d->proxyModel ) + { + connect ( d->proxyModel, SIGNAL ( layoutChanged() ), this, SLOT ( slotLayoutChanged() ) ); + } + + QListView::setModel ( model ); + + // if the model already had information inserted, update our data structures to it + if ( model->rowCount() ) + { + slotLayoutChanged(); + } +} + + +void KCategorizedView::setUniformItemWidths(bool enable) +{ + d->constantItemWidth = enable; +} + + +bool KCategorizedView::uniformItemWidths() const +{ + return d->constantItemWidth; +} + +void KCategorizedView::setGridSize ( const QSize &size ) +{ + setGridSizeOwn ( size ); +} + +void KCategorizedView::setGridSizeOwn ( const QSize &size ) +{ + d->regenerateAllElements(); + QListView::setGridSize ( size ); +} + +QRect KCategorizedView::visualRect ( const QModelIndex &index ) const +{ + if ( !d->isCategorized() ) + { + return QListView::visualRect ( index ); + } + + if ( !index.isValid() ) + { + return QRect(); + } + + const QString category = d->categoryForIndex ( index ); + + if ( !d->blocks.contains ( category ) ) + { + return QRect(); + } + + Private::Block &block = d->blocks[category]; + const int firstIndexRow = block.firstIndex.row(); + + Q_ASSERT ( block.firstIndex.isValid() ); + + if ( index.row() - firstIndexRow < 0 || index.row() - firstIndexRow >= block.items.count() ) + { + return QRect(); + } + + const QPoint blockPos = d->blockPosition ( category ); + + Private::Item &ritem = block.items[index.row() - firstIndexRow]; + + if ( ritem.topLeft.isNull() || ( block.quarantineStart.isValid() && + index.row() >= block.quarantineStart.row() ) ) + { + if ( flow() == LeftToRight ) + { + d->leftToRightVisualRect ( index, ritem, block, blockPos ); + } + else + { + d->topToBottomVisualRect ( index, ritem, block, blockPos ); + } + + //BEGIN: update the quarantine start + const bool wasLastIndex = ( index.row() == ( block.firstIndex.row() + block.items.count() - 1 ) ); + if ( index.row() == block.quarantineStart.row() ) + { + if ( wasLastIndex ) + { + block.quarantineStart = QModelIndex(); + } + else + { + const QModelIndex nextIndex = d->proxyModel->index ( index.row() + 1, modelColumn(), rootIndex() ); + block.quarantineStart = nextIndex; + } + } + //END: update the quarantine start + } + + // we get now the absolute position through the relative position of the parent block. do not + // save this on ritem, since this would override the item relative position in block terms. + Private::Item item ( ritem ); + item.topLeft.ry() += blockPos.y(); + + const QSize sizeHint = item.size; + + if ( d->hasGrid() ) + { + const QSize sizeGrid = gridSize(); + const QSize resultingSize = sizeHint.boundedTo ( sizeGrid ); + QRect res ( item.topLeft.x() + ( ( sizeGrid.width() - resultingSize.width() ) / 2 ), + item.topLeft.y(), resultingSize.width(), resultingSize.height() ); + if ( block.collapsed ) + { + // we can still do binary search, while we "hide" items. We move those items in collapsed + // blocks to the left and set a 0 height. + res.setLeft ( -resultingSize.width() ); + res.setHeight ( 0 ); + } + return d->mapToViewport ( res ); + } + + QRect res ( item.topLeft.x(), item.topLeft.y(), sizeHint.width(), sizeHint.height() ); + if ( block.collapsed ) + { + // we can still do binary search, while we "hide" items. We move those items in collapsed + // blocks to the left and set a 0 height. + res.setLeft ( -sizeHint.width() ); + res.setHeight ( 0 ); + } + return d->mapToViewport ( res ); +} + +KCategoryDrawer *KCategorizedView::categoryDrawer() const +{ + return d->categoryDrawer; +} + +void KCategorizedView::setCategoryDrawer ( KCategoryDrawer *categoryDrawer ) +{ + disconnect ( d->categoryDrawer, SIGNAL ( collapseOrExpandClicked ( QModelIndex ) ), + this, SLOT ( slotCollapseOrExpandClicked ( QModelIndex ) ) ); + d->categoryDrawer = categoryDrawer; + + connect ( d->categoryDrawer, SIGNAL ( collapseOrExpandClicked ( QModelIndex ) ), + this, SLOT ( slotCollapseOrExpandClicked ( QModelIndex ) ) ); +} + +int KCategorizedView::categorySpacing() const +{ + return d->categorySpacing; +} + +void KCategorizedView::setCategorySpacing ( int categorySpacing ) +{ + if ( d->categorySpacing == categorySpacing ) + { + return; + } + + d->categorySpacing = categorySpacing; + + for ( QHash::Iterator it = d->blocks.begin(); it != d->blocks.end(); ++it ) + { + Private::Block &block = *it; + block.outOfQuarantine = false; + } +} + +bool KCategorizedView::alternatingBlockColors() const +{ + return d->alternatingBlockColors; +} + +void KCategorizedView::setAlternatingBlockColors ( bool enable ) +{ + d->alternatingBlockColors = enable; +} + +bool KCategorizedView::collapsibleBlocks() const +{ + return d->collapsibleBlocks; +} + +void KCategorizedView::setCollapsibleBlocks ( bool enable ) +{ + d->collapsibleBlocks = enable; +} + +QModelIndexList KCategorizedView::block ( const QString &category ) +{ + QModelIndexList res; + const Private::Block &block = d->blocks[category]; + if ( block.height == -1 ) + { + return res; + } + QModelIndex current = block.firstIndex; + const int first = current.row(); + for ( int i = 1; i <= block.items.count(); ++i ) + { + if ( current.isValid() ) + { + res << current; + } + current = d->proxyModel->index ( first + i, modelColumn(), rootIndex() ); + } + return res; +} + +QModelIndexList KCategorizedView::block ( const QModelIndex &representative ) +{ + return block ( representative.data ( KCategorizedSortFilterProxyModel::CategoryDisplayRole ).toString() ); +} + +QModelIndex KCategorizedView::indexAt ( const QPoint &point ) const +{ + if ( !d->isCategorized() ) + { + return QListView::indexAt ( point ); + } + + const int rowCount = d->proxyModel->rowCount(); + if ( !rowCount ) + { + return QModelIndex(); + } + + // Binary search that will try to spot if there is an index under point + int bottom = 0; + int top = rowCount - 1; + while ( bottom <= top ) + { + const int middle = ( bottom + top ) / 2; + const QModelIndex index = d->proxyModel->index ( middle, modelColumn(), rootIndex() ); + QRect rect = visualRect ( index ); + const int verticalOff = verticalOffset(); + int horizontalOff = horizontalOffset(); + if ( layoutDirection() == Qt::RightToLeft ) + { + horizontalOff *= -1; + } + rect.topLeft().ry() += verticalOff; + rect.topLeft().rx() += horizontalOff; + rect.bottomRight().ry() += verticalOff; + rect.bottomRight().rx() += horizontalOff; + if ( rect.contains ( point ) ) + { + if ( index.model()->flags ( index ) & Qt::ItemIsEnabled ) + { + return index; + } + return QModelIndex(); + } + bool directionCondition; + if ( layoutDirection() == Qt::LeftToRight ) + { + directionCondition = point.x() > rect.bottomRight().x(); + } + else + { + directionCondition = point.x() < rect.bottomLeft().x(); + } + if ( point.y() > rect.bottomRight().y() || + ( point.y() > rect.topLeft().y() && point.y() < rect.bottomRight().y() && directionCondition ) ) + { + bottom = middle + 1; + } + else + { + top = middle - 1; + } + } + return QModelIndex(); +} + +void KCategorizedView::reset() +{ + d->blocks.clear(); + QListView::reset(); +} + +void KCategorizedView::paintEvent ( QPaintEvent *event ) +{ + if ( !d->isCategorized() ) + { + QListView::paintEvent ( event ); + return; + } + + const QPair intersecting = d->intersectingIndexesWithRect ( viewport()->rect().intersected ( event->rect() ) ); + + QPainter p ( viewport() ); + p.save(); + + Q_ASSERT ( selectionModel()->model() == d->proxyModel ); + + //BEGIN: draw categories + QHash::ConstIterator it ( d->blocks.constBegin() ); + while ( it != d->blocks.constEnd() ) + { + const Private::Block &block = *it; + const QModelIndex categoryIndex = d->proxyModel->index ( block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); + QStyleOptionViewItemV4 option ( viewOptions() ); + option.features |= d->alternatingBlockColors && block.alternate ? QStyleOptionViewItemV4::Alternate + : QStyleOptionViewItemV4::None; + option.state |= !d->collapsibleBlocks || !block.collapsed ? QStyle::State_Open + : QStyle::State_None; + const int height = d->categoryDrawer->categoryHeight ( categoryIndex, option ); + QPoint pos = d->blockPosition ( it.key() ); + pos.ry() -= height; + option.rect.setTopLeft ( pos ); + option.rect.setWidth ( d->viewportWidth() + d->categoryDrawer->leftMargin() + d->categoryDrawer->rightMargin() ); + option.rect.setHeight ( height + d->blockHeight ( it.key() ) ); + option.rect = d->mapToViewport ( option.rect ); + if ( !option.rect.intersects ( viewport()->rect() ) ) + { + ++it; + continue; + } + d->categoryDrawer->drawCategory ( categoryIndex, d->proxyModel->sortRole(), option, &p ); + ++it; + } + //END: draw categories + + if ( intersecting.first.isValid() && intersecting.second.isValid() ) + { + //BEGIN: draw items + int i = intersecting.first.row(); + int indexToCheckIfBlockCollapsed = i; + QModelIndex categoryIndex; + QString category; + Private::Block *block = 0; + while ( i <= intersecting.second.row() ) + { + //BEGIN: first check if the block is collapsed. if so, we have to skip the item painting + if ( i == indexToCheckIfBlockCollapsed ) + { + categoryIndex = d->proxyModel->index ( i, d->proxyModel->sortColumn(), rootIndex() ); + category = categoryIndex.data ( KCategorizedSortFilterProxyModel::CategoryDisplayRole ).toString(); + block = &d->blocks[category]; + indexToCheckIfBlockCollapsed = block->firstIndex.row() + block->items.count(); + if ( block->collapsed ) + { + i = indexToCheckIfBlockCollapsed; + continue; + } + } + //END: first check if the block is collapsed. if so, we have to skip the item painting + + Q_ASSERT ( block ); + + const bool alternateItem = ( i - block->firstIndex.row() ) % 2; + + const QModelIndex index = d->proxyModel->index ( i, modelColumn(), rootIndex() ); + const Qt::ItemFlags flags = d->proxyModel->flags ( index ); + QStyleOptionViewItemV4 option ( viewOptions() ); + option.rect = visualRect ( index ); + option.widget = this; + option.features |= wordWrap() ? QStyleOptionViewItemV2::WrapText + : QStyleOptionViewItemV2::None; + option.features |= alternatingRowColors() && alternateItem ? QStyleOptionViewItemV4::Alternate + : QStyleOptionViewItemV4::None; + if ( flags & Qt::ItemIsSelectable ) + { + option.state |= selectionModel()->isSelected ( index ) ? QStyle::State_Selected + : QStyle::State_None; + } + else + { + option.state &= ~QStyle::State_Selected; + } + option.state |= ( index == currentIndex() ) ? QStyle::State_HasFocus + : QStyle::State_None; + if ( ! ( flags & Qt::ItemIsEnabled ) ) + { + option.state &= ~QStyle::State_Enabled; + } + else + { + option.state |= ( index == d->hoveredIndex ) ? QStyle::State_MouseOver + : QStyle::State_None; + } + + itemDelegate ( index )->paint ( &p, option, index ); + ++i; + } + //END: draw items + } + + //BEGIN: draw selection rect + if ( isSelectionRectVisible() && d->rubberBandRect.isValid() ) + { + QStyleOptionRubberBand opt; + opt.initFrom ( this ); + opt.shape = QRubberBand::Rectangle; + opt.opaque = false; + opt.rect = d->mapToViewport ( d->rubberBandRect ).intersected ( viewport()->rect().adjusted ( -16, -16, 16, 16 ) ); + p.save(); + style()->drawControl ( QStyle::CE_RubberBand, &opt, &p ); + p.restore(); + } + //END: draw selection rect + + p.restore(); +} + +void KCategorizedView::resizeEvent ( QResizeEvent *event ) +{ + d->regenerateAllElements(); + QListView::resizeEvent ( event ); +} + +void KCategorizedView::setSelection ( const QRect &rect, + QItemSelectionModel::SelectionFlags flags ) +{ + if ( !d->isCategorized() ) + { + QListView::setSelection ( rect, flags ); + return; + } + + if ( rect.topLeft() == rect.bottomRight() ) + { + const QModelIndex index = indexAt ( rect.topLeft() ); + selectionModel()->select ( index, flags ); + return; + } + + const QPair intersecting = d->intersectingIndexesWithRect ( rect ); + + QItemSelection selection; + + //TODO: think of a faster implementation + QModelIndex firstIndex; + QModelIndex lastIndex; + for ( int i = intersecting.first.row(); i <= intersecting.second.row(); ++i ) + { + const QModelIndex index = d->proxyModel->index ( i, modelColumn(), rootIndex() ); + const bool visualRectIntersects = visualRect ( index ).intersects ( rect ); + if ( firstIndex.isValid() ) + { + if ( visualRectIntersects ) + { + lastIndex = index; + } + else + { + selection << QItemSelectionRange ( firstIndex, lastIndex ); + firstIndex = QModelIndex(); + } + } + else if ( visualRectIntersects ) + { + firstIndex = index; + lastIndex = index; + } + } + + if ( firstIndex.isValid() ) + { + selection << QItemSelectionRange ( firstIndex, lastIndex ); + } + + selectionModel()->select ( selection, flags ); +} + +void KCategorizedView::mouseMoveEvent ( QMouseEvent *event ) +{ + QListView::mouseMoveEvent ( event ); + d->hoveredIndex = indexAt ( event->pos() ); + const SelectionMode itemViewSelectionMode = selectionMode(); + if ( state() == DragSelectingState && isSelectionRectVisible() && itemViewSelectionMode != SingleSelection + && itemViewSelectionMode != NoSelection ) + { + QRect rect ( d->pressedPosition, event->pos() + QPoint ( horizontalOffset(), verticalOffset() ) ); + rect = rect.normalized(); + update ( rect.united ( d->rubberBandRect ) ); + d->rubberBandRect = rect; + } + QHash::ConstIterator it ( d->blocks.constBegin() ); + while ( it != d->blocks.constEnd() ) + { + const Private::Block &block = *it; + const QModelIndex categoryIndex = d->proxyModel->index ( block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); + QStyleOptionViewItemV4 option ( viewOptions() ); + const int height = d->categoryDrawer->categoryHeight ( categoryIndex, option ); + QPoint pos = d->blockPosition ( it.key() ); + pos.ry() -= height; + option.rect.setTopLeft ( pos ); + option.rect.setWidth ( d->viewportWidth() + d->categoryDrawer->leftMargin() + d->categoryDrawer->rightMargin() ); + option.rect.setHeight ( height + d->blockHeight ( it.key() ) ); + option.rect = d->mapToViewport ( option.rect ); + const QPoint mousePos = viewport()->mapFromGlobal ( QCursor::pos() ); + if ( option.rect.contains ( mousePos ) ) + { + if ( d->categoryDrawer && d->hoveredBlock->height != -1 && *d->hoveredBlock != block ) + { + const QModelIndex categoryIndex = d->proxyModel->index ( d->hoveredBlock->firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); + const QStyleOptionViewItemV4 option = d->blockRect ( categoryIndex ); + d->categoryDrawer->mouseLeft ( categoryIndex, option.rect ); + *d->hoveredBlock = block; + d->hoveredCategory = it.key(); + viewport()->update ( option.rect ); + } + else if ( d->hoveredBlock->height == -1 ) + { + *d->hoveredBlock = block; + d->hoveredCategory = it.key(); + } + else if ( d->categoryDrawer ) + { + d->categoryDrawer->mouseMoved ( categoryIndex, option.rect, event ); + } + viewport()->update ( option.rect ); + return; + } + ++it; + } + if ( d->categoryDrawer && d->hoveredBlock->height != -1 ) + { + const QModelIndex categoryIndex = d->proxyModel->index ( d->hoveredBlock->firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); + const QStyleOptionViewItemV4 option = d->blockRect ( categoryIndex ); + d->categoryDrawer->mouseLeft ( categoryIndex, option.rect ); + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + viewport()->update ( option.rect ); + } +} + +void KCategorizedView::mousePressEvent ( QMouseEvent *event ) +{ + if ( event->button() == Qt::LeftButton ) + { + d->pressedPosition = event->pos(); + d->pressedPosition.rx() += horizontalOffset(); + d->pressedPosition.ry() += verticalOffset(); + } + if ( !d->categoryDrawer ) + { + QListView::mousePressEvent ( event ); + return; + } + QHash::ConstIterator it ( d->blocks.constBegin() ); + while ( it != d->blocks.constEnd() ) + { + const Private::Block &block = *it; + const QModelIndex categoryIndex = d->proxyModel->index ( block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); + const QStyleOptionViewItemV4 option = d->blockRect ( categoryIndex ); + const QPoint mousePos = viewport()->mapFromGlobal ( QCursor::pos() ); + if ( option.rect.contains ( mousePos ) ) + { + if ( d->categoryDrawer ) + { + d->categoryDrawer->mouseButtonPressed ( categoryIndex, option.rect, event ); + } + viewport()->update ( option.rect ); + if ( !event->isAccepted() ) + { + QListView::mousePressEvent ( event ); + } + return; + } + ++it; + } + QListView::mousePressEvent ( event ); +} + +void KCategorizedView::mouseReleaseEvent ( QMouseEvent *event ) +{ + d->pressedPosition = QPoint(); + d->rubberBandRect = QRect(); + QHash::ConstIterator it ( d->blocks.constBegin() ); + while ( it != d->blocks.constEnd() ) + { + const Private::Block &block = *it; + const QModelIndex categoryIndex = d->proxyModel->index ( block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); + const QStyleOptionViewItemV4 option = d->blockRect ( categoryIndex ); + const QPoint mousePos = viewport()->mapFromGlobal ( QCursor::pos() ); + if ( option.rect.contains ( mousePos ) ) + { + if ( d->categoryDrawer ) + { + d->categoryDrawer->mouseButtonReleased ( categoryIndex, option.rect, event ); + } + viewport()->update ( option.rect ); + if ( !event->isAccepted() ) + { + QListView::mouseReleaseEvent ( event ); + } + return; + } + ++it; + } + QListView::mouseReleaseEvent ( event ); +} + +void KCategorizedView::leaveEvent ( QEvent *event ) +{ + QListView::leaveEvent ( event ); + if ( d->hoveredIndex.isValid() ) + { + viewport()->update ( visualRect ( d->hoveredIndex ) ); + d->hoveredIndex = QModelIndex(); + } + if ( d->categoryDrawer && d->hoveredBlock->height != -1 ) + { + const QModelIndex categoryIndex = d->proxyModel->index ( d->hoveredBlock->firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); + const QStyleOptionViewItemV4 option = d->blockRect ( categoryIndex ); + d->categoryDrawer->mouseLeft ( categoryIndex, option.rect ); + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + viewport()->update ( option.rect ); + } +} + +void KCategorizedView::startDrag ( Qt::DropActions supportedActions ) +{ + QListView::startDrag ( supportedActions ); +} + +void KCategorizedView::dragMoveEvent ( QDragMoveEvent *event ) +{ + QListView::dragMoveEvent ( event ); + d->hoveredIndex = indexAt ( event->pos() ); +} + +void KCategorizedView::dragEnterEvent ( QDragEnterEvent *event ) +{ + QListView::dragEnterEvent ( event ); +} + +void KCategorizedView::dragLeaveEvent ( QDragLeaveEvent *event ) +{ + QListView::dragLeaveEvent ( event ); +} + +void KCategorizedView::dropEvent ( QDropEvent *event ) +{ + QListView::dropEvent ( event ); +} + +//TODO: improve se we take into account collapsed blocks +//TODO: take into account when there is no grid and no uniformItemSizes +QModelIndex KCategorizedView::moveCursor ( CursorAction cursorAction, + Qt::KeyboardModifiers modifiers ) +{ + if ( !d->isCategorized() ) + { + return QListView::moveCursor ( cursorAction, modifiers ); + } + + const QModelIndex current = currentIndex(); + const QRect currentRect = visualRect ( current ); + if ( !current.isValid() ) + { + const int rowCount = d->proxyModel->rowCount ( rootIndex() ); + if ( !rowCount ) + { + return QModelIndex(); + } + return d->proxyModel->index ( 0, modelColumn(), rootIndex() ); + } + + switch ( cursorAction ) + { + case MoveLeft: + { + if ( !current.row() ) + { + return QModelIndex(); + } + const QModelIndex previous = d->proxyModel->index ( current.row() - 1, modelColumn(), rootIndex() ); + const QRect previousRect = visualRect ( previous ); + if ( previousRect.top() == currentRect.top() ) + { + return previous; + } + + return QModelIndex(); + } + case MoveRight: + { + if ( current.row() == d->proxyModel->rowCount() - 1 ) + { + return QModelIndex(); + } + const QModelIndex next = d->proxyModel->index ( current.row() + 1, modelColumn(), rootIndex() ); + const QRect nextRect = visualRect ( next ); + if ( nextRect.top() == currentRect.top() ) + { + return next; + } + + return QModelIndex(); + } + case MoveDown: + { + if ( d->hasGrid() || uniformItemSizes() || uniformItemWidths() ) + { + const QModelIndex current = currentIndex(); + const QSize itemSize = d->hasGrid() ? gridSize() + : sizeHintForIndex ( current ); + const Private::Block &block = d->blocks[d->categoryForIndex ( current )]; + //HACK: Why is the -2 needed? + const int maxItemsPerRow = qMax ( ( d->viewportWidth() - spacing() - 2 ) / ( itemSize.width() + spacing() ), 1 ); + const bool canMove = current.row() + maxItemsPerRow < block.firstIndex.row() + + block.items.count(); + + if ( canMove ) + { + return d->proxyModel->index ( current.row() + maxItemsPerRow, modelColumn(), rootIndex() ); + } + + const int currentRelativePos = ( current.row() - block.firstIndex.row() ) % maxItemsPerRow; + const QModelIndex nextIndex = d->proxyModel->index ( block.firstIndex.row() + block.items.count(), modelColumn(), rootIndex() ); + + if ( !nextIndex.isValid() ) + { + return QModelIndex(); + } + + const Private::Block &nextBlock = d->blocks[d->categoryForIndex ( nextIndex )]; + + if ( nextBlock.items.count() <= currentRelativePos ) + { + return QModelIndex(); + } + + if ( currentRelativePos < ( block.items.count() % maxItemsPerRow ) ) + { + return d->proxyModel->index ( nextBlock.firstIndex.row() + currentRelativePos, modelColumn(), rootIndex() ); + } + + return QModelIndex(); + } + } + case MoveUp: + { + if ( d->hasGrid() || uniformItemSizes() || uniformItemWidths() ) + { + const QModelIndex current = currentIndex(); + const QSize itemSize = d->hasGrid() ? gridSize() + : sizeHintForIndex ( current ); + const Private::Block &block = d->blocks[d->categoryForIndex ( current )]; + //HACK: Why is the -2 needed? + const int maxItemsPerRow = qMax ( ( d->viewportWidth() - spacing() - 2 ) / ( itemSize.width() + spacing() ), 1 ); + const bool canMove = current.row() - maxItemsPerRow >= block.firstIndex.row(); + + if ( canMove ) + { + return d->proxyModel->index ( current.row() - maxItemsPerRow, modelColumn(), rootIndex() ); + } + + const int currentRelativePos = ( current.row() - block.firstIndex.row() ) % maxItemsPerRow; + const QModelIndex prevIndex = d->proxyModel->index ( block.firstIndex.row() - 1, modelColumn(), rootIndex() ); + + if ( !prevIndex.isValid() ) + { + return QModelIndex(); + } + + const Private::Block &prevBlock = d->blocks[d->categoryForIndex ( prevIndex )]; + + if ( prevBlock.items.count() <= currentRelativePos ) + { + return QModelIndex(); + } + + const int remainder = prevBlock.items.count() % maxItemsPerRow; + if ( currentRelativePos < remainder ) + { + return d->proxyModel->index ( prevBlock.firstIndex.row() + prevBlock.items.count() - remainder + currentRelativePos, modelColumn(), rootIndex() ); + } + + return QModelIndex(); + } + } + default: + break; + } + + return QModelIndex(); +} + +void KCategorizedView::rowsAboutToBeRemoved ( const QModelIndex &parent, + int start, + int end ) +{ + if ( !d->isCategorized() ) + { + QListView::rowsAboutToBeRemoved ( parent, start, end ); + return; + } + + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + + if ( end - start + 1 == d->proxyModel->rowCount() ) + { + d->blocks.clear(); + QListView::rowsAboutToBeRemoved ( parent, start, end ); + return; + } + + // Removal feels a bit more complicated than insertion. Basically we can consider there are + // 3 different cases when going to remove items. (*) represents an item, Items between ([) and + // (]) are the ones which are marked for removal. + // + // - 1st case: + // ... * * * * * * [ * * * ... + // + // The items marked for removal are the last part of this category. No need to mark any item + // of this category as in quarantine, because no special offset will be pushed to items at + // the right because of any changes (since the removed items are those on the right most part + // of the category). + // + // - 2nd case: + // ... * * * * * * ] * * * ... + // + // The items marked for removal are the first part of this category. We have to mark as in + // quarantine all items in this category. Absolutely all. All items will have to be moved to + // the left (or moving up, because rows got a different offset). + // + // - 3rd case: + // ... * * [ * * * * ] * * ... + // + // The items marked for removal are in between of this category. We have to mark as in + // quarantine only those items that are at the right of the end of the removal interval, + // (starting on "]"). + // + // It hasn't been explicitly said, but when we remove, we have to mark all blocks that are + // located under the top most affected category as in quarantine (the block itself, as a whole), + // because such a change can force it to have a different offset (note that items themselves + // contain relative positions to the block, so marking the block as in quarantine is enough). + // + // Also note that removal implicitly means that we have to update correctly firstIndex of each + // block, and in general keep updated the internal information of elements. + + QStringList listOfCategoriesMarkedForRemoval; + + QString lastCategory; + int alreadyRemoved = 0; + for ( int i = start; i <= end; ++i ) + { + const QModelIndex index = d->proxyModel->index ( i, modelColumn(), parent ); + + Q_ASSERT ( index.isValid() ); + + const QString category = d->categoryForIndex ( index ); + + if ( lastCategory != category ) + { + lastCategory = category; + alreadyRemoved = 0; + } + + Private::Block &block = d->blocks[category]; + block.items.removeAt ( i - block.firstIndex.row() - alreadyRemoved ); + ++alreadyRemoved; + + if ( !block.items.count() ) + { + listOfCategoriesMarkedForRemoval << category; + } + + block.height = -1; + + viewport()->update(); + } + + //BEGIN: update the items that are in quarantine in affected categories + { + const QModelIndex lastIndex = d->proxyModel->index ( end, modelColumn(), parent ); + const QString category = d->categoryForIndex ( lastIndex ); + Private::Block &block = d->blocks[category]; + if ( block.items.count() && start <= block.firstIndex.row() && end >= block.firstIndex.row() ) + { + block.firstIndex = d->proxyModel->index ( end + 1, modelColumn(), parent ); + } + block.quarantineStart = block.firstIndex; + } + //END: update the items that are in quarantine in affected categories + + Q_FOREACH ( const QString &category, listOfCategoriesMarkedForRemoval ) + { + d->blocks.remove ( category ); + } + + //BEGIN: mark as in quarantine those categories that are under the affected ones + { + //BEGIN: order for marking as alternate those blocks that are alternate + QList blockList = d->blocks.values(); + qSort ( blockList.begin(), blockList.end(), Private::Block::lessThan ); + QList firstIndexesRows; + foreach ( const Private::Block &block, blockList ) + { + firstIndexesRows << block.firstIndex.row(); + } + //END: order for marking as alternate those blocks that are alternate + for ( QHash::Iterator it = d->blocks.begin(); it != d->blocks.end(); ++it ) + { + Private::Block &block = *it; + if ( block.firstIndex.row() > start ) + { + block.outOfQuarantine = false; + block.alternate = firstIndexesRows.indexOf ( block.firstIndex.row() ) % 2; + } + else if ( block.firstIndex.row() == start ) + { + block.alternate = firstIndexesRows.indexOf ( block.firstIndex.row() ) % 2; + } + } + } + //END: mark as in quarantine those categories that are under the affected ones + + QListView::rowsAboutToBeRemoved ( parent, start, end ); +} + +void KCategorizedView::updateGeometries() +{ + const int oldVerticalOffset = verticalOffset(); + const Qt::ScrollBarPolicy verticalP = verticalScrollBarPolicy(), horizontalP = horizontalScrollBarPolicy(); + + //BEGIN bugs 213068, 287847 ------------------------------------------------------------ + /* + * QListView::updateGeometries() has it's own opinion on whether the scrollbars should be visible (valid range) or not + * and triggers a (sometimes additionally timered) resize through ::layoutChildren() + * http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/itemviews/qlistview.cpp#line1499 + * (the comment above the main block isn't all accurate, layoutChldren is called regardless of the policy) + * + * As a result QListView and KCategorizedView occasionally started a race on the scrollbar visibility, effectively blocking the UI + * So we prevent QListView from having an own opinion on the scrollbar visibility by + * fixing it before calling the baseclass QListView::updateGeometries() + * + * Since the implicit show/hide by the followin range setting will cause further resizes if the policy is Qt::ScrollBarAsNeeded + * we keep it static until we're done, then restore the original value and ultimately change the scrollbar visibility ourself. + */ + if ( d->isCategorized() ) // important! - otherwise we'd pollute the setting if the view is initially not categorized + { + setVerticalScrollBarPolicy ( ( verticalP == Qt::ScrollBarAlwaysOn || verticalScrollBar()->isVisibleTo ( this ) ) ? + Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff ); + setHorizontalScrollBarPolicy ( ( horizontalP == Qt::ScrollBarAlwaysOn || horizontalScrollBar()->isVisibleTo ( this ) ) ? + Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff ); + } + //END bugs 213068, 287847 -------------------------------------------------------------- + + QListView::updateGeometries(); + + if ( !d->isCategorized() ) + { + return; + } + + const int rowCount = d->proxyModel->rowCount(); + if ( !rowCount ) + { + verticalScrollBar()->setRange ( 0, 0 ); + // unconditional, see function end todo + horizontalScrollBar()->setRange ( 0, 0 ); + return; + } + + const QModelIndex lastIndex = d->proxyModel->index ( rowCount - 1, modelColumn(), rootIndex() ); + Q_ASSERT ( lastIndex.isValid() ); + QRect lastItemRect = visualRect ( lastIndex ); + + if ( d->hasGrid() ) + { + lastItemRect.setSize ( lastItemRect.size().expandedTo ( gridSize() ) ); + } + else + { + if ( uniformItemSizes() ) + { + QSize itemSize = sizeHintForIndex ( lastIndex ); + itemSize.setHeight ( itemSize.height() + spacing() ); + lastItemRect.setSize ( itemSize ); + } + else + { + QSize itemSize = sizeHintForIndex ( lastIndex ); + const QString category = d->categoryForIndex ( lastIndex ); + itemSize.setHeight ( d->highestElementInLastRow ( d->blocks[category] ) + spacing() ); + lastItemRect.setSize ( itemSize ); + } + } + + const int bottomRange = lastItemRect.bottomRight().y() + verticalOffset() - viewport()->height(); + + if ( verticalScrollMode() == ScrollPerItem ) + { + verticalScrollBar()->setSingleStep ( lastItemRect.height() ); + const int rowsPerPage = qMax ( viewport()->height() / lastItemRect.height(), 1 ); + verticalScrollBar()->setPageStep ( rowsPerPage * lastItemRect.height() ); + } + + verticalScrollBar()->setRange ( 0, bottomRange ); + verticalScrollBar()->setValue ( oldVerticalOffset ); + + //TODO: also consider working with the horizontal scroll bar. since at this level I am not still + // supporting "top to bottom" flow, there is no real problem. If I support that someday + // (think how to draw categories), we would have to take care of the horizontal scroll bar too. + // In theory, as KCategorizedView has been designed, there is no need of horizontal scroll bar. + horizontalScrollBar()->setRange ( 0, 0 ); + + //BEGIN bugs 213068, 287847 ------------------------------------------------------------ + // restoring values from above ... + setVerticalScrollBarPolicy ( verticalP ); + setHorizontalScrollBarPolicy ( horizontalP ); + // ... and correct the visibility + bool validRange = verticalScrollBar()->maximum() != verticalScrollBar()->minimum(); + if ( verticalP == Qt::ScrollBarAsNeeded && ( verticalScrollBar()->isVisibleTo ( this ) != validRange ) ) + verticalScrollBar()->setVisible ( validRange ); + validRange = horizontalScrollBar()->maximum() > horizontalScrollBar()->minimum(); + if ( horizontalP == Qt::ScrollBarAsNeeded && ( horizontalScrollBar()->isVisibleTo ( this ) != validRange ) ) + horizontalScrollBar()->setVisible ( validRange ); + //END bugs 213068, 287847 -------------------------------------------------------------- +} + +void KCategorizedView::currentChanged ( const QModelIndex ¤t, + const QModelIndex &previous ) +{ + QListView::currentChanged ( current, previous ); +} + +void KCategorizedView::dataChanged ( const QModelIndex &topLeft, + const QModelIndex &bottomRight ) +{ + QListView::dataChanged ( topLeft, bottomRight ); + if ( !d->isCategorized() ) + { + return; + } + + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + + //BEGIN: since the model changed data, we need to reconsider item sizes + int i = topLeft.row(); + int indexToCheck = i; + QModelIndex categoryIndex; + QString category; + Private::Block *block; + while ( i <= bottomRight.row() ) + { + const QModelIndex currIndex = d->proxyModel->index ( i, modelColumn(), rootIndex() ); + if ( i == indexToCheck ) + { + categoryIndex = d->proxyModel->index ( i, d->proxyModel->sortColumn(), rootIndex() ); + category = categoryIndex.data ( KCategorizedSortFilterProxyModel::CategoryDisplayRole ).toString(); + block = &d->blocks[category]; + block->quarantineStart = currIndex; + indexToCheck = block->firstIndex.row() + block->items.count(); + } + visualRect ( currIndex ); + ++i; + } + //END: since the model changed data, we need to reconsider item sizes +} + +void KCategorizedView::rowsInserted ( const QModelIndex &parent, + int start, + int end ) +{ + QListView::rowsInserted ( parent, start, end ); + if ( !d->isCategorized() ) + { + return; + } + + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + d->rowsInserted ( parent, start, end ); +} + +void KCategorizedView::slotLayoutChanged() +{ + if ( !d->isCategorized() ) + { + return; + } + + d->blocks.clear(); + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + if ( d->proxyModel->rowCount() ) + { + d->rowsInserted ( rootIndex(), 0, d->proxyModel->rowCount() - 1 ); + } +} +//END: Public part + +void KCategorizedView::slotCollapseOrExpandClicked ( QModelIndex idx ) +{ + d->_k_slotCollapseOrExpandClicked ( idx ); +} + + +#include "categorizedview.moc" diff --git a/depends/groupview/src/categorizedview_p.h b/depends/groupview/src/categorizedview_p.h new file mode 100644 index 00000000..13809312 --- /dev/null +++ b/depends/groupview/src/categorizedview_p.h @@ -0,0 +1,159 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007, 2009 Rafael Fernández López + * + * This library 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 library 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 library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KCATEGORIZEDVIEW_P_H +#define KCATEGORIZEDVIEW_P_H + +class KCategorizedSortFilterProxyModel; +class KCategoryDrawer; +class KCategoryDrawerV2; +class KCategoryDrawerV3; + +/** + * @internal + */ +class KCategorizedView::Private +{ +public: + struct Block; + struct Item; + + Private(KCategorizedView *q); + ~Private(); + + /** + * @return whether this view has all required elements to be categorized. + */ + bool isCategorized() const; + + /** + * @return the block rect for the representative @p representative. + */ + QStyleOptionViewItemV4 blockRect(const QModelIndex &representative); + + /** + * Returns the first and last element that intersects with rect. + * + * @note see that here we cannot take out items between first and last (as we could + * do with the rubberband). + * + * Complexity: O(log(n)) where n is model()->rowCount(). + */ + QPair intersectingIndexesWithRect(const QRect &rect) const; + + /** + * Returns the position of the block of @p category. + * + * Complexity: O(n) where n is the number of different categories when the block has been + * marked as in quarantine. O(1) the rest of the times (the vast majority). + */ + QPoint blockPosition(const QString &category); + + /** + * Returns the height of the block determined by @p category. + */ + int blockHeight(const QString &category); + + /** + * Returns the actual viewport width. + */ + int viewportWidth() const; + + /** + * Marks all elements as in quarantine. + * + * Complexity: O(n) where n is model()->rowCount(). + * + * @warning this is an expensive operation + */ + void regenerateAllElements(); + + /** + * Update internal information, and keep sync with the real information that the model contains. + */ + void rowsInserted(const QModelIndex &parent, int start, int end); + + /** + * Returns @p rect in viewport terms, taking in count horizontal and vertical offsets. + */ + QRect mapToViewport(const QRect &rect) const; + + /** + * Returns @p rect in absolute terms, converted from viewport position. + */ + QRect mapFromViewport(const QRect &rect) const; + + /** + * Returns the height of the highest element in last row. This is only applicable if there is + * no grid set and uniformItemSizes is false. + * + * @param block in which block are we searching. Necessary to stop the search if we hit the + * first item in this block. + */ + int highestElementInLastRow(const Block &block) const; + + /** + * Returns whether the view has a valid grid size. + */ + bool hasGrid() const; + + /** + * Returns the category for the given index. + */ + QString categoryForIndex(const QModelIndex &index) const; + + /** + * Updates the visual rect for item when flow is LeftToRight. + */ + void leftToRightVisualRect(const QModelIndex &index, Item &item, + const Block &block, const QPoint &blockPos) const; + + /** + * Updates the visual rect for item when flow is TopToBottom. + * @note we only support viewMode == ListMode in this case. + */ + void topToBottomVisualRect(const QModelIndex &index, Item &item, + const Block &block, const QPoint &blockPos) const; + + /** + * Called when expand or collapse has been clicked on the category drawer. + */ + void _k_slotCollapseOrExpandClicked(QModelIndex); + + KCategorizedView *q; + KCategorizedSortFilterProxyModel *proxyModel; + KCategoryDrawer *categoryDrawer; + int categorySpacing; + bool alternatingBlockColors; + bool collapsibleBlocks; + bool constantItemWidth; + + Block *hoveredBlock; + QString hoveredCategory; + QModelIndex hoveredIndex; + + QPoint pressedPosition; + QRect rubberBandRect; + + QHash blocks; +}; + +#endif // KCATEGORIZEDVIEW_P_H + diff --git a/depends/groupview/src/categorydrawer.cpp b/depends/groupview/src/categorydrawer.cpp new file mode 100644 index 00000000..04903206 --- /dev/null +++ b/depends/groupview/src/categorydrawer.cpp @@ -0,0 +1,231 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007, 2009 Rafael Fernández López + * + * This library 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 library 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 library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "categorydrawer.h" + +#include +#include +#include + +#include +#include + +#define HORIZONTAL_HINT 3 + +class KCategoryDrawer::Private +{ +public: + Private(KCategorizedView *view) + : view(view) + , leftMargin(0) + , rightMargin(0) + { + } + + ~Private() + { + } + int leftMargin; + int rightMargin; + KCategorizedView *view; +}; + +KCategoryDrawer::KCategoryDrawer(KCategorizedView *view) + : QObject(view) + , d(new Private(view)) +{ + setLeftMargin(2); + setRightMargin(2); +} + +KCategoryDrawer::~KCategoryDrawer() +{ + delete d; +} + + +void KCategoryDrawer::drawCategory(const QModelIndex &index, + int /*sortRole*/, + const QStyleOption &option, + QPainter *painter) const +{ + painter->setRenderHint(QPainter::Antialiasing); + + const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + const QRect optRect = option.rect; + QFont font(QApplication::font()); + font.setBold(true); + const QFontMetrics fontMetrics = QFontMetrics(font); + + QColor outlineColor = option.palette.text().color(); + outlineColor.setAlphaF(0.35); + + //BEGIN: top left corner + { + painter->save(); + painter->setPen(outlineColor); + const QPointF topLeft(optRect.topLeft()); + QRectF arc(topLeft, QSizeF(4, 4)); + arc.translate(0.5, 0.5); + painter->drawArc(arc, 1440, 1440); + painter->restore(); + } + //END: top left corner + + //BEGIN: left vertical line + { + QPoint start(optRect.topLeft()); + start.ry() += 3; + QPoint verticalGradBottom(optRect.topLeft()); + verticalGradBottom.ry() += fontMetrics.height() + 5; + QLinearGradient gradient(start, verticalGradBottom); + gradient.setColorAt(0, outlineColor); + gradient.setColorAt(1, Qt::transparent); + painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); + } + //END: left vertical line + + //BEGIN: horizontal line + { + QPoint start(optRect.topLeft()); + start.rx() += 3; + QPoint horizontalGradTop(optRect.topLeft()); + horizontalGradTop.rx() += optRect.width() - 6; + painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor); + } + //END: horizontal line + + //BEGIN: top right corner + { + painter->save(); + painter->setPen(outlineColor); + QPointF topRight(optRect.topRight()); + topRight.rx() -= 4; + QRectF arc(topRight, QSizeF(4, 4)); + arc.translate(0.5, 0.5); + painter->drawArc(arc, 0, 1440); + painter->restore(); + } + //END: top right corner + + //BEGIN: right vertical line + { + QPoint start(optRect.topRight()); + start.ry() += 3; + QPoint verticalGradBottom(optRect.topRight()); + verticalGradBottom.ry() += fontMetrics.height() + 5; + QLinearGradient gradient(start, verticalGradBottom); + gradient.setColorAt(0, outlineColor); + gradient.setColorAt(1, Qt::transparent); + painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); + } + //END: right vertical line + + //BEGIN: text + { + QRect textRect(option.rect); + textRect.setTop(textRect.top() + 7); + textRect.setLeft(textRect.left() + 7); + textRect.setHeight(fontMetrics.height()); + textRect.setRight(textRect.right() - 7); + + painter->save(); + painter->setFont(font); + QColor penColor(option.palette.text().color()); + penColor.setAlphaF(0.6); + painter->setPen(penColor); + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, category); + painter->restore(); + } + //END: text +} + +int KCategoryDrawer::categoryHeight(const QModelIndex &index, const QStyleOption &option) const +{ + Q_UNUSED(index); + Q_UNUSED(option) + + QFont font(QApplication::font()); + font.setBold(true); + QFontMetrics fontMetrics(font); + + const int height = fontMetrics.height() + 1 /* 1 pixel-width gradient */ + + 11 /* top and bottom separation */; + return height; +} + +int KCategoryDrawer::leftMargin() const +{ + return d->leftMargin; +} + +void KCategoryDrawer::setLeftMargin(int leftMargin) +{ + d->leftMargin = leftMargin; +} + +int KCategoryDrawer::rightMargin() const +{ + return d->rightMargin; +} + +void KCategoryDrawer::setRightMargin(int rightMargin) +{ + d->rightMargin = rightMargin; +} + +KCategoryDrawer &KCategoryDrawer::operator=(const KCategoryDrawer &cd) +{ + d->leftMargin = cd.d->leftMargin; + d->rightMargin = cd.d->rightMargin; + d->view = cd.d->view; + return *this; +} + +KCategorizedView *KCategoryDrawer::view() const +{ + return d->view; +} + +void KCategoryDrawer::mouseButtonPressed(const QModelIndex&, const QRect&, QMouseEvent *event) +{ + event->ignore(); +} + +void KCategoryDrawer::mouseButtonReleased(const QModelIndex&, const QRect&, QMouseEvent *event) +{ + event->ignore(); +} + +void KCategoryDrawer::mouseMoved(const QModelIndex&, const QRect&, QMouseEvent *event) +{ + event->ignore(); +} + +void KCategoryDrawer::mouseButtonDoubleClicked(const QModelIndex&, const QRect&, QMouseEvent *event) +{ + event->ignore(); +} + +void KCategoryDrawer::mouseLeft(const QModelIndex&, const QRect&) +{ +} + +#include "categorydrawer.moc" diff --git a/depends/launcher/CMakeLists.txt b/depends/launcher/CMakeLists.txt new file mode 100644 index 00000000..e5402ce7 --- /dev/null +++ b/depends/launcher/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 2.8.6) +project(launcher Java) +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}") +find_package(Java 1.6 REQUIRED COMPONENTS Development) + + +include(UseJava) +set(CMAKE_JAVA_JAR_ENTRY_POINT MultiMCLauncher) +set(CMAKE_JAVA_COMPILE_FLAGS -target 1.6 -source 1.6 -Xlint:deprecation -Xlint:unchecked) +set(CMAKE_JAVA_TARGET_OUTPUT_DIR "${PROJECT_SOURCE_DIR}/../../resources") + +set(SRC + MultiMCLauncher.java + org/simplericity/macify/eawt/Application.java + org/simplericity/macify/eawt/ApplicationAdapter.java + org/simplericity/macify/eawt/ApplicationEvent.java + org/simplericity/macify/eawt/ApplicationListener.java + org/simplericity/macify/eawt/DefaultApplication.java + net/minecraft/Launcher.java + MCFrame.java +) + +add_jar(MultiMCLauncher ${SRC}) \ No newline at end of file diff --git a/depends/launcher/MCFrame.java b/depends/launcher/MCFrame.java new file mode 100644 index 00000000..d6ebb240 --- /dev/null +++ b/depends/launcher/MCFrame.java @@ -0,0 +1,123 @@ +// +// Copyright 2012 MultiMC Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import net.minecraft.Launcher; +import java.applet.Applet; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Toolkit; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.net.MalformedURLException; +import java.net.URL; +import java.io.IOException; +import java.io.File; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; + +public class MCFrame extends Frame implements WindowListener +{ + private Launcher appletWrap = null; + public MCFrame(String title) + { + super(title); + BufferedImage image = null; + try + { + image = ImageIO.read(new File("icon.png")); + setIconImage(image); + } + catch (IOException e) + { + e.printStackTrace(); + } + this.addWindowListener(this); + } + + public void start(Applet mcApplet, String user, String session, Dimension winSize, boolean maximize) + { + try + { + appletWrap = new Launcher(mcApplet, new URL("http://www.minecraft.net/game")); + } + catch (MalformedURLException ignored){} + + appletWrap.setParameter("username", user); + appletWrap.setParameter("sessionid", session); + appletWrap.setParameter("stand-alone", "true"); // Show the quit button. + mcApplet.setStub(appletWrap); + + this.add(appletWrap); + appletWrap.setPreferredSize(winSize); + this.pack(); + this.setLocationRelativeTo(null); + this.setResizable(true); + if (maximize) + this.setExtendedState(MAXIMIZED_BOTH); + + validate(); + appletWrap.init(); + appletWrap.start(); + setVisible(true); + } + + @Override + public void windowActivated(WindowEvent e) {} + + @Override + public void windowClosed(WindowEvent e) {} + + @Override + public void windowClosing(WindowEvent e) + { + new Thread() + { + public void run() + { + try + { + Thread.sleep(30000L); + } catch (InterruptedException localInterruptedException) + { + localInterruptedException.printStackTrace(); + } + System.out.println("FORCING EXIT!"); + System.exit(0); + } + } + .start(); + + if (appletWrap != null) + { + appletWrap.stop(); + appletWrap.destroy(); + } + // old minecraft versions can hang without this >_< + System.exit(0); + } + + @Override + public void windowDeactivated(WindowEvent e) {} + + @Override + public void windowDeiconified(WindowEvent e) {} + + @Override + public void windowIconified(WindowEvent e) {} + + @Override + public void windowOpened(WindowEvent e) {} +} \ No newline at end of file diff --git a/depends/launcher/MultiMCLauncher.java b/depends/launcher/MultiMCLauncher.java new file mode 100644 index 00000000..09a019ce --- /dev/null +++ b/depends/launcher/MultiMCLauncher.java @@ -0,0 +1,331 @@ +// +// Copyright 2012 MultiMC Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import java.applet.Applet; +import java.awt.Dimension; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import org.simplericity.macify.eawt.Application; +import org.simplericity.macify.eawt.DefaultApplication; + +public class MultiMCLauncher +{ + /** + * @param args + * The arguments you want to launch Minecraft with. New path, + * Username, Session ID. + */ + public static void main(String[] args) + { + if (args.length < 3) + { + System.out.println("Not enough arguments."); + System.exit(-1); + } + + // Set the OSX application icon first, if we are on OSX. + Application application = new DefaultApplication(); + if(application.isMac()) + { + try + { + BufferedImage image = ImageIO.read(new File("icon.png")); + application.setApplicationIconImage(image); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + String userName = args[0]; + String sessionId = args[1]; + String windowtitle = args[2]; + String windowParams = args[3]; + String lwjgl = args[4]; + String cwd = System.getProperty("user.dir"); + + Dimension winSize = new Dimension(854, 480); + boolean maximize = false; + boolean compatMode = false; + + + String[] dimStrings = windowParams.split("x"); + + if (windowParams.equalsIgnoreCase("compatmode")) + { + compatMode = true; + } + else if (windowParams.equalsIgnoreCase("max")) + { + maximize = true; + } + else if (dimStrings.length == 2) + { + try + { + winSize = new Dimension(Integer.parseInt(dimStrings[0]), + Integer.parseInt(dimStrings[1])); + } + catch (NumberFormatException e) + { + System.out.println("Invalid Window size argument, " + + "using default."); + } + } + else + { + System.out.println("Invalid Window size argument, " + + "using default."); + } + + try + { + File binDir = new File(cwd, "bin"); + File lwjglDir; + if(lwjgl.equalsIgnoreCase("Mojang")) + lwjglDir = binDir; + else + lwjglDir = new File(lwjgl); + + System.out.println("Loading jars..."); + String[] lwjglJars = new String[] { + "lwjgl.jar", "lwjgl_util.jar", "jinput.jar" + }; + + URL[] urls = new URL[4]; + try + { + File f = new File(binDir, "minecraft.jar"); + urls[0] = f.toURI().toURL(); + System.out.println("Loading URL: " + urls[0].toString()); + + for (int i = 1; i < urls.length; i++) + { + File jar = new File(lwjglDir, lwjglJars[i-1]); + urls[i] = jar.toURI().toURL(); + System.out.println("Loading URL: " + urls[i].toString()); + } + } + catch (MalformedURLException e) + { + System.err.println("MalformedURLException, " + e.toString()); + System.exit(5); + } + + System.out.println("Loading natives..."); + String nativesDir = new File(lwjglDir, "natives").toString(); + + System.setProperty("org.lwjgl.librarypath", nativesDir); + System.setProperty("net.java.games.input.librarypath", nativesDir); + + URLClassLoader cl = + new URLClassLoader(urls, MultiMCLauncher.class.getClassLoader()); + + // Get the Minecraft Class. + Class mc = null; + try + { + mc = cl.loadClass("net.minecraft.client.Minecraft"); + + Field f = getMCPathField(mc); + + if (f == null) + { + System.err.println("Could not find Minecraft path field. Launch failed."); + System.exit(-1); + } + + f.setAccessible(true); + f.set(null, new File(cwd)); + // And set it. + System.out.println("Fixed Minecraft Path: Field was " + f.toString()); + } + catch (ClassNotFoundException e) + { + System.err.println("Can't find main class. Searching..."); + + // Look for any class that looks like the main class. + File mcJar = new File(new File(cwd, "bin"), "minecraft.jar"); + ZipFile zip = null; + try + { + zip = new ZipFile(mcJar); + } catch (ZipException e1) + { + e1.printStackTrace(); + System.err.println("Search failed."); + System.exit(-1); + } catch (IOException e1) + { + e1.printStackTrace(); + System.err.println("Search failed."); + System.exit(-1); + } + + Enumeration entries = zip.entries(); + ArrayList classes = new ArrayList(); + + while (entries.hasMoreElements()) + { + ZipEntry entry = entries.nextElement(); + if (entry.getName().endsWith(".class")) + { + String entryName = entry.getName().substring(0, entry.getName().lastIndexOf('.')); + entryName = entryName.replace('/', '.'); + System.out.println("Found class: " + entryName); + classes.add(entryName); + } + } + + for (String clsName : classes) + { + try + { + Class cls = cl.loadClass(clsName); + if (!Runnable.class.isAssignableFrom(cls)) + { + continue; + } + else + { + System.out.println("Found class implementing runnable: " + + cls.getName()); + } + + if (getMCPathField(cls) == null) + { + continue; + } + else + { + System.out.println("Found class implementing runnable " + + "with mcpath field: " + cls.getName()); + } + + mc = cls; + break; + } + catch (ClassNotFoundException e1) + { + // Ignore + continue; + } + } + + if (mc == null) + { + System.err.println("Failed to find Minecraft main class."); + System.exit(-1); + } + else + { + System.out.println("Found main class: " + mc.getName()); + } + } + + System.setProperty("minecraft.applet.TargetDirectory", cwd); + + String[] mcArgs = new String[2]; + mcArgs[0] = userName; + mcArgs[1] = sessionId; + + if (compatMode) + { + System.out.println("Launching in compatibility mode..."); + mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs); + } + else + { + System.out.println("Launching with applet wrapper..."); + try + { + Class MCAppletClass = cl.loadClass( + "net.minecraft.client.MinecraftApplet"); + Applet mcappl = (Applet) MCAppletClass.newInstance(); + MCFrame mcWindow = new MCFrame(windowtitle); + mcWindow.start(mcappl, userName, sessionId, winSize, maximize); + } catch (InstantiationException e) + { + System.out.println("Applet wrapper failed! Falling back " + + "to compatibility mode."); + mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs); + } + } + } catch (ClassNotFoundException e) + { + e.printStackTrace(); + System.exit(1); + } catch (IllegalArgumentException e) + { + e.printStackTrace(); + System.exit(2); + } catch (IllegalAccessException e) + { + e.printStackTrace(); + System.exit(2); + } catch (InvocationTargetException e) + { + e.printStackTrace(); + System.exit(3); + } catch (NoSuchMethodException e) + { + e.printStackTrace(); + System.exit(3); + } catch (SecurityException e) + { + e.printStackTrace(); + System.exit(4); + } + } + + public static Field getMCPathField(Class mc) + { + Field[] fields = mc.getDeclaredFields(); + + for (int i = 0; i < fields.length; i++) + { + Field f = fields[i]; + if (f.getType() != File.class) + { + // Has to be File + continue; + } + if (f.getModifiers() != (Modifier.PRIVATE + Modifier.STATIC)) + { + // And Private Static. + continue; + } + return f; + } + return null; + } +} diff --git a/depends/launcher/UseJava.cmake b/depends/launcher/UseJava.cmake new file mode 100644 index 00000000..1a5ef107 --- /dev/null +++ b/depends/launcher/UseJava.cmake @@ -0,0 +1,881 @@ +# - Use Module for Java +# This file provides functions for Java. It is assumed that FindJava.cmake +# has already been loaded. See FindJava.cmake for information on how to +# load Java into your CMake project. +# +# add_jar(TARGET_NAME SRC1 SRC2 .. SRCN RCS1 RCS2 .. RCSN) +# +# This command creates a .jar. It compiles the given source +# files (SRC) and adds the given resource files (RCS) to the jar file. +# If only resource files are given then just a jar file is created. +# +# Additional instructions: +# To add compile flags to the target you can set these flags with +# the following variable: +# +# set(CMAKE_JAVA_COMPILE_FLAGS -nowarn) +# +# To add a path or a jar file to the class path you can do this +# with the CMAKE_JAVA_INCLUDE_PATH variable. +# +# set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar) +# +# To use a different output name for the target you can set it with: +# +# set(CMAKE_JAVA_TARGET_OUTPUT_NAME shibboleet.jar) +# add_jar(foobar foobar.java) +# +# To use a different output directory than CMAKE_CURRENT_BINARY_DIR +# you can set it with: +# +# set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin) +# +# To define an entry point in your jar you can set it with: +# +# set(CMAKE_JAVA_JAR_ENTRY_POINT com/examples/MyProject/Main) +# +# To add a VERSION to the target output name you can set it using +# CMAKE_JAVA_TARGET_VERSION. This will create a jar file with the name +# shibboleet-1.0.0.jar and will create a symlink shibboleet.jar +# pointing to the jar with the version information. +# +# set(CMAKE_JAVA_TARGET_VERSION 1.2.0) +# add_jar(shibboleet shibbotleet.java) +# +# If the target is a JNI library, utilize the following commands to +# create a JNI symbolic link: +# +# set(CMAKE_JNI_TARGET TRUE) +# set(CMAKE_JAVA_TARGET_VERSION 1.2.0) +# add_jar(shibboleet shibbotleet.java) +# install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet) +# install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR}) +# +# If a single target needs to produce more than one jar from its +# java source code, to prevent the accumulation of duplicate class +# files in subsequent jars, set/reset CMAKE_JAR_CLASSES_PREFIX prior +# to calling the add_jar() function: +# +# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo) +# add_jar(foo foo.java) +# +# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar) +# add_jar(bar bar.java) +# +# Target Properties: +# The add_jar() functions sets some target properties. You can get these +# properties with the +# get_property(TARGET PROPERTY ) +# command. +# +# INSTALL_FILES The files which should be installed. This is used by +# install_jar(). +# JNI_SYMLINK The JNI symlink which should be installed. +# This is used by install_jni_symlink(). +# JAR_FILE The location of the jar file so that you can include +# it. +# CLASS_DIR The directory where the class files can be found. For +# example to use them with javah. +# +# find_jar( +# name | NAMES name1 [name2 ...] +# [PATHS path1 [path2 ... ENV var]] +# [VERSIONS version1 [version2]] +# [DOC "cache documentation string"] +# ) +# +# This command is used to find a full path to the named jar. A cache +# entry named by is created to stor the result of this command. If +# the full path to a jar is found the result is stored in the variable +# and the search will not repeated unless the variable is cleared. If +# nothing is found, the result will be -NOTFOUND, and the search +# will be attempted again next time find_jar is invoked with the same +# variable. +# The name of the full path to a file that is searched for is specified +# by the names listed after NAMES argument. Additional search locations +# can be specified after the PATHS argument. If you require special a +# version of a jar file you can specify it with the VERSIONS argument. +# The argument after DOC will be used for the documentation string in +# the cache. +# +# install_jar(TARGET_NAME DESTINATION) +# +# This command installs the TARGET_NAME files to the given DESTINATION. +# It should be called in the same scope as add_jar() or it will fail. +# +# install_jni_symlink(TARGET_NAME DESTINATION) +# +# This command installs the TARGET_NAME JNI symlinks to the given +# DESTINATION. It should be called in the same scope as add_jar() +# or it will fail. +# +# create_javadoc( +# PACKAGES pkg1 [pkg2 ...] +# [SOURCEPATH ] +# [CLASSPATH ] +# [INSTALLPATH ] +# [DOCTITLE "the documentation title"] +# [WINDOWTITLE "the title of the document"] +# [AUTHOR TRUE|FALSE] +# [USE TRUE|FALSE] +# [VERSION TRUE|FALSE] +# ) +# +# Create java documentation based on files or packages. For more +# details please read the javadoc manpage. +# +# There are two main signatures for create_javadoc. The first +# signature works with package names on a path with source files: +# +# Example: +# create_javadoc(my_example_doc +# PACKAGES com.exmaple.foo com.example.bar +# SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}" +# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH} +# WINDOWTITLE "My example" +# DOCTITLE "

My example

" +# AUTHOR TRUE +# USE TRUE +# VERSION TRUE +# ) +# +# The second signature for create_javadoc works on a given list of +# files. +# +# create_javadoc( +# FILES file1 [file2 ...] +# [CLASSPATH ] +# [INSTALLPATH ] +# [DOCTITLE "the documentation title"] +# [WINDOWTITLE "the title of the document"] +# [AUTHOR TRUE|FALSE] +# [USE TRUE|FALSE] +# [VERSION TRUE|FALSE] +# ) +# +# Example: +# create_javadoc(my_example_doc +# FILES ${example_SRCS} +# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH} +# WINDOWTITLE "My example" +# DOCTITLE "

My example

" +# AUTHOR TRUE +# USE TRUE +# VERSION TRUE +# ) +# +# Both signatures share most of the options. These options are the +# same as what you can find in the javadoc manpage. Please look at +# the manpage for CLASSPATH, DOCTITLE, WINDOWTITLE, AUTHOR, USE and +# VERSION. +# +# The documentation will be by default installed to +# +# ${CMAKE_INSTALL_PREFIX}/share/javadoc/ +# +# if you don't set the INSTALLPATH. +# + +#============================================================================= +# Copyright 2010-2011 Andreas schneider +# Copyright 2010 Ben Boeckel +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +function (__java_copy_file src dest comment) + add_custom_command( + OUTPUT ${dest} + COMMAND cmake -E copy_if_different + ARGS ${src} + ${dest} + DEPENDS ${src} + COMMENT ${comment}) +endfunction (__java_copy_file src dest comment) + +# define helper scripts +set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake) +set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake) + +function(add_jar _TARGET_NAME) + set(_JAVA_SOURCE_FILES ${ARGN}) + + if (NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR) + set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) + endif(NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR) + + if (CMAKE_JAVA_JAR_ENTRY_POINT) + set(_ENTRY_POINT_OPTION e) + set(_ENTRY_POINT_VALUE ${CMAKE_JAVA_JAR_ENTRY_POINT}) + endif (CMAKE_JAVA_JAR_ENTRY_POINT) + + if (LIBRARY_OUTPUT_PATH) + set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}) + else (LIBRARY_OUTPUT_PATH) + set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR}) + endif (LIBRARY_OUTPUT_PATH) + + set(CMAKE_JAVA_INCLUDE_PATH + ${CMAKE_JAVA_INCLUDE_PATH} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_JAVA_OBJECT_OUTPUT_PATH} + ${CMAKE_JAVA_LIBRARY_OUTPUT_PATH} + ) + + if (WIN32 AND NOT CYGWIN AND NOT CMAKE_CROSSCOMPILING) + set(CMAKE_JAVA_INCLUDE_FLAG_SEP ";") + else () + set(CMAKE_JAVA_INCLUDE_FLAG_SEP ":") + endif() + + foreach (JAVA_INCLUDE_DIR ${CMAKE_JAVA_INCLUDE_PATH}) + set(CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_PATH_FINAL}${CMAKE_JAVA_INCLUDE_FLAG_SEP}${JAVA_INCLUDE_DIR}") + endforeach(JAVA_INCLUDE_DIR) + + set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_JAVA_TARGET_OUTPUT_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir") + + set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar") + if (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION) + set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") + set(_JAVA_TARGET_OUTPUT_LINK "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") + elseif (CMAKE_JAVA_TARGET_VERSION) + set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") + set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar") + elseif (CMAKE_JAVA_TARGET_OUTPUT_NAME) + set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") + endif (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION) + # reset + set(CMAKE_JAVA_TARGET_OUTPUT_NAME) + + set(_JAVA_CLASS_FILES) + set(_JAVA_COMPILE_FILES) + set(_JAVA_DEPENDS) + set(_JAVA_RESOURCE_FILES) + foreach(_JAVA_SOURCE_FILE ${_JAVA_SOURCE_FILES}) + get_filename_component(_JAVA_EXT ${_JAVA_SOURCE_FILE} EXT) + get_filename_component(_JAVA_FILE ${_JAVA_SOURCE_FILE} NAME_WE) + get_filename_component(_JAVA_PATH ${_JAVA_SOURCE_FILE} PATH) + get_filename_component(_JAVA_FULL ${_JAVA_SOURCE_FILE} ABSOLUTE) + + file(RELATIVE_PATH _JAVA_REL_BINARY_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR} ${_JAVA_FULL}) + file(RELATIVE_PATH _JAVA_REL_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${_JAVA_FULL}) + string(LENGTH ${_JAVA_REL_BINARY_PATH} _BIN_LEN) + string(LENGTH ${_JAVA_REL_SOURCE_PATH} _SRC_LEN) + if (${_BIN_LEN} LESS ${_SRC_LEN}) + set(_JAVA_REL_PATH ${_JAVA_REL_BINARY_PATH}) + else (${_BIN_LEN} LESS ${_SRC_LEN}) + set(_JAVA_REL_PATH ${_JAVA_REL_SOURCE_PATH}) + endif (${_BIN_LEN} LESS ${_SRC_LEN}) + get_filename_component(_JAVA_REL_PATH ${_JAVA_REL_PATH} PATH) + + if (_JAVA_EXT MATCHES ".java") + list(APPEND _JAVA_COMPILE_FILES ${_JAVA_SOURCE_FILE}) + set(_JAVA_CLASS_FILE "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_REL_PATH}/${_JAVA_FILE}.class") + set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES} ${_JAVA_CLASS_FILE}) + + elseif (_JAVA_EXT MATCHES ".jar" + OR _JAVA_EXT MATCHES ".war" + OR _JAVA_EXT MATCHES ".ear" + OR _JAVA_EXT MATCHES ".sar") + list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_SOURCE_FILE}) + + elseif (_JAVA_EXT STREQUAL "") + list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH}) + list(APPEND _JAVA_DEPENDS ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}}) + + else (_JAVA_EXT MATCHES ".java") + __java_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/${_JAVA_SOURCE_FILE} + ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_SOURCE_FILE} + "Copying ${_JAVA_SOURCE_FILE} to the build directory") + list(APPEND _JAVA_RESOURCE_FILES ${_JAVA_SOURCE_FILE}) + endif (_JAVA_EXT MATCHES ".java") + endforeach(_JAVA_SOURCE_FILE) + + # create an empty java_class_filelist + if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist) + file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "") + endif() + + if (_JAVA_COMPILE_FILES) + # Compile the java files and create a list of class files + add_custom_command( + # NOTE: this command generates an artificial dependency file + OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} + COMMAND ${Java_JAVAC_EXECUTABLE} + ${CMAKE_JAVA_COMPILE_FLAGS} + -classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}" + -d ${CMAKE_JAVA_CLASS_OUTPUT_PATH} + ${_JAVA_COMPILE_FILES} + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} + DEPENDS ${_JAVA_COMPILE_FILES} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Building Java objects for ${_TARGET_NAME}.jar" + ) + add_custom_command( + OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist + COMMAND ${CMAKE_COMMAND} + -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH} + -DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}" + -P ${_JAVA_CLASS_FILELIST_SCRIPT} + DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + endif (_JAVA_COMPILE_FILES) + + # create the jar file + set(_JAVA_JAR_OUTPUT_PATH + ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME}) + if (CMAKE_JNI_TARGET) + add_custom_command( + OUTPUT ${_JAVA_JAR_OUTPUT_PATH} + COMMAND ${Java_JAR_EXECUTABLE} + -cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE} + ${_JAVA_RESOURCE_FILES} @java_class_filelist + COMMAND ${CMAKE_COMMAND} + -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} + -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME} + -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} + -P ${_JAVA_SYMLINK_SCRIPT} + COMMAND ${CMAKE_COMMAND} + -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} + -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_JAR_OUTPUT_PATH} + -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} + -P ${_JAVA_SYMLINK_SCRIPT} + DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist + WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH} + COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}" + ) + else () + add_custom_command( + OUTPUT ${_JAVA_JAR_OUTPUT_PATH} + COMMAND ${Java_JAR_EXECUTABLE} + -cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE} + ${_JAVA_RESOURCE_FILES} @java_class_filelist + COMMAND ${CMAKE_COMMAND} + -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} + -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME} + -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} + -P ${_JAVA_SYMLINK_SCRIPT} + WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH} + DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist + COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}" + ) + endif (CMAKE_JNI_TARGET) + + # Add the target and make sure we have the latest resource files. + add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH}) + + set_property( + TARGET + ${_TARGET_NAME} + PROPERTY + INSTALL_FILES + ${_JAVA_JAR_OUTPUT_PATH} + ) + + if (_JAVA_TARGET_OUTPUT_LINK) + set_property( + TARGET + ${_TARGET_NAME} + PROPERTY + INSTALL_FILES + ${_JAVA_JAR_OUTPUT_PATH} + ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK} + ) + + if (CMAKE_JNI_TARGET) + set_property( + TARGET + ${_TARGET_NAME} + PROPERTY + JNI_SYMLINK + ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK} + ) + endif (CMAKE_JNI_TARGET) + endif (_JAVA_TARGET_OUTPUT_LINK) + + set_property( + TARGET + ${_TARGET_NAME} + PROPERTY + JAR_FILE + ${_JAVA_JAR_OUTPUT_PATH} + ) + + set_property( + TARGET + ${_TARGET_NAME} + PROPERTY + CLASSDIR + ${CMAKE_JAVA_CLASS_OUTPUT_PATH} + ) + +endfunction(add_jar) + +function(INSTALL_JAR _TARGET_NAME _DESTINATION) + get_property(__FILES + TARGET + ${_TARGET_NAME} + PROPERTY + INSTALL_FILES + ) + + if (__FILES) + install( + FILES + ${__FILES} + DESTINATION + ${_DESTINATION} + ) + else (__FILES) + message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.") + endif (__FILES) +endfunction(INSTALL_JAR _TARGET_NAME _DESTINATION) + +function(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION) + get_property(__SYMLINK + TARGET + ${_TARGET_NAME} + PROPERTY + JNI_SYMLINK + ) + + if (__SYMLINK) + install( + FILES + ${__SYMLINK} + DESTINATION + ${_DESTINATION} + ) + else (__SYMLINK) + message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.") + endif (__SYMLINK) +endfunction(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION) + +function (find_jar VARIABLE) + set(_jar_names) + set(_jar_files) + set(_jar_versions) + set(_jar_paths + /usr/share/java/ + /usr/local/share/java/ + ${Java_JAR_PATHS}) + set(_jar_doc "NOTSET") + + set(_state "name") + + foreach (arg ${ARGN}) + if (${_state} STREQUAL "name") + if (${arg} STREQUAL "VERSIONS") + set(_state "versions") + elseif (${arg} STREQUAL "NAMES") + set(_state "names") + elseif (${arg} STREQUAL "PATHS") + set(_state "paths") + elseif (${arg} STREQUAL "DOC") + set(_state "doc") + else (${arg} STREQUAL "NAMES") + set(_jar_names ${arg}) + if (_jar_doc STREQUAL "NOTSET") + set(_jar_doc "Finding ${arg} jar") + endif (_jar_doc STREQUAL "NOTSET") + endif (${arg} STREQUAL "VERSIONS") + elseif (${_state} STREQUAL "versions") + if (${arg} STREQUAL "NAMES") + set(_state "names") + elseif (${arg} STREQUAL "PATHS") + set(_state "paths") + elseif (${arg} STREQUAL "DOC") + set(_state "doc") + else (${arg} STREQUAL "NAMES") + set(_jar_versions ${_jar_versions} ${arg}) + endif (${arg} STREQUAL "NAMES") + elseif (${_state} STREQUAL "names") + if (${arg} STREQUAL "VERSIONS") + set(_state "versions") + elseif (${arg} STREQUAL "PATHS") + set(_state "paths") + elseif (${arg} STREQUAL "DOC") + set(_state "doc") + else (${arg} STREQUAL "VERSIONS") + set(_jar_names ${_jar_names} ${arg}) + if (_jar_doc STREQUAL "NOTSET") + set(_jar_doc "Finding ${arg} jar") + endif (_jar_doc STREQUAL "NOTSET") + endif (${arg} STREQUAL "VERSIONS") + elseif (${_state} STREQUAL "paths") + if (${arg} STREQUAL "VERSIONS") + set(_state "versions") + elseif (${arg} STREQUAL "NAMES") + set(_state "names") + elseif (${arg} STREQUAL "DOC") + set(_state "doc") + else (${arg} STREQUAL "VERSIONS") + set(_jar_paths ${_jar_paths} ${arg}) + endif (${arg} STREQUAL "VERSIONS") + elseif (${_state} STREQUAL "doc") + if (${arg} STREQUAL "VERSIONS") + set(_state "versions") + elseif (${arg} STREQUAL "NAMES") + set(_state "names") + elseif (${arg} STREQUAL "PATHS") + set(_state "paths") + else (${arg} STREQUAL "VERSIONS") + set(_jar_doc ${arg}) + endif (${arg} STREQUAL "VERSIONS") + endif (${_state} STREQUAL "name") + endforeach (arg ${ARGN}) + + if (NOT _jar_names) + message(FATAL_ERROR "find_jar: No name to search for given") + endif (NOT _jar_names) + + foreach (jar_name ${_jar_names}) + foreach (version ${_jar_versions}) + set(_jar_files ${_jar_files} ${jar_name}-${version}.jar) + endforeach (version ${_jar_versions}) + set(_jar_files ${_jar_files} ${jar_name}.jar) + endforeach (jar_name ${_jar_names}) + + find_file(${VARIABLE} + NAMES ${_jar_files} + PATHS ${_jar_paths} + DOC ${_jar_doc} + NO_DEFAULT_PATH) +endfunction (find_jar VARIABLE) + +function(create_javadoc _target) + set(_javadoc_packages) + set(_javadoc_files) + set(_javadoc_sourcepath) + set(_javadoc_classpath) + set(_javadoc_installpath "${CMAKE_INSTALL_PREFIX}/share/javadoc") + set(_javadoc_doctitle) + set(_javadoc_windowtitle) + set(_javadoc_author FALSE) + set(_javadoc_version FALSE) + set(_javadoc_use FALSE) + + set(_state "package") + + foreach (arg ${ARGN}) + if (${_state} STREQUAL "package") + if (${arg} STREQUAL "PACKAGES") + set(_state "packages") + elseif (${arg} STREQUAL "FILES") + set(_state "files") + elseif (${arg} STREQUAL "SOURCEPATH") + set(_state "sourcepath") + elseif (${arg} STREQUAL "CLASSPATH") + set(_state "classpath") + elseif (${arg} STREQUAL "INSTALLPATH") + set(_state "installpath") + elseif (${arg} STREQUAL "DOCTITLE") + set(_state "doctitle") + elseif (${arg} STREQUAL "WINDOWTITLE") + set(_state "windowtitle") + elseif (${arg} STREQUAL "AUTHOR") + set(_state "author") + elseif (${arg} STREQUAL "USE") + set(_state "use") + elseif (${arg} STREQUAL "VERSION") + set(_state "version") + else () + set(_javadoc_packages ${arg}) + set(_state "packages") + endif () + elseif (${_state} STREQUAL "packages") + if (${arg} STREQUAL "FILES") + set(_state "files") + elseif (${arg} STREQUAL "SOURCEPATH") + set(_state "sourcepath") + elseif (${arg} STREQUAL "CLASSPATH") + set(_state "classpath") + elseif (${arg} STREQUAL "INSTALLPATH") + set(_state "installpath") + elseif (${arg} STREQUAL "DOCTITLE") + set(_state "doctitle") + elseif (${arg} STREQUAL "WINDOWTITLE") + set(_state "windowtitle") + elseif (${arg} STREQUAL "AUTHOR") + set(_state "author") + elseif (${arg} STREQUAL "USE") + set(_state "use") + elseif (${arg} STREQUAL "VERSION") + set(_state "version") + else () + list(APPEND _javadoc_packages ${arg}) + endif () + elseif (${_state} STREQUAL "files") + if (${arg} STREQUAL "PACKAGES") + set(_state "packages") + elseif (${arg} STREQUAL "SOURCEPATH") + set(_state "sourcepath") + elseif (${arg} STREQUAL "CLASSPATH") + set(_state "classpath") + elseif (${arg} STREQUAL "INSTALLPATH") + set(_state "installpath") + elseif (${arg} STREQUAL "DOCTITLE") + set(_state "doctitle") + elseif (${arg} STREQUAL "WINDOWTITLE") + set(_state "windowtitle") + elseif (${arg} STREQUAL "AUTHOR") + set(_state "author") + elseif (${arg} STREQUAL "USE") + set(_state "use") + elseif (${arg} STREQUAL "VERSION") + set(_state "version") + else () + list(APPEND _javadoc_files ${arg}) + endif () + elseif (${_state} STREQUAL "sourcepath") + if (${arg} STREQUAL "PACKAGES") + set(_state "packages") + elseif (${arg} STREQUAL "FILES") + set(_state "files") + elseif (${arg} STREQUAL "CLASSPATH") + set(_state "classpath") + elseif (${arg} STREQUAL "INSTALLPATH") + set(_state "installpath") + elseif (${arg} STREQUAL "DOCTITLE") + set(_state "doctitle") + elseif (${arg} STREQUAL "WINDOWTITLE") + set(_state "windowtitle") + elseif (${arg} STREQUAL "AUTHOR") + set(_state "author") + elseif (${arg} STREQUAL "USE") + set(_state "use") + elseif (${arg} STREQUAL "VERSION") + set(_state "version") + else () + list(APPEND _javadoc_sourcepath ${arg}) + endif () + elseif (${_state} STREQUAL "classpath") + if (${arg} STREQUAL "PACKAGES") + set(_state "packages") + elseif (${arg} STREQUAL "FILES") + set(_state "files") + elseif (${arg} STREQUAL "SOURCEPATH") + set(_state "sourcepath") + elseif (${arg} STREQUAL "INSTALLPATH") + set(_state "installpath") + elseif (${arg} STREQUAL "DOCTITLE") + set(_state "doctitle") + elseif (${arg} STREQUAL "WINDOWTITLE") + set(_state "windowtitle") + elseif (${arg} STREQUAL "AUTHOR") + set(_state "author") + elseif (${arg} STREQUAL "USE") + set(_state "use") + elseif (${arg} STREQUAL "VERSION") + set(_state "version") + else () + list(APPEND _javadoc_classpath ${arg}) + endif () + elseif (${_state} STREQUAL "installpath") + if (${arg} STREQUAL "PACKAGES") + set(_state "packages") + elseif (${arg} STREQUAL "FILES") + set(_state "files") + elseif (${arg} STREQUAL "SOURCEPATH") + set(_state "sourcepath") + elseif (${arg} STREQUAL "DOCTITLE") + set(_state "doctitle") + elseif (${arg} STREQUAL "WINDOWTITLE") + set(_state "windowtitle") + elseif (${arg} STREQUAL "AUTHOR") + set(_state "author") + elseif (${arg} STREQUAL "USE") + set(_state "use") + elseif (${arg} STREQUAL "VERSION") + set(_state "version") + else () + set(_javadoc_installpath ${arg}) + endif () + elseif (${_state} STREQUAL "doctitle") + if (${arg} STREQUAL "PACKAGES") + set(_state "packages") + elseif (${arg} STREQUAL "FILES") + set(_state "files") + elseif (${arg} STREQUAL "SOURCEPATH") + set(_state "sourcepath") + elseif (${arg} STREQUAL "INSTALLPATH") + set(_state "installpath") + elseif (${arg} STREQUAL "CLASSPATH") + set(_state "classpath") + elseif (${arg} STREQUAL "WINDOWTITLE") + set(_state "windowtitle") + elseif (${arg} STREQUAL "AUTHOR") + set(_state "author") + elseif (${arg} STREQUAL "USE") + set(_state "use") + elseif (${arg} STREQUAL "VERSION") + set(_state "version") + else () + set(_javadoc_doctitle ${arg}) + endif () + elseif (${_state} STREQUAL "windowtitle") + if (${arg} STREQUAL "PACKAGES") + set(_state "packages") + elseif (${arg} STREQUAL "FILES") + set(_state "files") + elseif (${arg} STREQUAL "SOURCEPATH") + set(_state "sourcepath") + elseif (${arg} STREQUAL "CLASSPATH") + set(_state "classpath") + elseif (${arg} STREQUAL "INSTALLPATH") + set(_state "installpath") + elseif (${arg} STREQUAL "DOCTITLE") + set(_state "doctitle") + elseif (${arg} STREQUAL "AUTHOR") + set(_state "author") + elseif (${arg} STREQUAL "USE") + set(_state "use") + elseif (${arg} STREQUAL "VERSION") + set(_state "version") + else () + set(_javadoc_windowtitle ${arg}) + endif () + elseif (${_state} STREQUAL "author") + if (${arg} STREQUAL "PACKAGES") + set(_state "packages") + elseif (${arg} STREQUAL "FILES") + set(_state "files") + elseif (${arg} STREQUAL "SOURCEPATH") + set(_state "sourcepath") + elseif (${arg} STREQUAL "CLASSPATH") + set(_state "classpath") + elseif (${arg} STREQUAL "INSTALLPATH") + set(_state "installpath") + elseif (${arg} STREQUAL "DOCTITLE") + set(_state "doctitle") + elseif (${arg} STREQUAL "WINDOWTITLE") + set(_state "windowtitle") + elseif (${arg} STREQUAL "AUTHOR") + set(_state "author") + elseif (${arg} STREQUAL "USE") + set(_state "use") + elseif (${arg} STREQUAL "VERSION") + set(_state "version") + else () + set(_javadoc_author ${arg}) + endif () + elseif (${_state} STREQUAL "use") + if (${arg} STREQUAL "PACKAGES") + set(_state "packages") + elseif (${arg} STREQUAL "FILES") + set(_state "files") + elseif (${arg} STREQUAL "SOURCEPATH") + set(_state "sourcepath") + elseif (${arg} STREQUAL "CLASSPATH") + set(_state "classpath") + elseif (${arg} STREQUAL "INSTALLPATH") + set(_state "installpath") + elseif (${arg} STREQUAL "DOCTITLE") + set(_state "doctitle") + elseif (${arg} STREQUAL "WINDOWTITLE") + set(_state "windowtitle") + elseif (${arg} STREQUAL "AUTHOR") + set(_state "author") + elseif (${arg} STREQUAL "USE") + set(_state "use") + elseif (${arg} STREQUAL "VERSION") + set(_state "version") + else () + set(_javadoc_use ${arg}) + endif () + elseif (${_state} STREQUAL "version") + if (${arg} STREQUAL "PACKAGES") + set(_state "packages") + elseif (${arg} STREQUAL "FILES") + set(_state "files") + elseif (${arg} STREQUAL "SOURCEPATH") + set(_state "sourcepath") + elseif (${arg} STREQUAL "CLASSPATH") + set(_state "classpath") + elseif (${arg} STREQUAL "INSTALLPATH") + set(_state "installpath") + elseif (${arg} STREQUAL "DOCTITLE") + set(_state "doctitle") + elseif (${arg} STREQUAL "WINDOWTITLE") + set(_state "windowtitle") + elseif (${arg} STREQUAL "AUTHOR") + set(_state "author") + elseif (${arg} STREQUAL "USE") + set(_state "use") + elseif (${arg} STREQUAL "VERSION") + set(_state "version") + else () + set(_javadoc_version ${arg}) + endif () + endif (${_state} STREQUAL "package") + endforeach (arg ${ARGN}) + + set(_javadoc_builddir ${CMAKE_CURRENT_BINARY_DIR}/javadoc/${_target}) + set(_javadoc_options -d ${_javadoc_builddir}) + + if (_javadoc_sourcepath) + set(_start TRUE) + foreach(_path ${_javadoc_sourcepath}) + if (_start) + set(_sourcepath ${_path}) + set(_start FALSE) + else (_start) + set(_sourcepath ${_sourcepath}:${_path}) + endif (_start) + endforeach(_path ${_javadoc_sourcepath}) + set(_javadoc_options ${_javadoc_options} -sourcepath ${_sourcepath}) + endif (_javadoc_sourcepath) + + if (_javadoc_classpath) + set(_start TRUE) + foreach(_path ${_javadoc_classpath}) + if (_start) + set(_classpath ${_path}) + set(_start FALSE) + else (_start) + set(_classpath ${_classpath}:${_path}) + endif (_start) + endforeach(_path ${_javadoc_classpath}) + set(_javadoc_options ${_javadoc_options} -classpath "${_classpath}") + endif (_javadoc_classpath) + + if (_javadoc_doctitle) + set(_javadoc_options ${_javadoc_options} -doctitle '${_javadoc_doctitle}') + endif (_javadoc_doctitle) + + if (_javadoc_windowtitle) + set(_javadoc_options ${_javadoc_options} -windowtitle '${_javadoc_windowtitle}') + endif (_javadoc_windowtitle) + + if (_javadoc_author) + set(_javadoc_options ${_javadoc_options} -author) + endif (_javadoc_author) + + if (_javadoc_use) + set(_javadoc_options ${_javadoc_options} -use) + endif (_javadoc_use) + + if (_javadoc_version) + set(_javadoc_options ${_javadoc_options} -version) + endif (_javadoc_version) + + add_custom_target(${_target}_javadoc ALL + COMMAND ${Java_JAVADOC_EXECUTABLE} ${_javadoc_options} + ${_javadoc_files} + ${_javadoc_packages} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + install( + DIRECTORY ${_javadoc_builddir} + DESTINATION ${_javadoc_installpath} + ) +endfunction(create_javadoc) diff --git a/depends/launcher/UseJavaClassFilelist.cmake b/depends/launcher/UseJavaClassFilelist.cmake new file mode 100644 index 00000000..c842bf71 --- /dev/null +++ b/depends/launcher/UseJavaClassFilelist.cmake @@ -0,0 +1,52 @@ +# +# This script create a list of compiled Java class files to be added to a +# jar file. This avoids including cmake files which get created in the +# binary directory. +# + +#============================================================================= +# Copyright 2010-2011 Andreas schneider +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +if (CMAKE_JAVA_CLASS_OUTPUT_PATH) + if (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}") + + set(_JAVA_GLOBBED_FILES) + if (CMAKE_JAR_CLASSES_PREFIX) + foreach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX}) + message(STATUS "JAR_CLASS_PREFIX: ${JAR_CLASS_PREFIX}") + + file(GLOB_RECURSE _JAVA_GLOBBED_TMP_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${JAR_CLASS_PREFIX}/*.class") + if (_JAVA_GLOBBED_TMP_FILES) + list(APPEND _JAVA_GLOBBED_FILES ${_JAVA_GLOBBED_TMP_FILES}) + endif (_JAVA_GLOBBED_TMP_FILES) + endforeach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX}) + else() + file(GLOB_RECURSE _JAVA_GLOBBED_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/*.class") + endif (CMAKE_JAR_CLASSES_PREFIX) + + set(_JAVA_CLASS_FILES) + # file(GLOB_RECURSE foo RELATIVE) is broken so we need this. + foreach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES}) + file(RELATIVE_PATH _JAVA_CLASS_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ${_JAVA_GLOBBED_FILE}) + set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES}${_JAVA_CLASS_FILE}\n) + endforeach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES}) + + # write to file + file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist ${_JAVA_CLASS_FILES}) + + else (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}") + message(SEND_ERROR "FATAL: Java class output path doesn't exist") + endif (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}") +else (CMAKE_JAVA_CLASS_OUTPUT_PATH) + message(SEND_ERROR "FATAL: Can't find CMAKE_JAVA_CLASS_OUTPUT_PATH") +endif (CMAKE_JAVA_CLASS_OUTPUT_PATH) diff --git a/depends/launcher/UseJavaSymlinks.cmake b/depends/launcher/UseJavaSymlinks.cmake new file mode 100644 index 00000000..c66ee1ea --- /dev/null +++ b/depends/launcher/UseJavaSymlinks.cmake @@ -0,0 +1,32 @@ +# +# Helper script for UseJava.cmake +# + +#============================================================================= +# Copyright 2010-2011 Andreas schneider +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +if (UNIX AND _JAVA_TARGET_OUTPUT_LINK) + if (_JAVA_TARGET_OUTPUT_NAME) + find_program(LN_EXECUTABLE + NAMES + ln + ) + + execute_process( + COMMAND ${LN_EXECUTABLE} -sf "${_JAVA_TARGET_OUTPUT_NAME}" "${_JAVA_TARGET_OUTPUT_LINK}" + WORKING_DIRECTORY ${_JAVA_TARGET_DIR} + ) + else (_JAVA_TARGET_OUTPUT_NAME) + message(SEND_ERROR "FATAL: Can't find _JAVA_TARGET_OUTPUT_NAME") + endif (_JAVA_TARGET_OUTPUT_NAME) +endif (UNIX AND _JAVA_TARGET_OUTPUT_LINK) diff --git a/depends/launcher/net/minecraft/Launcher.java b/depends/launcher/net/minecraft/Launcher.java new file mode 100644 index 00000000..8cef35ad --- /dev/null +++ b/depends/launcher/net/minecraft/Launcher.java @@ -0,0 +1,154 @@ +// +// Copyright 2012 MultiMC Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package net.minecraft; + +import java.util.TreeMap; +import java.util.Map; +import java.net.URL; +import java.awt.Dimension; +import java.awt.BorderLayout; +import java.awt.Graphics; +import java.applet.Applet; +import java.applet.AppletStub; + +public class Launcher extends Applet implements AppletStub +{ + private Applet wrappedApplet; + private URL documentBase; + private boolean active = false; + private final Map params; + + public Launcher(Applet applet, URL documentBase) + { + params = new TreeMap(); + + this.setLayout(new BorderLayout()); + this.add(applet, "Center"); + this.wrappedApplet = applet; + this.documentBase = documentBase; + } + + public void setParameter(String name, String value) + { + params.put(name, value); + } + + public void replace(Applet applet) + { + this.wrappedApplet = applet; + + applet.setStub(this); + applet.setSize(getWidth(), getHeight()); + + this.setLayout(new BorderLayout()); + this.add(applet, "Center"); + + applet.init(); + active = true; + applet.start(); + validate(); + } + + @Override + public String getParameter(String name) + { + String param = params.get(name); + if (param != null) + return param; + try + { + return super.getParameter(name); + } catch (Exception ignore){} + return null; + } + + @Override + public boolean isActive() + { + return active; + } + + @Override + public void appletResize(int width, int height) + { + wrappedApplet.resize(width, height); + } + + @Override + public void resize(int width, int height) + { + wrappedApplet.resize(width, height); + } + + @Override + public void resize(Dimension d) + { + wrappedApplet.resize(d); + } + + @Override + public void init() + { + if (wrappedApplet != null) + { + wrappedApplet.init(); + } + } + + @Override + public void start() + { + wrappedApplet.start(); + active = true; + } + + @Override + public void stop() + { + wrappedApplet.stop(); + active = false; + } + + public void destroy() + { + wrappedApplet.destroy(); + } + + @Override + public URL getCodeBase() { + return wrappedApplet.getCodeBase(); + } + + @Override + public URL getDocumentBase() + { + return documentBase; + } + + @Override + public void setVisible(boolean b) + { + super.setVisible(b); + wrappedApplet.setVisible(b); + } + public void update(Graphics paramGraphics) + { + } + public void paint(Graphics paramGraphics) + { + } +} \ No newline at end of file diff --git a/depends/launcher/org/simplericity/macify/eawt/Application.java b/depends/launcher/org/simplericity/macify/eawt/Application.java new file mode 100644 index 00000000..153bb9ee --- /dev/null +++ b/depends/launcher/org/simplericity/macify/eawt/Application.java @@ -0,0 +1,176 @@ +package org.simplericity.macify.eawt; + +/* + * Copyright 2007 Eirik Bjorsnos. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.awt.*; +import java.awt.image.BufferedImage; + +/** + * The Macify Library API interface provides integration with the OS X platform for Java Applications. + * The API includes a facade to the + * + * Apple Java Extensions API + * . + * Additionally, it provides access to several useful methods in the Cocoa NSApplication API. + * + * The default implementation of this interface is {@link org.simplericity.macify.eawt.DefaultApplication}. + */ +public interface Application { + + static int REQUEST_USER_ATTENTION_TYPE_CRITICAL = 1 ; + static int REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL = 2 ; + + /** + * See + * + * Apple's API + * . + */ + void addAboutMenuItem(); + + /** + * See + * + * Apple's API + * . + */ + void addApplicationListener(ApplicationListener applicationListener); + + /** + * See + * + * Apple's API + * . + */ + void addPreferencesMenuItem(); + + /** + * See + * + * Apple's API + * . + */ + boolean getEnabledAboutMenu(); + + /** + * See + * + * Apple's API + * . + */ + boolean getEnabledPreferencesMenu(); + + /** + * See + * + * Apple's API + * . + */ + boolean isAboutMenuItemPresent(); + + /** + * See + * + * Apple's API + * . + */ + boolean isPreferencesMenuItemPresent(); + + /** + * See + * + * Apple's API + * . + */ + void removeAboutMenuItem(); + + /** + * See + * + * Apple's API + * . + */ + void removeApplicationListener(ApplicationListener applicationListener); + + /** + * See + * + * Apple's API + * . + */ + void removePreferencesMenuItem(); + + /** + * See + * + * Apple's API + * . + */ + void setEnabledAboutMenu(boolean enabled); + + /** + * See + * + * Apple's API + * . + */ + void setEnabledPreferencesMenu(boolean enabled); + + /** + * See + * + * Apple's API + * . + */ + Point getMouseLocationOnScreen(); + + /** + * See + * + * Apple's NSApplication Class Reference + * . + * @param type on of {@link #REQUEST_USER_ATTENTION_TYPE_CRITICAL} or {@link #REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL}. + */ + int requestUserAttention(int type); + + /** + * See + * + * Apple's NSApplication Class Reference + * + */ + void cancelUserAttentionRequest(int request); + + /** + * Update the application's icon image + * @param image + */ + void setApplicationIconImage(BufferedImage image); + + /** + * Get the application's icon image. + */ + BufferedImage getApplicationIconImage(); + + /** + * Determines whether the application is running on a Mac AND the Apple Extensions API classes are available. + * @return + */ + boolean isMac(); + + +} diff --git a/depends/launcher/org/simplericity/macify/eawt/ApplicationAdapter.java b/depends/launcher/org/simplericity/macify/eawt/ApplicationAdapter.java new file mode 100644 index 00000000..e9c3db7d --- /dev/null +++ b/depends/launcher/org/simplericity/macify/eawt/ApplicationAdapter.java @@ -0,0 +1,48 @@ +package org.simplericity.macify.eawt; + +/* + * Copyright 2007 Eirik Bjorsnos. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class ApplicationAdapter implements ApplicationListener { + + public void handleQuit(ApplicationEvent event) { + + } + + public void handleAbout(ApplicationEvent event) { + + } + + public void handleOpenApplication(ApplicationEvent event) { + + } + + public void handleOpenFile(ApplicationEvent event) { + + } + + public void handlePreferences(ApplicationEvent event) { + + } + + public void handlePrintFile(ApplicationEvent event) { + + } + + public void handleReOpenApplication(ApplicationEvent event) { + + } +} diff --git a/depends/launcher/org/simplericity/macify/eawt/ApplicationEvent.java b/depends/launcher/org/simplericity/macify/eawt/ApplicationEvent.java new file mode 100644 index 00000000..78420355 --- /dev/null +++ b/depends/launcher/org/simplericity/macify/eawt/ApplicationEvent.java @@ -0,0 +1,25 @@ +package org.simplericity.macify.eawt; + +/* + * Copyright 2007 Eirik Bjorsnos. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public interface ApplicationEvent { + String getFilename(); + boolean isHandled(); + void setHandled(boolean handled); + Object getSource(); + String toString(); +} diff --git a/depends/launcher/org/simplericity/macify/eawt/ApplicationListener.java b/depends/launcher/org/simplericity/macify/eawt/ApplicationListener.java new file mode 100644 index 00000000..a291bee4 --- /dev/null +++ b/depends/launcher/org/simplericity/macify/eawt/ApplicationListener.java @@ -0,0 +1,27 @@ +package org.simplericity.macify.eawt; + +/* + * Copyright 2007 Eirik Bjorsnos. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public interface ApplicationListener { + void handleAbout(ApplicationEvent event); + void handleOpenApplication(ApplicationEvent event); + void handleOpenFile(ApplicationEvent event); + void handlePreferences(ApplicationEvent event); + void handlePrintFile(ApplicationEvent event); + void handleQuit(ApplicationEvent event); + void handleReOpenApplication(ApplicationEvent event); +} diff --git a/depends/launcher/org/simplericity/macify/eawt/DefaultApplication.java b/depends/launcher/org/simplericity/macify/eawt/DefaultApplication.java new file mode 100644 index 00000000..5752a350 --- /dev/null +++ b/depends/launcher/org/simplericity/macify/eawt/DefaultApplication.java @@ -0,0 +1,418 @@ +package org.simplericity.macify.eawt; + +/* + * Copyright 2007 Eirik Bjorsnos. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.*; +import java.lang.reflect.*; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.MalformedURLException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + + +/** + * Implements Application by calling the Mac OS X API through reflection. + * If this class is used on a non-OS X platform the operations will have no effect or they will simulate + * what the Apple API would do for those who manipulate state. ({@link #setEnabledAboutMenu(boolean)} etc.) + */ +@SuppressWarnings("unchecked") +public class DefaultApplication implements Application { + + private Object application; + private Class applicationListenerClass; + + Map listenerMap = Collections.synchronizedMap(new HashMap()); + private boolean enabledAboutMenu = true; + private boolean enabledPreferencesMenu; + private boolean aboutMenuItemPresent = true; + private boolean preferencesMenuItemPresent; + private ClassLoader classLoader; + + public DefaultApplication() { + try { + final File file = new File("/System/Library/Java"); + if (file.exists()) { + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Class clc = scl.getClass(); + if (URLClassLoader.class.isAssignableFrom(clc)) { + Method addUrl = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class}); + addUrl.setAccessible(true); + addUrl.invoke(scl, new Object[]{file.toURI().toURL()}); + } + } + + Class appClass = Class.forName("com.apple.eawt.Application"); + application = appClass.getMethod("getApplication", new Class[0]).invoke(null, new Object[0]); + applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener"); + } catch (ClassNotFoundException e) { + application = null; + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + + } + + public boolean isMac() { + return application != null; + } + + public void addAboutMenuItem() { + if (isMac()) { + callMethod(application, "addAboutMenuItem"); + } else { + this.aboutMenuItemPresent = true; + } + } + + public void addApplicationListener(ApplicationListener applicationListener) { + + if (!Modifier.isPublic(applicationListener.getClass().getModifiers())) { + throw new IllegalArgumentException("ApplicationListener must be a public class"); + } + if (isMac()) { + Object listener = Proxy.newProxyInstance(getClass().getClassLoader(), + new Class[]{applicationListenerClass}, + new ApplicationListenerInvocationHandler(applicationListener)); + + callMethod(application, "addApplicationListener", new Class[]{applicationListenerClass}, new Object[]{listener}); + listenerMap.put(applicationListener, listener); + } else { + listenerMap.put(applicationListener, applicationListener); + } + } + + public void addPreferencesMenuItem() { + if (isMac()) { + callMethod("addPreferencesMenuItem"); + } else { + this.preferencesMenuItemPresent = true; + } + } + + public boolean getEnabledAboutMenu() { + if (isMac()) { + return callMethod("getEnabledAboutMenu").equals(Boolean.TRUE); + } else { + return enabledAboutMenu; + } + } + + public boolean getEnabledPreferencesMenu() { + if (isMac()) { + Object result = callMethod("getEnabledPreferencesMenu"); + return result.equals(Boolean.TRUE); + } else { + return enabledPreferencesMenu; + } + } + + public Point getMouseLocationOnScreen() { + if (isMac()) { + try { + Method method = application.getClass().getMethod("getMouseLocationOnScreen", new Class[0]); + return (Point) method.invoke(null, new Object[0]); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } else { + return new Point(0, 0); + } + } + + public boolean isAboutMenuItemPresent() { + if (isMac()) { + return callMethod("isAboutMenuItemPresent").equals(Boolean.TRUE); + } else { + return aboutMenuItemPresent; + } + } + + public boolean isPreferencesMenuItemPresent() { + if (isMac()) { + return callMethod("isPreferencesMenuItemPresent").equals(Boolean.TRUE); + } else { + return this.preferencesMenuItemPresent; + } + } + + public void removeAboutMenuItem() { + if (isMac()) { + callMethod("removeAboutMenuItem"); + } else { + this.aboutMenuItemPresent = false; + } + } + + public synchronized void removeApplicationListener(ApplicationListener applicationListener) { + if (isMac()) { + Object listener = listenerMap.get(applicationListener); + callMethod(application, "removeApplicationListener", new Class[]{applicationListenerClass}, new Object[]{listener}); + + } + listenerMap.remove(applicationListener); + } + + public void removePreferencesMenuItem() { + if (isMac()) { + callMethod("removeAboutMenuItem"); + } else { + this.preferencesMenuItemPresent = false; + } + } + + public void setEnabledAboutMenu(boolean enabled) { + if (isMac()) { + callMethod(application, "setEnabledAboutMenu", new Class[]{Boolean.TYPE}, new Object[]{Boolean.valueOf(enabled)}); + } else { + this.enabledAboutMenu = enabled; + } + } + + public void setEnabledPreferencesMenu(boolean enabled) { + if (isMac()) { + callMethod(application, "setEnabledPreferencesMenu", new Class[]{Boolean.TYPE}, new Object[]{Boolean.valueOf(enabled)}); + } else { + this.enabledPreferencesMenu = enabled; + } + + } + + public int requestUserAttention(int type) { + if (type != REQUEST_USER_ATTENTION_TYPE_CRITICAL && type != REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL) { + throw new IllegalArgumentException("Requested user attention type is not allowed: " + type); + } + try { + Object application = getNSApplication(); + Field critical = application.getClass().getField("UserAttentionRequestCritical"); + Field informational = application.getClass().getField("UserAttentionRequestInformational"); + Field actual = type == REQUEST_USER_ATTENTION_TYPE_CRITICAL ? critical : informational; + + return ((Integer) application.getClass().getMethod("requestUserAttention", new Class[]{Integer.TYPE}).invoke(application, new Object[]{actual.get(null)})).intValue(); + + } catch (ClassNotFoundException e) { + return -1; + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + + public void cancelUserAttentionRequest(int request) { + try { + Object application = getNSApplication(); + application.getClass().getMethod("cancelUserAttentionRequest", new Class[]{Integer.TYPE}).invoke(application, new Object[]{new Integer(request)}); + } catch (ClassNotFoundException e) { + // Nada + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private Object getNSApplication() throws ClassNotFoundException { + try { + Class applicationClass = Class.forName("com.apple.cocoa.application.NSApplication"); + return applicationClass.getMethod("sharedApplication", new Class[0]).invoke(null, new Object[0]); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + public void setApplicationIconImage(BufferedImage image) { + if (isMac()) { + try { + Method setDockIconImage = application.getClass().getMethod("setDockIconImage", Image.class); + + try { + setDockIconImage.invoke(application, image); + } catch (IllegalAccessException e) { + + } catch (InvocationTargetException e) { + + } + } catch (NoSuchMethodException mnfe) { + + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try { + ImageIO.write(image, "png", stream); + } catch (IOException e) { + throw new RuntimeException(e); + } + + try { + Class nsDataClass = Class.forName("com.apple.cocoa.foundation.NSData"); + Constructor constructor = nsDataClass.getConstructor(new Class[]{new byte[0].getClass()}); + + Object nsData = constructor.newInstance(new Object[]{stream.toByteArray()}); + + Class nsImageClass = Class.forName("com.apple.cocoa.application.NSImage"); + Object nsImage = nsImageClass.getConstructor(new Class[]{nsDataClass}).newInstance(new Object[]{nsData}); + + Object application = getNSApplication(); + + application.getClass().getMethod("setApplicationIconImage", new Class[]{nsImageClass}).invoke(application, new Object[]{nsImage}); + + } catch (ClassNotFoundException e) { + + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } + + } + + } + } + + public BufferedImage getApplicationIconImage() { + if (isMac()) { + + try { + Method getDockIconImage = application.getClass().getMethod("getDockIconImage"); + try { + return (BufferedImage) getDockIconImage.invoke(application); + } catch (IllegalAccessException e) { + + } catch (InvocationTargetException e) { + + } + } catch (NoSuchMethodException nsme) { + + try { + Class nsDataClass = Class.forName("com.apple.cocoa.foundation.NSData"); + Class nsImageClass = Class.forName("com.apple.cocoa.application.NSImage"); + Object application = getNSApplication(); + Object nsImage = application.getClass().getMethod("applicationIconImage", new Class[0]).invoke(application, new Object[0]); + + Object nsData = nsImageClass.getMethod("TIFFRepresentation", new Class[0]).invoke(nsImage, new Object[0]); + + Integer length = (Integer) nsDataClass.getMethod("length", new Class[0]).invoke(nsData, new Object[0]); + byte[] bytes = (byte[]) nsDataClass.getMethod("bytes", new Class[]{Integer.TYPE, Integer.TYPE}).invoke(nsData, new Object[]{Integer.valueOf(0), length}); + + BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); + return image; + + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + } + + return null; + } + + private Object callMethod(String methodname) { + return callMethod(application, methodname, new Class[0], new Object[0]); + } + + private Object callMethod(Object object, String methodname) { + return callMethod(object, methodname, new Class[0], new Object[0]); + } + + private Object callMethod(Object object, String methodname, Class[] classes, Object[] arguments) { + try { + if (classes == null) { + classes = new Class[arguments.length]; + for (int i = 0; i < classes.length; i++) { + classes[i] = arguments[i].getClass(); + + } + } + Method addListnerMethod = object.getClass().getMethod(methodname, classes); + return addListnerMethod.invoke(object, arguments); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + class ApplicationListenerInvocationHandler implements InvocationHandler { + private ApplicationListener applicationListener; + + ApplicationListenerInvocationHandler(ApplicationListener applicationListener) { + this.applicationListener = applicationListener; + } + + public Object invoke(Object object, Method appleMethod, Object[] objects) throws Throwable { + + ApplicationEvent event = createApplicationEvent(objects[0]); + try { + Method method = applicationListener.getClass().getMethod(appleMethod.getName(), new Class[]{ApplicationEvent.class}); + return method.invoke(applicationListener, new Object[]{event}); + } catch (NoSuchMethodException e) { + if (appleMethod.getName().equals("equals") && objects.length == 1) { + return Boolean.valueOf(object == objects[0]); + } + return null; + } + } + } + + private ApplicationEvent createApplicationEvent(final Object appleApplicationEvent) { + return (ApplicationEvent) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ApplicationEvent.class}, new InvocationHandler() { + public Object invoke(Object o, Method method, Object[] objects) throws Throwable { + return appleApplicationEvent.getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(appleApplicationEvent, objects); + } + }); + } +} diff --git a/depends/patchlib/CMakeLists.txt b/depends/patchlib/CMakeLists.txt new file mode 100644 index 00000000..4130e08f --- /dev/null +++ b/depends/patchlib/CMakeLists.txt @@ -0,0 +1,14 @@ +project(patchlib C) + +set(SRCS +blocksort.c +huffman.c +crctable.c +randtable.c +compress.c +decompress.c +bzlib.c +bspatch.c +) + +add_library(patchlib STATIC ${SRCS}) diff --git a/depends/patchlib/LICENSE-bzip2 b/depends/patchlib/LICENSE-bzip2 new file mode 100644 index 00000000..cc614178 --- /dev/null +++ b/depends/patchlib/LICENSE-bzip2 @@ -0,0 +1,42 @@ + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2010 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.6 of 6 September 2010 + +-------------------------------------------------------------------------- diff --git a/depends/patchlib/blocksort.c b/depends/patchlib/blocksort.c new file mode 100644 index 00000000..d63dbbf8 --- /dev/null +++ b/depends/patchlib/blocksort.c @@ -0,0 +1,1095 @@ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +void fallbackSimpleSort ( UInt32* fmap, + UInt32* eclass, + Int32 lo, + Int32 hi ) +{ + Int32 i, j, tmp; + UInt32 ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for ( i = hi-4; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for ( i = hi-1; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define fvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + fswap(fmap[yyp1], fmap[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + + +#define fmin(a,b) ((a) < (b)) ? (a) : (b) + +#define fpush(lz,hz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; } + +#define fpop(lz,hz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; } + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + + +static +void fallbackQSort3 ( UInt32* fmap, + UInt32* eclass, + Int32 loSt, + Int32 hiSt ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m; + Int32 sp, lo, hi; + UInt32 med, r, r3; + Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; + Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush ( loSt, hiSt ); + + while (sp > 0) { + + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); + + fpop ( lo, hi ); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort ( fmap, eclass, lo, hi ); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + avoid bad cases. Median of 9 seems to help but + looks rather expensive. This too seems to work but + is cheaper. Guidance for the magic constants + 7621 and 32768 is taken from Sedgewick's algorithms + book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) med = eclass[fmap[lo]]; else + if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unLo]] - (Int32)med; + if (n == 0) { + fswap(fmap[unLo], fmap[ltLo]); + ltLo++; unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unHi]] - (Int32)med; + if (n == 0) { + fswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); + + if (gtHi < ltLo) continue; + + n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); + m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush ( lo, n ); + fpush ( m, hi ); + } else { + fpush ( m, hi ); + fpush ( lo, n ); + } + } +} + +#undef fmin +#undef fpush +#undef fpop +#undef fswap +#undef fvswap +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + eclass exists for [0 .. nblock-1] + ((UChar*)eclass) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)eclass) [0 .. nblock-1] holds block + All other areas of eclass destroyed + fmap [0 .. nblock-1] holds sorted order + bhtab [ 0 .. 2+(nblock/32) ] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort ( UInt32* fmap, + UInt32* eclass, + UInt32* bhtab, + Int32 nblock, + Int32 verb ) +{ + Int32 ftab[257]; + Int32 ftabCopy[256]; + Int32 H, i, j, k, l, r, cc, cc1; + Int32 nNotDone; + Int32 nBhtab; + UChar* eclass8 = (UChar*)eclass; + + /*-- + Initial 1-char radix sort to generate + initial fmap and initial BH bits. + --*/ + if (verb >= 4) + VPrintf0 ( " bucket sorting ...\n" ); + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + (nblock / 32); + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /*-- + Inductively refine the buckets. Kind-of an + "exponential radix sort" (!), inspired by the + Manber-Myers suffix array construction algorithm. + --*/ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + + if (verb >= 4) + VPrintf1 ( " depth %6d has ", H ); + + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) j = i; + k = fmap[i] - H; if (k < 0) k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3 ( fmap, eclass, l, r ); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { SET_BH(i); cc = cc1; }; + } + } + } + + if (verb >= 4) + VPrintf1 ( "%6d unresolved strings\n", nNotDone ); + + H *= 2; + if (H > nblock || nNotDone == 0) break; + } + + /*-- + Reconstruct the original block in + eclass8 [0 .. nblock-1], since the + previous phase destroyed it. + --*/ + if (verb >= 4) + VPrintf0 ( " reconstructing block ...\n" ); + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (UChar)j; + } + AssertH ( j < 256, 1005 ); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +Bool mainGtU ( UInt32 i1, + UInt32 i2, + UChar* block, + UInt16* quadrant, + UInt32 nblock, + Int32* budget ) +{ + Int32 k; + UChar c1, c2; + UInt16 s1, s2; + + AssertD ( i1 != i2, "mainGtU" ); + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 9 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 10 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 11 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 12 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + + k = nblock + 8; + + do { + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + k -= 8; + (*budget)--; + } + while (k >= 0); + + return False; +} + + +/*---------------------------------------------*/ +/*-- + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. +--*/ +static +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + +static +void mainSimpleSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 lo, + Int32 hi, + Int32 d, + Int32* budget ) +{ + Int32 i, j, h, bigN, hp; + UInt32 v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (True) { + + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/*-- + The following is an implementation of + an elegant 3-way quicksort for strings, + described in a paper "Fast Algorithms for + Sorting and Searching Strings", by Robert + Sedgewick and Jon L. Bentley. +--*/ + +#define mswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define mvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + mswap(ptr[yyp1], ptr[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + +static +__inline__ +UChar mmed3 ( UChar a, UChar b, UChar c ) +{ + UChar t; + if (a > b) { t = a; a = b; b = t; }; + if (b > c) { + b = c; + if (a > b) b = a; + } + return b; +} + +#define mmin(a,b) ((a) < (b)) ? (a) : (b) + +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; } + +#define mpop(lz,hz,dz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; } + + +#define mnextsize(az) (nextHi[az]-nextLo[az]) + +#define mnextswap(az,bz) \ + { Int32 tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } + + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static +void mainQSort3 ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 loSt, + Int32 hiSt, + Int32 dSt, + Int32* budget ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m, med; + Int32 sp, lo, hi, d; + + Int32 stackLo[MAIN_QSORT_STACK_SIZE]; + Int32 stackHi[MAIN_QSORT_STACK_SIZE]; + Int32 stackD [MAIN_QSORT_STACK_SIZE]; + + Int32 nextLo[3]; + Int32 nextHi[3]; + Int32 nextD [3]; + + sp = 0; + mpush ( loSt, hiSt, dSt ); + + while (sp > 0) { + + AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); + + mpop ( lo, hi, d ); + if (hi - lo < MAIN_QSORT_SMALL_THRESH || + d > MAIN_QSORT_DEPTH_THRESH) { + mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); + if (*budget < 0) return; + continue; + } + + med = (Int32) + mmed3 ( block[ptr[ lo ]+d], + block[ptr[ hi ]+d], + block[ptr[ (lo+hi)>>1 ]+d] ); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (True) { + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; unLo++; continue; + }; + if (n > 0) break; + unLo++; + } + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; unHi--; continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "mainQSort3(2)" ); + + if (gtHi < ltLo) { + mpush(lo, hi, d+1 ); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); + + mpush (nextLo[0], nextHi[0], nextD[0]); + mpush (nextLo[1], nextHi[1], nextD[1]); + mpush (nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mswap +#undef mvswap +#undef mpush +#undef mpop +#undef mmin +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > N_OVERSHOOT + block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)block32) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)block32) [0 .. nblock-1] holds block + All other areas of block32 destroyed + ftab [0 .. 65536 ] destroyed + ptr [0 .. nblock-1] holds sorted order + if (*budget < 0), sorting was abandoned +*/ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static +void mainSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + UInt32* ftab, + Int32 nblock, + Int32 verb, + Int32* budget ) +{ + Int32 i, j, k, ss, sb; + Int32 runningOrder[256]; + Bool bigDone[256]; + Int32 copyStart[256]; + Int32 copyEnd [256]; + UChar c1; + Int32 numQSorted; + UInt16 s; + if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); + + /*-- set up the 2-byte frequency table --*/ + for (i = 65536; i >= 0; i--) ftab[i] = 0; + + j = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); + ftab[j]++; + } + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); + + /*-- Complete the initial radix sort --*/ + for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; + + s = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-3; + } + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + } + + /*-- + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + --*/ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + Int32 vv; + Int32 h = 1; + do h = 3 * h + 1; while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /*-- + The main sorting loop. + --*/ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /*-- + Process big buckets, starting with the least full. + Basically this is a 3-step process in which we call + mainQSort3 to sort the small buckets [ss, j], but + also make a big effort to avoid the calls if we can. + --*/ + ss = runningOrder[i]; + + /*-- + Step 1: + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j], for j != ss. + Hopefully previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + --*/ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if ( ! (ftab[sb] & SETMASK) ) { + Int32 lo = ftab[sb] & CLEARMASK; + Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + if (verb >= 4) + VPrintf4 ( " qsort [0x%x, 0x%x] " + "done %d this %d\n", + ss, j, numQSorted, hi - lo + 1 ); + mainQSort3 ( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + numQSorted += (hi - lo + 1); + if (*budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH ( !bigDone[ss], 1006 ); + + /*-- + Step 2: + Now scan this big bucket [ss] so as to synthesise the + sorted order for small buckets [t, ss] for all t, + including, magically, the bucket [ss,ss] too. + This will avoid doing Real Work in subsequent Step 1's. + --*/ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyStart[c1]++ ] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyEnd[c1]-- ] = k; + } + } + + AssertH ( (copyStart[ss]-1 == copyEnd[ss]) + || + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + Necessity for this case is demonstrated by compressing + a sequence of approximately 48.5 million of character + 251; 1.0.0/1.0.1 will then die here. */ + (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), + 1007 ) + + for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; + + /*-- + Step 3: + The [ss] big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + + The quadrant array provides a way to incrementally + cache sort orderings, as they appear, so as to + make subsequent comparisons in fullGtU() complete + faster. For repetitive blocks this makes a big + difference (but not big enough to be able to avoid + the fallback sorting mechanism, exponential radix sort). + + The precise meaning is: at all times: + + for 0 <= i < nblock and 0 <= j <= nblock + + if block[i] != block[j], + + then the relative values of quadrant[i] and + quadrant[j] are meaningless. + + else { + if quadrant[i] < quadrant[j] + then the string starting at i lexicographically + precedes the string starting at j + + else if quadrant[i] > quadrant[j] + then the string starting at j lexicographically + precedes the string starting at i + + else + the relative ordering of the strings starting + at i and j has not yet been determined. + } + --*/ + bigDone[ss] = True; + + if (i < 255) { + Int32 bbStart = ftab[ss << 8] & CLEARMASK; + Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + Int32 shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + Int32 a2update = ptr[bbStart + j]; + UInt16 qVal = (UInt16)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); + } + + } + + if (verb >= 4) + VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", + nblock, numQSorted, nblock - numQSorted ); +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)arr2) [0 .. nblock-1] holds block + arr1 exists for [0 .. nblock-1] + + Post: + ((UChar*)arr2) [0 .. nblock-1] holds block + All other areas of block destroyed + ftab [ 0 .. 65536 ] destroyed + arr1 [0 .. nblock-1] holds sorted order +*/ +void BZ2_blockSort ( EState* s ) +{ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt32* ftab = s->ftab; + Int32 nblock = s->nblock; + Int32 verb = s->verbosity; + Int32 wfact = s->workFactor; + UInt16* quadrant; + Int32 budget; + Int32 budgetInit; + Int32 i; + + if (nblock < 10000) { + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } else { + /* Calculate the location for quadrant, remembering to get + the alignment right. Assumes that &(block[0]) is at least + 2-byte aligned -- this should be ok since block is really + the first section of arr2. + */ + i = nblock+BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (UInt16*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + transition point at very roughly the same place as + with v0.1 and v0.9.0. + Not that it particularly matters any more, since the + resulting compressed stream is now the same regardless + of whether or not we use the main sort or fallback sort. + */ + if (wfact < 1 ) wfact = 1; + if (wfact > 100) wfact = 100; + budgetInit = nblock * ((wfact-1) / 3); + budget = budgetInit; + + mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); + if (verb >= 3) + VPrintf3 ( " %d work, %d block, ratio %5.2f\n", + budgetInit - budget, + nblock, + (float)(budgetInit - budget) / + (float)(nblock==0 ? 1 : nblock) ); + if (budget < 0) { + if (verb >= 2) + VPrintf0 ( " too repetitive; using fallback" + " sorting algorithm\n" ); + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) + { s->origPtr = i; break; }; + + AssertH( s->origPtr != -1, 1003 ); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ + diff --git a/depends/patchlib/bspatch.c b/depends/patchlib/bspatch.c new file mode 100644 index 00000000..e8469edc --- /dev/null +++ b/depends/patchlib/bspatch.c @@ -0,0 +1,303 @@ +/*- + * Copyright 2003-2005 Colin Percival + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef _MSC_VER + // bogus 'secure' nonsense + #define _CRT_SECURE_NO_WARNINGS + // bogus signed/unsigned mismatch + #pragma warning( disable: 4018) +#endif + +#ifdef _WIN32 + #include + #define ssize_t size_t +#else + #include +#endif + +#if defined __APPLE__ && defined __MACH__ + typedef unsigned char u_char; +#endif + +#include "bzlib.h" +#include "bspatch.h" +#include +#include +#include +#include + +static off_t offtin(u_char *buf) +{ + off_t y; + + y=buf[7]&0x7F; + y=y*256;y+=buf[6]; + y=y*256;y+=buf[5]; + y=y*256;y+=buf[4]; + y=y*256;y+=buf[3]; + y=y*256;y+=buf[2]; + y=y*256;y+=buf[1]; + y=y*256;y+=buf[0]; + + if(buf[7]&0x80) y=-y; + + return y; +} + +int bspatch(const char * oldfile, const char * newfile, const char * patchfile) +{ + FILE * f, * cpf, * dpf, * epf; + BZFILE * cpfbz2, * dpfbz2, * epfbz2; + int cbz2err, dbz2err, ebz2err; + FILE * temp; + ssize_t oldsize,newsize; + ssize_t bzctrllen,bzdatalen; + unsigned char header[32],buf[8]; + unsigned char *old_contents; + unsigned char *new_contents; + off_t oldpos,newpos; + off_t ctrl[3]; + off_t lenread; + off_t i; + + /* Open patch file */ + if ((f = fopen(patchfile, "rb")) == NULL) + { + //err(1, "fopen(%s)", argv[3]); + return ERR_OTHER; + } + + /* + File format: + 0 8 "BSDIFF40" + 8 8 X + 16 8 Y + 24 8 sizeof(newfile) + 32 X bzip2(control block) + 32+X Y bzip2(diff block) + 32+X+Y ??? bzip2(extra block) + with control block a set of triples (x,y,z) meaning "add x bytes + from oldfile to x bytes from the diff block; copy y bytes from the + extra block; seek forwards in oldfile by z bytes". + */ + + /* Read header */ + if (fread(header, 1, 32, f) < 32) + { + if (feof(f)) + { + //errx(1, "Corrupt patch\n"); + return ERR_CORRUPT_PATCH; + } + //err(1, "fread(%s)", argv[3]); + return ERR_OTHER; + } + + /* Check for appropriate magic */ + if (memcmp(header, "BSDIFF40", 8) != 0) + { + //errx(1, "Corrupt patch\n"); + return ERR_CORRUPT_PATCH; + } + + /* Read lengths from header */ + bzctrllen=offtin(header+8); + bzdatalen=offtin(header+16); + newsize=offtin(header+24); + if((bzctrllen<0) || (bzdatalen<0) || (newsize<0)) + { + //errx(1,"Corrupt patch\n"); + return ERR_CORRUPT_PATCH; + } + + /* Close patch file and re-open it via libbzip2 at the right places */ + if (fclose(f)) + { + //err(1, "fclose(%s)", argv[3]); + return ERR_OTHER; + } + if ((cpf = fopen(patchfile, "rb")) == NULL) + { + //err(1, "fopen(%s)", argv[3]); + return ERR_OTHER; + } + if (fseek(cpf, 32, SEEK_SET)) + { + // err(1, "fseeko(%s, %lld)", argv[3], (long long)32); + return ERR_OTHER; + } + if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL) + { + //errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err); + return ERR_OTHER; + } + if ((dpf = fopen(patchfile, "rb")) == NULL) + { + //err(1, "fopen(%s)", argv[3]); + return ERR_OTHER; + } + if (fseek(dpf, 32 + bzctrllen, SEEK_SET)) + { + //err(1, "fseeko(%s, %lld)", argv[3], (long long)(32 + bzctrllen)); + return ERR_OTHER; + } + if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL) + { + //errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err); + return ERR_OTHER; + } + if ((epf = fopen(patchfile, "rb")) == NULL) + { + //err(1, "fopen(%s)", argv[3]); + return ERR_OTHER; + } + if (fseek(epf, 32 + bzctrllen + bzdatalen, SEEK_SET)) + { + //err(1, "fseeko(%s, %lld)", argv[3], (long long)(32 + bzctrllen + bzdatalen)); + return ERR_OTHER; + } + if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL) + { + //errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err); + return ERR_OTHER; + } + + if((temp=fopen(oldfile,"rb")) == NULL) + { + return ERR_OTHER; + } + if((fseek(temp,0,SEEK_END))!=0) + { + return ERR_OTHER; + } + oldsize = ftell(temp); + if((old_contents=malloc(oldsize+1))==NULL) + { + return ERR_OTHER; + } + rewind(temp); + if(fread(old_contents,oldsize,1,temp)!=1) + { + return ERR_OTHER; + } + if(fclose(temp)==EOF) + { + return ERR_OTHER; + } + if((new_contents=malloc(newsize+1))==NULL) + { + //err(1,NULL); + return ERR_OTHER; + } + + oldpos=0;newpos=0; + while(newposnewsize) + { + //errx(1,"Corrupt patch\n"); + return ERR_CORRUPT_PATCH; + } + + /* Read diff string */ + lenread = BZ2_bzRead(&dbz2err, dpfbz2, new_contents + newpos, ctrl[0]); + if ((lenread < ctrl[0]) || ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END))) + { + //errx(1, "Corrupt patch\n"); + return ERR_CORRUPT_PATCH; + } + + /* Add old data to diff string */ + for(i=0;i=0) && (oldpos+inewsize) + { + //errx(1,"Corrupt patch\n"); + return ERR_CORRUPT_PATCH; + } + + /* Read extra string */ + lenread = BZ2_bzRead(&ebz2err, epfbz2, new_contents + newpos, ctrl[1]); + if ((lenread < ctrl[1]) || ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END))) + { + //errx(1, "Corrupt patch\n"); + return ERR_CORRUPT_PATCH; + } + + /* Adjust pointers */ + newpos+=ctrl[1]; + oldpos+=ctrl[2]; + }; + + /* Clean up the bzip2 reads */ + BZ2_bzReadClose(&cbz2err, cpfbz2); + BZ2_bzReadClose(&dbz2err, dpfbz2); + BZ2_bzReadClose(&ebz2err, epfbz2); + if (fclose(cpf) || fclose(dpf) || fclose(epf)) + { + //err(1, "fclose(%s)", argv[3]); + return ERR_OTHER; + } + + /* Write the new file */ + if( + ((temp=fopen(newfile,"wb"))==NULL) || + (fwrite(new_contents,newsize,1,temp)==0) || + (fclose(temp)==EOF) + ) + { + //err(1,"%s",argv[2]); + return ERR_OTHER; + } + + free(new_contents); + free(old_contents); + + return ERR_NONE; +} diff --git a/depends/patchlib/bspatch.h b/depends/patchlib/bspatch.h new file mode 100644 index 00000000..efb83ee5 --- /dev/null +++ b/depends/patchlib/bspatch.h @@ -0,0 +1,27 @@ +#ifndef _BSPATCH_H +#define _BSPATCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum BSPatchError +{ + ERR_CORRUPT_PATCH, + ERR_OTHER, + ERR_NONE, +}; + +/** + * patch oldfile by using patchfile and write the output to newfile. + * + * Returns ERR_NONE if successful + */ +int bspatch(const char * oldfile, const char * newfile, const char * patchfile); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/depends/patchlib/bzlib.c b/depends/patchlib/bzlib.c new file mode 100644 index 00000000..e2994b44 --- /dev/null +++ b/depends/patchlib/bzlib.c @@ -0,0 +1,1579 @@ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). + fixed bzWrite/bzRead to ignore zero-length requests. + fixed bzread to correctly handle read requests after EOF. + wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. +*/ + +#ifdef _MSC_VER + //'function': was declared deprecated + #define _CRT_SECURE_NO_DEPRECATE + #define _SCL_SECURE_NO_DEPRECATE + #pragma warning( disable: 4996 ) +#endif + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +#ifndef BZ_NO_STDIO +void BZ2_bz__AssertH__fail ( int errcode ) +{ + fprintf(stderr, + "\n\nbzip2/libbzip2: internal error number %d.\n" + "This is a bug in bzip2/libbzip2, %s.\n" + "Please report it to me at: jseward@bzip.org. If this happened\n" + "when you were using some program which uses libbzip2 as a\n" + "component, you should also report this bug to the author(s)\n" + "of that program. Please make an effort to report this bug;\n" + "timely and accurate bug reports eventually lead to higher\n" + "quality software. Thanks. Julian Seward, 10 December 2007.\n\n", + errcode, + BZ2_bzlibVersion() + ); + + if (errcode == 1007) { + fprintf(stderr, + "\n*** A special note about internal error number 1007 ***\n" + "\n" + "Experience suggests that a common cause of i.e. 1007\n" + "is unreliable memory or other hardware. The 1007 assertion\n" + "just happens to cross-check the results of huge numbers of\n" + "memory reads/writes, and so acts (unintendedly) as a stress\n" + "test of your memory system.\n" + "\n" + "I suggest the following: try compressing the file again,\n" + "possibly monitoring progress in detail with the -vv flag.\n" + "\n" + "* If the error cannot be reproduced, and/or happens at different\n" + " points in compression, you may have a flaky memory system.\n" + " Try a memory-test program. I have used Memtest86\n" + " (www.memtest86.com). At the time of writing it is free (GPLd).\n" + " Memtest86 tests memory much more thorougly than your BIOSs\n" + " power-on test, and may find failures that the BIOS doesn't.\n" + "\n" + "* If the error can be repeatably reproduced, this is a bug in\n" + " bzip2, and I would very much like to hear about it. Please\n" + " let me know, and, ideally, save a copy of the file causing the\n" + " problem -- without which I will be unable to investigate it.\n" + "\n" + ); + } + + exit(3); +} +#endif + + +/*---------------------------------------------------*/ +static +int bz_config_ok ( void ) +{ + if (sizeof(int) != 4) return 0; + if (sizeof(short) != 2) return 0; + if (sizeof(char) != 1) return 0; + return 1; +} + + +/*---------------------------------------------------*/ +static +void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) +{ + void* v = malloc ( items * size ); + return v; +} + +static +void default_bzfree ( void* opaque, void* addr ) +{ + if (addr != NULL) free ( addr ); +} + + +/*---------------------------------------------------*/ +static +void prepare_new_block ( EState* s ) +{ + Int32 i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC ( s->blockCRC ); + for (i = 0; i < 256; i++) s->inUse[i] = False; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +void init_RL ( EState* s ) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +Bool isempty_RL ( EState* s ) +{ + if (s->state_in_ch < 256 && s->state_in_len > 0) + return False; else + return True; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressInit) + ( bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 n; + EState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL || + blockSize100k < 1 || blockSize100k > 9 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(EState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + + s->arr1 = NULL; + s->arr2 = NULL; + s->ftab = NULL; + + n = 100000 * blockSize100k; + s->arr1 = BZALLOC( n * sizeof(UInt32) ); + s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); + s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); + + if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + if (s != NULL) BZFREE(s); + return BZ_MEM_ERROR; + } + + s->blockNo = 0; + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->combinedCRC = 0; + s->blockSize100k = blockSize100k; + s->nblockMAX = 100000 * blockSize100k - 19; + s->verbosity = verbosity; + s->workFactor = workFactor; + + s->block = (UChar*)s->arr2; + s->mtfv = (UInt16*)s->arr1; + s->zbits = NULL; + s->ptr = (UInt32*)s->arr1; + + strm->state = s; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + init_RL ( s ); + prepare_new_block ( s ); + return BZ_OK; +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block ( EState* s ) +{ + Int32 i; + UChar ch = (UChar)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC( s->blockCRC, ch ); + } + s->inUse[s->state_in_ch] = True; + switch (s->state_in_len) { + case 1: + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 2: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 3: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len-4] = True; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = ((UChar)(s->state_in_len-4)); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL ( EState* s ) +{ + if (s->state_in_ch < 256) add_pair_to_block ( s ); + init_RL ( s ); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ +{ \ + UInt32 zchh = (UInt32)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && \ + zs->state_in_len == 1) { \ + UChar ch = (UChar)(zs->state_in_ch); \ + BZ_UPDATE_CRC( zs->blockCRC, ch ); \ + zs->inUse[zs->state_in_ch] = True; \ + zs->block[zs->nblock] = (UChar)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || \ + zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block ( zs ); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +Bool copy_input_until_stop ( EState* s ) +{ + Bool progress_in = False; + + if (s->mode == BZ_M_RUNNING) { + + /*-- fast track the common case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + } + + } else { + + /*-- general, uncommon case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- flush/finish end? --*/ + if (s->avail_in_expect == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + s->avail_in_expect--; + } + } + return progress_in; +} + + +/*---------------------------------------------------*/ +static +Bool copy_output_until_stop ( EState* s ) +{ + Bool progress_out = False; + + while (True) { + + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + progress_out = True; + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + return progress_out; +} + + +/*---------------------------------------------------*/ +static +Bool handle_compress ( bz_stream* strm ) +{ + Bool progress_in = False; + Bool progress_out = False; + EState* s = strm->state; + + while (True) { + + if (s->state == BZ_S_OUTPUT) { + progress_out |= copy_output_until_stop ( s ); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + prepare_new_block ( s ); + s->state = BZ_S_INPUT; + if (s->mode == BZ_M_FLUSHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + } + + if (s->state == BZ_S_INPUT) { + progress_in |= copy_input_until_stop ( s ); + if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + flush_RL ( s ); + BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); + s->state = BZ_S_OUTPUT; + } + else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock ( s, False ); + s->state = BZ_S_OUTPUT; + } + else + if (s->strm->avail_in == 0) { + break; + } + } + + } + + return progress_in || progress_out; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) +{ + Bool progress; + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + preswitch: + switch (s->mode) { + + case BZ_M_IDLE: + return BZ_SEQUENCE_ERROR; + + case BZ_M_RUNNING: + if (action == BZ_RUN) { + progress = handle_compress ( strm ); + return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; + } + else + if (action == BZ_FLUSH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto preswitch; + } + else + if (action == BZ_FINISH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto preswitch; + } + else + return BZ_PARAM_ERROR; + + case BZ_M_FLUSHING: + if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; + + case BZ_M_FINISHING: + if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (!progress) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FINISH_OK; + s->mode = BZ_M_IDLE; + return BZ_STREAM_END; + } + return BZ_OK; /*--not reached--*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) +{ + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + BZFREE(strm->state); + + strm->state = NULL; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/*--- Decompression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressInit) + ( bz_stream* strm, + int verbosity, + int small ) +{ + DState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL) return BZ_PARAM_ERROR; + if (small != 0 && small != 1) return BZ_PARAM_ERROR; + if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; + + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(DState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + strm->state = s; + s->state = BZ_X_MAGIC_1; + s->bsLive = 0; + s->bsBuff = 0; + s->calculatedCombinedCRC = 0; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + s->smallDecompress = (Bool)small; + s->ll4 = NULL; + s->ll16 = NULL; + s->tt = NULL; + s->currBlockNo = 0; + s->verbosity = verbosity; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_FAST ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + /* restore */ + UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; + UChar c_state_out_ch = s->state_out_ch; + Int32 c_state_out_len = s->state_out_len; + Int32 c_nblock_used = s->nblock_used; + Int32 c_k0 = s->k0; + UInt32* c_tt = s->tt; + UInt32 c_tPos = s->tPos; + char* cs_next_out = s->strm->next_out; + unsigned int cs_avail_out = s->strm->avail_out; + Int32 ro_blockSize100k = s->blockSize100k; + /* end restore */ + + UInt32 avail_out_INIT = cs_avail_out; + Int32 s_save_nblockPP = s->save_nblock+1; + unsigned int total_out_lo32_old; + + while (True) { + + /* try to finish existing run */ + if (c_state_out_len > 0) { + while (True) { + if (cs_avail_out == 0) goto return_notr; + if (c_state_out_len == 1) break; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + c_state_out_len--; + cs_next_out++; + cs_avail_out--; + } + s_state_out_len_eq_one: + { + if (cs_avail_out == 0) { + c_state_out_len = 1; goto return_notr; + }; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + cs_next_out++; + cs_avail_out--; + } + } + /* Only caused by corrupt data stream? */ + if (c_nblock_used > s_save_nblockPP) + return True; + + /* can a new run be started? */ + if (c_nblock_used == s_save_nblockPP) { + c_state_out_len = 0; goto return_notr; + }; + c_state_out_ch = c_k0; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (k1 != c_k0) { + c_k0 = k1; goto s_state_out_len_eq_one; + }; + if (c_nblock_used == s_save_nblockPP) + goto s_state_out_len_eq_one; + + c_state_out_len = 2; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + c_state_out_len = 3; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + BZ_GET_FAST_C(k1); c_nblock_used++; + c_state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST_C(c_k0); c_nblock_used++; + } + + return_notr: + total_out_lo32_old = s->strm->total_out_lo32; + s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); + if (s->strm->total_out_lo32 < total_out_lo32_old) + s->strm->total_out_hi32++; + + /* save */ + s->calculatedBlockCRC = c_calculatedBlockCRC; + s->state_out_ch = c_state_out_ch; + s->state_out_len = c_state_out_len; + s->nblock_used = c_nblock_used; + s->k0 = c_k0; + s->tt = c_tt; + s->tPos = c_tPos; + s->strm->next_out = cs_next_out; + s->strm->avail_out = cs_avail_out; + /* end save */ + } + return False; +} + + + +/*---------------------------------------------------*/ +__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_SMALL ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) +{ + Bool corrupt; + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + while (True) { + if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; + if (s->state == BZ_X_OUTPUT) { + if (s->smallDecompress) + corrupt = unRLE_obuf_to_output_SMALL ( s ); else + corrupt = unRLE_obuf_to_output_FAST ( s ); + if (corrupt) return BZ_DATA_ERROR; + if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { + BZ_FINALISE_CRC ( s->calculatedBlockCRC ); + if (s->verbosity >= 3) + VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, + s->calculatedBlockCRC ); + if (s->verbosity >= 2) VPrintf0 ( "]" ); + if (s->calculatedBlockCRC != s->storedBlockCRC) + return BZ_DATA_ERROR; + s->calculatedCombinedCRC + = (s->calculatedCombinedCRC << 1) | + (s->calculatedCombinedCRC >> 31); + s->calculatedCombinedCRC ^= s->calculatedBlockCRC; + s->state = BZ_X_BLKHDR_1; + } else { + return BZ_OK; + } + } + if (s->state >= BZ_X_MAGIC_1) { + Int32 r = BZ2_decompress ( s ); + if (r == BZ_STREAM_END) { + if (s->verbosity >= 3) + VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", + s->storedCombinedCRC, s->calculatedCombinedCRC ); + if (s->calculatedCombinedCRC != s->storedCombinedCRC) + return BZ_DATA_ERROR; + return r; + } + if (s->state != BZ_X_OUTPUT) return r; + } + } + + AssertH ( 0, 6001 ); + + return 0; /*NOTREACHED*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) +{ + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->tt != NULL) BZFREE(s->tt); + if (s->ll16 != NULL) BZFREE(s->ll16); + if (s->ll4 != NULL) BZFREE(s->ll4); + + BZFREE(strm->state); + strm->state = NULL; + + return BZ_OK; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ +/*--- File I/O stuff ---*/ +/*---------------------------------------------------*/ + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +typedef + struct { + FILE* handle; + Char buf[BZ_MAX_UNUSED]; + Int32 bufN; + Bool writing; + bz_stream strm; + Int32 lastErr; + Bool initialisedOk; + } + bzFile; + + +/*---------------------------------------------*/ +static Bool myfeof ( FILE* f ) +{ + Int32 c = fgetc ( f ); + if (c == EOF) return True; + ungetc ( c, f ); + return False; +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzWriteOpen) + ( int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 ret; + bzFile* bzf = NULL; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (blockSize100k < 1 || blockSize100k > 9) || + (workFactor < 0 || workFactor > 250) || + (verbosity < 0 || verbosity > 4)) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + bzf->initialisedOk = False; + bzf->bufN = 0; + bzf->handle = f; + bzf->writing = True; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + if (workFactor == 0) workFactor = 30; + ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = 0; + bzf->initialisedOk = True; + return bzf; +} + + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWrite) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return; }; + + bzf->strm.avail_in = len; + bzf->strm.next_in = buf; + + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); + if (ret != BZ_RUN_OK) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (bzf->strm.avail_in == 0) + { BZ_SETERR(BZ_OK); return; }; + } +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWriteClose) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ) +{ + BZ2_bzWriteClose64 ( bzerror, b, abandon, + nbytes_in, NULL, nbytes_out, NULL ); +} + + +void BZ_API(BZ2_bzWriteClose64) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; + if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; + if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; + if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; + + if ((!abandon) && bzf->lastErr == BZ_OK) { + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (ret == BZ_STREAM_END) break; + } + } + + if ( !abandon && !ferror ( bzf->handle ) ) { + fflush ( bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (nbytes_in_lo32 != NULL) + *nbytes_in_lo32 = bzf->strm.total_in_lo32; + if (nbytes_in_hi32 != NULL) + *nbytes_in_hi32 = bzf->strm.total_in_hi32; + if (nbytes_out_lo32 != NULL) + *nbytes_out_lo32 = bzf->strm.total_out_lo32; + if (nbytes_out_hi32 != NULL) + *nbytes_out_hi32 = bzf->strm.total_out_hi32; + + BZ_SETERR(BZ_OK); + BZ2_bzCompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzReadOpen) + ( int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused ) +{ + bzFile* bzf = NULL; + int ret; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (small != 0 && small != 1) || + (verbosity < 0 || verbosity > 4) || + (unused == NULL && nUnused != 0) || + (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + + bzf->initialisedOk = False; + bzf->handle = f; + bzf->bufN = 0; + bzf->writing = False; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + while (nUnused > 0) { + bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; + unused = ((void*)( 1 + ((UChar*)(unused)) )); + nUnused--; + } + + ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + + bzf->initialisedOk = True; + return bzf; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) +{ + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + + if (bzf->initialisedOk) + (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzRead) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return 0; }; + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (True) { + + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread ( bzf->buf, sizeof(UChar), + BZ_MAX_UNUSED, bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + + if (ret != BZ_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return 0; }; + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) + { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; + + if (ret == BZ_STREAM_END) + { BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; }; + if (bzf->strm.avail_out == 0) + { BZ_SETERR(BZ_OK); return len; }; + + } + + return 0; /*not reached*/ +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadGetUnused) + ( int* bzerror, + BZFILE* b, + void** unused, + int* nUnused ) +{ + bzFile* bzf = (bzFile*)b; + if (bzf == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (bzf->lastErr != BZ_STREAM_END) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (unused == NULL || nUnused == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + + BZ_SETERR(BZ_OK); + *nUnused = bzf->strm.avail_in; + *unused = bzf->strm.next_in; +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffCompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + blockSize100k < 1 || blockSize100k > 9 || + verbosity < 0 || verbosity > 4 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzCompressInit ( &strm, blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress ( &strm, BZ_FINISH ); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd ( &strm ); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffDecompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + (small != 0 && small != 1) || + verbosity < 0 || verbosity > 4) + return BZ_PARAM_ERROR; + + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzDecompress ( &strm ); + if (ret == BZ_OK) goto output_overflow_or_eof; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzDecompressEnd ( &strm ); + return BZ_OK; + + output_overflow_or_eof: + if (strm.avail_out > 0) { + BZ2_bzDecompressEnd ( &strm ); + return BZ_UNEXPECTED_EOF; + } else { + BZ2_bzDecompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + }; + + errhandler: + BZ2_bzDecompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +/*-- + return version like "0.9.5d, 4-Sept-1999". +--*/ +const char * BZ_API(BZ2_bzlibVersion)(void) +{ + return BZ_VERSION; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ + +#if defined(_WIN32) || defined(OS2) || defined(MSDOS) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif +static +BZFILE * bzopen_or_bzdopen + ( const char *path, /* no use when bzdopen */ + int fd, /* no use when bzdopen */ + const char *mode, + int open_mode) /* bzopen: 0, bzdopen:1 */ +{ + int bzerr; + char unused[BZ_MAX_UNUSED]; + int blockSize100k = 9; + int writing = 0; + char mode2[10] = ""; + FILE *fp = NULL; + BZFILE *bzfp = NULL; + int verbosity = 0; + int workFactor = 30; + int smallMode = 0; + int nUnused = 0; + + if (mode == NULL) return NULL; + while (*mode) { + switch (*mode) { + case 'r': + writing = 0; break; + case 'w': + writing = 1; break; + case 's': + smallMode = 1; break; + default: + if (isdigit((int)(*mode))) { + blockSize100k = *mode-BZ_HDR_0; + } + } + mode++; + } + strcat(mode2, writing ? "w" : "r" ); + strcat(mode2,"b"); /* binary mode */ + + if (open_mode==0) { + if (path==NULL || strcmp(path,"")==0) { + fp = (writing ? stdout : stdin); + SET_BINARY_MODE(fp); + } else { + fp = fopen(path,mode2); + } + } else { +#ifdef BZ_STRICT_ANSI + fp = NULL; +#else + fp = fdopen(fd,mode2); +#endif + } + if (fp == NULL) return NULL; + + if (writing) { + /* Guard against total chaos and anarchy -- JRS */ + if (blockSize100k < 1) blockSize100k = 1; + if (blockSize100k > 9) blockSize100k = 9; + bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, + verbosity,workFactor); + } else { + bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, + unused,nUnused); + } + if (bzfp == NULL) { + if (fp != stdin && fp != stdout) fclose(fp); + return NULL; + } + return bzfp; +} + + +/*---------------------------------------------------*/ +/*-- + open file for read or write. + ex) bzopen("file","w9") + case path="" or NULL => use stdin or stdout. +--*/ +BZFILE * BZ_API(BZ2_bzopen) + ( const char *path, + const char *mode ) +{ + return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); +} + + +/*---------------------------------------------------*/ +BZFILE * BZ_API(BZ2_bzdopen) + ( int fd, + const char *mode ) +{ + return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) +{ + int bzerr, nread; + if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; + nread = BZ2_bzRead(&bzerr,b,buf,len); + if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { + return nread; + } else { + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) +{ + int bzerr; + + BZ2_bzWrite(&bzerr,b,buf,len); + if(bzerr == BZ_OK){ + return len; + }else{ + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzflush) (BZFILE *b) +{ + /* do nothing now... */ + return 0; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzclose) (BZFILE* b) +{ + int bzerr; + FILE *fp; + + if (b==NULL) {return;} + fp = ((bzFile *)b)->handle; + if(((bzFile*)b)->writing){ + BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); + if(bzerr != BZ_OK){ + BZ2_bzWriteClose(NULL,b,1,NULL,NULL); + } + }else{ + BZ2_bzReadClose(&bzerr,b); + } + if(fp!=stdin && fp!=stdout){ + fclose(fp); + } +} + + +/*---------------------------------------------------*/ +/*-- + return last error code +--*/ +static const char *bzerrorstrings[] = { + "OK" + ,"SEQUENCE_ERROR" + ,"PARAM_ERROR" + ,"MEM_ERROR" + ,"DATA_ERROR" + ,"DATA_ERROR_MAGIC" + ,"IO_ERROR" + ,"UNEXPECTED_EOF" + ,"OUTBUFF_FULL" + ,"CONFIG_ERROR" + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ +}; + + +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) +{ + int err = ((bzFile *)b)->lastErr; + + if(err>0) err = 0; + *errnum = err; + return bzerrorstrings[err*-1]; +} +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/depends/patchlib/bzlib.h b/depends/patchlib/bzlib.h new file mode 100644 index 00000000..7676f23a --- /dev/null +++ b/depends/patchlib/bzlib.h @@ -0,0 +1,283 @@ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_H +#define _BZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef + struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; + } + bz_stream; + + +#ifndef BZ_IMPORT +#define BZ_EXPORT +#endif + +#ifndef BZ_NO_STDIO +/* Need a definitition for FILE */ +#include +#endif + +#ifdef _WIN32 +# include +# ifdef small + /* windows.h define small to char */ +# undef small +# endif +# ifdef BZ_EXPORT +# define BZ_API(func) WINAPI func +# define BZ_EXTERN extern +# else + /* import windows dll dynamically */ +# define BZ_API(func) (WINAPI * func) +# define BZ_EXTERN +# endif +#else +# define BZ_API(func) func +# define BZ_EXTERN extern +#endif + + +/*-- Core (low-level) library functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( + bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( + bz_stream* strm, + int action + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( + bz_stream *strm, + int verbosity, + int small + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( + bz_stream *strm + ); + + + +/*-- High(er) level library functions --*/ + +#ifndef BZ_NO_STDIO +#define BZ_MAX_UNUSED 5000 + +typedef void BZFILE; + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( + int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( + int* bzerror, + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( + int* bzerror, + BZFILE* b, + void** unused, + int* nUnused + ); + +BZ_EXTERN int BZ_API(BZ2_bzRead) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( + int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 + ); +#endif + + +/*-- Utility functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity + ); + + +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ + +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( + void + ); + +#ifndef BZ_NO_STDIO +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( + const char *path, + const char *mode + ); + +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( + int fd, + const char *mode + ); + +BZ_EXTERN int BZ_API(BZ2_bzread) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzwrite) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzflush) ( + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzclose) ( + BZFILE* b + ); + +BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( + BZFILE *b, + int *errnum + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ + diff --git a/depends/patchlib/bzlib_private.h b/depends/patchlib/bzlib_private.h new file mode 100644 index 00000000..b134e220 --- /dev/null +++ b/depends/patchlib/bzlib_private.h @@ -0,0 +1,510 @@ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_PRIVATE_H +#define _BZLIB_PRIVATE_H + +#include + +#ifndef BZ_NO_STDIO +#include +#include +#include +#endif + +#include "bzlib.h" + + + +/*-- General stuff. --*/ + +#define BZ_VERSION "1.0.6, 6-Sept-2010" + +typedef char Char; +typedef unsigned char Bool; +typedef unsigned char UChar; +typedef int Int32; +typedef unsigned int UInt32; +typedef short Int16; +typedef unsigned short UInt16; + +#define True ((Bool)1) +#define False ((Bool)0) + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef BZ_NO_STDIO + +extern void BZ2_bz__AssertH__fail ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } + +#if BZ_DEBUG +#define AssertD(cond,msg) \ + { if (!(cond)) { \ + fprintf ( stderr, \ + "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ + exit(1); \ + }} +#else +#define AssertD(cond,msg) /* */ +#endif + +#define VPrintf0(zf) \ + fprintf(stderr,zf) +#define VPrintf1(zf,za1) \ + fprintf(stderr,zf,za1) +#define VPrintf2(zf,za1,za2) \ + fprintf(stderr,zf,za1,za2) +#define VPrintf3(zf,za1,za2,za3) \ + fprintf(stderr,zf,za1,za2,za3) +#define VPrintf4(zf,za1,za2,za3,za4) \ + fprintf(stderr,zf,za1,za2,za3,za4) +#define VPrintf5(zf,za1,za2,za3,za4,za5) \ + fprintf(stderr,zf,za1,za2,za3,za4,za5) + +#else + +extern void bz_internal_error ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) bz_internal_error ( errcode ); } +#define AssertD(cond,msg) do { } while (0) +#define VPrintf0(zf) do { } while (0) +#define VPrintf1(zf,za1) do { } while (0) +#define VPrintf2(zf,za1,za2) do { } while (0) +#define VPrintf3(zf,za1,za2,za3) do { } while (0) +#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) +#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) + +#endif + + +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) +#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + + +/*-- Stuff for randomising repetitive blocks. --*/ + +extern Int32 BZ2_rNums[512]; + +#define BZ_RAND_DECLS \ + Int32 rNToGo; \ + Int32 rTPos \ + +#define BZ_RAND_INIT_MASK \ + s->rNToGo = 0; \ + s->rTPos = 0 \ + +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) + +#define BZ_RAND_UPD_MASK \ + if (s->rNToGo == 0) { \ + s->rNToGo = BZ2_rNums[s->rTPos]; \ + s->rTPos++; \ + if (s->rTPos == 512) s->rTPos = 0; \ + } \ + s->rNToGo--; + + + +/*-- Stuff for doing CRCs. --*/ + +extern UInt32 BZ2_crc32Table[256]; + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + BZ2_crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + Int32 mode; + Int32 state; + + /* remembers avail_in when flush/finish requested */ + UInt32 avail_in_expect; + + /* for doing the block sorting */ + UInt32* arr1; + UInt32* arr2; + UInt32* ftab; + Int32 origPtr; + + /* aliases for arr1 and arr2 */ + UInt32* ptr; + UChar* block; + UInt16* mtfv; + UChar* zbits; + + /* for deciding when to use the fallback sorting algorithm */ + Int32 workFactor; + + /* run-length-encoding of the input */ + UInt32 state_in_ch; + Int32 state_in_len; + BZ_RAND_DECLS; + + /* input and output limits and current posns */ + Int32 nblock; + Int32 nblockMAX; + Int32 numZ; + Int32 state_out_pos; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + UChar unseqToSeq[256]; + + /* the buffer for bit stream creation */ + UInt32 bsBuff; + Int32 bsLive; + + /* block and combined CRCs */ + UInt32 blockCRC; + UInt32 combinedCRC; + + /* misc administratium */ + Int32 verbosity; + Int32 blockNo; + Int32 blockSize100k; + + /* stuff for coding the MTF values */ + Int32 nMTF; + Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + /* second dimension: only 3 needed; 4 makes index calculations faster */ + UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; + + } + EState; + + + +/*-- externs for compression. --*/ + +extern void +BZ2_blockSort ( EState* ); + +extern void +BZ2_compressBlock ( EState*, Bool ); + +extern void +BZ2_bsInitWrite ( EState* ); + +extern void +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); + +extern void +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); + + + +/*-- states for decompression. --*/ + +#define BZ_X_IDLE 1 +#define BZ_X_OUTPUT 2 + +#define BZ_X_MAGIC_1 10 +#define BZ_X_MAGIC_2 11 +#define BZ_X_MAGIC_3 12 +#define BZ_X_MAGIC_4 13 +#define BZ_X_BLKHDR_1 14 +#define BZ_X_BLKHDR_2 15 +#define BZ_X_BLKHDR_3 16 +#define BZ_X_BLKHDR_4 17 +#define BZ_X_BLKHDR_5 18 +#define BZ_X_BLKHDR_6 19 +#define BZ_X_BCRC_1 20 +#define BZ_X_BCRC_2 21 +#define BZ_X_BCRC_3 22 +#define BZ_X_BCRC_4 23 +#define BZ_X_RANDBIT 24 +#define BZ_X_ORIGPTR_1 25 +#define BZ_X_ORIGPTR_2 26 +#define BZ_X_ORIGPTR_3 27 +#define BZ_X_MAPPING_1 28 +#define BZ_X_MAPPING_2 29 +#define BZ_X_SELECTOR_1 30 +#define BZ_X_SELECTOR_2 31 +#define BZ_X_SELECTOR_3 32 +#define BZ_X_CODING_1 33 +#define BZ_X_CODING_2 34 +#define BZ_X_CODING_3 35 +#define BZ_X_MTF_1 36 +#define BZ_X_MTF_2 37 +#define BZ_X_MTF_3 38 +#define BZ_X_MTF_4 39 +#define BZ_X_MTF_5 40 +#define BZ_X_MTF_6 41 +#define BZ_X_ENDHDR_2 42 +#define BZ_X_ENDHDR_3 43 +#define BZ_X_ENDHDR_4 44 +#define BZ_X_ENDHDR_5 45 +#define BZ_X_ENDHDR_6 46 +#define BZ_X_CCRC_1 47 +#define BZ_X_CCRC_2 48 +#define BZ_X_CCRC_3 49 +#define BZ_X_CCRC_4 50 + + + +/*-- Constants for the fast MTF decoder. --*/ + +#define MTFA_SIZE 4096 +#define MTFL_SIZE 16 + + + +/*-- Structure holding all the decompression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* state indicator for this stream */ + Int32 state; + + /* for doing the final run-length decoding */ + UChar state_out_ch; + Int32 state_out_len; + Bool blockRandomised; + BZ_RAND_DECLS; + + /* the buffer for bit stream reading */ + UInt32 bsBuff; + Int32 bsLive; + + /* misc administratium */ + Int32 blockSize100k; + Bool smallDecompress; + Int32 currBlockNo; + Int32 verbosity; + + /* for undoing the Burrows-Wheeler transform */ + Int32 origPtr; + UInt32 tPos; + Int32 k0; + Int32 unzftab[256]; + Int32 nblock_used; + Int32 cftab[257]; + Int32 cftabCopy[257]; + + /* for undoing the Burrows-Wheeler transform (FAST) */ + UInt32 *tt; + + /* for undoing the Burrows-Wheeler transform (SMALL) */ + UInt16 *ll16; + UChar *ll4; + + /* stored and calculated CRCs */ + UInt32 storedBlockCRC; + UInt32 storedCombinedCRC; + UInt32 calculatedBlockCRC; + UInt32 calculatedCombinedCRC; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + Bool inUse16[16]; + UChar seqToUnseq[256]; + + /* for decoding the MTF values */ + UChar mtfa [MTFA_SIZE]; + Int32 mtfbase[256 / MTFL_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 minLens[BZ_N_GROUPS]; + + /* save area for scalars in the main decompress code */ + Int32 save_i; + Int32 save_j; + Int32 save_t; + Int32 save_alphaSize; + Int32 save_nGroups; + Int32 save_nSelectors; + Int32 save_EOB; + Int32 save_groupNo; + Int32 save_groupPos; + Int32 save_nextSym; + Int32 save_nblockMAX; + Int32 save_nblock; + Int32 save_es; + Int32 save_N; + Int32 save_curr; + Int32 save_zt; + Int32 save_zn; + Int32 save_zvec; + Int32 save_zj; + Int32 save_gSel; + Int32 save_gMinlen; + Int32* save_gLimit; + Int32* save_gBase; + Int32* save_gPerm; + + } + DState; + + + +/*-- Macros for decompression. --*/ + +#define BZ_GET_FAST(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ + s->tPos = s->tt[s->tPos]; \ + cccc = (UChar)(s->tPos & 0xff); \ + s->tPos >>= 8; + +#define BZ_GET_FAST_C(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \ + c_tPos = c_tt[c_tPos]; \ + cccc = (UChar)(c_tPos & 0xff); \ + c_tPos >>= 8; + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + +#define GET_LL4(i) \ + ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) + +#define SET_LL(i,n) \ + { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + +#define GET_LL(i) \ + (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) + +#define BZ_GET_SMALL(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); + + +/*-- externs for decompression. --*/ + +extern Int32 +BZ2_indexIntoF ( Int32, Int32* ); + +extern Int32 +BZ2_decompress ( DState* ); + +extern void +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, + Int32, Int32, Int32 ); + + +#endif + + +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ + +#ifdef BZ_NO_STDIO +#ifndef NULL +#define NULL 0 +#endif +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + diff --git a/depends/patchlib/compress.c b/depends/patchlib/compress.c new file mode 100644 index 00000000..caf76960 --- /dev/null +++ b/depends/patchlib/compress.c @@ -0,0 +1,672 @@ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- changed setting of nGroups in sendMTFValues() + so as to do a bit better on small files +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +void BZ2_bsInitWrite ( EState* s ) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static +void bsFinishWrite ( EState* s ) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +#define bsNEEDW(nz) \ +{ \ + while (s->bsLive >= 8) { \ + s->zbits[s->numZ] \ + = (UChar)(s->bsBuff >> 24); \ + s->numZ++; \ + s->bsBuff <<= 8; \ + s->bsLive -= 8; \ + } \ +} + + +/*---------------------------------------------------*/ +static +__inline__ +void bsW ( EState* s, Int32 n, UInt32 v ) +{ + bsNEEDW ( n ); + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutUInt32 ( EState* s, UInt32 u ) +{ + bsW ( s, 8, (u >> 24) & 0xffL ); + bsW ( s, 8, (u >> 16) & 0xffL ); + bsW ( s, 8, (u >> 8) & 0xffL ); + bsW ( s, 8, u & 0xffL ); +} + + +/*---------------------------------------------------*/ +static +void bsPutUChar ( EState* s, UChar c ) +{ + bsW( s, 8, (UInt32)c ); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e ( EState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +static +void generateMTFValues ( EState* s ) +{ + UChar yy[256]; + Int32 i, j; + Int32 zPend; + Int32 wr; + Int32 EOB; + + /* + After sorting (eg, here), + s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, + and + ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] + holds the original block data. + + The first thing to do is generate the MTF values, + and put them in + ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. + Because there are strictly fewer or equal MTF values + than block values, ptr values in this area are overwritten + with MTF values only when they are no longer needed. + + The final compressed bitstream is generated into the + area starting at + (UChar*) (&((UChar*)s->arr2)[s->nblock]) + + These storage aliases are set up in bzCompressInit(), + except for the last one, which is arranged in + compressBlock(). + */ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt16* mtfv = s->mtfv; + + makeMaps_e ( s ); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; + + for (i = 0; i < s->nblock; i++) { + UChar ll_i; + AssertD ( wr <= i, "generateMTFValues(1)" ); + j = ptr[i]-1; if (j < 0) j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); + + if (yy[0] == ll_i) { + zPend++; + } else { + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + { + register UChar rtmp; + register UChar* ryy_j; + register UChar rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while ( rll_i != rtmp ) { + register UChar rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; + } + + } + } + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + + mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static +void sendMTFValues ( EState* s ) +{ + Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; + Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; + Int32 nGroups, nBytes; + + /*-- + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + is a global since the decoder also needs it. + + Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + are also globals only used in this proc. + Made global to keep stack frame size small. + --*/ + + + UInt16 cost[BZ_N_GROUPS]; + Int32 fave[BZ_N_GROUPS]; + + UInt16* mtfv = s->mtfv; + + if (s->verbosity >= 3) + VPrintf3( " %d in block, %d after MTF & 1-2 coding, " + "%d+2 syms in use\n", + s->nblock, s->nMTF, s->nInUse ); + + alphaSize = s->nInUse+2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH ( s->nMTF > 0, 3001 ); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + Int32 nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs-1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups-nPart) % 2 == 1)) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + if (s->verbosity >= 3) + VPrintf5( " initial group %d, [%d .. %d], " + "has %d syms (%4.1f%%)\n", + nPart, gs, ge, aFreq, + (100.0 * (float)aFreq) / (float)(s->nMTF) ); + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge+1; + remF -= aFreq; + } + } + + /*--- + Iterate up to BZ_N_ITERS times to improve the tables. + ---*/ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + + for (t = 0; t < nGroups; t++) fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + + /*--- + Set up an auxiliary length table which is used to fast-track + the common case (nGroups == 6). + ---*/ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (True) { + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + + /*-- + Calculate the cost of this group as coded + by each of the coding tables. + --*/ + for (t = 0; t < nGroups; t++) cost[t] = 0; + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register UInt32 cost01, cost23, cost45; + register UInt16 icv; + cost01 = cost23 = cost45 = 0; + +# define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; \ + + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); + +# undef BZ_ITER + + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + UInt16 icv = mtfv[i]; + for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; + } + } + + /*-- + Find the coding table which is best for this group, + and record its identity in the selector table. + --*/ + bc = 999999999; bt = -1; + for (t = 0; t < nGroups; t++) + if (cost[t] < bc) { bc = cost[t]; bt = t; }; + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /*-- + Increment the symbol frequencies for the selected table. + --*/ + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + +# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ + + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); + +# undef BZ_ITUR + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) + s->rfreq[bt][ mtfv[i] ]++; + } + + gs = ge+1; + } + if (s->verbosity >= 3) { + VPrintf2 ( " pass %d: size is %d, grp uses are ", + iter+1, totc/8 ); + for (t = 0; t < nGroups; t++) + VPrintf1 ( "%d ", fave[t] ); + VPrintf0 ( "\n" ); + } + + /*-- + Recompute the tables based on the accumulated frequencies. + --*/ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), + alphaSize, 17 /*20*/ ); + } + + + AssertH( nGroups < 8, 3002 ); + AssertH( nSelectors < 32768 && + nSelectors <= (2 + (900000 / BZ_G_SIZE)), + 3003 ); + + + /*--- Compute MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while ( ll_i != tmp ) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); + AssertH ( !(minLen < 1), 3005 ); + BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), + minLen, maxLen, alphaSize ); + } + + /*--- Transmit the mapping table. ---*/ + { + Bool inUse16[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = False; + for (j = 0; j < 16; j++) + if (s->inUse[i * 16 + j]) inUse16[i] = True; + } + + nBytes = s->numZ; + for (i = 0; i < 16; i++) + if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) { + if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); + } + + if (s->verbosity >= 3) + VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW ( s, 3, nGroups ); + bsW ( s, 15, nSelectors ); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); + bsW(s,1,0); + } + if (s->verbosity >= 3) + VPrintf1( "selectors %d, ", s->numZ-nBytes ); + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + Int32 curr = s->len[t][0]; + bsW ( s, 5, curr ); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; + bsW ( s, 1, 0 ); + } + } + + if (s->verbosity >= 3) + VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (True) { + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + AssertH ( s->selector[selCtr] < nGroups, 3006 ); + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + UInt16 mtfv_i; + UChar* s_len_sel_selCtr + = &(s->len[s->selector[selCtr]][0]); + Int32* s_code_sel_selCtr + = &(s->code[s->selector[selCtr]][0]); + +# define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW ( s, \ + s_len_sel_selCtr[mtfv_i], \ + s_code_sel_selCtr[mtfv_i] ) + + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); + +# undef BZ_ITAH + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + bsW ( s, + s->len [s->selector[selCtr]] [mtfv[i]], + s->code [s->selector[selCtr]] [mtfv[i]] ); + } + } + + + gs = ge+1; + selCtr++; + } + AssertH( selCtr == nSelectors, 3007 ); + + if (s->verbosity >= 3) + VPrintf1( "codes %d\n", s->numZ-nBytes ); +} + + +/*---------------------------------------------------*/ +void BZ2_compressBlock ( EState* s, Bool is_last_block ) +{ + if (s->nblock > 0) { + + BZ_FINALISE_CRC ( s->blockCRC ); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) s->numZ = 0; + + if (s->verbosity >= 2) + VPrintf4( " block %d: crc = 0x%08x, " + "combined CRC = 0x%08x, size = %d\n", + s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); + + BZ2_blockSort ( s ); + } + + s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite ( s ); + bsPutUChar ( s, BZ_HDR_B ); + bsPutUChar ( s, BZ_HDR_Z ); + bsPutUChar ( s, BZ_HDR_h ); + bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); + } + + if (s->nblock > 0) { + + bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); + bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); + bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutUInt32 ( s, s->blockCRC ); + + /*-- + Now a single bit indicating (non-)randomisation. + As of version 0.9.5, we use a better sorting algorithm + which makes randomisation unnecessary. So always set + the randomised bit to 'no'. Of course, the decoder + still needs to be able to handle randomised blocks + so as to maintain backwards compatibility with + older versions of bzip2. + --*/ + bsW(s,1,0); + + bsW ( s, 24, s->origPtr ); + generateMTFValues ( s ); + sendMTFValues ( s ); + } + + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + + bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); + bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); + bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); + bsPutUInt32 ( s, s->combinedCRC ); + if (s->verbosity >= 2) + VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); + bsFinishWrite ( s ); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/depends/patchlib/crctable.c b/depends/patchlib/crctable.c new file mode 100644 index 00000000..1fea7e94 --- /dev/null +++ b/depends/patchlib/crctable.c @@ -0,0 +1,104 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for doing CRCs ---*/ +/*--- crctable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +UInt32 BZ2_crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, + 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, + 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, + 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, + 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, + 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, + 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, + 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, + 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, + 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, + 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, + 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, + 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, + 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, + 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, + 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, + 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, + 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, + 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, + 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, + 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, + 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, + 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, + 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, + 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, + 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, + 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, + 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, + 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, + 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, + 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, + 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, + 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, + 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, + 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, + 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, + 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, + 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, + 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, + 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, + 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, + 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, + 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, + 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, + 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, + 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, + 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, + 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, + 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, + 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, + 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, + 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, + 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, + 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, + 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, + 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, + 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, + 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, + 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, + 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, + 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, + 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, + 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, + 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L +}; + + +/*-------------------------------------------------------------*/ +/*--- end crctable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/depends/patchlib/decompress.c b/depends/patchlib/decompress.c new file mode 100644 index 00000000..311f5668 --- /dev/null +++ b/depends/patchlib/decompress.c @@ -0,0 +1,646 @@ + +/*-------------------------------------------------------------*/ +/*--- Decompression machinery ---*/ +/*--- decompress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +static +void makeMaps_d ( DState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->seqToUnseq[s->nInUse] = i; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +#define RETURN(rrr) \ + { retVal = rrr; goto save_state_and_return; }; + +#define GET_BITS(lll,vvv,nnn) \ + case lll: s->state = lll; \ + while (True) { \ + if (s->bsLive >= nnn) { \ + UInt32 v; \ + v = (s->bsBuff >> \ + (s->bsLive-nnn)) & ((1 << nnn)-1); \ + s->bsLive -= nnn; \ + vvv = v; \ + break; \ + } \ + if (s->strm->avail_in == 0) RETURN(BZ_OK); \ + s->bsBuff \ + = (s->bsBuff << 8) | \ + ((UInt32) \ + (*((UChar*)(s->strm->next_in)))); \ + s->bsLive += 8; \ + s->strm->next_in++; \ + s->strm->avail_in--; \ + s->strm->total_in_lo32++; \ + if (s->strm->total_in_lo32 == 0) \ + s->strm->total_in_hi32++; \ + } + +#define GET_UCHAR(lll,uuu) \ + GET_BITS(lll,uuu,8) + +#define GET_BIT(lll,uuu) \ + GET_BITS(lll,uuu,1) + +/*---------------------------------------------------*/ +#define GET_MTF_VAL(label1,label2,lval) \ +{ \ + if (groupPos == 0) { \ + groupNo++; \ + if (groupNo >= nSelectors) \ + RETURN(BZ_DATA_ERROR); \ + groupPos = BZ_G_SIZE; \ + gSel = s->selector[groupNo]; \ + gMinlen = s->minLens[gSel]; \ + gLimit = &(s->limit[gSel][0]); \ + gPerm = &(s->perm[gSel][0]); \ + gBase = &(s->base[gSel][0]); \ + } \ + groupPos--; \ + zn = gMinlen; \ + GET_BITS(label1, zvec, zn); \ + while (1) { \ + if (zn > 20 /* the longest code */) \ + RETURN(BZ_DATA_ERROR); \ + if (zvec <= gLimit[zn]) break; \ + zn++; \ + GET_BIT(label2, zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + if (zvec - gBase[zn] < 0 \ + || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ + RETURN(BZ_DATA_ERROR); \ + lval = gPerm[zvec - gBase[zn]]; \ +} + + +/*---------------------------------------------------*/ +Int32 BZ2_decompress ( DState* s ) +{ + UChar uc; + Int32 retVal; + Int32 minLen, maxLen; + bz_stream* strm = s->strm; + + /* stuff that needs to be saved/restored */ + Int32 i; + Int32 j; + Int32 t; + Int32 alphaSize; + Int32 nGroups; + Int32 nSelectors; + Int32 EOB; + Int32 groupNo; + Int32 groupPos; + Int32 nextSym; + Int32 nblockMAX; + Int32 nblock; + Int32 es; + Int32 N; + Int32 curr; + Int32 zt; + Int32 zn; + Int32 zvec; + Int32 zj; + Int32 gSel; + Int32 gMinlen; + Int32* gLimit; + Int32* gBase; + Int32* gPerm; + + if (s->state == BZ_X_MAGIC_1) { + /*initialise the save area*/ + s->save_i = 0; + s->save_j = 0; + s->save_t = 0; + s->save_alphaSize = 0; + s->save_nGroups = 0; + s->save_nSelectors = 0; + s->save_EOB = 0; + s->save_groupNo = 0; + s->save_groupPos = 0; + s->save_nextSym = 0; + s->save_nblockMAX = 0; + s->save_nblock = 0; + s->save_es = 0; + s->save_N = 0; + s->save_curr = 0; + s->save_zt = 0; + s->save_zn = 0; + s->save_zvec = 0; + s->save_zj = 0; + s->save_gSel = 0; + s->save_gMinlen = 0; + s->save_gLimit = NULL; + s->save_gBase = NULL; + s->save_gPerm = NULL; + } + + /*restore from the save area*/ + i = s->save_i; + j = s->save_j; + t = s->save_t; + alphaSize = s->save_alphaSize; + nGroups = s->save_nGroups; + nSelectors = s->save_nSelectors; + EOB = s->save_EOB; + groupNo = s->save_groupNo; + groupPos = s->save_groupPos; + nextSym = s->save_nextSym; + nblockMAX = s->save_nblockMAX; + nblock = s->save_nblock; + es = s->save_es; + N = s->save_N; + curr = s->save_curr; + zt = s->save_zt; + zn = s->save_zn; + zvec = s->save_zvec; + zj = s->save_zj; + gSel = s->save_gSel; + gMinlen = s->save_gMinlen; + gLimit = s->save_gLimit; + gBase = s->save_gBase; + gPerm = s->save_gPerm; + + retVal = BZ_OK; + + switch (s->state) { + + GET_UCHAR(BZ_X_MAGIC_1, uc); + if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_2, uc); + if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_3, uc) + if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) + if (s->blockSize100k < (BZ_HDR_0 + 1) || + s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); + s->blockSize100k -= BZ_HDR_0; + + if (s->smallDecompress) { + s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); + s->ll4 = BZALLOC( + ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) + ); + if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); + } else { + s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); + if (s->tt == NULL) RETURN(BZ_MEM_ERROR); + } + + GET_UCHAR(BZ_X_BLKHDR_1, uc); + + if (uc == 0x17) goto endhdr_2; + if (uc != 0x31) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_2, uc); + if (uc != 0x41) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_3, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_4, uc); + if (uc != 0x26) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_5, uc); + if (uc != 0x53) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_6, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + + s->currBlockNo++; + if (s->verbosity >= 2) + VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); + + s->storedBlockCRC = 0; + GET_UCHAR(BZ_X_BCRC_1, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_2, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_3, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_4, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + + GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); + + s->origPtr = 0; + GET_UCHAR(BZ_X_ORIGPTR_1, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_2, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_3, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + + if (s->origPtr < 0) + RETURN(BZ_DATA_ERROR); + if (s->origPtr > 10 + 100000*s->blockSize100k) + RETURN(BZ_DATA_ERROR); + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) { + GET_BIT(BZ_X_MAPPING_1, uc); + if (uc == 1) + s->inUse16[i] = True; else + s->inUse16[i] = False; + } + + for (i = 0; i < 256; i++) s->inUse[i] = False; + + for (i = 0; i < 16; i++) + if (s->inUse16[i]) + for (j = 0; j < 16; j++) { + GET_BIT(BZ_X_MAPPING_2, uc); + if (uc == 1) s->inUse[i * 16 + j] = True; + } + makeMaps_d ( s ); + if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); + alphaSize = s->nInUse+2; + + /*--- Now the selectors ---*/ + GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); + if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); + GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); + if (nSelectors < 1) RETURN(BZ_DATA_ERROR); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (True) { + GET_BIT(BZ_X_SELECTOR_3, uc); + if (uc == 0) break; + j++; + if (j >= nGroups) RETURN(BZ_DATA_ERROR); + } + s->selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = s->selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + s->selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + GET_BITS(BZ_X_CODING_1, curr, 5); + for (i = 0; i < alphaSize; i++) { + while (True) { + if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); + GET_BIT(BZ_X_CODING_2, uc); + if (uc == 0) break; + GET_BIT(BZ_X_CODING_3, uc); + if (uc == 0) curr++; else curr--; + } + s->len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + BZ2_hbCreateDecodeTables ( + &(s->limit[t][0]), + &(s->base[t][0]), + &(s->perm[t][0]), + &(s->len[t][0]), + minLen, maxLen, alphaSize + ); + s->minLens[t] = minLen; + } + + /*--- Now the MTF values ---*/ + + EOB = s->nInUse+1; + nblockMAX = 100000 * s->blockSize100k; + groupNo = -1; + groupPos = 0; + + for (i = 0; i <= 255; i++) s->unzftab[i] = 0; + + /*-- MTF init --*/ + { + Int32 ii, jj, kk; + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + /*-- end MTF init --*/ + + nblock = 0; + GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { + + es = -1; + N = 1; + do { + /* Check that N doesn't get too big, so that es doesn't + go negative. The maximum value that can be + RUNA/RUNB encoded is equal to the block size (post + the initial RLE), viz, 900k, so bounding N at 2 + million should guard against overflow without + rejecting any legitimate inputs. */ + if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR); + if (nextSym == BZ_RUNA) es = es + (0+1) * N; else + if (nextSym == BZ_RUNB) es = es + (1+1) * N; + N = N * 2; + GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); + } + while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); + + es++; + uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; + s->unzftab[uc] += es; + + if (s->smallDecompress) + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->ll16[nblock] = (UInt16)uc; + nblock++; + es--; + } + else + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->tt[nblock] = (UInt32)uc; + nblock++; + es--; + }; + + continue; + + } else { + + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + + /*-- uc = MTF ( nextSym-1 ) --*/ + { + Int32 ii, jj, kk, pp, lno, off; + UInt32 nn; + nn = (UInt32)(nextSym - 1); + + if (nn < MTFL_SIZE) { + /* avoid general-case expense */ + pp = s->mtfbase[0]; + uc = s->mtfa[pp+nn]; + while (nn > 3) { + Int32 z = pp+nn; + s->mtfa[(z) ] = s->mtfa[(z)-1]; + s->mtfa[(z)-1] = s->mtfa[(z)-2]; + s->mtfa[(z)-2] = s->mtfa[(z)-3]; + s->mtfa[(z)-3] = s->mtfa[(z)-4]; + nn -= 4; + } + while (nn > 0) { + s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; + }; + s->mtfa[pp] = uc; + } else { + /* general case */ + lno = nn / MTFL_SIZE; + off = nn % MTFL_SIZE; + pp = s->mtfbase[lno] + off; + uc = s->mtfa[pp]; + while (pp > s->mtfbase[lno]) { + s->mtfa[pp] = s->mtfa[pp-1]; pp--; + }; + s->mtfbase[lno]++; + while (lno > 0) { + s->mtfbase[lno]--; + s->mtfa[s->mtfbase[lno]] + = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; + lno--; + } + s->mtfbase[0]--; + s->mtfa[s->mtfbase[0]] = uc; + if (s->mtfbase[0] == 0) { + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + } + } + /*-- end uc = MTF ( nextSym-1 ) --*/ + + s->unzftab[s->seqToUnseq[uc]]++; + if (s->smallDecompress) + s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else + s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); + nblock++; + + GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); + continue; + } + } + + /* Now we know what nblock is, we can do a better sanity + check on s->origPtr. + */ + if (s->origPtr < 0 || s->origPtr >= nblock) + RETURN(BZ_DATA_ERROR); + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + /* Check: unzftab entries in range. */ + for (i = 0; i <= 255; i++) { + if (s->unzftab[i] < 0 || s->unzftab[i] > nblock) + RETURN(BZ_DATA_ERROR); + } + /* Actually generate cftab. */ + s->cftab[0] = 0; + for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; + for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; + /* Check: cftab entries in range. */ + for (i = 0; i <= 256; i++) { + if (s->cftab[i] < 0 || s->cftab[i] > nblock) { + /* s->cftab[i] can legitimately be == nblock */ + RETURN(BZ_DATA_ERROR); + } + } + /* Check: cftab entries non-descending. */ + for (i = 1; i <= 256; i++) { + if (s->cftab[i-1] > s->cftab[i]) { + RETURN(BZ_DATA_ERROR); + } + } + + s->state_out_len = 0; + s->state_out_ch = 0; + BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); + s->state = BZ_X_OUTPUT; + if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); + + if (s->smallDecompress) { + + /*-- Make a copy of cftab, used in generation of T --*/ + for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->ll16[i]); + SET_LL(i, s->cftabCopy[uc]); + s->cftabCopy[uc]++; + } + + /*-- Compute T^(-1) by pointer reversal on T --*/ + i = s->origPtr; + j = GET_LL(i); + do { + Int32 tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != s->origPtr); + + s->tPos = s->origPtr; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_SMALL(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } else { + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->tt[i] & 0xff); + s->tt[s->cftab[uc]] |= (i << 8); + s->cftab[uc]++; + } + + s->tPos = s->tt[s->origPtr] >> 8; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_FAST(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_FAST(s->k0); s->nblock_used++; + } + + } + + RETURN(BZ_OK); + + + + endhdr_2: + + GET_UCHAR(BZ_X_ENDHDR_2, uc); + if (uc != 0x72) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_3, uc); + if (uc != 0x45) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_4, uc); + if (uc != 0x38) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_5, uc); + if (uc != 0x50) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_6, uc); + if (uc != 0x90) RETURN(BZ_DATA_ERROR); + + s->storedCombinedCRC = 0; + GET_UCHAR(BZ_X_CCRC_1, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_2, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_3, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_4, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + + s->state = BZ_X_IDLE; + RETURN(BZ_STREAM_END); + + default: AssertH ( False, 4001 ); + } + + AssertH ( False, 4002 ); + + save_state_and_return: + + s->save_i = i; + s->save_j = j; + s->save_t = t; + s->save_alphaSize = alphaSize; + s->save_nGroups = nGroups; + s->save_nSelectors = nSelectors; + s->save_EOB = EOB; + s->save_groupNo = groupNo; + s->save_groupPos = groupPos; + s->save_nextSym = nextSym; + s->save_nblockMAX = nblockMAX; + s->save_nblock = nblock; + s->save_es = es; + s->save_N = N; + s->save_curr = curr; + s->save_zt = zt; + s->save_zn = zn; + s->save_zvec = zvec; + s->save_zj = zj; + s->save_gSel = gSel; + s->save_gMinlen = gMinlen; + s->save_gLimit = gLimit; + s->save_gBase = gBase; + s->save_gPerm = gPerm; + + return retVal; +} + + +/*-------------------------------------------------------------*/ +/*--- end decompress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/depends/patchlib/huffman.c b/depends/patchlib/huffman.c new file mode 100644 index 00000000..2283fdbc --- /dev/null +++ b/depends/patchlib/huffman.c @@ -0,0 +1,205 @@ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + Int32 zz, tmp; \ + zz = z; tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + +#define DOWNHEAP(z) \ +{ \ + Int32 zz, yy, tmp; \ + zz = z; tmp = heap[zz]; \ + while (True) { \ + yy = zz << 1; \ + if (yy > nHeap) break; \ + if (yy < nHeap && \ + weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + + +/*---------------------------------------------------*/ +void BZ2_hbMakeCodeLengths ( UChar *len, + Int32 *freq, + Int32 alphaSize, + Int32 maxLen ) +{ + /*-- + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + --*/ + Int32 nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; + Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; + Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (True) { + + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { k = parent[k]; j++; } + len[i-1] = j; + if (j > maxLen) tooLong = True; + } + + if (! tooLong) break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbAssignCodes ( Int32 *code, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) + if (length[i] == n) { code[i] = vec; vec++; }; + vec <<= 1; + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/depends/patchlib/randtable.c b/depends/patchlib/randtable.c new file mode 100644 index 00000000..6d624599 --- /dev/null +++ b/depends/patchlib/randtable.c @@ -0,0 +1,84 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for randomising repetitive blocks ---*/ +/*--- randtable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------*/ +Int32 BZ2_rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +/*-------------------------------------------------------------*/ +/*--- end randtable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/depends/quazip/CMakeLists.txt b/depends/quazip/CMakeLists.txt new file mode 100644 index 00000000..b5a391e9 --- /dev/null +++ b/depends/quazip/CMakeLists.txt @@ -0,0 +1,28 @@ +project(quazip) + +# set all include directories for in and out of source builds +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${ZLIB_INCLUDE_DIRS} +) + +# include with QT_USE selected library parts +# INCLUDE(${QT_USE_FILE}) + +file(GLOB SRCS "*.c" "*.cpp") +file(GLOB PUBLIC_HEADERS "*.h") + +# Static link! +ADD_DEFINITIONS(-DQUAZIP_STATIC) + +#qt5_wrap_cpp(MOC_SRCS ${PUBLIC_HEADERS}) +#set(SRCS ${SRCS} ${MOC_SRCS}) + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +add_library(quazip STATIC ${SRCS}) +target_link_libraries(quazip ${ZLIB_LIBRARIES}) + +#install(FILES ${PUBLIC_HEADERS} DESTINATION include/quazip) +#install(TARGETS quazip LIBRARY DESTINATION ${LIB_DESTINATION} ARCHIVE DESTINATION ${LIB_DESTINATION} RUNTIME DESTINATION ${LIB_DESTINATION}) diff --git a/depends/quazip/JlCompress.cpp b/depends/quazip/JlCompress.cpp new file mode 100644 index 00000000..69832140 --- /dev/null +++ b/depends/quazip/JlCompress.cpp @@ -0,0 +1,516 @@ +#include "JlCompress.h" +#include + +static bool copyData(QIODevice &inFile, QIODevice &outFile) +{ + while (!inFile.atEnd()) { + char buf[4096]; + qint64 readLen = inFile.read(buf, 4096); + if (readLen <= 0) + return false; + if (outFile.write(buf, readLen) != readLen) + return false; + } + return true; +} + +/**OK + * Comprime il file fileName, nell'oggetto zip, con il nome fileDest. + * + * La funzione fallisce se: + * * zip==NULL; + * * l'oggetto zip e stato aperto in una modalita non compatibile con l'aggiunta di file; + * * non e possibile aprire il file d'origine; + * * non e possibile creare il file all'interno dell'oggetto zip; + * * si e rilevato un errore nella copia dei dati; + * * non e stato possibile chiudere il file all'interno dell'oggetto zip; + */ +bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) { + // zip: oggetto dove aggiungere il file + // fileName: nome del file reale + // fileDest: nome del file all'interno del file compresso + + // Controllo l'apertura dello zip + if (!zip) return false; + if (zip->getMode()!=QuaZip::mdCreate && + zip->getMode()!=QuaZip::mdAppend && + zip->getMode()!=QuaZip::mdAdd) return false; + + // Apro il file originale + QFile inFile; + inFile.setFileName(fileName); + if(!inFile.open(QIODevice::ReadOnly)) return false; + + // Apro il file risulato + QuaZipFile outFile(zip); + if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, inFile.fileName()))) return false; + + // Copio i dati + if (!copyData(inFile, outFile) || outFile.getZipError()!=UNZ_OK) { + return false; + } + + // Chiudo i file + outFile.close(); + if (outFile.getZipError()!=UNZ_OK) return false; + inFile.close(); + + return true; +} + +/**OK + * Comprime la cartella dir nel file fileCompressed, se recursive e true allora + * comprime anche le sotto cartelle. I nomi dei file preceduti dal path creato + * togliendo il pat della cartella origDir al path della cartella dir. + * Se la funzione fallisce restituisce false e cancella il file che si e tentato + * di creare. + * + * La funzione fallisce se: + * * zip==NULL; + * * l'oggetto zip e stato aperto in una modalita non compatibile con l'aggiunta di file; + * * la cartella dir non esiste; + * * la compressione di una sotto cartella fallisce (1); + * * la compressione di un file fallisce; + * (1) La funzione si richiama in maniera ricorsiva per comprimere le sotto cartelle + * dunque gli errori di compressione di una sotto cartella sono gli stessi di questa + * funzione. + */ +bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive) { + // zip: oggetto dove aggiungere il file + // dir: cartella reale corrente + // origDir: cartella reale originale + // (path(dir)-path(origDir)) = path interno all'oggetto zip + + // Controllo l'apertura dello zip + if (!zip) return false; + if (zip->getMode()!=QuaZip::mdCreate && + zip->getMode()!=QuaZip::mdAppend && + zip->getMode()!=QuaZip::mdAdd) return false; + + // Controllo la cartella + QDir directory(dir); + if (!directory.exists()) return false; + + // Se comprimo anche le sotto cartelle + if (recursive) { + // Per ogni sotto cartella + QFileInfoList files = directory.entryInfoList(QDir::AllDirs|QDir::NoDotAndDotDot); + Q_FOREACH (QFileInfo file, files) { + // Comprimo la sotto cartella + if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive)) return false; + } + } + + // Per ogni file nella cartella + QFileInfoList files = directory.entryInfoList(QDir::Files); + QDir origDirectory(origDir); + Q_FOREACH (QFileInfo file, files) { + // Se non e un file o e il file compresso che sto creando + if(!file.isFile()||file.absoluteFilePath()==zip->getZipName()) continue; + + // Creo il nome relativo da usare all'interno del file compresso + QString filename = origDirectory.relativeFilePath(file.absoluteFilePath()); + + // Comprimo il file + if (!compressFile(zip,file.absoluteFilePath(),filename)) return false; + } + + return true; +} + +/**OK + * Estrae il file fileName, contenuto nell'oggetto zip, con il nome fileDest. + * Se la funzione fallisce restituisce false e cancella il file che si e tentato di estrarre. + * + * La funzione fallisce se: + * * zip==NULL; + * * l'oggetto zip e stato aperto in una modalita non compatibile con l'estrazione di file; + * * non e possibile aprire il file all'interno dell'oggetto zip; + * * non e possibile creare il file estratto; + * * si e rilevato un errore nella copia dei dati (1); + * * non e stato possibile chiudere il file all'interno dell'oggetto zip (1); + * + * (1): prima di uscire dalla funzione cancella il file estratto. + */ +bool JlCompress::extractFile(QuaZip* zip, QString fileName, QString fileDest) { + // zip: oggetto dove aggiungere il file + // filename: nome del file reale + // fileincompress: nome del file all'interno del file compresso + + // Controllo l'apertura dello zip + if (!zip) return false; + if (zip->getMode()!=QuaZip::mdUnzip) return false; + + // Apro il file compresso + if (!fileName.isEmpty()) + zip->setCurrentFile(fileName); + QuaZipFile inFile(zip); + if(!inFile.open(QIODevice::ReadOnly) || inFile.getZipError()!=UNZ_OK) return false; + + // Controllo esistenza cartella file risultato + QDir curDir; + if (!curDir.mkpath(QFileInfo(fileDest).absolutePath())) { + return false; + } + + if (QFileInfo(fileDest).isDir()) + return true; + + // Apro il file risultato + QFile outFile; + outFile.setFileName(fileDest); + if(!outFile.open(QIODevice::WriteOnly)) return false; + + // Copio i dati + if (!copyData(inFile, outFile) || inFile.getZipError()!=UNZ_OK) { + outFile.close(); + removeFile(QStringList(fileDest)); + return false; + } + outFile.close(); + + // Chiudo i file + inFile.close(); + if (inFile.getZipError()!=UNZ_OK) { + removeFile(QStringList(fileDest)); + return false; + } + + return true; +} + +/** + * Rimuove i file il cui nome e specificato all'interno di listFile. + * Restituisce true se tutti i file sono stati cancellati correttamente, attenzione + * perche puo restituire false anche se alcuni file non esistevano e si e tentato + * di cancellarli. + */ +bool JlCompress::removeFile(QStringList listFile) { + bool ret = true; + // Per ogni file + for (int i=0; iopen(QuaZip::mdUnzip)) { + delete zip; + return QStringList(); + } + + // Estraggo i nomi dei file + QStringList lst; + QuaZipFileInfo info; + for(bool more=zip->goToFirstFile(); more; more=zip->goToNextFile()) { + if(!zip->getCurrentFileInfo(&info)) { + delete zip; + return QStringList(); + } + lst << info.name; + //info.name.toLocal8Bit().constData() + } + + // Chiudo il file zip + zip->close(); + if(zip->getZipError()!=0) { + delete zip; + return QStringList(); + } + delete zip; + + return lst; +} + diff --git a/depends/quazip/JlCompress.h b/depends/quazip/JlCompress.h new file mode 100644 index 00000000..29d6191f --- /dev/null +++ b/depends/quazip/JlCompress.h @@ -0,0 +1,123 @@ +#ifndef JLCOMPRESSFOLDER_H_ +#define JLCOMPRESSFOLDER_H_ + +#include "quazip.h" +#include "quazipfile.h" +#include "quazipfileinfo.h" +#include +#include +#include +#include + +/// Utility class for typical operations. +/** + This class contains a number of useful static functions to perform + simple operations, such as mass ZIP packing or extraction. + */ +class QUAZIP_EXPORT JlCompress { +private: + /// Compress a single file. + /** + \param zip Opened zip to compress the file to. + \param fileName The full path to the source file. + \param fileDest The full name of the file inside the archive. + \return true if success, false otherwise. + */ + static bool compressFile(QuaZip* zip, QString fileName, QString fileDest); + /// Compress a subdirectory. + /** + \param parentZip Opened zip containing the parent directory. + \param dir The full path to the directory to pack. + \param parentDir The full path to the directory corresponding to + the root of the ZIP. + \param recursive Whether to pack sub-directories as well or only + files. + \return true if success, false otherwise. + */ + static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive = true); + /// Extract a single file. + /** + \param zip The opened zip archive to extract from. + \param fileName The full name of the file to extract. + \param fileDest The full path to the destination file. + \return true if success, false otherwise. + */ + static bool extractFile(QuaZip* zip, QString fileName, QString fileDest); + /// Remove some files. + /** + \param listFile The list of files to remove. + \return true if success, false otherwise. + */ + static bool removeFile(QStringList listFile); + +public: + /// Compress a single file. + /** + \param fileCompressed The name of the archive. + \param file The file to compress. + \return true if success, false otherwise. + */ + static bool compressFile(QString fileCompressed, QString file); + /// Compress a list of files. + /** + \param fileCompressed The name of the archive. + \param files The file list to compress. + \return true if success, false otherwise. + */ + static bool compressFiles(QString fileCompressed, QStringList files); + /// Compress a whole directory. + /** + \param fileCompressed The name of the archive. + \param dir The directory to compress. + \param recursive Whether to pack the subdirectories as well, or + just regular files. + \return true if success, false otherwise. + */ + static bool compressDir(QString fileCompressed, QString dir = QString(), bool recursive = true); + +public: + /// Extract a single file. + /** + \param fileCompressed The name of the archive. + \param fileName The file to extract. + \param fileDest The destination file, assumed to be identical to + \a file if left empty. + \return The list of the full paths of the files extracted, empty on failure. + */ + static QString extractFile(QString fileCompressed, QString fileName, QString fileDest = QString()); + /// Extract a list of files. + /** + \param fileCompressed The name of the archive. + \param files The file list to extract. + \param dir The directory to put the files to, the current + directory if left empty. + \return The list of the full paths of the files extracted, empty on failure. + */ + static QStringList extractFiles(QString fileCompressed, QStringList files, QString dir = QString()); + /// Extract a whole archive. + /** + \param fileCompressed The name of the archive. + \param dir The directory to extract to, the current directory if + left empty. + \return The list of the full paths of the files extracted, empty on failure. + */ + static QStringList extractDir(QString fileCompressed, QString dir = QString()); + /// Extract a whole archive, with a list of exceptions (prefixes to ignore). + /** + \param fileCompressed The name of the archive. + \param dir The directory to extract to, the current directory if + left empty. + \param exceptions The list of exception prefixes + \return The list of the full paths of the files extracted, empty on failure. + */ + static QStringList extractWithExceptions(QString fileCompressed, QString dir, QStringList exceptions); + /// Get the file list. + /** + \return The list of the files in the archive, or, more precisely, the + list of the entries, including both files and directories if they + are present separately. + */ + static QStringList getFileList(QString fileCompressed); +}; + +#endif /* JLCOMPRESSFOLDER_H_ */ diff --git a/depends/quazip/crypt.h b/depends/quazip/crypt.h new file mode 100644 index 00000000..1d6da628 --- /dev/null +++ b/depends/quazip/crypt.h @@ -0,0 +1,135 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + 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. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#include "quazip_global.h" + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab UNUSED) +{ + //(void) pcrc_32_tab; /* avoid "unused parameter" warning */ + 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)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* 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 long* pkeys,const unsigned long* 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,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), 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(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) + const char *passwd; /* password string */ + unsigned char *buf; /* where to write header */ + int bufSize; + unsigned long* pkeys; + const unsigned long* pcrc_32_tab; + unsigned long 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> 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++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/depends/quazip/ioapi.h b/depends/quazip/ioapi.h new file mode 100644 index 00000000..f4c21809 --- /dev/null +++ b/depends/quazip/ioapi.h @@ -0,0 +1,77 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + Modified by Sergey A. Tachenov to integrate with Qt. +*/ + +#ifndef _ZLIBIOAPI_H +#define _ZLIBIOAPI_H + + +#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 (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) +#define ZCALLBACK CALLBACK +#else +#define ZCALLBACK +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, voidpf file, 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 uLong (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_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; + + + +void fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) +#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) +#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) +#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) +#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/depends/quazip/qioapi.cpp b/depends/quazip/qioapi.cpp new file mode 100644 index 00000000..f254c34d --- /dev/null +++ b/depends/quazip/qioapi.cpp @@ -0,0 +1,146 @@ +/* ioapi.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + Modified by Sergey A. Tachenov to integrate with Qt. +*/ + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" +#include "quazip_global.h" +#include + + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +voidpf ZCALLBACK qiodevice_open_file_func ( + voidpf opaque UNUSED, + voidpf file, + int mode) +{ + QIODevice *iodevice = reinterpret_cast(file); + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + iodevice->open(QIODevice::ReadOnly); + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + iodevice->open(QIODevice::ReadWrite); + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + iodevice->open(QIODevice::WriteOnly); + + if (iodevice->isOpen()) { + if (iodevice->isSequential()) { + iodevice->close(); + return NULL; + } else { + return iodevice; + } + } else + return NULL; +} + + +uLong ZCALLBACK qiodevice_read_file_func ( + voidpf opaque UNUSED, + voidpf stream, + void* buf, + uLong size) +{ + uLong ret; + ret = (uLong)((QIODevice*)stream)->read((char*)buf,size); + return ret; +} + + +uLong ZCALLBACK qiodevice_write_file_func ( + voidpf opaque UNUSED, + voidpf stream, + const void* buf, + uLong size) +{ + uLong ret; + ret = (uLong)((QIODevice*)stream)->write((char*)buf,size); + return ret; +} + +uLong ZCALLBACK qiodevice_tell_file_func ( + voidpf opaque UNUSED, + voidpf stream) +{ + uLong ret; + ret = ((QIODevice*)stream)->pos(); + return ret; +} + +int ZCALLBACK qiodevice_seek_file_func ( + voidpf opaque UNUSED, + voidpf stream, + uLong offset, + int origin) +{ + uLong qiodevice_seek_result=0; + int ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset; + break; + case ZLIB_FILEFUNC_SEEK_END : + qiodevice_seek_result = ((QIODevice*)stream)->size() - offset; + break; + case ZLIB_FILEFUNC_SEEK_SET : + qiodevice_seek_result = offset; + break; + default: return -1; + } + ret = !((QIODevice*)stream)->seek(qiodevice_seek_result); + return ret; +} + +int ZCALLBACK qiodevice_close_file_func ( + voidpf opaque UNUSED, + voidpf stream) +{ + ((QIODevice*)stream)->close(); + return 0; +} + +int ZCALLBACK qiodevice_error_file_func ( + voidpf opaque UNUSED, + voidpf stream) +{ + // can't check for error due to the QIODevice API limitation + return 0; +} + +void fill_qiodevice_filefunc ( + zlib_filefunc_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen_file = qiodevice_open_file_func; + pzlib_filefunc_def->zread_file = qiodevice_read_file_func; + pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func; + pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func; + pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func; + pzlib_filefunc_def->zclose_file = qiodevice_close_file_func; + pzlib_filefunc_def->zerror_file = qiodevice_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/depends/quazip/quaadler32.cpp b/depends/quazip/quaadler32.cpp new file mode 100644 index 00000000..097899f6 --- /dev/null +++ b/depends/quazip/quaadler32.cpp @@ -0,0 +1,28 @@ +#include "quaadler32.h" + +#include "zlib.h" + +QuaAdler32::QuaAdler32() +{ + reset(); +} + +quint32 QuaAdler32::calculate(const QByteArray &data) +{ + return adler32( adler32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() ); +} + +void QuaAdler32::reset() +{ + checksum = adler32(0L, Z_NULL, 0); +} + +void QuaAdler32::update(const QByteArray &buf) +{ + checksum = adler32( checksum, (const Bytef*)buf.data(), buf.size() ); +} + +quint32 QuaAdler32::value() +{ + return checksum; +} diff --git a/depends/quazip/quaadler32.h b/depends/quazip/quaadler32.h new file mode 100644 index 00000000..c5ac0532 --- /dev/null +++ b/depends/quazip/quaadler32.h @@ -0,0 +1,29 @@ +#ifndef QUAADLER32_H +#define QUAADLER32_H + +#include + +#include "quachecksum32.h" + +/// Adler32 checksum +/** \class QuaAdler32 quaadler32.h + * This class wrappers the adler32 function with the QuaChecksum32 interface. + * See QuaChecksum32 for more info. + */ +class QUAZIP_EXPORT QuaAdler32 : public QuaChecksum32 +{ + +public: + QuaAdler32(); + + quint32 calculate(const QByteArray &data); + + void reset(); + void update(const QByteArray &buf); + quint32 value(); + +private: + quint32 checksum; +}; + +#endif //QUAADLER32_H diff --git a/depends/quazip/quachecksum32.h b/depends/quazip/quachecksum32.h new file mode 100644 index 00000000..773ec2a4 --- /dev/null +++ b/depends/quazip/quachecksum32.h @@ -0,0 +1,54 @@ +#ifndef QUACHECKSUM32_H +#define QUACHECKSUM32_H + +#include +#include "quazip_global.h" + +/// Checksum interface. +/** \class QuaChecksum32 quachecksum32.h + * This is an interface for 32 bit checksums. + * Classes implementing this interface can calcunate a certin + * checksum in a single step: + * \code + * QChecksum32 *crc32 = new QuaCrc32(); + * rasoult = crc32->calculate(data); + * \endcode + * or by streaming the data: + * \code + * QChecksum32 *crc32 = new QuaCrc32(); + * while(!fileA.atEnd()) + * crc32->update(fileA.read(bufSize)); + * resoultA = crc32->value(); + * crc32->reset(); + * while(!fileB.atEnd()) + * crc32->update(fileB.read(bufSize)); + * resoultB = crc32->value(); + * \endcode + */ +class QUAZIP_EXPORT QuaChecksum32 +{ + +public: + ///Calculates the checksum for data. + /** \a data source data + * \return data checksum + * + * This function has no efect on the value returned by value(). + */ + virtual quint32 calculate(const QByteArray &data) = 0; + + ///Resets the calculation on a checksun for a stream. + virtual void reset() = 0; + + ///Updates the calculated checksum for the stream + /** \a buf next portion of data from the stream + */ + virtual void update(const QByteArray &buf) = 0; + + ///Value of the checksum calculated for the stream passed throw update(). + /** \return checksum + */ + virtual quint32 value() = 0; +}; + +#endif //QUACHECKSUM32_H diff --git a/depends/quazip/quacrc32.cpp b/depends/quazip/quacrc32.cpp new file mode 100644 index 00000000..9381f24c --- /dev/null +++ b/depends/quazip/quacrc32.cpp @@ -0,0 +1,28 @@ +#include "quacrc32.h" + +#include "zlib.h" + +QuaCrc32::QuaCrc32() +{ + reset(); +} + +quint32 QuaCrc32::calculate(const QByteArray &data) +{ + return crc32( crc32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() ); +} + +void QuaCrc32::reset() +{ + checksum = crc32(0L, Z_NULL, 0); +} + +void QuaCrc32::update(const QByteArray &buf) +{ + checksum = crc32( checksum, (const Bytef*)buf.data(), buf.size() ); +} + +quint32 QuaCrc32::value() +{ + return checksum; +} diff --git a/depends/quazip/quacrc32.h b/depends/quazip/quacrc32.h new file mode 100644 index 00000000..4c86d566 --- /dev/null +++ b/depends/quazip/quacrc32.h @@ -0,0 +1,26 @@ +#ifndef QUACRC32_H +#define QUACRC32_H + +#include "quachecksum32.h" + +///CRC32 checksum +/** \class QuaCrc32 quacrc32.h +* This class wrappers the crc32 function with the QuaChecksum32 interface. +* See QuaChecksum32 for more info. +*/ +class QUAZIP_EXPORT QuaCrc32 : public QuaChecksum32 { + +public: + QuaCrc32(); + + quint32 calculate(const QByteArray &data); + + void reset(); + void update(const QByteArray &buf); + quint32 value(); + +private: + quint32 checksum; +}; + +#endif //QUACRC32_H diff --git a/depends/quazip/quagzipfile.cpp b/depends/quazip/quagzipfile.cpp new file mode 100644 index 00000000..c1c70aad --- /dev/null +++ b/depends/quazip/quagzipfile.cpp @@ -0,0 +1,141 @@ +#include + +#include "quagzipfile.h" + +class QuaGzipFilePrivate { + friend class QuaGzipFile; + QString fileName; + gzFile gzd; + inline QuaGzipFilePrivate(): gzd(NULL) {} + inline QuaGzipFilePrivate(const QString &fileName): + fileName(fileName), gzd(NULL) {} + template bool open(FileId id, + QIODevice::OpenMode mode, QString &error); + gzFile open(int fd, const char *modeString); + gzFile open(const QString &name, const char *modeString); +}; + +gzFile QuaGzipFilePrivate::open(const QString &name, const char *modeString) +{ + return gzopen(QFile::encodeName(name).constData(), modeString); +} + +gzFile QuaGzipFilePrivate::open(int fd, const char *modeString) +{ + return gzdopen(fd, modeString); +} + +template +bool QuaGzipFilePrivate::open(FileId id, QIODevice::OpenMode mode, + QString &error) +{ + char modeString[2]; + modeString[0] = modeString[1] = '\0'; + if ((mode & QIODevice::ReadOnly) != 0 + && (mode & QIODevice::WriteOnly) != 0) { + error = QuaGzipFile::trUtf8("Opening gzip for both reading" + " and writing is not supported"); + return false; + } else if ((mode & QIODevice::ReadOnly) != 0) { + modeString[0] = 'r'; + } else if ((mode & QIODevice::WriteOnly) != 0) { + modeString[0] = 'w'; + } else { + error = QuaGzipFile::trUtf8("You can open a gzip either for reading" + " or for writing. Which is it?"); + return false; + } + gzd = open(id, modeString); + if (gzd == NULL) { + error = QuaGzipFile::trUtf8("Could not gzopen() file"); + return false; + } + return true; +} + +QuaGzipFile::QuaGzipFile(): +d(new QuaGzipFilePrivate()) +{ +} + +QuaGzipFile::QuaGzipFile(QObject *parent): +QIODevice(parent), +d(new QuaGzipFilePrivate()) +{ +} + +QuaGzipFile::QuaGzipFile(const QString &fileName, QObject *parent): + QIODevice(parent), +d(new QuaGzipFilePrivate(fileName)) +{ +} + +QuaGzipFile::~QuaGzipFile() +{ + if (isOpen()) { + close(); + } + delete d; +} + +void QuaGzipFile::setFileName(const QString& fileName) +{ + d->fileName = fileName; +} + +QString QuaGzipFile::getFileName() const +{ + return d->fileName; +} + +bool QuaGzipFile::isSequential() const +{ + return true; +} + +bool QuaGzipFile::open(QIODevice::OpenMode mode) +{ + QString error; + if (!d->open(d->fileName, mode, error)) { + setErrorString(error); + return false; + } + return QIODevice::open(mode); +} + +bool QuaGzipFile::open(int fd, QIODevice::OpenMode mode) +{ + QString error; + if (!d->open(fd, mode, error)) { + setErrorString(error); + return false; + } + return QIODevice::open(mode); +} + +bool QuaGzipFile::flush() +{ + return gzflush(d->gzd, Z_SYNC_FLUSH) == Z_OK; +} + +void QuaGzipFile::close() +{ + QIODevice::close(); + gzclose(d->gzd); +} + +qint64 QuaGzipFile::readData(char *data, qint64 maxSize) +{ + return gzread(d->gzd, (voidp)data, (unsigned)maxSize); +} + +qint64 QuaGzipFile::writeData(const char *data, qint64 maxSize) +{ + if (maxSize == 0) + return 0; + int written = gzwrite(d->gzd, (voidp)data, (unsigned)maxSize); + if (written == 0) + return -1; + else + return written; +} diff --git a/depends/quazip/quagzipfile.h b/depends/quazip/quagzipfile.h new file mode 100644 index 00000000..211ceadb --- /dev/null +++ b/depends/quazip/quagzipfile.h @@ -0,0 +1,35 @@ +#ifndef QUAZIP_QUAGZIPFILE_H +#define QUAZIP_QUAGZIPFILE_H + +#include +#include "quazip_global.h" + +#include + +class QuaGzipFilePrivate; + +class QUAZIP_EXPORT QuaGzipFile: public QIODevice { + Q_OBJECT +public: + QuaGzipFile(); + QuaGzipFile(QObject *parent); + QuaGzipFile(const QString &fileName, QObject *parent = NULL); + virtual ~QuaGzipFile(); + void setFileName(const QString& fileName); + QString getFileName() const; + virtual bool isSequential() const; + virtual bool open(QIODevice::OpenMode mode); + virtual bool open(int fd, QIODevice::OpenMode mode); + virtual bool flush(); + virtual void close(); +protected: + virtual qint64 readData(char *data, qint64 maxSize); + virtual qint64 writeData(const char *data, qint64 maxSize); +private: + // not implemented by design to disable copy + QuaGzipFile(const QuaGzipFile &that); + QuaGzipFile& operator=(const QuaGzipFile &that); + QuaGzipFilePrivate *d; +}; + +#endif // QUAZIP_QUAGZIPFILE_H diff --git a/depends/quazip/quaziodevice.cpp b/depends/quazip/quaziodevice.cpp new file mode 100644 index 00000000..959ca0e8 --- /dev/null +++ b/depends/quazip/quaziodevice.cpp @@ -0,0 +1,283 @@ +#include "quaziodevice.h" + +#define QUAZIO_INBUFSIZE 4096 +#define QUAZIO_OUTBUFSIZE 4096 + +class QuaZIODevicePrivate { + friend class QuaZIODevice; + QuaZIODevicePrivate(QIODevice *io); + ~QuaZIODevicePrivate(); + QIODevice *io; + z_stream zins; + z_stream zouts; + char *inBuf; + int inBufPos; + int inBufSize; + char *outBuf; + int outBufPos; + int outBufSize; + bool zBufError; + int doFlush(QString &error); +}; + +QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io): + io(io), + inBuf(NULL), + inBufPos(0), + inBufSize(0), + outBuf(NULL), + outBufPos(0), + outBufSize(0), + zBufError(false) +{ + zins.zalloc = (alloc_func) NULL; + zins.zfree = (free_func) NULL; + zins.opaque = NULL; + zouts.zalloc = (alloc_func) NULL; + zouts.zfree = (free_func) NULL; + zouts.opaque = NULL; + inBuf = new char[QUAZIO_INBUFSIZE]; + outBuf = new char[QUAZIO_OUTBUFSIZE]; +#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT + debug.setFileName("debug.out"); + debug.open(QIODevice::WriteOnly); +#endif +#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT + indebug.setFileName("debug.in"); + indebug.open(QIODevice::WriteOnly); +#endif +} + +QuaZIODevicePrivate::~QuaZIODevicePrivate() +{ +#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT + debug.close(); +#endif +#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT + indebug.close(); +#endif + if (inBuf != NULL) + delete[] inBuf; + if (outBuf != NULL) + delete[] outBuf; +} + +int QuaZIODevicePrivate::doFlush(QString &error) +{ + int flushed = 0; + while (outBufPos < outBufSize) { + int more = io->write(outBuf + outBufPos, outBufSize - outBufPos); + if (more == -1) { + error = io->errorString(); + return -1; + } + if (more == 0) + break; + outBufPos += more; + flushed += more; + } + if (outBufPos == outBufSize) { + outBufPos = outBufSize = 0; + } + return flushed; +} + +// #define QUAZIP_ZIODEVICE_DEBUG_OUTPUT +// #define QUAZIP_ZIODEVICE_DEBUG_INPUT +#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT +#include +static QFile debug; +#endif +#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT +#include +static QFile indebug; +#endif + +QuaZIODevice::QuaZIODevice(QIODevice *io, QObject *parent): + QIODevice(parent), + d(new QuaZIODevicePrivate(io)) +{ + connect(io, SIGNAL(readyRead()), SIGNAL(readyRead())); +} + +QuaZIODevice::~QuaZIODevice() +{ + if (isOpen()) + close(); + delete d; +} + +QIODevice *QuaZIODevice::getIoDevice() const +{ + return d->io; +} + +bool QuaZIODevice::open(QIODevice::OpenMode mode) +{ + if ((mode & QIODevice::ReadOnly) != 0) { + if (inflateInit(&d->zins) != Z_OK) { + setErrorString(d->zins.msg); + return false; + } + } + if ((mode & QIODevice::WriteOnly) != 0) { + if (deflateInit(&d->zouts, Z_DEFAULT_COMPRESSION) != Z_OK) { + setErrorString(d->zouts.msg); + return false; + } + } + return QIODevice::open(mode); +} + +void QuaZIODevice::close() +{ + if ((openMode() & QIODevice::ReadOnly) != 0) { + if (inflateEnd(&d->zins) != Z_OK) { + setErrorString(d->zins.msg); + } + } + if ((openMode() & QIODevice::WriteOnly) != 0) { + flush(); + if (deflateEnd(&d->zouts) != Z_OK) { + setErrorString(d->zouts.msg); + } + } + QIODevice::close(); +} + +qint64 QuaZIODevice::readData(char *data, qint64 maxSize) +{ + int read = 0; + while (read < maxSize) { + if (d->inBufPos == d->inBufSize) { + d->inBufPos = 0; + d->inBufSize = d->io->read(d->inBuf, QUAZIO_INBUFSIZE); + if (d->inBufSize == -1) { + d->inBufSize = 0; + setErrorString(d->io->errorString()); + return -1; + } + if (d->inBufSize == 0) + break; + } + while (read < maxSize && d->inBufPos < d->inBufSize) { + d->zins.next_in = (Bytef *) (d->inBuf + d->inBufPos); + d->zins.avail_in = d->inBufSize - d->inBufPos; + d->zins.next_out = (Bytef *) (data + read); + d->zins.avail_out = (uInt) (maxSize - read); // hope it's less than 2GB + int more = 0; + switch (inflate(&d->zins, Z_SYNC_FLUSH)) { + case Z_OK: + read = (char *) d->zins.next_out - data; + d->inBufPos = (char *) d->zins.next_in - d->inBuf; + break; + case Z_STREAM_END: + read = (char *) d->zins.next_out - data; + d->inBufPos = (char *) d->zins.next_in - d->inBuf; + return read; + case Z_BUF_ERROR: // this should never happen, but just in case + if (!d->zBufError) { + qWarning("Z_BUF_ERROR detected with %d/%d in/out, weird", + d->zins.avail_in, d->zins.avail_out); + d->zBufError = true; + } + memmove(d->inBuf, d->inBuf + d->inBufPos, d->inBufSize - d->inBufPos); + d->inBufSize -= d->inBufPos; + d->inBufPos = 0; + more = d->io->read(d->inBuf + d->inBufSize, QUAZIO_INBUFSIZE - d->inBufSize); + if (more == -1) { + setErrorString(d->io->errorString()); + return -1; + } + if (more == 0) + return read; + d->inBufSize += more; + break; + default: + setErrorString(QString::fromLocal8Bit(d->zins.msg)); + return -1; + } + } + } +#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT + indebug.write(data, read); +#endif + return read; +} + +qint64 QuaZIODevice::writeData(const char *data, qint64 maxSize) +{ + int written = 0; + QString error; + if (d->doFlush(error) == -1) { + setErrorString(error); + return -1; + } + while (written < maxSize) { + // there is some data waiting in the output buffer + if (d->outBufPos < d->outBufSize) + return written; + d->zouts.next_in = (Bytef *) (data + written); + d->zouts.avail_in = (uInt) (maxSize - written); // hope it's less than 2GB + d->zouts.next_out = (Bytef *) d->outBuf; + d->zouts.avail_out = QUAZIO_OUTBUFSIZE; + switch (deflate(&d->zouts, Z_NO_FLUSH)) { + case Z_OK: + written = (char *) d->zouts.next_in - data; + d->outBufSize = (char *) d->zouts.next_out - d->outBuf; + break; + default: + setErrorString(QString::fromLocal8Bit(d->zouts.msg)); + return -1; + } + if (d->doFlush(error) == -1) { + setErrorString(error); + return -1; + } + } +#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT + debug.write(data, written); +#endif + return written; +} + +bool QuaZIODevice::flush() +{ + QString error; + if (d->doFlush(error) < 0) { + setErrorString(error); + return false; + } + // can't flush buffer, some data is still waiting + if (d->outBufPos < d->outBufSize) + return true; + Bytef c = 0; + d->zouts.next_in = &c; // fake input buffer + d->zouts.avail_in = 0; // of zero size + do { + d->zouts.next_out = (Bytef *) d->outBuf; + d->zouts.avail_out = QUAZIO_OUTBUFSIZE; + switch (deflate(&d->zouts, Z_SYNC_FLUSH)) { + case Z_OK: + d->outBufSize = (char *) d->zouts.next_out - d->outBuf; + if (d->doFlush(error) < 0) { + setErrorString(error); + return false; + } + if (d->outBufPos < d->outBufSize) + return true; + break; + case Z_BUF_ERROR: // nothing to write? + return true; + default: + setErrorString(QString::fromLocal8Bit(d->zouts.msg)); + return false; + } + } while (d->zouts.avail_out == 0); + return true; +} + +bool QuaZIODevice::isSequential() const +{ + return true; +} diff --git a/depends/quazip/quaziodevice.h b/depends/quazip/quaziodevice.h new file mode 100644 index 00000000..b061cd16 --- /dev/null +++ b/depends/quazip/quaziodevice.h @@ -0,0 +1,27 @@ +#ifndef QUAZIP_QUAZIODEVICE_H +#define QUAZIP_QUAZIODEVICE_H + +#include +#include "quazip_global.h" + +#include + +class QuaZIODevicePrivate; + +class QUAZIP_EXPORT QuaZIODevice: public QIODevice { + Q_OBJECT +public: + QuaZIODevice(QIODevice *io, QObject *parent = NULL); + ~QuaZIODevice(); + virtual bool flush(); + virtual bool open(QIODevice::OpenMode); + virtual void close(); + QIODevice *getIoDevice() const; + virtual bool isSequential() const; +protected: + virtual qint64 readData(char *data, qint64 maxSize); + virtual qint64 writeData(const char *data, qint64 maxSize); +private: + QuaZIODevicePrivate *d; +}; +#endif // QUAZIP_QUAZIODEVICE_H diff --git a/depends/quazip/quazip.cpp b/depends/quazip/quazip.cpp new file mode 100644 index 00000000..b6fa92f0 --- /dev/null +++ b/depends/quazip/quazip.cpp @@ -0,0 +1,554 @@ +/* +Copyright (C) 2005-2011 Sergey A. Tachenov + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser 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 Lesser +General Public License for more details. + +You should have received a copy of the GNU Lesser 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 + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant, see +quazip/(un)zip.h files for details, basically it's zlib license. + **/ + +#include +#include + +#include "quazip.h" + +/// All the internal stuff for the QuaZip class. +/** + \internal + + This class keeps all the private stuff for the QuaZip class so it can + be changed without breaking binary compatibility, according to the + Pimpl idiom. + */ +class QuaZipPrivate { + friend class QuaZip; + private: + /// The pointer to the corresponding QuaZip instance. + QuaZip *q; + /// The codec for file names. + QTextCodec *fileNameCodec; + /// The codec for comments. + QTextCodec *commentCodec; + /// The archive file name. + QString zipName; + /// The device to access the archive. + QIODevice *ioDevice; + /// The global comment. + QString comment; + /// The open mode. + QuaZip::Mode mode; + union { + /// The internal handle for UNZIP modes. + unzFile unzFile_f; + /// The internal handle for ZIP modes. + zipFile zipFile_f; + }; + /// Whether a current file is set. + bool hasCurrentFile_f; + /// The last error. + int zipError; + /// Whether \ref QuaZip::setDataDescriptorWritingEnabled() "the data descriptor writing mode" is enabled. + bool dataDescriptorWritingEnabled; + /// The constructor for the corresponding QuaZip constructor. + inline QuaZipPrivate(QuaZip *q): + q(q), + fileNameCodec(QTextCodec::codecForLocale()), + commentCodec(QTextCodec::codecForLocale()), + ioDevice(NULL), + mode(QuaZip::mdNotOpen), + hasCurrentFile_f(false), + zipError(UNZ_OK), + dataDescriptorWritingEnabled(true) {} + /// The constructor for the corresponding QuaZip constructor. + inline QuaZipPrivate(QuaZip *q, const QString &zipName): + q(q), + fileNameCodec(QTextCodec::codecForLocale()), + commentCodec(QTextCodec::codecForLocale()), + zipName(zipName), + ioDevice(NULL), + mode(QuaZip::mdNotOpen), + hasCurrentFile_f(false), + zipError(UNZ_OK), + dataDescriptorWritingEnabled(true) {} + /// The constructor for the corresponding QuaZip constructor. + inline QuaZipPrivate(QuaZip *q, QIODevice *ioDevice): + q(q), + fileNameCodec(QTextCodec::codecForLocale()), + commentCodec(QTextCodec::codecForLocale()), + ioDevice(ioDevice), + mode(QuaZip::mdNotOpen), + hasCurrentFile_f(false), + zipError(UNZ_OK), + dataDescriptorWritingEnabled(true) {} + /// Returns either a list of file names or a list of QuaZipFileInfo. + template + bool getFileInfoList(QList *result) const; +}; + +QuaZip::QuaZip(): + p(new QuaZipPrivate(this)) +{ +} + +QuaZip::QuaZip(const QString& zipName): + p(new QuaZipPrivate(this, zipName)) +{ +} + +QuaZip::QuaZip(QIODevice *ioDevice): + p(new QuaZipPrivate(this, ioDevice)) +{ +} + +QuaZip::~QuaZip() +{ + if(isOpen()) + close(); + delete p; +} + +bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi) +{ + p->zipError=UNZ_OK; + if(isOpen()) { + qWarning("QuaZip::open(): ZIP already opened"); + return false; + } + QIODevice *ioDevice = p->ioDevice; + if (ioDevice == NULL) { + if (p->zipName.isEmpty()) { + qWarning("QuaZip::open(): set either ZIP file name or IO device first"); + return false; + } else { + ioDevice = new QFile(p->zipName); + } + } + switch(mode) { + case mdUnzip: + p->unzFile_f=unzOpen2(ioDevice, ioApi); + if(p->unzFile_f!=NULL) { + p->mode=mode; + p->ioDevice = ioDevice; + return true; + } else { + p->zipError=UNZ_OPENERROR; + if (!p->zipName.isEmpty()) + delete ioDevice; + return false; + } + case mdCreate: + case mdAppend: + case mdAdd: + p->zipFile_f=zipOpen2(ioDevice, + mode==mdCreate?APPEND_STATUS_CREATE: + mode==mdAppend?APPEND_STATUS_CREATEAFTER: + APPEND_STATUS_ADDINZIP, + NULL, + ioApi); + if(p->zipFile_f!=NULL) { + p->mode=mode; + p->ioDevice = ioDevice; + return true; + } else { + p->zipError=UNZ_OPENERROR; + if (!p->zipName.isEmpty()) + delete ioDevice; + return false; + } + default: + qWarning("QuaZip::open(): unknown mode: %d", (int)mode); + if (!p->zipName.isEmpty()) + delete ioDevice; + return false; + break; + } +} + +void QuaZip::close() +{ + p->zipError=UNZ_OK; + switch(p->mode) { + case mdNotOpen: + qWarning("QuaZip::close(): ZIP is not open"); + return; + case mdUnzip: + p->zipError=unzClose(p->unzFile_f); + break; + case mdCreate: + case mdAppend: + case mdAdd: + p->zipError=zipClose(p->zipFile_f, + p->comment.isNull() ? NULL + : p->commentCodec->fromUnicode(p->comment).constData()); + break; + default: + qWarning("QuaZip::close(): unknown mode: %d", (int)p->mode); + return; + } + // opened by name, need to delete the internal IO device + if (!p->zipName.isEmpty()) { + delete p->ioDevice; + p->ioDevice = NULL; + } + if(p->zipError==UNZ_OK) + p->mode=mdNotOpen; +} + +void QuaZip::setZipName(const QString& zipName) +{ + if(isOpen()) { + qWarning("QuaZip::setZipName(): ZIP is already open!"); + return; + } + p->zipName=zipName; + p->ioDevice = NULL; +} + +void QuaZip::setIoDevice(QIODevice *ioDevice) +{ + if(isOpen()) { + qWarning("QuaZip::setIoDevice(): ZIP is already open!"); + return; + } + p->ioDevice = ioDevice; + p->zipName = QString(); +} + +int QuaZip::getEntriesCount()const +{ + QuaZip *fakeThis=(QuaZip*)this; // non-const + fakeThis->p->zipError=UNZ_OK; + if(p->mode!=mdUnzip) { + qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode"); + return -1; + } + unz_global_info globalInfo; + if((fakeThis->p->zipError=unzGetGlobalInfo(p->unzFile_f, &globalInfo))!=UNZ_OK) + return p->zipError; + return (int)globalInfo.number_entry; +} + +QString QuaZip::getComment()const +{ + QuaZip *fakeThis=(QuaZip*)this; // non-const + fakeThis->p->zipError=UNZ_OK; + if(p->mode!=mdUnzip) { + qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode"); + return QString(); + } + unz_global_info globalInfo; + QByteArray comment; + if((fakeThis->p->zipError=unzGetGlobalInfo(p->unzFile_f, &globalInfo))!=UNZ_OK) + return QString(); + comment.resize(globalInfo.size_comment); + if((fakeThis->p->zipError=unzGetGlobalComment(p->unzFile_f, comment.data(), comment.size())) < 0) + return QString(); + fakeThis->p->zipError = UNZ_OK; + return p->commentCodec->toUnicode(comment); +} + +bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs) +{ + p->zipError=UNZ_OK; + if(p->mode!=mdUnzip) { + qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode"); + return false; + } + if(fileName.isEmpty()) { + p->hasCurrentFile_f=false; + return true; + } + // Unicode-aware reimplementation of the unzLocateFile function + if(p->unzFile_f==NULL) { + p->zipError=UNZ_PARAMERROR; + return false; + } + if(fileName.length()>MAX_FILE_NAME_LENGTH) { + p->zipError=UNZ_PARAMERROR; + return false; + } + bool sens = convertCaseSensitivity(cs) == Qt::CaseSensitive; + QString lower, current; + if(!sens) lower=fileName.toLower(); + p->hasCurrentFile_f=false; + for(bool more=goToFirstFile(); more; more=goToNextFile()) { + current=getCurrentFileName(); + if(current.isEmpty()) return false; + if(sens) { + if(current==fileName) break; + } else { + if(current.toLower()==lower) break; + } + } + return p->hasCurrentFile_f; +} + +bool QuaZip::goToFirstFile() +{ + p->zipError=UNZ_OK; + if(p->mode!=mdUnzip) { + qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); + return false; + } + p->zipError=unzGoToFirstFile(p->unzFile_f); + p->hasCurrentFile_f=p->zipError==UNZ_OK; + return p->hasCurrentFile_f; +} + +bool QuaZip::goToNextFile() +{ + p->zipError=UNZ_OK; + if(p->mode!=mdUnzip) { + qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); + return false; + } + p->zipError=unzGoToNextFile(p->unzFile_f); + p->hasCurrentFile_f=p->zipError==UNZ_OK; + if(p->zipError==UNZ_END_OF_LIST_OF_FILE) + p->zipError=UNZ_OK; + return p->hasCurrentFile_f; +} + +bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const +{ + QuaZip *fakeThis=(QuaZip*)this; // non-const + fakeThis->p->zipError=UNZ_OK; + if(p->mode!=mdUnzip) { + qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode"); + return false; + } + unz_file_info info_z; + QByteArray fileName; + QByteArray extra; + QByteArray comment; + if(info==NULL) return false; + if(!isOpen()||!hasCurrentFile()) return false; + if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0))!=UNZ_OK) + return false; + fileName.resize(info_z.size_filename); + extra.resize(info_z.size_file_extra); + comment.resize(info_z.size_file_comment); + if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, NULL, + fileName.data(), fileName.size(), + extra.data(), extra.size(), + comment.data(), comment.size()))!=UNZ_OK) + return false; + info->versionCreated=info_z.version; + info->versionNeeded=info_z.version_needed; + info->flags=info_z.flag; + info->method=info_z.compression_method; + info->crc=info_z.crc; + info->compressedSize=info_z.compressed_size; + info->uncompressedSize=info_z.uncompressed_size; + info->diskNumberStart=info_z.disk_num_start; + info->internalAttr=info_z.internal_fa; + info->externalAttr=info_z.external_fa; + info->name=p->fileNameCodec->toUnicode(fileName); + info->comment=p->commentCodec->toUnicode(comment); + info->extra=extra; + info->dateTime=QDateTime( + QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon+1, info_z.tmu_date.tm_mday), + QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec)); + return true; +} + +QString QuaZip::getCurrentFileName()const +{ + QuaZip *fakeThis=(QuaZip*)this; // non-const + fakeThis->p->zipError=UNZ_OK; + if(p->mode!=mdUnzip) { + qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode"); + return QString(); + } + if(!isOpen()||!hasCurrentFile()) return QString(); + QByteArray fileName(MAX_FILE_NAME_LENGTH, 0); + if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, NULL, fileName.data(), fileName.size(), + NULL, 0, NULL, 0))!=UNZ_OK) + return QString(); + return p->fileNameCodec->toUnicode(fileName.constData()); +} + +void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec) +{ + p->fileNameCodec=fileNameCodec; +} + +void QuaZip::setFileNameCodec(const char *fileNameCodecName) +{ + p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName); +} + +QTextCodec *QuaZip::getFileNameCodec()const +{ + return p->fileNameCodec; +} + +void QuaZip::setCommentCodec(QTextCodec *commentCodec) +{ + p->commentCodec=commentCodec; +} + +void QuaZip::setCommentCodec(const char *commentCodecName) +{ + p->commentCodec=QTextCodec::codecForName(commentCodecName); +} + +QTextCodec *QuaZip::getCommentCodec()const +{ + return p->commentCodec; +} + +QString QuaZip::getZipName() const +{ + return p->zipName; +} + +QIODevice *QuaZip::getIoDevice() const +{ + if (!p->zipName.isEmpty()) // opened by name, using an internal QIODevice + return NULL; + return p->ioDevice; +} + +QuaZip::Mode QuaZip::getMode()const +{ + return p->mode; +} + +bool QuaZip::isOpen()const +{ + return p->mode!=mdNotOpen; +} + +int QuaZip::getZipError() const +{ + return p->zipError; +} + +void QuaZip::setComment(const QString& comment) +{ + p->comment=comment; +} + +bool QuaZip::hasCurrentFile()const +{ + return p->hasCurrentFile_f; +} + +unzFile QuaZip::getUnzFile() +{ + return p->unzFile_f; +} + +zipFile QuaZip::getZipFile() +{ + return p->zipFile_f; +} + +void QuaZip::setDataDescriptorWritingEnabled(bool enabled) +{ + p->dataDescriptorWritingEnabled = enabled; +} + +bool QuaZip::isDataDescriptorWritingEnabled() const +{ + return p->dataDescriptorWritingEnabled; +} + +template +TFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok); + +template<> +QuaZipFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok) +{ + QuaZipFileInfo info; + *ok = zip->getCurrentFileInfo(&info); + return info; +} + +template<> +QString QuaZip_getFileInfo(QuaZip *zip, bool *ok) +{ + QString name = zip->getCurrentFileName(); + *ok = !name.isEmpty(); + return name; +} + +template +bool QuaZipPrivate::getFileInfoList(QList *result) const +{ + QuaZipPrivate *fakeThis=const_cast(this); + fakeThis->zipError=UNZ_OK; + if (mode!=QuaZip::mdUnzip) { + qWarning("QuaZip::getFileNameList/getFileInfoList(): " + "ZIP is not open in mdUnzip mode"); + return false; + } + QString currentFile; + if (q->hasCurrentFile()) { + currentFile = q->getCurrentFileName(); + } + if (q->goToFirstFile()) { + do { + bool ok; + result->append(QuaZip_getFileInfo(q, &ok)); + if (!ok) + return false; + } while (q->goToNextFile()); + } + if (zipError != UNZ_OK) + return false; + if (currentFile.isEmpty()) { + if (!q->goToFirstFile()) + return false; + } else { + if (!q->setCurrentFile(currentFile)) + return false; + } + return true; +} + +QStringList QuaZip::getFileNameList() const +{ + QStringList list; + if (p->getFileInfoList(&list)) + return list; + else + return QStringList(); +} + +QList QuaZip::getFileInfoList() const +{ + QList list; + if (p->getFileInfoList(&list)) + return list; + else + return QList(); +} + +Qt::CaseSensitivity QuaZip::convertCaseSensitivity(QuaZip::CaseSensitivity cs) +{ + if (cs == csDefault) { +#ifdef Q_WS_WIN + return Qt::CaseInsensitive; +#else + return Qt::CaseSensitive; +#endif + } else { + return cs == csSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; + } +} diff --git a/depends/quazip/quazip.h b/depends/quazip/quazip.h new file mode 100644 index 00000000..a3ab8e52 --- /dev/null +++ b/depends/quazip/quazip.h @@ -0,0 +1,411 @@ +#ifndef QUA_ZIP_H +#define QUA_ZIP_H + +/* +Copyright (C) 2005-2011 Sergey A. Tachenov + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser 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 Lesser +General Public License for more details. + +You should have received a copy of the GNU Lesser 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 + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant, see +quazip/(un)zip.h files for details, basically it's zlib license. + **/ + +#include +#include +#include + +#include "zip.h" +#include "unzip.h" + +#include "quazip_global.h" +#include "quazipfileinfo.h" + +// just in case it will be defined in the later versions of the ZIP/UNZIP +#ifndef UNZ_OPENERROR +// define additional error code +#define UNZ_OPENERROR -1000 +#endif + +class QuaZipPrivate; + +/// ZIP archive. +/** \class QuaZip quazip.h + * This class implements basic interface to the ZIP archive. It can be + * used to read table contents of the ZIP archive and retreiving + * information about the files inside it. + * + * You can also use this class to open files inside archive by passing + * pointer to the instance of this class to the constructor of the + * QuaZipFile class. But see QuaZipFile::QuaZipFile(QuaZip*, QObject*) + * for the possible pitfalls. + * + * This class is indended to provide interface to the ZIP subpackage of + * the ZIP/UNZIP package as well as to the UNZIP subpackage. But + * currently it supports only UNZIP. + * + * The use of this class is simple - just create instance using + * constructor, then set ZIP archive file name using setFile() function + * (if you did not passed the name to the constructor), then open() and + * then use different functions to work with it! Well, if you are + * paranoid, you may also wish to call close before destructing the + * instance, to check for errors on close. + * + * You may also use getUnzFile() and getZipFile() functions to get the + * ZIP archive handle and use it with ZIP/UNZIP package API directly. + * + * This class supports localized file names inside ZIP archive, but you + * have to set up proper codec with setCodec() function. By default, + * locale codec will be used, which is probably ok for UNIX systems, but + * will almost certainly fail with ZIP archives created in Windows. This + * is because Windows ZIP programs have strange habit of using DOS + * encoding for file names in ZIP archives. For example, ZIP archive + * with cyrillic names created in Windows will have file names in \c + * IBM866 encoding instead of \c WINDOWS-1251. I think that calling one + * function is not much trouble, but for true platform independency it + * would be nice to have some mechanism for file name encoding auto + * detection using locale information. Does anyone know a good way to do + * it? + **/ +class QUAZIP_EXPORT QuaZip { + friend class QuaZipPrivate; + public: + /// Useful constants. + enum Constants { + MAX_FILE_NAME_LENGTH=256 /**< Maximum file name length. Taken from + \c UNZ_MAXFILENAMEINZIP constant in + unzip.c. */ + }; + /// Open mode of the ZIP file. + enum Mode { + mdNotOpen, ///< ZIP file is not open. This is the initial mode. + mdUnzip, ///< ZIP file is open for reading files inside it. + mdCreate, ///< ZIP file was created with open() call. + mdAppend, /**< ZIP file was opened in append mode. This refers to + * \c APPEND_STATUS_CREATEAFTER mode in ZIP/UNZIP package + * and means that zip is appended to some existing file + * what is useful when that file contains + * self-extractor code. This is obviously \em not what + * you whant to use to add files to the existing ZIP + * archive. + **/ + mdAdd ///< ZIP file was opened for adding files in the archive. + }; + /// Case sensitivity for the file names. + /** This is what you specify when accessing files in the archive. + * Works perfectly fine with any characters thanks to Qt's great + * unicode support. This is different from ZIP/UNZIP API, where + * only US-ASCII characters was supported. + **/ + enum CaseSensitivity { + csDefault=0, ///< Default for platform. Case sensitive for UNIX, not for Windows. + csSensitive=1, ///< Case sensitive. + csInsensitive=2 ///< Case insensitive. + }; + static Qt::CaseSensitivity convertCaseSensitivity(CaseSensitivity); + private: + QuaZipPrivate *p; + // not (and will not be) implemented + QuaZip(const QuaZip& that); + // not (and will not be) implemented + QuaZip& operator=(const QuaZip& that); + public: + /// Constructs QuaZip object. + /** Call setName() before opening constructed object. */ + QuaZip(); + /// Constructs QuaZip object associated with ZIP file \a zipName. + QuaZip(const QString& zipName); + /// Constructs QuaZip object associated with ZIP file represented by \a ioDevice. + /** The IO device must be seekable, otherwise an error will occur when opening. */ + QuaZip(QIODevice *ioDevice); + /// Destroys QuaZip object. + /** Calls close() if necessary. */ + ~QuaZip(); + /// Opens ZIP file. + /** + * Argument \a mode specifies open mode of the ZIP archive. See Mode + * for details. Note that there is zipOpen2() function in the + * ZIP/UNZIP API which accepts \a globalcomment argument, but it + * does not use it anywhere, so this open() function does not have this + * argument. See setComment() if you need to set global comment. + * + * If the ZIP file is accessed via explicitly set QIODevice, then + * this device is opened in the necessary mode. If the device was + * already opened by some other means, then the behaviour is defined by + * the device implementation, but generally it is not a very good + * idea. For example, QFile will at least issue a warning. + * + * \return \c true if successful, \c false otherwise. + * + * \note ZIP/UNZIP API open calls do not return error code - they + * just return \c NULL indicating an error. But to make things + * easier, quazip.h header defines additional error code \c + * UNZ_ERROROPEN and getZipError() will return it if the open call + * of the ZIP/UNZIP API returns \c NULL. + * + * Argument \a ioApi specifies IO function set for ZIP/UNZIP + * package to use. See unzip.h, zip.h and ioapi.h for details. Note + * that IO API for QuaZip is different from the original package. + * The file path argument was changed to be of type \c voidpf, and + * QuaZip passes a QIODevice pointer there. This QIODevice is either + * set explicitly via setIoDevice() or the QuaZip(QIODevice*) + * constructor, or it is created internally when opening the archive + * by its file name. The default API (qioapi.cpp) just delegates + * everything to the QIODevice API. Not only this allows to use a + * QIODevice instead of file name, but also has a nice side effect + * of raising the file size limit from 2G to 4G. + * + * In short: just forget about the \a ioApi argument and you'll be + * fine. + **/ + bool open(Mode mode, zlib_filefunc_def *ioApi =NULL); + /// Closes ZIP file. + /** Call getZipError() to determine if the close was successful. The + * underlying QIODevice is also closed, regardless of whether it was + * set explicitly or not. */ + void close(); + /// Sets the codec used to encode/decode file names inside archive. + /** This is necessary to access files in the ZIP archive created + * under Windows with non-latin characters in file names. For + * example, file names with cyrillic letters will be in \c IBM866 + * encoding. + **/ + void setFileNameCodec(QTextCodec *fileNameCodec); + /// Sets the codec used to encode/decode file names inside archive. + /** \overload + * Equivalent to calling setFileNameCodec(QTextCodec::codecForName(codecName)); + **/ + void setFileNameCodec(const char *fileNameCodecName); + /// Returns the codec used to encode/decode comments inside archive. + QTextCodec* getFileNameCodec() const; + /// Sets the codec used to encode/decode comments inside archive. + /** This codec defaults to locale codec, which is probably ok. + **/ + void setCommentCodec(QTextCodec *commentCodec); + /// Sets the codec used to encode/decode comments inside archive. + /** \overload + * Equivalent to calling setCommentCodec(QTextCodec::codecForName(codecName)); + **/ + void setCommentCodec(const char *commentCodecName); + /// Returns the codec used to encode/decode comments inside archive. + QTextCodec* getCommentCodec() const; + /// Returns the name of the ZIP file. + /** Returns null string if no ZIP file name has been set, for + * example when the QuaZip instance is set up to use a QIODevice + * instead. + * \sa setZipName(), setIoDevice(), getIoDevice() + **/ + QString getZipName() const; + /// Sets the name of the ZIP file. + /** Does nothing if the ZIP file is open. + * + * Does not reset error code returned by getZipError(). + * \sa setIoDevice(), getIoDevice(), getZipName() + **/ + void setZipName(const QString& zipName); + /// Returns the device representing this ZIP file. + /** Returns null string if no device has been set explicitly, for + * example when opening a ZIP file by name. + * \sa setIoDevice(), getZipName(), setZipName() + **/ + QIODevice *getIoDevice() const; + /// Sets the device representing the ZIP file. + /** Does nothing if the ZIP file is open. + * + * Does not reset error code returned by getZipError(). + * \sa getIoDevice(), getZipName(), setZipName() + **/ + void setIoDevice(QIODevice *ioDevice); + /// Returns the mode in which ZIP file was opened. + Mode getMode() const; + /// Returns \c true if ZIP file is open, \c false otherwise. + bool isOpen() const; + /// Returns the error code of the last operation. + /** Returns \c UNZ_OK if the last operation was successful. + * + * Error code resets to \c UNZ_OK every time you call any function + * that accesses something inside ZIP archive, even if it is \c + * const (like getEntriesCount()). open() and close() calls reset + * error code too. See documentation for the specific functions for + * details on error detection. + **/ + int getZipError() const; + /// Returns number of the entries in the ZIP central directory. + /** Returns negative error code in the case of error. The same error + * code will be returned by subsequent getZipError() call. + **/ + int getEntriesCount() const; + /// Returns global comment in the ZIP file. + QString getComment() const; + /// Sets the global comment in the ZIP file. + /** The comment will be written to the archive on close operation. + * QuaZip makes a distinction between a null QByteArray() comment + * and an empty "" comment in the QuaZip::mdAdd mode. + * A null comment is the default and it means "don't change + * the comment". An empty comment removes the original comment. + * + * \sa open() + **/ + void setComment(const QString& comment); + /// Sets the current file to the first file in the archive. + /** Returns \c true on success, \c false otherwise. Call + * getZipError() to get the error code. + **/ + bool goToFirstFile(); + /// Sets the current file to the next file in the archive. + /** Returns \c true on success, \c false otherwise. Call + * getZipError() to determine if there was an error. + * + * Should be used only in QuaZip::mdUnzip mode. + * + * \note If the end of file was reached, getZipError() will return + * \c UNZ_OK instead of \c UNZ_END_OF_LIST_OF_FILE. This is to make + * things like this easier: + * \code + * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { + * // do something + * } + * if(zip.getZipError()==UNZ_OK) { + * // ok, there was no error + * } + * \endcode + **/ + bool goToNextFile(); + /// Sets current file by its name. + /** Returns \c true if successful, \c false otherwise. Argument \a + * cs specifies case sensitivity of the file name. Call + * getZipError() in the case of a failure to get error code. + * + * This is not a wrapper to unzLocateFile() function. That is + * because I had to implement locale-specific case-insensitive + * comparison. + * + * Here are the differences from the original implementation: + * + * - If the file was not found, error code is \c UNZ_OK, not \c + * UNZ_END_OF_LIST_OF_FILE (see also goToNextFile()). + * - If this function fails, it unsets the current file rather than + * resetting it back to what it was before the call. + * + * If \a fileName is null string then this function unsets the + * current file and return \c true. Note that you should close the + * file first if it is open! See + * QuaZipFile::QuaZipFile(QuaZip*,QObject*) for the details. + * + * Should be used only in QuaZip::mdUnzip mode. + * + * \sa setFileNameCodec(), CaseSensitivity + **/ + bool setCurrentFile(const QString& fileName, CaseSensitivity cs =csDefault); + /// Returns \c true if the current file has been set. + bool hasCurrentFile() const; + /// Retrieves information about the current file. + /** Fills the structure pointed by \a info. Returns \c true on + * success, \c false otherwise. In the latter case structure pointed + * by \a info remains untouched. If there was an error, + * getZipError() returns error code. + * + * Should be used only in QuaZip::mdUnzip mode. + * + * Does nothing and returns \c false in any of the following cases. + * - ZIP is not open; + * - ZIP does not have current file; + * - \a info is \c NULL; + * + * In all these cases getZipError() returns \c UNZ_OK since there + * is no ZIP/UNZIP API call. + **/ + bool getCurrentFileInfo(QuaZipFileInfo* info)const; + /// Returns the current file name. + /** Equivalent to calling getCurrentFileInfo() and then getting \c + * name field of the QuaZipFileInfo structure, but faster and more + * convenient. + * + * Should be used only in QuaZip::mdUnzip mode. + **/ + QString getCurrentFileName()const; + /// Returns \c unzFile handle. + /** You can use this handle to directly call UNZIP part of the + * ZIP/UNZIP package functions (see unzip.h). + * + * \warning When using the handle returned by this function, please + * keep in mind that QuaZip class is unable to detect any changes + * you make in the ZIP file state (e. g. changing current file, or + * closing the handle). So please do not do anything with this + * handle that is possible to do with the functions of this class. + * Or at least return the handle in the original state before + * calling some another function of this class (including implicit + * destructor calls and calls from the QuaZipFile objects that refer + * to this QuaZip instance!). So if you have changed the current + * file in the ZIP archive - then change it back or you may + * experience some strange behavior or even crashes. + **/ + unzFile getUnzFile(); + /// Returns \c zipFile handle. + /** You can use this handle to directly call ZIP part of the + * ZIP/UNZIP package functions (see zip.h). Warnings about the + * getUnzFile() function also apply to this function. + **/ + zipFile getZipFile(); + /// Changes the data descriptor writing mode. + /** + According to the ZIP format specification, a file inside archive + may have a data descriptor immediately following the file + data. This is reflected by a special flag in the local file header + and in the central directory. By default, QuaZIP sets this flag + and writes the data descriptor unless both method and level were + set to 0, in which case it operates in 1.0-compatible mode and + never writes data descriptors. + + By setting this flag to false, it is possible to disable data + descriptor writing, thus increasing compatibility with archive + readers that don't understand this feature of the ZIP file format. + + Setting this flag affects all the QuaZipFile instances that are + opened after this flag is set. + + The data descriptor writing mode is enabled by default. + + \param enabled If \c true, enable local descriptor writing, + disable it otherwise. + + \sa QuaZipFile::setDataDescriptorWritingEnabled() + */ + void setDataDescriptorWritingEnabled(bool enabled); + /// Returns the data descriptor default writing mode. + /** + \sa setDataDescriptorWritingEnabled() + */ + bool isDataDescriptorWritingEnabled() const; + /// Returns a list of files inside the archive. + /** + \return A list of file names or an empty list if there + was an error or if the archive is empty (call getZipError() to + figure out which). + \sa getFileInfoList() + */ + QStringList getFileNameList() const; + /// Returns information list about all files inside the archive. + /** + \return A list of QuaZipFileInfo objects or an empty list if there + was an error or if the archive is empty (call getZipError() to + figure out which). + \sa getFileNameList() + */ + QList getFileInfoList() const; +}; + +#endif diff --git a/depends/quazip/quazip_global.h b/depends/quazip/quazip_global.h new file mode 100644 index 00000000..d9d09ade --- /dev/null +++ b/depends/quazip/quazip_global.h @@ -0,0 +1,55 @@ +/** +Copyright (C) 2005-2011 Sergey A. Tachenov + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser 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 Lesser +General Public License for more details. + +You should have received a copy of the GNU Lesser 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 + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant, see +quazip/(un)zip.h files for details, basically it's zlib license. + */ + +#ifndef QUAZIP_GLOBAL_H +#define QUAZIP_GLOBAL_H + +#include + +/** + This is automatically defined when building a static library, but when + including QuaZip sources directly into a project, QUAZIP_STATIC should + be defined explicitly to avoid possible troubles with unnecessary + importing/exporting. + */ +#ifdef QUAZIP_STATIC +#define QUAZIP_EXPORT +#else +/** + * When building a DLL with MSVC, QUAZIP_BUILD must be defined. + * qglobal.h takes care of defining Q_DECL_* correctly for msvc/gcc. + */ +#if defined(QUAZIP_BUILD) + #define QUAZIP_EXPORT Q_DECL_EXPORT +#else + #define QUAZIP_EXPORT Q_DECL_IMPORT +#endif +#endif // QUAZIP_STATIC + +#ifdef __GNUC__ +#define UNUSED __attribute__((__unused__)) +#else +#define UNUSED +#endif + +#endif // QUAZIP_GLOBAL_H diff --git a/depends/quazip/quazipdir.cpp b/depends/quazip/quazipdir.cpp new file mode 100644 index 00000000..02208894 --- /dev/null +++ b/depends/quazip/quazipdir.cpp @@ -0,0 +1,507 @@ +#include "quazipdir.h" + +#include +#include + +class QuaZipDirPrivate: public QSharedData { + friend class QuaZipDir; +private: + QuaZipDirPrivate(QuaZip *zip, const QString &dir = QString()): + zip(zip), dir(dir), caseSensitivity(QuaZip::csDefault), + filter(QDir::NoFilter), sorting(QDir::NoSort) {} + QuaZip *zip; + QString dir; + QuaZip::CaseSensitivity caseSensitivity; + QDir::Filters filter; + QStringList nameFilters; + QDir::SortFlags sorting; + template + bool entryInfoList(QStringList nameFilters, QDir::Filters filter, + QDir::SortFlags sort, TFileInfoList &result) const; + inline QString simplePath() const {return QDir::cleanPath(dir);} +}; + +QuaZipDir::QuaZipDir(const QuaZipDir &that): + d(that.d) +{ +} + +QuaZipDir::QuaZipDir(QuaZip *zip, const QString &dir): + d(new QuaZipDirPrivate(zip, dir)) +{ + if (d->dir.startsWith('/')) + d->dir = d->dir.mid(1); +} + +QuaZipDir::~QuaZipDir() +{ +} + +bool QuaZipDir::operator==(const QuaZipDir &that) +{ + return d->zip == that.d->zip && d->dir == that.d->dir; +} + +QuaZipDir& QuaZipDir::operator=(const QuaZipDir &that) +{ + this->d = that.d; + return *this; +} + +QString QuaZipDir::operator[](int pos) const +{ + return entryList().at(pos); +} + +QuaZip::CaseSensitivity QuaZipDir::caseSensitivity() const +{ + return d->caseSensitivity; +} + +bool QuaZipDir::cd(const QString &directoryName) +{ + if (directoryName == "/") { + d->dir = ""; + return true; + } + QString dirName = directoryName; + if (dirName.endsWith('/')) + dirName.chop(1); + if (dirName.contains('/')) { + QuaZipDir dir(*this); + if (dirName.startsWith('/')) { +#ifdef QUAZIP_QUAZIPDIR_DEBUG + qDebug("QuaZipDir::cd(%s): going to /", + dirName.toUtf8().constData()); +#endif + if (!dir.cd("/")) + return false; + } + QStringList path = dirName.split('/', QString::SkipEmptyParts); + for (QStringList::const_iterator i = path.constBegin(); + i != path.end(); + ++i) { + const QString &step = *i; +#ifdef QUAZIP_QUAZIPDIR_DEBUG + qDebug("QuaZipDir::cd(%s): going to %s", + dirName.toUtf8().constData(), + step.toUtf8().constData()); +#endif + if (!dir.cd(step)) + return false; + } + d->dir = dir.path(); + return true; + } else { // no '/' + if (dirName == ".") { + return true; + } else if (dirName == "..") { + if (isRoot()) { + return false; + } else { + int slashPos = d->dir.lastIndexOf('/'); + if (slashPos == -1) { + d->dir = ""; + } else { + d->dir = d->dir.left(slashPos); + } + return true; + } + } else { // a simple subdirectory + if (exists(dirName)) { + if (isRoot()) + d->dir = dirName; + else + d->dir += "/" + dirName; + return true; + } else { + return false; + } + } + } +} + +bool QuaZipDir::cdUp() +{ + return cd(".."); +} + +uint QuaZipDir::count() const +{ + return entryList().count(); +} + +QString QuaZipDir::dirName() const +{ + return QDir(d->dir).dirName(); +} + +QuaZipFileInfo QuaZipDir_getFileInfo(QuaZip *zip, bool *ok, + const QString &relativeName, + bool isReal) +{ + QuaZipFileInfo info; + if (isReal) { + *ok = zip->getCurrentFileInfo(&info); + } else { + *ok = true; + info.compressedSize = 0; + info.crc = 0; + info.diskNumberStart = 0; + info.externalAttr = 0; + info.flags = 0; + info.internalAttr = 0; + info.method = 0; + info.uncompressedSize = 0; + info.versionCreated = info.versionNeeded = 0; + } + info.name = relativeName; + return info; +} + +template +void QuaZipDir_convertInfoList(const QList &from, TFileInfoList &to); + +template<> +void QuaZipDir_convertInfoList(const QList &from, QList &to) +{ + to = from; +} + +template<> +void QuaZipDir_convertInfoList(const QList &from, QStringList &to) +{ + to.clear(); + for (QList::const_iterator i = from.constBegin(); + i != from.constEnd(); + ++i) { + to.append(i->name); + } +} + +// utility class to restore the current file +class QuaZipDirRestoreCurrent { +public: + inline QuaZipDirRestoreCurrent(QuaZip *zip): + zip(zip), currentFile(zip->getCurrentFileName()) {} + inline ~QuaZipDirRestoreCurrent() + { + zip->setCurrentFile(currentFile); + } +private: + QuaZip *zip; + QString currentFile; +}; + +class QuaZipDirComparator +{ + private: + QDir::SortFlags sort; + static QString getExtension(const QString &name); + int compareStrings(const QString &string1, const QString &string2); + public: + inline QuaZipDirComparator(QDir::SortFlags sort): sort(sort) {} + bool operator()(const QuaZipFileInfo &info1, const QuaZipFileInfo &info2); +}; + +QString QuaZipDirComparator::getExtension(const QString &name) +{ + if (name.endsWith('.') || name.indexOf('.', 1) == -1) { + return ""; + } else { + return name.mid(name.lastIndexOf('.') + 1); + } + +} + +int QuaZipDirComparator::compareStrings(const QString &string1, + const QString &string2) +{ + if (sort & QDir::LocaleAware) { + if (sort & QDir::IgnoreCase) { + return string1.toLower().localeAwareCompare(string2.toLower()); + } else { + return string1.localeAwareCompare(string2); + } + } else { + return string1.compare(string2, (sort & QDir::IgnoreCase) + ? Qt::CaseInsensitive : Qt::CaseSensitive); + } +} + +bool QuaZipDirComparator::operator()(const QuaZipFileInfo &info1, + const QuaZipFileInfo &info2) +{ + QDir::SortFlags order = sort + & (QDir::Name | QDir::Time | QDir::Size | QDir::Type); + if ((sort & QDir::DirsFirst) == QDir::DirsFirst + || (sort & QDir::DirsLast) == QDir::DirsLast) { + if (info1.name.endsWith('/') && !info2.name.endsWith('/')) + return (sort & QDir::DirsFirst) == QDir::DirsFirst; + else if (!info1.name.endsWith('/') && info2.name.endsWith('/')) + return (sort & QDir::DirsLast) == QDir::DirsLast; + } + bool result; + int extDiff; + switch (order) { + case QDir::Name: + result = compareStrings(info1.name, info2.name) < 0; + break; + case QDir::Type: + extDiff = compareStrings(getExtension(info1.name), + getExtension(info2.name)); + if (extDiff == 0) { + result = compareStrings(info1.name, info2.name) < 0; + } else { + result = extDiff < 0; + } + break; + case QDir::Size: + if (info1.uncompressedSize == info2.uncompressedSize) { + result = compareStrings(info1.name, info2.name) < 0; + } else { + result = info1.uncompressedSize < info2.uncompressedSize; + } + break; + case QDir::Time: + if (info1.dateTime == info2.dateTime) { + result = compareStrings(info1.name, info2.name) < 0; + } else { + result = info1.dateTime < info2.dateTime; + } + break; + default: + qWarning("QuaZipDirComparator(): Invalid sort mode 0x%2X", + static_cast(sort)); + return false; + } + return (sort & QDir::Reversed) ? !result : result; +} + +template +bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters, + QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const +{ + QString basePath = simplePath(); + if (!basePath.isEmpty()) + basePath += "/"; + int baseLength = basePath.length(); + result.clear(); + QuaZipDirRestoreCurrent saveCurrent(zip); + if (!zip->goToFirstFile()) { + return zip->getZipError() == UNZ_OK; + } + QDir::Filters fltr = filter; + if (fltr == QDir::NoFilter) + fltr = this->filter; + if (fltr == QDir::NoFilter) + fltr = QDir::AllEntries; + QStringList nmfltr = nameFilters; + if (nmfltr.isEmpty()) + nmfltr = this->nameFilters; + QSet dirsFound; + QList list; + do { + QString name = zip->getCurrentFileName(); + if (!name.startsWith(basePath)) + continue; + QString relativeName = name.mid(baseLength); + bool isDir = false; + bool isReal = true; + if (relativeName.contains('/')) { + int indexOfSlash = relativeName.indexOf('/'); + // something like "subdir/" + isReal = indexOfSlash == relativeName.length() - 1; + relativeName = relativeName.left(indexOfSlash + 1); + if (dirsFound.contains(relativeName)) + continue; + isDir = true; + } + dirsFound.insert(relativeName); + if ((fltr & QDir::Dirs) == 0 && isDir) + continue; + if ((fltr & QDir::Files) == 0 && !isDir) + continue; + if (!nmfltr.isEmpty() && QDir::match(nmfltr, relativeName)) + continue; + bool ok; + QuaZipFileInfo info = QuaZipDir_getFileInfo(zip, &ok, relativeName, + isReal); + if (!ok) { + return false; + } + list.append(info); + } while (zip->goToNextFile()); + QDir::SortFlags srt = sort; + if (srt == QDir::NoSort) + srt = sorting; +#ifdef QUAZIP_QUAZIPDIR_DEBUG + qDebug("QuaZipDirPrivate::entryInfoList(): before sort:"); + foreach (QuaZipFileInfo info, list) { + qDebug("%s\t%s", info.name.toUtf8().constData(), + info.dateTime.toString(Qt::ISODate).toUtf8().constData()); + } +#endif + if (srt != QDir::NoSort && (srt & QDir::Unsorted) != QDir::Unsorted) { + if (QuaZip::convertCaseSensitivity(caseSensitivity) + == Qt::CaseInsensitive) + srt |= QDir::IgnoreCase; + QuaZipDirComparator lessThan(srt); + qSort(list.begin(), list.end(), lessThan); + } + QuaZipDir_convertInfoList(list, result); + return true; +} + +QList QuaZipDir::entryInfoList(const QStringList &nameFilters, + QDir::Filters filters, QDir::SortFlags sort) const +{ + QList result; + if (d->entryInfoList(nameFilters, filters, sort, result)) + return result; + else + return QList(); +} + +QList QuaZipDir::entryInfoList(QDir::Filters filters, + QDir::SortFlags sort) const +{ + return entryInfoList(QStringList(), filters, sort); +} + +QStringList QuaZipDir::entryList(const QStringList &nameFilters, + QDir::Filters filters, QDir::SortFlags sort) const +{ + QStringList result; + if (d->entryInfoList(nameFilters, filters, sort, result)) + return result; + else + return QStringList(); +} + +QStringList QuaZipDir::entryList(QDir::Filters filters, + QDir::SortFlags sort) const +{ + return entryList(QStringList(), filters, sort); +} + +bool QuaZipDir::exists(const QString &filePath) const +{ + if (filePath == "/") + return true; + QString fileName = filePath; + if (fileName.endsWith('/')) + fileName.chop(1); + if (fileName.contains('/')) { + QFileInfo fileInfo(fileName); +#ifdef QUAZIP_QUAZIPDIR_DEBUG + qDebug("QuaZipDir::exists(): fileName=%s, fileInfo.fileName()=%s, " + "fileInfo.path()=%s", fileName.toUtf8().constData(), + fileInfo.fileName().toUtf8().constData(), + fileInfo.path().toUtf8().constData()); +#endif + QuaZipDir dir(*this); + return dir.cd(fileInfo.path()) && dir.exists(fileInfo.fileName()); + } else { + if (fileName == "..") { + return !isRoot(); + } else if (fileName == ".") { + return true; + } else { + QStringList entries = entryList(QDir::AllEntries, QDir::NoSort); +#ifdef QUAZIP_QUAZIPDIR_DEBUG + qDebug("QuaZipDir::exists(): looking for %s", + fileName.toUtf8().constData()); + for (QStringList::const_iterator i = entries.constBegin(); + i != entries.constEnd(); + ++i) { + qDebug("QuaZipDir::exists(): entry: %s", + i->toUtf8().constData()); + } +#endif + Qt::CaseSensitivity cs = QuaZip::convertCaseSensitivity( + d->caseSensitivity); + if (filePath.endsWith('/')) { + return entries.contains(filePath, cs); + } else { + return entries.contains(fileName, cs) + || entries.contains(fileName + "/", cs); + } + } + } +} + +bool QuaZipDir::exists() const +{ + QDir thisDir(d->dir); + return QuaZipDir(d->zip, thisDir.filePath("..")).exists(thisDir.dirName()); +} + +QString QuaZipDir::filePath(const QString &fileName) const +{ + return QDir(d->dir).filePath(fileName); +} + +QDir::Filters QuaZipDir::filter() +{ + return d->filter; +} + +bool QuaZipDir::isRoot() const +{ + return d->simplePath().isEmpty(); +} + +QStringList QuaZipDir::nameFilters() const +{ + return d->nameFilters; +} + +QString QuaZipDir::path() const +{ + return d->dir; +} + +QString QuaZipDir::relativeFilePath(const QString &fileName) const +{ + return QDir(d->dir).relativeFilePath(fileName); +} + +void QuaZipDir::setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity) +{ + d->caseSensitivity = caseSensitivity; +} + +void QuaZipDir::setFilter(QDir::Filters filters) +{ + d->filter = filters; +} + +void QuaZipDir::setNameFilters(const QStringList &nameFilters) +{ + d->nameFilters = nameFilters; +} + +void QuaZipDir::setPath(const QString &path) +{ + QString newDir = path; + if (newDir == "/") { + d->dir = ""; + } else { + if (newDir.endsWith('/')) + newDir.chop(1); + if (newDir.startsWith('/')) + newDir = newDir.mid(1); + d->dir = newDir; + } +} + +void QuaZipDir::setSorting(QDir::SortFlags sort) +{ + d->sorting = sort; +} + +QDir::SortFlags QuaZipDir::sorting() const +{ + return d->sorting; +} diff --git a/depends/quazip/quazipdir.h b/depends/quazip/quazipdir.h new file mode 100644 index 00000000..e2d70bc8 --- /dev/null +++ b/depends/quazip/quazipdir.h @@ -0,0 +1,171 @@ +#ifndef QUAZIP_QUAZIPDIR_H +#define QUAZIP_QUAZIPDIR_H + +class QuaZipDirPrivate; + +#include "quazip.h" +#include "quazipfileinfo.h" +#include +#include +#include + +/// Provides ZIP archive navigation. +/** +* This class is modelled after QDir, and is designed to provide similar +* features for ZIP archives. +* +* The only significant difference from QDir is that the root path is not +* '/', but an empty string since that's how the file paths are stored in +* the archive. However, QuaZipDir understands the paths starting with +* '/'. It is important in a few places: +* +* - In the cd() function. +* - In the constructor. +* - In the exists() function. +* +* Note that since ZIP uses '/' on all platforms, the '\' separator is +* not supported. +*/ +class QUAZIP_EXPORT QuaZipDir { +private: + QSharedDataPointer d; +public: + /// The copy constructor. + QuaZipDir(const QuaZipDir &that); + /// Constructs a QuaZipDir instance pointing to the specified directory. + /** + If \a dir is not specified, points to the root of the archive. + The same happens if the \a dir is "/". + */ + QuaZipDir(QuaZip *zip, const QString &dir = QString()); + /// Destructor. + ~QuaZipDir(); + /// The assignment operator. + bool operator==(const QuaZipDir &that); + /// operator!= + /** + \return \c true if either this and \a that use different QuaZip + instances or if they point to different directories. + */ + inline bool operator!=(const QuaZipDir &that) {return !operator==(that);} + /// operator== + /** + \return \c true if both this and \a that use the same QuaZip + instance and point to the same directory. + */ + QuaZipDir& operator=(const QuaZipDir &that); + /// Returns the name of the entry at the specified position. + QString operator[](int pos) const; + /// Returns the current case sensitivity mode. + QuaZip::CaseSensitivity caseSensitivity() const; + /// Changes the 'current' directory. + /** + * If the path starts with '/', it is interpreted as an absolute + * path from the root of the archive. Otherwise, it is interpreted + * as a path relative to the current directory as was set by the + * previous cd() or the constructor. + * + * Note that the subsequent path() call will not return a path + * starting with '/' in all cases. + */ + bool cd(const QString &dirName); + /// Goes up. + bool cdUp(); + /// Returns the number of entries in the directory. + uint count() const; + /// Returns the current directory name. + /** + The name doesn't include the path. + */ + QString dirName() const; + /// Returns the list of the entries in the directory. + /** + \param nameFilters The list of file patterns to list, uses the same + syntax as QDir. + \param filters The entry type filters, only Files and Dirs are + accepted. + \param sort Sorting mode (not supported yet). + */ + QList entryInfoList(const QStringList &nameFilters, + QDir::Filters filters = QDir::NoFilter, + QDir::SortFlags sort = QDir::NoSort) const; + /// Returns the list of the entries in the directory. + /** + \overload + + The same as entryInfoList(QStringList(), filters, sort). + */ + QList entryInfoList(QDir::Filters filters = QDir::NoFilter, + QDir::SortFlags sort = QDir::NoSort) const; + /// Returns the list of the entry names in the directory. + /** + The same as entryInfoList(nameFilters, filters, sort), but only + returns entry names. + */ + QStringList entryList(const QStringList &nameFilters, + QDir::Filters filters = QDir::NoFilter, + QDir::SortFlags sort = QDir::NoSort) const; + /// Returns the list of the entry names in the directory. + /** + \overload + + The same as entryList(QStringList(), filters, sort). + */ + QStringList entryList(QDir::Filters filters = QDir::NoFilter, + QDir::SortFlags sort = QDir::NoSort) const; + /// Returns \c true if the entry with the specified name exists. + /** + The ".." is considered to exist if the current directory + is not root. The "." and "/" are considered to + always exist. Paths starting with "/" are relative to + the archive root, other paths are relative to the current dir. + */ + bool exists(const QString &fileName) const; + /// Return \c true if the directory pointed by this QuaZipDir exists. + bool exists() const; + /// Returns the full path to the specified file. + /** + Doesn't check if the file actually exists. + */ + QString filePath(const QString &fileName) const; + /// Returns the default filter. + QDir::Filters filter(); + /// Returns if the QuaZipDir points to the root of the archive. + /** + Not that the root path is the empty string, not '/'. + */ + bool isRoot() const; + /// Return the default name filter. + QStringList nameFilters() const; + /// Returns the path to the current dir. + /** + The path never starts with '/', and the root path is an empty + string. + */ + QString path() const; + /// Returns the path to the specified file relative to the current dir. + QString relativeFilePath(const QString &fileName) const; + /// Sets the default case sensitivity mode. + void setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity); + /// Sets the default filter. + void setFilter(QDir::Filters filters); + /// Sets the default name filter. + void setNameFilters(const QStringList &nameFilters); + /// Goes to the specified path. + /** + The difference from cd() is that this function never checks if the + path actually exists and doesn't use relative paths, so it's + possible to go to the root directory with setPath(""). + + Note that this function still chops the trailing and/or leading + '/' and treats a single '/' as the root path (path() will still + return an empty string). + */ + void setPath(const QString &path); + /// Sets the default sorting mode. + void setSorting(QDir::SortFlags sort); + /// Returns the default sorting mode. + QDir::SortFlags sorting() const; +}; + +#endif // QUAZIP_QUAZIPDIR_H diff --git a/depends/quazip/quazipfile.cpp b/depends/quazip/quazipfile.cpp new file mode 100644 index 00000000..323f815e --- /dev/null +++ b/depends/quazip/quazipfile.cpp @@ -0,0 +1,488 @@ +/* +Copyright (C) 2005-2011 Sergey A. Tachenov + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser 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 Lesser +General Public License for more details. + +You should have received a copy of the GNU Lesser 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 + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant, see +quazip/(un)zip.h files for details, basically it's zlib license. + **/ + +#include "quazipfile.h" + +using namespace std; + +/// The implementation class for QuaZip. +/** +\internal + +This class contains all the private stuff for the QuaZipFile class, thus +allowing to preserve binary compatibility between releases, the +technique known as the Pimpl (private implementation) idiom. +*/ +class QuaZipFilePrivate { + friend class QuaZipFile; + private: + /// The pointer to the associated QuaZipFile instance. + QuaZipFile *q; + /// The QuaZip object to work with. + QuaZip *zip; + /// The file name. + QString fileName; + /// Case sensitivity mode. + QuaZip::CaseSensitivity caseSensitivity; + /// Whether this file is opened in the raw mode. + bool raw; + /// Write position to keep track of. + /** + QIODevice::pos() is broken for non-seekable devices, so we need + our own position. + */ + qint64 writePos; + /// Uncompressed size to write along with a raw file. + ulong uncompressedSize; + /// CRC to write along with a raw file. + quint32 crc; + /// Whether \ref zip points to an internal QuaZip instance. + /** + This is true if the archive was opened by name, rather than by + supplying an existing QuaZip instance. + */ + bool internal; + /// The last error. + int zipError; + /// Resets \ref zipError. + inline void resetZipError() const {setZipError(UNZ_OK);} + /// Sets the zip error. + /** + This function is marked as const although it changes one field. + This allows to call it from const functions that don't change + anything by themselves. + */ + void setZipError(int zipError) const; + /// The constructor for the corresponding QuaZipFile constructor. + inline QuaZipFilePrivate(QuaZipFile *q): + q(q), zip(NULL), internal(true), zipError(UNZ_OK) {} + /// The constructor for the corresponding QuaZipFile constructor. + inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName): + q(q), internal(true), zipError(UNZ_OK) + { + zip=new QuaZip(zipName); + } + /// The constructor for the corresponding QuaZipFile constructor. + inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName, + QuaZip::CaseSensitivity cs): + q(q), internal(true), zipError(UNZ_OK) + { + zip=new QuaZip(zipName); + this->fileName=fileName; + if (this->fileName.startsWith('/')) + this->fileName = this->fileName.mid(1); + this->caseSensitivity=cs; + } + /// The constructor for the QuaZipFile constructor accepting a file name. + inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip): + q(q), zip(zip), internal(false), zipError(UNZ_OK) {} + /// The destructor. + inline ~QuaZipFilePrivate() + { + if (internal) + delete zip; + } +}; + +QuaZipFile::QuaZipFile(): + p(new QuaZipFilePrivate(this)) +{ +} + +QuaZipFile::QuaZipFile(QObject *parent): + QIODevice(parent), + p(new QuaZipFilePrivate(this)) +{ +} + +QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent): + QIODevice(parent), + p(new QuaZipFilePrivate(this, zipName)) +{ +} + +QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName, + QuaZip::CaseSensitivity cs, QObject *parent): + QIODevice(parent), + p(new QuaZipFilePrivate(this, zipName, fileName, cs)) +{ +} + +QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent): + QIODevice(parent), + p(new QuaZipFilePrivate(this, zip)) +{ +} + +QuaZipFile::~QuaZipFile() +{ + if (isOpen()) + close(); + delete p; +} + +QString QuaZipFile::getZipName() const +{ + return p->zip==NULL ? QString() : p->zip->getZipName(); +} + +QuaZip *QuaZipFile::getZip() const +{ + return p->internal ? NULL : p->zip; +} + +QString QuaZipFile::getActualFileName()const +{ + p->setZipError(UNZ_OK); + if (p->zip == NULL || (openMode() & WriteOnly)) + return QString(); + QString name=p->zip->getCurrentFileName(); + if(name.isNull()) + p->setZipError(p->zip->getZipError()); + return name; +} + +void QuaZipFile::setZipName(const QString& zipName) +{ + if(isOpen()) { + qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name"); + return; + } + if(p->zip!=NULL && p->internal) + delete p->zip; + p->zip=new QuaZip(zipName); + p->internal=true; +} + +void QuaZipFile::setZip(QuaZip *zip) +{ + if(isOpen()) { + qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP"); + return; + } + if(p->zip!=NULL && p->internal) + delete p->zip; + p->zip=zip; + p->fileName=QString(); + p->internal=false; +} + +void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs) +{ + if(p->zip==NULL) { + qWarning("QuaZipFile::setFileName(): call setZipName() first"); + return; + } + if(!p->internal) { + qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip"); + return; + } + if(isOpen()) { + qWarning("QuaZipFile::setFileName(): can not set file name for already opened file"); + return; + } + p->fileName=fileName; + if (p->fileName.startsWith('/')) + p->fileName = p->fileName.mid(1); + p->caseSensitivity=cs; +} + +void QuaZipFilePrivate::setZipError(int zipError) const +{ + QuaZipFilePrivate *fakeThis = const_cast(this); // non-const + fakeThis->zipError=zipError; + if(zipError==UNZ_OK) + q->setErrorString(QString()); + else + q->setErrorString(q->tr("ZIP/UNZIP API error %1").arg(zipError)); +} + +bool QuaZipFile::open(OpenMode mode) +{ + return open(mode, NULL); +} + +bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password) +{ + p->resetZipError(); + if(isOpen()) { + qWarning("QuaZipFile::open(): already opened"); + return false; + } + if(mode&Unbuffered) { + qWarning("QuaZipFile::open(): Unbuffered mode is not supported"); + return false; + } + if((mode&ReadOnly)&&!(mode&WriteOnly)) { + if(p->internal) { + if(!p->zip->open(QuaZip::mdUnzip)) { + p->setZipError(p->zip->getZipError()); + return false; + } + if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) { + p->setZipError(p->zip->getZipError()); + p->zip->close(); + return false; + } + } else { + if(p->zip==NULL) { + qWarning("QuaZipFile::open(): zip is NULL"); + return false; + } + if(p->zip->getMode()!=QuaZip::mdUnzip) { + qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", + (int)mode, (int)p->zip->getMode()); + return false; + } + if(!p->zip->hasCurrentFile()) { + qWarning("QuaZipFile::open(): zip does not have current file"); + return false; + } + } + p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password)); + if(p->zipError==UNZ_OK) { + setOpenMode(mode); + p->raw=raw; + return true; + } else + return false; + } + qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); + return false; +} + +bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info, + const char *password, quint32 crc, + int method, int level, bool raw, + int windowBits, int memLevel, int strategy) +{ + zip_fileinfo info_z; + p->resetZipError(); + if(isOpen()) { + qWarning("QuaZipFile::open(): already opened"); + return false; + } + if((mode&WriteOnly)&&!(mode&ReadOnly)) { + if(p->internal) { + qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach"); + return false; + } + if(p->zip==NULL) { + qWarning("QuaZipFile::open(): zip is NULL"); + return false; + } + if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) { + qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", + (int)mode, (int)p->zip->getMode()); + return false; + } + info_z.tmz_date.tm_year=info.dateTime.date().year(); + info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1; + info_z.tmz_date.tm_mday=info.dateTime.date().day(); + info_z.tmz_date.tm_hour=info.dateTime.time().hour(); + info_z.tmz_date.tm_min=info.dateTime.time().minute(); + info_z.tmz_date.tm_sec=info.dateTime.time().second(); + info_z.dosDate = 0; + info_z.internal_fa=(uLong)info.internalAttr; + info_z.external_fa=(uLong)info.externalAttr; + if (!p->zip->isDataDescriptorWritingEnabled()) + zipClearFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR); + p->setZipError(zipOpenNewFileInZip3(p->zip->getZipFile(), + p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z, + info.extraLocal.constData(), info.extraLocal.length(), + info.extraGlobal.constData(), info.extraGlobal.length(), + p->zip->getCommentCodec()->fromUnicode(info.comment).constData(), + method, level, (int)raw, + windowBits, memLevel, strategy, + password, (uLong)crc)); + if(p->zipError==UNZ_OK) { + p->writePos=0; + setOpenMode(mode); + p->raw=raw; + if(raw) { + p->crc=crc; + p->uncompressedSize=info.uncompressedSize; + } + return true; + } else + return false; + } + qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); + return false; +} + +bool QuaZipFile::isSequential()const +{ + return true; +} + +qint64 QuaZipFile::pos()const +{ + if(p->zip==NULL) { + qWarning("QuaZipFile::pos(): call setZipName() or setZip() first"); + return -1; + } + if(!isOpen()) { + qWarning("QuaZipFile::pos(): file is not open"); + return -1; + } + if(openMode()&ReadOnly) + // QIODevice::pos() is broken for sequential devices, + // but thankfully bytesAvailable() returns the number of + // bytes buffered, so we know how far ahead we are. + return unztell(p->zip->getUnzFile()) - QIODevice::bytesAvailable(); + else + return p->writePos; +} + +bool QuaZipFile::atEnd()const +{ + if(p->zip==NULL) { + qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first"); + return false; + } + if(!isOpen()) { + qWarning("QuaZipFile::atEnd(): file is not open"); + return false; + } + if(openMode()&ReadOnly) + // the same problem as with pos() + return QIODevice::bytesAvailable() == 0 + && unzeof(p->zip->getUnzFile())==1; + else + return true; +} + +qint64 QuaZipFile::size()const +{ + if(!isOpen()) { + qWarning("QuaZipFile::atEnd(): file is not open"); + return -1; + } + if(openMode()&ReadOnly) + return p->raw?csize():usize(); + else + return p->writePos; +} + +qint64 QuaZipFile::csize()const +{ + unz_file_info info_z; + p->setZipError(UNZ_OK); + if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1; + p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); + if(p->zipError!=UNZ_OK) + return -1; + return info_z.compressed_size; +} + +qint64 QuaZipFile::usize()const +{ + unz_file_info info_z; + p->setZipError(UNZ_OK); + if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1; + p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); + if(p->zipError!=UNZ_OK) + return -1; + return info_z.uncompressed_size; +} + +bool QuaZipFile::getFileInfo(QuaZipFileInfo *info) +{ + if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false; + p->zip->getCurrentFileInfo(info); + p->setZipError(p->zip->getZipError()); + return p->zipError==UNZ_OK; +} + +void QuaZipFile::close() +{ + p->resetZipError(); + if(p->zip==NULL||!p->zip->isOpen()) return; + if(!isOpen()) { + qWarning("QuaZipFile::close(): file isn't open"); + return; + } + if(openMode()&ReadOnly) + p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile())); + else if(openMode()&WriteOnly) + if(isRaw()) p->setZipError(zipCloseFileInZipRaw(p->zip->getZipFile(), p->uncompressedSize, p->crc)); + else p->setZipError(zipCloseFileInZip(p->zip->getZipFile())); + else { + qWarning("Wrong open mode: %d", (int)openMode()); + return; + } + if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen); + else return; + if(p->internal) { + p->zip->close(); + p->setZipError(p->zip->getZipError()); + } +} + +qint64 QuaZipFile::readData(char *data, qint64 maxSize) +{ + p->setZipError(UNZ_OK); + qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize); + if (bytesRead < 0) { + p->setZipError((int) bytesRead); + return -1; + } + return bytesRead; +} + +qint64 QuaZipFile::writeData(const char* data, qint64 maxSize) +{ + p->setZipError(ZIP_OK); + p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize)); + if(p->zipError!=ZIP_OK) return -1; + else { + p->writePos+=maxSize; + return maxSize; + } +} + +QString QuaZipFile::getFileName() const +{ + return p->fileName; +} + +QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const +{ + return p->caseSensitivity; +} + +bool QuaZipFile::isRaw() const +{ + return p->raw; +} + +int QuaZipFile::getZipError() const +{ + return p->zipError; +} + +qint64 QuaZipFile::bytesAvailable() const +{ + return size() - pos(); +} diff --git a/depends/quazip/quazipfile.h b/depends/quazip/quazipfile.h new file mode 100644 index 00000000..f6cc41a6 --- /dev/null +++ b/depends/quazip/quazipfile.h @@ -0,0 +1,442 @@ +#ifndef QUA_ZIPFILE_H +#define QUA_ZIPFILE_H + +/* +Copyright (C) 2005-2011 Sergey A. Tachenov + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser 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 Lesser +General Public License for more details. + +You should have received a copy of the GNU Lesser 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 + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant, see +quazip/(un)zip.h files for details, basically it's zlib license. + **/ + +#include + +#include "quazip_global.h" +#include "quazip.h" +#include "quazipnewinfo.h" + +class QuaZipFilePrivate; + +/// A file inside ZIP archive. +/** \class QuaZipFile quazipfile.h + * This is the most interesting class. Not only it provides C++ + * interface to the ZIP/UNZIP package, but also integrates it with Qt by + * subclassing QIODevice. This makes possible to access files inside ZIP + * archive using QTextStream or QDataStream, for example. Actually, this + * is the main purpose of the whole QuaZIP library. + * + * You can either use existing QuaZip instance to create instance of + * this class or pass ZIP archive file name to this class, in which case + * it will create internal QuaZip object. See constructors' descriptions + * for details. Writing is only possible with the existing instance. + * + * Note that due to the underlying library's limitation it is not + * possible to use multiple QuaZipFile instances to open several files + * in the same archive at the same time. If you need to write to + * multiple files in parallel, then you should write to temporary files + * first, then pack them all at once when you have finished writing. If + * you need to read multiple files inside the same archive in parallel, + * you should extract them all into a temporary directory first. + * + * \section quazipfile-sequential Sequential or random-access? + * + * At the first thought, QuaZipFile has fixed size, the start and the + * end and should be therefore considered random-access device. But + * there is one major obstacle to making it random-access: ZIP/UNZIP API + * does not support seek() operation and the only way to implement it is + * through reopening the file and re-reading to the required position, + * but this is prohibitively slow. + * + * Therefore, QuaZipFile is considered to be a sequential device. This + * has advantage of availability of the ungetChar() operation (QIODevice + * does not implement it properly for non-sequential devices unless they + * support seek()). Disadvantage is a somewhat strange behaviour of the + * size() and pos() functions. This should be kept in mind while using + * this class. + * + **/ +class QUAZIP_EXPORT QuaZipFile: public QIODevice { + friend class QuaZipFilePrivate; + Q_OBJECT + private: + QuaZipFilePrivate *p; + // these are not supported nor implemented + QuaZipFile(const QuaZipFile& that); + QuaZipFile& operator=(const QuaZipFile& that); + protected: + /// Implementation of the QIODevice::readData(). + qint64 readData(char *data, qint64 maxSize); + /// Implementation of the QIODevice::writeData(). + qint64 writeData(const char *data, qint64 maxSize); + public: + /// Constructs a QuaZipFile instance. + /** You should use setZipName() and setFileName() or setZip() before + * trying to call open() on the constructed object. + **/ + QuaZipFile(); + /// Constructs a QuaZipFile instance. + /** \a parent argument specifies this object's parent object. + * + * You should use setZipName() and setFileName() or setZip() before + * trying to call open() on the constructed object. + **/ + QuaZipFile(QObject *parent); + /// Constructs a QuaZipFile instance. + /** \a parent argument specifies this object's parent object and \a + * zipName specifies ZIP archive file name. + * + * You should use setFileName() before trying to call open() on the + * constructed object. + * + * QuaZipFile constructed by this constructor can be used for read + * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. + **/ + QuaZipFile(const QString& zipName, QObject *parent =NULL); + /// Constructs a QuaZipFile instance. + /** \a parent argument specifies this object's parent object, \a + * zipName specifies ZIP archive file name and \a fileName and \a cs + * specify a name of the file to open inside archive. + * + * QuaZipFile constructed by this constructor can be used for read + * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. + * + * \sa QuaZip::setCurrentFile() + **/ + QuaZipFile(const QString& zipName, const QString& fileName, + QuaZip::CaseSensitivity cs =QuaZip::csDefault, QObject *parent =NULL); + /// Constructs a QuaZipFile instance. + /** \a parent argument specifies this object's parent object. + * + * \a zip is the pointer to the existing QuaZip object. This + * QuaZipFile object then can be used to read current file in the + * \a zip or to write to the file inside it. + * + * \warning Using this constructor for reading current file can be + * tricky. Let's take the following example: + * \code + * QuaZip zip("archive.zip"); + * zip.open(QuaZip::mdUnzip); + * zip.setCurrentFile("file-in-archive"); + * QuaZipFile file(&zip); + * file.open(QIODevice::ReadOnly); + * // ok, now we can read from the file + * file.read(somewhere, some); + * zip.setCurrentFile("another-file-in-archive"); // oops... + * QuaZipFile anotherFile(&zip); + * anotherFile.open(QIODevice::ReadOnly); + * anotherFile.read(somewhere, some); // this is still ok... + * file.read(somewhere, some); // and this is NOT + * \endcode + * So, what exactly happens here? When we change current file in the + * \c zip archive, \c file that references it becomes invalid + * (actually, as far as I understand ZIP/UNZIP sources, it becomes + * closed, but QuaZipFile has no means to detect it). + * + * Summary: do not close \c zip object or change its current file as + * long as QuaZipFile is open. Even better - use another constructors + * which create internal QuaZip instances, one per object, and + * therefore do not cause unnecessary trouble. This constructor may + * be useful, though, if you already have a QuaZip instance and do + * not want to access several files at once. Good example: + * \code + * QuaZip zip("archive.zip"); + * zip.open(QuaZip::mdUnzip); + * // first, we need some information about archive itself + * QByteArray comment=zip.getComment(); + * // and now we are going to access files inside it + * QuaZipFile file(&zip); + * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { + * file.open(QIODevice::ReadOnly); + * // do something cool with file here + * file.close(); // do not forget to close! + * } + * zip.close(); + * \endcode + **/ + QuaZipFile(QuaZip *zip, QObject *parent =NULL); + /// Destroys a QuaZipFile instance. + /** Closes file if open, destructs internal QuaZip object (if it + * exists and \em is internal, of course). + **/ + virtual ~QuaZipFile(); + /// Returns the ZIP archive file name. + /** If this object was created by passing QuaZip pointer to the + * constructor, this function will return that QuaZip's file name + * (or null string if that object does not have file name yet). + * + * Otherwise, returns associated ZIP archive file name or null + * string if there are no name set yet. + * + * \sa setZipName() getFileName() + **/ + QString getZipName()const; + /// Returns a pointer to the associated QuaZip object. + /** Returns \c NULL if there is no associated QuaZip or it is + * internal (so you will not mess with it). + **/ + QuaZip* getZip()const; + /// Returns file name. + /** This function returns file name you passed to this object either + * by using + * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) + * or by calling setFileName(). Real name of the file may differ in + * case if you used case-insensitivity. + * + * Returns null string if there is no file name set yet. This is the + * case when this QuaZipFile operates on the existing QuaZip object + * (constructor QuaZipFile(QuaZip*,QObject*) or setZip() was used). + * + * \sa getActualFileName + **/ + QString getFileName() const; + /// Returns case sensitivity of the file name. + /** This function returns case sensitivity argument you passed to + * this object either by using + * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) + * or by calling setFileName(). + * + * Returns unpredictable value if getFileName() returns null string + * (this is the case when you did not used setFileName() or + * constructor above). + * + * \sa getFileName + **/ + QuaZip::CaseSensitivity getCaseSensitivity() const; + /// Returns the actual file name in the archive. + /** This is \em not a ZIP archive file name, but a name of file inside + * archive. It is not necessary the same name that you have passed + * to the + * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*), + * setFileName() or QuaZip::setCurrentFile() - this is the real file + * name inside archive, so it may differ in case if the file name + * search was case-insensitive. + * + * Equivalent to calling getCurrentFileName() on the associated + * QuaZip object. Returns null string if there is no associated + * QuaZip object or if it does not have a current file yet. And this + * is the case if you called setFileName() but did not open the + * file yet. So this is perfectly fine: + * \code + * QuaZipFile file("somezip.zip"); + * file.setFileName("somefile"); + * QString name=file.getName(); // name=="somefile" + * QString actual=file.getActualFileName(); // actual is null string + * file.open(QIODevice::ReadOnly); + * QString actual=file.getActualFileName(); // actual can be "SoMeFiLe" on Windows + * \endcode + * + * \sa getZipName(), getFileName(), QuaZip::CaseSensitivity + **/ + QString getActualFileName()const; + /// Sets the ZIP archive file name. + /** Automatically creates internal QuaZip object and destroys + * previously created internal QuaZip object, if any. + * + * Will do nothing if this file is already open. You must close() it + * first. + **/ + void setZipName(const QString& zipName); + /// Returns \c true if the file was opened in raw mode. + /** If the file is not open, the returned value is undefined. + * + * \sa open(OpenMode,int*,int*,bool,const char*) + **/ + bool isRaw() const; + /// Binds to the existing QuaZip instance. + /** This function destroys internal QuaZip object, if any, and makes + * this QuaZipFile to use current file in the \a zip object for any + * further operations. See QuaZipFile(QuaZip*,QObject*) for the + * possible pitfalls. + * + * Will do nothing if the file is currently open. You must close() + * it first. + **/ + void setZip(QuaZip *zip); + /// Sets the file name. + /** Will do nothing if at least one of the following conditions is + * met: + * - ZIP name has not been set yet (getZipName() returns null + * string). + * - This QuaZipFile is associated with external QuaZip. In this + * case you should call that QuaZip's setCurrentFile() function + * instead! + * - File is already open so setting the name is meaningless. + * + * \sa QuaZip::setCurrentFile + **/ + void setFileName(const QString& fileName, QuaZip::CaseSensitivity cs =QuaZip::csDefault); + /// Opens a file for reading. + /** Returns \c true on success, \c false otherwise. + * Call getZipError() to get error code. + * + * \note Since ZIP/UNZIP API provides buffered reading only, + * QuaZipFile does not support unbuffered reading. So do not pass + * QIODevice::Unbuffered flag in \a mode, or open will fail. + **/ + virtual bool open(OpenMode mode); + /// Opens a file for reading. + /** \overload + * Argument \a password specifies a password to decrypt the file. If + * it is NULL then this function behaves just like open(OpenMode). + **/ + inline bool open(OpenMode mode, const char *password) + {return open(mode, NULL, NULL, false, password);} + /// Opens a file for reading. + /** \overload + * Argument \a password specifies a password to decrypt the file. + * + * An integers pointed by \a method and \a level will receive codes + * of the compression method and level used. See unzip.h. + * + * If raw is \c true then no decompression is performed. + * + * \a method should not be \c NULL. \a level can be \c NULL if you + * don't want to know the compression level. + **/ + bool open(OpenMode mode, int *method, int *level, bool raw, const char *password =NULL); + /// Opens a file for writing. + /** \a info argument specifies information about file. It should at + * least specify a correct file name. Also, it is a good idea to + * specify correct timestamp (by default, current time will be + * used). See QuaZipNewInfo. + * + * The \a password argument specifies the password for crypting. Pass NULL + * if you don't need any crypting. The \a crc argument was supposed + * to be used for crypting too, but then it turned out that it's + * false information, so you need to set it to 0 unless you want to + * use the raw mode (see below). + * + * Arguments \a method and \a level specify compression method and + * level. The only method supported is Z_DEFLATED, but you may also + * specify 0 for no compression. If all of the files in the archive + * use both method 0 and either level 0 is explicitly specified or + * data descriptor writing is disabled with + * QuaZip::setDataDescriptorWritingEnabled(), then the + * resulting archive is supposed to be compatible with the 1.0 ZIP + * format version, should you need that. Except for this, \a level + * has no other effects with method 0. + * + * If \a raw is \c true, no compression is performed. In this case, + * \a crc and uncompressedSize field of the \a info are required. + * + * Arguments \a windowBits, \a memLevel, \a strategy provide zlib + * algorithms tuning. See deflateInit2() in zlib. + **/ + bool open(OpenMode mode, const QuaZipNewInfo& info, + const char *password =NULL, quint32 crc =0, + int method =Z_DEFLATED, int level =Z_DEFAULT_COMPRESSION, bool raw =false, + int windowBits =-MAX_WBITS, int memLevel =DEF_MEM_LEVEL, int strategy =Z_DEFAULT_STRATEGY); + /// Returns \c true, but \ref quazipfile-sequential "beware"! + virtual bool isSequential()const; + /// Returns current position in the file. + /** Implementation of the QIODevice::pos(). When reading, this + * function is a wrapper to the ZIP/UNZIP unztell(), therefore it is + * unable to keep track of the ungetChar() calls (which is + * non-virtual and therefore is dangerous to reimplement). So if you + * are using ungetChar() feature of the QIODevice, this function + * reports incorrect value until you get back characters which you + * ungot. + * + * When writing, pos() returns number of bytes already written + * (uncompressed unless you use raw mode). + * + * \note Although + * \ref quazipfile-sequential "QuaZipFile is a sequential device" + * and therefore pos() should always return zero, it does not, + * because it would be misguiding. Keep this in mind. + * + * This function returns -1 if the file or archive is not open. + * + * Error code returned by getZipError() is not affected by this + * function call. + **/ + virtual qint64 pos()const; + /// Returns \c true if the end of file was reached. + /** This function returns \c false in the case of error. This means + * that you called this function on either not open file, or a file + * in the not open archive or even on a QuaZipFile instance that + * does not even have QuaZip instance associated. Do not do that + * because there is no means to determine whether \c false is + * returned because of error or because end of file was reached. + * Well, on the other side you may interpret \c false return value + * as "there is no file open to check for end of file and there is + * no end of file therefore". + * + * When writing, this function always returns \c true (because you + * are always writing to the end of file). + * + * Error code returned by getZipError() is not affected by this + * function call. + **/ + virtual bool atEnd()const; + /// Returns file size. + /** This function returns csize() if the file is open for reading in + * raw mode, usize() if it is open for reading in normal mode and + * pos() if it is open for writing. + * + * Returns -1 on error, call getZipError() to get error code. + * + * \note This function returns file size despite that + * \ref quazipfile-sequential "QuaZipFile is considered to be sequential device", + * for which size() should return bytesAvailable() instead. But its + * name would be very misguiding otherwise, so just keep in mind + * this inconsistence. + **/ + virtual qint64 size()const; + /// Returns compressed file size. + /** Equivalent to calling getFileInfo() and then getting + * compressedSize field, but more convenient and faster. + * + * File must be open for reading before calling this function. + * + * Returns -1 on error, call getZipError() to get error code. + **/ + qint64 csize()const; + /// Returns uncompressed file size. + /** Equivalent to calling getFileInfo() and then getting + * uncompressedSize field, but more convenient and faster. See + * getFileInfo() for a warning. + * + * File must be open for reading before calling this function. + * + * Returns -1 on error, call getZipError() to get error code. + **/ + qint64 usize()const; + /// Gets information about current file. + /** This function does the same thing as calling + * QuaZip::getCurrentFileInfo() on the associated QuaZip object, + * but you can not call getCurrentFileInfo() if the associated + * QuaZip is internal (because you do not have access to it), while + * you still can call this function in that case. + * + * File must be open for reading before calling this function. + * + * Returns \c false in the case of an error. + **/ + bool getFileInfo(QuaZipFileInfo *info); + /// Closes the file. + /** Call getZipError() to determine if the close was successful. + **/ + virtual void close(); + /// Returns the error code returned by the last ZIP/UNZIP API call. + int getZipError() const; + /// Returns the number of bytes available for reading. + virtual qint64 bytesAvailable() const; +}; + +#endif diff --git a/depends/quazip/quazipfileinfo.h b/depends/quazip/quazipfileinfo.h new file mode 100644 index 00000000..99540229 --- /dev/null +++ b/depends/quazip/quazipfileinfo.h @@ -0,0 +1,66 @@ +#ifndef QUA_ZIPFILEINFO_H +#define QUA_ZIPFILEINFO_H + +/* +Copyright (C) 2005-2011 Sergey A. Tachenov + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser 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 Lesser +General Public License for more details. + +You should have received a copy of the GNU Lesser 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 + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant, see +quazip/(un)zip.h files for details, basically it's zlib license. + **/ + +#include +#include + +#include "quazip_global.h" + +/// Information about a file inside archive. +/** Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to + * fill this structure. */ +struct QUAZIP_EXPORT QuaZipFileInfo { + /// File name. + QString name; + /// Version created by. + quint16 versionCreated; + /// Version needed to extract. + quint16 versionNeeded; + /// General purpose flags. + quint16 flags; + /// Compression method. + quint16 method; + /// Last modification date and time. + QDateTime dateTime; + /// CRC. + quint32 crc; + /// Compressed file size. + quint32 compressedSize; + /// Uncompressed file size. + quint32 uncompressedSize; + /// Disk number start. + quint16 diskNumberStart; + /// Internal file attributes. + quint16 internalAttr; + /// External file attributes. + quint32 externalAttr; + /// Comment. + QString comment; + /// Extra field. + QByteArray extra; +}; + +#endif diff --git a/depends/quazip/quazipnewinfo.cpp b/depends/quazip/quazipnewinfo.cpp new file mode 100644 index 00000000..ed57e09f --- /dev/null +++ b/depends/quazip/quazipnewinfo.cpp @@ -0,0 +1,51 @@ +/* +Copyright (C) 2005-2011 Sergey A. Tachenov + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser 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 Lesser +General Public License for more details. + +You should have received a copy of the GNU Lesser 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 + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant, see +quazip/(un)zip.h files for details, basically it's zlib license. +*/ + +#include + +#include "quazipnewinfo.h" + + +QuaZipNewInfo::QuaZipNewInfo(const QString& name): + name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0) +{ +} + +QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file): + name(name), internalAttr(0), externalAttr(0) +{ + QFileInfo info(file); + QDateTime lm = info.lastModified(); + if (!info.exists()) + dateTime = QDateTime::currentDateTime(); + else + dateTime = lm; +} + +void QuaZipNewInfo::setFileDateTime(const QString& file) +{ + QFileInfo info(file); + QDateTime lm = info.lastModified(); + if (info.exists()) + dateTime = lm; +} diff --git a/depends/quazip/quazipnewinfo.h b/depends/quazip/quazipnewinfo.h new file mode 100644 index 00000000..62159ea7 --- /dev/null +++ b/depends/quazip/quazipnewinfo.h @@ -0,0 +1,102 @@ +#ifndef QUA_ZIPNEWINFO_H +#define QUA_ZIPNEWINFO_H + +/* +Copyright (C) 2005-2011 Sergey A. Tachenov + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser 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 Lesser +General Public License for more details. + +You should have received a copy of the GNU Lesser 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 + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant, see +quazip/(un)zip.h files for details, basically it's zlib license. + **/ + +#include +#include + +#include "quazip_global.h" + +/// Information about a file to be created. +/** This structure holds information about a file to be created inside + * ZIP archive. At least name should be set to something correct before + * passing this structure to + * QuaZipFile::open(OpenMode,const QuaZipNewInfo&,int,int,bool). + **/ +struct QUAZIP_EXPORT QuaZipNewInfo { + /// File name. + /** This field holds file name inside archive, including path relative + * to archive root. + **/ + QString name; + /// File timestamp. + /** This is the last file modification date and time. Will be stored + * in the archive central directory. It is a good practice to set it + * to the source file timestamp instead of archive creating time. Use + * setFileDateTime() or QuaZipNewInfo(const QString&, const QString&). + **/ + QDateTime dateTime; + /// File internal attributes. + quint16 internalAttr; + /// File external attributes. + quint32 externalAttr; + /// File comment. + /** Will be encoded using QuaZip::getCommentCodec(). + **/ + QString comment; + /// File local extra field. + QByteArray extraLocal; + /// File global extra field. + QByteArray extraGlobal; + /// Uncompressed file size. + /** This is only needed if you are using raw file zipping mode, i. e. + * adding precompressed file in the zip archive. + **/ + ulong uncompressedSize; + /// Constructs QuaZipNewInfo instance. + /** Initializes name with \a name, dateTime with current date and + * time. Attributes are initialized with zeros, comment and extra + * field with null values. + **/ + QuaZipNewInfo(const QString& name); + /// Constructs QuaZipNewInfo instance. + /** Initializes name with \a name and dateTime with timestamp of the + * file named \a file. If the \a file does not exists or its timestamp + * is inaccessible (e. g. you do not have read permission for the + * directory file in), uses current date and time. Attributes are + * initialized with zeros, comment and extra field with null values. + * + * \sa setFileDateTime() + **/ + QuaZipNewInfo(const QString& name, const QString& file); + /// Sets the file timestamp from the existing file. + /** Use this function to set the file timestamp from the existing + * file. Use it like this: + * \code + * QuaZipFile zipFile(&zip); + * QFile file("file-to-add"); + * file.open(QIODevice::ReadOnly); + * QuaZipNewInfo info("file-name-in-archive"); + * info.setFileDateTime("file-to-add"); // take the timestamp from file + * zipFile.open(QIODevice::WriteOnly, info); + * \endcode + * + * This function does not change dateTime if some error occured (e. g. + * file is inaccessible). + **/ + void setFileDateTime(const QString& file); +}; + +#endif diff --git a/depends/quazip/unzip.c b/depends/quazip/unzip.c new file mode 100644 index 00000000..6e115ae6 --- /dev/null +++ b/depends/quazip/unzip.c @@ -0,0 +1,1603 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + Read unzip.h for more info + + Modified by Sergey A. Tachenov to integrate with Qt. +*/ + +/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of +compatibility with older software. The following is from the original crypt.c. Code +woven in by Terry Thorsen 1/2003. +*/ +/* + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html +*/ +/* + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + 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). + */ + + +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#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 + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + + +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_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unzlocal_getByte OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + int *pi; +{ + unsigned char c; + int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unzlocal_getShort OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unzlocal_getLong OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (fileName1,fileName2) + const char* fileName1; + const char* fileName2; +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) + const char* fileName1; + const char* fileName2; + int iCaseSensitivity; +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong unzlocal_SearchCentralDir OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream)); + +local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen2 (file, pzlib_filefunc_def) + voidpf file; + zlib_filefunc_def* pzlib_filefunc_def; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + if (pzlib_filefunc_def==NULL) + fill_qiodevice_filefunc(&us.z_filefunc); + else + us.z_filefunc = *pzlib_filefunc_def; + + us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, + file, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + if (ZSEEK(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(&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 (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + uLong uSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (ZSEEK(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) { + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + uSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + uSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + uSeek=0; + else + err=UNZ_ERRNO; + } + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + uSeek += file_info.size_file_extra - uSizeRead; + } + else + uSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + uSeek=0; + else + err=UNZ_ERRNO; + } + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + uSeek+=file_info.size_file_comment - uSizeRead; + } + else + uSeek+=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; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo (file, + pfile_info, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_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; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_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 = unzlocal_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; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) + unzFile file; + const char *szFileName; + int iCaseSensitivity; +{ + unz_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info cur_file_infoSaved; + unz_file_info_internal cur_file_info_internalSaved; + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; // offset in file + uLong num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_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 unzGoToFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_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 = unzlocal_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; +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + 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 unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) { + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_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 += (uInt)size_filename; + + if (unzlocal_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 = (uInt)size_extra_field; + + *piSizeVar += (uInt)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 (file, method, level, raw, password) + unzFile file; + int* method; + int* level; + int raw; + const char* password; +{ + int err=UNZ_OK; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)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; + + if (method!=NULL) + *method = (int)s->cur_file_info.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 ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.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->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_DEFLATED) && + (!raw)) + { + 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=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + 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 = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD(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->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (file) + unzFile file; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (file, password) + unzFile file; + const char* password; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw) + 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 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 unzReadCurrentFile (file, buf, len) + unzFile file; + voidp buf; + unsigned len; +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->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(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + 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 that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + 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) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern uLong ZEXPORT unzGetOffset (file) + unzFile file; +{ + unz_s* s; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_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 (file, pos) + unzFile file; + uLong pos; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unzlocal_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; +} diff --git a/depends/quazip/unzip.h b/depends/quazip/unzip.h new file mode 100644 index 00000000..33c9dc1a --- /dev/null +++ b/depends/quazip/unzip.h @@ -0,0 +1,356 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + + Multi volume ZipFile (span) are not supported. + Encryption compatible with pkzip 2.04g only supported + Old compressions used by old PKZip 1.x are not supported + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Modified by Sergey A. Tachenov to integrate with Qt. + + +*/ + +/* for more info about .ZIP format, see + http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip + http://www.info-zip.org/pub/infozip/doc/ + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip +*/ + +#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 + +#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 +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt 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_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + 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_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; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((voidpf file)); +/* + Open a Zip file. path contain whatever zopen_file from the IO API + accepts. For Qt implementation it is a pointer to QIODevice, for + fopen() implementation it's a file name. + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern unzFile ZEXPORT unzOpen2 OF((voidpf file, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +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( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for 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. + If there is no error, the return value is UNZ_OK. +*/ + +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 + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than 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 than 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 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 +*/ + +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 z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +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. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */ diff --git a/depends/quazip/zip.c b/depends/quazip/zip.c new file mode 100644 index 00000000..bf8c0a10 --- /dev/null +++ b/depends/quazip/zip.c @@ -0,0 +1,1281 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.01e, February 12th, 2005 + + 27 Dec 2004 Rolf Kalbermatter + Modification to zipOpen2 to support globalComment retrieval. + + Copyright (C) 1998-2005 Gilles Vollant + + Read zip.h for more info + + Modified by Sergey A. Tachenov to integrate with Qt. +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" +#include "quazip_global.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x031e) /* best for standard pkware crypt */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (16384) +#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 + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#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"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define DESCRIPTORHEADERMAGIC (0x08074b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +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 alignement */ + 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 */ + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + uLong pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralheader; /* size of the central header for cur file */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + 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 encrypt; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile_info; + +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + 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.*/ + curfile_info ci; /* info on the file curretly writing */ + + uLong begin_pos; /* position of the beginning of the zipfile */ + uLong add_position_when_writting_offset; + uLong number_entry; +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif + unsigned flags; +} zip_internal; + + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +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; +} + +local void free_datablock(ldi) + linkedlist_datablock_internal* ldi; +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(ll) + linkedlist_data* ll; +{ + ll->first_block = ll->last_block = NULL; +} + +#if 0 // unused +local void free_linkedlist(ll) + linkedlist_data* ll; +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} +#endif + +local int add_data_in_datablock(ll,buf,len) + 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) + { + uInt copy_this; + uInt 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 = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 or 4 (byte, short or long) +*/ + +local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, uLong x, int nbByte)); +local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong x; + int nbByte; +{ + unsigned char buf[4]; + 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 (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); +local void ziplocal_putValue_inmemory (dest, x, nbByte) + void* dest; + uLong 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 uLong ziplocal_TmzDateToDosDate(ptm,dosDate) + const tm_zip* ptm; + uLong dosDate UNUSED; +{ + uLong year = (uLong)ptm->tm_year; + if (year>1980) + year-=1980; + else if (year>80) + year-=80; + 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)); +} + + +/****************************************************************************/ + +local int ziplocal_getByte OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int ziplocal_getByte(pzlib_filefunc_def,filestream,pi) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + int *pi; +{ + unsigned char c; + int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int ziplocal_getShort OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int ziplocal_getLong OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong ziplocal_SearchCentralDir OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream)); + +local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + +/************************************************************/ +extern zipFile ZEXPORT zipOpen2 (file, append, globalcomment, pzlib_filefunc_def) + voidpf file; + int append; + zipcharpc* globalcomment; + zlib_filefunc_def* pzlib_filefunc_def; +{ + zip_internal ziinit; + zip_internal* zi; + int err=ZIP_OK; + + + if (pzlib_filefunc_def==NULL) + fill_qiodevice_filefunc(&ziinit.z_filefunc); + else + ziinit.z_filefunc = *pzlib_filefunc_def; + + ziinit.filestream = (*(ziinit.z_filefunc.zopen_file)) + (ziinit.z_filefunc.opaque, + file, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + ziinit.begin_pos = ZTELL(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; + ziinit.flags = ZIP_WRITE_DATA_DESCRIPTOR; + init_linkedlist(&(ziinit.central_dir)); + + + zi = (zip_internal*)ALLOC(sizeof(zip_internal)); + if (zi==NULL) + { + ZCLOSE(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory */ + uLong central_pos,uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry; + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong size_comment; + + central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); + if (central_pos==0) + err=ZIP_ERRNO; + + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (ziplocal_getLong(&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 (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* zipfile global comment length */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((central_pos0) + { + ziinit.globalcomment = ALLOC(size_comment+1); + if (ziinit.globalcomment) + { + size_comment = ZREAD(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; + + { + uLong size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK(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)) + { + uLong read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,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 (ZSEEK(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 /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen (file, append) + voidpf file; + int append; +{ + return zipOpen2(file,append,NULL,NULL); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; + int windowBits; + int memLevel; + int strategy; + const char* password; + uLong crcForCrypting; +{ + zip_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + uLong version_to_extract; + +# ifdef NOCRYPT + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; + + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + if (method == 0 + && (level == 0 || (zi->flags & ZIP_WRITE_DATA_DESCRIPTOR) == 0)) + { + version_to_extract = 10; + } + else + { + version_to_extract = 20; + } + + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); + } + + zi->ci.flag = 0; + 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; + } + if (version_to_extract >= 20 + && (zi->flags & ZIP_WRITE_DATA_DESCRIPTOR) != 0) + zi->ci.flag |= 8; + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ; + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + + size_extrafield_global + size_comment; + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); + + ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2); + ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)version_to_extract,2); + ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + /* write the local header */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)version_to_extract,2); + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2); + + if ((err==ZIP_OK) && (size_filename>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + + if ((err==ZIP_OK) && (size_extrafield_local>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local) + !=size_extrafield_local) + err = ZIP_ERRNO; + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, + Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = 1; + } +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + crcForCrypting = (uLong)zi->ci.dosDate << 16; // ATTANTION! Without this row, you don't unpack your password protected archive in other app. + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE(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 zipOpenNewFileInZip2(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; +{ + return zipOpenNewFileInZip3 (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); +} + +extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; +{ + return zipOpenNewFileInZip2 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0); +} + +local int zipFlushWriteBuffer(zi) + zip_internal* zi; +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.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 + } + if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) + !=zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + zi->ci.pos_in_buffered_data = 0; + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (file, buf, len) + zipFile file; + const void* buf; + unsigned len; +{ + zip_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.stream.next_in = (void*)buf; + zi->ci.stream.avail_in = len; + zi->ci.crc32 = crc32(zi->ci.crc32,buf,len); + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + + } + else + { + uInt 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;ici.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 (file, uncompressed_size, crc32) + zipFile file; + uLong uncompressed_size; + uLong crc32; +{ + zip_internal* zi; + uLong compressed_size; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + if (zipFlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + err=deflateEnd(&zi->ci.stream); + zi->ci.stream_initialised = 0; + } + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = (uLong)zi->ci.stream.total_in; + } + compressed_size = (uLong)zi->ci.stream.total_out; +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20, + compressed_size,4); /*compr size*/ + if (zi->ci.stream.data_type == Z_ASCII) + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + ziplocal_putValue_inmemory(zi->ci.central_header+24, + uncompressed_size,4); /*uncompr size*/ + + 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) + { + uLong cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); + if (ZSEEK(zi->z_filefunc,zi->filestream, + zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if (err==ZIP_OK) /* compressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + + if (ZSEEK(zi->z_filefunc,zi->filestream, + cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if ((zi->ci.flag & 8) != 0) { + /* Write local Descriptor after file data */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)DESCRIPTORHEADERMAGIC,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if (err==ZIP_OK) /* compressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + } + + + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (file) + zipFile file; +{ + return zipCloseFileInZipRaw (file,0,0); +} + +extern int ZEXPORT zipClose (file, global_comment) + zipFile file; + const char* global_comment; +{ + zip_internal* zi; + int err = 0; + uLong size_centraldir = 0; + uLong centraldir_pos_inzip; + uInt size_global_comment; + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_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 (global_comment==NULL) + size_global_comment = 0; + else + size_global_comment = (uInt)strlen(global_comment); + + centraldir_pos_inzip = ZTELL(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)) + if (ZWRITE(zi->z_filefunc,zi->filestream, + ldi->data,ldi->filled_in_this_block) + !=ldi->filled_in_this_block ) + err = ZIP_ERRNO; + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_datablock(zi->central_dir.first_block); + + if (err==ZIP_OK) /* Magic End */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* size of the central directory */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the + starting disk number */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream, + (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + + if (err==ZIP_OK) /* zipfile comment length */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if ((err==ZIP_OK) && (size_global_comment>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream, + global_comment,size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + + if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} + +extern int ZEXPORT zipSetFlags(zipFile file, unsigned flags) +{ + zip_internal* zi; + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + zi->flags |= flags; + return ZIP_OK; +} + +extern int ZEXPORT zipClearFlags(zipFile file, unsigned flags) +{ + zip_internal* zi; + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + zi->flags &= ~flags; + return ZIP_OK; +} diff --git a/depends/quazip/zip.h b/depends/quazip/zip.h new file mode 100644 index 00000000..269ec2da --- /dev/null +++ b/depends/quazip/zip.h @@ -0,0 +1,245 @@ +/* zip.h -- IO for compress .zip files using zlib + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This unzip package allow creates .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Multi volume ZipFile (span) are not supported. + Encryption compatible with pkzip 2.04g only supported + Old compressions used by old PKZip 1.x are not supported + + For uncompress .zip file, look at unzip.h + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.html for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Modified by Sergey A. Tachenov to integrate with Qt. + + +*/ + +/* for more info about .ZIP format, see + http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip + http://www.info-zip.org/pub/infozip/doc/ + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip +*/ + +#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 + +#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) + +#define ZIP_WRITE_DATA_DESCRIPTOR 0x8u + +#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 +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt 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 flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((voidpf file, int append)); +/* + Create a zipfile. + file is whatever the IO API accepts. For Qt IO API it's a pointer to + QIODevice. For fopen() IO API it's a file name (const char*). + 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) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* 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 couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((voidpf file, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt 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 + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the 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) +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCtypting)); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCtypting : crc of file to compress (needed for crypting) + */ + + +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)); +/* + Close the current file in the zipfile, for fiel 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 +*/ + +/* + Added by Sergey A. Tachenov to tweak zipping behaviour. + */ +extern int ZEXPORT zipSetFlags(zipFile file, unsigned flags); +extern int ZEXPORT zipClearFlags(zipFile file, unsigned flags); + +#ifdef __cplusplus +} +#endif + +#endif /* _zip_H */ diff --git a/depends/settings/CMakeLists.txt b/depends/settings/CMakeLists.txt new file mode 100644 index 00000000..e5aae0b7 --- /dev/null +++ b/depends/settings/CMakeLists.txt @@ -0,0 +1,51 @@ +project(libSettings) + +# Find Qt +find_package(Qt5Core REQUIRED) + +# Include Qt headers. +include_directories(${Qt5Base_INCLUDE_DIRS}) +include_directories(${Qt5Network_INCLUDE_DIRS}) + +SET(LIBSETTINGS_HEADERS +include/libsettings_config.h + +include/inifile.h + +include/settingsobject.h +include/setting.h +include/overridesetting.h + +include/basicsettingsobject.h +include/inisettingsobject.h + +include/keyring.h +) + +SET(LIBSETTINGS_HEADERS_PRIVATE +src/stubkeyring.h +) + +SET(LIBSETTINGS_SOURCES +src/inifile.cpp + +src/settingsobject.cpp +src/setting.cpp +src/overridesetting.cpp + +src/basicsettingsobject.cpp +src/inisettingsobject.cpp + +src/keyring.cpp +src/stubkeyring.cpp +) + +# Set the include dir path. +SET(LIBSETTINGS_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE) +include_directories(${LIBSETTINGS_INCLUDE_DIR}) + +add_definitions(-DLIBSETTINGS_LIBRARY) + +add_library(libSettings SHARED ${LIBSETTINGS_SOURCES} ${LIBSETTINGS_HEADERS} ${LIBSETTINGS_HEADERS_PRIVATE}) +qt5_use_modules(libSettings Core) +target_link_libraries(libSettings) diff --git a/depends/settings/include/basicsettingsobject.h b/depends/settings/include/basicsettingsobject.h new file mode 100644 index 00000000..b7e5851d --- /dev/null +++ b/depends/settings/include/basicsettingsobject.h @@ -0,0 +1,44 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASICSETTINGSOBJECT_H +#define BASICSETTINGSOBJECT_H + +#include +#include + +#include "settingsobject.h" + +#include "libsettings_config.h" + +/*! + * \brief A settings object that stores its settings in a QSettings object. + */ +class LIBSETTINGS_EXPORT BasicSettingsObject : public SettingsObject +{ + Q_OBJECT +public: + explicit BasicSettingsObject(QObject *parent = 0); + +protected slots: + virtual void changeSetting(const Setting &setting, QVariant value); + +protected: + virtual QVariant retrieveValue(const Setting &setting); + + QSettings config; +}; + +#endif // BASICSETTINGSOBJECT_H diff --git a/depends/settings/include/inifile.h b/depends/settings/include/inifile.h new file mode 100644 index 00000000..94467832 --- /dev/null +++ b/depends/settings/include/inifile.h @@ -0,0 +1,38 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INIFILE_H +#define INIFILE_H + +#include +#include +#include + +#include "libsettings_config.h" + +// Sectionless INI parser (for instance config files) +class LIBSETTINGS_EXPORT INIFile : public QMap +{ +public: + explicit INIFile(); + + bool loadFile(QString fileName); + bool saveFile(QString fileName); + + QVariant get(QString key, QVariant def) const; + void set(QString key, QVariant val); +}; + +#endif // INIFILE_H diff --git a/depends/settings/include/inisettingsobject.h b/depends/settings/include/inisettingsobject.h new file mode 100644 index 00000000..03d6fe05 --- /dev/null +++ b/depends/settings/include/inisettingsobject.h @@ -0,0 +1,60 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INISETTINGSOBJECT_H +#define INISETTINGSOBJECT_H + +#include + +#include "inifile.h" + +#include "settingsobject.h" + +#include "libutil_config.h" + +/*! + * \brief A settings object that stores its settings in an INIFile. + */ +class LIBSETTINGS_EXPORT INISettingsObject : public SettingsObject +{ + Q_OBJECT +public: + explicit INISettingsObject(const QString &path, QObject *parent = 0); + + /*! + * \brief Gets the path to the INI file. + * \return The path to the INI file. + */ + virtual QString filePath() const { return m_filePath; } + + /*! + * \brief Sets the path to the INI file and reloads it. + * \param filePath The INI file's new path. + */ + virtual void setFilePath(const QString &filePath); + +protected slots: + virtual void changeSetting(const Setting &setting, QVariant value); + virtual void resetSetting ( const Setting& setting ); + +protected: + virtual QVariant retrieveValue(const Setting &setting); + + INIFile m_ini; + + QString m_filePath; +}; + +#endif // INISETTINGSOBJECT_H diff --git a/depends/settings/include/keyring.h b/depends/settings/include/keyring.h new file mode 100644 index 00000000..299b14b0 --- /dev/null +++ b/depends/settings/include/keyring.h @@ -0,0 +1,92 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KEYRING_H +#define KEYRING_H + +#include + +#include "libsettings_config.h" + +/** + * @file libsettings/include/keyring.h + * Access to System Keyrings + */ + +/** + * @brief The Keyring class + * the System Keyring/Keychain/Wallet/Vault/etc + */ +class LIBSETTINGS_EXPORT Keyring +{ +public: + /** + * @brief the System Keyring instance + * @return the Keyring instance + */ + static Keyring *instance(); + + /** + * @brief store a password in the Keyring + * @param service the service name + * @param username the account name + * @param password the password to store + * @return success + */ + virtual bool storePassword(QString service, QString username, QString password) = 0; + + /** + * @brief get a password from the Keyring + * @param service the service name + * @param username the account name + * @return the password (success=!isNull()) + */ + virtual QString getPassword(QString service, QString username) = 0; + + /** + * @brief lookup a password + * @param service the service name + * @param username the account name + * @return wether the password is available + */ + virtual bool hasPassword(QString service, QString username) = 0; + + /** + * @brief get a list of all stored accounts. + * @param service the service name + * @return + */ + virtual QStringList getStoredAccounts(QString service) = 0; + + /** + * @brief Remove the specified account from storage + * @param service the service name + * @param username the account name + * @return + */ + virtual void removeStoredAccount(QString service, QString username) = 0; + +protected: + /// fall back to StubKeyring if false + virtual bool isValid() { return false; } + +private: + static Keyring *m_instance; + static void destroy(); +}; + +#endif // KEYRING_H diff --git a/depends/settings/include/libsettings_config.h b/depends/settings/include/libsettings_config.h new file mode 100644 index 00000000..dc8e6228 --- /dev/null +++ b/depends/settings/include/libsettings_config.h @@ -0,0 +1,27 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBINSTANCE_CONFIG_H +#define LIBINSTANCE_CONFIG_H + +#include + +#ifdef LIBSETTINGS_LIBRARY +# define LIBSETTINGS_EXPORT Q_DECL_EXPORT +#else +# define LIBSETTINGS_EXPORT Q_DECL_IMPORT +#endif + +#endif // LIBINSTANCE_CONFIG_H diff --git a/depends/settings/include/overridesetting.h b/depends/settings/include/overridesetting.h new file mode 100644 index 00000000..58bb6d40 --- /dev/null +++ b/depends/settings/include/overridesetting.h @@ -0,0 +1,43 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVERRIDESETTING_H +#define OVERRIDESETTING_H + +#include + +#include "setting.h" + +#include "libsettings_config.h" + +/*! + * \brief A setting that 'overrides another.' + * This means that the setting's default value will be the value of another setting. + * The other setting can be (and usually is) a part of a different SettingsObject + * than this one. + */ +class LIBSETTINGS_EXPORT OverrideSetting : public Setting +{ + Q_OBJECT +public: + explicit OverrideSetting(const QString &name, Setting *other, QObject *parent = 0); + + virtual QVariant defValue() const; + +protected: + Setting *m_other; +}; + +#endif // OVERRIDESETTING_H diff --git a/depends/settings/include/setting.h b/depends/settings/include/setting.h new file mode 100644 index 00000000..a161ab50 --- /dev/null +++ b/depends/settings/include/setting.h @@ -0,0 +1,114 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SETTING_H +#define SETTING_H + +#include +#include + +#include "libsettings_config.h" + +class SettingsObject; + +/*! + * + */ +class LIBSETTINGS_EXPORT Setting : public QObject +{ + Q_OBJECT +public: + /*! + * \brief Constructs a new Setting object with the given parent. + * \param parent The Setting's parent object. + */ + explicit Setting(QString id, QVariant defVal = QVariant(), QObject *parent = 0); + + /*! + * \brief Gets this setting's ID. + * This is used to refer to the setting within the application. + * \warning Changing the ID while the setting is registered with a SettingsObject results in undefined behavior. + * \return The ID of the setting. + */ + virtual QString id() const { return m_id; } + + /*! + * \brief Gets this setting's config file key. + * This is used to store the setting's value in the config file. It is usually + * the same as the setting's ID, but it can be different. + * \return The setting's config file key. + */ + virtual QString configKey() const { return id(); } + + /*! + * \brief Gets this setting's value as a QVariant. + * This is done by calling the SettingsObject's retrieveValue() function. + * If this Setting doesn't have a SettingsObject, this returns an invalid QVariant. + * \return QVariant containing this setting's value. + * \sa value() + */ + virtual QVariant get() const; + + /*! + * \brief Gets this setting's actual value (I.E. not as a QVariant). + * This function is just shorthand for get().value() + * \return The setting's actual value. + */ + template + inline T value() const { return get().value(); } + + + /*! + * \brief Gets this setting's default value. + * \return The default value of this setting. + */ + virtual QVariant defValue() const; + +signals: + /*! + * \brief Signal emitted when this Setting object's value changes. + * \param setting A reference to the Setting that changed. + * \param value This Setting object's new value. + */ + void settingChanged(const Setting &setting, QVariant value); + + /*! + * \brief Signal emitted when this Setting object's value resets to default. + * \param setting A reference to the Setting that changed. + */ + void settingReset(const Setting &setting); + +public slots: + /*! + * \brief Changes the setting's value. + * This is done by emitting the settingChanged() signal which will then be + * handled by the SettingsObject object and cause the setting to change. + * \param value The new value. + */ + virtual void set(QVariant value); + + /*! + * \brief Reset the setting to default + * This is done by emitting the settingReset() signal which will then be + * handled by the SettingsObject object and cause the setting to change. + * \param value The new value. + */ + virtual void reset(); +protected: + QString m_id; + QVariant m_defVal; +}; + +#endif // SETTING_H diff --git a/depends/settings/include/settingsobject.h b/depends/settings/include/settingsobject.h new file mode 100644 index 00000000..a2f03699 --- /dev/null +++ b/depends/settings/include/settingsobject.h @@ -0,0 +1,192 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SETTINGSOBJECT_H +#define SETTINGSOBJECT_H + +#include +#include + +#include "libsettings_config.h" + +class Setting; + +/*! + * \brief The SettingsObject handles communicating settings between the application and a settings file. + * The class keeps a list of Setting objects. Each Setting object represents one + * of the application's settings. These Setting objects are registered with + * a SettingsObject and can be managed similarly to the way a list works. + * + * \author Andrew Okin + * \date 2/22/2013 + * + * \sa Setting + */ +class LIBSETTINGS_EXPORT SettingsObject : public QObject +{ + Q_OBJECT +public: + explicit SettingsObject(QObject *parent = 0); + + /*! + * \brief Registers the given setting with this SettingsObject and connects the necessary signals. + * This will fail if there is already a setting with the same ID as + * the one that is being registered. + * \note Registering a setting object causes the SettingsObject to take ownership + * of the object. This means that setting's parent will be set to the object + * it was registered with. Because the object it was registered with has taken + * ownership, it becomes responsible for managing that setting object's memory. + * \warning Do \b not delete the setting after registering it. + * \param setting A pointer to the setting that will be registered. + * \return True if successful. False if registry failed. + */ + virtual bool registerSetting(Setting *setting); + + /*! + * \brief Unregisters the given setting from this SettingsObject and disconnects its signals. + * \note This does not delete the setting. Furthermore, when the setting is + * unregistered, the SettingsObject drops ownership of the setting. This means + * that if you unregister a setting, its parent is set to null and you become + * responsible for freeing its memory. + * \param setting The setting to unregister. + */ + virtual void unregisterSetting(Setting *setting); + + + /*! + * \brief Gets the setting with the given ID. + * \param id The ID of the setting to get. + * \return A pointer to the setting with the given ID. + * Returns null if there is no setting with the given ID. + * \sa operator []() + */ + virtual Setting *getSetting(const QString &id) const; + + /*! + * \brief Same as getSetting() + * \param id The ID of the setting to get. + * \return A pointer to the setting with the given ID. + * \sa getSetting() + */ + inline Setting *operator [](const QString &id) { return getSetting(id); } + + + /*! + * \brief Gets the value of the setting with the given ID. + * \param id The ID of the setting to get. + * \return The setting's value as a QVariant. + * If no setting with the given ID exists, returns an invalid QVariant. + */ + virtual QVariant get(const QString &id) const; + + /*! + * \brief Sets the value of the setting with the given ID. + * If no setting with the given ID exists, returns false and logs to qDebug + * \param id The ID of the setting to change. + * \param value The new value of the setting. + * \return True if successful, false if it failed. + */ + virtual bool set(const QString &id, QVariant value); + + /*! + * \brief Reverts the setting with the given ID to default. + * \param id The ID of the setting to reset. + */ + virtual void reset(const QString &id) const; + + /*! + * \brief Gets a QList with pointers to all of the registered settings. + * The order of the entries in the list is undefined. + * \return A QList with pointers to all registered settings. + */ + virtual QList getSettings(); + + /*! + * \brief Checks if this SettingsObject contains a setting with the given ID. + * \param id The ID to check for. + * \return True if the SettingsObject has a setting with the given ID. + */ + virtual bool contains(const QString &id); + +signals: + /*! + * \brief Signal emitted when one of this SettingsObject object's settings changes. + * This is usually just connected directly to each Setting object's + * settingChanged() signals. + * \param setting A reference to the Setting object that changed. + * \param value The Setting object's new value. + */ + void settingChanged(const Setting &setting, QVariant value); + + /*! + * \brief Signal emitted when one of this SettingsObject object's settings resets. + * This is usually just connected directly to each Setting object's + * settingReset() signals. + * \param setting A reference to the Setting object that changed. + */ + void settingReset(const Setting &setting); + +protected slots: + /*! + * \brief Changes a setting. + * This slot is usually connected to each Setting object's + * settingChanged() signal. The signal is emitted, causing this slot + * to update the setting's value in the config file. + * \param setting A reference to the Setting object that changed. + * \param value The setting's new value. + */ + virtual void changeSetting(const Setting &setting, QVariant value) = 0; + + /*! + * \brief Resets a setting. + * This slot is usually connected to each Setting object's + * settingReset() signal. The signal is emitted, causing this slot + * to update the setting's value in the config file. + * \param setting A reference to the Setting object that changed. + */ + virtual void resetSetting(const Setting &setting) = 0; + +protected: + /*! + * \brief Connects the necessary signals to the given Setting. + * \param setting The setting to connect. + */ + virtual void connectSignals(const Setting &setting); + + /*! + * \brief Disconnects signals from the given Setting. + * \param setting The setting to disconnect. + */ + virtual void disconnectSignals(const Setting &setting); + + /*! + * \brief Function used by Setting objects to get their values from the SettingsObject. + * \param setting The + * \return + */ + virtual QVariant retrieveValue(const Setting &setting) = 0; + + friend class Setting; + +private: + QMap m_settings; +}; + +/*! + * \brief A global settings object. + */ +LIBSETTINGS_EXPORT extern SettingsObject *globalSettings; + +#endif // SETTINGSOBJECT_H diff --git a/depends/settings/src/basicsettingsobject.cpp b/depends/settings/src/basicsettingsobject.cpp new file mode 100644 index 00000000..484928c8 --- /dev/null +++ b/depends/settings/src/basicsettingsobject.cpp @@ -0,0 +1,46 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/basicsettingsobject.h" +#include "include/setting.h" + +BasicSettingsObject::BasicSettingsObject(QObject *parent) : + SettingsObject(parent) +{ + +} + +void BasicSettingsObject::changeSetting(const Setting &setting, QVariant value) +{ + if (contains(setting.id())) + { + if(value.isValid()) + config.setValue(setting.configKey(), value); + else + config.remove(setting.configKey()); + } +} + +QVariant BasicSettingsObject::retrieveValue(const Setting &setting) +{ + if (contains(setting.id())) + { + return config.value(setting.configKey()); + } + else + { + return QVariant(); + } +} diff --git a/depends/settings/src/inifile.cpp b/depends/settings/src/inifile.cpp new file mode 100644 index 00000000..43545a4a --- /dev/null +++ b/depends/settings/src/inifile.cpp @@ -0,0 +1,86 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/inifile.h" + +#include +#include +#include + +INIFile::INIFile() +{ + +} + +bool INIFile::saveFile(QString fileName) +{ + // TODO Handle errors. + QFile file(fileName); + file.open(QIODevice::WriteOnly); + QTextStream out(&file); + + for (Iterator iter = begin(); iter != end(); iter++) + { + out << iter.key() << "=" << iter.value().toString() << "\n"; + } + + return true; +} + +bool INIFile::loadFile(QString fileName) +{ + // TODO Handle errors. + QFile file(fileName); + file.open(QIODevice::ReadOnly); + QTextStream in(&file); + + QStringList lines = in.readAll().split('\n'); + for (int i = 0; i < lines.count(); i++) + { + QString & lineRaw = lines[i]; + // Ignore comments. + QString line = lineRaw.left(lineRaw.indexOf('#')).trimmed(); + + int eqPos = line.indexOf('='); + if(eqPos == -1) + continue; + QString key = line.left(eqPos).trimmed(); + QString valueStr = line.right(line.length() - eqPos - 1).trimmed(); + + QVariant value(valueStr); + /* + QString dbg = key; + dbg += " = "; + dbg += valueStr; + qDebug(dbg.toLocal8Bit()); + */ + this->operator [](key) = value; + } + + return true; +} + +QVariant INIFile::get(QString key, QVariant def) const +{ + if (!this->contains(key)) + return def; + else + return this->operator [](key); +} + +void INIFile::set(QString key, QVariant val) +{ + this->operator [](key) = val; +} diff --git a/depends/settings/src/inisettingsobject.cpp b/depends/settings/src/inisettingsobject.cpp new file mode 100644 index 00000000..854421b6 --- /dev/null +++ b/depends/settings/src/inisettingsobject.cpp @@ -0,0 +1,62 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/inisettingsobject.h" +#include "include/setting.h" + +INISettingsObject::INISettingsObject(const QString &path, QObject *parent) : + SettingsObject(parent) +{ + m_filePath = path; + m_ini.loadFile(path); +} + +void INISettingsObject::setFilePath(const QString &filePath) +{ + m_filePath = filePath; +} + +void INISettingsObject::changeSetting(const Setting &setting, QVariant value) +{ + if (contains(setting.id())) + { + if(value.isValid()) + m_ini.set(setting.configKey(), value); + else + m_ini.remove(setting.configKey()); + m_ini.saveFile(m_filePath); + } +} + +void INISettingsObject::resetSetting ( const Setting& setting ) +{ + if (contains(setting.id())) + { + m_ini.remove(setting.configKey()); + m_ini.saveFile(m_filePath); + } +} + +QVariant INISettingsObject::retrieveValue(const Setting &setting) +{ + if (contains(setting.id())) + { + return m_ini.get(setting.configKey(), QVariant()); + } + else + { + return QVariant(); + } +} diff --git a/depends/settings/src/keyring.cpp b/depends/settings/src/keyring.cpp new file mode 100644 index 00000000..9eaba684 --- /dev/null +++ b/depends/settings/src/keyring.cpp @@ -0,0 +1,63 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/keyring.h" + +#include "osutils.h" + +#include "stubkeyring.h" + +// system specific keyrings +/*#if defined(OSX) +class OSXKeychain; +#define KEYRING OSXKeychain +#elif defined(LINUX) +class XDGKeyring; +#define KEYRING XDGKeyring +#elif defined(WINDOWS) +class Win32Keystore; +#define KEYRING Win32Keystore +#else +#pragma message Keyrings are not supported on your os. Falling back to the insecure StubKeyring +#endif*/ + +Keyring *Keyring::instance() +{ + if (m_instance == nullptr) + { +#ifdef KEYRING + m_instance = new KEYRING(); + if (!m_instance->isValid()) + { + qWarning("Could not create SystemKeyring! falling back to StubKeyring."); + m_instance = new StubKeyring(); + } +#else + qWarning("Keyrings are not supported on your OS. Fallback StubKeyring is insecure!"); + m_instance = new StubKeyring(); +#endif + atexit(Keyring::destroy); + } + return m_instance; +} + +void Keyring::destroy() +{ + delete m_instance; +} + +Keyring *Keyring::m_instance; diff --git a/depends/settings/src/overridesetting.cpp b/depends/settings/src/overridesetting.cpp new file mode 100644 index 00000000..eafb298f --- /dev/null +++ b/depends/settings/src/overridesetting.cpp @@ -0,0 +1,30 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/overridesetting.h" + +OverrideSetting::OverrideSetting(const QString &name, Setting *other, QObject *parent) : + Setting(name, QVariant(), parent) +{ + m_other = other; +} + +QVariant OverrideSetting::defValue() const +{ + if (m_other) + return m_other->get(); + else + return QVariant(); +} diff --git a/depends/settings/src/setting.cpp b/depends/settings/src/setting.cpp new file mode 100644 index 00000000..8e60af06 --- /dev/null +++ b/depends/settings/src/setting.cpp @@ -0,0 +1,54 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/setting.h" +#include "include/settingsobject.h" + +Setting::Setting(QString id, QVariant defVal, QObject *parent) : + QObject(parent), m_id(id), m_defVal(defVal) +{ + +} + +QVariant Setting::get() const +{ + SettingsObject *sbase = qobject_cast(parent()); + if (!sbase) + { + return defValue(); + } + else + { + QVariant test = sbase->retrieveValue(*this); + if(!test.isValid()) + return defValue(); + return test; + } +} + +QVariant Setting::defValue() const +{ + return m_defVal; +} + +void Setting::set(QVariant value) +{ + emit settingChanged(*this, value); +} + +void Setting::reset() +{ + emit settingReset(*this); +} diff --git a/depends/settings/src/settingsobject.cpp b/depends/settings/src/settingsobject.cpp new file mode 100644 index 00000000..bf7b8825 --- /dev/null +++ b/depends/settings/src/settingsobject.cpp @@ -0,0 +1,144 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/settingsobject.h" +#include "include/setting.h" + +#include + +SettingsObject *globalSettings; + +SettingsObject::SettingsObject(QObject *parent) : + QObject(parent) +{ + +} + +bool SettingsObject::registerSetting(Setting *setting) +{ + // Check if setting is null or we already have a setting with the same ID. + if (!setting) + { + qDebug(QString("Failed to register setting. Setting is null."). + arg(setting->id()).toUtf8()); + return false; // Fail + } + + if (contains(setting->id())) + { + qDebug(QString("Failed to register setting %1. ID already exists."). + arg(setting->id()).toUtf8()); + return false; // Fail + } + + m_settings.insert(setting->id(), setting); + setting->setParent(this); // Take ownership. + + // Connect signals. + connectSignals(*setting); + + // qDebug(QString("Registered setting %1.").arg(setting->id()).toUtf8()); + return true; +} + +void SettingsObject::unregisterSetting(Setting *setting) +{ + if (!setting || !m_settings.contains(setting->id())) + return; // We can't unregister something that's not registered. + + m_settings.remove(setting->id()); + + // Disconnect signals. + disconnectSignals(*setting); + + setting->setParent(NULL); // Drop ownership. +} + + +Setting *SettingsObject::getSetting(const QString &id) const +{ + // Make sure there is a setting with the given ID. + if (!m_settings.contains(id)) + return NULL; + + return m_settings[id]; +} + +QVariant SettingsObject::get(const QString &id) const +{ + Setting *setting = getSetting(id); + return (setting ? setting->get() : QVariant()); +} + +bool SettingsObject::set(const QString &id, QVariant value) +{ + Setting *setting = getSetting(id); + if (!setting) + { + qDebug(QString("Error changing setting %1. Setting doesn't exist."). + arg(id).toUtf8()); + return false; + } + else + { + setting->set(value); + return true; + } +} + +void SettingsObject::reset(const QString &id) const +{ + Setting *setting = getSetting(id); + if(setting) + setting->reset(); +} + + +QList SettingsObject::getSettings() +{ + return m_settings.values(); +} + +bool SettingsObject::contains(const QString &id) +{ + return m_settings.contains(id); +} + + +void SettingsObject::connectSignals(const Setting &setting) +{ + connect(&setting, SIGNAL(settingChanged(const Setting &, QVariant)), + SLOT(changeSetting(const Setting &, QVariant))); + connect(&setting, SIGNAL(settingChanged(const Setting &, QVariant)), + SIGNAL(settingChanged(const Setting &, QVariant))); + + connect(&setting, SIGNAL(settingReset(Setting)), + SLOT(resetSetting(const Setting &))); + connect(&setting, SIGNAL(settingReset(Setting)), + SIGNAL(settingReset(const Setting &))); +} + +void SettingsObject::disconnectSignals(const Setting &setting) +{ + setting.disconnect(SIGNAL(settingChanged(const Setting &, QVariant)), + this, SLOT(changeSetting(const Setting &, QVariant))); + setting.disconnect(SIGNAL(settingChanged(const Setting &, QVariant)), + this, SIGNAL(settingChanged(const Setting &, QVariant))); + + setting.disconnect(SIGNAL(settingReset(const Setting &, QVariant)), + this, SLOT(resetSetting(const Setting &, QVariant))); + setting.disconnect(SIGNAL(settingReset(const Setting &, QVariant)), + this, SIGNAL(settingReset(const Setting &, QVariant))); +} diff --git a/depends/settings/src/stubkeyring.cpp b/depends/settings/src/stubkeyring.cpp new file mode 100644 index 00000000..cf814d2f --- /dev/null +++ b/depends/settings/src/stubkeyring.cpp @@ -0,0 +1,104 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stubkeyring.h" + +#include + +// Scrambling +// this is NOT SAFE, but it's not plain either. +int scrambler = 0x9586309; + +QString scramble(QString in_) +{ + QByteArray in = in_.toUtf8(); + QByteArray out; + for (int i = 0; i + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef STUBKEYRING_H +#define STUBKEYRING_H + +#include "include/keyring.h" + +#include + +class StubKeyring : public Keyring +{ +public: + virtual bool storePassword(QString service, QString username, QString password); + virtual QString getPassword(QString service, QString username); + virtual bool hasPassword(QString service, QString username); + virtual QStringList getStoredAccounts(QString service); + virtual void removeStoredAccount(QString service, QString username); +private: + friend class Keyring; + explicit StubKeyring(); + virtual bool isValid() { return true; } + + QSettings m_settings; +}; + +#endif // STUBKEYRING_H diff --git a/depends/util/CMakeLists.txt b/depends/util/CMakeLists.txt new file mode 100644 index 00000000..7affb5ea --- /dev/null +++ b/depends/util/CMakeLists.txt @@ -0,0 +1,51 @@ +project(libUtil) + +######## Set compiler flags ######## +IF(APPLE) + # assume clang 4.1.0+, add C++0x/C++11 stuff + message(STATUS "Using APPLE CMAKE_CXX_FLAGS") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++") +ELSEIF(UNIX) + # assume GCC, add C++0x/C++11 stuff + MESSAGE(STATUS "Using UNIX CMAKE_CXX_FLAGS") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") +ELSEIF(MINGW) + MESSAGE(STATUS "Using MINGW CMAKE_CXX_FLAGS") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") +ENDIF() + + +# Find Qt +find_package(Qt5Core REQUIRED) + +# Include Qt headers. +include_directories(${Qt5Base_INCLUDE_DIRS}) +# include_directories(${Qt5Network_INCLUDE_DIRS}) + +SET(LIBUTIL_HEADERS +include/libutil_config.h + +include/apputils.h + +include/pathutils.h +include/osutils.h +include/userutils.h +include/cmdutils.h +) + +SET(LIBUTIL_SOURCES +src/pathutils.cpp +src/osutils.cpp +src/userutils.cpp +src/cmdutils.cpp +) + +# Set the include dir path. +SET(LIBUTIL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE) + +add_definitions(-DLIBUTIL_LIBRARY) + +add_library(libUtil SHARED ${LIBUTIL_SOURCES} ${LIBUTIL_HEADERS}) +# qt5_use_modules(libUtil Core Network) +qt5_use_modules(libUtil Core) +target_link_libraries(libUtil) diff --git a/depends/util/include/apputils.h b/depends/util/include/apputils.h new file mode 100644 index 00000000..a64adc50 --- /dev/null +++ b/depends/util/include/apputils.h @@ -0,0 +1,21 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef APPUTILS_H +#define APPUTILS_H + +#define STR_VAL(val) # val + +#endif // APPUTILS_H diff --git a/depends/util/include/cmdutils.h b/depends/util/include/cmdutils.h new file mode 100644 index 00000000..a6379397 --- /dev/null +++ b/depends/util/include/cmdutils.h @@ -0,0 +1,259 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CMDUTILS_H +#define CMDUTILS_H + +#include + +#include +#include +#include +#include + +#include "libutil_config.h" + +/** + * @file libutil/include/cmdutils.h + * @brief commandline parsing and processing utilities + */ + +namespace Util { +namespace Commandline { + +/** + * @brief split a string into argv items like a shell would do + * @param args the argument string + * @return a QStringList containing all arguments + */ +LIBUTIL_EXPORT QStringList splitArgs(QString args); + +/** + * @brief The FlagStyle enum + * Specifies how flags are decorated + */ + +namespace FlagStyle +{ +enum LIBUTIL_EXPORT Enum +{ + GNU, /**< --option and -o (GNU Style) */ + Unix, /**< -option and -o (Unix Style) */ + Windows, /**< /option and /o (Windows Style) */ +#ifdef Q_OS_WIN32 + Default = Windows +#else + Default = GNU +#endif +}; +} + +/** + * @brief The ArgumentStyle enum + */ +namespace ArgumentStyle +{ +enum LIBUTIL_EXPORT Enum +{ + Space, /**< --option=value */ + Equals, /**< --option value */ + SpaceAndEquals, /**< --option[= ]value */ +#ifdef Q_OS_WIN32 + Default = Equals +#else + Default = SpaceAndEquals +#endif +}; +} + +/** + * @brief The ParsingError class + */ +class LIBUTIL_EXPORT ParsingError : public std::exception +{ +public: + ParsingError(const QString &what); + ParsingError(const ParsingError &e); + ~ParsingError() throw() {} + const char *what() const throw(); + QString qwhat() const; +private: + QString m_what; +}; + +/** + * @brief The Parser class + */ +class LIBUTIL_EXPORT Parser +{ +public: + /** + * @brief Parser constructor + * @param flagStyle the FlagStyle to use in this Parser + * @param argStyle the ArgumentStyle to use in this Parser + */ + Parser(FlagStyle::Enum flagStyle = FlagStyle::Default, + ArgumentStyle::Enum argStyle = ArgumentStyle::Default); + + /** + * @brief set the flag style + * @param style + */ + void setFlagStyle(FlagStyle::Enum style); + + /** + * @brief get the flag style + * @return + */ + FlagStyle::Enum flagStyle(); + + /** + * @brief set the argument style + * @param style + */ + void setArgumentStyle(ArgumentStyle::Enum style); + + /** + * @brief get the argument style + * @return + */ + ArgumentStyle::Enum argumentStyle(); + + /** + * @brief define a boolean switch + * @param name the parameter name + * @param def the default value + */ + void addSwitch(QString name, bool def = false); + + /** + * @brief define an option that takes an additional argument + * @param name the parameter name + * @param def the default value + */ + void addOption(QString name, QVariant def = QVariant()); + + /** + * @brief define a positional argument + * @param name the parameter name + * @param required wether this argument is required + * @param def the default value + */ + void addArgument(QString name, bool required = true, QVariant def = QVariant()); + + /** + * @brief adds a flag to an existing parameter + * @param name the (existing) parameter name + * @param flag the flag character + * @see addSwitch addArgument addOption + * Note: any one parameter can only have one flag + */ + void addShortOpt(QString name, QChar flag); + + /** + * @brief adds documentation to a Parameter + * @param name the parameter name + * @param metavar a string to be displayed as placeholder for the value + * @param doc a QString containing the documentation + * Note: on positional arguments, metavar replaces the name as displayed. + * on options , metavar replaces the value placeholder + */ + void addDocumentation(QString name, QString doc, QString metavar = QString()); + + /** + * @brief generate a help message + * @param progName the program name to use in the help message + * @param helpIndent how much the parameter documentation should be indented + * @param flagsInUsage whether we should use flags instead of options in the usage + * @return a help message + */ + QString compileHelp(QString progName, int helpIndent = 22, bool flagsInUsage = true); + + /** + * @brief generate a short usage message + * @param progName the program name to use in the usage message + * @param useFlags whether we should use flags instead of options + * @return a usage message + */ + QString compileUsage(QString progName, bool useFlags = true); + + /** + * @brief parse + * @param argv a QStringList containing the program ARGV + * @return a QHash mapping argument names to their values + */ + QHash parse(QStringList argv); + + /** + * @brief clear all definitions + */ + void clear(); + + ~Parser(); + +private: + FlagStyle::Enum m_flagStyle; + ArgumentStyle::Enum m_argStyle; + + enum OptionType + { + otSwitch, + otOption + }; + + // Important: the common part MUST BE COMMON ON ALL THREE structs + struct CommonDef { + QString name; + QString doc; + QString metavar; + QVariant def; + }; + + struct OptionDef { + // common + QString name; + QString doc; + QString metavar; + QVariant def; + // option + OptionType type; + QChar flag; + }; + + struct PositionalDef { + // common + QString name; + QString doc; + QString metavar; + QVariant def; + // positional + bool required; + }; + + QHash m_options; + QHash m_flags; + QHash m_params; + QList m_positionals; + QList m_optionList; + + void getPrefix(QString &opt, QString &flag); +}; + +} +} + +#endif // CMDUTILS_H diff --git a/depends/util/include/libutil_config.h b/depends/util/include/libutil_config.h new file mode 100644 index 00000000..4bf111e6 --- /dev/null +++ b/depends/util/include/libutil_config.h @@ -0,0 +1,27 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBUTIL_CONFIG_H +#define LIBUTIL_CONFIG_H + +#include + +#ifdef LIBUTIL_LIBRARY +# define LIBUTIL_EXPORT Q_DECL_EXPORT +#else +# define LIBUTIL_EXPORT Q_DECL_IMPORT +#endif + +#endif // LIBUTIL_CONFIG_H diff --git a/depends/util/include/osutils.h b/depends/util/include/osutils.h new file mode 100644 index 00000000..c5d4bb61 --- /dev/null +++ b/depends/util/include/osutils.h @@ -0,0 +1,29 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OSUTILS_H +#define OSUTILS_H + +#include + +#if defined _WIN32 | defined _WIN64 +#define WINDOWS 1 +#elif __APPLE__ & __MACH__ +#define OSX 1 +#elif __linux__ +#define LINUX 1 +#endif + +#endif // OSUTILS_H diff --git a/depends/util/include/pathutils.h b/depends/util/include/pathutils.h new file mode 100644 index 00000000..d4f41da3 --- /dev/null +++ b/depends/util/include/pathutils.h @@ -0,0 +1,37 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PATHUTILS_H +#define PATHUTILS_H + +#include + +#include "libutil_config.h" + +LIBUTIL_EXPORT QString PathCombine(QString path1, QString path2); +LIBUTIL_EXPORT QString PathCombine(QString path1, QString path2, QString path3); + +LIBUTIL_EXPORT QString AbsolutePath(QString path); + +LIBUTIL_EXPORT QString RemoveInvalidFilenameChars(QString string, QChar replaceWith = '-'); + +LIBUTIL_EXPORT QString DirNameFromString(QString string, QString inDir = "."); + +LIBUTIL_EXPORT bool ensurePathExists(QString filenamepath); + +LIBUTIL_EXPORT bool copyPath(QString src, QString dst); + + +#endif // PATHUTILS_H diff --git a/depends/util/include/siglist.h b/depends/util/include/siglist.h new file mode 100644 index 00000000..24b1a889 --- /dev/null +++ b/depends/util/include/siglist.h @@ -0,0 +1,129 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGLIST_H +#define SIGLIST_H + +#include +#include + +// A QList that allows emitting signals when the list changes. +// Since QObject doesn't support templates, to use this class with a +// certain type, you should create a class deriving from SigList and then +// call the DEFINE_SIGLIST_SIGNALS(T) and SETUP_SIGLIST_SIGNALS(T) macros. +template +class SigList : public QList +{ +public: + explicit SigList() : QList() {} + + virtual void append(const T &value); + virtual void append(const QList &other); + + virtual void clear(); + + virtual void erase(typename QList::iterator pos); + virtual void erase(typename QList::iterator first, typename QList::iterator last); + + virtual void insert(int i, const T &t); + virtual void insert(typename QList::iterator before, const T &t); + + virtual void move(int from, int to); + + virtual void pop_back() { takeLast(); } + virtual void pop_front() { takeFirst(); } + + virtual void push_back(const T &t) { append(t); } + virtual void push_front(const T &t) { prepend(t); } + + virtual void prepend(const T &t); + + virtual int removeAll(const T &t); + virtual bool removeOne(const T &t); + + virtual void removeAt(int i) { takeAt(i); } + virtual void removeFirst() { takeFirst(); } + virtual void removeLast() { takeLast(); } + + virtual void swap(QList &other); + virtual void swap(int i, int j); + + virtual T takeAt(int i); + virtual T takeFirst(); + virtual T takeLast(); + + virtual QList &operator +=(const QList &other) { append(other); return *this; } + virtual QList &operator +=(const T &value) { append(value); return *this; } + virtual QList &operator <<(const QList &other) { append(other); return *this; } + virtual QList &operator <<(const T &value) { append(value); return *this; } + + virtual QList &operator =(const QList &other); + +protected: + // Signal emitted after an item is added to the list. + // Contains a reference to item and the item's new index. + virtual void onItemAdded(const T &item, int index) = 0; + + // Signal emitted after multiple items are added to the list at once. + // The items parameter is a const reference to a QList of the items that + // were added. + // The firstIndex parameter is the new index of the first item added. + virtual void onItemsAdded(const QList &items, int firstIndex) = 0; + + // Signal emitted after an item is removed to the list. + // Contains a reference to the item and the item's old index. + virtual void onItemRemoved(const T &item, int index) = 0; + + // Signal emitted after multiple items are removed from the list at once. + // The items parameter is a const reference to a QList of the items that + // were added. + // The firstIndex parameter is the new index of the first item added. + virtual void onItemsRemoved(const QList &items, int firstIndex) = 0; + + // Signal emitted after an item is moved to another index. + // Contains the item, the old index, and the new index. + virtual void onItemMoved(const T &item, int oldIndex, int newIndex) = 0; + + // Signal emitted after an operation that changes the whole list occurs. + // This signal should be treated as if all data in the entire list was cleared + // and new data added in its place. + virtual void onInvalidated() = 0; +}; + +// Defines the signals for a SigList +#define DEFINE_SIGLIST_SIGNALS(TYPE) \ + Q_SIGNAL void itemAdded(TYPE const &item, int index);\ + Q_SIGNAL void itemsAdded(const QList &items, int firstIndex);\ + Q_SIGNAL void itemRemoved(TYPE const &item, int index);\ + Q_SIGNAL void itemsRemoved(const QList &items, int firstIndex);\ + Q_SIGNAL void itemMoved(TYPE const &item, int oldIndex, int newIndex);\ + Q_SIGNAL void invalidated(); + +// Overrides the onItem* functions and causes them to emit their corresponding +// signals. +#define SETUP_SIGLIST_SIGNALS(TYPE) \ + virtual void onItemAdded(TYPE const &item, int index)\ + { emit itemAdded(item, index); }\ + virtual void onItemsAdded(const QList &items, int firstIndex)\ + { emit itemsAdded(items, firstIndex); }\ + virtual void onItemRemoved(TYPE const &item, int index)\ + { emit itemRemoved(item, index); }\ + virtual void onItemsRemoved(const QList &items, int firstIndex)\ + { emit itemsRemoved(items, firstIndex); }\ + virtual void onItemMoved(TYPE const &item, int oldIndex, int newIndex)\ + { emit itemMoved(item, oldIndex, newIndex); }\ + virtual void onInvalidated() { emit invalidated(); } + +#endif // SIGLIST_H diff --git a/depends/util/include/siglist_impl.h b/depends/util/include/siglist_impl.h new file mode 100644 index 00000000..5cdc632a --- /dev/null +++ b/depends/util/include/siglist_impl.h @@ -0,0 +1,156 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "siglist.h" + +template +void SigList::append(const T &value) +{ + QList::append(value); + onItemAdded(value, QList::length() - 1); +} + +template +void SigList::prepend(const T &value) +{ + QList::prepend(value); + onItemAdded(value, 0); +} + +template +void SigList::append(const QList &other) +{ + int index = QList::length(); + QList::append(other); + onItemsAdded(other, index); +} + +template +void SigList::clear() +{ + QList::clear(); + onInvalidated(); +} + +template +void SigList::erase(typename QList::iterator pos) +{ + T value = *pos; + int index = QList::indexOf(*pos); + QList::erase(pos); + onItemRemoved(value, index); +} + +template +void SigList::erase(typename QList::iterator first, typename QList::iterator last) +{ + QList removedValues; + int firstIndex = QList::indexOf(*first); + + for (auto iter = first; iter < last; iter++) + { + removedValues << *iter; + QList::erase(iter); + } + + onItemsRemoved(removedValues, firstIndex); +} + +template +void SigList::insert(int i, const T &t) +{ + QList::insert(i, t); + onItemAdded(t, i); +} + +template +void SigList::insert(typename QList::iterator before, const T &t) +{ + QList::insert(before, t); + onItemAdded(t, QList::indexOf(t)); +} + +template +void SigList::move(int from, int to) +{ + const T &item = QList::at(from); + QList::move(from, to); + onItemMoved(item, from, to); +} + +template +int SigList::removeAll(const T &t) +{ + int retVal = QList::removeAll(t); + onInvalidated(); + return retVal; +} + +template +bool SigList::removeOne(const T &t) +{ + int index = QList::indexOf(t); + if (QList::removeOne(t)) + { + onItemRemoved(t, index); + return true; + } + return false; +} + +template +void SigList::swap(QList &other) +{ + QList::swap(other); + onInvalidated(); +} + +template +void SigList::swap(int i, int j) +{ + const T &item1 = QList::at(i); + const T &item2 = QList::at(j); + QList::swap(i, j); + onItemMoved(item1, i, j); + onItemMoved(item2, j, i); +} + +template +T SigList::takeAt(int i) +{ + T val = QList::takeAt(i); + onItemRemoved(val, i); + return val; +} + +template +T SigList::takeFirst() +{ + return takeAt(0); +} + +template +T SigList::takeLast() +{ + return takeAt(QList::length() - 1); +} + +template +QList &SigList::operator =(const QList &other) +{ + QList::operator =(other); + onInvalidated(); + return *this; +} diff --git a/depends/util/include/userutils.h b/depends/util/include/userutils.h new file mode 100644 index 00000000..4f2760b1 --- /dev/null +++ b/depends/util/include/userutils.h @@ -0,0 +1,19 @@ +#ifndef USERUTILS_H +#define USERUTILS_H + +#include + +#include "libutil_config.h" + +namespace Util +{ +// Get the Directory representing the User's Desktop +LIBUTIL_EXPORT QString getDesktopDir(); + +// Create a shortcut at *location*, pointing to *dest* called with the arguments *args* +// call it *name* and assign it the icon *icon* +// return true if operation succeeded +LIBUTIL_EXPORT bool createShortCut(QString location, QString dest, QStringList args, QString name, QString iconLocation); +} + +#endif // USERUTILS_H diff --git a/depends/util/src/cmdutils.cpp b/depends/util/src/cmdutils.cpp new file mode 100644 index 00000000..80ba719d --- /dev/null +++ b/depends/util/src/cmdutils.cpp @@ -0,0 +1,484 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/cmdutils.h" + +/** + * @file libutil/src/cmdutils.cpp + */ + +namespace Util { +namespace Commandline { + +// commandline splitter +QStringList splitArgs(QString args) +{ + QStringList argv; + QString current; + bool escape = false; + QChar inquotes; + for (int i=0; itype = otSwitch; + param->name = name; + param->metavar = QString("<%1>").arg(name); + param->def = def; + + m_options[name] = param; + m_params[name] = (CommonDef *)param; + m_optionList.append(param); +} + +void Parser::addOption(QString name, QVariant def) +{ + if (m_params.contains(name)) + throw "Name not unique"; + + OptionDef *param = new OptionDef; + param->type = otOption; + param->name = name; + param->metavar = QString("<%1>").arg(name); + param->def = def; + + m_options[name] = param; + m_params[name] = (CommonDef *)param; + m_optionList.append(param); +} + +void Parser::addArgument(QString name, bool required, QVariant def) +{ + if (m_params.contains(name)) + throw "Name not unique"; + + PositionalDef *param = new PositionalDef; + param->name = name; + param->def = def; + param->required = required; + param->metavar = name; + + m_positionals.append(param); + m_params[name] = (CommonDef *)param; +} + +void Parser::addDocumentation(QString name, QString doc, QString metavar) +{ + if (!m_params.contains(name)) + throw "Name does not exist"; + + CommonDef *param = m_params[name]; + param->doc = doc; + if (!metavar.isNull()) + param->metavar = metavar; +} + +void Parser::addShortOpt(QString name, QChar flag) +{ + if (!m_params.contains(name)) + throw "Name does not exist"; + if (!m_options.contains(name)) + throw "Name is not an Option or Swtich"; + + OptionDef *param = m_options[name]; + m_flags[flag] = param; + param->flag = flag; +} + +// help methods +QString Parser::compileHelp(QString progName, int helpIndent, bool useFlags) +{ + QStringList help; + help << compileUsage(progName, useFlags) << "\r\n"; + + // positionals + if (!m_positionals.isEmpty()) + { + help << "\r\n"; + help << "Positional arguments:\r\n"; + QListIterator it2(m_positionals); + while(it2.hasNext()) + { + PositionalDef *param = it2.next(); + help << " " << param->metavar; + help << " " << QString(helpIndent - param->metavar.length() - 1, ' '); + help << param->doc << "\r\n"; + } + } + + // Options + if (!m_optionList.isEmpty()) + { + help << "\r\n"; + QString optPrefix, flagPrefix; + getPrefix(optPrefix, flagPrefix); + + help << "Options & Switches:\r\n"; + QListIterator it(m_optionList); + while(it.hasNext()) + { + OptionDef *option = it.next(); + help << " "; + int nameLength = optPrefix.length() + option->name.length(); + if (!option->flag.isNull()) + { + nameLength += 3 + flagPrefix.length(); + help << flagPrefix << option->flag << ", "; + } + help << optPrefix << option->name; + if (option->type == otOption) + { + QString arg = QString("%1%2").arg(((m_argStyle == ArgumentStyle::Equals) ? "=" : " "), option->metavar); + nameLength += arg.length(); + help << arg; + } + help << " " << QString(helpIndent - nameLength - 1, ' '); + help << option->doc << "\r\n"; + } + } + + return help.join(""); +} + +QString Parser::compileUsage(QString progName, bool useFlags) +{ + QStringList usage; + usage << "Usage: " << progName; + + QString optPrefix, flagPrefix; + getPrefix(optPrefix, flagPrefix); + + // options + QListIterator it(m_optionList); + while(it.hasNext()) + { + OptionDef *option = it.next(); + usage << " ["; + if (!option->flag.isNull() && useFlags) + usage << flagPrefix << option->flag; + else + usage << optPrefix << option->name; + if (option->type == otOption) + usage << ((m_argStyle == ArgumentStyle::Equals) ? "=" : " ") << option->metavar; + usage << "]"; + } + + // arguments + QListIterator it2(m_positionals); + while(it2.hasNext()) + { + PositionalDef *param = it2.next(); + usage << " " << (param->required ? "<" : "["); + usage << param->metavar; + usage << (param->required ? ">" : "]"); + } + + return usage.join(""); +} + +// parsing +QHash Parser::parse(QStringList argv) +{ + QHash map; + + QStringListIterator it(argv); + QString programName = it.next(); + + QString optionPrefix; + QString flagPrefix; + QListIterator positionals(m_positionals); + QStringList expecting; + + getPrefix(optionPrefix, flagPrefix); + + while (it.hasNext()) + { + QString arg = it.next(); + + if (!expecting.isEmpty()) + // we were expecting an argument + { + QString name = expecting.first(); + + if (map.contains(name)) + throw ParsingError(QString("Option %2%1 was given multiple times").arg(name, optionPrefix)); + + map[name] = QVariant(arg); + + expecting.removeFirst(); + continue; + } + + if (arg.startsWith(optionPrefix)) + // we have an option + { + //qDebug("Found option %s", qPrintable(arg)); + + QString name = arg.mid(optionPrefix.length()); + QString equals; + + if ((m_argStyle == ArgumentStyle::Equals || m_argStyle == ArgumentStyle::SpaceAndEquals) && name.contains("=")) + { + int i = name.indexOf("="); + equals = name.mid(i+1); + name = name.left(i); + } + + if (m_options.contains(name)) + { + if (map.contains(name)) + throw ParsingError(QString("Option %2%1 was given multiple times").arg(name, optionPrefix)); + + OptionDef *option = m_options[name]; + if (option->type == otSwitch) + map[name] = true; + else //if (option->type == otOption) + { + if (m_argStyle == ArgumentStyle::Space) + expecting.append(name); + else if (!equals.isNull()) + map[name] = equals; + else if (m_argStyle == ArgumentStyle::SpaceAndEquals) + expecting.append(name); + else + throw ParsingError(QString("Option %2%1 reqires an argument.").arg(name, optionPrefix)); + } + + continue; + } + + throw ParsingError(QString("Unknown Option %2%1").arg(name, optionPrefix)); + } + + if (arg.startsWith(flagPrefix)) + // we have (a) flag(s) + { + //qDebug("Found flags %s", qPrintable(arg)); + + QString flags = arg.mid(flagPrefix.length()); + QString equals; + + if ((m_argStyle == ArgumentStyle::Equals || m_argStyle == ArgumentStyle::SpaceAndEquals) && flags.contains("=")) + { + int i = flags.indexOf("="); + equals = flags.mid(i+1); + flags = flags.left(i); + } + + for (int i = 0; i < flags.length(); i++) + { + QChar flag = flags.at(i); + + if (!m_flags.contains(flag)) + throw ParsingError(QString("Unknown flag %2%1").arg(flag, flagPrefix)); + + OptionDef *option = m_flags[flag]; + + if (map.contains(option->name)) + throw ParsingError(QString("Option %2%1 was given multiple times").arg(option->name, optionPrefix)); + + if (option->type == otSwitch) + map[option->name] = true; + else //if (option->type == otOption) + { + if (m_argStyle == ArgumentStyle::Space) + expecting.append(option->name); + else if (!equals.isNull()) + if (i == flags.length()-1) + map[option->name] = equals; + else + throw ParsingError(QString("Flag %4%2 of Argument-requiring Option %1 not last flag in %4%3").arg(option->name, flag, flags, flagPrefix)); + else if (m_argStyle == ArgumentStyle::SpaceAndEquals) + expecting.append(option->name); + else + throw ParsingError(QString("Option %1 reqires an argument. (flag %3%2)").arg(option->name, flag, flagPrefix)); + } + } + + continue; + } + + // must be a positional argument + if (!positionals.hasNext()) + throw ParsingError(QString("Don't know what to do with '%1'").arg(arg)); + + PositionalDef *param = positionals.next(); + + map[param->name] = arg; + } + + // check if we're missing something + if (!expecting.isEmpty()) + throw ParsingError(QString("Was still expecting arguments for %2%1").arg(expecting.join(QString(", ")+optionPrefix), optionPrefix)); + + while (positionals.hasNext()) + { + PositionalDef *param = positionals.next(); + if (param->required) + throw ParsingError(QString("Missing required positional argument '%1'").arg(param->name)); + else + map[param->name] = param->def; + } + + // fill out gaps + QListIterator iter(m_optionList); + while (iter.hasNext()) + { + OptionDef *option = iter.next(); + if (!map.contains(option->name)) + map[option->name] = option->def; + } + + return map; +} + +//clear defs +void Parser::clear() +{ + m_flags.clear(); + m_params.clear(); + m_options.clear(); + + QMutableListIterator it(m_optionList); + while(it.hasNext()) + { + OptionDef *option = it.next(); + it.remove(); + delete option; + } + + QMutableListIterator it2(m_positionals); + while(it2.hasNext()) + { + PositionalDef *arg = it2.next(); + it2.remove(); + delete arg; + } +} + +//Destructor +Parser::~Parser() +{ + clear(); +} + +//getPrefix +void Parser::getPrefix(QString &opt, QString &flag) +{ + if (m_flagStyle == FlagStyle::Windows) + opt = flag = "/"; + else if (m_flagStyle == FlagStyle::Unix) + opt = flag = "-"; + //else if (m_flagStyle == FlagStyle::GNU) + else { + opt = "--"; + flag = "-"; + } +} + +// ParsingError +ParsingError::ParsingError(const QString &what) +{ + m_what = what; +} +ParsingError::ParsingError(const ParsingError &e) +{ + m_what = e.m_what; +} + +const char *ParsingError::what() const throw() +{ + return m_what.toLocal8Bit().constData(); +} +QString ParsingError::qwhat() const +{ + return m_what; +} + +} +} diff --git a/depends/util/src/osutils.cpp b/depends/util/src/osutils.cpp new file mode 100644 index 00000000..9a85d1e5 --- /dev/null +++ b/depends/util/src/osutils.cpp @@ -0,0 +1,19 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/osutils.h" + +#include +#include diff --git a/depends/util/src/pathutils.cpp b/depends/util/src/pathutils.cpp new file mode 100644 index 00000000..97287840 --- /dev/null +++ b/depends/util/src/pathutils.cpp @@ -0,0 +1,94 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/pathutils.h" + +#include +#include + +QString PathCombine(QString path1, QString path2) +{ + if (!path1.endsWith('/')) + return path1.append('/').append(path2); + else + return path1.append(path2); +} + +QString PathCombine(QString path1, QString path2, QString path3) +{ + return PathCombine(PathCombine(path1, path2), path3); +} + +QString AbsolutePath(QString path) +{ + return QFileInfo(path).absolutePath(); +} + +QString badFilenameChars = "\"\\/?<>:*|!"; + +QString RemoveInvalidFilenameChars(QString string, QChar replaceWith) +{ + for (int i = 0; i < string.length(); i++) + { + if (badFilenameChars.contains(string[i])) + { + string[i] = replaceWith; + } + } + return string; +} + +QString DirNameFromString(QString string, QString inDir) +{ + int num = 0; + QString dirName = RemoveInvalidFilenameChars(string, '-'); + while (QFileInfo(PathCombine(inDir, dirName)).exists()) + { + num++; + dirName = RemoveInvalidFilenameChars(dirName, '-') + QString::number(num); + + // If it's over 9000 + if (num > 9000) + return ""; + } + return dirName; +} + +bool ensurePathExists(QString filenamepath) +{ + QFileInfo a ( filenamepath ); + QDir dir; + return (dir.mkpath ( a.path() )); +} + +bool copyPath(QString src, QString dst) +{ + QDir dir(src); + if (!dir.exists()) + return false; + + foreach (QString d, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) + { + QString dst_path = dst + QDir::separator() + d; + dir.mkpath(dst_path); + copyPath(src+ QDir::separator() + d, dst_path); + } + + foreach (QString f, dir.entryList(QDir::Files)) + { + QFile::copy(src + QDir::separator() + f, dst + QDir::separator() + f); + } + return true; +} diff --git a/depends/util/src/userutils.cpp b/depends/util/src/userutils.cpp new file mode 100644 index 00000000..b70841ed --- /dev/null +++ b/depends/util/src/userutils.cpp @@ -0,0 +1,123 @@ +#include "include/userutils.h" + +#include +#include +#include + +#include "include/osutils.h" +#include "include/pathutils.h" + +// Win32 crap +#if WINDOWS + +#include +#include +#include +#include +#include +#include +#include + +bool called_coinit = false; + +HRESULT CreateLink(LPCSTR linkPath, LPCSTR targetPath, LPCSTR args) +{ + HRESULT hres; + + if (!called_coinit) + { + hres = CoInitialize(NULL); + called_coinit = true; + + if (!SUCCEEDED(hres)) + { + qWarning("Failed to initialize COM. Error 0x%08X", hres); + return hres; + } + } + + + IShellLink* link; + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&link); + + if (SUCCEEDED(hres)) + { + IPersistFile* persistFile; + + link->SetPath(targetPath); + link->SetArguments(args); + + hres = link->QueryInterface(IID_IPersistFile, (LPVOID*)&persistFile); + if (SUCCEEDED(hres)) + { + WCHAR wstr[MAX_PATH]; + + MultiByteToWideChar(CP_ACP, 0, linkPath, -1, wstr, MAX_PATH); + + hres = persistFile->Save(wstr, TRUE); + persistFile->Release(); + } + link->Release(); + } + return hres; +} + +#endif + +QString Util::getDesktopDir() +{ + return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); +} + +// Cross-platform Shortcut creation +bool Util::createShortCut(QString location, QString dest, QStringList args, QString name, QString icon) +{ +#if LINUX + location = PathCombine(location, name + ".desktop"); + qDebug("location: %s", qPrintable(location)); + + QFile f(location); + f.open(QIODevice::WriteOnly | QIODevice::Text); + QTextStream stream(&f); + + QString argstring; + if (!args.empty()) + argstring = " '" + args.join("' '") + "'"; + + stream << "[Desktop Entry]" << "\n"; + stream << "Type=Application" << "\n"; + stream << "TryExec=" << dest.toLocal8Bit() << "\n"; + stream << "Exec=" << dest.toLocal8Bit() << argstring.toLocal8Bit() << "\n"; + stream << "Name=" << name.toLocal8Bit() << "\n"; + stream << "Icon=" << icon.toLocal8Bit() << "\n"; + + stream.flush(); + f.close(); + + f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther); + + return true; +#elif WINDOWS + // TODO: Fix +// QFile file(PathCombine(location, name + ".lnk")); +// WCHAR *file_w; +// WCHAR *dest_w; +// WCHAR *args_w; +// file.fileName().toWCharArray(file_w); +// dest.toWCharArray(dest_w); + +// QString argStr; +// for (int i = 0; i < args.count(); i++) +// { +// argStr.append(args[i]); +// argStr.append(" "); +// } +// argStr.toWCharArray(args_w); + +// return SUCCEEDED(CreateLink(file_w, dest_w, args_w)); + return false; +#else + qWarning("Desktop Shortcuts not supported on your platform!"); + return false; +#endif +} diff --git a/gui/IconPickerDialog.cpp b/gui/IconPickerDialog.cpp index 27e7f3b6..d80673a8 100644 --- a/gui/IconPickerDialog.cpp +++ b/gui/IconPickerDialog.cpp @@ -1,7 +1,7 @@ #include "IconPickerDialog.h" #include "instancedelegate.h" #include "ui_IconPickerDialog.h" -#include +#include "logic/IconListModel.h" IconPickerDialog::IconPickerDialog(QWidget *parent) : QDialog(parent), diff --git a/gui/LegacyModEditDialog.cpp b/gui/LegacyModEditDialog.cpp new file mode 100644 index 00000000..a6becd7d --- /dev/null +++ b/gui/LegacyModEditDialog.cpp @@ -0,0 +1,36 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LegacyModEditDialog.h" +#include "ui_LegacyModEditDialog.h" + +LegacyModEditDialog::LegacyModEditDialog( LegacyInstance* inst, QWidget* parent ) : + m_inst(inst), + QDialog(parent), + ui(new Ui::LegacyModEditDialog) +{ + ui->setupUi(this); + +} + +LegacyModEditDialog::~LegacyModEditDialog() +{ + delete ui; +} + +void LegacyModEditDialog::on_buttonBox_rejected() +{ + close(); +} \ No newline at end of file diff --git a/gui/LegacyModEditDialog.h b/gui/LegacyModEditDialog.h new file mode 100644 index 00000000..3af6c8d7 --- /dev/null +++ b/gui/LegacyModEditDialog.h @@ -0,0 +1,59 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "logic/LegacyInstance.h" + +namespace Ui { +class LegacyModEditDialog; +} + +class LegacyModEditDialog : public QDialog +{ + Q_OBJECT + +public: + explicit LegacyModEditDialog(LegacyInstance* inst, QWidget *parent = 0); + ~LegacyModEditDialog(); + +private slots: + /* Mapped for implementation + void on_addJarBtn_clicked(); + void on_rmJarBtn_clicked(); + void on_addForgeBtn_clicked(); + void on_moveJarUpBtn_clicked(); + void on_moveJarDownBtn_clicked(); + + void on_addCoreBtn_clicked(); + void on_rmCoreBtn_clicked(); + void on_viewCoreBtn_clicked(); + + void on_addModBtn_clicked(); + void on_rmModBtn_clicked(); + void on_viewModBtn_clicked(); + + void on_addTexPackBtn_clicked(); + void on_rmTexPackBtn_clicked(); + void on_viewTexPackBtn_clicked(); + */ + // Questionable: SettingsDialog doesn't need this for some reason? + void on_buttonBox_rejected(); + +private: + Ui::LegacyModEditDialog *ui; + LegacyInstance * m_inst; +}; diff --git a/gui/LegacyModEditDialog.ui b/gui/LegacyModEditDialog.ui new file mode 100644 index 00000000..d55c3e1c --- /dev/null +++ b/gui/LegacyModEditDialog.ui @@ -0,0 +1,281 @@ + + + LegacyModEditDialog + + + + 0 + 0 + 540 + 420 + + + + Dialog + + + + + + false + + + 0 + + + + Jar Mods + + + + + + true + + + QAbstractItemView::DropOnly + + + + + + + + + &Add + + + + + + + &Remove + + + + + + + MCForge + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Move &Up + + + + + + + Move &Down + + + + + + + + + + Core Mods + + + + + + true + + + QAbstractItemView::DropOnly + + + + + + + + + &Add + + + + + + + &Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + &View Folder + + + + + + + + + + Mods + + + + + + true + + + QAbstractItemView::DropOnly + + + + + + + + + &Add + + + + + + + &Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + &View Folder + + + + + + + + + + false + + + Texture Packs + + + + + + true + + + false + + + QAbstractItemView::DropOnly + + + Qt::IgnoreAction + + + + + + + + + &Add + + + + + + + &Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + &View Folder + + + + + + + + + + + + + QDialogButtonBox::Close + + + + + + + + diff --git a/gui/consolewindow.h b/gui/consolewindow.h index 3ea02ad9..60bec69f 100644 --- a/gui/consolewindow.h +++ b/gui/consolewindow.h @@ -2,7 +2,7 @@ #define CONSOLEWINDOW_H #include -#include "MinecraftProcess.h" +#include "logic/MinecraftProcess.h" namespace Ui { class ConsoleWindow; diff --git a/gui/instancemodel.cpp b/gui/instancemodel.cpp index 3cbb0fb9..39dea34b 100644 --- a/gui/instancemodel.cpp +++ b/gui/instancemodel.cpp @@ -1,6 +1,6 @@ #include "instancemodel.h" -#include -#include +#include +#include #include //#include "iconcache.h" diff --git a/gui/instancemodel.h b/gui/instancemodel.h index fe05744f..52b58081 100644 --- a/gui/instancemodel.h +++ b/gui/instancemodel.h @@ -2,7 +2,7 @@ #include #include "categorizedsortfilterproxymodel.h" -#include "lists/InstanceList.h" +#include "logic/lists/InstanceList.h" #include class InstanceModel : public QAbstractListModel diff --git a/gui/legacymodeditdialog.cpp b/gui/legacymodeditdialog.cpp deleted file mode 100644 index 319705f9..00000000 --- a/gui/legacymodeditdialog.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "legacymodeditdialog.h" -#include "ui_legacymodeditdialog.h" -#include "BaseInstance.h" - -LegacyModEditDialog::LegacyModEditDialog(QWidget *parent, BaseInstance* m_inst) : - QDialog(parent), - ui(new Ui::LegacyModEditDialog) -{ - ui->setupUi(this); -} - -LegacyModEditDialog::~LegacyModEditDialog() -{ - delete ui; -} - -void LegacyModEditDialog::on_buttonBox_rejected() -{ - close(); -} \ No newline at end of file diff --git a/gui/legacymodeditdialog.h b/gui/legacymodeditdialog.h deleted file mode 100644 index 54dceffe..00000000 --- a/gui/legacymodeditdialog.h +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LEGACYMODEDITDIALOG_H -#define LEGACYMODEDITDIALOG_H - -#include - -#include "BaseInstance.h" - -namespace Ui { -class LegacyModEditDialog; -} - -class LegacyModEditDialog : public QDialog -{ - Q_OBJECT - -public: - explicit LegacyModEditDialog(QWidget *parent = 0, BaseInstance* m_inst = 0); - ~LegacyModEditDialog(); - -private slots: - /* Mapped for implementation - void on_addJarBtn_clicked(); - void on_rmJarBtn_clicked(); - void on_addForgeBtn_clicked(); - void on_moveJarUpBtn_clicked(); - void on_moveJarDownBtn_clicked(); - - void on_addCoreBtn_clicked(); - void on_rmCoreBtn_clicked(); - void on_viewCoreBtn_clicked(); - - void on_addModBtn_clicked(); - void on_rmModBtn_clicked(); - void on_viewModBtn_clicked(); - - void on_addTexPackBtn_clicked(); - void on_rmTexPackBtn_clicked(); - void on_viewTexPackBtn_clicked(); - */ - // Questionable: SettingsDialog doesn't need this for some reason? - void on_buttonBox_rejected(); - -private: - Ui::LegacyModEditDialog *ui; -}; - -#endif // LEGACYMODEDITDIALOG_H diff --git a/gui/legacymodeditdialog.ui b/gui/legacymodeditdialog.ui deleted file mode 100644 index d8b09bfe..00000000 --- a/gui/legacymodeditdialog.ui +++ /dev/null @@ -1,281 +0,0 @@ - - - LegacyModEditDialog - - - - 0 - 0 - 540 - 420 - - - - Dialog - - - - - - false - - - 3 - - - - Jar Mods - - - - - - true - - - QAbstractItemView::DropOnly - - - - - - - - - &Add - - - - - - - &Remove - - - - - - - MCForge - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Move &Up - - - - - - - Move &Down - - - - - - - - - - Core Mods - - - - - - true - - - QAbstractItemView::DropOnly - - - - - - - - - &Add - - - - - - - &Remove - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - &View Folder - - - - - - - - - - Mods - - - - - - true - - - QAbstractItemView::DropOnly - - - - - - - - - &Add - - - - - - - &Remove - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - &View Folder - - - - - - - - - - false - - - Texture Packs - - - - - - true - - - false - - - QAbstractItemView::DropOnly - - - Qt::IgnoreAction - - - - - - - - - &Add - - - - - - - &Remove - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - &View Folder - - - - - - - - - - - - - QDialogButtonBox::Close - - - - - - - - diff --git a/gui/lwjglselectdialog.cpp b/gui/lwjglselectdialog.cpp index d4a42b59..9de92754 100644 --- a/gui/lwjglselectdialog.cpp +++ b/gui/lwjglselectdialog.cpp @@ -16,7 +16,7 @@ #include "lwjglselectdialog.h" #include "ui_lwjglselectdialog.h" -#include "lists/LwjglVersionList.h" +#include "logic/lists/LwjglVersionList.h" LWJGLSelectDialog::LWJGLSelectDialog(QWidget *parent) : QDialog(parent), diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 6176c079..5087b38f 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -33,6 +33,9 @@ #include "userutils.h" #include "pathutils.h" +#include "categorizedview.h" +#include "categorydrawer.h" + #include "gui/settingsdialog.h" #include "gui/newinstancedialog.h" #include "gui/logindialog.h" @@ -42,31 +45,25 @@ #include "gui/versionselectdialog.h" #include "gui/lwjglselectdialog.h" #include "gui/consolewindow.h" -#include "gui/legacymodeditdialog.h" #include "gui/instancesettings.h" -#include "categorizedview.h" -#include "categorydrawer.h" - -#include "lists/InstanceList.h" #include "AppSettings.h" #include "AppVersion.h" -#include "tasks/LoginTask.h" - -#include "BaseInstance.h" -#include "InstanceFactory.h" -#include "MinecraftProcess.h" -#include "OneSixAssets.h" -#include "OneSixUpdate.h" +#include "logic/lists/InstanceList.h" +#include "logic/tasks/LoginTask.h" +#include "logic/BaseInstance.h" +#include "logic/InstanceFactory.h" +#include "logic/MinecraftProcess.h" +#include "logic/OneSixAssets.h" +#include "logic/OneSixUpdate.h" +#include "logic/lists/MinecraftVersionList.h" +#include "logic/lists/LwjglVersionList.h" #include "instancemodel.h" #include "instancedelegate.h" #include "IconPickerDialog.h" -#include "lists/MinecraftVersionList.h" -#include "lists/LwjglVersionList.h" - // Opens the given file in the default application. // TODO: Move this somewhere. void openFileInDefaultProgram ( QString filename ); @@ -378,8 +375,8 @@ void MainWindow::on_actionEditInstMods_triggered() BaseInstance* inst = selectedInstance(); if (inst) { - LegacyModEditDialog dialog ( this, inst ); - dialog.exec(); + auto dialog = inst->createModEditDialog(this); + dialog->exec(); } } diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 62115e1d..79716e5e 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -18,9 +18,9 @@ #include -#include "lists/InstanceList.h" -#include "tasks/LoginTask.h" -#include "BaseInstance.h" +#include "logic/lists/InstanceList.h" +#include "logic/tasks/LoginTask.h" +#include "logic/BaseInstance.h" class InstanceModel; class InstanceProxyModel; diff --git a/gui/modeditdialog.cpp b/gui/modeditdialog.cpp index 2f437101..011de53d 100644 --- a/gui/modeditdialog.cpp +++ b/gui/modeditdialog.cpp @@ -15,7 +15,7 @@ #include "modeditdialog.h" #include "ui_modeditdialog.h" -#include "BaseInstance.h" +#include "logic/BaseInstance.h" ModEditDialog::ModEditDialog(QWidget *parent, BaseInstance* m_inst) : QDialog(parent), diff --git a/gui/modeditdialog.h b/gui/modeditdialog.h index 329a1b4e..94272a32 100644 --- a/gui/modeditdialog.h +++ b/gui/modeditdialog.h @@ -18,7 +18,7 @@ #include -#include "BaseInstance.h" +#include "logic/BaseInstance.h" namespace Ui { class ModEditDialog; diff --git a/gui/modeditdialog.ui b/gui/modeditdialog.ui index 380aec39..dfc59d21 100644 --- a/gui/modeditdialog.ui +++ b/gui/modeditdialog.ui @@ -26,7 +26,7 @@ - 2 + 0 Qt::ElideNone diff --git a/gui/newinstancedialog.cpp b/gui/newinstancedialog.cpp index 4f19e9a2..3a4adbc1 100644 --- a/gui/newinstancedialog.cpp +++ b/gui/newinstancedialog.cpp @@ -16,13 +16,11 @@ #include "newinstancedialog.h" #include "ui_newinstancedialog.h" -#include "InstanceFactory.h" - -#include -#include "InstanceVersion.h" - -#include "tasks/Task.h" -#include +#include "logic/InstanceFactory.h" +#include "logic/InstanceVersion.h" +#include "logic/IconListModel.h" +#include "logic/lists/MinecraftVersionList.h" +#include "logic/tasks/Task.h" #include "versionselectdialog.h" #include "taskdialog.h" diff --git a/gui/newinstancedialog.h b/gui/newinstancedialog.h index 07267e19..e8c57024 100644 --- a/gui/newinstancedialog.h +++ b/gui/newinstancedialog.h @@ -17,7 +17,7 @@ #define NEWINSTANCEDIALOG_H #include -#include "InstanceVersion.h" +#include "logic/InstanceVersion.h" namespace Ui { class NewInstanceDialog; diff --git a/gui/taskdialog.cpp b/gui/taskdialog.cpp index f61614e8..8c745b38 100644 --- a/gui/taskdialog.cpp +++ b/gui/taskdialog.cpp @@ -18,7 +18,7 @@ #include -#include "tasks/Task.h" +#include "logic/tasks/Task.h" TaskDialog::TaskDialog(QWidget *parent) : QDialog(parent), diff --git a/gui/versionselectdialog.cpp b/gui/versionselectdialog.cpp index 33aedc71..afe112f4 100644 --- a/gui/versionselectdialog.cpp +++ b/gui/versionselectdialog.cpp @@ -22,9 +22,9 @@ #include -#include -#include -#include +#include +#include +#include VersionSelectDialog::VersionSelectDialog(InstVersionList *vlist, QWidget *parent) : QDialog(parent), diff --git a/gui/versionselectdialog.h b/gui/versionselectdialog.h index 752c937b..b864aee1 100644 --- a/gui/versionselectdialog.h +++ b/gui/versionselectdialog.h @@ -19,7 +19,7 @@ #include #include -#include +#include "logic/InstanceVersion.h" class InstVersionList; diff --git a/java/annotations.cpp b/java/annotations.cpp deleted file mode 100644 index fc0c98fa..00000000 --- a/java/annotations.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "classfile.h" -#include "annotations.h" -#include - -namespace java -{ - std::string annotation::toString() - { - std::ostringstream ss; - ss << "Annotation type : " << type_index << " - " << pool[type_index].str_data << std::endl; - ss << "Contains " << name_val_pairs.size() << " pairs:" << std::endl; - for(unsigned i = 0; i < name_val_pairs.size(); i++) - { - std::pair &val = name_val_pairs[i]; - auto name_idx = val.first; - ss << pool[name_idx].str_data << "(" << name_idx << ")" << " = " << val.second->toString() << std::endl; - } - return ss.str(); - } - - annotation * annotation::read (util::membuffer& input, constant_pool& pool) - { - uint16_t type_index = 0; - input.read_be(type_index); - annotation * ann = new annotation(type_index,pool); - - uint16_t num_pairs = 0; - input.read_be(num_pairs); - while(num_pairs) - { - uint16_t name_idx = 0; - // read name index - input.read_be(name_idx); - auto elem = element_value::readElementValue(input,pool); - // read value - ann->add_pair(name_idx, elem); - num_pairs --; - } - return ann; - } - - element_value* element_value::readElementValue ( util::membuffer& input, java::constant_pool& pool ) - { - element_value_type type = INVALID; - input.read(type); - uint16_t index = 0; - uint16_t index2 = 0; - std::vector vals; - switch (type) - { - case PRIMITIVE_BYTE: - case PRIMITIVE_CHAR: - case PRIMITIVE_DOUBLE: - case PRIMITIVE_FLOAT: - case PRIMITIVE_INT: - case PRIMITIVE_LONG: - case PRIMITIVE_SHORT: - case PRIMITIVE_BOOLEAN: - case STRING: - input.read_be(index); - return new element_value_simple(type, index, pool); - case ENUM_CONSTANT: - input.read_be(index); - input.read_be(index2); - return new element_value_enum(type, index, index2, pool); - case CLASS: // Class - input.read_be(index); - return new element_value_class(type, index, pool); - case ANNOTATION: // Annotation - // FIXME: runtime visibility info needs to be passed from parent - return new element_value_annotation(ANNOTATION, annotation::read(input, pool), pool); - case ARRAY: // Array - input.read_be(index); - for (int i = 0; i < index; i++) - { - vals.push_back(element_value::readElementValue(input, pool)); - } - return new element_value_array(ARRAY, vals, pool); - default: - throw new java::classfile_exception(); - } - } -} \ No newline at end of file diff --git a/java/annotations.h b/java/annotations.h deleted file mode 100644 index b115dc0b..00000000 --- a/java/annotations.h +++ /dev/null @@ -1,252 +0,0 @@ -#pragma once -#include "classfile.h" -#include -#include - -namespace java -{ - enum element_value_type : uint8_t - { - INVALID = 0, - STRING = 's', - ENUM_CONSTANT = 'e', - CLASS = 'c', - ANNOTATION = '@', - ARRAY = '[', // one array dimension - PRIMITIVE_INT = 'I', // integer - PRIMITIVE_BYTE = 'B', // signed byte - PRIMITIVE_CHAR = 'C', // Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16 - PRIMITIVE_DOUBLE = 'D', // double-precision floating-point value - PRIMITIVE_FLOAT = 'F', // single-precision floating-point value - PRIMITIVE_LONG = 'J', // long integer - PRIMITIVE_SHORT = 'S', // signed short - PRIMITIVE_BOOLEAN = 'Z' // true or false - }; - /** - * The element_value structure is a discriminated union representing the value of an element-value pair. - * It is used to represent element values in all attributes that describe annotations - * - RuntimeVisibleAnnotations - * - RuntimeInvisibleAnnotations - * - RuntimeVisibleParameterAnnotations - * - RuntimeInvisibleParameterAnnotations). - * - * The element_value structure has the following format: - */ - class element_value - { - protected: - element_value_type type; - constant_pool & pool; - - public: - element_value(element_value_type type, constant_pool & pool): type(type), pool(pool) {}; - - element_value_type getElementValueType() - { - return type; - } - - virtual std::string toString() = 0; - - static element_value * readElementValue(util::membuffer & input, constant_pool & pool); - }; - - /** - * Each value of the annotations table represents a single runtime-visible annotation on a program element. - * The annotation structure has the following format: - */ - class annotation - { - public: - typedef std::vector< std::pair > value_list; - protected: - /** - * The value of the type_index item must be a valid index into the constant_pool table. - * The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure - * representing a field descriptor representing the annotation type corresponding - * to the annotation represented by this annotation structure. - */ - uint16_t type_index; - /** - * map between element_name_index and value. - * - * The value of the element_name_index item must be a valid index into the constant_pool table. - * The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure representing - * a valid field descriptor (§4.3.2) that denotes the name of the annotation type element represented - * by this element_value_pairs entry. - */ - value_list name_val_pairs; - /** - * Reference to the parent constant pool - */ - constant_pool & pool; - public: - annotation(uint16_t type_index, constant_pool& pool):type_index(type_index), pool(pool) {}; - ~annotation() - { - for(unsigned i = 0 ; i < name_val_pairs.size(); i++) - { - delete name_val_pairs[i].second; - } - } - void add_pair(uint16_t key, element_value * value) - { - name_val_pairs.push_back(std::make_pair(key, value)); - }; - value_list::const_iterator begin() - { - return name_val_pairs.cbegin(); - } - value_list::const_iterator end() - { - return name_val_pairs.cend(); - } - std::string toString(); - static annotation * read(util::membuffer & input, constant_pool & pool); - }; - typedef std::vector annotation_table; - - - /// type for simple value annotation elements - class element_value_simple : public element_value - { - protected: - /// index of the constant in the constant pool - uint16_t index; - public: - element_value_simple(element_value_type type, uint16_t index , constant_pool& pool): - element_value(type, pool), index(index) - { - // TODO: verify consistency - }; - uint16_t getIndex() - { - return index; - } - virtual std::string toString() - { - return pool[index].toString(); - }; - }; - /// The enum_const_value item is used if the tag item is 'e'. - class element_value_enum : public element_value - { - protected: - /** - * The value of the type_name_index item must be a valid index into the constant_pool table. - * The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure - * representing a valid field descriptor (§4.3.2) that denotes the internal form of the binary - * name (§4.2.1) of the type of the enum constant represented by this element_value structure. - */ - uint16_t typeIndex; - /** - * The value of the const_name_index item must be a valid index into the constant_pool table. - * The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure - * representing the simple name of the enum constant represented by this element_value structure. - */ - uint16_t valueIndex; - public: - element_value_enum(element_value_type type, uint16_t typeIndex, uint16_t valueIndex, constant_pool& pool): - element_value(type, pool), typeIndex(typeIndex), valueIndex(valueIndex) - { - // TODO: verify consistency - } - uint16_t getValueIndex() - { - return valueIndex; - } - uint16_t getTypeIndex() - { - return typeIndex; - } - virtual std::string toString() - { - return "enum value"; - }; - }; - - class element_value_class : public element_value - { - protected: - /** - * The class_info_index item must be a valid index into the constant_pool table. - * The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure - * representing the return descriptor (§4.3.3) of the type that is reified by the class - * represented by this element_value structure. - * - * For example, 'V' for Void.class, 'Ljava/lang/Object;' for Object, etc. - * - * Or in plain english, you can store type information in annotations. Yay. - */ - uint16_t classIndex; - public: - element_value_class(element_value_type type, uint16_t classIndex, constant_pool& pool): - element_value(type, pool), classIndex(classIndex) - { - // TODO: verify consistency - } - uint16_t getIndex() - { - return classIndex; - } - virtual std::string toString() - { - return "class"; - }; - }; - - /// nested annotations... yay - class element_value_annotation : public element_value - { - private: - annotation * nestedAnnotation; - public: - element_value_annotation(element_value_type type, annotation * nestedAnnotation, constant_pool& pool): - element_value(type, pool), nestedAnnotation(nestedAnnotation) - {}; - ~element_value_annotation() - { - if(nestedAnnotation) - { - delete nestedAnnotation; - nestedAnnotation = nullptr; - } - } - virtual std::string toString() - { - return "nested annotation"; - }; - }; - - /// and arrays! - class element_value_array : public element_value - { - public: - typedef std::vector elem_vec; - protected: - elem_vec values; - public: - element_value_array ( element_value_type type, std::vector & values, constant_pool& pool ): - element_value(type, pool), values(values) - {}; - ~element_value_array () - { - for(unsigned i = 0; i < values.size();i++) - { - delete values[i]; - } - }; - elem_vec::const_iterator begin() - { - return values.cbegin(); - } - elem_vec::const_iterator end() - { - return values.cend(); - } - virtual std::string toString() - { - return "array"; - }; - }; -} \ No newline at end of file diff --git a/java/classfile.h b/java/classfile.h deleted file mode 100644 index 33207e99..00000000 --- a/java/classfile.h +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once -#include "membuffer.h" -#include "constants.h" -#include "annotations.h" -#include -namespace java -{ - /** - * Class representing a Java .class file - */ - class classfile : public util::membuffer - { - public: - classfile(char * data, std::size_t size) : membuffer(data, size) - { - valid = false; - is_synthetic = false; - read_be(magic); - if(magic != 0xCAFEBABE) - throw new classfile_exception(); - read_be(minor_version); - read_be(major_version); - constants.load(*this); - read_be(access_flags); - read_be(this_class); - read_be(super_class); - - // Interfaces - uint16_t iface_count = 0; - read_be(iface_count); - while (iface_count) - { - uint16_t iface; - read_be(iface); - interfaces.push_back(iface); - iface_count --; - } - - // Fields - // read fields (and attributes from inside fields) (and possible inner classes. yay for recursion!) - // for now though, we will ignore all attributes - /* - * field_info - * { - * u2 access_flags; - * u2 name_index; - * u2 descriptor_index; - * u2 attributes_count; - * attribute_info attributes[attributes_count]; - * } - */ - uint16_t field_count = 0; - read_be(field_count); - while (field_count) - { - // skip field stuff - skip(6); - // and skip field attributes - uint16_t attr_count = 0; - read_be(attr_count); - while(attr_count) - { - skip(2); - uint32_t attr_length = 0; - read_be(attr_length); - skip(attr_length); - attr_count --; - } - field_count --; - } - - // class methods - /* - * method_info - * { - * u2 access_flags; - * u2 name_index; - * u2 descriptor_index; - * u2 attributes_count; - * attribute_info attributes[attributes_count]; - * } - */ - uint16_t method_count = 0; - read_be(method_count); - while( method_count ) - { - skip(6); - // and skip method attributes - uint16_t attr_count = 0; - read_be(attr_count); - while(attr_count) - { - skip(2); - uint32_t attr_length = 0; - read_be(attr_length); - skip(attr_length); - attr_count --; - } - method_count --; - } - - // class attributes - // there are many kinds of attributes. this is just the generic wrapper structure. - // type is decided by attribute name. extensions to the standard are *possible* - // class annotations are one kind of a attribute (one per class) - /* - * attribute_info - * { - * u2 attribute_name_index; - * u4 attribute_length; - * u1 info[attribute_length]; - * } - */ - uint16_t class_attr_count = 0; - read_be(class_attr_count); - while(class_attr_count) - { - uint16_t name_idx = 0; - read_be(name_idx); - uint32_t attr_length = 0; - read_be(attr_length); - - auto name = constants[name_idx]; - if(name.str_data == "RuntimeVisibleAnnotations") - { - uint16_t num_annotations = 0; - read_be(num_annotations); - while (num_annotations) - { - visible_class_annotations.push_back(annotation::read(*this, constants)); - num_annotations --; - } - } - else skip(attr_length); - class_attr_count --; - } - valid = true; - }; - bool valid; - bool is_synthetic; - uint32_t magic; - uint16_t minor_version; - uint16_t major_version; - constant_pool constants; - uint16_t access_flags; - uint16_t this_class; - uint16_t super_class; - // interfaces this class implements ? must be. investigate. - std::vector interfaces; - // FIXME: doesn't free up memory on delete - java::annotation_table visible_class_annotations; - }; -} \ No newline at end of file diff --git a/java/constants.h b/java/constants.h deleted file mode 100644 index 61aa5687..00000000 --- a/java/constants.h +++ /dev/null @@ -1,212 +0,0 @@ -#pragma once -#include "errors.h" -#include - -namespace java -{ - class constant - { - public: - enum type_t : uint8_t - { - j_hole = 0, // HACK: this is a hole in the array, because java is crazy - j_string_data = 1, - j_int = 3, - j_float = 4, - j_long = 5, - j_double = 6, - j_class = 7, - j_string = 8, - j_fieldref = 9, - j_methodref = 10, - j_interface_methodref = 11, - j_nameandtype = 12 - } type; - - constant(util::membuffer & buf ) - { - buf.read(type); - // invalid constant type! - if(type > j_nameandtype || type == (type_t)0 || type == (type_t)2) - throw new classfile_exception(); - - // load data depending on type - switch(type) - { - case j_float: - case j_int: - buf.read_be(int_data); // same as float data really - break; - case j_double: - case j_long: - buf.read_be(long_data); // same as double - break; - case j_class: - buf.read_be(ref_type.class_idx); - break; - case j_fieldref: - case j_methodref: - case j_interface_methodref: - buf.read_be(ref_type.class_idx); - buf.read_be(ref_type.name_and_type_idx); - break; - case j_string: - buf.read_be(index); - break; - case j_string_data: - // HACK HACK: for now, we call these UTF-8 and do no further processing. - // Later, we should do some decoding. It's really modified UTF-8 - // * U+0000 is represented as 0xC0,0x80 invalid character - // * any single zero byte ends the string - // * characters above U+10000 are encoded like in CESU-8 - buf.read_jstr(str_data); - break; - case j_nameandtype: - buf.read_be(name_and_type.name_index); - buf.read_be(name_and_type.descriptor_index); - break; - } - } - - constant(int fake) - { - type = j_hole; - } - - std::string toString() - { - std::ostringstream ss; - switch(type) - { - case j_hole: - ss << "Fake legacy entry"; - break; - case j_float: - ss << "Float: " << float_data; - break; - case j_double: - ss << "Double: " << double_data; - break; - case j_int: - ss << "Int: " << int_data; - break; - case j_long: - ss << "Long: " << long_data; - break; - case j_string_data: - ss << "StrData: " << str_data; - break; - case j_string: - ss << "Str: " << index; - break; - case j_fieldref: - ss << "FieldRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx; - break; - case j_methodref: - ss << "MethodRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx; - break; - case j_interface_methodref: - ss << "IfMethodRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx; - break; - case j_class: - ss << "Class: " << ref_type.class_idx; - break; - case j_nameandtype: - ss << "NameAndType: " << name_and_type.name_index << " " << name_and_type.descriptor_index; - break; - } - return ss.str(); - } - - std::string str_data; /** String data in 'modified utf-8'.*/ - // store everything here. - union - { - int32_t int_data; - int64_t long_data; - float float_data; - double double_data; - uint16_t index; - struct - { - /** - * Class reference: - * an index within the constant pool to a UTF-8 string containing - * the fully qualified class name (in internal format) - * Used for j_class, j_fieldref, j_methodref and j_interface_methodref - */ - uint16_t class_idx; - // used for j_fieldref, j_methodref and j_interface_methodref - uint16_t name_and_type_idx; - } ref_type; - struct - { - uint16_t name_index; - uint16_t descriptor_index; - } name_and_type; - }; - }; - - /** - * A helper class that represents the custom container used in Java class file for storage of constants - */ - class constant_pool - { - public: - /** - * Create a pool of constants - */ - constant_pool(){} - /** - * Load a java constant pool - */ - void load(util::membuffer & buf) - { - uint16_t length = 0; - buf.read_be(length); - length --; - uint16_t index = 1; - const constant * last_constant = nullptr; - while(length) - { - const constant & cnst = constant(buf); - constants.push_back(cnst); - last_constant = &constants[constants.size() - 1]; - if(last_constant->type == constant::j_double || last_constant->type == constant::j_long) - { - // push in a fake constant to preserve indexing - constants.push_back(constant(0)); - length-=2; - index+=2; - } - else - { - length--; - index++; - } - } - } - typedef std::vector container_type; - /** - * Access constants based on jar file index numbers (index of the first element is 1) - */ - java::constant & operator[](std::size_t constant_index) - { - if(constant_index == 0 || constant_index > constants.size()) - { - throw new classfile_exception(); - } - return constants[constant_index - 1]; - }; - container_type::const_iterator begin() const - { - return constants.begin(); - }; - container_type::const_iterator end() const - { - return constants.end(); - } - private: - container_type constants; - }; -} diff --git a/java/errors.h b/java/errors.h deleted file mode 100644 index c02b07c8..00000000 --- a/java/errors.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include -namespace java -{ - class classfile_exception : public std::exception {}; -} diff --git a/java/javaendian.h b/java/javaendian.h deleted file mode 100644 index fa6207fe..00000000 --- a/java/javaendian.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once -#include - -/** - * Swap bytes between big endian and local number representation - */ -namespace util -{ -#ifdef MULTIMC_BIG_ENDIAN -inline uint64_t bigswap(uint64_t x) -{ - return x; -}; -inline uint32_t bigswap(uint32_t x) -{ - return x; -}; -inline uint16_t bigswap(uint16_t x) -{ - return x; -}; -inline int64_t bigswap(int64_t x) -{ - return x; -}; -inline int32_t bigswap(int32_t x) -{ - return x; -}; -inline int16_t bigswap(int16_t x) -{ - return x; -}; -#else -inline uint64_t bigswap(uint64_t x) -{ - return (x>>56) | ((x<<40) & 0x00FF000000000000) | ((x<<24) & 0x0000FF0000000000) | ((x<<8) & 0x000000FF00000000) | - ((x>>8) & 0x00000000FF000000) | ((x>>24) & 0x0000000000FF0000) | ((x>>40) & 0x000000000000FF00) | (x<<56); -}; -inline uint32_t bigswap(uint32_t x) -{ - return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24); -}; -inline uint16_t bigswap(uint16_t x) -{ - return (x>>8) | (x<<8); -}; -inline int64_t bigswap(int64_t x) -{ - return (x>>56) | ((x<<40) & 0x00FF000000000000) | ((x<<24) & 0x0000FF0000000000) | ((x<<8) & 0x000000FF00000000) | - ((x>>8) & 0x00000000FF000000) | ((x>>24) & 0x0000000000FF0000) | ((x>>40) & 0x000000000000FF00) | (x<<56); -}; -inline int32_t bigswap(int32_t x) -{ - return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24); -}; -inline int16_t bigswap(int16_t x) -{ - return (x>>8) | (x<<8); -}; -#endif -} diff --git a/java/javautils.cpp b/java/javautils.cpp deleted file mode 100644 index 4a359031..00000000 --- a/java/javautils.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "multimc_pragma.h" -#include "classfile.h" -#include "javautils.h" - -#include -#include - -namespace javautils -{ - -QString GetMinecraftJarVersion(QString jarName) -{ - QString version = MCVer_Unknown; - - // check if minecraft.jar exists - QFile jar(jarName); - if (!jar.exists()) - return version; - - // open minecraft.jar - QuaZip zip(&jar); - if (!zip.open(QuaZip::mdUnzip)) - return version; - - // open Minecraft.class - zip.setCurrentFile("net/minecraft/client/Minecraft.class", QuaZip::csSensitive); - QuaZipFile Minecraft(&zip); - if (!Minecraft.open(QuaZipFile::ReadOnly)) - return version; - - // read Minecraft.class - qint64 size = Minecraft.size(); - char *classfile = new char[size]; - Minecraft.read(classfile, size); - - // parse Minecraft.class - try { - char *temp = classfile; - java::classfile MinecraftClass(temp, size); - java::constant_pool constants = MinecraftClass.constants; - for(java::constant_pool::container_type::const_iterator iter=constants.begin(); - iter != constants.end(); iter++) - { - const java::constant & constant = *iter; - if (constant.type != java::constant::j_string_data) - continue; - const std::string & str = constant.str_data; - if (str.compare(0, 20, "Minecraft Minecraft ") == 0) - { - version = str.substr(20).data(); - break; - } - } - } catch(java::classfile_exception &) {} - - // clean up - delete[] classfile; - Minecraft.close(); - zip.close(); - jar.close(); - - return version; -} - -} diff --git a/java/javautils.h b/java/javautils.h deleted file mode 100644 index 883eff1d..00000000 --- a/java/javautils.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once -#include - -#define MCVer_Unknown "Unknown" - -namespace javautils -{ - /** - * @brief Get the version from a minecraft.jar by parsing its class files. Expensive! - */ - QString GetMinecraftJarVersion(QString jar); -} diff --git a/java/membuffer.h b/java/membuffer.h deleted file mode 100644 index 2ea3a69b..00000000 --- a/java/membuffer.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include "javaendian.h" - -namespace util -{ - class membuffer - { - public: - membuffer(char * buffer, std::size_t size) - { - current = start = buffer; - end = start + size; - } - ~membuffer() - { - // maybe? possibly? left out to avoid confusion. for now. - //delete start; - } - /** - * Read some value. That's all ;) - */ - template - void read(T& val) - { - val = *(T *)current; - current += sizeof(T); - } - /** - * Read a big-endian number - * valid for 2-byte, 4-byte and 8-byte variables - */ - template - void read_be(T& val) - { - val = util::bigswap(*(T *)current); - current += sizeof(T); - } - /** - * Read a string in the format: - * 2B length (big endian, unsigned) - * length bytes data - */ - void read_jstr(std::string & str) - { - uint16_t length = 0; - read_be(length); - str.append(current,length); - current += length; - } - /** - * Skip N bytes - */ - void skip (std::size_t N) - { - current += N; - } - private: - char * start, *end, *current; - }; -} diff --git a/java/test.cpp b/java/test.cpp deleted file mode 100644 index f73e3c21..00000000 --- a/java/test.cpp +++ /dev/null @@ -1,35 +0,0 @@ - -#include "classfile.h" -#include "annotations.h" -#include -#include - -int main(int argc, char* argv[]) -{ - if(argc > 1) - { - std::ifstream file_in(argv[1]); - if(file_in.is_open()) - { - file_in.seekg(0, std::_S_end); - auto length = file_in.tellg(); - char * data = new char[length]; - file_in.seekg(0); - file_in.read(data,length); - java::classfile cf (data, length); - java::annotation_table atable = cf.visible_class_annotations; - for(int i = 0; i < atable.size(); i++) - { - std::cout << atable[i]->toString() << std::endl; - } - return 0; - } - else - { - std::cerr << "Failed to open file : " << argv[1] << std::endl; - return 1; - } - } - std::cerr << "No file to open :(" << std::endl; - return 1; -} \ No newline at end of file diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt deleted file mode 100644 index 7f189458..00000000 --- a/launcher/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -cmake_minimum_required(VERSION 2.8.6) -project(launcher Java) -set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}") -find_package(Java 1.6 REQUIRED COMPONENTS Development) - - -include(UseJava) -set(CMAKE_JAVA_JAR_ENTRY_POINT MultiMCLauncher) -set(CMAKE_JAVA_COMPILE_FLAGS -target 1.6 -source 1.6 -Xlint:deprecation -Xlint:unchecked) -set(CMAKE_JAVA_TARGET_OUTPUT_DIR "${PROJECT_SOURCE_DIR}/../resources") - -set(SRC - MultiMCLauncher.java - org/simplericity/macify/eawt/Application.java - org/simplericity/macify/eawt/ApplicationAdapter.java - org/simplericity/macify/eawt/ApplicationEvent.java - org/simplericity/macify/eawt/ApplicationListener.java - org/simplericity/macify/eawt/DefaultApplication.java - net/minecraft/Launcher.java - MCFrame.java -) - -add_jar(MultiMCLauncher ${SRC}) \ No newline at end of file diff --git a/launcher/MCFrame.java b/launcher/MCFrame.java deleted file mode 100644 index d6ebb240..00000000 --- a/launcher/MCFrame.java +++ /dev/null @@ -1,123 +0,0 @@ -// -// Copyright 2012 MultiMC Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import net.minecraft.Launcher; -import java.applet.Applet; -import java.awt.Dimension; -import java.awt.Frame; -import java.awt.Toolkit; -import java.awt.event.WindowEvent; -import java.awt.event.WindowListener; -import java.net.MalformedURLException; -import java.net.URL; -import java.io.IOException; -import java.io.File; -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; - -public class MCFrame extends Frame implements WindowListener -{ - private Launcher appletWrap = null; - public MCFrame(String title) - { - super(title); - BufferedImage image = null; - try - { - image = ImageIO.read(new File("icon.png")); - setIconImage(image); - } - catch (IOException e) - { - e.printStackTrace(); - } - this.addWindowListener(this); - } - - public void start(Applet mcApplet, String user, String session, Dimension winSize, boolean maximize) - { - try - { - appletWrap = new Launcher(mcApplet, new URL("http://www.minecraft.net/game")); - } - catch (MalformedURLException ignored){} - - appletWrap.setParameter("username", user); - appletWrap.setParameter("sessionid", session); - appletWrap.setParameter("stand-alone", "true"); // Show the quit button. - mcApplet.setStub(appletWrap); - - this.add(appletWrap); - appletWrap.setPreferredSize(winSize); - this.pack(); - this.setLocationRelativeTo(null); - this.setResizable(true); - if (maximize) - this.setExtendedState(MAXIMIZED_BOTH); - - validate(); - appletWrap.init(); - appletWrap.start(); - setVisible(true); - } - - @Override - public void windowActivated(WindowEvent e) {} - - @Override - public void windowClosed(WindowEvent e) {} - - @Override - public void windowClosing(WindowEvent e) - { - new Thread() - { - public void run() - { - try - { - Thread.sleep(30000L); - } catch (InterruptedException localInterruptedException) - { - localInterruptedException.printStackTrace(); - } - System.out.println("FORCING EXIT!"); - System.exit(0); - } - } - .start(); - - if (appletWrap != null) - { - appletWrap.stop(); - appletWrap.destroy(); - } - // old minecraft versions can hang without this >_< - System.exit(0); - } - - @Override - public void windowDeactivated(WindowEvent e) {} - - @Override - public void windowDeiconified(WindowEvent e) {} - - @Override - public void windowIconified(WindowEvent e) {} - - @Override - public void windowOpened(WindowEvent e) {} -} \ No newline at end of file diff --git a/launcher/MultiMCLauncher.java b/launcher/MultiMCLauncher.java deleted file mode 100644 index 09a019ce..00000000 --- a/launcher/MultiMCLauncher.java +++ /dev/null @@ -1,331 +0,0 @@ -// -// Copyright 2012 MultiMC Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import java.applet.Applet; -import java.awt.Dimension; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; - -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import org.simplericity.macify.eawt.Application; -import org.simplericity.macify.eawt.DefaultApplication; - -public class MultiMCLauncher -{ - /** - * @param args - * The arguments you want to launch Minecraft with. New path, - * Username, Session ID. - */ - public static void main(String[] args) - { - if (args.length < 3) - { - System.out.println("Not enough arguments."); - System.exit(-1); - } - - // Set the OSX application icon first, if we are on OSX. - Application application = new DefaultApplication(); - if(application.isMac()) - { - try - { - BufferedImage image = ImageIO.read(new File("icon.png")); - application.setApplicationIconImage(image); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - String userName = args[0]; - String sessionId = args[1]; - String windowtitle = args[2]; - String windowParams = args[3]; - String lwjgl = args[4]; - String cwd = System.getProperty("user.dir"); - - Dimension winSize = new Dimension(854, 480); - boolean maximize = false; - boolean compatMode = false; - - - String[] dimStrings = windowParams.split("x"); - - if (windowParams.equalsIgnoreCase("compatmode")) - { - compatMode = true; - } - else if (windowParams.equalsIgnoreCase("max")) - { - maximize = true; - } - else if (dimStrings.length == 2) - { - try - { - winSize = new Dimension(Integer.parseInt(dimStrings[0]), - Integer.parseInt(dimStrings[1])); - } - catch (NumberFormatException e) - { - System.out.println("Invalid Window size argument, " + - "using default."); - } - } - else - { - System.out.println("Invalid Window size argument, " + - "using default."); - } - - try - { - File binDir = new File(cwd, "bin"); - File lwjglDir; - if(lwjgl.equalsIgnoreCase("Mojang")) - lwjglDir = binDir; - else - lwjglDir = new File(lwjgl); - - System.out.println("Loading jars..."); - String[] lwjglJars = new String[] { - "lwjgl.jar", "lwjgl_util.jar", "jinput.jar" - }; - - URL[] urls = new URL[4]; - try - { - File f = new File(binDir, "minecraft.jar"); - urls[0] = f.toURI().toURL(); - System.out.println("Loading URL: " + urls[0].toString()); - - for (int i = 1; i < urls.length; i++) - { - File jar = new File(lwjglDir, lwjglJars[i-1]); - urls[i] = jar.toURI().toURL(); - System.out.println("Loading URL: " + urls[i].toString()); - } - } - catch (MalformedURLException e) - { - System.err.println("MalformedURLException, " + e.toString()); - System.exit(5); - } - - System.out.println("Loading natives..."); - String nativesDir = new File(lwjglDir, "natives").toString(); - - System.setProperty("org.lwjgl.librarypath", nativesDir); - System.setProperty("net.java.games.input.librarypath", nativesDir); - - URLClassLoader cl = - new URLClassLoader(urls, MultiMCLauncher.class.getClassLoader()); - - // Get the Minecraft Class. - Class mc = null; - try - { - mc = cl.loadClass("net.minecraft.client.Minecraft"); - - Field f = getMCPathField(mc); - - if (f == null) - { - System.err.println("Could not find Minecraft path field. Launch failed."); - System.exit(-1); - } - - f.setAccessible(true); - f.set(null, new File(cwd)); - // And set it. - System.out.println("Fixed Minecraft Path: Field was " + f.toString()); - } - catch (ClassNotFoundException e) - { - System.err.println("Can't find main class. Searching..."); - - // Look for any class that looks like the main class. - File mcJar = new File(new File(cwd, "bin"), "minecraft.jar"); - ZipFile zip = null; - try - { - zip = new ZipFile(mcJar); - } catch (ZipException e1) - { - e1.printStackTrace(); - System.err.println("Search failed."); - System.exit(-1); - } catch (IOException e1) - { - e1.printStackTrace(); - System.err.println("Search failed."); - System.exit(-1); - } - - Enumeration entries = zip.entries(); - ArrayList classes = new ArrayList(); - - while (entries.hasMoreElements()) - { - ZipEntry entry = entries.nextElement(); - if (entry.getName().endsWith(".class")) - { - String entryName = entry.getName().substring(0, entry.getName().lastIndexOf('.')); - entryName = entryName.replace('/', '.'); - System.out.println("Found class: " + entryName); - classes.add(entryName); - } - } - - for (String clsName : classes) - { - try - { - Class cls = cl.loadClass(clsName); - if (!Runnable.class.isAssignableFrom(cls)) - { - continue; - } - else - { - System.out.println("Found class implementing runnable: " + - cls.getName()); - } - - if (getMCPathField(cls) == null) - { - continue; - } - else - { - System.out.println("Found class implementing runnable " + - "with mcpath field: " + cls.getName()); - } - - mc = cls; - break; - } - catch (ClassNotFoundException e1) - { - // Ignore - continue; - } - } - - if (mc == null) - { - System.err.println("Failed to find Minecraft main class."); - System.exit(-1); - } - else - { - System.out.println("Found main class: " + mc.getName()); - } - } - - System.setProperty("minecraft.applet.TargetDirectory", cwd); - - String[] mcArgs = new String[2]; - mcArgs[0] = userName; - mcArgs[1] = sessionId; - - if (compatMode) - { - System.out.println("Launching in compatibility mode..."); - mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs); - } - else - { - System.out.println("Launching with applet wrapper..."); - try - { - Class MCAppletClass = cl.loadClass( - "net.minecraft.client.MinecraftApplet"); - Applet mcappl = (Applet) MCAppletClass.newInstance(); - MCFrame mcWindow = new MCFrame(windowtitle); - mcWindow.start(mcappl, userName, sessionId, winSize, maximize); - } catch (InstantiationException e) - { - System.out.println("Applet wrapper failed! Falling back " + - "to compatibility mode."); - mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs); - } - } - } catch (ClassNotFoundException e) - { - e.printStackTrace(); - System.exit(1); - } catch (IllegalArgumentException e) - { - e.printStackTrace(); - System.exit(2); - } catch (IllegalAccessException e) - { - e.printStackTrace(); - System.exit(2); - } catch (InvocationTargetException e) - { - e.printStackTrace(); - System.exit(3); - } catch (NoSuchMethodException e) - { - e.printStackTrace(); - System.exit(3); - } catch (SecurityException e) - { - e.printStackTrace(); - System.exit(4); - } - } - - public static Field getMCPathField(Class mc) - { - Field[] fields = mc.getDeclaredFields(); - - for (int i = 0; i < fields.length; i++) - { - Field f = fields[i]; - if (f.getType() != File.class) - { - // Has to be File - continue; - } - if (f.getModifiers() != (Modifier.PRIVATE + Modifier.STATIC)) - { - // And Private Static. - continue; - } - return f; - } - return null; - } -} diff --git a/launcher/UseJava.cmake b/launcher/UseJava.cmake deleted file mode 100644 index 1a5ef107..00000000 --- a/launcher/UseJava.cmake +++ /dev/null @@ -1,881 +0,0 @@ -# - Use Module for Java -# This file provides functions for Java. It is assumed that FindJava.cmake -# has already been loaded. See FindJava.cmake for information on how to -# load Java into your CMake project. -# -# add_jar(TARGET_NAME SRC1 SRC2 .. SRCN RCS1 RCS2 .. RCSN) -# -# This command creates a .jar. It compiles the given source -# files (SRC) and adds the given resource files (RCS) to the jar file. -# If only resource files are given then just a jar file is created. -# -# Additional instructions: -# To add compile flags to the target you can set these flags with -# the following variable: -# -# set(CMAKE_JAVA_COMPILE_FLAGS -nowarn) -# -# To add a path or a jar file to the class path you can do this -# with the CMAKE_JAVA_INCLUDE_PATH variable. -# -# set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar) -# -# To use a different output name for the target you can set it with: -# -# set(CMAKE_JAVA_TARGET_OUTPUT_NAME shibboleet.jar) -# add_jar(foobar foobar.java) -# -# To use a different output directory than CMAKE_CURRENT_BINARY_DIR -# you can set it with: -# -# set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin) -# -# To define an entry point in your jar you can set it with: -# -# set(CMAKE_JAVA_JAR_ENTRY_POINT com/examples/MyProject/Main) -# -# To add a VERSION to the target output name you can set it using -# CMAKE_JAVA_TARGET_VERSION. This will create a jar file with the name -# shibboleet-1.0.0.jar and will create a symlink shibboleet.jar -# pointing to the jar with the version information. -# -# set(CMAKE_JAVA_TARGET_VERSION 1.2.0) -# add_jar(shibboleet shibbotleet.java) -# -# If the target is a JNI library, utilize the following commands to -# create a JNI symbolic link: -# -# set(CMAKE_JNI_TARGET TRUE) -# set(CMAKE_JAVA_TARGET_VERSION 1.2.0) -# add_jar(shibboleet shibbotleet.java) -# install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet) -# install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR}) -# -# If a single target needs to produce more than one jar from its -# java source code, to prevent the accumulation of duplicate class -# files in subsequent jars, set/reset CMAKE_JAR_CLASSES_PREFIX prior -# to calling the add_jar() function: -# -# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo) -# add_jar(foo foo.java) -# -# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar) -# add_jar(bar bar.java) -# -# Target Properties: -# The add_jar() functions sets some target properties. You can get these -# properties with the -# get_property(TARGET PROPERTY ) -# command. -# -# INSTALL_FILES The files which should be installed. This is used by -# install_jar(). -# JNI_SYMLINK The JNI symlink which should be installed. -# This is used by install_jni_symlink(). -# JAR_FILE The location of the jar file so that you can include -# it. -# CLASS_DIR The directory where the class files can be found. For -# example to use them with javah. -# -# find_jar( -# name | NAMES name1 [name2 ...] -# [PATHS path1 [path2 ... ENV var]] -# [VERSIONS version1 [version2]] -# [DOC "cache documentation string"] -# ) -# -# This command is used to find a full path to the named jar. A cache -# entry named by is created to stor the result of this command. If -# the full path to a jar is found the result is stored in the variable -# and the search will not repeated unless the variable is cleared. If -# nothing is found, the result will be -NOTFOUND, and the search -# will be attempted again next time find_jar is invoked with the same -# variable. -# The name of the full path to a file that is searched for is specified -# by the names listed after NAMES argument. Additional search locations -# can be specified after the PATHS argument. If you require special a -# version of a jar file you can specify it with the VERSIONS argument. -# The argument after DOC will be used for the documentation string in -# the cache. -# -# install_jar(TARGET_NAME DESTINATION) -# -# This command installs the TARGET_NAME files to the given DESTINATION. -# It should be called in the same scope as add_jar() or it will fail. -# -# install_jni_symlink(TARGET_NAME DESTINATION) -# -# This command installs the TARGET_NAME JNI symlinks to the given -# DESTINATION. It should be called in the same scope as add_jar() -# or it will fail. -# -# create_javadoc( -# PACKAGES pkg1 [pkg2 ...] -# [SOURCEPATH ] -# [CLASSPATH ] -# [INSTALLPATH ] -# [DOCTITLE "the documentation title"] -# [WINDOWTITLE "the title of the document"] -# [AUTHOR TRUE|FALSE] -# [USE TRUE|FALSE] -# [VERSION TRUE|FALSE] -# ) -# -# Create java documentation based on files or packages. For more -# details please read the javadoc manpage. -# -# There are two main signatures for create_javadoc. The first -# signature works with package names on a path with source files: -# -# Example: -# create_javadoc(my_example_doc -# PACKAGES com.exmaple.foo com.example.bar -# SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}" -# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH} -# WINDOWTITLE "My example" -# DOCTITLE "

My example

" -# AUTHOR TRUE -# USE TRUE -# VERSION TRUE -# ) -# -# The second signature for create_javadoc works on a given list of -# files. -# -# create_javadoc( -# FILES file1 [file2 ...] -# [CLASSPATH ] -# [INSTALLPATH ] -# [DOCTITLE "the documentation title"] -# [WINDOWTITLE "the title of the document"] -# [AUTHOR TRUE|FALSE] -# [USE TRUE|FALSE] -# [VERSION TRUE|FALSE] -# ) -# -# Example: -# create_javadoc(my_example_doc -# FILES ${example_SRCS} -# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH} -# WINDOWTITLE "My example" -# DOCTITLE "

My example

" -# AUTHOR TRUE -# USE TRUE -# VERSION TRUE -# ) -# -# Both signatures share most of the options. These options are the -# same as what you can find in the javadoc manpage. Please look at -# the manpage for CLASSPATH, DOCTITLE, WINDOWTITLE, AUTHOR, USE and -# VERSION. -# -# The documentation will be by default installed to -# -# ${CMAKE_INSTALL_PREFIX}/share/javadoc/ -# -# if you don't set the INSTALLPATH. -# - -#============================================================================= -# Copyright 2010-2011 Andreas schneider -# Copyright 2010 Ben Boeckel -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -function (__java_copy_file src dest comment) - add_custom_command( - OUTPUT ${dest} - COMMAND cmake -E copy_if_different - ARGS ${src} - ${dest} - DEPENDS ${src} - COMMENT ${comment}) -endfunction (__java_copy_file src dest comment) - -# define helper scripts -set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake) -set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake) - -function(add_jar _TARGET_NAME) - set(_JAVA_SOURCE_FILES ${ARGN}) - - if (NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR) - set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) - endif(NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR) - - if (CMAKE_JAVA_JAR_ENTRY_POINT) - set(_ENTRY_POINT_OPTION e) - set(_ENTRY_POINT_VALUE ${CMAKE_JAVA_JAR_ENTRY_POINT}) - endif (CMAKE_JAVA_JAR_ENTRY_POINT) - - if (LIBRARY_OUTPUT_PATH) - set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}) - else (LIBRARY_OUTPUT_PATH) - set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR}) - endif (LIBRARY_OUTPUT_PATH) - - set(CMAKE_JAVA_INCLUDE_PATH - ${CMAKE_JAVA_INCLUDE_PATH} - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_JAVA_OBJECT_OUTPUT_PATH} - ${CMAKE_JAVA_LIBRARY_OUTPUT_PATH} - ) - - if (WIN32 AND NOT CYGWIN AND NOT CMAKE_CROSSCOMPILING) - set(CMAKE_JAVA_INCLUDE_FLAG_SEP ";") - else () - set(CMAKE_JAVA_INCLUDE_FLAG_SEP ":") - endif() - - foreach (JAVA_INCLUDE_DIR ${CMAKE_JAVA_INCLUDE_PATH}) - set(CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_PATH_FINAL}${CMAKE_JAVA_INCLUDE_FLAG_SEP}${JAVA_INCLUDE_DIR}") - endforeach(JAVA_INCLUDE_DIR) - - set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_JAVA_TARGET_OUTPUT_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir") - - set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar") - if (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION) - set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") - set(_JAVA_TARGET_OUTPUT_LINK "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") - elseif (CMAKE_JAVA_TARGET_VERSION) - set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") - set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar") - elseif (CMAKE_JAVA_TARGET_OUTPUT_NAME) - set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") - endif (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION) - # reset - set(CMAKE_JAVA_TARGET_OUTPUT_NAME) - - set(_JAVA_CLASS_FILES) - set(_JAVA_COMPILE_FILES) - set(_JAVA_DEPENDS) - set(_JAVA_RESOURCE_FILES) - foreach(_JAVA_SOURCE_FILE ${_JAVA_SOURCE_FILES}) - get_filename_component(_JAVA_EXT ${_JAVA_SOURCE_FILE} EXT) - get_filename_component(_JAVA_FILE ${_JAVA_SOURCE_FILE} NAME_WE) - get_filename_component(_JAVA_PATH ${_JAVA_SOURCE_FILE} PATH) - get_filename_component(_JAVA_FULL ${_JAVA_SOURCE_FILE} ABSOLUTE) - - file(RELATIVE_PATH _JAVA_REL_BINARY_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR} ${_JAVA_FULL}) - file(RELATIVE_PATH _JAVA_REL_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${_JAVA_FULL}) - string(LENGTH ${_JAVA_REL_BINARY_PATH} _BIN_LEN) - string(LENGTH ${_JAVA_REL_SOURCE_PATH} _SRC_LEN) - if (${_BIN_LEN} LESS ${_SRC_LEN}) - set(_JAVA_REL_PATH ${_JAVA_REL_BINARY_PATH}) - else (${_BIN_LEN} LESS ${_SRC_LEN}) - set(_JAVA_REL_PATH ${_JAVA_REL_SOURCE_PATH}) - endif (${_BIN_LEN} LESS ${_SRC_LEN}) - get_filename_component(_JAVA_REL_PATH ${_JAVA_REL_PATH} PATH) - - if (_JAVA_EXT MATCHES ".java") - list(APPEND _JAVA_COMPILE_FILES ${_JAVA_SOURCE_FILE}) - set(_JAVA_CLASS_FILE "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_REL_PATH}/${_JAVA_FILE}.class") - set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES} ${_JAVA_CLASS_FILE}) - - elseif (_JAVA_EXT MATCHES ".jar" - OR _JAVA_EXT MATCHES ".war" - OR _JAVA_EXT MATCHES ".ear" - OR _JAVA_EXT MATCHES ".sar") - list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_SOURCE_FILE}) - - elseif (_JAVA_EXT STREQUAL "") - list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH}) - list(APPEND _JAVA_DEPENDS ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}}) - - else (_JAVA_EXT MATCHES ".java") - __java_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/${_JAVA_SOURCE_FILE} - ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_SOURCE_FILE} - "Copying ${_JAVA_SOURCE_FILE} to the build directory") - list(APPEND _JAVA_RESOURCE_FILES ${_JAVA_SOURCE_FILE}) - endif (_JAVA_EXT MATCHES ".java") - endforeach(_JAVA_SOURCE_FILE) - - # create an empty java_class_filelist - if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist) - file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "") - endif() - - if (_JAVA_COMPILE_FILES) - # Compile the java files and create a list of class files - add_custom_command( - # NOTE: this command generates an artificial dependency file - OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} - COMMAND ${Java_JAVAC_EXECUTABLE} - ${CMAKE_JAVA_COMPILE_FLAGS} - -classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}" - -d ${CMAKE_JAVA_CLASS_OUTPUT_PATH} - ${_JAVA_COMPILE_FILES} - COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} - DEPENDS ${_JAVA_COMPILE_FILES} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMENT "Building Java objects for ${_TARGET_NAME}.jar" - ) - add_custom_command( - OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist - COMMAND ${CMAKE_COMMAND} - -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH} - -DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}" - -P ${_JAVA_CLASS_FILELIST_SCRIPT} - DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) - endif (_JAVA_COMPILE_FILES) - - # create the jar file - set(_JAVA_JAR_OUTPUT_PATH - ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME}) - if (CMAKE_JNI_TARGET) - add_custom_command( - OUTPUT ${_JAVA_JAR_OUTPUT_PATH} - COMMAND ${Java_JAR_EXECUTABLE} - -cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE} - ${_JAVA_RESOURCE_FILES} @java_class_filelist - COMMAND ${CMAKE_COMMAND} - -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} - -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME} - -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} - -P ${_JAVA_SYMLINK_SCRIPT} - COMMAND ${CMAKE_COMMAND} - -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} - -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_JAR_OUTPUT_PATH} - -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} - -P ${_JAVA_SYMLINK_SCRIPT} - DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist - WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH} - COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}" - ) - else () - add_custom_command( - OUTPUT ${_JAVA_JAR_OUTPUT_PATH} - COMMAND ${Java_JAR_EXECUTABLE} - -cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE} - ${_JAVA_RESOURCE_FILES} @java_class_filelist - COMMAND ${CMAKE_COMMAND} - -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} - -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME} - -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} - -P ${_JAVA_SYMLINK_SCRIPT} - WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH} - DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist - COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}" - ) - endif (CMAKE_JNI_TARGET) - - # Add the target and make sure we have the latest resource files. - add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH}) - - set_property( - TARGET - ${_TARGET_NAME} - PROPERTY - INSTALL_FILES - ${_JAVA_JAR_OUTPUT_PATH} - ) - - if (_JAVA_TARGET_OUTPUT_LINK) - set_property( - TARGET - ${_TARGET_NAME} - PROPERTY - INSTALL_FILES - ${_JAVA_JAR_OUTPUT_PATH} - ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK} - ) - - if (CMAKE_JNI_TARGET) - set_property( - TARGET - ${_TARGET_NAME} - PROPERTY - JNI_SYMLINK - ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK} - ) - endif (CMAKE_JNI_TARGET) - endif (_JAVA_TARGET_OUTPUT_LINK) - - set_property( - TARGET - ${_TARGET_NAME} - PROPERTY - JAR_FILE - ${_JAVA_JAR_OUTPUT_PATH} - ) - - set_property( - TARGET - ${_TARGET_NAME} - PROPERTY - CLASSDIR - ${CMAKE_JAVA_CLASS_OUTPUT_PATH} - ) - -endfunction(add_jar) - -function(INSTALL_JAR _TARGET_NAME _DESTINATION) - get_property(__FILES - TARGET - ${_TARGET_NAME} - PROPERTY - INSTALL_FILES - ) - - if (__FILES) - install( - FILES - ${__FILES} - DESTINATION - ${_DESTINATION} - ) - else (__FILES) - message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.") - endif (__FILES) -endfunction(INSTALL_JAR _TARGET_NAME _DESTINATION) - -function(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION) - get_property(__SYMLINK - TARGET - ${_TARGET_NAME} - PROPERTY - JNI_SYMLINK - ) - - if (__SYMLINK) - install( - FILES - ${__SYMLINK} - DESTINATION - ${_DESTINATION} - ) - else (__SYMLINK) - message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.") - endif (__SYMLINK) -endfunction(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION) - -function (find_jar VARIABLE) - set(_jar_names) - set(_jar_files) - set(_jar_versions) - set(_jar_paths - /usr/share/java/ - /usr/local/share/java/ - ${Java_JAR_PATHS}) - set(_jar_doc "NOTSET") - - set(_state "name") - - foreach (arg ${ARGN}) - if (${_state} STREQUAL "name") - if (${arg} STREQUAL "VERSIONS") - set(_state "versions") - elseif (${arg} STREQUAL "NAMES") - set(_state "names") - elseif (${arg} STREQUAL "PATHS") - set(_state "paths") - elseif (${arg} STREQUAL "DOC") - set(_state "doc") - else (${arg} STREQUAL "NAMES") - set(_jar_names ${arg}) - if (_jar_doc STREQUAL "NOTSET") - set(_jar_doc "Finding ${arg} jar") - endif (_jar_doc STREQUAL "NOTSET") - endif (${arg} STREQUAL "VERSIONS") - elseif (${_state} STREQUAL "versions") - if (${arg} STREQUAL "NAMES") - set(_state "names") - elseif (${arg} STREQUAL "PATHS") - set(_state "paths") - elseif (${arg} STREQUAL "DOC") - set(_state "doc") - else (${arg} STREQUAL "NAMES") - set(_jar_versions ${_jar_versions} ${arg}) - endif (${arg} STREQUAL "NAMES") - elseif (${_state} STREQUAL "names") - if (${arg} STREQUAL "VERSIONS") - set(_state "versions") - elseif (${arg} STREQUAL "PATHS") - set(_state "paths") - elseif (${arg} STREQUAL "DOC") - set(_state "doc") - else (${arg} STREQUAL "VERSIONS") - set(_jar_names ${_jar_names} ${arg}) - if (_jar_doc STREQUAL "NOTSET") - set(_jar_doc "Finding ${arg} jar") - endif (_jar_doc STREQUAL "NOTSET") - endif (${arg} STREQUAL "VERSIONS") - elseif (${_state} STREQUAL "paths") - if (${arg} STREQUAL "VERSIONS") - set(_state "versions") - elseif (${arg} STREQUAL "NAMES") - set(_state "names") - elseif (${arg} STREQUAL "DOC") - set(_state "doc") - else (${arg} STREQUAL "VERSIONS") - set(_jar_paths ${_jar_paths} ${arg}) - endif (${arg} STREQUAL "VERSIONS") - elseif (${_state} STREQUAL "doc") - if (${arg} STREQUAL "VERSIONS") - set(_state "versions") - elseif (${arg} STREQUAL "NAMES") - set(_state "names") - elseif (${arg} STREQUAL "PATHS") - set(_state "paths") - else (${arg} STREQUAL "VERSIONS") - set(_jar_doc ${arg}) - endif (${arg} STREQUAL "VERSIONS") - endif (${_state} STREQUAL "name") - endforeach (arg ${ARGN}) - - if (NOT _jar_names) - message(FATAL_ERROR "find_jar: No name to search for given") - endif (NOT _jar_names) - - foreach (jar_name ${_jar_names}) - foreach (version ${_jar_versions}) - set(_jar_files ${_jar_files} ${jar_name}-${version}.jar) - endforeach (version ${_jar_versions}) - set(_jar_files ${_jar_files} ${jar_name}.jar) - endforeach (jar_name ${_jar_names}) - - find_file(${VARIABLE} - NAMES ${_jar_files} - PATHS ${_jar_paths} - DOC ${_jar_doc} - NO_DEFAULT_PATH) -endfunction (find_jar VARIABLE) - -function(create_javadoc _target) - set(_javadoc_packages) - set(_javadoc_files) - set(_javadoc_sourcepath) - set(_javadoc_classpath) - set(_javadoc_installpath "${CMAKE_INSTALL_PREFIX}/share/javadoc") - set(_javadoc_doctitle) - set(_javadoc_windowtitle) - set(_javadoc_author FALSE) - set(_javadoc_version FALSE) - set(_javadoc_use FALSE) - - set(_state "package") - - foreach (arg ${ARGN}) - if (${_state} STREQUAL "package") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_packages ${arg}) - set(_state "packages") - endif () - elseif (${_state} STREQUAL "packages") - if (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - list(APPEND _javadoc_packages ${arg}) - endif () - elseif (${_state} STREQUAL "files") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - list(APPEND _javadoc_files ${arg}) - endif () - elseif (${_state} STREQUAL "sourcepath") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - list(APPEND _javadoc_sourcepath ${arg}) - endif () - elseif (${_state} STREQUAL "classpath") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - list(APPEND _javadoc_classpath ${arg}) - endif () - elseif (${_state} STREQUAL "installpath") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_installpath ${arg}) - endif () - elseif (${_state} STREQUAL "doctitle") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_doctitle ${arg}) - endif () - elseif (${_state} STREQUAL "windowtitle") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_windowtitle ${arg}) - endif () - elseif (${_state} STREQUAL "author") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_author ${arg}) - endif () - elseif (${_state} STREQUAL "use") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_use ${arg}) - endif () - elseif (${_state} STREQUAL "version") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_version ${arg}) - endif () - endif (${_state} STREQUAL "package") - endforeach (arg ${ARGN}) - - set(_javadoc_builddir ${CMAKE_CURRENT_BINARY_DIR}/javadoc/${_target}) - set(_javadoc_options -d ${_javadoc_builddir}) - - if (_javadoc_sourcepath) - set(_start TRUE) - foreach(_path ${_javadoc_sourcepath}) - if (_start) - set(_sourcepath ${_path}) - set(_start FALSE) - else (_start) - set(_sourcepath ${_sourcepath}:${_path}) - endif (_start) - endforeach(_path ${_javadoc_sourcepath}) - set(_javadoc_options ${_javadoc_options} -sourcepath ${_sourcepath}) - endif (_javadoc_sourcepath) - - if (_javadoc_classpath) - set(_start TRUE) - foreach(_path ${_javadoc_classpath}) - if (_start) - set(_classpath ${_path}) - set(_start FALSE) - else (_start) - set(_classpath ${_classpath}:${_path}) - endif (_start) - endforeach(_path ${_javadoc_classpath}) - set(_javadoc_options ${_javadoc_options} -classpath "${_classpath}") - endif (_javadoc_classpath) - - if (_javadoc_doctitle) - set(_javadoc_options ${_javadoc_options} -doctitle '${_javadoc_doctitle}') - endif (_javadoc_doctitle) - - if (_javadoc_windowtitle) - set(_javadoc_options ${_javadoc_options} -windowtitle '${_javadoc_windowtitle}') - endif (_javadoc_windowtitle) - - if (_javadoc_author) - set(_javadoc_options ${_javadoc_options} -author) - endif (_javadoc_author) - - if (_javadoc_use) - set(_javadoc_options ${_javadoc_options} -use) - endif (_javadoc_use) - - if (_javadoc_version) - set(_javadoc_options ${_javadoc_options} -version) - endif (_javadoc_version) - - add_custom_target(${_target}_javadoc ALL - COMMAND ${Java_JAVADOC_EXECUTABLE} ${_javadoc_options} - ${_javadoc_files} - ${_javadoc_packages} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) - - install( - DIRECTORY ${_javadoc_builddir} - DESTINATION ${_javadoc_installpath} - ) -endfunction(create_javadoc) diff --git a/launcher/UseJavaClassFilelist.cmake b/launcher/UseJavaClassFilelist.cmake deleted file mode 100644 index c842bf71..00000000 --- a/launcher/UseJavaClassFilelist.cmake +++ /dev/null @@ -1,52 +0,0 @@ -# -# This script create a list of compiled Java class files to be added to a -# jar file. This avoids including cmake files which get created in the -# binary directory. -# - -#============================================================================= -# Copyright 2010-2011 Andreas schneider -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -if (CMAKE_JAVA_CLASS_OUTPUT_PATH) - if (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}") - - set(_JAVA_GLOBBED_FILES) - if (CMAKE_JAR_CLASSES_PREFIX) - foreach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX}) - message(STATUS "JAR_CLASS_PREFIX: ${JAR_CLASS_PREFIX}") - - file(GLOB_RECURSE _JAVA_GLOBBED_TMP_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${JAR_CLASS_PREFIX}/*.class") - if (_JAVA_GLOBBED_TMP_FILES) - list(APPEND _JAVA_GLOBBED_FILES ${_JAVA_GLOBBED_TMP_FILES}) - endif (_JAVA_GLOBBED_TMP_FILES) - endforeach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX}) - else() - file(GLOB_RECURSE _JAVA_GLOBBED_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/*.class") - endif (CMAKE_JAR_CLASSES_PREFIX) - - set(_JAVA_CLASS_FILES) - # file(GLOB_RECURSE foo RELATIVE) is broken so we need this. - foreach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES}) - file(RELATIVE_PATH _JAVA_CLASS_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ${_JAVA_GLOBBED_FILE}) - set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES}${_JAVA_CLASS_FILE}\n) - endforeach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES}) - - # write to file - file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist ${_JAVA_CLASS_FILES}) - - else (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}") - message(SEND_ERROR "FATAL: Java class output path doesn't exist") - endif (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}") -else (CMAKE_JAVA_CLASS_OUTPUT_PATH) - message(SEND_ERROR "FATAL: Can't find CMAKE_JAVA_CLASS_OUTPUT_PATH") -endif (CMAKE_JAVA_CLASS_OUTPUT_PATH) diff --git a/launcher/UseJavaSymlinks.cmake b/launcher/UseJavaSymlinks.cmake deleted file mode 100644 index c66ee1ea..00000000 --- a/launcher/UseJavaSymlinks.cmake +++ /dev/null @@ -1,32 +0,0 @@ -# -# Helper script for UseJava.cmake -# - -#============================================================================= -# Copyright 2010-2011 Andreas schneider -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -if (UNIX AND _JAVA_TARGET_OUTPUT_LINK) - if (_JAVA_TARGET_OUTPUT_NAME) - find_program(LN_EXECUTABLE - NAMES - ln - ) - - execute_process( - COMMAND ${LN_EXECUTABLE} -sf "${_JAVA_TARGET_OUTPUT_NAME}" "${_JAVA_TARGET_OUTPUT_LINK}" - WORKING_DIRECTORY ${_JAVA_TARGET_DIR} - ) - else (_JAVA_TARGET_OUTPUT_NAME) - message(SEND_ERROR "FATAL: Can't find _JAVA_TARGET_OUTPUT_NAME") - endif (_JAVA_TARGET_OUTPUT_NAME) -endif (UNIX AND _JAVA_TARGET_OUTPUT_LINK) diff --git a/launcher/net/minecraft/Launcher.java b/launcher/net/minecraft/Launcher.java deleted file mode 100644 index 8cef35ad..00000000 --- a/launcher/net/minecraft/Launcher.java +++ /dev/null @@ -1,154 +0,0 @@ -// -// Copyright 2012 MultiMC Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package net.minecraft; - -import java.util.TreeMap; -import java.util.Map; -import java.net.URL; -import java.awt.Dimension; -import java.awt.BorderLayout; -import java.awt.Graphics; -import java.applet.Applet; -import java.applet.AppletStub; - -public class Launcher extends Applet implements AppletStub -{ - private Applet wrappedApplet; - private URL documentBase; - private boolean active = false; - private final Map params; - - public Launcher(Applet applet, URL documentBase) - { - params = new TreeMap(); - - this.setLayout(new BorderLayout()); - this.add(applet, "Center"); - this.wrappedApplet = applet; - this.documentBase = documentBase; - } - - public void setParameter(String name, String value) - { - params.put(name, value); - } - - public void replace(Applet applet) - { - this.wrappedApplet = applet; - - applet.setStub(this); - applet.setSize(getWidth(), getHeight()); - - this.setLayout(new BorderLayout()); - this.add(applet, "Center"); - - applet.init(); - active = true; - applet.start(); - validate(); - } - - @Override - public String getParameter(String name) - { - String param = params.get(name); - if (param != null) - return param; - try - { - return super.getParameter(name); - } catch (Exception ignore){} - return null; - } - - @Override - public boolean isActive() - { - return active; - } - - @Override - public void appletResize(int width, int height) - { - wrappedApplet.resize(width, height); - } - - @Override - public void resize(int width, int height) - { - wrappedApplet.resize(width, height); - } - - @Override - public void resize(Dimension d) - { - wrappedApplet.resize(d); - } - - @Override - public void init() - { - if (wrappedApplet != null) - { - wrappedApplet.init(); - } - } - - @Override - public void start() - { - wrappedApplet.start(); - active = true; - } - - @Override - public void stop() - { - wrappedApplet.stop(); - active = false; - } - - public void destroy() - { - wrappedApplet.destroy(); - } - - @Override - public URL getCodeBase() { - return wrappedApplet.getCodeBase(); - } - - @Override - public URL getDocumentBase() - { - return documentBase; - } - - @Override - public void setVisible(boolean b) - { - super.setVisible(b); - wrappedApplet.setVisible(b); - } - public void update(Graphics paramGraphics) - { - } - public void paint(Graphics paramGraphics) - { - } -} \ No newline at end of file diff --git a/launcher/org/simplericity/macify/eawt/Application.java b/launcher/org/simplericity/macify/eawt/Application.java deleted file mode 100644 index 153bb9ee..00000000 --- a/launcher/org/simplericity/macify/eawt/Application.java +++ /dev/null @@ -1,176 +0,0 @@ -package org.simplericity.macify.eawt; - -/* - * Copyright 2007 Eirik Bjorsnos. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import java.awt.*; -import java.awt.image.BufferedImage; - -/** - * The Macify Library API interface provides integration with the OS X platform for Java Applications. - * The API includes a facade to the - * - * Apple Java Extensions API - * . - * Additionally, it provides access to several useful methods in the Cocoa NSApplication API. - * - * The default implementation of this interface is {@link org.simplericity.macify.eawt.DefaultApplication}. - */ -public interface Application { - - static int REQUEST_USER_ATTENTION_TYPE_CRITICAL = 1 ; - static int REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL = 2 ; - - /** - * See - * - * Apple's API - * . - */ - void addAboutMenuItem(); - - /** - * See - * - * Apple's API - * . - */ - void addApplicationListener(ApplicationListener applicationListener); - - /** - * See - * - * Apple's API - * . - */ - void addPreferencesMenuItem(); - - /** - * See - * - * Apple's API - * . - */ - boolean getEnabledAboutMenu(); - - /** - * See - * - * Apple's API - * . - */ - boolean getEnabledPreferencesMenu(); - - /** - * See - * - * Apple's API - * . - */ - boolean isAboutMenuItemPresent(); - - /** - * See - * - * Apple's API - * . - */ - boolean isPreferencesMenuItemPresent(); - - /** - * See - * - * Apple's API - * . - */ - void removeAboutMenuItem(); - - /** - * See - * - * Apple's API - * . - */ - void removeApplicationListener(ApplicationListener applicationListener); - - /** - * See - * - * Apple's API - * . - */ - void removePreferencesMenuItem(); - - /** - * See - * - * Apple's API - * . - */ - void setEnabledAboutMenu(boolean enabled); - - /** - * See - * - * Apple's API - * . - */ - void setEnabledPreferencesMenu(boolean enabled); - - /** - * See - * - * Apple's API - * . - */ - Point getMouseLocationOnScreen(); - - /** - * See - * - * Apple's NSApplication Class Reference - * . - * @param type on of {@link #REQUEST_USER_ATTENTION_TYPE_CRITICAL} or {@link #REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL}. - */ - int requestUserAttention(int type); - - /** - * See - * - * Apple's NSApplication Class Reference - * - */ - void cancelUserAttentionRequest(int request); - - /** - * Update the application's icon image - * @param image - */ - void setApplicationIconImage(BufferedImage image); - - /** - * Get the application's icon image. - */ - BufferedImage getApplicationIconImage(); - - /** - * Determines whether the application is running on a Mac AND the Apple Extensions API classes are available. - * @return - */ - boolean isMac(); - - -} diff --git a/launcher/org/simplericity/macify/eawt/ApplicationAdapter.java b/launcher/org/simplericity/macify/eawt/ApplicationAdapter.java deleted file mode 100644 index e9c3db7d..00000000 --- a/launcher/org/simplericity/macify/eawt/ApplicationAdapter.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.simplericity.macify.eawt; - -/* - * Copyright 2007 Eirik Bjorsnos. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -public class ApplicationAdapter implements ApplicationListener { - - public void handleQuit(ApplicationEvent event) { - - } - - public void handleAbout(ApplicationEvent event) { - - } - - public void handleOpenApplication(ApplicationEvent event) { - - } - - public void handleOpenFile(ApplicationEvent event) { - - } - - public void handlePreferences(ApplicationEvent event) { - - } - - public void handlePrintFile(ApplicationEvent event) { - - } - - public void handleReOpenApplication(ApplicationEvent event) { - - } -} diff --git a/launcher/org/simplericity/macify/eawt/ApplicationEvent.java b/launcher/org/simplericity/macify/eawt/ApplicationEvent.java deleted file mode 100644 index 78420355..00000000 --- a/launcher/org/simplericity/macify/eawt/ApplicationEvent.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.simplericity.macify.eawt; - -/* - * Copyright 2007 Eirik Bjorsnos. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -public interface ApplicationEvent { - String getFilename(); - boolean isHandled(); - void setHandled(boolean handled); - Object getSource(); - String toString(); -} diff --git a/launcher/org/simplericity/macify/eawt/ApplicationListener.java b/launcher/org/simplericity/macify/eawt/ApplicationListener.java deleted file mode 100644 index a291bee4..00000000 --- a/launcher/org/simplericity/macify/eawt/ApplicationListener.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.simplericity.macify.eawt; - -/* - * Copyright 2007 Eirik Bjorsnos. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -public interface ApplicationListener { - void handleAbout(ApplicationEvent event); - void handleOpenApplication(ApplicationEvent event); - void handleOpenFile(ApplicationEvent event); - void handlePreferences(ApplicationEvent event); - void handlePrintFile(ApplicationEvent event); - void handleQuit(ApplicationEvent event); - void handleReOpenApplication(ApplicationEvent event); -} diff --git a/launcher/org/simplericity/macify/eawt/DefaultApplication.java b/launcher/org/simplericity/macify/eawt/DefaultApplication.java deleted file mode 100644 index 5752a350..00000000 --- a/launcher/org/simplericity/macify/eawt/DefaultApplication.java +++ /dev/null @@ -1,418 +0,0 @@ -package org.simplericity.macify.eawt; - -/* - * Copyright 2007 Eirik Bjorsnos. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import javax.imageio.ImageIO; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.io.*; -import java.lang.reflect.*; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.MalformedURLException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - - -/** - * Implements Application by calling the Mac OS X API through reflection. - * If this class is used on a non-OS X platform the operations will have no effect or they will simulate - * what the Apple API would do for those who manipulate state. ({@link #setEnabledAboutMenu(boolean)} etc.) - */ -@SuppressWarnings("unchecked") -public class DefaultApplication implements Application { - - private Object application; - private Class applicationListenerClass; - - Map listenerMap = Collections.synchronizedMap(new HashMap()); - private boolean enabledAboutMenu = true; - private boolean enabledPreferencesMenu; - private boolean aboutMenuItemPresent = true; - private boolean preferencesMenuItemPresent; - private ClassLoader classLoader; - - public DefaultApplication() { - try { - final File file = new File("/System/Library/Java"); - if (file.exists()) { - ClassLoader scl = ClassLoader.getSystemClassLoader(); - Class clc = scl.getClass(); - if (URLClassLoader.class.isAssignableFrom(clc)) { - Method addUrl = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class}); - addUrl.setAccessible(true); - addUrl.invoke(scl, new Object[]{file.toURI().toURL()}); - } - } - - Class appClass = Class.forName("com.apple.eawt.Application"); - application = appClass.getMethod("getApplication", new Class[0]).invoke(null, new Object[0]); - applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener"); - } catch (ClassNotFoundException e) { - application = null; - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - - } - - public boolean isMac() { - return application != null; - } - - public void addAboutMenuItem() { - if (isMac()) { - callMethod(application, "addAboutMenuItem"); - } else { - this.aboutMenuItemPresent = true; - } - } - - public void addApplicationListener(ApplicationListener applicationListener) { - - if (!Modifier.isPublic(applicationListener.getClass().getModifiers())) { - throw new IllegalArgumentException("ApplicationListener must be a public class"); - } - if (isMac()) { - Object listener = Proxy.newProxyInstance(getClass().getClassLoader(), - new Class[]{applicationListenerClass}, - new ApplicationListenerInvocationHandler(applicationListener)); - - callMethod(application, "addApplicationListener", new Class[]{applicationListenerClass}, new Object[]{listener}); - listenerMap.put(applicationListener, listener); - } else { - listenerMap.put(applicationListener, applicationListener); - } - } - - public void addPreferencesMenuItem() { - if (isMac()) { - callMethod("addPreferencesMenuItem"); - } else { - this.preferencesMenuItemPresent = true; - } - } - - public boolean getEnabledAboutMenu() { - if (isMac()) { - return callMethod("getEnabledAboutMenu").equals(Boolean.TRUE); - } else { - return enabledAboutMenu; - } - } - - public boolean getEnabledPreferencesMenu() { - if (isMac()) { - Object result = callMethod("getEnabledPreferencesMenu"); - return result.equals(Boolean.TRUE); - } else { - return enabledPreferencesMenu; - } - } - - public Point getMouseLocationOnScreen() { - if (isMac()) { - try { - Method method = application.getClass().getMethod("getMouseLocationOnScreen", new Class[0]); - return (Point) method.invoke(null, new Object[0]); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } else { - return new Point(0, 0); - } - } - - public boolean isAboutMenuItemPresent() { - if (isMac()) { - return callMethod("isAboutMenuItemPresent").equals(Boolean.TRUE); - } else { - return aboutMenuItemPresent; - } - } - - public boolean isPreferencesMenuItemPresent() { - if (isMac()) { - return callMethod("isPreferencesMenuItemPresent").equals(Boolean.TRUE); - } else { - return this.preferencesMenuItemPresent; - } - } - - public void removeAboutMenuItem() { - if (isMac()) { - callMethod("removeAboutMenuItem"); - } else { - this.aboutMenuItemPresent = false; - } - } - - public synchronized void removeApplicationListener(ApplicationListener applicationListener) { - if (isMac()) { - Object listener = listenerMap.get(applicationListener); - callMethod(application, "removeApplicationListener", new Class[]{applicationListenerClass}, new Object[]{listener}); - - } - listenerMap.remove(applicationListener); - } - - public void removePreferencesMenuItem() { - if (isMac()) { - callMethod("removeAboutMenuItem"); - } else { - this.preferencesMenuItemPresent = false; - } - } - - public void setEnabledAboutMenu(boolean enabled) { - if (isMac()) { - callMethod(application, "setEnabledAboutMenu", new Class[]{Boolean.TYPE}, new Object[]{Boolean.valueOf(enabled)}); - } else { - this.enabledAboutMenu = enabled; - } - } - - public void setEnabledPreferencesMenu(boolean enabled) { - if (isMac()) { - callMethod(application, "setEnabledPreferencesMenu", new Class[]{Boolean.TYPE}, new Object[]{Boolean.valueOf(enabled)}); - } else { - this.enabledPreferencesMenu = enabled; - } - - } - - public int requestUserAttention(int type) { - if (type != REQUEST_USER_ATTENTION_TYPE_CRITICAL && type != REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL) { - throw new IllegalArgumentException("Requested user attention type is not allowed: " + type); - } - try { - Object application = getNSApplication(); - Field critical = application.getClass().getField("UserAttentionRequestCritical"); - Field informational = application.getClass().getField("UserAttentionRequestInformational"); - Field actual = type == REQUEST_USER_ATTENTION_TYPE_CRITICAL ? critical : informational; - - return ((Integer) application.getClass().getMethod("requestUserAttention", new Class[]{Integer.TYPE}).invoke(application, new Object[]{actual.get(null)})).intValue(); - - } catch (ClassNotFoundException e) { - return -1; - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } - } - - public void cancelUserAttentionRequest(int request) { - try { - Object application = getNSApplication(); - application.getClass().getMethod("cancelUserAttentionRequest", new Class[]{Integer.TYPE}).invoke(application, new Object[]{new Integer(request)}); - } catch (ClassNotFoundException e) { - // Nada - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } - - private Object getNSApplication() throws ClassNotFoundException { - try { - Class applicationClass = Class.forName("com.apple.cocoa.application.NSApplication"); - return applicationClass.getMethod("sharedApplication", new Class[0]).invoke(null, new Object[0]); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - public void setApplicationIconImage(BufferedImage image) { - if (isMac()) { - try { - Method setDockIconImage = application.getClass().getMethod("setDockIconImage", Image.class); - - try { - setDockIconImage.invoke(application, image); - } catch (IllegalAccessException e) { - - } catch (InvocationTargetException e) { - - } - } catch (NoSuchMethodException mnfe) { - - - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - try { - ImageIO.write(image, "png", stream); - } catch (IOException e) { - throw new RuntimeException(e); - } - - try { - Class nsDataClass = Class.forName("com.apple.cocoa.foundation.NSData"); - Constructor constructor = nsDataClass.getConstructor(new Class[]{new byte[0].getClass()}); - - Object nsData = constructor.newInstance(new Object[]{stream.toByteArray()}); - - Class nsImageClass = Class.forName("com.apple.cocoa.application.NSImage"); - Object nsImage = nsImageClass.getConstructor(new Class[]{nsDataClass}).newInstance(new Object[]{nsData}); - - Object application = getNSApplication(); - - application.getClass().getMethod("setApplicationIconImage", new Class[]{nsImageClass}).invoke(application, new Object[]{nsImage}); - - } catch (ClassNotFoundException e) { - - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } - - } - - } - } - - public BufferedImage getApplicationIconImage() { - if (isMac()) { - - try { - Method getDockIconImage = application.getClass().getMethod("getDockIconImage"); - try { - return (BufferedImage) getDockIconImage.invoke(application); - } catch (IllegalAccessException e) { - - } catch (InvocationTargetException e) { - - } - } catch (NoSuchMethodException nsme) { - - try { - Class nsDataClass = Class.forName("com.apple.cocoa.foundation.NSData"); - Class nsImageClass = Class.forName("com.apple.cocoa.application.NSImage"); - Object application = getNSApplication(); - Object nsImage = application.getClass().getMethod("applicationIconImage", new Class[0]).invoke(application, new Object[0]); - - Object nsData = nsImageClass.getMethod("TIFFRepresentation", new Class[0]).invoke(nsImage, new Object[0]); - - Integer length = (Integer) nsDataClass.getMethod("length", new Class[0]).invoke(nsData, new Object[0]); - byte[] bytes = (byte[]) nsDataClass.getMethod("bytes", new Class[]{Integer.TYPE, Integer.TYPE}).invoke(nsData, new Object[]{Integer.valueOf(0), length}); - - BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); - return image; - - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - } - - return null; - } - - private Object callMethod(String methodname) { - return callMethod(application, methodname, new Class[0], new Object[0]); - } - - private Object callMethod(Object object, String methodname) { - return callMethod(object, methodname, new Class[0], new Object[0]); - } - - private Object callMethod(Object object, String methodname, Class[] classes, Object[] arguments) { - try { - if (classes == null) { - classes = new Class[arguments.length]; - for (int i = 0; i < classes.length; i++) { - classes[i] = arguments[i].getClass(); - - } - } - Method addListnerMethod = object.getClass().getMethod(methodname, classes); - return addListnerMethod.invoke(object, arguments); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } - - class ApplicationListenerInvocationHandler implements InvocationHandler { - private ApplicationListener applicationListener; - - ApplicationListenerInvocationHandler(ApplicationListener applicationListener) { - this.applicationListener = applicationListener; - } - - public Object invoke(Object object, Method appleMethod, Object[] objects) throws Throwable { - - ApplicationEvent event = createApplicationEvent(objects[0]); - try { - Method method = applicationListener.getClass().getMethod(appleMethod.getName(), new Class[]{ApplicationEvent.class}); - return method.invoke(applicationListener, new Object[]{event}); - } catch (NoSuchMethodException e) { - if (appleMethod.getName().equals("equals") && objects.length == 1) { - return Boolean.valueOf(object == objects[0]); - } - return null; - } - } - } - - private ApplicationEvent createApplicationEvent(final Object appleApplicationEvent) { - return (ApplicationEvent) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ApplicationEvent.class}, new InvocationHandler() { - public Object invoke(Object o, Method method, Object[] objects) throws Throwable { - return appleApplicationEvent.getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(appleApplicationEvent, objects); - } - }); - } -} diff --git a/libgroupview/CMakeLists.txt b/libgroupview/CMakeLists.txt deleted file mode 100644 index d60d914a..00000000 --- a/libgroupview/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -project(libGroupView) - -set(CMAKE_AUTOMOC ON) - -# Find Qt -find_package(Qt5Core REQUIRED) -find_package(Qt5Widgets REQUIRED) - -# Include Qt headers. -include_directories(${Qt5Base_INCLUDE_DIRS}) - -SET(LIBGROUPVIEW_HEADERS -include/libgroupview_config.h - -# Public headers -include/categorizedsortfilterproxymodel.h -include/categorizedview.h -include/categorydrawer.h - -# Private headers -src/categorizedsortfilterproxymodel_p.h -src/categorizedview_p.h -) - -SET(LIBGROUPVIEW_SOURCES -src/categorizedsortfilterproxymodel.cpp -src/categorizedview.cpp -src/categorydrawer.cpp -) - -# Set the include dir path. -SET(LIBGROUPVIEW_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE) - -# Include self. -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) -include_directories(${CMAKE_BINARY_DIR}/include) - -add_definitions(-DLIBGROUPVIEW_LIBRARY) - -add_library(libGroupView SHARED ${LIBGROUPVIEW_SOURCES} ${LIBGROUPVIEW_HEADERS}) -qt5_use_modules(libGroupView Core Widgets) diff --git a/libgroupview/include/categorizedsortfilterproxymodel.h b/libgroupview/include/categorizedsortfilterproxymodel.h deleted file mode 100644 index 1ef39fc2..00000000 --- a/libgroupview/include/categorizedsortfilterproxymodel.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * This file is part of the KDE project - * Copyright (C) 2007 Rafael Fernández López - * Copyright (C) 2007 John Tapsell - * - * This library 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 library 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 library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef KCATEGORIZEDSORTFILTERPROXYMODEL_H -#define KCATEGORIZEDSORTFILTERPROXYMODEL_H - -#include - -#include - -class QItemSelection; - - -/** - * This class lets you categorize a view. It is meant to be used along with - * KCategorizedView class. - * - * In general terms all you need to do is to reimplement subSortLessThan() and - * compareCategories() methods. In order to make categorization work, you need - * to also call setCategorizedModel() class to enable it, since the categorization - * is disabled by default. - * - * @see KCategorizedView - * - * @author Rafael Fernández López - */ -class LIBGROUPVIEW_EXPORT KCategorizedSortFilterProxyModel - : public QSortFilterProxyModel -{ -public: - enum AdditionalRoles - { - // Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM)) - // to define additional roles. - CategoryDisplayRole = 0x17CE990A, ///< This role is used for asking the category to a given index - - CategorySortRole = 0x27857E60 ///< This role is used for sorting categories. You can return a - ///< string or a long long value. Strings will be sorted alphabetically - ///< while long long will be sorted by their value. Please note that this - ///< value won't be shown on the view, is only for sorting purposes. What will - ///< be shown as "Category" on the view will be asked with the role - ///< CategoryDisplayRole. - }; - - KCategorizedSortFilterProxyModel ( QObject *parent = 0 ); - virtual ~KCategorizedSortFilterProxyModel(); - - /** - * Overridden from QSortFilterProxyModel. Sorts the source model using - * @p column for the given @p order. - */ - virtual void sort ( int column, Qt::SortOrder order = Qt::AscendingOrder ); - - /** - * @return whether the model is categorized or not. Disabled by default. - */ - bool isCategorizedModel() const; - - /** - * Enables or disables the categorization feature. - * - * @param categorizedModel whether to enable or disable the categorization feature. - */ - void setCategorizedModel ( bool categorizedModel ); - - /** - * @return the column being used for sorting. - */ - int sortColumn() const; - - /** - * @return the sort order being used for sorting. - */ - Qt::SortOrder sortOrder() const; - - /** - * Set if the sorting using CategorySortRole will use a natural comparison - * in the case that strings were returned. If enabled, QString::localeAwareCompare - * will be used for sorting. - * - * @param sortCategoriesByNaturalComparison whether to sort using a natural comparison or not. - */ - void setSortCategoriesByNaturalComparison ( bool sortCategoriesByNaturalComparison ); - - /** - * @return whether it is being used a natural comparison for sorting. Enabled by default. - */ - bool sortCategoriesByNaturalComparison() const; - -protected: - /** - * Overridden from QSortFilterProxyModel. If you are subclassing - * KCategorizedSortFilterProxyModel, you will probably not need to reimplement this - * method. - * - * It calls compareCategories() to sort by category. If the both items are in the - * same category (i.e. compareCategories returns 0), then subSortLessThan is called. - * - * @return Returns true if the item @p left is less than the item @p right when sorting. - * - * @warning You usually won't need to reimplement this method when subclassing - * from KCategorizedSortFilterProxyModel. - */ - virtual bool lessThan ( const QModelIndex &left, const QModelIndex &right ) const; - - /** - * This method has a similar purpose as lessThan() has on QSortFilterProxyModel. - * It is used for sorting items that are in the same category. - * - * @return Returns true if the item @p left is less than the item @p right when sorting. - */ - virtual bool subSortLessThan ( const QModelIndex &left, const QModelIndex &right ) const; - - /** - * This method compares the category of the @p left index with the category - * of the @p right index. - * - * Internally and if not reimplemented, this method will ask for @p left and - * @p right models for role CategorySortRole. In order to correctly sort - * categories, the data() metod of the model should return a qlonglong (or numeric) value, or - * a QString object. QString objects will be sorted with QString::localeAwareCompare if - * sortCategoriesByNaturalComparison() is true. - * - * @note Please have present that: - * QString(QChar(QChar::ObjectReplacementCharacter)) > - * QString(QChar(QChar::ReplacementCharacter)) > - * [ all possible strings ] > - * QString(); - * - * This means that QString() will be sorted the first one, while - * QString(QChar(QChar::ObjectReplacementCharacter)) and - * QString(QChar(QChar::ReplacementCharacter)) will be sorted in last - * position. - * - * @warning Please note that data() method of the model should return always - * information of the same type. If you return a QString for an index, - * you should return always QStrings for all indexes for role CategorySortRole - * in order to correctly sort categories. You can't mix by returning - * a QString for one index, and a qlonglong for other. - * - * @note If you need a more complex layout, you will have to reimplement this - * method. - * - * @return A negative value if the category of @p left should be placed before the - * category of @p right. 0 if @p left and @p right are on the same category, and - * a positive value if the category of @p left should be placed after the - * category of @p right. - */ - virtual int compareCategories ( const QModelIndex &left, const QModelIndex &right ) const; - -private: - class Private; - Private *const d; -}; - - -#endif // KCATEGORIZEDSORTFILTERPROXYMODEL_H diff --git a/libgroupview/include/categorizedview.h b/libgroupview/include/categorizedview.h deleted file mode 100644 index 243ccf15..00000000 --- a/libgroupview/include/categorizedview.h +++ /dev/null @@ -1,332 +0,0 @@ -/** - * This file is part of the KDE project - * Copyright (C) 2007, 2009 Rafael Fernández López - * - * This library 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 library 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 library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef KCATEGORIZEDVIEW_H -#define KCATEGORIZEDVIEW_H - -#include - -#include - -class KCategoryDrawer; - -/** - * @short Item view for listing items in a categorized fashion optionally - * - * KCategorizedView basically has the same functionality as QListView, only that it also lets you - * layout items in a way that they are categorized visually. - * - * For it to work you will need to set a KCategorizedSortFilterProxyModel and a KCategoryDrawer - * with methods setModel() and setCategoryDrawer() respectively. Also, the model will need to be - * flagged as categorized with KCategorizedSortFilterProxyModel::setCategorizedModel(true). - * - * The way it works (if categorization enabled): - * - * - When sorting, it does more things than QListView does. It will ask the model for the - * special role CategorySortRole (@see KCategorizedSortFilterProxyModel). This can return - * a QString or an int in order to tell the view the order of categories. In this sense, for - * instance, if we are sorting by name ascending, "A" would be before than "B". If we are - * sorting by size ascending, 512 bytes would be before 1024 bytes. This way categories are - * also sorted. - * - * - When the view has to paint, it will ask the model with the role CategoryDisplayRole - * (@see KCategorizedSortFilterProxyModel). It will for instance return "F" for "foo.pdf" if - * we are sorting by name ascending, or "Small" if a certain item has 100 bytes, for example. - * - * For drawing categories, KCategoryDrawer will be used. You can inherit this class to do your own - * drawing. - * - * @note All examples cited before talk about filesystems and such, but have present that this - * is a completely generic class, and it can be used for whatever your purpose is. For - * instance when talking about animals, you can separate them by "Mammal" and "Oviparous". In - * this very case, for example, the CategorySortRole and the CategoryDisplayRole could be the - * same ("Mammal" and "Oviparous"). - * - * @note There is a really performance boost if CategorySortRole returns an int instead of a QString. - * Have present that this role is asked (n * log n) times when sorting and compared. Comparing - * ints is always faster than comparing strings, whithout mattering how fast the string - * comparison is. Consider thinking of a way of returning ints instead of QStrings if your - * model can contain a high number of items. - * - * @warning Note that for really drawing items in blocks you will need some things to be done: - * - The model set to this view has to be (or inherit if you want to do special stuff - * in it) KCategorizedSortFilterProxyModel. - * - This model needs to be set setCategorizedModel to true. - * - Set a category drawer by calling setCategoryDrawer. - * - * @see KCategorizedSortFilterProxyModel, KCategoryDrawer - * - * @author Rafael Fernández López - */ -class LIBGROUPVIEW_EXPORT KCategorizedView - : public QListView -{ - Q_OBJECT - Q_PROPERTY ( int categorySpacing READ categorySpacing WRITE setCategorySpacing ) - Q_PROPERTY ( bool alternatingBlockColors READ alternatingBlockColors WRITE setAlternatingBlockColors ) - Q_PROPERTY ( bool collapsibleBlocks READ collapsibleBlocks WRITE setCollapsibleBlocks ) - -public: - KCategorizedView ( QWidget *parent = 0 ); - - ~KCategorizedView(); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void setModel ( QAbstractItemModel *model ); - - /** - * Calls to setGridSizeOwn(). - */ - void setGridSize ( const QSize &size ); - - /** - * @warning note that setGridSize is not virtual in the base class (QListView), so if you are - * calling to this method, make sure you have a KCategorizedView pointer around. This - * means that something like: - * @code - * QListView *lv = new KCategorizedView(); - * lv->setGridSize(mySize); - * @endcode - * - * will not call to the expected setGridSize method. Instead do something like this: - * - * @code - * QListView *lv; - * ... - * KCategorizedView *cv = qobject_cast(lv); - * if (cv) { - * cv->setGridSizeOwn(mySize); - * } else { - * lv->setGridSize(mySize); - * } - * @endcode - * - * @note this method will call to QListView::setGridSize among other operations. - * - * @since 4.4 - */ - void setGridSizeOwn ( const QSize &size ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual QRect visualRect ( const QModelIndex &index ) const; - - /** - * Returns the current category drawer. - */ - KCategoryDrawer *categoryDrawer() const; - - /** - * The category drawer that will be used for drawing categories. - */ - void setCategoryDrawer ( KCategoryDrawer *categoryDrawer ); - - /** - * @return Category spacing. The spacing between categories. - * - * @since 4.4 - */ - int categorySpacing() const; - - /** - * Stablishes the category spacing. This is the spacing between categories. - * - * @since 4.4 - */ - void setCategorySpacing ( int categorySpacing ); - - /** - * @return Whether blocks should be drawn with alternating colors. - * - * @since 4.4 - */ - bool alternatingBlockColors() const; - - /** - * Sets whether blocks should be drawn with alternating colors. - * - * @since 4.4 - */ - void setAlternatingBlockColors ( bool enable ); - - /** - * @return Whether blocks can be collapsed or not. - * - * @since 4.4 - */ - bool collapsibleBlocks() const; - - /** - * Sets whether blocks can be collapsed or not. - * - * @since 4.4 - */ - void setCollapsibleBlocks ( bool enable ); - - /** - * @return Block of indexes that are into @p category. - * - * @since 4.5 - */ - QModelIndexList block ( const QString &category ); - - /** - * @return Block of indexes that are represented by @p representative. - * - * @since 4.5 - */ - QModelIndexList block ( const QModelIndex &representative ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual QModelIndex indexAt ( const QPoint &point ) const; - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void reset(); - - /** - * Signify that all item delegates size hints return the same fixed size - */ - void setUniformItemWidths(bool enable); - - /** - * Do all item delegate size hints return the same fixed size? - */ - bool uniformItemWidths() const; - -protected: - /** - * Reimplemented from QWidget. - */ - virtual void paintEvent ( QPaintEvent *event ); - - /** - * Reimplemented from QWidget. - */ - virtual void resizeEvent ( QResizeEvent *event ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void setSelection ( const QRect &rect, - QItemSelectionModel::SelectionFlags flags ); - - /** - * Reimplemented from QWidget. - */ - virtual void mouseMoveEvent ( QMouseEvent *event ); - - /** - * Reimplemented from QWidget. - */ - virtual void mousePressEvent ( QMouseEvent *event ); - - /** - * Reimplemented from QWidget. - */ - virtual void mouseReleaseEvent ( QMouseEvent *event ); - - /** - * Reimplemented from QWidget. - */ - virtual void leaveEvent ( QEvent *event ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void startDrag ( Qt::DropActions supportedActions ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void dragMoveEvent ( QDragMoveEvent *event ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void dragEnterEvent ( QDragEnterEvent *event ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void dragLeaveEvent ( QDragLeaveEvent *event ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void dropEvent ( QDropEvent *event ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual QModelIndex moveCursor ( CursorAction cursorAction, - Qt::KeyboardModifiers modifiers ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void rowsAboutToBeRemoved ( const QModelIndex &parent, - int start, - int end ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void updateGeometries(); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void currentChanged ( const QModelIndex ¤t, - const QModelIndex &previous ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void dataChanged ( const QModelIndex &topLeft, - const QModelIndex &bottomRight ); - - /** - * Reimplemented from QAbstractItemView. - */ - virtual void rowsInserted ( const QModelIndex &parent, - int start, - int end ); - -protected Q_SLOTS: - /** - * @internal - * Reposition items as needed. - */ - virtual void slotLayoutChanged(); - virtual void slotCollapseOrExpandClicked ( QModelIndex ); - -private: - class Private; - Private *const d; -}; - -#endif // KCATEGORIZEDVIEW_H diff --git a/libgroupview/include/categorydrawer.h b/libgroupview/include/categorydrawer.h deleted file mode 100644 index aa561f0d..00000000 --- a/libgroupview/include/categorydrawer.h +++ /dev/null @@ -1,179 +0,0 @@ -/** - * This file is part of the KDE project - * Copyright (C) 2007, 2009 Rafael Fernández López - * - * This library 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 library 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 library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef KCATEGORYDRAWER_H -#define KCATEGORYDRAWER_H - -#include - -#include -#include - -class QPainter; -class QModelIndex; -class QStyleOption; -class KCategorizedView; - - -/** - * @since 4.5 - */ -class LIBGROUPVIEW_EXPORT KCategoryDrawer - : public QObject -{ - friend class KCategorizedView; - Q_OBJECT - - -public: - KCategoryDrawer ( KCategorizedView *view ); - virtual ~KCategoryDrawer(); - - /** - * @return The view this category drawer is associated with. - */ - KCategorizedView *view() const; - - /** - * This method purpose is to draw a category represented by the given - * @param index with the given @param sortRole sorting role - * - * @note This method will be called one time per category, always with the - * first element in that category - */ - virtual void drawCategory ( const QModelIndex &index, - int sortRole, - const QStyleOption &option, - QPainter *painter ) const; - - /** - * @return The category height for the category representated by index @p index with - * style options @p option. - */ - virtual int categoryHeight ( const QModelIndex &index, const QStyleOption &option ) const; - - //TODO KDE5: make virtual as leftMargin - /** - * @note 0 by default - * - * @since 4.4 - */ - int leftMargin() const; - - /** - * @note call to this method on the KCategoryDrawer constructor to set the left margin - * - * @since 4.4 - */ - void setLeftMargin ( int leftMargin ); - - //TODO KDE5: make virtual as rightMargin - /** - * @note 0 by default - * - * @since 4.4 - */ - int rightMargin() const; - - /** - * @note call to this method on the KCategoryDrawer constructor to set the right margin - * - * @since 4.4 - */ - void setRightMargin ( int rightMargin ); - - KCategoryDrawer &operator= ( const KCategoryDrawer &cd ); -protected: - /** - * Method called when the mouse button has been pressed. - * - * @param index The representative index of the block of items. - * @param blockRect The rect occupied by the block of items. - * @param event The mouse event. - * - * @warning You explicitly have to determine whether the event has been accepted or not. You - * have to call event->accept() or event->ignore() at all possible case branches in - * your code. - */ - virtual void mouseButtonPressed ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); - - /** - * Method called when the mouse button has been released. - * - * @param index The representative index of the block of items. - * @param blockRect The rect occupied by the block of items. - * @param event The mouse event. - * - * @warning You explicitly have to determine whether the event has been accepted or not. You - * have to call event->accept() or event->ignore() at all possible case branches in - * your code. - */ - virtual void mouseButtonReleased ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); - - /** - * Method called when the mouse has been moved. - * - * @param index The representative index of the block of items. - * @param blockRect The rect occupied by the block of items. - * @param event The mouse event. - */ - virtual void mouseMoved ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); - - /** - * Method called when the mouse button has been double clicked. - * - * @param index The representative index of the block of items. - * @param blockRect The rect occupied by the block of items. - * @param event The mouse event. - * - * @warning You explicitly have to determine whether the event has been accepted or not. You - * have to call event->accept() or event->ignore() at all possible case branches in - * your code. - */ - virtual void mouseButtonDoubleClicked ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); - - /** - * Method called when the mouse button has left this block. - * - * @param index The representative index of the block of items. - * @param blockRect The rect occupied by the block of items. - */ - virtual void mouseLeft ( const QModelIndex &index, const QRect &blockRect ); - -private: - class Private; - Private *const d; -Q_SIGNALS: - /** - * This signal becomes emitted when collapse or expand has been clicked. - */ - void collapseOrExpandClicked ( const QModelIndex &index ); - - /** - * Emit this signal on your subclass implementation to notify that something happened. Usually - * this will be triggered when you have received an event, and its position matched some "hot spot". - * - * You give this action the integer you want, and having connected this signal to your code, - * the connected slot can perform the needed changes (view, model, selection model, delegate...) - */ - void actionRequested ( int action, const QModelIndex &index ); -}; - -#endif // KCATEGORYDRAWER_H diff --git a/libgroupview/include/libgroupview_config.h b/libgroupview/include/libgroupview_config.h deleted file mode 100644 index 86bed139..00000000 --- a/libgroupview/include/libgroupview_config.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#ifndef LIBINSTANCE_CONFIG_H -//#define LIBINSTANCE_CONFIG_H - -#include - -#ifdef LIBGROUPVIEW_LIBRARY -# define LIBGROUPVIEW_EXPORT Q_DECL_EXPORT -#else -# define LIBGROUPVIEW_EXPORT Q_DECL_IMPORT -#endif - -//#endif // LIBINSTANCE_CONFIG_H diff --git a/libgroupview/src/categorizedsortfilterproxymodel.cpp b/libgroupview/src/categorizedsortfilterproxymodel.cpp deleted file mode 100644 index 09da9dd3..00000000 --- a/libgroupview/src/categorizedsortfilterproxymodel.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/** - * This file is part of the KDE project - * Copyright (C) 2007 Rafael Fernández López - * Copyright (C) 2007 John Tapsell - * - * This library 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 library 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 library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "categorizedsortfilterproxymodel.h" -#include "categorizedsortfilterproxymodel_p.h" - -#include - -#include -#include -#include - -KCategorizedSortFilterProxyModel::KCategorizedSortFilterProxyModel ( QObject *parent ) - : QSortFilterProxyModel ( parent ) - , d ( new Private() ) -{ -} - -KCategorizedSortFilterProxyModel::~KCategorizedSortFilterProxyModel() -{ - delete d; -} - -void KCategorizedSortFilterProxyModel::sort ( int column, Qt::SortOrder order ) -{ - d->sortColumn = column; - d->sortOrder = order; - - QSortFilterProxyModel::sort ( column, order ); -} - -bool KCategorizedSortFilterProxyModel::isCategorizedModel() const -{ - return d->categorizedModel; -} - -void KCategorizedSortFilterProxyModel::setCategorizedModel ( bool categorizedModel ) -{ - if ( categorizedModel == d->categorizedModel ) - { - return; - } - - d->categorizedModel = categorizedModel; - - invalidate(); -} - -int KCategorizedSortFilterProxyModel::sortColumn() const -{ - return d->sortColumn; -} - -Qt::SortOrder KCategorizedSortFilterProxyModel::sortOrder() const -{ - return d->sortOrder; -} - -void KCategorizedSortFilterProxyModel::setSortCategoriesByNaturalComparison ( bool sortCategoriesByNaturalComparison ) -{ - if ( sortCategoriesByNaturalComparison == d->sortCategoriesByNaturalComparison ) - { - return; - } - - d->sortCategoriesByNaturalComparison = sortCategoriesByNaturalComparison; - - invalidate(); -} - -bool KCategorizedSortFilterProxyModel::sortCategoriesByNaturalComparison() const -{ - return d->sortCategoriesByNaturalComparison; -} - -bool KCategorizedSortFilterProxyModel::lessThan ( const QModelIndex &left, const QModelIndex &right ) const -{ - if ( d->categorizedModel ) - { - int compare = compareCategories ( left, right ); - - if ( compare > 0 ) // left is greater than right - { - return false; - } - else if ( compare < 0 ) // left is less than right - { - return true; - } - } - - return subSortLessThan ( left, right ); -} - -bool KCategorizedSortFilterProxyModel::subSortLessThan ( const QModelIndex &left, const QModelIndex &right ) const -{ - return QSortFilterProxyModel::lessThan ( left, right ); -} - -int KCategorizedSortFilterProxyModel::compareCategories ( const QModelIndex &left, const QModelIndex &right ) const -{ - QVariant l = ( left.model() ? left.model()->data ( left, CategorySortRole ) : QVariant() ); - QVariant r = ( right.model() ? right.model()->data ( right, CategorySortRole ) : QVariant() ); - - Q_ASSERT ( l.isValid() ); - Q_ASSERT ( r.isValid() ); - Q_ASSERT ( l.type() == r.type() ); - - if ( l.type() == QVariant::String ) - { - QString lstr = l.toString(); - QString rstr = r.toString(); - - /* - if ( d->sortCategoriesByNaturalComparison ) - { - return KStringHandler::naturalCompare ( lstr, rstr ); - } - else - { - */ - if ( lstr < rstr ) - { - return -1; - } - - if ( lstr > rstr ) - { - return 1; - } - - return 0; - //} - } - - qlonglong lint = l.toLongLong(); - qlonglong rint = r.toLongLong(); - - if ( lint < rint ) - { - return -1; - } - - if ( lint > rint ) - { - return 1; - } - - return 0; -} diff --git a/libgroupview/src/categorizedsortfilterproxymodel_p.h b/libgroupview/src/categorizedsortfilterproxymodel_p.h deleted file mode 100644 index d7e7c9a0..00000000 --- a/libgroupview/src/categorizedsortfilterproxymodel_p.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * This file is part of the KDE project - * Copyright (C) 2007 Rafael Fernández López - * Copyright (C) 2007 John Tapsell - * - * This library 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 library 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 library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef KCATEGORIZEDSORTFILTERPROXYMODEL_P_H -#define KCATEGORIZEDSORTFILTERPROXYMODEL_P_H - -class KCategorizedSortFilterProxyModel; - -class KCategorizedSortFilterProxyModel::Private -{ -public: - Private() - : sortColumn ( 0 ) - , sortOrder ( Qt::AscendingOrder ) - , categorizedModel ( false ) - , sortCategoriesByNaturalComparison ( true ) - { - } - - ~Private() - { - } - - int sortColumn; - Qt::SortOrder sortOrder; - bool categorizedModel; - bool sortCategoriesByNaturalComparison; -}; - -#endif diff --git a/libgroupview/src/categorizedview.cpp b/libgroupview/src/categorizedview.cpp deleted file mode 100644 index f4449949..00000000 --- a/libgroupview/src/categorizedview.cpp +++ /dev/null @@ -1,1713 +0,0 @@ -/** - * This file is part of the KDE project - * Copyright (C) 2007, 2009 Rafael Fernández López - * - * This library 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 library 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 library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -/** - * IMPLEMENTATION NOTES: - * - * QListView::setRowHidden() and QListView::isRowHidden() are not taken into - * account. This methods should actually not exist. This effect should be handled - * by an hypothetical QSortFilterProxyModel which filters out the desired rows. - * - * In case this needs to be implemented, contact me, but I consider this a faulty - * design. - */ - -#include "categorizedview.h" -#include "categorizedview_p.h" - -#include // trunc on C99 compliant systems -//#include // trunc for not C99 compliant systems - -#include -#include -#include - -#include "categorydrawer.h" -#include "categorizedsortfilterproxymodel.h" - -//BEGIN: Private part - -struct KCategorizedView::Private::Item -{ - Item() - : topLeft ( QPoint() ) - , size ( QSize() ) - { - } - - QPoint topLeft; - QSize size; -}; - -struct KCategorizedView::Private::Block -{ - Block() - : topLeft ( QPoint() ) - , height ( -1 ) - , firstIndex ( QModelIndex() ) - , quarantineStart ( QModelIndex() ) - , items ( QList() ) - , outOfQuarantine ( false ) - , alternate ( false ) - , collapsed ( false ) - { - } - - bool operator!= ( const Block &rhs ) const - { - return firstIndex != rhs.firstIndex; - } - - static bool lessThan ( const Block &left, const Block &right ) - { - Q_ASSERT ( left.firstIndex.isValid() ); - Q_ASSERT ( right.firstIndex.isValid() ); - return left.firstIndex.row() < right.firstIndex.row(); - } - - QPoint topLeft; - int height; - QPersistentModelIndex firstIndex; - // if we have n elements on this block, and we inserted an element at position i. The quarantine - // will start at index (i, column, parent). This means that for all elements j where i <= j <= n, the - // visual rect position of item j will have to be recomputed (cannot use the cached point). The quarantine - // will only affect the current block, since the rest of blocks can be affected only in the way - // that the whole block will have different offset, but items will keep the same relative position - // in terms of their parent blocks. - QPersistentModelIndex quarantineStart; - QList items; - - // this affects the whole block, not items separately. items contain the topLeft point relative - // to the block. Because of insertions or removals a whole block can be moved, so the whole block - // will enter in quarantine, what is faster than moving all items in absolute terms. - bool outOfQuarantine; - - // should we alternate its color ? is just a hint, could not be used - bool alternate; - bool collapsed; -}; - -KCategorizedView::Private::Private ( KCategorizedView *q ) - : q ( q ) - , proxyModel ( 0 ) - , categoryDrawer ( 0 ) - , categorySpacing ( 5 ) - , alternatingBlockColors ( false ) - , collapsibleBlocks ( false ) - , hoveredBlock ( new Block() ) - , hoveredIndex ( QModelIndex() ) - , pressedPosition ( QPoint() ) - , rubberBandRect ( QRect() ) - , constantItemWidth( 0 ) -{ -} - -KCategorizedView::Private::~Private() -{ - delete hoveredBlock; -} - -bool KCategorizedView::Private::isCategorized() const -{ - return proxyModel && categoryDrawer && proxyModel->isCategorizedModel(); -} - -QStyleOptionViewItemV4 KCategorizedView::Private::blockRect ( const QModelIndex &representative ) -{ - QStyleOptionViewItemV4 option ( q->viewOptions() ); - const int height = categoryDrawer->categoryHeight ( representative, option ); - const QString categoryDisplay = representative.data ( KCategorizedSortFilterProxyModel::CategoryDisplayRole ).toString(); - QPoint pos = blockPosition ( categoryDisplay ); - pos.ry() -= height; - option.rect.setTopLeft ( pos ); - option.rect.setWidth ( viewportWidth() + categoryDrawer->leftMargin() + categoryDrawer->rightMargin() ); - option.rect.setHeight ( height + blockHeight ( categoryDisplay ) ); - option.rect = mapToViewport ( option.rect ); - - return option; -} - -QPair KCategorizedView::Private::intersectingIndexesWithRect ( const QRect &_rect ) const -{ - const int rowCount = proxyModel->rowCount(); - - const QRect rect = _rect.normalized(); - - // binary search to find out the top border - int bottom = 0; - int top = rowCount - 1; - while ( bottom <= top ) - { - const int middle = ( bottom + top ) / 2; - const QModelIndex index = proxyModel->index ( middle, q->modelColumn(), q->rootIndex() ); - QRect itemRect = q->visualRect ( index ); - const int verticalOff = q->verticalOffset(); - const int horizontalOff = q->horizontalOffset(); - itemRect.topLeft().ry() += verticalOff; - itemRect.topLeft().rx() += horizontalOff; - itemRect.bottomRight().ry() += verticalOff; - itemRect.bottomRight().rx() += horizontalOff; - if ( itemRect.bottomRight().y() <= rect.topLeft().y() ) - { - bottom = middle + 1; - } - else - { - top = middle - 1; - } - } - - const QModelIndex bottomIndex = proxyModel->index ( bottom, q->modelColumn(), q->rootIndex() ); - - // binary search to find out the bottom border - bottom = 0; - top = rowCount - 1; - while ( bottom <= top ) - { - const int middle = ( bottom + top ) / 2; - const QModelIndex index = proxyModel->index ( middle, q->modelColumn(), q->rootIndex() ); - QRect itemRect = q->visualRect ( index ); - const int verticalOff = q->verticalOffset(); - const int horizontalOff = q->horizontalOffset(); - itemRect.topLeft().ry() += verticalOff; - itemRect.topLeft().rx() += horizontalOff; - itemRect.bottomRight().ry() += verticalOff; - itemRect.bottomRight().rx() += horizontalOff; - if ( itemRect.topLeft().y() <= rect.bottomRight().y() ) - { - bottom = middle + 1; - } - else - { - top = middle - 1; - } - } - - const QModelIndex topIndex = proxyModel->index ( top, q->modelColumn(), q->rootIndex() ); - - return qMakePair ( bottomIndex, topIndex ); -} - -QPoint KCategorizedView::Private::blockPosition ( const QString &category ) -{ - Block &block = blocks[category]; - - if ( block.outOfQuarantine && !block.topLeft.isNull() ) - { - return block.topLeft; - } - - QPoint res ( categorySpacing, 0 ); - - const QModelIndex index = block.firstIndex; - - for ( QHash::Iterator it = blocks.begin(); it != blocks.end(); ++it ) - { - Block &block = *it; - const QModelIndex categoryIndex = block.firstIndex; - if ( index.row() < categoryIndex.row() ) - { - continue; - } - res.ry() += categoryDrawer->categoryHeight ( categoryIndex, q->viewOptions() ) + categorySpacing; - if ( index.row() == categoryIndex.row() ) - { - continue; - } - res.ry() += blockHeight ( it.key() ); - } - - block.outOfQuarantine = true; - block.topLeft = res; - - return res; -} - -int KCategorizedView::Private::blockHeight ( const QString &category ) -{ - Block &block = blocks[category]; - - if ( block.collapsed ) - { - return 0; - } - - if ( block.height > -1 ) - { - return block.height; - } - - const QModelIndex firstIndex = block.firstIndex; - const QModelIndex lastIndex = proxyModel->index ( firstIndex.row() + block.items.count() - 1, q->modelColumn(), q->rootIndex() ); - const QRect topLeft = q->visualRect ( firstIndex ); - QRect bottomRight = q->visualRect ( lastIndex ); - - if ( hasGrid() ) - { - bottomRight.setHeight ( qMax ( bottomRight.height(), q->gridSize().height() ) ); - } - else - { - if ( !q->uniformItemSizes() ) - { - bottomRight.setHeight ( highestElementInLastRow ( block ) + q->spacing() * 2 ); - } - } - - const int height = bottomRight.bottomRight().y() - topLeft.topLeft().y() + 1; - block.height = height; - - return height; -} - -int KCategorizedView::Private::viewportWidth() const -{ - return q->viewport()->width() - categorySpacing * 2 - categoryDrawer->leftMargin() - categoryDrawer->rightMargin(); -} - -void KCategorizedView::Private::regenerateAllElements() -{ - for ( QHash::Iterator it = blocks.begin(); it != blocks.end(); ++it ) - { - Block &block = *it; - block.outOfQuarantine = false; - block.quarantineStart = block.firstIndex; - block.height = -1; - } -} - -void KCategorizedView::Private::rowsInserted ( const QModelIndex &parent, int start, int end ) -{ - if ( !isCategorized() ) - { - return; - } - - for ( int i = start; i <= end; ++i ) - { - const QModelIndex index = proxyModel->index ( i, q->modelColumn(), parent ); - - Q_ASSERT ( index.isValid() ); - - const QString category = categoryForIndex ( index ); - - Block &block = blocks[category]; - - //BEGIN: update firstIndex - // save as firstIndex in block if - // - it forced the category creation (first element on this category) - // - it is before the first row on that category - const QModelIndex firstIndex = block.firstIndex; - if ( !firstIndex.isValid() || index.row() < firstIndex.row() ) - { - block.firstIndex = index; - } - //END: update firstIndex - - Q_ASSERT ( block.firstIndex.isValid() ); - - const int firstIndexRow = block.firstIndex.row(); - - block.items.insert ( index.row() - firstIndexRow, Private::Item() ); - block.height = -1; - - q->visualRect ( index ); - q->viewport()->update(); - } - - //BEGIN: update the items that are in quarantine in affected categories - { - const QModelIndex lastIndex = proxyModel->index ( end, q->modelColumn(), parent ); - const QString category = categoryForIndex ( lastIndex ); - Private::Block &block = blocks[category]; - block.quarantineStart = block.firstIndex; - } - //END: update the items that are in quarantine in affected categories - - //BEGIN: mark as in quarantine those categories that are under the affected ones - { - const QModelIndex firstIndex = proxyModel->index ( start, q->modelColumn(), parent ); - const QString category = categoryForIndex ( firstIndex ); - const QModelIndex firstAffectedCategory = blocks[category].firstIndex; - //BEGIN: order for marking as alternate those blocks that are alternate - QList blockList = blocks.values(); - qSort ( blockList.begin(), blockList.end(), Block::lessThan ); - QList firstIndexesRows; - foreach ( const Block &block, blockList ) - { - firstIndexesRows << block.firstIndex.row(); - } - //END: order for marking as alternate those blocks that are alternate - for ( QHash::Iterator it = blocks.begin(); it != blocks.end(); ++it ) - { - Private::Block &block = *it; - if ( block.firstIndex.row() > firstAffectedCategory.row() ) - { - block.outOfQuarantine = false; - block.alternate = firstIndexesRows.indexOf ( block.firstIndex.row() ) % 2; - } - else if ( block.firstIndex.row() == firstAffectedCategory.row() ) - { - block.alternate = firstIndexesRows.indexOf ( block.firstIndex.row() ) % 2; - } - } - } - //END: mark as in quarantine those categories that are under the affected ones -} - -QRect KCategorizedView::Private::mapToViewport ( const QRect &rect ) const -{ - const int dx = -q->horizontalOffset(); - const int dy = -q->verticalOffset(); - return rect.adjusted ( dx, dy, dx, dy ); -} - -QRect KCategorizedView::Private::mapFromViewport ( const QRect &rect ) const -{ - const int dx = q->horizontalOffset(); - const int dy = q->verticalOffset(); - return rect.adjusted ( dx, dy, dx, dy ); -} - -int KCategorizedView::Private::highestElementInLastRow ( const Block &block ) const -{ - //Find the highest element in the last row - const QModelIndex lastIndex = proxyModel->index ( block.firstIndex.row() + block.items.count() - 1, q->modelColumn(), q->rootIndex() ); - const QRect prevRect = q->visualRect ( lastIndex ); - int res = prevRect.height(); - QModelIndex prevIndex = proxyModel->index ( lastIndex.row() - 1, q->modelColumn(), q->rootIndex() ); - if ( !prevIndex.isValid() ) - { - return res; - } - Q_FOREVER - { - const QRect tempRect = q->visualRect ( prevIndex ); - if ( tempRect.topLeft().y() < prevRect.topLeft().y() ) - { - break; - } - res = qMax ( res, tempRect.height() ); - if ( prevIndex == block.firstIndex ) - { - break; - } - prevIndex = proxyModel->index ( prevIndex.row() - 1, q->modelColumn(), q->rootIndex() ); - } - - return res; -} - -bool KCategorizedView::Private::hasGrid() const -{ - const QSize gridSize = q->gridSize(); - return gridSize.isValid() && !gridSize.isNull(); -} - -QString KCategorizedView::Private::categoryForIndex ( const QModelIndex &index ) const -{ - const QModelIndex categoryIndex = index.model()->index ( index.row(), proxyModel->sortColumn(), index.parent() ); - return categoryIndex.data ( KCategorizedSortFilterProxyModel::CategoryDisplayRole ).toString(); -} - -void KCategorizedView::Private::leftToRightVisualRect ( const QModelIndex &index, Item &item, - const Block &block, const QPoint &blockPos ) const -{ - const int firstIndexRow = block.firstIndex.row(); - - if ( hasGrid() ) - { - const int relativeRow = index.row() - firstIndexRow; - const int maxItemsPerRow = qMax ( viewportWidth() / q->gridSize().width(), 1 ); - if ( q->layoutDirection() == Qt::LeftToRight ) - { - item.topLeft.rx() = ( relativeRow % maxItemsPerRow ) * q->gridSize().width() + blockPos.x() + categoryDrawer->leftMargin(); - } - else - { - item.topLeft.rx() = viewportWidth() - ( ( relativeRow % maxItemsPerRow ) + 1 ) * q->gridSize().width() + categoryDrawer->leftMargin() + categorySpacing; - } - item.topLeft.ry() = ( relativeRow / maxItemsPerRow ) * q->gridSize().height(); - } - else - { - if ( q->uniformItemSizes() /*|| q->uniformItemWidths()*/ ) - { - const int relativeRow = index.row() - firstIndexRow; - const QSize itemSize = q->sizeHintForIndex ( index ); - //HACK: Why is the -2 needed? - const int maxItemsPerRow = qMax ( ( viewportWidth() - q->spacing() - 2 ) / ( itemSize.width() + q->spacing() ), 1 ); - if ( q->layoutDirection() == Qt::LeftToRight ) - { - item.topLeft.rx() = ( relativeRow % maxItemsPerRow ) * itemSize.width() + blockPos.x() + categoryDrawer->leftMargin(); - } - else - { - item.topLeft.rx() = viewportWidth() - ( relativeRow % maxItemsPerRow ) * itemSize.width() + categoryDrawer->leftMargin() + categorySpacing; - } - item.topLeft.ry() = ( relativeRow / maxItemsPerRow ) * itemSize.height(); - } - else - { - const QSize currSize = q->sizeHintForIndex ( index ); - if ( index != block.firstIndex ) - { - const int viewportW = viewportWidth() - q->spacing(); - QModelIndex prevIndex = proxyModel->index ( index.row() - 1, q->modelColumn(), q->rootIndex() ); - QRect prevRect = q->visualRect ( prevIndex ); - prevRect = mapFromViewport ( prevRect ); - if ( ( prevRect.bottomRight().x() + 1 ) + currSize.width() - blockPos.x() + q->spacing() > viewportW ) - { - // we have to check the whole previous row, and see which one was the - // highest. - Q_FOREVER - { - prevIndex = proxyModel->index ( prevIndex.row() - 1, q->modelColumn(), q->rootIndex() ); - QRect tempRect = q->visualRect ( prevIndex ); - tempRect = mapFromViewport ( tempRect ); - if ( tempRect.topLeft().y() < prevRect.topLeft().y() ) - { - break; - } - if ( tempRect.bottomRight().y() > prevRect.bottomRight().y() ) - { - prevRect = tempRect; - } - if ( prevIndex == block.firstIndex ) - { - break; - } - } - if ( q->layoutDirection() == Qt::LeftToRight ) - { - item.topLeft.rx() = categoryDrawer->leftMargin() + blockPos.x() + q->spacing(); - } - else - { - item.topLeft.rx() = viewportWidth() - currSize.width() + categoryDrawer->leftMargin() + categorySpacing; - } - item.topLeft.ry() = ( prevRect.bottomRight().y() + 1 ) + q->spacing() - blockPos.y(); - } - else - { - if ( q->layoutDirection() == Qt::LeftToRight ) - { - item.topLeft.rx() = ( prevRect.bottomRight().x() + 1 ) + q->spacing(); - } - else - { - item.topLeft.rx() = ( prevRect.bottomLeft().x() - 1 ) - q->spacing() - item.size.width() + categoryDrawer->leftMargin() + categorySpacing; - } - item.topLeft.ry() = prevRect.topLeft().y() - blockPos.y(); - } - } - else - { - if ( q->layoutDirection() == Qt::LeftToRight ) - { - item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin() + q->spacing(); - } - else - { - item.topLeft.rx() = viewportWidth() - currSize.width() + categoryDrawer->leftMargin() + categorySpacing; - } - item.topLeft.ry() = q->spacing(); - } - } - } - item.size = q->sizeHintForIndex ( index ); -} - -void KCategorizedView::Private::topToBottomVisualRect ( const QModelIndex &index, Item &item, - const Block &block, const QPoint &blockPos ) const -{ - const int firstIndexRow = block.firstIndex.row(); - - if ( hasGrid() ) - { - const int relativeRow = index.row() - firstIndexRow; - item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin(); - item.topLeft.ry() = relativeRow * q->gridSize().height(); - } - else - { - if ( q->uniformItemSizes() ) - { - const int relativeRow = index.row() - firstIndexRow; - const QSize itemSize = q->sizeHintForIndex ( index ); - item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin(); - item.topLeft.ry() = relativeRow * itemSize.height(); - } - else - { - if ( index != block.firstIndex ) - { - QModelIndex prevIndex = proxyModel->index ( index.row() - 1, q->modelColumn(), q->rootIndex() ); - QRect prevRect = q->visualRect ( prevIndex ); - prevRect = mapFromViewport ( prevRect ); - item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin() + q->spacing(); - item.topLeft.ry() = ( prevRect.bottomRight().y() + 1 ) + q->spacing() - blockPos.y(); - } - else - { - item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin() + q->spacing(); - item.topLeft.ry() = q->spacing(); - } - } - } - item.size = q->sizeHintForIndex ( index ); - item.size.setWidth ( viewportWidth() ); -} - -void KCategorizedView::Private::_k_slotCollapseOrExpandClicked ( QModelIndex ) -{ -} - -//END: Private part - -//BEGIN: Public part - -KCategorizedView::KCategorizedView ( QWidget *parent ) - : QListView ( parent ) - , d ( new Private ( this ) ) -{ -} - -KCategorizedView::~KCategorizedView() -{ - delete d; -} - -void KCategorizedView::setModel ( QAbstractItemModel *model ) -{ - if ( d->proxyModel == model ) - { - return; - } - - d->blocks.clear(); - - if ( d->proxyModel ) - { - disconnect ( d->proxyModel, SIGNAL ( layoutChanged() ), this, SLOT ( slotLayoutChanged() ) ); - } - - d->proxyModel = dynamic_cast ( model ); - - if ( d->proxyModel ) - { - connect ( d->proxyModel, SIGNAL ( layoutChanged() ), this, SLOT ( slotLayoutChanged() ) ); - } - - QListView::setModel ( model ); - - // if the model already had information inserted, update our data structures to it - if ( model->rowCount() ) - { - slotLayoutChanged(); - } -} - - -void KCategorizedView::setUniformItemWidths(bool enable) -{ - d->constantItemWidth = enable; -} - - -bool KCategorizedView::uniformItemWidths() const -{ - return d->constantItemWidth; -} - -void KCategorizedView::setGridSize ( const QSize &size ) -{ - setGridSizeOwn ( size ); -} - -void KCategorizedView::setGridSizeOwn ( const QSize &size ) -{ - d->regenerateAllElements(); - QListView::setGridSize ( size ); -} - -QRect KCategorizedView::visualRect ( const QModelIndex &index ) const -{ - if ( !d->isCategorized() ) - { - return QListView::visualRect ( index ); - } - - if ( !index.isValid() ) - { - return QRect(); - } - - const QString category = d->categoryForIndex ( index ); - - if ( !d->blocks.contains ( category ) ) - { - return QRect(); - } - - Private::Block &block = d->blocks[category]; - const int firstIndexRow = block.firstIndex.row(); - - Q_ASSERT ( block.firstIndex.isValid() ); - - if ( index.row() - firstIndexRow < 0 || index.row() - firstIndexRow >= block.items.count() ) - { - return QRect(); - } - - const QPoint blockPos = d->blockPosition ( category ); - - Private::Item &ritem = block.items[index.row() - firstIndexRow]; - - if ( ritem.topLeft.isNull() || ( block.quarantineStart.isValid() && - index.row() >= block.quarantineStart.row() ) ) - { - if ( flow() == LeftToRight ) - { - d->leftToRightVisualRect ( index, ritem, block, blockPos ); - } - else - { - d->topToBottomVisualRect ( index, ritem, block, blockPos ); - } - - //BEGIN: update the quarantine start - const bool wasLastIndex = ( index.row() == ( block.firstIndex.row() + block.items.count() - 1 ) ); - if ( index.row() == block.quarantineStart.row() ) - { - if ( wasLastIndex ) - { - block.quarantineStart = QModelIndex(); - } - else - { - const QModelIndex nextIndex = d->proxyModel->index ( index.row() + 1, modelColumn(), rootIndex() ); - block.quarantineStart = nextIndex; - } - } - //END: update the quarantine start - } - - // we get now the absolute position through the relative position of the parent block. do not - // save this on ritem, since this would override the item relative position in block terms. - Private::Item item ( ritem ); - item.topLeft.ry() += blockPos.y(); - - const QSize sizeHint = item.size; - - if ( d->hasGrid() ) - { - const QSize sizeGrid = gridSize(); - const QSize resultingSize = sizeHint.boundedTo ( sizeGrid ); - QRect res ( item.topLeft.x() + ( ( sizeGrid.width() - resultingSize.width() ) / 2 ), - item.topLeft.y(), resultingSize.width(), resultingSize.height() ); - if ( block.collapsed ) - { - // we can still do binary search, while we "hide" items. We move those items in collapsed - // blocks to the left and set a 0 height. - res.setLeft ( -resultingSize.width() ); - res.setHeight ( 0 ); - } - return d->mapToViewport ( res ); - } - - QRect res ( item.topLeft.x(), item.topLeft.y(), sizeHint.width(), sizeHint.height() ); - if ( block.collapsed ) - { - // we can still do binary search, while we "hide" items. We move those items in collapsed - // blocks to the left and set a 0 height. - res.setLeft ( -sizeHint.width() ); - res.setHeight ( 0 ); - } - return d->mapToViewport ( res ); -} - -KCategoryDrawer *KCategorizedView::categoryDrawer() const -{ - return d->categoryDrawer; -} - -void KCategorizedView::setCategoryDrawer ( KCategoryDrawer *categoryDrawer ) -{ - disconnect ( d->categoryDrawer, SIGNAL ( collapseOrExpandClicked ( QModelIndex ) ), - this, SLOT ( slotCollapseOrExpandClicked ( QModelIndex ) ) ); - d->categoryDrawer = categoryDrawer; - - connect ( d->categoryDrawer, SIGNAL ( collapseOrExpandClicked ( QModelIndex ) ), - this, SLOT ( slotCollapseOrExpandClicked ( QModelIndex ) ) ); -} - -int KCategorizedView::categorySpacing() const -{ - return d->categorySpacing; -} - -void KCategorizedView::setCategorySpacing ( int categorySpacing ) -{ - if ( d->categorySpacing == categorySpacing ) - { - return; - } - - d->categorySpacing = categorySpacing; - - for ( QHash::Iterator it = d->blocks.begin(); it != d->blocks.end(); ++it ) - { - Private::Block &block = *it; - block.outOfQuarantine = false; - } -} - -bool KCategorizedView::alternatingBlockColors() const -{ - return d->alternatingBlockColors; -} - -void KCategorizedView::setAlternatingBlockColors ( bool enable ) -{ - d->alternatingBlockColors = enable; -} - -bool KCategorizedView::collapsibleBlocks() const -{ - return d->collapsibleBlocks; -} - -void KCategorizedView::setCollapsibleBlocks ( bool enable ) -{ - d->collapsibleBlocks = enable; -} - -QModelIndexList KCategorizedView::block ( const QString &category ) -{ - QModelIndexList res; - const Private::Block &block = d->blocks[category]; - if ( block.height == -1 ) - { - return res; - } - QModelIndex current = block.firstIndex; - const int first = current.row(); - for ( int i = 1; i <= block.items.count(); ++i ) - { - if ( current.isValid() ) - { - res << current; - } - current = d->proxyModel->index ( first + i, modelColumn(), rootIndex() ); - } - return res; -} - -QModelIndexList KCategorizedView::block ( const QModelIndex &representative ) -{ - return block ( representative.data ( KCategorizedSortFilterProxyModel::CategoryDisplayRole ).toString() ); -} - -QModelIndex KCategorizedView::indexAt ( const QPoint &point ) const -{ - if ( !d->isCategorized() ) - { - return QListView::indexAt ( point ); - } - - const int rowCount = d->proxyModel->rowCount(); - if ( !rowCount ) - { - return QModelIndex(); - } - - // Binary search that will try to spot if there is an index under point - int bottom = 0; - int top = rowCount - 1; - while ( bottom <= top ) - { - const int middle = ( bottom + top ) / 2; - const QModelIndex index = d->proxyModel->index ( middle, modelColumn(), rootIndex() ); - QRect rect = visualRect ( index ); - const int verticalOff = verticalOffset(); - int horizontalOff = horizontalOffset(); - if ( layoutDirection() == Qt::RightToLeft ) - { - horizontalOff *= -1; - } - rect.topLeft().ry() += verticalOff; - rect.topLeft().rx() += horizontalOff; - rect.bottomRight().ry() += verticalOff; - rect.bottomRight().rx() += horizontalOff; - if ( rect.contains ( point ) ) - { - if ( index.model()->flags ( index ) & Qt::ItemIsEnabled ) - { - return index; - } - return QModelIndex(); - } - bool directionCondition; - if ( layoutDirection() == Qt::LeftToRight ) - { - directionCondition = point.x() > rect.bottomRight().x(); - } - else - { - directionCondition = point.x() < rect.bottomLeft().x(); - } - if ( point.y() > rect.bottomRight().y() || - ( point.y() > rect.topLeft().y() && point.y() < rect.bottomRight().y() && directionCondition ) ) - { - bottom = middle + 1; - } - else - { - top = middle - 1; - } - } - return QModelIndex(); -} - -void KCategorizedView::reset() -{ - d->blocks.clear(); - QListView::reset(); -} - -void KCategorizedView::paintEvent ( QPaintEvent *event ) -{ - if ( !d->isCategorized() ) - { - QListView::paintEvent ( event ); - return; - } - - const QPair intersecting = d->intersectingIndexesWithRect ( viewport()->rect().intersected ( event->rect() ) ); - - QPainter p ( viewport() ); - p.save(); - - Q_ASSERT ( selectionModel()->model() == d->proxyModel ); - - //BEGIN: draw categories - QHash::ConstIterator it ( d->blocks.constBegin() ); - while ( it != d->blocks.constEnd() ) - { - const Private::Block &block = *it; - const QModelIndex categoryIndex = d->proxyModel->index ( block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); - QStyleOptionViewItemV4 option ( viewOptions() ); - option.features |= d->alternatingBlockColors && block.alternate ? QStyleOptionViewItemV4::Alternate - : QStyleOptionViewItemV4::None; - option.state |= !d->collapsibleBlocks || !block.collapsed ? QStyle::State_Open - : QStyle::State_None; - const int height = d->categoryDrawer->categoryHeight ( categoryIndex, option ); - QPoint pos = d->blockPosition ( it.key() ); - pos.ry() -= height; - option.rect.setTopLeft ( pos ); - option.rect.setWidth ( d->viewportWidth() + d->categoryDrawer->leftMargin() + d->categoryDrawer->rightMargin() ); - option.rect.setHeight ( height + d->blockHeight ( it.key() ) ); - option.rect = d->mapToViewport ( option.rect ); - if ( !option.rect.intersects ( viewport()->rect() ) ) - { - ++it; - continue; - } - d->categoryDrawer->drawCategory ( categoryIndex, d->proxyModel->sortRole(), option, &p ); - ++it; - } - //END: draw categories - - if ( intersecting.first.isValid() && intersecting.second.isValid() ) - { - //BEGIN: draw items - int i = intersecting.first.row(); - int indexToCheckIfBlockCollapsed = i; - QModelIndex categoryIndex; - QString category; - Private::Block *block = 0; - while ( i <= intersecting.second.row() ) - { - //BEGIN: first check if the block is collapsed. if so, we have to skip the item painting - if ( i == indexToCheckIfBlockCollapsed ) - { - categoryIndex = d->proxyModel->index ( i, d->proxyModel->sortColumn(), rootIndex() ); - category = categoryIndex.data ( KCategorizedSortFilterProxyModel::CategoryDisplayRole ).toString(); - block = &d->blocks[category]; - indexToCheckIfBlockCollapsed = block->firstIndex.row() + block->items.count(); - if ( block->collapsed ) - { - i = indexToCheckIfBlockCollapsed; - continue; - } - } - //END: first check if the block is collapsed. if so, we have to skip the item painting - - Q_ASSERT ( block ); - - const bool alternateItem = ( i - block->firstIndex.row() ) % 2; - - const QModelIndex index = d->proxyModel->index ( i, modelColumn(), rootIndex() ); - const Qt::ItemFlags flags = d->proxyModel->flags ( index ); - QStyleOptionViewItemV4 option ( viewOptions() ); - option.rect = visualRect ( index ); - option.widget = this; - option.features |= wordWrap() ? QStyleOptionViewItemV2::WrapText - : QStyleOptionViewItemV2::None; - option.features |= alternatingRowColors() && alternateItem ? QStyleOptionViewItemV4::Alternate - : QStyleOptionViewItemV4::None; - if ( flags & Qt::ItemIsSelectable ) - { - option.state |= selectionModel()->isSelected ( index ) ? QStyle::State_Selected - : QStyle::State_None; - } - else - { - option.state &= ~QStyle::State_Selected; - } - option.state |= ( index == currentIndex() ) ? QStyle::State_HasFocus - : QStyle::State_None; - if ( ! ( flags & Qt::ItemIsEnabled ) ) - { - option.state &= ~QStyle::State_Enabled; - } - else - { - option.state |= ( index == d->hoveredIndex ) ? QStyle::State_MouseOver - : QStyle::State_None; - } - - itemDelegate ( index )->paint ( &p, option, index ); - ++i; - } - //END: draw items - } - - //BEGIN: draw selection rect - if ( isSelectionRectVisible() && d->rubberBandRect.isValid() ) - { - QStyleOptionRubberBand opt; - opt.initFrom ( this ); - opt.shape = QRubberBand::Rectangle; - opt.opaque = false; - opt.rect = d->mapToViewport ( d->rubberBandRect ).intersected ( viewport()->rect().adjusted ( -16, -16, 16, 16 ) ); - p.save(); - style()->drawControl ( QStyle::CE_RubberBand, &opt, &p ); - p.restore(); - } - //END: draw selection rect - - p.restore(); -} - -void KCategorizedView::resizeEvent ( QResizeEvent *event ) -{ - d->regenerateAllElements(); - QListView::resizeEvent ( event ); -} - -void KCategorizedView::setSelection ( const QRect &rect, - QItemSelectionModel::SelectionFlags flags ) -{ - if ( !d->isCategorized() ) - { - QListView::setSelection ( rect, flags ); - return; - } - - if ( rect.topLeft() == rect.bottomRight() ) - { - const QModelIndex index = indexAt ( rect.topLeft() ); - selectionModel()->select ( index, flags ); - return; - } - - const QPair intersecting = d->intersectingIndexesWithRect ( rect ); - - QItemSelection selection; - - //TODO: think of a faster implementation - QModelIndex firstIndex; - QModelIndex lastIndex; - for ( int i = intersecting.first.row(); i <= intersecting.second.row(); ++i ) - { - const QModelIndex index = d->proxyModel->index ( i, modelColumn(), rootIndex() ); - const bool visualRectIntersects = visualRect ( index ).intersects ( rect ); - if ( firstIndex.isValid() ) - { - if ( visualRectIntersects ) - { - lastIndex = index; - } - else - { - selection << QItemSelectionRange ( firstIndex, lastIndex ); - firstIndex = QModelIndex(); - } - } - else if ( visualRectIntersects ) - { - firstIndex = index; - lastIndex = index; - } - } - - if ( firstIndex.isValid() ) - { - selection << QItemSelectionRange ( firstIndex, lastIndex ); - } - - selectionModel()->select ( selection, flags ); -} - -void KCategorizedView::mouseMoveEvent ( QMouseEvent *event ) -{ - QListView::mouseMoveEvent ( event ); - d->hoveredIndex = indexAt ( event->pos() ); - const SelectionMode itemViewSelectionMode = selectionMode(); - if ( state() == DragSelectingState && isSelectionRectVisible() && itemViewSelectionMode != SingleSelection - && itemViewSelectionMode != NoSelection ) - { - QRect rect ( d->pressedPosition, event->pos() + QPoint ( horizontalOffset(), verticalOffset() ) ); - rect = rect.normalized(); - update ( rect.united ( d->rubberBandRect ) ); - d->rubberBandRect = rect; - } - QHash::ConstIterator it ( d->blocks.constBegin() ); - while ( it != d->blocks.constEnd() ) - { - const Private::Block &block = *it; - const QModelIndex categoryIndex = d->proxyModel->index ( block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); - QStyleOptionViewItemV4 option ( viewOptions() ); - const int height = d->categoryDrawer->categoryHeight ( categoryIndex, option ); - QPoint pos = d->blockPosition ( it.key() ); - pos.ry() -= height; - option.rect.setTopLeft ( pos ); - option.rect.setWidth ( d->viewportWidth() + d->categoryDrawer->leftMargin() + d->categoryDrawer->rightMargin() ); - option.rect.setHeight ( height + d->blockHeight ( it.key() ) ); - option.rect = d->mapToViewport ( option.rect ); - const QPoint mousePos = viewport()->mapFromGlobal ( QCursor::pos() ); - if ( option.rect.contains ( mousePos ) ) - { - if ( d->categoryDrawer && d->hoveredBlock->height != -1 && *d->hoveredBlock != block ) - { - const QModelIndex categoryIndex = d->proxyModel->index ( d->hoveredBlock->firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); - const QStyleOptionViewItemV4 option = d->blockRect ( categoryIndex ); - d->categoryDrawer->mouseLeft ( categoryIndex, option.rect ); - *d->hoveredBlock = block; - d->hoveredCategory = it.key(); - viewport()->update ( option.rect ); - } - else if ( d->hoveredBlock->height == -1 ) - { - *d->hoveredBlock = block; - d->hoveredCategory = it.key(); - } - else if ( d->categoryDrawer ) - { - d->categoryDrawer->mouseMoved ( categoryIndex, option.rect, event ); - } - viewport()->update ( option.rect ); - return; - } - ++it; - } - if ( d->categoryDrawer && d->hoveredBlock->height != -1 ) - { - const QModelIndex categoryIndex = d->proxyModel->index ( d->hoveredBlock->firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); - const QStyleOptionViewItemV4 option = d->blockRect ( categoryIndex ); - d->categoryDrawer->mouseLeft ( categoryIndex, option.rect ); - *d->hoveredBlock = Private::Block(); - d->hoveredCategory = QString(); - viewport()->update ( option.rect ); - } -} - -void KCategorizedView::mousePressEvent ( QMouseEvent *event ) -{ - if ( event->button() == Qt::LeftButton ) - { - d->pressedPosition = event->pos(); - d->pressedPosition.rx() += horizontalOffset(); - d->pressedPosition.ry() += verticalOffset(); - } - if ( !d->categoryDrawer ) - { - QListView::mousePressEvent ( event ); - return; - } - QHash::ConstIterator it ( d->blocks.constBegin() ); - while ( it != d->blocks.constEnd() ) - { - const Private::Block &block = *it; - const QModelIndex categoryIndex = d->proxyModel->index ( block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); - const QStyleOptionViewItemV4 option = d->blockRect ( categoryIndex ); - const QPoint mousePos = viewport()->mapFromGlobal ( QCursor::pos() ); - if ( option.rect.contains ( mousePos ) ) - { - if ( d->categoryDrawer ) - { - d->categoryDrawer->mouseButtonPressed ( categoryIndex, option.rect, event ); - } - viewport()->update ( option.rect ); - if ( !event->isAccepted() ) - { - QListView::mousePressEvent ( event ); - } - return; - } - ++it; - } - QListView::mousePressEvent ( event ); -} - -void KCategorizedView::mouseReleaseEvent ( QMouseEvent *event ) -{ - d->pressedPosition = QPoint(); - d->rubberBandRect = QRect(); - QHash::ConstIterator it ( d->blocks.constBegin() ); - while ( it != d->blocks.constEnd() ) - { - const Private::Block &block = *it; - const QModelIndex categoryIndex = d->proxyModel->index ( block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); - const QStyleOptionViewItemV4 option = d->blockRect ( categoryIndex ); - const QPoint mousePos = viewport()->mapFromGlobal ( QCursor::pos() ); - if ( option.rect.contains ( mousePos ) ) - { - if ( d->categoryDrawer ) - { - d->categoryDrawer->mouseButtonReleased ( categoryIndex, option.rect, event ); - } - viewport()->update ( option.rect ); - if ( !event->isAccepted() ) - { - QListView::mouseReleaseEvent ( event ); - } - return; - } - ++it; - } - QListView::mouseReleaseEvent ( event ); -} - -void KCategorizedView::leaveEvent ( QEvent *event ) -{ - QListView::leaveEvent ( event ); - if ( d->hoveredIndex.isValid() ) - { - viewport()->update ( visualRect ( d->hoveredIndex ) ); - d->hoveredIndex = QModelIndex(); - } - if ( d->categoryDrawer && d->hoveredBlock->height != -1 ) - { - const QModelIndex categoryIndex = d->proxyModel->index ( d->hoveredBlock->firstIndex.row(), d->proxyModel->sortColumn(), rootIndex() ); - const QStyleOptionViewItemV4 option = d->blockRect ( categoryIndex ); - d->categoryDrawer->mouseLeft ( categoryIndex, option.rect ); - *d->hoveredBlock = Private::Block(); - d->hoveredCategory = QString(); - viewport()->update ( option.rect ); - } -} - -void KCategorizedView::startDrag ( Qt::DropActions supportedActions ) -{ - QListView::startDrag ( supportedActions ); -} - -void KCategorizedView::dragMoveEvent ( QDragMoveEvent *event ) -{ - QListView::dragMoveEvent ( event ); - d->hoveredIndex = indexAt ( event->pos() ); -} - -void KCategorizedView::dragEnterEvent ( QDragEnterEvent *event ) -{ - QListView::dragEnterEvent ( event ); -} - -void KCategorizedView::dragLeaveEvent ( QDragLeaveEvent *event ) -{ - QListView::dragLeaveEvent ( event ); -} - -void KCategorizedView::dropEvent ( QDropEvent *event ) -{ - QListView::dropEvent ( event ); -} - -//TODO: improve se we take into account collapsed blocks -//TODO: take into account when there is no grid and no uniformItemSizes -QModelIndex KCategorizedView::moveCursor ( CursorAction cursorAction, - Qt::KeyboardModifiers modifiers ) -{ - if ( !d->isCategorized() ) - { - return QListView::moveCursor ( cursorAction, modifiers ); - } - - const QModelIndex current = currentIndex(); - const QRect currentRect = visualRect ( current ); - if ( !current.isValid() ) - { - const int rowCount = d->proxyModel->rowCount ( rootIndex() ); - if ( !rowCount ) - { - return QModelIndex(); - } - return d->proxyModel->index ( 0, modelColumn(), rootIndex() ); - } - - switch ( cursorAction ) - { - case MoveLeft: - { - if ( !current.row() ) - { - return QModelIndex(); - } - const QModelIndex previous = d->proxyModel->index ( current.row() - 1, modelColumn(), rootIndex() ); - const QRect previousRect = visualRect ( previous ); - if ( previousRect.top() == currentRect.top() ) - { - return previous; - } - - return QModelIndex(); - } - case MoveRight: - { - if ( current.row() == d->proxyModel->rowCount() - 1 ) - { - return QModelIndex(); - } - const QModelIndex next = d->proxyModel->index ( current.row() + 1, modelColumn(), rootIndex() ); - const QRect nextRect = visualRect ( next ); - if ( nextRect.top() == currentRect.top() ) - { - return next; - } - - return QModelIndex(); - } - case MoveDown: - { - if ( d->hasGrid() || uniformItemSizes() || uniformItemWidths() ) - { - const QModelIndex current = currentIndex(); - const QSize itemSize = d->hasGrid() ? gridSize() - : sizeHintForIndex ( current ); - const Private::Block &block = d->blocks[d->categoryForIndex ( current )]; - //HACK: Why is the -2 needed? - const int maxItemsPerRow = qMax ( ( d->viewportWidth() - spacing() - 2 ) / ( itemSize.width() + spacing() ), 1 ); - const bool canMove = current.row() + maxItemsPerRow < block.firstIndex.row() + - block.items.count(); - - if ( canMove ) - { - return d->proxyModel->index ( current.row() + maxItemsPerRow, modelColumn(), rootIndex() ); - } - - const int currentRelativePos = ( current.row() - block.firstIndex.row() ) % maxItemsPerRow; - const QModelIndex nextIndex = d->proxyModel->index ( block.firstIndex.row() + block.items.count(), modelColumn(), rootIndex() ); - - if ( !nextIndex.isValid() ) - { - return QModelIndex(); - } - - const Private::Block &nextBlock = d->blocks[d->categoryForIndex ( nextIndex )]; - - if ( nextBlock.items.count() <= currentRelativePos ) - { - return QModelIndex(); - } - - if ( currentRelativePos < ( block.items.count() % maxItemsPerRow ) ) - { - return d->proxyModel->index ( nextBlock.firstIndex.row() + currentRelativePos, modelColumn(), rootIndex() ); - } - - return QModelIndex(); - } - } - case MoveUp: - { - if ( d->hasGrid() || uniformItemSizes() || uniformItemWidths() ) - { - const QModelIndex current = currentIndex(); - const QSize itemSize = d->hasGrid() ? gridSize() - : sizeHintForIndex ( current ); - const Private::Block &block = d->blocks[d->categoryForIndex ( current )]; - //HACK: Why is the -2 needed? - const int maxItemsPerRow = qMax ( ( d->viewportWidth() - spacing() - 2 ) / ( itemSize.width() + spacing() ), 1 ); - const bool canMove = current.row() - maxItemsPerRow >= block.firstIndex.row(); - - if ( canMove ) - { - return d->proxyModel->index ( current.row() - maxItemsPerRow, modelColumn(), rootIndex() ); - } - - const int currentRelativePos = ( current.row() - block.firstIndex.row() ) % maxItemsPerRow; - const QModelIndex prevIndex = d->proxyModel->index ( block.firstIndex.row() - 1, modelColumn(), rootIndex() ); - - if ( !prevIndex.isValid() ) - { - return QModelIndex(); - } - - const Private::Block &prevBlock = d->blocks[d->categoryForIndex ( prevIndex )]; - - if ( prevBlock.items.count() <= currentRelativePos ) - { - return QModelIndex(); - } - - const int remainder = prevBlock.items.count() % maxItemsPerRow; - if ( currentRelativePos < remainder ) - { - return d->proxyModel->index ( prevBlock.firstIndex.row() + prevBlock.items.count() - remainder + currentRelativePos, modelColumn(), rootIndex() ); - } - - return QModelIndex(); - } - } - default: - break; - } - - return QModelIndex(); -} - -void KCategorizedView::rowsAboutToBeRemoved ( const QModelIndex &parent, - int start, - int end ) -{ - if ( !d->isCategorized() ) - { - QListView::rowsAboutToBeRemoved ( parent, start, end ); - return; - } - - *d->hoveredBlock = Private::Block(); - d->hoveredCategory = QString(); - - if ( end - start + 1 == d->proxyModel->rowCount() ) - { - d->blocks.clear(); - QListView::rowsAboutToBeRemoved ( parent, start, end ); - return; - } - - // Removal feels a bit more complicated than insertion. Basically we can consider there are - // 3 different cases when going to remove items. (*) represents an item, Items between ([) and - // (]) are the ones which are marked for removal. - // - // - 1st case: - // ... * * * * * * [ * * * ... - // - // The items marked for removal are the last part of this category. No need to mark any item - // of this category as in quarantine, because no special offset will be pushed to items at - // the right because of any changes (since the removed items are those on the right most part - // of the category). - // - // - 2nd case: - // ... * * * * * * ] * * * ... - // - // The items marked for removal are the first part of this category. We have to mark as in - // quarantine all items in this category. Absolutely all. All items will have to be moved to - // the left (or moving up, because rows got a different offset). - // - // - 3rd case: - // ... * * [ * * * * ] * * ... - // - // The items marked for removal are in between of this category. We have to mark as in - // quarantine only those items that are at the right of the end of the removal interval, - // (starting on "]"). - // - // It hasn't been explicitly said, but when we remove, we have to mark all blocks that are - // located under the top most affected category as in quarantine (the block itself, as a whole), - // because such a change can force it to have a different offset (note that items themselves - // contain relative positions to the block, so marking the block as in quarantine is enough). - // - // Also note that removal implicitly means that we have to update correctly firstIndex of each - // block, and in general keep updated the internal information of elements. - - QStringList listOfCategoriesMarkedForRemoval; - - QString lastCategory; - int alreadyRemoved = 0; - for ( int i = start; i <= end; ++i ) - { - const QModelIndex index = d->proxyModel->index ( i, modelColumn(), parent ); - - Q_ASSERT ( index.isValid() ); - - const QString category = d->categoryForIndex ( index ); - - if ( lastCategory != category ) - { - lastCategory = category; - alreadyRemoved = 0; - } - - Private::Block &block = d->blocks[category]; - block.items.removeAt ( i - block.firstIndex.row() - alreadyRemoved ); - ++alreadyRemoved; - - if ( !block.items.count() ) - { - listOfCategoriesMarkedForRemoval << category; - } - - block.height = -1; - - viewport()->update(); - } - - //BEGIN: update the items that are in quarantine in affected categories - { - const QModelIndex lastIndex = d->proxyModel->index ( end, modelColumn(), parent ); - const QString category = d->categoryForIndex ( lastIndex ); - Private::Block &block = d->blocks[category]; - if ( block.items.count() && start <= block.firstIndex.row() && end >= block.firstIndex.row() ) - { - block.firstIndex = d->proxyModel->index ( end + 1, modelColumn(), parent ); - } - block.quarantineStart = block.firstIndex; - } - //END: update the items that are in quarantine in affected categories - - Q_FOREACH ( const QString &category, listOfCategoriesMarkedForRemoval ) - { - d->blocks.remove ( category ); - } - - //BEGIN: mark as in quarantine those categories that are under the affected ones - { - //BEGIN: order for marking as alternate those blocks that are alternate - QList blockList = d->blocks.values(); - qSort ( blockList.begin(), blockList.end(), Private::Block::lessThan ); - QList firstIndexesRows; - foreach ( const Private::Block &block, blockList ) - { - firstIndexesRows << block.firstIndex.row(); - } - //END: order for marking as alternate those blocks that are alternate - for ( QHash::Iterator it = d->blocks.begin(); it != d->blocks.end(); ++it ) - { - Private::Block &block = *it; - if ( block.firstIndex.row() > start ) - { - block.outOfQuarantine = false; - block.alternate = firstIndexesRows.indexOf ( block.firstIndex.row() ) % 2; - } - else if ( block.firstIndex.row() == start ) - { - block.alternate = firstIndexesRows.indexOf ( block.firstIndex.row() ) % 2; - } - } - } - //END: mark as in quarantine those categories that are under the affected ones - - QListView::rowsAboutToBeRemoved ( parent, start, end ); -} - -void KCategorizedView::updateGeometries() -{ - const int oldVerticalOffset = verticalOffset(); - const Qt::ScrollBarPolicy verticalP = verticalScrollBarPolicy(), horizontalP = horizontalScrollBarPolicy(); - - //BEGIN bugs 213068, 287847 ------------------------------------------------------------ - /* - * QListView::updateGeometries() has it's own opinion on whether the scrollbars should be visible (valid range) or not - * and triggers a (sometimes additionally timered) resize through ::layoutChildren() - * http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/itemviews/qlistview.cpp#line1499 - * (the comment above the main block isn't all accurate, layoutChldren is called regardless of the policy) - * - * As a result QListView and KCategorizedView occasionally started a race on the scrollbar visibility, effectively blocking the UI - * So we prevent QListView from having an own opinion on the scrollbar visibility by - * fixing it before calling the baseclass QListView::updateGeometries() - * - * Since the implicit show/hide by the followin range setting will cause further resizes if the policy is Qt::ScrollBarAsNeeded - * we keep it static until we're done, then restore the original value and ultimately change the scrollbar visibility ourself. - */ - if ( d->isCategorized() ) // important! - otherwise we'd pollute the setting if the view is initially not categorized - { - setVerticalScrollBarPolicy ( ( verticalP == Qt::ScrollBarAlwaysOn || verticalScrollBar()->isVisibleTo ( this ) ) ? - Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff ); - setHorizontalScrollBarPolicy ( ( horizontalP == Qt::ScrollBarAlwaysOn || horizontalScrollBar()->isVisibleTo ( this ) ) ? - Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff ); - } - //END bugs 213068, 287847 -------------------------------------------------------------- - - QListView::updateGeometries(); - - if ( !d->isCategorized() ) - { - return; - } - - const int rowCount = d->proxyModel->rowCount(); - if ( !rowCount ) - { - verticalScrollBar()->setRange ( 0, 0 ); - // unconditional, see function end todo - horizontalScrollBar()->setRange ( 0, 0 ); - return; - } - - const QModelIndex lastIndex = d->proxyModel->index ( rowCount - 1, modelColumn(), rootIndex() ); - Q_ASSERT ( lastIndex.isValid() ); - QRect lastItemRect = visualRect ( lastIndex ); - - if ( d->hasGrid() ) - { - lastItemRect.setSize ( lastItemRect.size().expandedTo ( gridSize() ) ); - } - else - { - if ( uniformItemSizes() ) - { - QSize itemSize = sizeHintForIndex ( lastIndex ); - itemSize.setHeight ( itemSize.height() + spacing() ); - lastItemRect.setSize ( itemSize ); - } - else - { - QSize itemSize = sizeHintForIndex ( lastIndex ); - const QString category = d->categoryForIndex ( lastIndex ); - itemSize.setHeight ( d->highestElementInLastRow ( d->blocks[category] ) + spacing() ); - lastItemRect.setSize ( itemSize ); - } - } - - const int bottomRange = lastItemRect.bottomRight().y() + verticalOffset() - viewport()->height(); - - if ( verticalScrollMode() == ScrollPerItem ) - { - verticalScrollBar()->setSingleStep ( lastItemRect.height() ); - const int rowsPerPage = qMax ( viewport()->height() / lastItemRect.height(), 1 ); - verticalScrollBar()->setPageStep ( rowsPerPage * lastItemRect.height() ); - } - - verticalScrollBar()->setRange ( 0, bottomRange ); - verticalScrollBar()->setValue ( oldVerticalOffset ); - - //TODO: also consider working with the horizontal scroll bar. since at this level I am not still - // supporting "top to bottom" flow, there is no real problem. If I support that someday - // (think how to draw categories), we would have to take care of the horizontal scroll bar too. - // In theory, as KCategorizedView has been designed, there is no need of horizontal scroll bar. - horizontalScrollBar()->setRange ( 0, 0 ); - - //BEGIN bugs 213068, 287847 ------------------------------------------------------------ - // restoring values from above ... - setVerticalScrollBarPolicy ( verticalP ); - setHorizontalScrollBarPolicy ( horizontalP ); - // ... and correct the visibility - bool validRange = verticalScrollBar()->maximum() != verticalScrollBar()->minimum(); - if ( verticalP == Qt::ScrollBarAsNeeded && ( verticalScrollBar()->isVisibleTo ( this ) != validRange ) ) - verticalScrollBar()->setVisible ( validRange ); - validRange = horizontalScrollBar()->maximum() > horizontalScrollBar()->minimum(); - if ( horizontalP == Qt::ScrollBarAsNeeded && ( horizontalScrollBar()->isVisibleTo ( this ) != validRange ) ) - horizontalScrollBar()->setVisible ( validRange ); - //END bugs 213068, 287847 -------------------------------------------------------------- -} - -void KCategorizedView::currentChanged ( const QModelIndex ¤t, - const QModelIndex &previous ) -{ - QListView::currentChanged ( current, previous ); -} - -void KCategorizedView::dataChanged ( const QModelIndex &topLeft, - const QModelIndex &bottomRight ) -{ - QListView::dataChanged ( topLeft, bottomRight ); - if ( !d->isCategorized() ) - { - return; - } - - *d->hoveredBlock = Private::Block(); - d->hoveredCategory = QString(); - - //BEGIN: since the model changed data, we need to reconsider item sizes - int i = topLeft.row(); - int indexToCheck = i; - QModelIndex categoryIndex; - QString category; - Private::Block *block; - while ( i <= bottomRight.row() ) - { - const QModelIndex currIndex = d->proxyModel->index ( i, modelColumn(), rootIndex() ); - if ( i == indexToCheck ) - { - categoryIndex = d->proxyModel->index ( i, d->proxyModel->sortColumn(), rootIndex() ); - category = categoryIndex.data ( KCategorizedSortFilterProxyModel::CategoryDisplayRole ).toString(); - block = &d->blocks[category]; - block->quarantineStart = currIndex; - indexToCheck = block->firstIndex.row() + block->items.count(); - } - visualRect ( currIndex ); - ++i; - } - //END: since the model changed data, we need to reconsider item sizes -} - -void KCategorizedView::rowsInserted ( const QModelIndex &parent, - int start, - int end ) -{ - QListView::rowsInserted ( parent, start, end ); - if ( !d->isCategorized() ) - { - return; - } - - *d->hoveredBlock = Private::Block(); - d->hoveredCategory = QString(); - d->rowsInserted ( parent, start, end ); -} - -void KCategorizedView::slotLayoutChanged() -{ - if ( !d->isCategorized() ) - { - return; - } - - d->blocks.clear(); - *d->hoveredBlock = Private::Block(); - d->hoveredCategory = QString(); - if ( d->proxyModel->rowCount() ) - { - d->rowsInserted ( rootIndex(), 0, d->proxyModel->rowCount() - 1 ); - } -} -//END: Public part - -void KCategorizedView::slotCollapseOrExpandClicked ( QModelIndex idx ) -{ - d->_k_slotCollapseOrExpandClicked ( idx ); -} - - -#include "categorizedview.moc" diff --git a/libgroupview/src/categorizedview_p.h b/libgroupview/src/categorizedview_p.h deleted file mode 100644 index 13809312..00000000 --- a/libgroupview/src/categorizedview_p.h +++ /dev/null @@ -1,159 +0,0 @@ -/** - * This file is part of the KDE project - * Copyright (C) 2007, 2009 Rafael Fernández López - * - * This library 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 library 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 library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef KCATEGORIZEDVIEW_P_H -#define KCATEGORIZEDVIEW_P_H - -class KCategorizedSortFilterProxyModel; -class KCategoryDrawer; -class KCategoryDrawerV2; -class KCategoryDrawerV3; - -/** - * @internal - */ -class KCategorizedView::Private -{ -public: - struct Block; - struct Item; - - Private(KCategorizedView *q); - ~Private(); - - /** - * @return whether this view has all required elements to be categorized. - */ - bool isCategorized() const; - - /** - * @return the block rect for the representative @p representative. - */ - QStyleOptionViewItemV4 blockRect(const QModelIndex &representative); - - /** - * Returns the first and last element that intersects with rect. - * - * @note see that here we cannot take out items between first and last (as we could - * do with the rubberband). - * - * Complexity: O(log(n)) where n is model()->rowCount(). - */ - QPair intersectingIndexesWithRect(const QRect &rect) const; - - /** - * Returns the position of the block of @p category. - * - * Complexity: O(n) where n is the number of different categories when the block has been - * marked as in quarantine. O(1) the rest of the times (the vast majority). - */ - QPoint blockPosition(const QString &category); - - /** - * Returns the height of the block determined by @p category. - */ - int blockHeight(const QString &category); - - /** - * Returns the actual viewport width. - */ - int viewportWidth() const; - - /** - * Marks all elements as in quarantine. - * - * Complexity: O(n) where n is model()->rowCount(). - * - * @warning this is an expensive operation - */ - void regenerateAllElements(); - - /** - * Update internal information, and keep sync with the real information that the model contains. - */ - void rowsInserted(const QModelIndex &parent, int start, int end); - - /** - * Returns @p rect in viewport terms, taking in count horizontal and vertical offsets. - */ - QRect mapToViewport(const QRect &rect) const; - - /** - * Returns @p rect in absolute terms, converted from viewport position. - */ - QRect mapFromViewport(const QRect &rect) const; - - /** - * Returns the height of the highest element in last row. This is only applicable if there is - * no grid set and uniformItemSizes is false. - * - * @param block in which block are we searching. Necessary to stop the search if we hit the - * first item in this block. - */ - int highestElementInLastRow(const Block &block) const; - - /** - * Returns whether the view has a valid grid size. - */ - bool hasGrid() const; - - /** - * Returns the category for the given index. - */ - QString categoryForIndex(const QModelIndex &index) const; - - /** - * Updates the visual rect for item when flow is LeftToRight. - */ - void leftToRightVisualRect(const QModelIndex &index, Item &item, - const Block &block, const QPoint &blockPos) const; - - /** - * Updates the visual rect for item when flow is TopToBottom. - * @note we only support viewMode == ListMode in this case. - */ - void topToBottomVisualRect(const QModelIndex &index, Item &item, - const Block &block, const QPoint &blockPos) const; - - /** - * Called when expand or collapse has been clicked on the category drawer. - */ - void _k_slotCollapseOrExpandClicked(QModelIndex); - - KCategorizedView *q; - KCategorizedSortFilterProxyModel *proxyModel; - KCategoryDrawer *categoryDrawer; - int categorySpacing; - bool alternatingBlockColors; - bool collapsibleBlocks; - bool constantItemWidth; - - Block *hoveredBlock; - QString hoveredCategory; - QModelIndex hoveredIndex; - - QPoint pressedPosition; - QRect rubberBandRect; - - QHash blocks; -}; - -#endif // KCATEGORIZEDVIEW_P_H - diff --git a/libgroupview/src/categorydrawer.cpp b/libgroupview/src/categorydrawer.cpp deleted file mode 100644 index 04903206..00000000 --- a/libgroupview/src/categorydrawer.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/** - * This file is part of the KDE project - * Copyright (C) 2007, 2009 Rafael Fernández López - * - * This library 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 library 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 library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "categorydrawer.h" - -#include -#include -#include - -#include -#include - -#define HORIZONTAL_HINT 3 - -class KCategoryDrawer::Private -{ -public: - Private(KCategorizedView *view) - : view(view) - , leftMargin(0) - , rightMargin(0) - { - } - - ~Private() - { - } - int leftMargin; - int rightMargin; - KCategorizedView *view; -}; - -KCategoryDrawer::KCategoryDrawer(KCategorizedView *view) - : QObject(view) - , d(new Private(view)) -{ - setLeftMargin(2); - setRightMargin(2); -} - -KCategoryDrawer::~KCategoryDrawer() -{ - delete d; -} - - -void KCategoryDrawer::drawCategory(const QModelIndex &index, - int /*sortRole*/, - const QStyleOption &option, - QPainter *painter) const -{ - painter->setRenderHint(QPainter::Antialiasing); - - const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); - const QRect optRect = option.rect; - QFont font(QApplication::font()); - font.setBold(true); - const QFontMetrics fontMetrics = QFontMetrics(font); - - QColor outlineColor = option.palette.text().color(); - outlineColor.setAlphaF(0.35); - - //BEGIN: top left corner - { - painter->save(); - painter->setPen(outlineColor); - const QPointF topLeft(optRect.topLeft()); - QRectF arc(topLeft, QSizeF(4, 4)); - arc.translate(0.5, 0.5); - painter->drawArc(arc, 1440, 1440); - painter->restore(); - } - //END: top left corner - - //BEGIN: left vertical line - { - QPoint start(optRect.topLeft()); - start.ry() += 3; - QPoint verticalGradBottom(optRect.topLeft()); - verticalGradBottom.ry() += fontMetrics.height() + 5; - QLinearGradient gradient(start, verticalGradBottom); - gradient.setColorAt(0, outlineColor); - gradient.setColorAt(1, Qt::transparent); - painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); - } - //END: left vertical line - - //BEGIN: horizontal line - { - QPoint start(optRect.topLeft()); - start.rx() += 3; - QPoint horizontalGradTop(optRect.topLeft()); - horizontalGradTop.rx() += optRect.width() - 6; - painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor); - } - //END: horizontal line - - //BEGIN: top right corner - { - painter->save(); - painter->setPen(outlineColor); - QPointF topRight(optRect.topRight()); - topRight.rx() -= 4; - QRectF arc(topRight, QSizeF(4, 4)); - arc.translate(0.5, 0.5); - painter->drawArc(arc, 0, 1440); - painter->restore(); - } - //END: top right corner - - //BEGIN: right vertical line - { - QPoint start(optRect.topRight()); - start.ry() += 3; - QPoint verticalGradBottom(optRect.topRight()); - verticalGradBottom.ry() += fontMetrics.height() + 5; - QLinearGradient gradient(start, verticalGradBottom); - gradient.setColorAt(0, outlineColor); - gradient.setColorAt(1, Qt::transparent); - painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); - } - //END: right vertical line - - //BEGIN: text - { - QRect textRect(option.rect); - textRect.setTop(textRect.top() + 7); - textRect.setLeft(textRect.left() + 7); - textRect.setHeight(fontMetrics.height()); - textRect.setRight(textRect.right() - 7); - - painter->save(); - painter->setFont(font); - QColor penColor(option.palette.text().color()); - penColor.setAlphaF(0.6); - painter->setPen(penColor); - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, category); - painter->restore(); - } - //END: text -} - -int KCategoryDrawer::categoryHeight(const QModelIndex &index, const QStyleOption &option) const -{ - Q_UNUSED(index); - Q_UNUSED(option) - - QFont font(QApplication::font()); - font.setBold(true); - QFontMetrics fontMetrics(font); - - const int height = fontMetrics.height() + 1 /* 1 pixel-width gradient */ - + 11 /* top and bottom separation */; - return height; -} - -int KCategoryDrawer::leftMargin() const -{ - return d->leftMargin; -} - -void KCategoryDrawer::setLeftMargin(int leftMargin) -{ - d->leftMargin = leftMargin; -} - -int KCategoryDrawer::rightMargin() const -{ - return d->rightMargin; -} - -void KCategoryDrawer::setRightMargin(int rightMargin) -{ - d->rightMargin = rightMargin; -} - -KCategoryDrawer &KCategoryDrawer::operator=(const KCategoryDrawer &cd) -{ - d->leftMargin = cd.d->leftMargin; - d->rightMargin = cd.d->rightMargin; - d->view = cd.d->view; - return *this; -} - -KCategorizedView *KCategoryDrawer::view() const -{ - return d->view; -} - -void KCategoryDrawer::mouseButtonPressed(const QModelIndex&, const QRect&, QMouseEvent *event) -{ - event->ignore(); -} - -void KCategoryDrawer::mouseButtonReleased(const QModelIndex&, const QRect&, QMouseEvent *event) -{ - event->ignore(); -} - -void KCategoryDrawer::mouseMoved(const QModelIndex&, const QRect&, QMouseEvent *event) -{ - event->ignore(); -} - -void KCategoryDrawer::mouseButtonDoubleClicked(const QModelIndex&, const QRect&, QMouseEvent *event) -{ - event->ignore(); -} - -void KCategoryDrawer::mouseLeft(const QModelIndex&, const QRect&) -{ -} - -#include "categorydrawer.moc" diff --git a/libsettings/CMakeLists.txt b/libsettings/CMakeLists.txt deleted file mode 100644 index e5aae0b7..00000000 --- a/libsettings/CMakeLists.txt +++ /dev/null @@ -1,51 +0,0 @@ -project(libSettings) - -# Find Qt -find_package(Qt5Core REQUIRED) - -# Include Qt headers. -include_directories(${Qt5Base_INCLUDE_DIRS}) -include_directories(${Qt5Network_INCLUDE_DIRS}) - -SET(LIBSETTINGS_HEADERS -include/libsettings_config.h - -include/inifile.h - -include/settingsobject.h -include/setting.h -include/overridesetting.h - -include/basicsettingsobject.h -include/inisettingsobject.h - -include/keyring.h -) - -SET(LIBSETTINGS_HEADERS_PRIVATE -src/stubkeyring.h -) - -SET(LIBSETTINGS_SOURCES -src/inifile.cpp - -src/settingsobject.cpp -src/setting.cpp -src/overridesetting.cpp - -src/basicsettingsobject.cpp -src/inisettingsobject.cpp - -src/keyring.cpp -src/stubkeyring.cpp -) - -# Set the include dir path. -SET(LIBSETTINGS_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE) -include_directories(${LIBSETTINGS_INCLUDE_DIR}) - -add_definitions(-DLIBSETTINGS_LIBRARY) - -add_library(libSettings SHARED ${LIBSETTINGS_SOURCES} ${LIBSETTINGS_HEADERS} ${LIBSETTINGS_HEADERS_PRIVATE}) -qt5_use_modules(libSettings Core) -target_link_libraries(libSettings) diff --git a/libsettings/include/basicsettingsobject.h b/libsettings/include/basicsettingsobject.h deleted file mode 100644 index b7e5851d..00000000 --- a/libsettings/include/basicsettingsobject.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef BASICSETTINGSOBJECT_H -#define BASICSETTINGSOBJECT_H - -#include -#include - -#include "settingsobject.h" - -#include "libsettings_config.h" - -/*! - * \brief A settings object that stores its settings in a QSettings object. - */ -class LIBSETTINGS_EXPORT BasicSettingsObject : public SettingsObject -{ - Q_OBJECT -public: - explicit BasicSettingsObject(QObject *parent = 0); - -protected slots: - virtual void changeSetting(const Setting &setting, QVariant value); - -protected: - virtual QVariant retrieveValue(const Setting &setting); - - QSettings config; -}; - -#endif // BASICSETTINGSOBJECT_H diff --git a/libsettings/include/inifile.h b/libsettings/include/inifile.h deleted file mode 100644 index 94467832..00000000 --- a/libsettings/include/inifile.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INIFILE_H -#define INIFILE_H - -#include -#include -#include - -#include "libsettings_config.h" - -// Sectionless INI parser (for instance config files) -class LIBSETTINGS_EXPORT INIFile : public QMap -{ -public: - explicit INIFile(); - - bool loadFile(QString fileName); - bool saveFile(QString fileName); - - QVariant get(QString key, QVariant def) const; - void set(QString key, QVariant val); -}; - -#endif // INIFILE_H diff --git a/libsettings/include/inisettingsobject.h b/libsettings/include/inisettingsobject.h deleted file mode 100644 index 03d6fe05..00000000 --- a/libsettings/include/inisettingsobject.h +++ /dev/null @@ -1,60 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INISETTINGSOBJECT_H -#define INISETTINGSOBJECT_H - -#include - -#include "inifile.h" - -#include "settingsobject.h" - -#include "libutil_config.h" - -/*! - * \brief A settings object that stores its settings in an INIFile. - */ -class LIBSETTINGS_EXPORT INISettingsObject : public SettingsObject -{ - Q_OBJECT -public: - explicit INISettingsObject(const QString &path, QObject *parent = 0); - - /*! - * \brief Gets the path to the INI file. - * \return The path to the INI file. - */ - virtual QString filePath() const { return m_filePath; } - - /*! - * \brief Sets the path to the INI file and reloads it. - * \param filePath The INI file's new path. - */ - virtual void setFilePath(const QString &filePath); - -protected slots: - virtual void changeSetting(const Setting &setting, QVariant value); - virtual void resetSetting ( const Setting& setting ); - -protected: - virtual QVariant retrieveValue(const Setting &setting); - - INIFile m_ini; - - QString m_filePath; -}; - -#endif // INISETTINGSOBJECT_H diff --git a/libsettings/include/keyring.h b/libsettings/include/keyring.h deleted file mode 100644 index 299b14b0..00000000 --- a/libsettings/include/keyring.h +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef KEYRING_H -#define KEYRING_H - -#include - -#include "libsettings_config.h" - -/** - * @file libsettings/include/keyring.h - * Access to System Keyrings - */ - -/** - * @brief The Keyring class - * the System Keyring/Keychain/Wallet/Vault/etc - */ -class LIBSETTINGS_EXPORT Keyring -{ -public: - /** - * @brief the System Keyring instance - * @return the Keyring instance - */ - static Keyring *instance(); - - /** - * @brief store a password in the Keyring - * @param service the service name - * @param username the account name - * @param password the password to store - * @return success - */ - virtual bool storePassword(QString service, QString username, QString password) = 0; - - /** - * @brief get a password from the Keyring - * @param service the service name - * @param username the account name - * @return the password (success=!isNull()) - */ - virtual QString getPassword(QString service, QString username) = 0; - - /** - * @brief lookup a password - * @param service the service name - * @param username the account name - * @return wether the password is available - */ - virtual bool hasPassword(QString service, QString username) = 0; - - /** - * @brief get a list of all stored accounts. - * @param service the service name - * @return - */ - virtual QStringList getStoredAccounts(QString service) = 0; - - /** - * @brief Remove the specified account from storage - * @param service the service name - * @param username the account name - * @return - */ - virtual void removeStoredAccount(QString service, QString username) = 0; - -protected: - /// fall back to StubKeyring if false - virtual bool isValid() { return false; } - -private: - static Keyring *m_instance; - static void destroy(); -}; - -#endif // KEYRING_H diff --git a/libsettings/include/libsettings_config.h b/libsettings/include/libsettings_config.h deleted file mode 100644 index dc8e6228..00000000 --- a/libsettings/include/libsettings_config.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LIBINSTANCE_CONFIG_H -#define LIBINSTANCE_CONFIG_H - -#include - -#ifdef LIBSETTINGS_LIBRARY -# define LIBSETTINGS_EXPORT Q_DECL_EXPORT -#else -# define LIBSETTINGS_EXPORT Q_DECL_IMPORT -#endif - -#endif // LIBINSTANCE_CONFIG_H diff --git a/libsettings/include/overridesetting.h b/libsettings/include/overridesetting.h deleted file mode 100644 index 58bb6d40..00000000 --- a/libsettings/include/overridesetting.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef OVERRIDESETTING_H -#define OVERRIDESETTING_H - -#include - -#include "setting.h" - -#include "libsettings_config.h" - -/*! - * \brief A setting that 'overrides another.' - * This means that the setting's default value will be the value of another setting. - * The other setting can be (and usually is) a part of a different SettingsObject - * than this one. - */ -class LIBSETTINGS_EXPORT OverrideSetting : public Setting -{ - Q_OBJECT -public: - explicit OverrideSetting(const QString &name, Setting *other, QObject *parent = 0); - - virtual QVariant defValue() const; - -protected: - Setting *m_other; -}; - -#endif // OVERRIDESETTING_H diff --git a/libsettings/include/setting.h b/libsettings/include/setting.h deleted file mode 100644 index a161ab50..00000000 --- a/libsettings/include/setting.h +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SETTING_H -#define SETTING_H - -#include -#include - -#include "libsettings_config.h" - -class SettingsObject; - -/*! - * - */ -class LIBSETTINGS_EXPORT Setting : public QObject -{ - Q_OBJECT -public: - /*! - * \brief Constructs a new Setting object with the given parent. - * \param parent The Setting's parent object. - */ - explicit Setting(QString id, QVariant defVal = QVariant(), QObject *parent = 0); - - /*! - * \brief Gets this setting's ID. - * This is used to refer to the setting within the application. - * \warning Changing the ID while the setting is registered with a SettingsObject results in undefined behavior. - * \return The ID of the setting. - */ - virtual QString id() const { return m_id; } - - /*! - * \brief Gets this setting's config file key. - * This is used to store the setting's value in the config file. It is usually - * the same as the setting's ID, but it can be different. - * \return The setting's config file key. - */ - virtual QString configKey() const { return id(); } - - /*! - * \brief Gets this setting's value as a QVariant. - * This is done by calling the SettingsObject's retrieveValue() function. - * If this Setting doesn't have a SettingsObject, this returns an invalid QVariant. - * \return QVariant containing this setting's value. - * \sa value() - */ - virtual QVariant get() const; - - /*! - * \brief Gets this setting's actual value (I.E. not as a QVariant). - * This function is just shorthand for get().value() - * \return The setting's actual value. - */ - template - inline T value() const { return get().value(); } - - - /*! - * \brief Gets this setting's default value. - * \return The default value of this setting. - */ - virtual QVariant defValue() const; - -signals: - /*! - * \brief Signal emitted when this Setting object's value changes. - * \param setting A reference to the Setting that changed. - * \param value This Setting object's new value. - */ - void settingChanged(const Setting &setting, QVariant value); - - /*! - * \brief Signal emitted when this Setting object's value resets to default. - * \param setting A reference to the Setting that changed. - */ - void settingReset(const Setting &setting); - -public slots: - /*! - * \brief Changes the setting's value. - * This is done by emitting the settingChanged() signal which will then be - * handled by the SettingsObject object and cause the setting to change. - * \param value The new value. - */ - virtual void set(QVariant value); - - /*! - * \brief Reset the setting to default - * This is done by emitting the settingReset() signal which will then be - * handled by the SettingsObject object and cause the setting to change. - * \param value The new value. - */ - virtual void reset(); -protected: - QString m_id; - QVariant m_defVal; -}; - -#endif // SETTING_H diff --git a/libsettings/include/settingsobject.h b/libsettings/include/settingsobject.h deleted file mode 100644 index a2f03699..00000000 --- a/libsettings/include/settingsobject.h +++ /dev/null @@ -1,192 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SETTINGSOBJECT_H -#define SETTINGSOBJECT_H - -#include -#include - -#include "libsettings_config.h" - -class Setting; - -/*! - * \brief The SettingsObject handles communicating settings between the application and a settings file. - * The class keeps a list of Setting objects. Each Setting object represents one - * of the application's settings. These Setting objects are registered with - * a SettingsObject and can be managed similarly to the way a list works. - * - * \author Andrew Okin - * \date 2/22/2013 - * - * \sa Setting - */ -class LIBSETTINGS_EXPORT SettingsObject : public QObject -{ - Q_OBJECT -public: - explicit SettingsObject(QObject *parent = 0); - - /*! - * \brief Registers the given setting with this SettingsObject and connects the necessary signals. - * This will fail if there is already a setting with the same ID as - * the one that is being registered. - * \note Registering a setting object causes the SettingsObject to take ownership - * of the object. This means that setting's parent will be set to the object - * it was registered with. Because the object it was registered with has taken - * ownership, it becomes responsible for managing that setting object's memory. - * \warning Do \b not delete the setting after registering it. - * \param setting A pointer to the setting that will be registered. - * \return True if successful. False if registry failed. - */ - virtual bool registerSetting(Setting *setting); - - /*! - * \brief Unregisters the given setting from this SettingsObject and disconnects its signals. - * \note This does not delete the setting. Furthermore, when the setting is - * unregistered, the SettingsObject drops ownership of the setting. This means - * that if you unregister a setting, its parent is set to null and you become - * responsible for freeing its memory. - * \param setting The setting to unregister. - */ - virtual void unregisterSetting(Setting *setting); - - - /*! - * \brief Gets the setting with the given ID. - * \param id The ID of the setting to get. - * \return A pointer to the setting with the given ID. - * Returns null if there is no setting with the given ID. - * \sa operator []() - */ - virtual Setting *getSetting(const QString &id) const; - - /*! - * \brief Same as getSetting() - * \param id The ID of the setting to get. - * \return A pointer to the setting with the given ID. - * \sa getSetting() - */ - inline Setting *operator [](const QString &id) { return getSetting(id); } - - - /*! - * \brief Gets the value of the setting with the given ID. - * \param id The ID of the setting to get. - * \return The setting's value as a QVariant. - * If no setting with the given ID exists, returns an invalid QVariant. - */ - virtual QVariant get(const QString &id) const; - - /*! - * \brief Sets the value of the setting with the given ID. - * If no setting with the given ID exists, returns false and logs to qDebug - * \param id The ID of the setting to change. - * \param value The new value of the setting. - * \return True if successful, false if it failed. - */ - virtual bool set(const QString &id, QVariant value); - - /*! - * \brief Reverts the setting with the given ID to default. - * \param id The ID of the setting to reset. - */ - virtual void reset(const QString &id) const; - - /*! - * \brief Gets a QList with pointers to all of the registered settings. - * The order of the entries in the list is undefined. - * \return A QList with pointers to all registered settings. - */ - virtual QList getSettings(); - - /*! - * \brief Checks if this SettingsObject contains a setting with the given ID. - * \param id The ID to check for. - * \return True if the SettingsObject has a setting with the given ID. - */ - virtual bool contains(const QString &id); - -signals: - /*! - * \brief Signal emitted when one of this SettingsObject object's settings changes. - * This is usually just connected directly to each Setting object's - * settingChanged() signals. - * \param setting A reference to the Setting object that changed. - * \param value The Setting object's new value. - */ - void settingChanged(const Setting &setting, QVariant value); - - /*! - * \brief Signal emitted when one of this SettingsObject object's settings resets. - * This is usually just connected directly to each Setting object's - * settingReset() signals. - * \param setting A reference to the Setting object that changed. - */ - void settingReset(const Setting &setting); - -protected slots: - /*! - * \brief Changes a setting. - * This slot is usually connected to each Setting object's - * settingChanged() signal. The signal is emitted, causing this slot - * to update the setting's value in the config file. - * \param setting A reference to the Setting object that changed. - * \param value The setting's new value. - */ - virtual void changeSetting(const Setting &setting, QVariant value) = 0; - - /*! - * \brief Resets a setting. - * This slot is usually connected to each Setting object's - * settingReset() signal. The signal is emitted, causing this slot - * to update the setting's value in the config file. - * \param setting A reference to the Setting object that changed. - */ - virtual void resetSetting(const Setting &setting) = 0; - -protected: - /*! - * \brief Connects the necessary signals to the given Setting. - * \param setting The setting to connect. - */ - virtual void connectSignals(const Setting &setting); - - /*! - * \brief Disconnects signals from the given Setting. - * \param setting The setting to disconnect. - */ - virtual void disconnectSignals(const Setting &setting); - - /*! - * \brief Function used by Setting objects to get their values from the SettingsObject. - * \param setting The - * \return - */ - virtual QVariant retrieveValue(const Setting &setting) = 0; - - friend class Setting; - -private: - QMap m_settings; -}; - -/*! - * \brief A global settings object. - */ -LIBSETTINGS_EXPORT extern SettingsObject *globalSettings; - -#endif // SETTINGSOBJECT_H diff --git a/libsettings/src/basicsettingsobject.cpp b/libsettings/src/basicsettingsobject.cpp deleted file mode 100644 index 484928c8..00000000 --- a/libsettings/src/basicsettingsobject.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/basicsettingsobject.h" -#include "include/setting.h" - -BasicSettingsObject::BasicSettingsObject(QObject *parent) : - SettingsObject(parent) -{ - -} - -void BasicSettingsObject::changeSetting(const Setting &setting, QVariant value) -{ - if (contains(setting.id())) - { - if(value.isValid()) - config.setValue(setting.configKey(), value); - else - config.remove(setting.configKey()); - } -} - -QVariant BasicSettingsObject::retrieveValue(const Setting &setting) -{ - if (contains(setting.id())) - { - return config.value(setting.configKey()); - } - else - { - return QVariant(); - } -} diff --git a/libsettings/src/inifile.cpp b/libsettings/src/inifile.cpp deleted file mode 100644 index 43545a4a..00000000 --- a/libsettings/src/inifile.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/inifile.h" - -#include -#include -#include - -INIFile::INIFile() -{ - -} - -bool INIFile::saveFile(QString fileName) -{ - // TODO Handle errors. - QFile file(fileName); - file.open(QIODevice::WriteOnly); - QTextStream out(&file); - - for (Iterator iter = begin(); iter != end(); iter++) - { - out << iter.key() << "=" << iter.value().toString() << "\n"; - } - - return true; -} - -bool INIFile::loadFile(QString fileName) -{ - // TODO Handle errors. - QFile file(fileName); - file.open(QIODevice::ReadOnly); - QTextStream in(&file); - - QStringList lines = in.readAll().split('\n'); - for (int i = 0; i < lines.count(); i++) - { - QString & lineRaw = lines[i]; - // Ignore comments. - QString line = lineRaw.left(lineRaw.indexOf('#')).trimmed(); - - int eqPos = line.indexOf('='); - if(eqPos == -1) - continue; - QString key = line.left(eqPos).trimmed(); - QString valueStr = line.right(line.length() - eqPos - 1).trimmed(); - - QVariant value(valueStr); - /* - QString dbg = key; - dbg += " = "; - dbg += valueStr; - qDebug(dbg.toLocal8Bit()); - */ - this->operator [](key) = value; - } - - return true; -} - -QVariant INIFile::get(QString key, QVariant def) const -{ - if (!this->contains(key)) - return def; - else - return this->operator [](key); -} - -void INIFile::set(QString key, QVariant val) -{ - this->operator [](key) = val; -} diff --git a/libsettings/src/inisettingsobject.cpp b/libsettings/src/inisettingsobject.cpp deleted file mode 100644 index 854421b6..00000000 --- a/libsettings/src/inisettingsobject.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/inisettingsobject.h" -#include "include/setting.h" - -INISettingsObject::INISettingsObject(const QString &path, QObject *parent) : - SettingsObject(parent) -{ - m_filePath = path; - m_ini.loadFile(path); -} - -void INISettingsObject::setFilePath(const QString &filePath) -{ - m_filePath = filePath; -} - -void INISettingsObject::changeSetting(const Setting &setting, QVariant value) -{ - if (contains(setting.id())) - { - if(value.isValid()) - m_ini.set(setting.configKey(), value); - else - m_ini.remove(setting.configKey()); - m_ini.saveFile(m_filePath); - } -} - -void INISettingsObject::resetSetting ( const Setting& setting ) -{ - if (contains(setting.id())) - { - m_ini.remove(setting.configKey()); - m_ini.saveFile(m_filePath); - } -} - -QVariant INISettingsObject::retrieveValue(const Setting &setting) -{ - if (contains(setting.id())) - { - return m_ini.get(setting.configKey(), QVariant()); - } - else - { - return QVariant(); - } -} diff --git a/libsettings/src/keyring.cpp b/libsettings/src/keyring.cpp deleted file mode 100644 index 9eaba684..00000000 --- a/libsettings/src/keyring.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/keyring.h" - -#include "osutils.h" - -#include "stubkeyring.h" - -// system specific keyrings -/*#if defined(OSX) -class OSXKeychain; -#define KEYRING OSXKeychain -#elif defined(LINUX) -class XDGKeyring; -#define KEYRING XDGKeyring -#elif defined(WINDOWS) -class Win32Keystore; -#define KEYRING Win32Keystore -#else -#pragma message Keyrings are not supported on your os. Falling back to the insecure StubKeyring -#endif*/ - -Keyring *Keyring::instance() -{ - if (m_instance == nullptr) - { -#ifdef KEYRING - m_instance = new KEYRING(); - if (!m_instance->isValid()) - { - qWarning("Could not create SystemKeyring! falling back to StubKeyring."); - m_instance = new StubKeyring(); - } -#else - qWarning("Keyrings are not supported on your OS. Fallback StubKeyring is insecure!"); - m_instance = new StubKeyring(); -#endif - atexit(Keyring::destroy); - } - return m_instance; -} - -void Keyring::destroy() -{ - delete m_instance; -} - -Keyring *Keyring::m_instance; diff --git a/libsettings/src/overridesetting.cpp b/libsettings/src/overridesetting.cpp deleted file mode 100644 index eafb298f..00000000 --- a/libsettings/src/overridesetting.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/overridesetting.h" - -OverrideSetting::OverrideSetting(const QString &name, Setting *other, QObject *parent) : - Setting(name, QVariant(), parent) -{ - m_other = other; -} - -QVariant OverrideSetting::defValue() const -{ - if (m_other) - return m_other->get(); - else - return QVariant(); -} diff --git a/libsettings/src/setting.cpp b/libsettings/src/setting.cpp deleted file mode 100644 index 8e60af06..00000000 --- a/libsettings/src/setting.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/setting.h" -#include "include/settingsobject.h" - -Setting::Setting(QString id, QVariant defVal, QObject *parent) : - QObject(parent), m_id(id), m_defVal(defVal) -{ - -} - -QVariant Setting::get() const -{ - SettingsObject *sbase = qobject_cast(parent()); - if (!sbase) - { - return defValue(); - } - else - { - QVariant test = sbase->retrieveValue(*this); - if(!test.isValid()) - return defValue(); - return test; - } -} - -QVariant Setting::defValue() const -{ - return m_defVal; -} - -void Setting::set(QVariant value) -{ - emit settingChanged(*this, value); -} - -void Setting::reset() -{ - emit settingReset(*this); -} diff --git a/libsettings/src/settingsobject.cpp b/libsettings/src/settingsobject.cpp deleted file mode 100644 index bf7b8825..00000000 --- a/libsettings/src/settingsobject.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/settingsobject.h" -#include "include/setting.h" - -#include - -SettingsObject *globalSettings; - -SettingsObject::SettingsObject(QObject *parent) : - QObject(parent) -{ - -} - -bool SettingsObject::registerSetting(Setting *setting) -{ - // Check if setting is null or we already have a setting with the same ID. - if (!setting) - { - qDebug(QString("Failed to register setting. Setting is null."). - arg(setting->id()).toUtf8()); - return false; // Fail - } - - if (contains(setting->id())) - { - qDebug(QString("Failed to register setting %1. ID already exists."). - arg(setting->id()).toUtf8()); - return false; // Fail - } - - m_settings.insert(setting->id(), setting); - setting->setParent(this); // Take ownership. - - // Connect signals. - connectSignals(*setting); - - // qDebug(QString("Registered setting %1.").arg(setting->id()).toUtf8()); - return true; -} - -void SettingsObject::unregisterSetting(Setting *setting) -{ - if (!setting || !m_settings.contains(setting->id())) - return; // We can't unregister something that's not registered. - - m_settings.remove(setting->id()); - - // Disconnect signals. - disconnectSignals(*setting); - - setting->setParent(NULL); // Drop ownership. -} - - -Setting *SettingsObject::getSetting(const QString &id) const -{ - // Make sure there is a setting with the given ID. - if (!m_settings.contains(id)) - return NULL; - - return m_settings[id]; -} - -QVariant SettingsObject::get(const QString &id) const -{ - Setting *setting = getSetting(id); - return (setting ? setting->get() : QVariant()); -} - -bool SettingsObject::set(const QString &id, QVariant value) -{ - Setting *setting = getSetting(id); - if (!setting) - { - qDebug(QString("Error changing setting %1. Setting doesn't exist."). - arg(id).toUtf8()); - return false; - } - else - { - setting->set(value); - return true; - } -} - -void SettingsObject::reset(const QString &id) const -{ - Setting *setting = getSetting(id); - if(setting) - setting->reset(); -} - - -QList SettingsObject::getSettings() -{ - return m_settings.values(); -} - -bool SettingsObject::contains(const QString &id) -{ - return m_settings.contains(id); -} - - -void SettingsObject::connectSignals(const Setting &setting) -{ - connect(&setting, SIGNAL(settingChanged(const Setting &, QVariant)), - SLOT(changeSetting(const Setting &, QVariant))); - connect(&setting, SIGNAL(settingChanged(const Setting &, QVariant)), - SIGNAL(settingChanged(const Setting &, QVariant))); - - connect(&setting, SIGNAL(settingReset(Setting)), - SLOT(resetSetting(const Setting &))); - connect(&setting, SIGNAL(settingReset(Setting)), - SIGNAL(settingReset(const Setting &))); -} - -void SettingsObject::disconnectSignals(const Setting &setting) -{ - setting.disconnect(SIGNAL(settingChanged(const Setting &, QVariant)), - this, SLOT(changeSetting(const Setting &, QVariant))); - setting.disconnect(SIGNAL(settingChanged(const Setting &, QVariant)), - this, SIGNAL(settingChanged(const Setting &, QVariant))); - - setting.disconnect(SIGNAL(settingReset(const Setting &, QVariant)), - this, SLOT(resetSetting(const Setting &, QVariant))); - setting.disconnect(SIGNAL(settingReset(const Setting &, QVariant)), - this, SIGNAL(settingReset(const Setting &, QVariant))); -} diff --git a/libsettings/src/stubkeyring.cpp b/libsettings/src/stubkeyring.cpp deleted file mode 100644 index cf814d2f..00000000 --- a/libsettings/src/stubkeyring.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "stubkeyring.h" - -#include - -// Scrambling -// this is NOT SAFE, but it's not plain either. -int scrambler = 0x9586309; - -QString scramble(QString in_) -{ - QByteArray in = in_.toUtf8(); - QByteArray out; - for (int i = 0; i - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef STUBKEYRING_H -#define STUBKEYRING_H - -#include "include/keyring.h" - -#include - -class StubKeyring : public Keyring -{ -public: - virtual bool storePassword(QString service, QString username, QString password); - virtual QString getPassword(QString service, QString username); - virtual bool hasPassword(QString service, QString username); - virtual QStringList getStoredAccounts(QString service); - virtual void removeStoredAccount(QString service, QString username); -private: - friend class Keyring; - explicit StubKeyring(); - virtual bool isValid() { return true; } - - QSettings m_settings; -}; - -#endif // STUBKEYRING_H diff --git a/libutil/CMakeLists.txt b/libutil/CMakeLists.txt deleted file mode 100644 index 7affb5ea..00000000 --- a/libutil/CMakeLists.txt +++ /dev/null @@ -1,51 +0,0 @@ -project(libUtil) - -######## Set compiler flags ######## -IF(APPLE) - # assume clang 4.1.0+, add C++0x/C++11 stuff - message(STATUS "Using APPLE CMAKE_CXX_FLAGS") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++") -ELSEIF(UNIX) - # assume GCC, add C++0x/C++11 stuff - MESSAGE(STATUS "Using UNIX CMAKE_CXX_FLAGS") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") -ELSEIF(MINGW) - MESSAGE(STATUS "Using MINGW CMAKE_CXX_FLAGS") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") -ENDIF() - - -# Find Qt -find_package(Qt5Core REQUIRED) - -# Include Qt headers. -include_directories(${Qt5Base_INCLUDE_DIRS}) -# include_directories(${Qt5Network_INCLUDE_DIRS}) - -SET(LIBUTIL_HEADERS -include/libutil_config.h - -include/apputils.h - -include/pathutils.h -include/osutils.h -include/userutils.h -include/cmdutils.h -) - -SET(LIBUTIL_SOURCES -src/pathutils.cpp -src/osutils.cpp -src/userutils.cpp -src/cmdutils.cpp -) - -# Set the include dir path. -SET(LIBUTIL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE) - -add_definitions(-DLIBUTIL_LIBRARY) - -add_library(libUtil SHARED ${LIBUTIL_SOURCES} ${LIBUTIL_HEADERS}) -# qt5_use_modules(libUtil Core Network) -qt5_use_modules(libUtil Core) -target_link_libraries(libUtil) diff --git a/libutil/include/apputils.h b/libutil/include/apputils.h deleted file mode 100644 index a64adc50..00000000 --- a/libutil/include/apputils.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APPUTILS_H -#define APPUTILS_H - -#define STR_VAL(val) # val - -#endif // APPUTILS_H diff --git a/libutil/include/cmdutils.h b/libutil/include/cmdutils.h deleted file mode 100644 index a6379397..00000000 --- a/libutil/include/cmdutils.h +++ /dev/null @@ -1,259 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CMDUTILS_H -#define CMDUTILS_H - -#include - -#include -#include -#include -#include - -#include "libutil_config.h" - -/** - * @file libutil/include/cmdutils.h - * @brief commandline parsing and processing utilities - */ - -namespace Util { -namespace Commandline { - -/** - * @brief split a string into argv items like a shell would do - * @param args the argument string - * @return a QStringList containing all arguments - */ -LIBUTIL_EXPORT QStringList splitArgs(QString args); - -/** - * @brief The FlagStyle enum - * Specifies how flags are decorated - */ - -namespace FlagStyle -{ -enum LIBUTIL_EXPORT Enum -{ - GNU, /**< --option and -o (GNU Style) */ - Unix, /**< -option and -o (Unix Style) */ - Windows, /**< /option and /o (Windows Style) */ -#ifdef Q_OS_WIN32 - Default = Windows -#else - Default = GNU -#endif -}; -} - -/** - * @brief The ArgumentStyle enum - */ -namespace ArgumentStyle -{ -enum LIBUTIL_EXPORT Enum -{ - Space, /**< --option=value */ - Equals, /**< --option value */ - SpaceAndEquals, /**< --option[= ]value */ -#ifdef Q_OS_WIN32 - Default = Equals -#else - Default = SpaceAndEquals -#endif -}; -} - -/** - * @brief The ParsingError class - */ -class LIBUTIL_EXPORT ParsingError : public std::exception -{ -public: - ParsingError(const QString &what); - ParsingError(const ParsingError &e); - ~ParsingError() throw() {} - const char *what() const throw(); - QString qwhat() const; -private: - QString m_what; -}; - -/** - * @brief The Parser class - */ -class LIBUTIL_EXPORT Parser -{ -public: - /** - * @brief Parser constructor - * @param flagStyle the FlagStyle to use in this Parser - * @param argStyle the ArgumentStyle to use in this Parser - */ - Parser(FlagStyle::Enum flagStyle = FlagStyle::Default, - ArgumentStyle::Enum argStyle = ArgumentStyle::Default); - - /** - * @brief set the flag style - * @param style - */ - void setFlagStyle(FlagStyle::Enum style); - - /** - * @brief get the flag style - * @return - */ - FlagStyle::Enum flagStyle(); - - /** - * @brief set the argument style - * @param style - */ - void setArgumentStyle(ArgumentStyle::Enum style); - - /** - * @brief get the argument style - * @return - */ - ArgumentStyle::Enum argumentStyle(); - - /** - * @brief define a boolean switch - * @param name the parameter name - * @param def the default value - */ - void addSwitch(QString name, bool def = false); - - /** - * @brief define an option that takes an additional argument - * @param name the parameter name - * @param def the default value - */ - void addOption(QString name, QVariant def = QVariant()); - - /** - * @brief define a positional argument - * @param name the parameter name - * @param required wether this argument is required - * @param def the default value - */ - void addArgument(QString name, bool required = true, QVariant def = QVariant()); - - /** - * @brief adds a flag to an existing parameter - * @param name the (existing) parameter name - * @param flag the flag character - * @see addSwitch addArgument addOption - * Note: any one parameter can only have one flag - */ - void addShortOpt(QString name, QChar flag); - - /** - * @brief adds documentation to a Parameter - * @param name the parameter name - * @param metavar a string to be displayed as placeholder for the value - * @param doc a QString containing the documentation - * Note: on positional arguments, metavar replaces the name as displayed. - * on options , metavar replaces the value placeholder - */ - void addDocumentation(QString name, QString doc, QString metavar = QString()); - - /** - * @brief generate a help message - * @param progName the program name to use in the help message - * @param helpIndent how much the parameter documentation should be indented - * @param flagsInUsage whether we should use flags instead of options in the usage - * @return a help message - */ - QString compileHelp(QString progName, int helpIndent = 22, bool flagsInUsage = true); - - /** - * @brief generate a short usage message - * @param progName the program name to use in the usage message - * @param useFlags whether we should use flags instead of options - * @return a usage message - */ - QString compileUsage(QString progName, bool useFlags = true); - - /** - * @brief parse - * @param argv a QStringList containing the program ARGV - * @return a QHash mapping argument names to their values - */ - QHash parse(QStringList argv); - - /** - * @brief clear all definitions - */ - void clear(); - - ~Parser(); - -private: - FlagStyle::Enum m_flagStyle; - ArgumentStyle::Enum m_argStyle; - - enum OptionType - { - otSwitch, - otOption - }; - - // Important: the common part MUST BE COMMON ON ALL THREE structs - struct CommonDef { - QString name; - QString doc; - QString metavar; - QVariant def; - }; - - struct OptionDef { - // common - QString name; - QString doc; - QString metavar; - QVariant def; - // option - OptionType type; - QChar flag; - }; - - struct PositionalDef { - // common - QString name; - QString doc; - QString metavar; - QVariant def; - // positional - bool required; - }; - - QHash m_options; - QHash m_flags; - QHash m_params; - QList m_positionals; - QList m_optionList; - - void getPrefix(QString &opt, QString &flag); -}; - -} -} - -#endif // CMDUTILS_H diff --git a/libutil/include/libutil_config.h b/libutil/include/libutil_config.h deleted file mode 100644 index 4bf111e6..00000000 --- a/libutil/include/libutil_config.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LIBUTIL_CONFIG_H -#define LIBUTIL_CONFIG_H - -#include - -#ifdef LIBUTIL_LIBRARY -# define LIBUTIL_EXPORT Q_DECL_EXPORT -#else -# define LIBUTIL_EXPORT Q_DECL_IMPORT -#endif - -#endif // LIBUTIL_CONFIG_H diff --git a/libutil/include/osutils.h b/libutil/include/osutils.h deleted file mode 100644 index c5d4bb61..00000000 --- a/libutil/include/osutils.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef OSUTILS_H -#define OSUTILS_H - -#include - -#if defined _WIN32 | defined _WIN64 -#define WINDOWS 1 -#elif __APPLE__ & __MACH__ -#define OSX 1 -#elif __linux__ -#define LINUX 1 -#endif - -#endif // OSUTILS_H diff --git a/libutil/include/pathutils.h b/libutil/include/pathutils.h deleted file mode 100644 index d4f41da3..00000000 --- a/libutil/include/pathutils.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef PATHUTILS_H -#define PATHUTILS_H - -#include - -#include "libutil_config.h" - -LIBUTIL_EXPORT QString PathCombine(QString path1, QString path2); -LIBUTIL_EXPORT QString PathCombine(QString path1, QString path2, QString path3); - -LIBUTIL_EXPORT QString AbsolutePath(QString path); - -LIBUTIL_EXPORT QString RemoveInvalidFilenameChars(QString string, QChar replaceWith = '-'); - -LIBUTIL_EXPORT QString DirNameFromString(QString string, QString inDir = "."); - -LIBUTIL_EXPORT bool ensurePathExists(QString filenamepath); - -LIBUTIL_EXPORT bool copyPath(QString src, QString dst); - - -#endif // PATHUTILS_H diff --git a/libutil/include/siglist.h b/libutil/include/siglist.h deleted file mode 100644 index 24b1a889..00000000 --- a/libutil/include/siglist.h +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGLIST_H -#define SIGLIST_H - -#include -#include - -// A QList that allows emitting signals when the list changes. -// Since QObject doesn't support templates, to use this class with a -// certain type, you should create a class deriving from SigList and then -// call the DEFINE_SIGLIST_SIGNALS(T) and SETUP_SIGLIST_SIGNALS(T) macros. -template -class SigList : public QList -{ -public: - explicit SigList() : QList() {} - - virtual void append(const T &value); - virtual void append(const QList &other); - - virtual void clear(); - - virtual void erase(typename QList::iterator pos); - virtual void erase(typename QList::iterator first, typename QList::iterator last); - - virtual void insert(int i, const T &t); - virtual void insert(typename QList::iterator before, const T &t); - - virtual void move(int from, int to); - - virtual void pop_back() { takeLast(); } - virtual void pop_front() { takeFirst(); } - - virtual void push_back(const T &t) { append(t); } - virtual void push_front(const T &t) { prepend(t); } - - virtual void prepend(const T &t); - - virtual int removeAll(const T &t); - virtual bool removeOne(const T &t); - - virtual void removeAt(int i) { takeAt(i); } - virtual void removeFirst() { takeFirst(); } - virtual void removeLast() { takeLast(); } - - virtual void swap(QList &other); - virtual void swap(int i, int j); - - virtual T takeAt(int i); - virtual T takeFirst(); - virtual T takeLast(); - - virtual QList &operator +=(const QList &other) { append(other); return *this; } - virtual QList &operator +=(const T &value) { append(value); return *this; } - virtual QList &operator <<(const QList &other) { append(other); return *this; } - virtual QList &operator <<(const T &value) { append(value); return *this; } - - virtual QList &operator =(const QList &other); - -protected: - // Signal emitted after an item is added to the list. - // Contains a reference to item and the item's new index. - virtual void onItemAdded(const T &item, int index) = 0; - - // Signal emitted after multiple items are added to the list at once. - // The items parameter is a const reference to a QList of the items that - // were added. - // The firstIndex parameter is the new index of the first item added. - virtual void onItemsAdded(const QList &items, int firstIndex) = 0; - - // Signal emitted after an item is removed to the list. - // Contains a reference to the item and the item's old index. - virtual void onItemRemoved(const T &item, int index) = 0; - - // Signal emitted after multiple items are removed from the list at once. - // The items parameter is a const reference to a QList of the items that - // were added. - // The firstIndex parameter is the new index of the first item added. - virtual void onItemsRemoved(const QList &items, int firstIndex) = 0; - - // Signal emitted after an item is moved to another index. - // Contains the item, the old index, and the new index. - virtual void onItemMoved(const T &item, int oldIndex, int newIndex) = 0; - - // Signal emitted after an operation that changes the whole list occurs. - // This signal should be treated as if all data in the entire list was cleared - // and new data added in its place. - virtual void onInvalidated() = 0; -}; - -// Defines the signals for a SigList -#define DEFINE_SIGLIST_SIGNALS(TYPE) \ - Q_SIGNAL void itemAdded(TYPE const &item, int index);\ - Q_SIGNAL void itemsAdded(const QList &items, int firstIndex);\ - Q_SIGNAL void itemRemoved(TYPE const &item, int index);\ - Q_SIGNAL void itemsRemoved(const QList &items, int firstIndex);\ - Q_SIGNAL void itemMoved(TYPE const &item, int oldIndex, int newIndex);\ - Q_SIGNAL void invalidated(); - -// Overrides the onItem* functions and causes them to emit their corresponding -// signals. -#define SETUP_SIGLIST_SIGNALS(TYPE) \ - virtual void onItemAdded(TYPE const &item, int index)\ - { emit itemAdded(item, index); }\ - virtual void onItemsAdded(const QList &items, int firstIndex)\ - { emit itemsAdded(items, firstIndex); }\ - virtual void onItemRemoved(TYPE const &item, int index)\ - { emit itemRemoved(item, index); }\ - virtual void onItemsRemoved(const QList &items, int firstIndex)\ - { emit itemsRemoved(items, firstIndex); }\ - virtual void onItemMoved(TYPE const &item, int oldIndex, int newIndex)\ - { emit itemMoved(item, oldIndex, newIndex); }\ - virtual void onInvalidated() { emit invalidated(); } - -#endif // SIGLIST_H diff --git a/libutil/include/siglist_impl.h b/libutil/include/siglist_impl.h deleted file mode 100644 index 5cdc632a..00000000 --- a/libutil/include/siglist_impl.h +++ /dev/null @@ -1,156 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "siglist.h" - -template -void SigList::append(const T &value) -{ - QList::append(value); - onItemAdded(value, QList::length() - 1); -} - -template -void SigList::prepend(const T &value) -{ - QList::prepend(value); - onItemAdded(value, 0); -} - -template -void SigList::append(const QList &other) -{ - int index = QList::length(); - QList::append(other); - onItemsAdded(other, index); -} - -template -void SigList::clear() -{ - QList::clear(); - onInvalidated(); -} - -template -void SigList::erase(typename QList::iterator pos) -{ - T value = *pos; - int index = QList::indexOf(*pos); - QList::erase(pos); - onItemRemoved(value, index); -} - -template -void SigList::erase(typename QList::iterator first, typename QList::iterator last) -{ - QList removedValues; - int firstIndex = QList::indexOf(*first); - - for (auto iter = first; iter < last; iter++) - { - removedValues << *iter; - QList::erase(iter); - } - - onItemsRemoved(removedValues, firstIndex); -} - -template -void SigList::insert(int i, const T &t) -{ - QList::insert(i, t); - onItemAdded(t, i); -} - -template -void SigList::insert(typename QList::iterator before, const T &t) -{ - QList::insert(before, t); - onItemAdded(t, QList::indexOf(t)); -} - -template -void SigList::move(int from, int to) -{ - const T &item = QList::at(from); - QList::move(from, to); - onItemMoved(item, from, to); -} - -template -int SigList::removeAll(const T &t) -{ - int retVal = QList::removeAll(t); - onInvalidated(); - return retVal; -} - -template -bool SigList::removeOne(const T &t) -{ - int index = QList::indexOf(t); - if (QList::removeOne(t)) - { - onItemRemoved(t, index); - return true; - } - return false; -} - -template -void SigList::swap(QList &other) -{ - QList::swap(other); - onInvalidated(); -} - -template -void SigList::swap(int i, int j) -{ - const T &item1 = QList::at(i); - const T &item2 = QList::at(j); - QList::swap(i, j); - onItemMoved(item1, i, j); - onItemMoved(item2, j, i); -} - -template -T SigList::takeAt(int i) -{ - T val = QList::takeAt(i); - onItemRemoved(val, i); - return val; -} - -template -T SigList::takeFirst() -{ - return takeAt(0); -} - -template -T SigList::takeLast() -{ - return takeAt(QList::length() - 1); -} - -template -QList &SigList::operator =(const QList &other) -{ - QList::operator =(other); - onInvalidated(); - return *this; -} diff --git a/libutil/include/userutils.h b/libutil/include/userutils.h deleted file mode 100644 index 4f2760b1..00000000 --- a/libutil/include/userutils.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef USERUTILS_H -#define USERUTILS_H - -#include - -#include "libutil_config.h" - -namespace Util -{ -// Get the Directory representing the User's Desktop -LIBUTIL_EXPORT QString getDesktopDir(); - -// Create a shortcut at *location*, pointing to *dest* called with the arguments *args* -// call it *name* and assign it the icon *icon* -// return true if operation succeeded -LIBUTIL_EXPORT bool createShortCut(QString location, QString dest, QStringList args, QString name, QString iconLocation); -} - -#endif // USERUTILS_H diff --git a/libutil/src/cmdutils.cpp b/libutil/src/cmdutils.cpp deleted file mode 100644 index 80ba719d..00000000 --- a/libutil/src/cmdutils.cpp +++ /dev/null @@ -1,484 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/cmdutils.h" - -/** - * @file libutil/src/cmdutils.cpp - */ - -namespace Util { -namespace Commandline { - -// commandline splitter -QStringList splitArgs(QString args) -{ - QStringList argv; - QString current; - bool escape = false; - QChar inquotes; - for (int i=0; itype = otSwitch; - param->name = name; - param->metavar = QString("<%1>").arg(name); - param->def = def; - - m_options[name] = param; - m_params[name] = (CommonDef *)param; - m_optionList.append(param); -} - -void Parser::addOption(QString name, QVariant def) -{ - if (m_params.contains(name)) - throw "Name not unique"; - - OptionDef *param = new OptionDef; - param->type = otOption; - param->name = name; - param->metavar = QString("<%1>").arg(name); - param->def = def; - - m_options[name] = param; - m_params[name] = (CommonDef *)param; - m_optionList.append(param); -} - -void Parser::addArgument(QString name, bool required, QVariant def) -{ - if (m_params.contains(name)) - throw "Name not unique"; - - PositionalDef *param = new PositionalDef; - param->name = name; - param->def = def; - param->required = required; - param->metavar = name; - - m_positionals.append(param); - m_params[name] = (CommonDef *)param; -} - -void Parser::addDocumentation(QString name, QString doc, QString metavar) -{ - if (!m_params.contains(name)) - throw "Name does not exist"; - - CommonDef *param = m_params[name]; - param->doc = doc; - if (!metavar.isNull()) - param->metavar = metavar; -} - -void Parser::addShortOpt(QString name, QChar flag) -{ - if (!m_params.contains(name)) - throw "Name does not exist"; - if (!m_options.contains(name)) - throw "Name is not an Option or Swtich"; - - OptionDef *param = m_options[name]; - m_flags[flag] = param; - param->flag = flag; -} - -// help methods -QString Parser::compileHelp(QString progName, int helpIndent, bool useFlags) -{ - QStringList help; - help << compileUsage(progName, useFlags) << "\r\n"; - - // positionals - if (!m_positionals.isEmpty()) - { - help << "\r\n"; - help << "Positional arguments:\r\n"; - QListIterator it2(m_positionals); - while(it2.hasNext()) - { - PositionalDef *param = it2.next(); - help << " " << param->metavar; - help << " " << QString(helpIndent - param->metavar.length() - 1, ' '); - help << param->doc << "\r\n"; - } - } - - // Options - if (!m_optionList.isEmpty()) - { - help << "\r\n"; - QString optPrefix, flagPrefix; - getPrefix(optPrefix, flagPrefix); - - help << "Options & Switches:\r\n"; - QListIterator it(m_optionList); - while(it.hasNext()) - { - OptionDef *option = it.next(); - help << " "; - int nameLength = optPrefix.length() + option->name.length(); - if (!option->flag.isNull()) - { - nameLength += 3 + flagPrefix.length(); - help << flagPrefix << option->flag << ", "; - } - help << optPrefix << option->name; - if (option->type == otOption) - { - QString arg = QString("%1%2").arg(((m_argStyle == ArgumentStyle::Equals) ? "=" : " "), option->metavar); - nameLength += arg.length(); - help << arg; - } - help << " " << QString(helpIndent - nameLength - 1, ' '); - help << option->doc << "\r\n"; - } - } - - return help.join(""); -} - -QString Parser::compileUsage(QString progName, bool useFlags) -{ - QStringList usage; - usage << "Usage: " << progName; - - QString optPrefix, flagPrefix; - getPrefix(optPrefix, flagPrefix); - - // options - QListIterator it(m_optionList); - while(it.hasNext()) - { - OptionDef *option = it.next(); - usage << " ["; - if (!option->flag.isNull() && useFlags) - usage << flagPrefix << option->flag; - else - usage << optPrefix << option->name; - if (option->type == otOption) - usage << ((m_argStyle == ArgumentStyle::Equals) ? "=" : " ") << option->metavar; - usage << "]"; - } - - // arguments - QListIterator it2(m_positionals); - while(it2.hasNext()) - { - PositionalDef *param = it2.next(); - usage << " " << (param->required ? "<" : "["); - usage << param->metavar; - usage << (param->required ? ">" : "]"); - } - - return usage.join(""); -} - -// parsing -QHash Parser::parse(QStringList argv) -{ - QHash map; - - QStringListIterator it(argv); - QString programName = it.next(); - - QString optionPrefix; - QString flagPrefix; - QListIterator positionals(m_positionals); - QStringList expecting; - - getPrefix(optionPrefix, flagPrefix); - - while (it.hasNext()) - { - QString arg = it.next(); - - if (!expecting.isEmpty()) - // we were expecting an argument - { - QString name = expecting.first(); - - if (map.contains(name)) - throw ParsingError(QString("Option %2%1 was given multiple times").arg(name, optionPrefix)); - - map[name] = QVariant(arg); - - expecting.removeFirst(); - continue; - } - - if (arg.startsWith(optionPrefix)) - // we have an option - { - //qDebug("Found option %s", qPrintable(arg)); - - QString name = arg.mid(optionPrefix.length()); - QString equals; - - if ((m_argStyle == ArgumentStyle::Equals || m_argStyle == ArgumentStyle::SpaceAndEquals) && name.contains("=")) - { - int i = name.indexOf("="); - equals = name.mid(i+1); - name = name.left(i); - } - - if (m_options.contains(name)) - { - if (map.contains(name)) - throw ParsingError(QString("Option %2%1 was given multiple times").arg(name, optionPrefix)); - - OptionDef *option = m_options[name]; - if (option->type == otSwitch) - map[name] = true; - else //if (option->type == otOption) - { - if (m_argStyle == ArgumentStyle::Space) - expecting.append(name); - else if (!equals.isNull()) - map[name] = equals; - else if (m_argStyle == ArgumentStyle::SpaceAndEquals) - expecting.append(name); - else - throw ParsingError(QString("Option %2%1 reqires an argument.").arg(name, optionPrefix)); - } - - continue; - } - - throw ParsingError(QString("Unknown Option %2%1").arg(name, optionPrefix)); - } - - if (arg.startsWith(flagPrefix)) - // we have (a) flag(s) - { - //qDebug("Found flags %s", qPrintable(arg)); - - QString flags = arg.mid(flagPrefix.length()); - QString equals; - - if ((m_argStyle == ArgumentStyle::Equals || m_argStyle == ArgumentStyle::SpaceAndEquals) && flags.contains("=")) - { - int i = flags.indexOf("="); - equals = flags.mid(i+1); - flags = flags.left(i); - } - - for (int i = 0; i < flags.length(); i++) - { - QChar flag = flags.at(i); - - if (!m_flags.contains(flag)) - throw ParsingError(QString("Unknown flag %2%1").arg(flag, flagPrefix)); - - OptionDef *option = m_flags[flag]; - - if (map.contains(option->name)) - throw ParsingError(QString("Option %2%1 was given multiple times").arg(option->name, optionPrefix)); - - if (option->type == otSwitch) - map[option->name] = true; - else //if (option->type == otOption) - { - if (m_argStyle == ArgumentStyle::Space) - expecting.append(option->name); - else if (!equals.isNull()) - if (i == flags.length()-1) - map[option->name] = equals; - else - throw ParsingError(QString("Flag %4%2 of Argument-requiring Option %1 not last flag in %4%3").arg(option->name, flag, flags, flagPrefix)); - else if (m_argStyle == ArgumentStyle::SpaceAndEquals) - expecting.append(option->name); - else - throw ParsingError(QString("Option %1 reqires an argument. (flag %3%2)").arg(option->name, flag, flagPrefix)); - } - } - - continue; - } - - // must be a positional argument - if (!positionals.hasNext()) - throw ParsingError(QString("Don't know what to do with '%1'").arg(arg)); - - PositionalDef *param = positionals.next(); - - map[param->name] = arg; - } - - // check if we're missing something - if (!expecting.isEmpty()) - throw ParsingError(QString("Was still expecting arguments for %2%1").arg(expecting.join(QString(", ")+optionPrefix), optionPrefix)); - - while (positionals.hasNext()) - { - PositionalDef *param = positionals.next(); - if (param->required) - throw ParsingError(QString("Missing required positional argument '%1'").arg(param->name)); - else - map[param->name] = param->def; - } - - // fill out gaps - QListIterator iter(m_optionList); - while (iter.hasNext()) - { - OptionDef *option = iter.next(); - if (!map.contains(option->name)) - map[option->name] = option->def; - } - - return map; -} - -//clear defs -void Parser::clear() -{ - m_flags.clear(); - m_params.clear(); - m_options.clear(); - - QMutableListIterator it(m_optionList); - while(it.hasNext()) - { - OptionDef *option = it.next(); - it.remove(); - delete option; - } - - QMutableListIterator it2(m_positionals); - while(it2.hasNext()) - { - PositionalDef *arg = it2.next(); - it2.remove(); - delete arg; - } -} - -//Destructor -Parser::~Parser() -{ - clear(); -} - -//getPrefix -void Parser::getPrefix(QString &opt, QString &flag) -{ - if (m_flagStyle == FlagStyle::Windows) - opt = flag = "/"; - else if (m_flagStyle == FlagStyle::Unix) - opt = flag = "-"; - //else if (m_flagStyle == FlagStyle::GNU) - else { - opt = "--"; - flag = "-"; - } -} - -// ParsingError -ParsingError::ParsingError(const QString &what) -{ - m_what = what; -} -ParsingError::ParsingError(const ParsingError &e) -{ - m_what = e.m_what; -} - -const char *ParsingError::what() const throw() -{ - return m_what.toLocal8Bit().constData(); -} -QString ParsingError::qwhat() const -{ - return m_what; -} - -} -} diff --git a/libutil/src/osutils.cpp b/libutil/src/osutils.cpp deleted file mode 100644 index 9a85d1e5..00000000 --- a/libutil/src/osutils.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/osutils.h" - -#include -#include diff --git a/libutil/src/pathutils.cpp b/libutil/src/pathutils.cpp deleted file mode 100644 index 97287840..00000000 --- a/libutil/src/pathutils.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/pathutils.h" - -#include -#include - -QString PathCombine(QString path1, QString path2) -{ - if (!path1.endsWith('/')) - return path1.append('/').append(path2); - else - return path1.append(path2); -} - -QString PathCombine(QString path1, QString path2, QString path3) -{ - return PathCombine(PathCombine(path1, path2), path3); -} - -QString AbsolutePath(QString path) -{ - return QFileInfo(path).absolutePath(); -} - -QString badFilenameChars = "\"\\/?<>:*|!"; - -QString RemoveInvalidFilenameChars(QString string, QChar replaceWith) -{ - for (int i = 0; i < string.length(); i++) - { - if (badFilenameChars.contains(string[i])) - { - string[i] = replaceWith; - } - } - return string; -} - -QString DirNameFromString(QString string, QString inDir) -{ - int num = 0; - QString dirName = RemoveInvalidFilenameChars(string, '-'); - while (QFileInfo(PathCombine(inDir, dirName)).exists()) - { - num++; - dirName = RemoveInvalidFilenameChars(dirName, '-') + QString::number(num); - - // If it's over 9000 - if (num > 9000) - return ""; - } - return dirName; -} - -bool ensurePathExists(QString filenamepath) -{ - QFileInfo a ( filenamepath ); - QDir dir; - return (dir.mkpath ( a.path() )); -} - -bool copyPath(QString src, QString dst) -{ - QDir dir(src); - if (!dir.exists()) - return false; - - foreach (QString d, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) - { - QString dst_path = dst + QDir::separator() + d; - dir.mkpath(dst_path); - copyPath(src+ QDir::separator() + d, dst_path); - } - - foreach (QString f, dir.entryList(QDir::Files)) - { - QFile::copy(src + QDir::separator() + f, dst + QDir::separator() + f); - } - return true; -} diff --git a/libutil/src/userutils.cpp b/libutil/src/userutils.cpp deleted file mode 100644 index b70841ed..00000000 --- a/libutil/src/userutils.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "include/userutils.h" - -#include -#include -#include - -#include "include/osutils.h" -#include "include/pathutils.h" - -// Win32 crap -#if WINDOWS - -#include -#include -#include -#include -#include -#include -#include - -bool called_coinit = false; - -HRESULT CreateLink(LPCSTR linkPath, LPCSTR targetPath, LPCSTR args) -{ - HRESULT hres; - - if (!called_coinit) - { - hres = CoInitialize(NULL); - called_coinit = true; - - if (!SUCCEEDED(hres)) - { - qWarning("Failed to initialize COM. Error 0x%08X", hres); - return hres; - } - } - - - IShellLink* link; - hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&link); - - if (SUCCEEDED(hres)) - { - IPersistFile* persistFile; - - link->SetPath(targetPath); - link->SetArguments(args); - - hres = link->QueryInterface(IID_IPersistFile, (LPVOID*)&persistFile); - if (SUCCEEDED(hres)) - { - WCHAR wstr[MAX_PATH]; - - MultiByteToWideChar(CP_ACP, 0, linkPath, -1, wstr, MAX_PATH); - - hres = persistFile->Save(wstr, TRUE); - persistFile->Release(); - } - link->Release(); - } - return hres; -} - -#endif - -QString Util::getDesktopDir() -{ - return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); -} - -// Cross-platform Shortcut creation -bool Util::createShortCut(QString location, QString dest, QStringList args, QString name, QString icon) -{ -#if LINUX - location = PathCombine(location, name + ".desktop"); - qDebug("location: %s", qPrintable(location)); - - QFile f(location); - f.open(QIODevice::WriteOnly | QIODevice::Text); - QTextStream stream(&f); - - QString argstring; - if (!args.empty()) - argstring = " '" + args.join("' '") + "'"; - - stream << "[Desktop Entry]" << "\n"; - stream << "Type=Application" << "\n"; - stream << "TryExec=" << dest.toLocal8Bit() << "\n"; - stream << "Exec=" << dest.toLocal8Bit() << argstring.toLocal8Bit() << "\n"; - stream << "Name=" << name.toLocal8Bit() << "\n"; - stream << "Icon=" << icon.toLocal8Bit() << "\n"; - - stream.flush(); - f.close(); - - f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther); - - return true; -#elif WINDOWS - // TODO: Fix -// QFile file(PathCombine(location, name + ".lnk")); -// WCHAR *file_w; -// WCHAR *dest_w; -// WCHAR *args_w; -// file.fileName().toWCharArray(file_w); -// dest.toWCharArray(dest_w); - -// QString argStr; -// for (int i = 0; i < args.count(); i++) -// { -// argStr.append(args[i]); -// argStr.append(" "); -// } -// argStr.toWCharArray(args_w); - -// return SUCCEEDED(CreateLink(file_w, dest_w, args_w)); - return false; -#else - qWarning("Desktop Shortcuts not supported on your platform!"); - return false; -#endif -} diff --git a/logic/BaseInstance.cpp b/logic/BaseInstance.cpp new file mode 100644 index 00000000..c2df34e1 --- /dev/null +++ b/logic/BaseInstance.cpp @@ -0,0 +1,181 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BaseInstance.h" +#include "BaseInstance_p.h" + +#include + +#include "inisettingsobject.h" +#include "setting.h" +#include "overridesetting.h" + +#include "pathutils.h" +#include "lists/MinecraftVersionList.h" + + +BaseInstance::BaseInstance( BaseInstancePrivate* d_in, + const QString& rootDir, + SettingsObject* settings_obj, + QObject* parent + ) +:inst_d(d_in), QObject(parent) +{ + I_D(BaseInstance); + d->m_settings = settings_obj; + d->m_rootDir = rootDir; + + settings().registerSetting(new Setting("name", "Unnamed Instance")); + settings().registerSetting(new Setting("iconKey", "default")); + settings().registerSetting(new Setting("notes", "")); + settings().registerSetting(new Setting("lastLaunchTime", 0)); + + // Java Settings + settings().registerSetting(new Setting("OverrideJava", false)); + settings().registerSetting(new OverrideSetting("JavaPath", globalSettings->getSetting("JavaPath"))); + settings().registerSetting(new OverrideSetting("JvmArgs", globalSettings->getSetting("JvmArgs"))); + + // Custom Commands + settings().registerSetting(new Setting("OverrideCommands", false)); + settings().registerSetting(new OverrideSetting("PreLaunchCommand", globalSettings->getSetting("PreLaunchCommand"))); + settings().registerSetting(new OverrideSetting("PostExitCommand", globalSettings->getSetting("PostExitCommand"))); + + // Window Size + settings().registerSetting(new Setting("OverrideWindow", false)); + settings().registerSetting(new OverrideSetting("LaunchMaximized", globalSettings->getSetting("LaunchMaximized"))); + settings().registerSetting(new OverrideSetting("MinecraftWinWidth", globalSettings->getSetting("MinecraftWinWidth"))); + settings().registerSetting(new OverrideSetting("MinecraftWinHeight", globalSettings->getSetting("MinecraftWinHeight"))); + + // Memory + settings().registerSetting(new Setting("OverrideMemory", false)); + settings().registerSetting(new OverrideSetting("MinMemAlloc", globalSettings->getSetting("MinMemAlloc"))); + settings().registerSetting(new OverrideSetting("MaxMemAlloc", globalSettings->getSetting("MaxMemAlloc"))); + + // Auto login + settings().registerSetting(new Setting("OverrideLogin", false)); + settings().registerSetting(new OverrideSetting("AutoLogin", globalSettings->getSetting("AutoLogin"))); + + // Console + settings().registerSetting(new Setting("OverrideConsole", false)); + settings().registerSetting(new OverrideSetting("ShowConsole", globalSettings->getSetting("ShowConsole"))); + settings().registerSetting(new OverrideSetting("AutoCloseConsole", globalSettings->getSetting("AutoCloseConsole"))); +} + +QString BaseInstance::id() const +{ + return QFileInfo(instanceRoot()).fileName(); +} + +QString BaseInstance::instanceType() const +{ + I_D(BaseInstance); + return d->m_settings->get("InstanceType").toString(); +} + + +QString BaseInstance::instanceRoot() const +{ + I_D(BaseInstance); + return d->m_rootDir; +} + +QString BaseInstance::minecraftRoot() const +{ + QFileInfo mcDir(PathCombine(instanceRoot(), "minecraft")); + QFileInfo dotMCDir(PathCombine(instanceRoot(), ".minecraft")); + + if (dotMCDir.exists() && !mcDir.exists()) + return dotMCDir.filePath(); + else + return mcDir.filePath(); +} + +InstanceList *BaseInstance::instList() const +{ + if (parent()->inherits("InstanceList")) + return (InstanceList *)parent(); + else + return NULL; +} + +InstVersionList *BaseInstance::versionList() const +{ + return &MinecraftVersionList::getMainList(); +} + +SettingsObject &BaseInstance::settings() const +{ + I_D(BaseInstance); + return *d->m_settings; +} + +qint64 BaseInstance::lastLaunch() const +{ + I_D(BaseInstance); + return d->m_settings->get ( "lastLaunchTime" ).value(); +} +void BaseInstance::setLastLaunch ( qint64 val ) +{ + I_D(BaseInstance); + d->m_settings->set ( "lastLaunchTime", val ); + emit propertiesChanged ( this ); +} + +void BaseInstance::setGroup ( QString val ) +{ + I_D(BaseInstance); + d->m_group = val; + emit propertiesChanged ( this ); +} +QString BaseInstance::group() const +{ + I_D(BaseInstance); + return d->m_group; +} + +void BaseInstance::setNotes ( QString val ) +{ + I_D(BaseInstance); + d->m_settings->set ( "notes", val ); +} +QString BaseInstance::notes() const +{ + I_D(BaseInstance); + return d->m_settings->get ( "notes" ).toString(); +} + +void BaseInstance::setIconKey ( QString val ) +{ + I_D(BaseInstance); + d->m_settings->set ( "iconKey", val ); + emit propertiesChanged ( this ); +} +QString BaseInstance::iconKey() const +{ + I_D(BaseInstance); + return d->m_settings->get ( "iconKey" ).toString(); +} + +void BaseInstance::setName ( QString val ) +{ + I_D(BaseInstance); + d->m_settings->set ( "name", val ); + emit propertiesChanged ( this ); +} +QString BaseInstance::name() const +{ + I_D(BaseInstance); + return d->m_settings->get ( "name" ).toString(); +} diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h new file mode 100644 index 00000000..8b5de6f5 --- /dev/null +++ b/logic/BaseInstance.h @@ -0,0 +1,145 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +#include "inifile.h" +#include "lists/InstVersionList.h" + +class QDialog; +class BaseUpdate; +class MinecraftProcess; +class OneSixUpdate; +class InstanceList; +class BaseInstancePrivate; + +/*! + * \brief Base class for instances. + * This class implements many functions that are common between instances and + * provides a standard interface for all instances. + * + * To create a new instance type, create a new class inheriting from this class + * and implement the pure virtual functions. + */ +class BaseInstance : public QObject +{ + Q_OBJECT +protected: + /// no-touchy! + BaseInstance(BaseInstancePrivate * d, const QString &rootDir, SettingsObject * settings, QObject *parent = 0); +public: + /// virtual destructor to make sure the destruction is COMPLETE + virtual ~BaseInstance() {}; + + /// The instance's ID. The ID SHALL be determined by MMC internally. The ID IS guaranteed to be unique. + QString id() const; + + /// get the type of this instance + QString instanceType() const; + + /// Path to the instance's root directory. + QString instanceRoot() const; + + /// Path to the instance's minecraft directory. + QString minecraftRoot() const; + + QString name() const; + void setName(QString val); + + QString iconKey() const; + void setIconKey(QString val); + + QString notes() const; + void setNotes(QString val); + + QString group() const; + void setGroup(QString val); + + virtual QString intendedVersionId() const = 0; + virtual bool setIntendedVersionId(QString version) = 0; + + /*! + * The instance's current version. + * This value represents the instance's current version. If this value is + * different from the intendedVersion, the instance should be updated. + * \warning Don't change this value unless you know what you're doing. + */ + virtual QString currentVersionId() const = 0; + //virtual void setCurrentVersionId(QString val) = 0; + + /*! + * Whether or not Minecraft should be downloaded when the instance is launched. + */ + virtual bool shouldUpdate() const = 0; + virtual void setShouldUpdate(bool val) = 0; + + /** + * Gets the time that the instance was last launched. + * Stored in milliseconds since epoch. + */ + qint64 lastLaunch() const; + /// Sets the last launched time to 'val' milliseconds since epoch + void setLastLaunch(qint64 val = QDateTime::currentMSecsSinceEpoch()); + + /*! + * \brief Gets the instance list that this instance is a part of. + * Returns NULL if this instance is not in a list + * (the parent is not an InstanceList). + * \return A pointer to the InstanceList containing this instance. + */ + InstanceList *instList() const; + + /*! + * \brief Gets a pointer to this instance's version list. + * \return A pointer to the available version list for this instance. + */ + virtual InstVersionList *versionList() const; + + /*! + * \brief Gets this instance's settings object. + * This settings object stores instance-specific settings. + * \return A pointer to this instance's settings object. + */ + virtual SettingsObject &settings() const; + + /// returns a valid update task if update is needed, NULL otherwise + virtual BaseUpdate* doUpdate() = 0; + + /// returns a valid minecraft process, ready for launch + virtual MinecraftProcess* prepareForLaunch(QString user, QString session) = 0; + + /// do any necessary cleanups after the instance finishes. also runs before 'prepareForLaunch' + virtual void cleanupAfterRun() = 0; + + /// create a mod edit dialog for the instance + virtual QSharedPointer createModEditDialog ( QWidget* parent ) = 0; +signals: + /*! + * \brief Signal emitted when properties relevant to the instance view change + */ + void propertiesChanged(BaseInstance * inst); + +protected: + QSharedPointer inst_d; +}; + +// pointer for lazy people +typedef QSharedPointer InstancePtr; + diff --git a/logic/BaseInstance_p.h b/logic/BaseInstance_p.h new file mode 100644 index 00000000..a30916a4 --- /dev/null +++ b/logic/BaseInstance_p.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include + +class BaseInstance; + +#define I_D(Class) Class##Private * const d = (Class##Private * const) inst_d.data() + +struct BaseInstancePrivate +{ + QString m_rootDir; + QString m_group; + SettingsObject *m_settings; +}; \ No newline at end of file diff --git a/logic/BaseUpdate.cpp b/logic/BaseUpdate.cpp new file mode 100644 index 00000000..b086ab14 --- /dev/null +++ b/logic/BaseUpdate.cpp @@ -0,0 +1,13 @@ +#include "BaseUpdate.h" + +BaseUpdate::BaseUpdate ( BaseInstance* inst, QObject* parent ) : Task ( parent ) +{ + m_inst = inst; +} + +void BaseUpdate::updateDownloadProgress(qint64 current, qint64 total) +{ + // The progress on the current file is current / total + float currentDLProgress = (float) current / (float) total; + setProgress((int)(currentDLProgress * 100)); // convert to percentage +} \ No newline at end of file diff --git a/logic/BaseUpdate.h b/logic/BaseUpdate.h new file mode 100644 index 00000000..d1e7b735 --- /dev/null +++ b/logic/BaseUpdate.h @@ -0,0 +1,49 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "net/DownloadJob.h" + +#include "tasks/Task.h" + +class MinecraftVersion; +class BaseInstance; + +/*! + * The game update task is the task that handles downloading instances' files. + */ +class BaseUpdate : public Task +{ + Q_OBJECT +public: + explicit BaseUpdate(BaseInstance *inst, QObject *parent = 0); + + virtual void executeTask() = 0; + +protected slots: + //virtual void error(const QString &msg); + void updateDownloadProgress(qint64 current, qint64 total); + +protected: + JobListQueue download_queue; + BaseInstance *m_inst; +}; + + diff --git a/logic/CMakeLists.txt b/logic/CMakeLists.txt new file mode 100644 index 00000000..b1eacced --- /dev/null +++ b/logic/CMakeLists.txt @@ -0,0 +1,24 @@ +project(libMultiMC) + +set(CMAKE_AUTOMOC ON) + +# Find Qt +find_package(Qt5Core REQUIRED) +find_package(Qt5Network REQUIRED) +find_package(Qt5Xml REQUIRED) + +# Include Qt headers. +include_directories(${Qt5Base_INCLUDE_DIRS}) +include_directories(${Qt5Network_INCLUDE_DIRS}) + +# Include utility library. +include_directories(${CMAKE_SOURCE_DIR}/libutil/include) + +# Include settings library. +include_directories(${CMAKE_SOURCE_DIR}/libsettings/include) + +SET(LIBINST_HEADERS + +) + + diff --git a/logic/IconListModel.cpp b/logic/IconListModel.cpp new file mode 100644 index 00000000..2d2fb6cf --- /dev/null +++ b/logic/IconListModel.cpp @@ -0,0 +1,163 @@ +#include "IconListModel.h" +#include +#include +#include +#include + +#define MAX_SIZE 1024 +IconList* IconList::m_Instance = 0; +QMutex IconList::mutex; + +struct entry +{ + QString key; + QString name; + QIcon icon; + bool is_builtin; +}; + +class Private : public QObject +{ + Q_OBJECT +public: + QMap index; + QVector icons; + Private() + { + } +}; + + +IconList::IconList() : QAbstractListModel(), d(new Private()) +{ + QDir instance_icons(":/icons/instances/"); + auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name); + for(auto file_info: file_info_list) + { + QString key = file_info.baseName(); + addIcon(key, key, file_info.absoluteFilePath(), true); + } + + // FIXME: get from settings + ensurePathExists("icons/"); + QDir user_icons("icons/"); + file_info_list = user_icons.entryInfoList(QDir::Files, QDir::Name); + for(auto file_info: file_info_list) + { + QString filename = file_info.absoluteFilePath(); + QString key = file_info.baseName(); + addIcon(key, key, filename); + } +} + +IconList::~IconList() +{ + delete d; + d = nullptr; +} + +QVariant IconList::data ( const QModelIndex& index, int role ) const +{ + if(!index.isValid()) + return QVariant(); + + int row = index.row(); + + if(row < 0 || row >= d->icons.size()) + return QVariant(); + + switch(role) + { + case Qt::DecorationRole: + return d->icons[row].icon; + case Qt::DisplayRole: + return d->icons[row].name; + case Qt::UserRole: + return d->icons[row].key; + default: + return QVariant(); + } +} + +int IconList::rowCount ( const QModelIndex& parent ) const +{ + return d->icons.size(); +} + +bool IconList::addIcon ( QString key, QString name, QString path, bool is_builtin ) +{ + auto iter = d->index.find(key); + if(iter != d->index.end()) + { + if(d->icons[*iter].is_builtin) return false; + + QIcon icon(path); + if(icon.isNull()) return false; + + // replace the icon + d->icons[*iter] = {key, name, icon, is_builtin}; + return true; + } + else + { + QIcon icon(path); + if(icon.isNull()) return false; + + // add a new icon + d->icons.push_back({key, name, icon, is_builtin}); + d->index[key] = d->icons.size() - 1; + return true; + } +} + + +QIcon IconList::getIcon ( QString key ) +{ + int icon_index = getIconIndex(key); + + if(icon_index != -1) + return d->icons[icon_index].icon; + + // Fallback for icons that don't exist. + icon_index = getIconIndex("infinity"); + + if(icon_index != -1) + return d->icons[icon_index].icon; + return QIcon(); +} + +int IconList::getIconIndex ( QString key ) +{ + if(key == "default") + key = "infinity"; + + auto iter = d->index.find(key); + if(iter != d->index.end()) + return *iter; + + + return -1; +} + + +void IconList::drop() +{ + mutex.lock(); + delete m_Instance; + m_Instance = 0; + mutex.unlock(); +} + +IconList* IconList::instance() +{ + if ( !m_Instance ) + { + mutex.lock(); + if ( !m_Instance ) + m_Instance = new IconList; + mutex.unlock(); + } + return m_Instance; +} + +#include "IconListModel.moc" \ No newline at end of file diff --git a/logic/IconListModel.h b/logic/IconListModel.h new file mode 100644 index 00000000..31b05e64 --- /dev/null +++ b/logic/IconListModel.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +class Private; + +class IconList : public QAbstractListModel +{ +public: + static IconList* instance(); + static void drop(); + QIcon getIcon ( QString key ); + int getIconIndex ( QString key ); + + virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const; + virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const; + + bool addIcon(QString key, QString name, QString path, bool is_builtin = false); + + +private: + virtual ~IconList(); + IconList(); + // hide copy constructor + IconList ( const IconList & ) = delete; + // hide assign op + IconList& operator= ( const IconList & ) = delete; + static IconList* m_Instance; + static QMutex mutex; + Private* d; +}; diff --git a/logic/InstanceFactory.cpp b/logic/InstanceFactory.cpp new file mode 100644 index 00000000..f3511157 --- /dev/null +++ b/logic/InstanceFactory.cpp @@ -0,0 +1,113 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "InstanceFactory.h" + +#include +#include + +#include "BaseInstance.h" +#include "LegacyInstance.h" +#include "OneSixInstance.h" +#include "NostalgiaInstance.h" +#include "InstanceVersion.h" +#include "MinecraftVersion.h" + +#include "inifile.h" +#include +#include + +#include "pathutils.h" + +InstanceFactory InstanceFactory::loader; + +InstanceFactory::InstanceFactory() : + QObject(NULL) +{ + +} + +InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst, const QString &instDir) +{ + auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg")); + + m_settings->registerSetting(new Setting("InstanceType", "Legacy")); + + QString inst_type = m_settings->get("InstanceType").toString(); + + //FIXME: replace with a map lookup, where instance classes register their types + if(inst_type == "Legacy") + { + inst = new LegacyInstance(instDir, m_settings, this); + } + else if(inst_type == "OneSix") + { + inst = new OneSixInstance(instDir, m_settings, this); + } + else if(inst_type == "Nostalgia") + { + inst = new NostalgiaInstance(instDir, m_settings, this); + } + else + { + return InstanceFactory::UnknownLoadError; + } + return NoLoadError; +} + + +InstanceFactory::InstCreateError InstanceFactory::createInstance( BaseInstance*& inst, InstVersionPtr version, const QString& instDir ) +{ + QDir rootDir(instDir); + + qDebug(instDir.toUtf8()); + if (!rootDir.exists() && !rootDir.mkpath(".")) + { + return InstanceFactory::CantCreateDir; + } + auto mcVer = version.dynamicCast(); + if(!mcVer) + return InstanceFactory::NoSuchVersion; + + auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg")); + m_settings->registerSetting(new Setting("InstanceType", "Legacy")); + + switch(mcVer->type) + { + case MinecraftVersion::Legacy: + m_settings->set("InstanceType", "Legacy"); + inst = new LegacyInstance(instDir, m_settings, this); + inst->setIntendedVersionId(version->descriptor); + break; + case MinecraftVersion::OneSix: + m_settings->set("InstanceType", "OneSix"); + inst = new OneSixInstance(instDir, m_settings, this); + inst->setIntendedVersionId(version->descriptor); + break; + case MinecraftVersion::Nostalgia: + m_settings->set("InstanceType", "Nostalgia"); + inst = new NostalgiaInstance(instDir, m_settings, this); + inst->setIntendedVersionId(version->descriptor); + break; + default: + { + delete m_settings; + return InstanceFactory::NoSuchVersion; + } + } + + //FIXME: really, how do you even know? + return InstanceFactory::NoCreateError; +} diff --git a/logic/InstanceFactory.h b/logic/InstanceFactory.h new file mode 100644 index 00000000..ed54f520 --- /dev/null +++ b/logic/InstanceFactory.h @@ -0,0 +1,80 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "InstanceVersion.h" + +class InstVersion; +class BaseInstance; + +/*! + * The \bInstanceFactory\b is a singleton that manages loading and creating instances. + */ +class InstanceFactory : public QObject +{ + Q_OBJECT +public: + /*! + * \brief Gets a reference to the instance loader. + */ + static InstanceFactory &get() { return loader; } + + enum InstLoadError + { + NoLoadError = 0, + UnknownLoadError, + NotAnInstance + }; + + enum InstCreateError + { + NoCreateError = 0, + NoSuchVersion, + UnknownCreateError, + InstExists, + CantCreateDir + }; + + /*! + * \brief Creates a stub instance + * + * \param inst Pointer to store the created instance in. + * \param instDir The instance's directory. + * \return An InstCreateError error code. + * - InstExists if the given instance directory is already an instance. + * - CantCreateDir if the given instance directory cannot be created. + */ + InstCreateError createInstance(BaseInstance *&inst, InstVersionPtr version, const QString &instDir); + + /*! + * \brief Loads an instance from the given directory. + * Checks the instance's INI file to figure out what the instance's type is first. + * \param inst Pointer to store the loaded instance in. + * \param instDir The instance's directory. + * \return An InstLoadError error code. + * - NotAnInstance if the given instance directory isn't a valid instance. + */ + InstLoadError loadInstance(BaseInstance *&inst, const QString &instDir); + +private: + InstanceFactory(); + + static InstanceFactory loader; +}; diff --git a/logic/InstanceVersion.h b/logic/InstanceVersion.h new file mode 100644 index 00000000..eecd9c4e --- /dev/null +++ b/logic/InstanceVersion.h @@ -0,0 +1,68 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +/*! + * An abstract base class for versions. + */ +struct InstVersion +{ + /*! + * Checks if this version is less (older) than the given version. + * \param other The version to compare this one to. + * \return True if this version is older than the given version. + */ + virtual bool operator<(const InstVersion &rhs) const + { + return timestamp < rhs.timestamp; + } + + /*! + * Checks if this version is greater (newer) than the given version. + * \param other The version to compare this one to. + * \return True if this version is newer than the given version. + */ + virtual bool operator>( const InstVersion& rhs ) const + { + return timestamp > rhs.timestamp; + } + + /*! + * A string used to identify this version in config files. + * This should be unique within the version list or shenanigans will occur. + */ + QString descriptor; + /*! + * The name of this version as it is displayed to the user. + * For example: "1.5.1" + */ + QString name; + /*! + * Gets the version's timestamp. + * This is primarily used for sorting versions in a list. + */ + qint64 timestamp; + + virtual QString typeString() const + { + return "InstVersion"; + } +}; + +typedef QSharedPointer InstVersionPtr; + +Q_DECLARE_METATYPE( InstVersionPtr ) \ No newline at end of file diff --git a/logic/LegacyForge.cpp b/logic/LegacyForge.cpp new file mode 100644 index 00000000..adcf487c --- /dev/null +++ b/logic/LegacyForge.cpp @@ -0,0 +1,57 @@ +// +// Copyright 2012 MultiMC Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "LegacyForge.h" + +MinecraftForge::MinecraftForge ( const QString& file ) : Mod ( file ) +{ + +} +bool MinecraftForge::FixVersionIfNeeded ( QString newVersion ) +{/* + wxString reportedVersion = GetModVersion(); + if(reportedVersion == "..." || reportedVersion.empty()) + { + std::auto_ptr in(new wxFFileInputStream("forge.zip")); + wxTempFileOutputStream out("forge.zip"); + wxTextOutputStream textout(out); + wxZipInputStream inzip(*in); + wxZipOutputStream outzip(out); + std::auto_ptr entry; + // preserve metadata + outzip.CopyArchiveMetaData(inzip); + // copy all entries + while (entry.reset(inzip.GetNextEntry()), entry.get() != NULL) + if (!outzip.CopyEntry(entry.release(), inzip)) + return false; + // release last entry + in.reset(); + outzip.PutNextEntry("forgeversion.properties"); + + wxStringTokenizer tokenizer(newVersion,"."); + wxString verFile; + verFile << wxString("forge.major.number=") << tokenizer.GetNextToken() << "\n"; + verFile << wxString("forge.minor.number=") << tokenizer.GetNextToken() << "\n"; + verFile << wxString("forge.revision.number=") << tokenizer.GetNextToken() << "\n"; + verFile << wxString("forge.build.number=") << tokenizer.GetNextToken() << "\n"; + auto buf = verFile.ToUTF8(); + outzip.Write(buf.data(), buf.length()); + // check if we succeeded + return inzip.Eof() && outzip.Close() && out.Commit(); + } + */ + return true; +} diff --git a/logic/LegacyForge.h b/logic/LegacyForge.h new file mode 100644 index 00000000..00a054b8 --- /dev/null +++ b/logic/LegacyForge.h @@ -0,0 +1,25 @@ +// +// Copyright 2012 MultiMC Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#pragma once +#include "Mod.h" + +class MinecraftForge : public Mod +{ +public: + MinecraftForge ( const QString& file ); + bool FixVersionIfNeeded(QString newVersion); +}; diff --git a/logic/LegacyInstance.cpp b/logic/LegacyInstance.cpp new file mode 100644 index 00000000..db2a72d9 --- /dev/null +++ b/logic/LegacyInstance.cpp @@ -0,0 +1,274 @@ +#include "LegacyInstance.h" +#include "LegacyInstance_p.h" +#include "MinecraftProcess.h" +#include "LegacyUpdate.h" +#include +#include +#include +#include "gui/LegacyModEditDialog.h" +#include +#include +#include + +#define LAUNCHER_FILE "MultiMCLauncher.jar" + +LegacyInstance::LegacyInstance(const QString& rootDir, SettingsObject* settings, QObject* parent) + :BaseInstance( new LegacyInstancePrivate(),rootDir, settings, parent) +{ + settings->registerSetting(new Setting("NeedsRebuild", true)); + settings->registerSetting(new Setting("ShouldUpdate", false)); + settings->registerSetting(new Setting("JarVersion", "Unknown")); + settings->registerSetting(new Setting("LwjglVersion", "2.9.0")); + settings->registerSetting(new Setting("IntendedJarVersion", "")); +} + +BaseUpdate* LegacyInstance::doUpdate() +{ + return new LegacyUpdate(this, this); +} + +MinecraftProcess* LegacyInstance::prepareForLaunch(QString user, QString session) +{ + MinecraftProcess * proc = new MinecraftProcess(this); + + // FIXME: extract the icon + // QImage(":/icons/instances/" + iconKey()).save(PathCombine(minecraftRoot(), "icon.png")); + + // extract the legacy launcher + QFile(":/launcher/launcher.jar").copy(PathCombine(minecraftRoot(), LAUNCHER_FILE)); + + // set the process arguments + { + QStringList args; + + // window size + QString windowSize; + if (settings().get("LaunchMaximized").toBool()) + windowSize = "max"; + else + windowSize = QString("%1x%2"). + arg(settings().get("MinecraftWinWidth").toInt()). + arg(settings().get("MinecraftWinHeight").toInt()); + + // window title + QString windowTitle; + windowTitle.append("MultiMC: ").append(name()); + + // Java arguments + args.append(Util::Commandline::splitArgs(settings().get("JvmArgs").toString())); + +#ifdef OSX + // OSX dock icon and name + args << "-Xdock:icon=icon.png"; + args << QString("-Xdock:name=\"%1\"").arg(windowTitle); +#endif + + QString lwjgl = QDir(globalSettings->get("LWJGLDir").toString() + "/" + lwjglVersion()).absolutePath(); + + // launcher arguments + args << QString("-Xms%1m").arg(settings().get("MinMemAlloc").toInt()); + args << QString("-Xmx%1m").arg(settings().get("MaxMemAlloc").toInt()); + args << "-jar" << LAUNCHER_FILE; + args << user; + args << session; + args << windowTitle; + args << windowSize; + args << lwjgl; + proc->setMinecraftArguments(args); + } + + // set the process work path + proc->setMinecraftWorkdir(minecraftRoot()); + + return proc; +} + +QSharedPointer< ModList > LegacyInstance::coreModList() +{ + I_D(LegacyInstance); + if(!d->core_mod_list) + { + d->core_mod_list.reset(new ModList(coreModsDir(), QString())); + } + return d->core_mod_list; +} + +QSharedPointer< ModList > LegacyInstance::jarModList() +{ + I_D(LegacyInstance); + if(!d->jar_mod_list) + { + auto list = new ModList(instModsDir(), modListFile()); + connect(list, SIGNAL(changed()), SLOT(jarModsChanged())); + d->jar_mod_list.reset(list); + } + return d->jar_mod_list; +} + +void LegacyInstance::jarModsChanged() +{ + setShouldRebuild(true); +} + + +QSharedPointer< ModList > LegacyInstance::loaderModList() +{ + I_D(LegacyInstance); + if(!d->loader_mod_list) + { + d->loader_mod_list.reset(new ModList(mlModsDir(), QString())); + } + return d->loader_mod_list; +} + +QSharedPointer< QDialog > LegacyInstance::createModEditDialog ( QWidget* parent ) +{ + return QSharedPointer (new LegacyModEditDialog(this, parent)); +} + + +void LegacyInstance::cleanupAfterRun() +{ + //FIXME: delete the launcher and icons and whatnot. +} + + +QString LegacyInstance::instModsDir() const +{ + return PathCombine(instanceRoot(), "instMods"); +} + +QString LegacyInstance::binDir() const +{ + return PathCombine(minecraftRoot(), "bin"); +} + +QString LegacyInstance::savesDir() const +{ + return PathCombine(minecraftRoot(), "saves"); +} + +QString LegacyInstance::mlModsDir() const +{ + return PathCombine(minecraftRoot(), "mods"); +} + +QString LegacyInstance::coreModsDir() const +{ + return PathCombine(minecraftRoot(), "coremods"); +} + +QString LegacyInstance::resourceDir() const +{ + return PathCombine(minecraftRoot(), "resources"); +} + +QString LegacyInstance::mcJar() const +{ + return PathCombine(binDir(), "minecraft.jar"); +} + +QString LegacyInstance::mcBackup() const +{ + return PathCombine(binDir(), "mcbackup.jar"); +} + +QString LegacyInstance::modListFile() const +{ + return PathCombine(instanceRoot(), "modlist"); +} + +bool LegacyInstance::shouldUpdateCurrentVersion() const +{ + QFileInfo jar(mcJar()); + return jar.lastModified().toUTC().toMSecsSinceEpoch() != lastCurrentVersionUpdate(); +} + +void LegacyInstance::updateCurrentVersion(bool keepCurrent) +{ + QFileInfo jar(mcJar()); + + if(!jar.exists()) + { + setLastCurrentVersionUpdate(0); + setCurrentVersionId("Unknown"); + return; + } + + qint64 time = jar.lastModified().toUTC().toMSecsSinceEpoch(); + + setLastCurrentVersionUpdate(time); + if (!keepCurrent) + { + // TODO: Implement GetMinecraftJarVersion function. + QString newVersion = "Unknown";//javautils::GetMinecraftJarVersion(jar.absoluteFilePath()); + setCurrentVersionId(newVersion); + } +} +qint64 LegacyInstance::lastCurrentVersionUpdate() const +{ + I_D(LegacyInstance); + return d->m_settings->get ( "lastVersionUpdate" ).value(); +} +void LegacyInstance::setLastCurrentVersionUpdate ( qint64 val ) +{ + I_D(LegacyInstance); + d->m_settings->set ( "lastVersionUpdate", val ); +} +bool LegacyInstance::shouldRebuild() const +{ + I_D(LegacyInstance); + return d->m_settings->get ( "NeedsRebuild" ).toBool(); +} +void LegacyInstance::setShouldRebuild ( bool val ) +{ + I_D(LegacyInstance); + d->m_settings->set ( "NeedsRebuild", val ); +} +QString LegacyInstance::currentVersionId() const +{ + I_D(LegacyInstance); + return d->m_settings->get ( "JarVersion" ).toString(); +} + +void LegacyInstance::setCurrentVersionId ( QString val ) +{ + I_D(LegacyInstance); + d->m_settings->set ( "JarVersion", val ); +} + +QString LegacyInstance::lwjglVersion() const +{ + I_D(LegacyInstance); + return d->m_settings->get ( "LwjglVersion" ).toString(); +} +void LegacyInstance::setLWJGLVersion ( QString val ) +{ + I_D(LegacyInstance); + d->m_settings->set ( "LwjglVersion", val ); +} +QString LegacyInstance::intendedVersionId() const +{ + I_D(LegacyInstance); + return d->m_settings->get ( "IntendedJarVersion" ).toString(); +} +bool LegacyInstance::setIntendedVersionId ( QString version ) +{ + settings().set("IntendedJarVersion", version); + setShouldUpdate(true); + return true; +} +bool LegacyInstance::shouldUpdate() const +{ + I_D(LegacyInstance); + QVariant var = settings().get ( "ShouldUpdate" ); + if ( !var.isValid() || var.toBool() == false ) + { + return intendedVersionId() != currentVersionId(); + } + return true; +} +void LegacyInstance::setShouldUpdate ( bool val ) +{ + settings().set ( "ShouldUpdate", val ); +} diff --git a/logic/LegacyInstance.h b/logic/LegacyInstance.h new file mode 100644 index 00000000..43a66a2b --- /dev/null +++ b/logic/LegacyInstance.h @@ -0,0 +1,95 @@ +#pragma once + +#include "BaseInstance.h" + +class ModList; +class BaseUpdate; + +class LegacyInstance : public BaseInstance +{ + Q_OBJECT +public: + + explicit LegacyInstance(const QString &rootDir, SettingsObject * settings, QObject *parent = 0); + + /// Path to the instance's minecraft.jar + QString mcJar() const; + + //! Path to the instance's mcbackup.jar + QString mcBackup() const; + + //! Path to the instance's modlist file. + QString modListFile() const; + + ////// Mod Lists ////// + QSharedPointer jarModList(); + QSharedPointer coreModList(); + QSharedPointer loaderModList(); + + ////// Directories ////// + QString savesDir() const; + QString instModsDir() const; + QString binDir() const; + QString mlModsDir() const; + QString coreModsDir() const; + QString resourceDir() const; + + /*! + * \brief Checks whether or not the currentVersion of the instance needs to be updated. + * If this returns true, updateCurrentVersion is called. In the + * standard instance, this is determined by checking a timestamp + * stored in the instance config file against the last modified time of Minecraft.jar. + * \return True if updateCurrentVersion() should be called. + */ + bool shouldUpdateCurrentVersion() const; + + /*! + * \brief Updates the current version. + * This function should first set the current version timestamp + * (setCurrentVersionTimestamp()) to the current time. Next, if + * keepCurrent is false, this function should check what the + * instance's current version is and call setCurrentVersion() to + * update it. This function will automatically be called when the + * instance is loaded if shouldUpdateCurrentVersion returns true. + * \param keepCurrent If true, only the version timestamp will be updated. + */ + void updateCurrentVersion(bool keepCurrent = false); + + /*! + * Gets the last time that the current version was checked. + * This is checked against the last modified time on the jar file to see if + * the current version needs to be checked again. + */ + qint64 lastCurrentVersionUpdate() const; + void setLastCurrentVersionUpdate(qint64 val); + + /*! + * Whether or not the instance's minecraft.jar needs to be rebuilt. + * If this is true, when the instance launches, its jar mods will be + * re-added to a fresh minecraft.jar file. + */ + bool shouldRebuild() const; + void setShouldRebuild(bool val); + + virtual QString currentVersionId() const; + virtual void setCurrentVersionId(QString val); + + //! The version of LWJGL that this instance uses. + QString lwjglVersion() const; + /// st the version of LWJGL libs this instance will use + void setLWJGLVersion(QString val); + + virtual QString intendedVersionId() const; + virtual bool setIntendedVersionId ( QString version ); + + virtual bool shouldUpdate() const; + virtual void setShouldUpdate(bool val); + virtual BaseUpdate* doUpdate(); + + virtual MinecraftProcess* prepareForLaunch( QString user, QString session ); + virtual void cleanupAfterRun(); + virtual QSharedPointer< QDialog > createModEditDialog ( QWidget* parent ); + +protected slots: + virtual void jarModsChanged(); +}; \ No newline at end of file diff --git a/logic/LegacyInstance_p.h b/logic/LegacyInstance_p.h new file mode 100644 index 00000000..a1d195b4 --- /dev/null +++ b/logic/LegacyInstance_p.h @@ -0,0 +1,15 @@ +#pragma once +#include +#include +#include "BaseInstance_p.h" +#include "ModList.h" +#include + +class ModList; + +struct LegacyInstancePrivate: public BaseInstancePrivate +{ + QSharedPointer jar_mod_list; + QSharedPointer core_mod_list; + QSharedPointer loader_mod_list; +}; \ No newline at end of file diff --git a/logic/LegacyUpdate.cpp b/logic/LegacyUpdate.cpp new file mode 100644 index 00000000..a748bad3 --- /dev/null +++ b/logic/LegacyUpdate.cpp @@ -0,0 +1,381 @@ +#include "LegacyUpdate.h" +#include "lists/LwjglVersionList.h" +#include "lists/MinecraftVersionList.h" +#include "BaseInstance.h" +#include "LegacyInstance.h" +#include "net/NetWorker.h" +#include +#include +#include + + +LegacyUpdate::LegacyUpdate ( BaseInstance* inst, QObject* parent ) : BaseUpdate ( inst, parent ) {} + +void LegacyUpdate::executeTask() +{ + lwjglStart(); +} + +void LegacyUpdate::lwjglStart() +{ + LegacyInstance * inst = (LegacyInstance *) m_inst; + + lwjglVersion = inst->lwjglVersion(); + lwjglTargetPath = PathCombine("lwjgl", lwjglVersion ); + lwjglNativesPath = PathCombine( lwjglTargetPath, "natives/"); + + // if the 'done' file exists, we don't have to download this again + QFileInfo doneFile(PathCombine(lwjglTargetPath, "done")); + if(doneFile.exists()) + { + jarStart(); + return; + } + + auto &list = LWJGLVersionList::get(); + if(!list.isLoaded()) + { + emitFailed("Too soon! Let the LWJGL list load :)"); + return; + } + + setStatus("Downloading new LWJGL."); + auto version = list.getVersion(lwjglVersion); + if(!version) + { + emitFailed("Game update failed: the selected LWJGL version is invalid."); + return; + } + + QString url = version->url(); + QUrl realUrl(url); + QString hostname = realUrl.host(); + auto &worker = NetWorker::spawn(); + QNetworkRequest req(realUrl); + req.setRawHeader("Host", hostname.toLatin1()); + req.setHeader(QNetworkRequest::UserAgentHeader, "Wget/1.14 (linux-gnu)"); + QNetworkReply * rep = worker.get ( req ); + + m_reply = QSharedPointer (rep, &QObject::deleteLater); + connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + connect(&worker, SIGNAL(finished(QNetworkReply*)), SLOT(lwjglFinished(QNetworkReply*))); + //connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError))); +} + +void LegacyUpdate::lwjglFinished(QNetworkReply* reply) +{ + if(m_reply != reply) + { + return; + } + if(reply->error() != QNetworkReply::NoError) + { + emitFailed( "Failed to download: "+ + reply->errorString()+ + "\nSometimes you have to wait a bit if you download many LWJGL versions in a row. YMMV"); + return; + } + auto &worker = NetWorker::spawn(); + //Here i check if there is a cookie for me in the reply and extract it + QList cookies = qvariant_cast>(reply->header(QNetworkRequest::SetCookieHeader)); + if(cookies.count() != 0) + { + //you must tell which cookie goes with which url + worker.cookieJar()->setCookiesFromUrl(cookies, QUrl("sourceforge.net")); + } + + //here you can check for the 302 or whatever other header i need + QVariant newLoc = reply->header(QNetworkRequest::LocationHeader); + if(newLoc.isValid()) + { + auto &worker = NetWorker::spawn(); + QString redirectedTo = reply->header(QNetworkRequest::LocationHeader).toString(); + QUrl realUrl(redirectedTo); + QString hostname = realUrl.host(); + QNetworkRequest req(redirectedTo); + req.setRawHeader("Host", hostname.toLatin1()); + req.setHeader(QNetworkRequest::UserAgentHeader, "Wget/1.14 (linux-gnu)"); + QNetworkReply * rep = worker.get(req); + connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + m_reply = QSharedPointer (rep, &QObject::deleteLater); + return; + } + QFile saveMe("lwjgl.zip"); + saveMe.open(QIODevice::WriteOnly); + saveMe.write(m_reply->readAll()); + saveMe.close(); + setStatus("Installing new LWJGL..."); + extractLwjgl(); + jarStart(); +} +void LegacyUpdate::extractLwjgl() +{ + // make sure the directories are there + + bool success = ensurePathExists(lwjglNativesPath); + + if(!success) + { + emitFailed("Failed to extract the lwjgl libs - error when creating required folders."); + return; + } + + QuaZip zip("lwjgl.zip"); + if(!zip.open(QuaZip::mdUnzip)) + { + emitFailed("Failed to extract the lwjgl libs - not a valid archive."); + return; + } + + // and now we are going to access files inside it + QuaZipFile file(&zip); + const QString jarNames[] = { "jinput.jar", "lwjgl_util.jar", "lwjgl.jar" }; + for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) + { + if(!file.open(QIODevice::ReadOnly)) + { + zip.close(); + emitFailed("Failed to extract the lwjgl libs - error while reading archive."); + return; + } + QuaZipFileInfo info; + QString name = file.getActualFileName(); + if(name.endsWith('/')) + { + file.close(); + continue; + } + QString destFileName; + // Look for the jars + for (int i = 0; i < 3; i++) + { + if (name.endsWith(jarNames[i])) + { + destFileName = PathCombine(lwjglTargetPath, jarNames[i]); + } + } + // Not found? look for the natives + if(destFileName.isEmpty()) + { +#ifdef Q_OS_WIN32 + QString nativesDir = "windows"; +#elif Q_OS_MAC + QString nativesDir = "macosx"; +#else + QString nativesDir = "linux"; +#endif + if (name.contains(nativesDir)) + { + int lastSlash = name.lastIndexOf('/'); + int lastBackSlash = name.lastIndexOf('/'); + if(lastSlash != -1) + name = name.mid(lastSlash+1); + else if(lastBackSlash != -1) + name = name.mid(lastBackSlash+1); + destFileName = PathCombine(lwjglNativesPath, name); + } + } + // Now if destFileName is still empty, go to the next file. + if (!destFileName.isEmpty()) + { + setStatus("Installing new LWJGL - Extracting " + name); + QFile output(destFileName); + output.open(QIODevice::WriteOnly); + output.write(file.readAll()); // FIXME: wste of memory!? + output.close(); + } + file.close(); // do not forget to close! + } + zip.close(); + m_reply.clear(); + QFile doneFile(PathCombine(lwjglTargetPath, "done")); + doneFile.open(QIODevice::WriteOnly); + doneFile.write("done."); + doneFile.close(); +} + +void LegacyUpdate::lwjglFailed() +{ + emitFailed("Bad stuff happened while trying to get the lwjgl libs..."); +} + +void LegacyUpdate::jarStart() +{ + setStatus("Checking ..."); + LegacyInstance * inst = (LegacyInstance *) m_inst; + QString current_version_id = inst->currentVersionId(); + QString intended_version_id = inst->intendedVersionId(); + bool shouldUpdate = inst->shouldUpdate(); + if(!shouldUpdate) + { + emitSucceeded(); + return; + } + + // nuke the backup file, we are replacing the base jar anyway + QFile mc_backup(inst->mcBackup()); + if (mc_backup.exists()) + { + mc_backup.remove(); + } + + // Get a pointer to the version object that corresponds to the instance's version. + auto targetVersion = MinecraftVersionList::getMainList().findVersion(intended_version_id); + + if(!targetVersion) + { + emitFailed("Not a valid version:" + intended_version_id); + return; + } + + // Make directories + QDir binDir(inst->binDir()); + if (!binDir.exists() && !binDir.mkpath(".")) + { + emitFailed("Failed to create bin folder."); + return; + } + + // Build a list of URLs that will need to be downloaded. + setStatus("Downloading new minecraft.jar"); + + // This will be either 'minecraft' or the version number, depending on where + // we're downloading from. + QString jarFilename = "minecraft"; + QString download_path = PathCombine(inst->minecraftRoot(), "bin/minecraft.jar"); + + QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/"); + urlstr += targetVersion->descriptor + "/" + targetVersion->descriptor + ".jar"; + auto dljob = DownloadJob::create(QUrl(urlstr), download_path); + + legacyDownloadJob.reset(new JobList()); + legacyDownloadJob->add(dljob); + connect(legacyDownloadJob.data(), SIGNAL(finished()), SLOT(jarFinished())); + connect(legacyDownloadJob.data(), SIGNAL(failed()), SLOT(jarFailed())); + connect(legacyDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + download_queue.enqueue(legacyDownloadJob); +} + +void LegacyUpdate::jarFinished() +{ + // process the jar + emitSucceeded(); +} + +void LegacyUpdate::jarFailed() +{ + // bad, bad + emitFailed("Failed to download the minecraft jar. Try again later."); +} + +void LegacyUpdate::ModTheJar() +{ + /* + LegacyInstance * inst = (LegacyInstance *) m_inst; + // Get the mod list + auto modList = inst->getJarModList(); + + QFileInfo mcBin(inst->binDir()); + QFileInfo mcJar(inst->mcJar()); + QFileInfo mcBackup(inst->mcBackup()); + + // Nothing to do if there are no jar mods to install, no backup and just the mc jar + if(mcJar.isFile() && !mcBackup.exists() && modList->empty()) + { + inst->setShouldRebuild(false); + emitSucceeded(); + return; + } + + setStatus("Installing mods - backing up minecraft.jar..."); + if (!mcBackup.exists() && !QFile::copy(mcJar.absoluteFilePath(), mcBackup.absoluteFilePath()) ) + { + emitFailed("Failed to back up minecraft.jar"); + return; + } + + if (mcJar.isFile() && !QFile::remove(mcJar.absoluteFilePath())) + { + emitFailed("Failed to delete old minecraft.jar"); + return; + } + + setStatus("Installing mods - Opening minecraft.jar"); + + wxFFileOutputStream jarStream(mcJar.absoluteFilePath()); + wxZipOutputStream zipOut(jarStream); + + // Files already added to the jar. + // These files will be skipped. + QSet addedFiles; + + // Modify the jar + setStatus("Installing mods - Adding mod files..."); + for (ModList::const_reverse_iterator iter = modList->rbegin(); iter != modList->rend(); iter++) + { + wxFileName modFileName = iter->GetFileName(); + setStatus("Installing mods - Adding " + modFileName.GetFullName()); + if (iter->GetModType() == Mod::ModType::MOD_ZIPFILE) + { + wxFFileInputStream modStream(modFileName.GetFullPath()); + wxZipInputStream zipStream(modStream); + std::unique_ptr entry; + while (entry.reset(zipStream.GetNextEntry()), entry.get() != NULL) + { + if (entry->IsDir()) + continue; + + wxString name = entry->GetName(); + if (addedFiles.count(name) == 0) + { + if (!zipOut.CopyEntry(entry.release(), zipStream)) + break; + addedFiles.insert(name); + } + } + } + else + { + wxFileName destFileName = modFileName; + destFileName.MakeRelativeTo(m_inst->GetInstModsDir().GetFullPath()); + wxString destFile = destFileName.GetFullPath(); + + if (addedFiles.count(destFile) == 0) + { + wxFFileInputStream input(modFileName.GetFullPath()); + zipOut.PutNextEntry(destFile); + zipOut.Write(input); + + addedFiles.insert(destFile); + } + } + } + + { + wxFFileInputStream inStream(mcBackup.GetFullPath()); + wxZipInputStream zipIn(inStream); + + std::auto_ptr entry; + while (entry.reset(zipIn.GetNextEntry()), entry.get() != NULL) + { + wxString name = entry->GetName(); + + if (!name.Matches("META-INF*") && + addedFiles.count(name) == 0) + { + if (!zipOut.CopyEntry(entry.release(), zipIn)) + break; + addedFiles.insert(name); + } + } + } + + // Recompress the jar + TaskStep(); // STEP 3 + SetStatus(_("Installing mods - Recompressing jar...")); + + inst->SetNeedsRebuild(false); + inst->UpdateVersion(true); + return (ExitCode)1; + */ +} \ No newline at end of file diff --git a/logic/LegacyUpdate.h b/logic/LegacyUpdate.h new file mode 100644 index 00000000..342d1eab --- /dev/null +++ b/logic/LegacyUpdate.h @@ -0,0 +1,67 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "net/DownloadJob.h" +#include "tasks/Task.h" +#include "BaseUpdate.h" + +class MinecraftVersion; +class BaseInstance; + +class LegacyUpdate : public BaseUpdate +{ + Q_OBJECT +public: + explicit LegacyUpdate(BaseInstance *inst, QObject *parent = 0); + virtual void executeTask(); + +private slots: + void lwjglStart(); + void lwjglFinished( QNetworkReply* ); + void lwjglFailed(); + + void jarStart(); + void jarFinished(); + void jarFailed(); + + void extractLwjgl(); + + void ModTheJar(); +private: + + QSharedPointer m_reply; + + // target version, determined during this task + // MinecraftVersion *targetVersion; + QString lwjglURL; + QString lwjglVersion; + + QString lwjglTargetPath; + QString lwjglNativesPath; +private: + JobListPtr legacyDownloadJob; + JobListQueue download_queue; + + // target version, determined during this task + QSharedPointer targetVersion; +}; + + diff --git a/logic/MinecraftProcess.cpp b/logic/MinecraftProcess.cpp new file mode 100644 index 00000000..d34be835 --- /dev/null +++ b/logic/MinecraftProcess.cpp @@ -0,0 +1,169 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MinecraftProcess.h" + +#include +#include +#include +//#include +#include + +#include "BaseInstance.h" + +#include "osutils.h" +#include "pathutils.h" +#include "cmdutils.h" + +#define IBUS "@im=ibus" + +// constructor +MinecraftProcess::MinecraftProcess( BaseInstance* inst ) : + m_instance(inst) +{ + connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(finish(int, QProcess::ExitStatus))); + + // prepare the process environment + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + +#ifdef LINUX + // Strip IBus + if (env.value("XMODIFIERS").contains(IBUS)) + env.insert("XMODIFIERS", env.value("XMODIFIERS").replace(IBUS, "")); +#endif + + // export some infos + env.insert("INST_NAME", inst->name()); + env.insert("INST_ID", inst->id()); + env.insert("INST_DIR", QDir(inst->instanceRoot()).absolutePath()); + + this->setProcessEnvironment(env); + m_prepostlaunchprocess.setProcessEnvironment(env); + + // std channels + connect(this, SIGNAL(readyReadStandardError()), SLOT(on_stdErr())); + connect(this, SIGNAL(readyReadStandardOutput()), SLOT(on_stdOut())); +} + +void MinecraftProcess::setMinecraftArguments ( QStringList args ) +{ + m_args = args; +} + +void MinecraftProcess::setMinecraftWorkdir ( QString path ) +{ + QDir mcDir(path); + this->setWorkingDirectory(mcDir.absolutePath()); + m_prepostlaunchprocess.setWorkingDirectory(mcDir.absolutePath()); +} + + +// console window +void MinecraftProcess::on_stdErr() +{ + QByteArray data = readAllStandardError(); + QString str = m_err_leftover + QString::fromLocal8Bit(data); + m_err_leftover.clear(); + QStringList lines = str.split("\n"); + bool complete = str.endsWith("\n"); + + for(int i = 0; i < lines.size() - 1; i++) + { + QString & line = lines[i]; + MessageLevel::Enum level = MessageLevel::Error; + if(line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || line.contains("[FINER]") || line.contains("[FINEST]") ) + level = MessageLevel::Message; + if(line.contains("[SEVERE]") || line.contains("[WARNING]") || line.contains("[STDERR]")) + level = MessageLevel::Error; + emit log(lines[i].toLocal8Bit(), level); + } + if(!complete) + m_err_leftover = lines.last(); +} + +void MinecraftProcess::on_stdOut() +{ + QByteArray data = readAllStandardOutput(); + QString str = m_out_leftover + QString::fromLocal8Bit(data); + m_out_leftover.clear(); + QStringList lines = str.split("\n"); + bool complete = str.endsWith("\n"); + + for(int i = 0; i < lines.size() - 1; i++) + { + QString & line = lines[i]; + emit log(lines[i].toLocal8Bit(), MessageLevel::Message); + } + if(!complete) + m_out_leftover = lines.last(); +} + +// exit handler +void MinecraftProcess::finish(int code, ExitStatus status) +{ + if (status != NormalExit) + { + //TODO: error handling + } + + emit log("Minecraft exited."); + + m_prepostlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(code)); + + // run post-exit + if (!m_instance->settings().get("PostExitCommand").toString().isEmpty()) + { + m_prepostlaunchprocess.start(m_instance->settings().get("PostExitCommand").toString()); + m_prepostlaunchprocess.waitForFinished(); + if (m_prepostlaunchprocess.exitStatus() != NormalExit) + { + //TODO: error handling + } + } + m_instance->cleanupAfterRun(); + emit ended(); +} + +void MinecraftProcess::launch() +{ + if (!m_instance->settings().get("PreLaunchCommand").toString().isEmpty()) + { + m_prepostlaunchprocess.start(m_instance->settings().get("PreLaunchCommand").toString()); + m_prepostlaunchprocess.waitForFinished(); + if (m_prepostlaunchprocess.exitStatus() != NormalExit) + { + //TODO: error handling + return; + } + } + + m_instance->setLastLaunch(); + + emit log(QString("Minecraft folder is: '%1'").arg(workingDirectory())); + QString JavaPath = m_instance->settings().get("JavaPath").toString(); + emit log(QString("Java path: '%1'").arg(JavaPath)); + emit log(QString("Arguments: '%1'").arg(m_args.join("' '"))); + start(JavaPath, m_args); + if (!waitForStarted()) + { + emit log("Could not launch minecraft!"); + return; + //TODO: error handling + } +} + + diff --git a/logic/MinecraftProcess.h b/logic/MinecraftProcess.h new file mode 100644 index 00000000..516bf986 --- /dev/null +++ b/logic/MinecraftProcess.h @@ -0,0 +1,86 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +#include "BaseInstance.h" + +/** + * @brief the MessageLevel Enum + * defines what level a message is + */ +namespace MessageLevel { +enum Enum { + MultiMC, /**< MultiMC Messages */ + Debug, /**< Debug Messages */ + Info, /**< Info Messages */ + Message, /**< Standard Messages */ + Warning, /**< Warnings */ + Error, /**< Errors */ + Fatal /**< Fatal Errors */ +}; +} + +/** + * @file data/minecraftprocess.h + * @brief The MinecraftProcess class + */ +class MinecraftProcess : public QProcess +{ + Q_OBJECT +public: + /** + * @brief MinecraftProcess constructor + * @param inst the Instance pointer to launch + */ + MinecraftProcess(BaseInstance *inst); + + /** + * @brief launch minecraft + */ + void launch(); + + void setMinecraftWorkdir(QString path); + + void setMinecraftArguments(QStringList args); + +signals: + /** + * @brief emitted when mc has finished and the PostLaunchCommand was run + */ + void ended(); + + /** + * @brief emitted when we want to log something + * @param text the text to log + * @param level the level to log at + */ + void log(QString text, MessageLevel::Enum level=MessageLevel::MultiMC); + +protected: + BaseInstance *m_instance; + QStringList m_args; + QString m_err_leftover; + QString m_out_leftover; + QProcess m_prepostlaunchprocess; + +protected slots: + void finish(int, QProcess::ExitStatus status); + void on_stdErr(); + void on_stdOut(); +}; diff --git a/logic/MinecraftVersion.h b/logic/MinecraftVersion.h new file mode 100644 index 00000000..27977262 --- /dev/null +++ b/logic/MinecraftVersion.h @@ -0,0 +1,76 @@ +/* Copyright 2013 Andrew Okin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "InstanceVersion.h" +#include + +struct MinecraftVersion : public InstVersion +{ + // From InstVersion: + /* + QString m_descriptor; + QString m_name; + qint64 m_timestamp; + */ + + /// The URL that this version will be downloaded from. maybe. + QString download_url; + + /// This version's type. Used internally to identify what kind of version this is. + enum VersionType + { + OneSix, + Legacy, + Nostalgia + } type; + + /// is this the latest version? + bool is_latest = false; + + /// is this a snapshot? + bool is_snapshot = false; + + virtual QString typeString() const + { + QStringList pre_final; + if(is_latest == true) + { + pre_final.append("Latest"); + } + switch (type) + { + case OneSix: + pre_final.append("OneSix"); + break; + case Legacy: + pre_final.append("Legacy"); + break; + case Nostalgia: + pre_final.append("Nostalgia"); + break; + + default: + pre_final.append(QString("Type(%1)").arg(type)); + break; + } + if(is_snapshot == true) + { + pre_final.append("Snapshot"); + } + return pre_final.join(' '); + } +}; diff --git a/logic/Mod.cpp b/logic/Mod.cpp new file mode 100644 index 00000000..652bbda7 --- /dev/null +++ b/logic/Mod.cpp @@ -0,0 +1,264 @@ +// +// Copyright 2012 MultiMC Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "Mod.h" +#include +#include + +Mod::Mod( const QFileInfo& file ) +{ + repath(file); +} + +void Mod::repath ( const QFileInfo& file ) +{ + m_file = file; + m_name = file.baseName(); + m_id = file.fileName(); + + m_type = Mod::MOD_UNKNOWN; + if (m_file.isDir()) + m_type = MOD_FOLDER; + else if (m_file.isFile()) + { + QString ext = m_file.suffix().toLower(); + if (ext == "zip" || ext == "jar") + m_type = MOD_ZIPFILE; + else + m_type = MOD_SINGLEFILE; + } + + /* + switch (modType) + { + case MOD_ZIPFILE: + { + wxFFileInputStream fileIn(modFile.GetFullPath()); + wxZipInputStream zipIn(fileIn); + + std::auto_ptr entry; + + bool is_forge = false; + while(true) + { + entry.reset(zipIn.GetNextEntry()); + if (entry.get() == nullptr) + break; + if(entry->GetInternalName().EndsWith("mcmod.info")) + break; + if(entry->GetInternalName().EndsWith("forgeversion.properties")) + { + is_forge = true; + break; + } + } + + if (entry.get() != nullptr) + { + // Read the info file into text + wxString infoFileData; + wxStringOutputStream stringOut(&infoFileData); + zipIn.Read(stringOut); + if(!is_forge) + ReadModInfoData(infoFileData); + else + ReadForgeInfoData(infoFileData); + } + } + break; + + case MOD_FOLDER: + { + wxString infoFile = Path::Combine(modFile, "mcmod.info"); + if (!wxFileExists(infoFile)) + { + infoFile = wxEmptyString; + + wxDir modDir(modFile.GetFullPath()); + + if (!modDir.IsOpened()) + { + wxLogError(_("Can't fine mod info file. Failed to open mod folder.")); + break; + } + + wxString currentFile; + if (modDir.GetFirst(¤tFile)) + { + do + { + if (currentFile.EndsWith("mcmod.info")) + { + infoFile = Path::Combine(modFile.GetFullPath(), currentFile); + break; + } + } while (modDir.GetNext(¤tFile)); + } + } + + if (infoFile != wxEmptyString && wxFileExists(infoFile)) + { + wxString infoStr; + wxFFileInputStream fileIn(infoFile); + wxStringOutputStream strOut(&infoStr); + fileIn.Read(strOut); + ReadModInfoData(infoStr); + } + } + break; + } +*/ +} + + +/* +void ReadModInfoData(QString info) +{ + using namespace boost::property_tree; + + // Read the data + ptree ptRoot; + + std::stringstream stringIn(cStr(info)); + try + { + read_json(stringIn, ptRoot); + + ptree pt = ptRoot.get_child(ptRoot.count("modlist") == 1 ? "modlist" : "").begin()->second; + + modID = wxStr(pt.get("modid")); + modName = wxStr(pt.get("name")); + modVersion = wxStr(pt.get("version")); + } + catch (json_parser_error e) + { + // Silently fail... + } + catch (ptree_error e) + { + // Silently fail... + } +} +*/ + +// FIXME: abstraction violated. +/* +void Mod::ReadForgeInfoData(QString infoFileData) +{ + using namespace boost::property_tree; + + // Read the data + ptree ptRoot; + modName = "Minecraft Forge"; + modID = "Forge"; + std::stringstream stringIn(cStr(infoFileData)); + try + { + read_ini(stringIn, ptRoot); + wxString major, minor, revision, build; + // BUG: boost property tree is bad. won't let us get a key with dots in it + // Likely cause = treating the dots as path separators. + for (auto iter = ptRoot.begin(); iter != ptRoot.end(); iter++) + { + auto &item = *iter; + std::string key = item.first; + std::string value = item.second.get_value(); + if(key == "forge.major.number") + major = value; + if(key == "forge.minor.number") + minor = value; + if(key == "forge.revision.number") + revision = value; + if(key == "forge.build.number") + build = value; + } + modVersion.Empty(); + modVersion << major << "." << minor << "." << revision << "." << build; + } + catch (json_parser_error e) + { + std::cerr << e.what(); + } + catch (ptree_error e) + { + std::cerr << e.what(); + } +} +*/ + +bool Mod::replace ( Mod& with ) +{ + if(!destroy()) + return false; + bool success = false; + auto t = with.type(); + if(t == MOD_ZIPFILE || t == MOD_SINGLEFILE) + { + success = QFile::copy(with.m_file.filePath(), m_file.path()); + } + if(t == MOD_FOLDER) + { + success = copyPath(with.m_file.filePath(), m_file.path()); + } + if(success) + { + m_id = with.m_id; + m_mcversion = with.m_mcversion; + m_type = with.m_type; + m_name = with.m_name; + m_version = with.m_version; + } + return success; +} + +bool Mod::destroy() +{ + if(m_type == MOD_FOLDER) + { + QDir d(m_file.filePath()); + if(d.removeRecursively()) + { + m_type = MOD_UNKNOWN; + return true; + } + return false; + } + else if (m_type == MOD_SINGLEFILE || m_type == MOD_ZIPFILE) + { + QFile f(m_file.filePath()); + if(f.remove()) + { + m_type = MOD_UNKNOWN; + return true; + } + return false; + } + return true; +} + + +QString Mod::version() const +{ + switch(type()) + { + case MOD_ZIPFILE: + return m_version; + case MOD_FOLDER: + return "Folder"; + case MOD_SINGLEFILE: + return "File"; + } +} diff --git a/logic/Mod.h b/logic/Mod.h new file mode 100644 index 00000000..f14818d1 --- /dev/null +++ b/logic/Mod.h @@ -0,0 +1,71 @@ +// +// Copyright 2012 MultiMC Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#pragma once +#include + +class Mod +{ +public: + enum ModType + { + MOD_UNKNOWN, //!< Indicates an unspecified mod type. + MOD_ZIPFILE, //!< The mod is a zip file containing the mod's class files. + MOD_SINGLEFILE, //!< The mod is a single file (not a zip file). + MOD_FOLDER, //!< The mod is in a folder on the filesystem. + }; + + Mod(const QFileInfo &file); + + QFileInfo filename() const { return m_file; } + QString id() const { return m_id; } + ModType type() const { return m_type; } + QString mcversion() const { return m_mcversion; }; + bool valid() {return m_type != MOD_UNKNOWN;} + QString name() const {return m_name; }; + + QString version() const; + + + // delete all the files of this mod + bool destroy(); + // replace this mod with a copy of the other + bool replace(Mod & with); + // change the mod's filesystem path (used by mod lists for *MAGIC* purposes) + void repath(const QFileInfo &file); + + + bool operator ==(const Mod &other) const + { + return filename() == other.filename(); + } + +protected: + + //FIXME: what do do with those? HMM... + /* + void ReadModInfoData(QString info); + void ReadForgeInfoData(QString infoFileData); + */ + + QFileInfo m_file; + QString m_id; + QString m_name; + QString m_version; + QString m_mcversion; + + ModType m_type; +}; diff --git a/logic/ModList.cpp b/logic/ModList.cpp new file mode 100644 index 00000000..d9e67574 --- /dev/null +++ b/logic/ModList.cpp @@ -0,0 +1,472 @@ +// +// Copyright 2013 MultiMC Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "ModList.h" +#include "LegacyInstance.h" +#include + +ModList::ModList ( const QString& dir, const QString& list_file ) +: QAbstractListModel(), m_dir(dir), m_list_file(list_file) +{ + m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs | QDir::NoSymLinks); + m_dir.setSorting(QDir::Name); + update(); +} + +bool ModList::update() +{ + if (!isValid()) + return false; + + bool initial = mods.empty(); + + bool listChanged = false; + + auto list = m_dir.entryInfoList(); + for(auto entry: list) + { + Mod mod(entry); + if (initial || !mods.contains(mod)) + { + mods.push_back(mod); + listChanged = true; + } + } + return listChanged; +} + +bool ModList::isValid() +{ + return m_dir.exists() && m_dir.isReadable(); +} + +bool ModList::installMod ( const QFileInfo& filename, size_t index ) +{ + if(!filename.exists() || !filename.isReadable()) + { + return false; + } + Mod m(filename); + if(!m.valid()) + return false; + + // if it's already there, replace the original mod (in place) + int idx = mods.indexOf(m); + if(idx != -1) + { + if(mods[idx].replace(m)) + { + emit changed(); + return true; + } + return false; + } + + auto type = m.type(); + if(type == Mod::MOD_UNKNOWN) + return false; + if(type == Mod::MOD_SINGLEFILE || type == Mod::MOD_ZIPFILE) + { + QString newpath = PathCombine(m_dir.path(), filename.fileName()); + if(!QFile::copy(filename.filePath(), newpath)) + return false; + m.repath(newpath); + mods.append(m); + emit changed(); + return true; + } + else if(type == Mod::MOD_FOLDER) + { + QString newpath = PathCombine(m_dir.path(), filename.fileName()); + if(!copyPath(filename.filePath(), newpath)) + return false; + m.repath(newpath); + mods.append(m); + emit changed(); + return true; + } + return false; +} + +bool ModList::deleteMod ( size_t index ) +{ + if(index >= mods.size()) + return false; + Mod & m = mods[index]; + if(m.destroy()) + { + mods.erase(mods.begin() + index); + emit changed(); + return true; + } + return false; +} + +bool ModList::moveMod ( size_t from, size_t to ) +{ + return false; +} + +int ModList::columnCount ( const QModelIndex& parent ) const +{ + return 2; +} + +QVariant ModList::data ( const QModelIndex& index, int role ) const +{ + if(!index.isValid()) + return QVariant(); + + int row = index.row(); + int column = index.column(); + + if(row < 0 || row >= mods.size()) + return QVariant(); + + if(role != Qt::DisplayRole) + return QVariant(); + + switch(column) + { + case 0: + return mods[row].name(); + case 1: + return mods[row].version(); + case 2: + return mods[row].mcversion(); + default: + return QVariant(); + } +} + +QVariant ModList::headerData ( int section, Qt::Orientation orientation, int role ) const +{ + if (role != Qt::DisplayRole || orientation != Qt::Horizontal) + return QVariant(); + switch (section) + { + case 0: + return QString("Mod Name"); + case 1: + return QString("Mod Version"); + case 2: + return QString("MC Version"); + } +} + + + +/* +ModList::ModList(const QString &dir) + : modsFolder(dir) +{ + +} + +bool ModList::update(bool quickLoad) +{ + bool listChanged = false; + + // Check for mods in the list whose files do not exist and remove them from the list. + // If doing a quickLoad, erase the whole list. + for (size_t i = 0; i < size(); i++) + { + if (quickLoad || !at(i).GetFileName().FileExists()) + { + erase(begin() + i); + i--; + listChanged = true; + } + } + + // Add any mods in the mods folder that aren't already in the list. + if (LoadModListFromDir(QString(), quickLoad)) + listChanged = true; + + return listChanged; +} + +bool ModList::LoadModListFromDir(const QString& loadFrom, bool quickLoad) +{ + QString dir(loadFrom.isEmpty() ? modsFolder : loadFrom); + + QDir modDir(dir); + if (!modDir.exists()) + return false; + + bool listChanged = false; + + auto list = modDir.entryInfoList(QDir::Readable|QDir::NoDotAndDotDot, QDir::Name); + for(auto currentFile: list) + { + if (currentFile.isFile()) + { + if (quickLoad || FindByFilename(currentFile.absoluteFilePath()) == nullptr) + { + Mod mod(currentFile.absoluteFilePath()); + push_back(mod); + listChanged = true; + } + } + else if (currentFile.isDir()) + { + if (LoadModListFromDir(currentFile.absoluteFilePath())) + listChanged = true; + } + } + + return listChanged; +} + +Mod *ModList::FindByFilename(const QString& filename) +{ + // Search the list for a mod with the given filename. + for (auto iter = begin(); iter != end(); ++iter) + { + if (iter->GetFileName() == QFileInfo(filename)) + return &(*iter); + } + + // If nothing is found, return nullptr. + return nullptr; +} + +int ModList::FindIndexByFilename(const QString& filename) +{ + // Search the list for a mod with the given filename. + int i = 0; + for (auto iter = begin(); iter != end(); ++iter, i++) + { + if (iter->GetFileName() == QFileInfo(filename)) + return i; + } + + // If nothing is found, return nullptr. + return -1; +} + +Mod* ModList::FindByID(const QString& modID, const QString& modVersion) +{ + // Search the list for a mod that matches + for (auto iter = begin(); iter != end(); ++iter) + { + QString ID = iter->GetModID(); + QString version = iter->GetModVersion(); + if ( ID == modID && version == modVersion) + return &(*iter); + } + + // If nothing is found, return nullptr. + return nullptr; +} + +void ModList::LoadFromFile(const QString& file) +{ + if (!wxFileExists(file)) + return; + + wxFFileInputStream inputStream(file); + wxArrayString modListFile = ReadAllLines(inputStream); + + for (wxArrayString::iterator iter = modListFile.begin(); iter != modListFile.end(); iter++) + { + // Normalize the path to the instMods dir. + wxFileName modFile(*iter); + modFile.Normalize(wxPATH_NORM_ALL, modsFolder); + modFile.MakeRelativeTo(); + // if the file is gone, do not load it + if(!modFile.Exists()) + { + continue; + } + + if (FindByFilename(modFile.GetFullPath()) == nullptr) + { + push_back(Mod(modFile)); + } + } +} + +void ModList::SaveToFile(const QString& file) +{ + QString text; + for (iterator iter = begin(); iter != end(); ++iter) + { + wxFileName modFile = iter->GetFileName(); + modFile.MakeRelativeTo(modsFolder); + text.append(modFile.GetFullPath()); + text.append("\n"); + } + + wxTempFileOutputStream out(file); + WriteAllText(out, text); + out.Commit(); +} + +bool ModList::InsertMod(size_t index, const QString &filename, const QString& saveToFile) +{ + QFileInfo source(filename); + QFileInfo dest(PathCombine(modsFolder, source.fileName())); + + if (source != dest) + { + QFile::copy(source.absoluteFilePath(), dest.absoluteFilePath()); + } + + int oldIndex = FindIndexByFilename(dest.absoluteFilePath()); + + if (oldIndex != -1) + { + erase(begin() + oldIndex); + } + + if (index >= size()) + push_back(Mod(dest)); + else + insert(begin() + index, Mod(dest)); + + if (!saveToFile.isEmpty()) + SaveToFile(saveToFile); + + return true; +} + +bool ModList::DeleteMod(size_t index, const QString& saveToFile) +{ + Mod *mod = &at(index); + if(mod->GetModType() == Mod::MOD_FOLDER) + { + QDir dir(mod->GetFileName().absoluteFilePath()); + if(dir.removeRecursively()) + { + erase(begin() + index); + + if (!saveToFile.isEmpty()) + SaveToFile(saveToFile); + + return true; + } + else + { + // wxLogError(_("Failed to delete mod.")); + } + } + else if (QFile(mod->GetFileName().absoluteFilePath()).remove()) + { + erase(begin() + index); + + if (!saveToFile.isEmpty()) + SaveToFile(saveToFile); + + return true; + } + else + { + // wxLogError(_("Failed to delete mod.")); + } + return false; +} + +bool JarModList::InsertMod(size_t index, const QString &filename, const QString& saveToFile) +{ + QString saveFile = saveToFile; + if (saveToFile.isEmpty()) + saveFile = m_inst->GetModListFile().GetFullPath(); + + if (ModList::InsertMod(index, filename, saveFile)) + { + m_inst->setLWJGLVersion(true); + return true; + } + return false; +} + +bool JarModList::DeleteMod(size_t index, const QString& saveToFile) +{ + QString saveFile = saveToFile; + if (saveToFile.IsEmpty()) + saveFile = m_inst->GetModListFile().GetFullPath(); + + if (ModList::DeleteMod(index, saveFile)) + { + m_inst->SetNeedsRebuild(); + return true; + } + return false; +} + +bool JarModList::UpdateModList(bool quickLoad) +{ + if (ModList::UpdateModList(quickLoad)) + { + m_inst->SetNeedsRebuild(); + return true; + } + return false; +} + +bool FolderModList::LoadModListFromDir(const QString& loadFrom, bool quickLoad) +{ + QString dir(loadFrom.IsEmpty() ? modsFolder : loadFrom); + + if (!wxDirExists(dir)) + return false; + + bool listChanged = false; + wxDir modDir(dir); + + if (!modDir.IsOpened()) + { + wxLogError(_("Failed to open directory: ") + dir); + return false; + } + + QString currentFile; + if (modDir.GetFirst(¤tFile)) + { + do + { + wxFileName modFile(Path::Combine(dir, currentFile)); + + if (wxFileExists(modFile.GetFullPath()) || wxDirExists(modFile.GetFullPath())) + { + if (quickLoad || FindByFilename(modFile.GetFullPath()) == nullptr) + { + Mod mod(modFile.GetFullPath()); + push_back(mod); + listChanged = true; + } + } + } while (modDir.GetNext(¤tFile)); + } + + return listChanged; +} + +bool ModNameSort (const Mod & i,const Mod & j) +{ + if(i.GetModType() == j.GetModType()) + return (i.GetName().toLower() < j.GetName().toLower()); + return (i.GetModType() < j.GetModType()); +} + +bool FolderModList::UpdateModList ( bool quickLoad ) +{ + bool changed = ModList::UpdateModList(quickLoad); + std::sort(begin(),end(),ModNameSort); + return changed; +} +*/ diff --git a/logic/ModList.h b/logic/ModList.h new file mode 100644 index 00000000..41d26491 --- /dev/null +++ b/logic/ModList.h @@ -0,0 +1,67 @@ +// +// Copyright 2013 MultiMC Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +#pragma once + +class LegacyInstance; +class BaseInstance; +#include +#include +#include +#include + +#include "Mod.h" + +/** + * A legacy mod list. + * Backed by a folder. + */ +class ModList : public QAbstractListModel +{ + Q_OBJECT +public: + ModList(const QString& dir, const QString& list_file); + + virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const; + virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const + { + return size(); + }; + virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; + virtual int columnCount ( const QModelIndex& parent ) const; + + size_t size() const { return mods.size(); }; + Mod& operator[](size_t index) { return mods[index]; }; + + /// Reloads the mod list and returns true if the list changed. + virtual bool update(); + + /** + * Adds the given mod to the list at the given index - if the list supports custom ordering + */ + virtual bool installMod(const QFileInfo& filename, size_t index = 0); + + /// Deletes the mod at the given index. + virtual bool deleteMod(size_t index); + + /** + * move the mod at index to the position N + * 0 is the beginning of the list, length() is the end of the list. + */ + virtual bool moveMod(size_t from, size_t to); + + virtual bool isValid(); + +signals: + void changed(); +protected: + QDir m_dir; + QString m_list_file; + QList mods; +}; diff --git a/logic/NostalgiaInstance.cpp b/logic/NostalgiaInstance.cpp new file mode 100644 index 00000000..0a7f3c5a --- /dev/null +++ b/logic/NostalgiaInstance.cpp @@ -0,0 +1,12 @@ +#include "NostalgiaInstance.h" + +NostalgiaInstance::NostalgiaInstance ( const QString& rootDir, SettingsObject* settings, QObject* parent ) + : OneSixInstance ( rootDir, settings, parent ) +{ + +} + +/* +ADD MORE + IF REQUIRED +*/ diff --git a/logic/NostalgiaInstance.h b/logic/NostalgiaInstance.h new file mode 100644 index 00000000..b8858218 --- /dev/null +++ b/logic/NostalgiaInstance.h @@ -0,0 +1,10 @@ +#pragma once + +#include "OneSixInstance.h" + +class NostalgiaInstance : public OneSixInstance +{ + Q_OBJECT +public: + explicit NostalgiaInstance(const QString &rootDir, SettingsObject * settings, QObject *parent = 0); +}; diff --git a/logic/OneSixAssets.cpp b/logic/OneSixAssets.cpp new file mode 100644 index 00000000..db9e7421 --- /dev/null +++ b/logic/OneSixAssets.cpp @@ -0,0 +1,162 @@ +#include +#include +#include +#include "OneSixAssets.h" +#include "net/DownloadJob.h" + +inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname) +{ + QDomNodeList elementList = parent.elementsByTagName(tagname); + if (elementList.count()) + return elementList.at(0).toElement(); + else + return QDomElement(); +} + +class ThreadedDeleter : public QThread +{ + Q_OBJECT +public: + void run() + { + QDirIterator iter(m_base, QDirIterator::Subdirectories); + QStringList nuke_list; + int base_length = m_base.length(); + while (iter.hasNext()) + { + QString filename = iter.next(); + QFileInfo current(filename); + // we keep the dirs... whatever + if(current.isDir()) + continue; + QString trimmedf = filename; + trimmedf.remove(0, base_length + 1); + if(m_whitelist.contains(trimmedf)) + { + // qDebug() << trimmedf << " gets to live"; + } + else + { + // DO NOT TOLERATE JUNK + // qDebug() << trimmedf << " dies"; + QFile f (filename); + f.remove(); + } + } + }; + QString m_base; + QStringList m_whitelist; +}; + +class NukeAndPaveJob: public Job +{ + Q_OBJECT +public: + + explicit NukeAndPaveJob(QString base, QStringList whitelist) + :Job() + { + QDir dir(base); + deleterThread.m_base = dir.absolutePath(); + deleterThread.m_whitelist = whitelist; + }; +public slots: + virtual void start() + { + connect(&deleterThread, SIGNAL(finished()), SLOT(threadFinished())); + deleterThread.start(); + }; + void threadFinished() + { + emit finish(); + } +private: + ThreadedDeleter deleterThread; +}; + + + +void OneSixAssets::fetchFinished() +{ + QString prefix ( "http://s3.amazonaws.com/Minecraft.Resources/" ); + QString fprefix ( "assets/" ); + QStringList nuke_whitelist; + + JobPtr firstJob = index_job->getFirstJob(); + auto DlJob = firstJob.dynamicCast(); + QByteArray ba = DlJob->m_data; + + QString xmlErrorMsg; + QDomDocument doc; + if ( !doc.setContent ( ba, false, &xmlErrorMsg ) ) + { + qDebug() << "Failed to process s3.amazonaws.com/Minecraft.Resources. XML error:" << + xmlErrorMsg << ba; + } + //QRegExp etag_match(".*([a-f0-9]{32}).*"); + QDomNodeList contents = doc.elementsByTagName ( "Contents" ); + + JobList *job = new JobList(); + connect ( job, SIGNAL ( finished() ), SIGNAL(finished()) ); + connect ( job, SIGNAL ( failed() ), SIGNAL(failed()) ); + + for ( int i = 0; i < contents.length(); i++ ) + { + QDomElement element = contents.at ( i ).toElement(); + + if ( element.isNull() ) + continue; + + QDomElement keyElement = getDomElementByTagName ( element, "Key" ); + QDomElement lastmodElement = getDomElementByTagName ( element, "LastModified" ); + QDomElement etagElement = getDomElementByTagName ( element, "ETag" ); + QDomElement sizeElement = getDomElementByTagName ( element, "Size" ); + + if ( keyElement.isNull() || lastmodElement.isNull() || etagElement.isNull() || sizeElement.isNull() ) + continue; + + QString keyStr = keyElement.text(); + QString lastModStr = lastmodElement.text(); + QString etagStr = etagElement.text(); + QString sizeStr = sizeElement.text(); + + //Filter folder keys + if ( sizeStr == "0" ) + continue; + + QString filename = fprefix + keyStr; + QFile check_file ( filename ); + QString client_etag = "nonsense"; + // if there already is a file and md5 checking is in effect and it can be opened + if ( check_file.exists() && check_file.open ( QIODevice::ReadOnly ) ) + { + // check the md5 against the expected one + client_etag = QCryptographicHash::hash ( check_file.readAll(), QCryptographicHash::Md5 ).toHex().constData(); + check_file.close(); + } + + QString trimmedEtag = etagStr.remove ( '"' ); + nuke_whitelist.append ( keyStr ); + if(trimmedEtag != client_etag) + job->add ( DownloadJob::create ( QUrl ( prefix + keyStr ), filename ) ); + + } + job->add ( JobPtr ( new NukeAndPaveJob ( fprefix, nuke_whitelist ) ) ); + files_job.reset ( job ); + dl.enqueue ( files_job ); +} +void OneSixAssets::fetchStarted() +{ + qDebug() << "Started downloading!"; +} +void OneSixAssets::start() +{ + JobList *job = new JobList(); + job->add ( DownloadJob::create ( QUrl ( "http://s3.amazonaws.com/Minecraft.Resources/" ) ) ); + connect ( job, SIGNAL ( finished() ), SLOT ( fetchFinished() ) ); + connect ( job, SIGNAL ( started() ), SLOT ( fetchStarted() ) ); + index_job.reset ( job ); + dl.enqueue ( index_job ); +} + +#include "OneSixAssets.moc" \ No newline at end of file diff --git a/logic/OneSixAssets.h b/logic/OneSixAssets.h new file mode 100644 index 00000000..8c345daa --- /dev/null +++ b/logic/OneSixAssets.h @@ -0,0 +1,22 @@ +#pragma once +#include "net/DownloadJob.h" + +class Private; + +class OneSixAssets : public QObject +{ + Q_OBJECT +signals: + void failed(); + void finished(); + +public slots: + void fetchFinished(); + void fetchStarted(); +public: + void start(); +private: + JobListQueue dl; + JobListPtr index_job; + JobListPtr files_job; +}; diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp new file mode 100644 index 00000000..b7f39e4a --- /dev/null +++ b/logic/OneSixInstance.cpp @@ -0,0 +1,218 @@ +#include "OneSixInstance.h" +#include "OneSixInstance_p.h" +#include "OneSixUpdate.h" +#include "MinecraftProcess.h" +#include "VersionFactory.h" + +#include +#include +#include +#include + +OneSixInstance::OneSixInstance ( const QString& rootDir, SettingsObject* setting_obj, QObject* parent ) +: BaseInstance ( new OneSixInstancePrivate(), rootDir, setting_obj, parent ) +{ + I_D(OneSixInstance); + d->m_settings->registerSetting(new Setting("IntendedVersion", "")); + d->m_settings->registerSetting(new Setting("ShouldUpdate", false)); + reloadFullVersion(); +} + +BaseUpdate* OneSixInstance::doUpdate() +{ + return new OneSixUpdate(this); +} + +QString replaceTokensIn(QString text, QMap with) +{ + QString result; + QRegExp token_regexp("\\$\\{(.+)\\}"); + token_regexp.setMinimal(true); + QStringList list; + int tail = 0; + int head = 0; + while ((head = token_regexp.indexIn(text, head)) != -1) + { + result.append(text.mid(tail, head-tail)); + QString key = token_regexp.cap(1); + auto iter = with.find(key); + if(iter != with.end()) + { + result.append(*iter); + } + head += token_regexp.matchedLength(); + tail = head; + } + result.append(text.mid(tail)); + return result; +} + +QStringList OneSixInstance::processMinecraftArgs( QString user, QString session ) +{ + I_D(OneSixInstance); + auto version = d->version; + QString args_pattern = version->minecraftArguments; + + QMap token_mapping; + token_mapping["auth_username"] = user; + token_mapping["auth_session"] = session; + //FIXME: user and player name are DIFFERENT! + token_mapping["auth_player_name"] = user; + //FIXME: WTF is this. I just plugged in a random UUID here. + token_mapping["auth_uuid"] = "7d4bacf0-fd62-11e2-b778-0800200c9a66"; // obviously fake. + + // this is for offline: + /* + map["auth_player_name"] = "Player"; + map["auth_player_name"] = "00000000-0000-0000-0000-000000000000"; + */ + + token_mapping["profile_name"] = name(); + token_mapping["version_name"] = version->id; + + QString absRootDir = QDir(minecraftRoot()).absolutePath(); + token_mapping["game_directory"] = absRootDir; + QString absAssetsDir = QDir("assets/").absolutePath(); + token_mapping["game_assets"] = absAssetsDir; + + QStringList parts = args_pattern.split(' ',QString::SkipEmptyParts); + for (int i = 0; i < parts.length(); i++) + { + parts[i] = replaceTokensIn(parts[i], token_mapping); + } + return parts; +} + +MinecraftProcess* OneSixInstance::prepareForLaunch ( QString user, QString session ) +{ + I_D(OneSixInstance); + cleanupAfterRun(); + auto version = d->version; + if(!version) + return nullptr; + auto libs_to_extract = version->getActiveNativeLibs(); + QString natives_dir_raw = PathCombine(instanceRoot(), "natives/"); + bool success = ensurePathExists(natives_dir_raw); + if(!success) + { + // FIXME: handle errors + return nullptr; + } + + for(auto lib: libs_to_extract) + { + QString path = "libraries/" + lib->storagePath(); + qDebug() << "Will extract " << path.toLocal8Bit(); + if(JlCompress::extractWithExceptions(path, natives_dir_raw, lib->extract_excludes).isEmpty()) + { + return nullptr; + } + } + + QStringList args; + args.append(Util::Commandline::splitArgs(settings().get("JvmArgs").toString())); + args << QString("-Xms%1m").arg(settings().get("MinMemAlloc").toInt()); + args << QString("-Xmx%1m").arg(settings().get("MaxMemAlloc").toInt()); + QDir natives_dir(natives_dir_raw); + args << QString("-Djava.library.path=%1").arg( natives_dir.absolutePath() ); + QString classPath; + { + auto libs = version->getActiveNormalLibs(); + for (auto lib: libs) + { + QFileInfo fi(QString("libraries/") + lib->storagePath()); + classPath.append(fi.absoluteFilePath()); + //FIXME: make separator tweakable + classPath.append(':'); + } + QString targetstr = "versions/" + version->id + "/" + version->id + ".jar"; + QFileInfo fi(targetstr); + classPath.append(fi.absoluteFilePath()); + } + if(classPath.size()) + { + args << "-cp"; + args << classPath; + } + args << version->mainClass; + args.append(processMinecraftArgs(user, session)); + + // create the process and set its parameters + MinecraftProcess * proc = new MinecraftProcess(this); + proc->setMinecraftArguments(args); + proc->setMinecraftWorkdir(minecraftRoot()); + return proc; +} + +void OneSixInstance::cleanupAfterRun() +{ + QString target_dir = PathCombine(instanceRoot(), "natives/"); + QDir dir(target_dir); + dir.removeRecursively(); +} + +QSharedPointer< QDialog > OneSixInstance::createModEditDialog ( QWidget* parent ) +{ + return QSharedPointer< QDialog >(); +} + + + +bool OneSixInstance::setIntendedVersionId ( QString version ) +{ + settings().set("IntendedVersion", version); + setShouldUpdate(true); + return true; +} + +QString OneSixInstance::intendedVersionId() const +{ + return settings().get("IntendedVersion").toString(); +} + +void OneSixInstance::setShouldUpdate ( bool val ) +{ + settings().set ( "ShouldUpdate", val ); +} + +bool OneSixInstance::shouldUpdate() const +{ + I_D(OneSixInstance); + QVariant var = settings().get ( "ShouldUpdate" ); + if ( !var.isValid() || var.toBool() == false ) + { + return intendedVersionId() != currentVersionId(); + } + return true; +} + +QString OneSixInstance::currentVersionId() const +{ + return intendedVersionId(); +} + +bool OneSixInstance::reloadFullVersion() +{ + I_D(OneSixInstance); + + QString verpath = PathCombine(instanceRoot(), "version.json"); + QFile versionfile(verpath); + if(versionfile.exists() && versionfile.open(QIODevice::ReadOnly)) + { + FullVersionFactory fvf; + auto version = fvf.parse(versionfile.readAll()); + versionfile.close(); + if(version) + { + d->version = version; + return true; + } + }; + return false; +} + +QSharedPointer< FullVersion > OneSixInstance::getFullVersion() +{ + I_D(OneSixInstance); + return d->version; +} diff --git a/logic/OneSixInstance.h b/logic/OneSixInstance.h new file mode 100644 index 00000000..edd96eaa --- /dev/null +++ b/logic/OneSixInstance.h @@ -0,0 +1,34 @@ +#pragma once + +#include "BaseInstance.h" +#include +class FullVersion; +class BaseUpdate; + +class OneSixInstance : public BaseInstance +{ + Q_OBJECT +public: + explicit OneSixInstance(const QString &rootDir, SettingsObject * settings, QObject *parent = 0); + virtual BaseUpdate* doUpdate(); + virtual MinecraftProcess* prepareForLaunch ( QString user, QString session ); + virtual void cleanupAfterRun(); + + virtual QString intendedVersionId() const; + virtual bool setIntendedVersionId ( QString version ); + + virtual QString currentVersionId() const; + // virtual void setCurrentVersionId ( QString val ) {}; + + virtual bool shouldUpdate() const; + virtual void setShouldUpdate(bool val); + + virtual QSharedPointer< QDialog > createModEditDialog ( QWidget* parent ); + + /// reload the full version json file. return true on success! + bool reloadFullVersion(); + /// get the current full version info + QSharedPointer getFullVersion(); +private: + QStringList processMinecraftArgs( QString user, QString session ); +}; \ No newline at end of file diff --git a/logic/OneSixInstance_p.h b/logic/OneSixInstance_p.h new file mode 100644 index 00000000..1037e03c --- /dev/null +++ b/logic/OneSixInstance_p.h @@ -0,0 +1,9 @@ +#pragma once + +#include "BaseInstance_p.h" +#include "OneSixVersion.h" + +struct OneSixInstancePrivate: public BaseInstancePrivate +{ + QSharedPointer version; +}; \ No newline at end of file diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp new file mode 100644 index 00000000..2bb2f496 --- /dev/null +++ b/logic/OneSixUpdate.cpp @@ -0,0 +1,169 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OneSixUpdate.h" + +#include + +#include +#include +#include +#include + +#include + +#include "BaseInstance.h" +#include "lists/MinecraftVersionList.h" +#include "VersionFactory.h" +#include "OneSixVersion.h" +#include "OneSixInstance.h" + +#include "pathutils.h" + + +OneSixUpdate::OneSixUpdate(BaseInstance *inst, QObject *parent):BaseUpdate(inst, parent){} + +void OneSixUpdate::executeTask() +{ + QString intendedVersion = m_inst->intendedVersionId(); + + // Make directories + QDir mcDir(m_inst->minecraftRoot()); + if (!mcDir.exists() && !mcDir.mkpath(".")) + { + emitFailed("Failed to create bin folder."); + return; + } + + // Get a pointer to the version object that corresponds to the instance's version. + targetVersion = MinecraftVersionList::getMainList().findVersion(intendedVersion).dynamicCast(); + if(targetVersion == nullptr) + { + // don't do anything if it was invalid + emitSucceeded(); + return; + } + + if(m_inst->shouldUpdate()) + { + versionFileStart(); + } + else + { + jarlibStart(); + } +} + +void OneSixUpdate::versionFileStart() +{ + setStatus("Getting the version files from Mojang."); + + QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/"); + urlstr += targetVersion->descriptor + "/" + targetVersion->descriptor + ".json"; + auto dljob = DownloadJob::create(QUrl(urlstr)); + specificVersionDownloadJob.reset(new JobList()); + specificVersionDownloadJob->add(dljob); + connect(specificVersionDownloadJob.data(), SIGNAL(finished()), SLOT(versionFileFinished())); + connect(specificVersionDownloadJob.data(), SIGNAL(failed()), SLOT(versionFileFailed())); + connect(specificVersionDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + download_queue.enqueue(specificVersionDownloadJob); +} + +void OneSixUpdate::versionFileFinished() +{ + JobPtr firstJob = specificVersionDownloadJob->getFirstJob(); + auto DlJob = firstJob.dynamicCast(); + + QString version_id = targetVersion->descriptor; + QString inst_dir = m_inst->instanceRoot(); + // save the version file in $instanceId/version.json + { + QString version1 = PathCombine(inst_dir, "/version.json"); + ensurePathExists(version1); + // FIXME: detect errors here, download to a temp file, swap + QFile vfile1 (version1); + vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly ); + vfile1.write(DlJob->m_data); + vfile1.close(); + } + + // the version is downloaded safely. update is 'done' at this point + m_inst->setShouldUpdate(false); + // save the version file in versions/$version/$version.json + /* + //QString version2 = QString("versions/") + version_id + "/" + version_id + ".json"; + //ensurePathExists(version2); + //QFile vfile2 (version2); + //vfile2.open(QIODevice::Truncate | QIODevice::WriteOnly ); + //vfile2.write(DlJob->m_data); + //vfile2.close(); + */ + + jarlibStart(); +} + +void OneSixUpdate::versionFileFailed() +{ + emitFailed("Failed to download the version description. Try again."); +} + +void OneSixUpdate::jarlibStart() +{ + OneSixInstance * inst = (OneSixInstance *) m_inst; + bool successful = inst->reloadFullVersion(); + if(!successful) + { + emitFailed("Failed to load the version description file (version.json). It might be corrupted, missing or simply too new."); + return; + } + + QSharedPointer version = inst->getFullVersion(); + + // download the right jar, save it in versions/$version/$version.jar + QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/"); + urlstr += version->id + "/" + version->id + ".jar"; + QString targetstr ("versions/"); + targetstr += version->id + "/" + version->id + ".jar"; + + auto dljob = DownloadJob::create(QUrl(urlstr), targetstr); + jarlibDownloadJob.reset(new JobList()); + jarlibDownloadJob->add(dljob); + + auto libs = version->getActiveNativeLibs(); + libs.append(version->getActiveNormalLibs()); + + for(auto lib: libs) + { + QString download_path = lib->downloadPath(); + QString storage_path = "libraries/" + lib->storagePath(); + jarlibDownloadJob->add(DownloadJob::create(download_path, storage_path)); + } + connect(jarlibDownloadJob.data(), SIGNAL(finished()), SLOT(jarlibFinished())); + connect(jarlibDownloadJob.data(), SIGNAL(failed()), SLOT(jarlibFailed())); + connect(jarlibDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + + download_queue.enqueue(jarlibDownloadJob); +} + +void OneSixUpdate::jarlibFinished() +{ + emitSucceeded(); +} + +void OneSixUpdate::jarlibFailed() +{ + emitFailed("Failed to download the binary garbage. Try again. Maybe. IF YOU DARE"); +} + diff --git a/logic/OneSixUpdate.h b/logic/OneSixUpdate.h new file mode 100644 index 00000000..7a0cac52 --- /dev/null +++ b/logic/OneSixUpdate.h @@ -0,0 +1,54 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include "net/DownloadJob.h" + +#include "tasks/Task.h" +#include "BaseUpdate.h" + +class MinecraftVersion; +class BaseInstance; + +class OneSixUpdate : public BaseUpdate +{ + Q_OBJECT +public: + explicit OneSixUpdate(BaseInstance *inst, QObject *parent = 0); + virtual void executeTask(); + +private slots: + void versionFileStart(); + void versionFileFinished(); + void versionFileFailed(); + + void jarlibStart(); + void jarlibFinished(); + void jarlibFailed(); + +private: + JobListPtr specificVersionDownloadJob; + JobListPtr jarlibDownloadJob; + JobListQueue download_queue; + + // target version, determined during this task + QSharedPointer targetVersion; +}; + + diff --git a/logic/OneSixVersion.cpp b/logic/OneSixVersion.cpp new file mode 100644 index 00000000..2b2f79f5 --- /dev/null +++ b/logic/OneSixVersion.cpp @@ -0,0 +1,132 @@ +#include "OneSixVersion.h" + +RuleAction RuleAction_fromString(QString name) +{ + if(name == "allow") + return Allow; + if(name == "disallow") + return Disallow; + return Defer; +} + +OpSys OpSys_fromString(QString name) +{ + if(name == "linux") + return Os_Linux; + if(name == "windows") + return Os_Windows; + if(name == "osx") + return Os_OSX; + return Os_Other; +} + +void Library::finalize() +{ + QStringList parts = m_name.split ( ':' ); + QString relative = parts[0]; + relative.replace ( '.','/' ); + relative += '/' + parts[1] + '/' + parts[2] + '/' + parts[1] + '-' + parts[2]; + if ( !m_is_native ) + relative += ".jar"; + else + { + if ( m_native_suffixes.contains ( currentSystem ) ) + { + relative += "-" + m_native_suffixes[currentSystem] + ".jar"; + } + else + { + // really, bad. + relative += ".jar"; + } + } + m_storage_path = relative; + m_download_path = m_base_url + relative; + + if ( m_rules.empty() ) + { + m_is_active = true; + } + else + { + RuleAction result = Disallow; + for ( auto rule: m_rules ) + { + RuleAction temp = rule->apply ( this ); + if ( temp != Defer ) + result = temp; + } + m_is_active = ( result == Allow ); + } + if ( m_is_native ) + { + m_is_active = m_is_active && m_native_suffixes.contains ( currentSystem ); + } +} + +void Library::setName ( QString name ) +{ + m_name = name; +} +void Library::setBaseUrl ( QString base_url ) +{ + m_base_url = base_url; +} +void Library::setIsNative() +{ + m_is_native = true; +} +void Library::addNative ( OpSys os, QString suffix ) +{ + m_is_native = true; + m_native_suffixes[os] = suffix; +} +void Library::setRules ( QList< QSharedPointer< Rule > > rules ) +{ + m_rules = rules; +} +bool Library::isActive() +{ + return m_is_active; +} +bool Library::isNative() +{ + return m_is_native; +} +QString Library::downloadPath() +{ + return m_download_path; +} +QString Library::storagePath() +{ + return m_storage_path; +} + + +QList > FullVersion::getActiveNormalLibs() +{ + QList > output; + for ( auto lib: libraries ) + { + if (lib->isActive() && !lib->isNative()) + { + output.append(lib); + } + } + return output; +} + +QList > FullVersion::getActiveNativeLibs() +{ + QList > output; + for ( auto lib: libraries ) + { + if (lib->isActive() && lib->isNative()) + { + output.append(lib); + } + } + return output; +} + + diff --git a/logic/OneSixVersion.h b/logic/OneSixVersion.h new file mode 100644 index 00000000..e4f75542 --- /dev/null +++ b/logic/OneSixVersion.h @@ -0,0 +1,212 @@ +#pragma once +#include + +class Library; + +enum OpSys +{ + Os_Windows, + Os_Linux, + Os_OSX, + Os_Other +}; + +OpSys OpSys_fromString(QString); + +#ifdef Q_OS_WIN32 + #define currentSystem Os_Windows +#elif Q_OS_MAC + #define currentSystem Os_OSX +#else + #define currentSystem Os_Linux +#endif + +enum RuleAction +{ + Allow, + Disallow, + Defer +}; + +RuleAction RuleAction_fromString(QString); + +class Rule +{ +protected: + RuleAction m_result; + virtual bool applies(Library * parent) = 0; +public: + Rule(RuleAction result) + :m_result(result) {} + virtual ~Rule(){}; + RuleAction apply(Library * parent) + { + if(applies(parent)) + return m_result; + else + return Defer; + }; +}; + +class OsRule : public Rule +{ +private: + // the OS + OpSys m_system; + // the OS version regexp + QString m_version_regexp; +protected: + virtual bool applies ( Library* ) + { + return (m_system == currentSystem); + } + OsRule(RuleAction result, OpSys system, QString version_regexp) + : Rule(result), m_system(system), m_version_regexp(version_regexp) {} +public: + static QSharedPointer create(RuleAction result, OpSys system, QString version_regexp) + { + return QSharedPointer (new OsRule(result, system, version_regexp)); + } +}; + +class ImplicitRule : public Rule +{ +protected: + virtual bool applies ( Library* ) + { + return true; + } + ImplicitRule(RuleAction result) + : Rule(result) {} +public: + static QSharedPointer create(RuleAction result) + { + return QSharedPointer (new ImplicitRule(result)); + } +}; + +class Library +{ +private: + // basic values used internally (so far) + QString m_name; + QString m_base_url; + QList > m_rules; + + // derived values used for real things + /// where to store the lib locally + QString m_storage_path; + /// where to download the lib from + QString m_download_path; + /// is this lib actually active on the current OS? + bool m_is_active; + /// is the library a native? + bool m_is_native; + /// native suffixes per OS + QMap m_native_suffixes; +public: + QStringList extract_excludes; + +public: + /// Constructor + Library(QString name) + { + m_is_native = false; + m_is_native = false; + m_name = name; + m_base_url = "https://s3.amazonaws.com/Minecraft.Download/libraries/"; + } + + /** + * finalize the library, processing the input values into derived values and state + * + * This SHALL be called after all the values are parsed or after any further change. + */ + void finalize(); + + /// Set the library composite name + void setName(QString name); + /// Set the url base for downloads + void setBaseUrl(QString base_url); + /// Call this to mark the library as 'native' (it's a zip archive with DLLs) + void setIsNative(); + /// Attach a name suffix to the specified OS native + void addNative(OpSys os, QString suffix); + /// Set the load rules + void setRules(QList > rules); + + /// Returns true if the library should be loaded (or extracted, in case of natives) + bool isActive(); + /// Returns true if the library is native + bool isNative(); + /// Get the URL to download the library from + QString downloadPath(); + /// Get the relative path where the library should be saved + QString storagePath(); +}; + + +class FullVersion +{ +public: + /// the ID - determines which jar to use! ACTUALLY IMPORTANT! + QString id; + /// Last updated time - as a string + QString time; + /// Release time - as a string + QString releaseTime; + /// Release type - "release" or "snapshot" + QString type; + /** + * DEPRECATED: Old versions of the new vanilla launcher used this + * ex: "username_session_version" + */ + QString processArguments; + /** + * arguments that should be used for launching minecraft + * + * ex: "--username ${auth_player_name} --session ${auth_session} + * --version ${version_name} --gameDir ${game_directory} --assetsDir ${game_assets}" + */ + QString minecraftArguments; + /** + * the minimum launcher version required by this version ... current is 4 (at point of writing) + */ + int minimumLauncherVersion; + /** + * The main class to load first + */ + QString mainClass; + + /// the list of libs - both active and inactive, native and java + QList > libraries; + + /* + FIXME: add support for those rules here? Looks like a pile of quick hacks to me though. + + "rules": [ + { + "action": "allow" + }, + { + "action": "disallow", + "os": { + "name": "osx", + "version": "^10\\.5\\.\\d$" + } + } + ], + "incompatibilityReason": "There is a bug in LWJGL which makes it incompatible with OSX 10.5.8. Please go to New Profile and use 1.5.2 for now. Sorry!" + } + */ + // QList rules; + +public: + FullVersion() + { + minimumLauncherVersion = 0xDEADBEEF; + } + + QList > getActiveNormalLibs(); + QList > getActiveNativeLibs(); +}; \ No newline at end of file diff --git a/logic/VersionFactory.cpp b/logic/VersionFactory.cpp new file mode 100644 index 00000000..9eccce26 --- /dev/null +++ b/logic/VersionFactory.cpp @@ -0,0 +1,195 @@ +#include "VersionFactory.h" +#include "OneSixVersion.h" + +// Library rules (if any) +QList > FullVersionFactory::parse4rules(QJsonObject & baseObj) +{ + QList > rules; + auto rulesVal = baseObj.value("rules"); + if(rulesVal.isArray()) + { + QJsonArray ruleList = rulesVal.toArray(); + for(auto ruleVal : ruleList) + { + QSharedPointer rule; + if(!ruleVal.isObject()) + continue; + auto ruleObj = ruleVal.toObject(); + auto actionVal = ruleObj.value("action"); + if(!actionVal.isString()) + continue; + auto action = RuleAction_fromString(actionVal.toString()); + if(action == Defer) + continue; + + auto osVal = ruleObj.value("os"); + if(!osVal.isObject()) + { + // add a new implicit action rule + rules.append(ImplicitRule::create(action)); + } + else + { + auto osObj = osVal.toObject(); + auto osNameVal = osObj.value("name"); + if(!osNameVal.isString()) + continue; + OpSys requiredOs = OpSys_fromString(osNameVal.toString()); + QString versionRegex = osObj.value("version").toString(); + // add a new OS rule + rules.append(OsRule::create(action, requiredOs, versionRegex)); + } + } + } + return rules; +} + + +QSharedPointer FullVersionFactory::parse4(QJsonObject root, QSharedPointer fullVersion) +{ + fullVersion->id = root.value("id").toString(); + + fullVersion->mainClass = root.value("mainClass").toString(); + auto procArgsValue = root.value("processArguments"); + if(procArgsValue.isString()) + { + fullVersion->processArguments = procArgsValue.toString(); + QString toCompare = fullVersion->processArguments.toLower(); + if(toCompare == "legacy") + { + fullVersion->minecraftArguments = " ${auth_player_name} ${auth_session}"; + } + else if(toCompare == "username_session") + { + fullVersion->minecraftArguments = "--username ${auth_player_name} --session ${auth_session}"; + } + else if(toCompare == "username_session_version") + { + fullVersion->minecraftArguments = "--username ${auth_player_name} --session ${auth_session} --version ${profile_name}"; + } + } + + auto minecraftArgsValue = root.value("minecraftArguments"); + if(minecraftArgsValue.isString()) + { + fullVersion->minecraftArguments = minecraftArgsValue.toString(); + } + + auto minecraftTypeValue = root.value("type"); + if(minecraftTypeValue.isString()) + { + fullVersion->type = minecraftTypeValue.toString(); + } + + fullVersion->releaseTime = root.value("releaseTime").toString(); + fullVersion->time = root.value("time").toString(); + + // Iterate through the list, if it's a list. + auto librariesValue = root.value("libraries"); + if(!librariesValue.isArray()) + return fullVersion; + + QJsonArray libList = root.value("libraries").toArray(); + for (auto libVal : libList) + { + if (!libVal.isObject()) + { + continue; + } + + QJsonObject libObj = libVal.toObject(); + + // Library name + auto nameVal = libObj.value("name"); + if(!nameVal.isString()) + continue; + QSharedPointer library(new Library(nameVal.toString())); + + auto urlVal = libObj.value("url"); + if(urlVal.isString()) + { + library->setBaseUrl(urlVal.toString()); + } + + // Extract excludes (if any) + auto extractVal = libObj.value("extract"); + if(extractVal.isObject()) + { + QStringList excludes; + auto extractObj = extractVal.toObject(); + auto excludesVal = extractObj.value("exclude"); + if(!excludesVal.isArray()) + goto SKIP_EXTRACTS; + auto excludesList = excludesVal.toArray(); + for(auto excludeVal : excludesList) + { + if(excludeVal.isString()) + excludes.append(excludeVal.toString()); + } + library->extract_excludes = excludes; + } + SKIP_EXTRACTS: + + auto nativesVal = libObj.value("natives"); + if(nativesVal.isObject()) + { + library->setIsNative(); + auto nativesObj = nativesVal.toObject(); + auto iter = nativesObj.begin(); + while(iter != nativesObj.end()) + { + auto osType = OpSys_fromString(iter.key()); + if(osType == Os_Other) + continue; + if(!iter.value().isString()) + continue; + library->addNative(osType, iter.value().toString()); + iter++; + } + } + library->setRules(parse4rules(libObj)); + library->finalize(); + fullVersion->libraries.append(library); + } + return fullVersion; +} + +QSharedPointer FullVersionFactory::parse(QByteArray data) +{ + QSharedPointer readVersion(new FullVersion()); + + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); + + if (jsonError.error != QJsonParseError::NoError) + { + error_string = QString( "Error reading version file :") + " " + jsonError.errorString(); + m_error = FullVersionFactory::ParseError; + return QSharedPointer(); + } + + if(!jsonDoc.isObject()) + { + error_string = "Error reading version file."; + m_error = FullVersionFactory::ParseError; + return QSharedPointer(); + } + QJsonObject root = jsonDoc.object(); + + int launcher_ver = readVersion->minimumLauncherVersion = root.value("minimumLauncherVersion").toDouble(); + // ADD MORE HERE :D + if(launcher_ver > 0 && launcher_ver <= 7) + return parse4(root, readVersion); + else + { + error_string = "Version file was for an unrecognized launcher version. RIP"; + m_error = FullVersionFactory::UnsupportedVersion; + return QSharedPointer(); + } +} + + +FullVersionFactory::FullVersionFactory() +{ + m_error = FullVersionFactory::AllOK; +} diff --git a/logic/VersionFactory.h b/logic/VersionFactory.h new file mode 100644 index 00000000..82c5278a --- /dev/null +++ b/logic/VersionFactory.h @@ -0,0 +1,24 @@ +#pragma once +#include + +struct FullVersion; +class Rule; + +class FullVersionFactory +{ +public: + enum Error + { + AllOK, // all parsed OK + ParseError, // the file was corrupted somehow + UnsupportedVersion // the file was meant for a launcher version we don't support (yet) + } m_error; + QString error_string; + +public: + FullVersionFactory(); + QSharedPointer parse(QByteArray data); +private: + QSharedPointer parse4(QJsonObject root, QSharedPointer product); + QList > parse4rules(QJsonObject & baseObj); +}; \ No newline at end of file diff --git a/logic/lists/InstVersionList.cpp b/logic/lists/InstVersionList.cpp new file mode 100644 index 00000000..7dc67155 --- /dev/null +++ b/logic/lists/InstVersionList.cpp @@ -0,0 +1,129 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "logic/lists/InstVersionList.h" +#include "logic/InstanceVersion.h" + +InstVersionList::InstVersionList(QObject *parent) : + QAbstractListModel(parent) +{ +} + +InstVersionPtr InstVersionList::findVersion( const QString& descriptor ) +{ + for (int i = 0; i < count(); i++) + { + if (at(i)->descriptor == descriptor) + return at(i); + } + return InstVersionPtr(); +} + +InstVersionPtr InstVersionList::getLatestStable() const +{ + if (count() <= 0) + return InstVersionPtr(); + else + return at(0); +} + +QVariant InstVersionList::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() > count()) + return QVariant(); + + + InstVersionPtr version = at(index.row()); + + switch (role) + { + case Qt::DisplayRole: + switch (index.column()) + { + case NameColumn: + return version->name; + + case TypeColumn: + return version->typeString(); + + case TimeColumn: + return version->timestamp; + + default: + return QVariant(); + } + + case Qt::ToolTipRole: + return version->descriptor; + + case VersionPointerRole: + return qVariantFromValue(version); + + default: + return QVariant(); + } +} + +QVariant InstVersionList::headerData(int section, Qt::Orientation orientation, int role) const +{ + switch (role) + { + case Qt::DisplayRole: + switch (section) + { + case NameColumn: + return "Name"; + + case TypeColumn: + return "Type"; + + case TimeColumn: + return "Time"; + + default: + return QVariant(); + } + + case Qt::ToolTipRole: + switch (section) + { + case NameColumn: + return "The name of the version."; + + case TypeColumn: + return "The version's type."; + + default: + return QVariant(); + } + + default: + return QVariant(); + } +} + +int InstVersionList::rowCount(const QModelIndex &parent) const +{ + // Return count + return count(); +} + +int InstVersionList::columnCount(const QModelIndex &parent) const +{ + return 2; +} diff --git a/logic/lists/InstVersionList.h b/logic/lists/InstVersionList.h new file mode 100644 index 00000000..bc6aa5d4 --- /dev/null +++ b/logic/lists/InstVersionList.h @@ -0,0 +1,121 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include "logic/InstanceVersion.h" + +class Task; + +/*! + * \brief Class that each instance type's version list derives from. + * Version lists are the lists that keep track of the available game versions + * for that instance. This list will not be loaded on startup. It will be loaded + * when the list's load function is called. Before using the version list, you + * should check to see if it has been loaded yet and if not, load the list. + * + * Note that this class also inherits from QAbstractListModel. Methods from that + * class determine how this version list shows up in a list view. Said methods + * all have a default implementation, but they can be overridden by plugins to + * change the behavior of the list. + */ +class InstVersionList : public QAbstractListModel +{ + Q_OBJECT +public: + enum ModelRoles + { + VersionPointerRole = 0x34B1CB48 + }; + + enum VListColumns + { + // First column - Name + NameColumn = 0, + + // Second column - Type + TypeColumn, + + // Third column - Timestamp + TimeColumn + }; + + explicit InstVersionList(QObject *parent = 0); + + /*! + * \brief Gets a task that will reload the version list. + * Simply execute the task to load the list. + * The task returned by this function should reset the model when it's done. + * \return A pointer to a task that reloads the version list. + */ + virtual Task *getLoadTask() = 0; + + //! Checks whether or not the list is loaded. If this returns false, the list should be loaded. + virtual bool isLoaded() = 0; + + //! Gets the version at the given index. + virtual const InstVersionPtr at(int i) const = 0; + + //! Returns the number of versions in the list. + virtual int count() const = 0; + + + //////// List Model Functions //////// + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + + + /*! + * \brief Finds a version by its descriptor. + * \param The descriptor of the version to find. + * \return A const pointer to the version with the given descriptor. NULL if + * one doesn't exist. + */ + virtual InstVersionPtr findVersion(const QString &descriptor); + + /*! + * \brief Gets the latest stable version of this instance type. + * This is the version that will be selected by default. + * By default, this is simply the first version in the list. + */ + virtual InstVersionPtr getLatestStable() const; + + /*! + * Sorts the version list. + */ + virtual void sort() = 0; + +protected slots: + /*! + * Updates this list with the given list of versions. + * This is done by copying each version in the given list and inserting it + * into this one. + * We need to do this so that we can set the parents of the versions are set to this + * version list. This can't be done in the load task, because the versions the load + * task creates are on the load task's thread and Qt won't allow their parents + * to be set to something created on another thread. + * To get around that problem, we invoke this method on the GUI thread, which + * then copies the versions and sets their parents correctly. + * \param versions List of versions whose parents should be set. + */ + virtual void updateListData(QList versions) = 0; +}; diff --git a/logic/lists/InstanceList.cpp b/logic/lists/InstanceList.cpp new file mode 100644 index 00000000..39f55f7b --- /dev/null +++ b/logic/lists/InstanceList.cpp @@ -0,0 +1,232 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "logic/lists/InstanceList.h" +#include "logic/BaseInstance.h" +#include "logic/InstanceFactory.h" + +#include "pathutils.h" + +const static int GROUP_FILE_FORMAT_VERSION = 1; + +InstanceList::InstanceList(const QString &instDir, QObject *parent) : + QObject(parent), m_instDir("instances") +{ + +} + +void InstanceList::loadGroupList(QMap & groupMap) +{ + QString groupFileName = m_instDir + "/instgroups.json"; + + // if there's no group file, fail + if(!QFileInfo(groupFileName).exists()) + return; + + QFile groupFile(groupFileName); + + // if you can't open the file, fail + if (!groupFile.open(QIODevice::ReadOnly)) + { + // An error occurred. Ignore it. + qDebug("Failed to read instance group file."); + return; + } + + QTextStream in(&groupFile); + QString jsonStr = in.readAll(); + groupFile.close(); + + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonStr.toUtf8(), &error); + + // if the json was bad, fail + if (error.error != QJsonParseError::NoError) + { + qWarning(QString("Failed to parse instance group file: %1 at offset %2"). + arg(error.errorString(), QString::number(error.offset)).toUtf8()); + return; + } + + // if the root of the json wasn't an object, fail + if (!jsonDoc.isObject()) + { + qWarning("Invalid group file. Root entry should be an object."); + return; + } + + QJsonObject rootObj = jsonDoc.object(); + + // Make sure the format version matches, otherwise fail. + if (rootObj.value("formatVersion").toVariant().toInt() != GROUP_FILE_FORMAT_VERSION) + return; + + // Get the groups. if it's not an object, fail + if (!rootObj.value("groups").isObject()) + { + qWarning("Invalid group list JSON: 'groups' should be an object."); + return; + } + + // Iterate through all the groups. + QJsonObject groupMapping = rootObj.value("groups").toObject(); + for (QJsonObject::iterator iter = groupMapping.begin(); iter != groupMapping.end(); iter++) + { + QString groupName = iter.key(); + + // If not an object, complain and skip to the next one. + if (!iter.value().isObject()) + { + qWarning(QString("Group '%1' in the group list should " + "be an object.").arg(groupName).toUtf8()); + continue; + } + + QJsonObject groupObj = iter.value().toObject(); + if (!groupObj.value("instances").isArray()) + { + qWarning(QString("Group '%1' in the group list is invalid. " + "It should contain an array " + "called 'instances'.").arg(groupName).toUtf8()); + continue; + } + + // Iterate through the list of instances in the group. + QJsonArray instancesArray = groupObj.value("instances").toArray(); + + for (QJsonArray::iterator iter2 = instancesArray.begin(); + iter2 != instancesArray.end(); iter2++) + { + groupMap[(*iter2).toString()] = groupName; + } + } +} + +InstanceList::InstListError InstanceList::loadList() +{ + // load the instance groups + QMap groupMap; + loadGroupList(groupMap); + + m_instances.clear(); + QDir dir(m_instDir); + QDirIterator iter(dir); + while (iter.hasNext()) + { + QString subDir = iter.next(); + if (!QFileInfo(PathCombine(subDir, "instance.cfg")).exists()) + continue; + + BaseInstance *instPtr = NULL; + auto &loader = InstanceFactory::get(); + auto error = loader.loadInstance(instPtr, subDir); + + switch(error) + { + case InstanceFactory::NoLoadError: + break; + case InstanceFactory::NotAnInstance: + break; + } + + if (error != InstanceFactory::NoLoadError && + error != InstanceFactory::NotAnInstance) + { + QString errorMsg = QString("Failed to load instance %1: "). + arg(QFileInfo(subDir).baseName()).toUtf8(); + + switch (error) + { + default: + errorMsg += QString("Unknown instance loader error %1"). + arg(error); + break; + } + qDebug(errorMsg.toUtf8()); + } + else if (!instPtr) + { + qDebug(QString("Error loading instance %1. Instance loader returned null."). + arg(QFileInfo(subDir).baseName()).toUtf8()); + } + else + { + QSharedPointer inst(instPtr); + auto iter = groupMap.find(inst->id()); + if(iter != groupMap.end()) + { + inst->setGroup((*iter)); + } + qDebug(QString("Loaded instance %1").arg(inst->name()).toUtf8()); + inst->setParent(this); + m_instances.append(inst); + connect(instPtr, SIGNAL(propertiesChanged(BaseInstance*)),this, SLOT(propertiesChanged(BaseInstance*))); + } + } + emit invalidated(); + return NoError; +} + +/// Clear all instances. Triggers notifications. +void InstanceList::clear() +{ + m_instances.clear(); + emit invalidated(); +}; + +/// Add an instance. Triggers notifications, returns the new index +int InstanceList::add(InstancePtr t) +{ + m_instances.append(t); + emit instanceAdded(count() - 1); + return count() - 1; +} + +InstancePtr InstanceList::getInstanceById(QString instId) +{ + QListIterator iter(m_instances); + InstancePtr inst; + while(iter.hasNext()) + { + inst = iter.next(); + if (inst->id() == instId) + break; + } + if (inst->id() != instId) + return InstancePtr(); + else + return iter.peekPrevious(); +} + +void InstanceList::propertiesChanged(BaseInstance * inst) +{ + for(int i = 0; i < m_instances.count(); i++) + { + if(inst == m_instances[i].data()) + { + emit instanceChanged(i); + break; + } + } +} diff --git a/logic/lists/InstanceList.h b/logic/lists/InstanceList.h new file mode 100644 index 00000000..82ef0ea4 --- /dev/null +++ b/logic/lists/InstanceList.h @@ -0,0 +1,91 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "logic/BaseInstance.h" + +class BaseInstance; + +class InstanceList : public QObject +{ + Q_OBJECT +private: + /*! + * \brief Get the instance groups + */ + void loadGroupList(QMap & groupList); + +public: + explicit InstanceList(const QString &instDir, QObject *parent = 0); + + /*! + * \brief Error codes returned by functions in the InstanceList class. + * NoError Indicates that no error occurred. + * UnknownError indicates that an unspecified error occurred. + */ + enum InstListError + { + NoError = 0, + UnknownError + }; + + QString instDir() const { return m_instDir; } + + /*! + * \brief Loads the instance list. Triggers notifications. + */ + InstListError loadList(); + + /*! + * \brief Get the instance at index + */ + InstancePtr at(int i) const + { + return m_instances.at(i); + }; + + /*! + * \brief Get the count of loaded instances + */ + int count() const + { + return m_instances.count(); + }; + + /// Clear all instances. Triggers notifications. + void clear(); + + /// Add an instance. Triggers notifications, returns the new index + int add(InstancePtr t); + + /// Get an instance by ID + InstancePtr getInstanceById (QString id); + +signals: + void instanceAdded(int index); + void instanceChanged(int index); + void invalidated(); + +private slots: + void propertiesChanged(BaseInstance * inst); + +protected: + QString m_instDir; + QList< InstancePtr > m_instances; +}; diff --git a/logic/lists/LwjglVersionList.cpp b/logic/lists/LwjglVersionList.cpp new file mode 100644 index 00000000..0e7b5a34 --- /dev/null +++ b/logic/lists/LwjglVersionList.cpp @@ -0,0 +1,206 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LwjglVersionList.h" +#include "logic/net/NetWorker.h" + +#include + +#include + +#include + +#define RSS_URL "http://sourceforge.net/api/file/index/project-id/58488/mtime/desc/rss" + +LWJGLVersionList mainVersionList; + +LWJGLVersionList &LWJGLVersionList::get() +{ + return mainVersionList; +} + + +LWJGLVersionList::LWJGLVersionList(QObject *parent) : + QAbstractListModel(parent) +{ + setLoading(false); +} + +QVariant LWJGLVersionList::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() > count()) + return QVariant(); + + const PtrLWJGLVersion version = at(index.row()); + + switch (role) + { + case Qt::DisplayRole: + return version->name(); + + case Qt::ToolTipRole: + return version->url(); + + default: + return QVariant(); + } +} + +QVariant LWJGLVersionList::headerData(int section, Qt::Orientation orientation, int role) const +{ + switch (role) + { + case Qt::DisplayRole: + return "Version"; + + case Qt::ToolTipRole: + return "LWJGL version name."; + + default: + return QVariant(); + } +} + +int LWJGLVersionList::columnCount(const QModelIndex &parent) const +{ + return 1; +} + +bool LWJGLVersionList::isLoading() const +{ + return m_loading; +} + +void LWJGLVersionList::loadList() +{ + Q_ASSERT_X(!m_loading, "loadList", "list is already loading (m_loading is true)"); + + setLoading(true); + auto & worker = NetWorker::spawn(); + reply = worker.get(QNetworkRequest(QUrl(RSS_URL))); + connect(reply, SIGNAL(finished()), SLOT(netRequestComplete())); +} + +inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname) +{ + QDomNodeList elementList = parent.elementsByTagName(tagname); + if (elementList.count()) + return elementList.at(0).toElement(); + else + return QDomElement(); +} + +void LWJGLVersionList::netRequestComplete() +{ + if (reply->error() == QNetworkReply::NoError) + { + QRegExp lwjglRegex("lwjgl-(([0-9]\\.?)+)\\.zip"); + Q_ASSERT_X(lwjglRegex.isValid(), "load LWJGL list", + "LWJGL regex is invalid"); + + QDomDocument doc; + + QString xmlErrorMsg; + int errorLine; + if (!doc.setContent(reply->readAll(), false, &xmlErrorMsg, &errorLine)) + { + failed("Failed to load LWJGL list. XML error: " + xmlErrorMsg + " at line " + QString::number(errorLine)); + setLoading(false); + return; + } + + QDomNodeList items = doc.elementsByTagName("item"); + + QList tempList; + + for (int i = 0; i < items.length(); i++) + { + Q_ASSERT_X(items.at(i).isElement(), "load LWJGL list", + "XML element isn't an element... wat?"); + + QDomElement linkElement = getDomElementByTagName(items.at(i).toElement(), "link"); + if (linkElement.isNull()) + { + qWarning() << "Link element" << i << "in RSS feed doesn't exist! Skipping."; + continue; + } + + QString link = linkElement.text(); + + // Make sure it's a download link. + if (link.endsWith("/download") && link.contains(lwjglRegex)) + { + QString name = link.mid(lwjglRegex.indexIn(link) + 6); + // Subtract 4 here to remove the .zip file extension. + name = name.left(lwjglRegex.matchedLength() - 10); + + QUrl url(link); + if (!url.isValid()) + { + qWarning() << "LWJGL version URL isn't valid:" << link << "Skipping."; + continue; + } + + tempList.append(LWJGLVersion::Create(name, link)); + } + } + + beginResetModel(); + m_vlist.swap(tempList); + endResetModel(); + + qDebug("Loaded LWJGL list."); + finished(); + } + else + { + failed("Failed to load LWJGL list. Network error: " + reply->errorString()); + } + + setLoading(false); + reply->deleteLater(); +} + +const PtrLWJGLVersion LWJGLVersionList::getVersion(const QString &versionName) +{ + for (int i = 0; i < count(); i++) + { + QString name = at(i)->name(); + if ( name == versionName) + return at(i); + } + return PtrLWJGLVersion(); +} + + +void LWJGLVersionList::failed(QString msg) +{ + qWarning() << msg; + emit loadListFailed(msg); +} + +void LWJGLVersionList::finished() +{ + emit loadListFinished(); +} + +void LWJGLVersionList::setLoading(bool loading) +{ + m_loading = loading; + emit loadingStateUpdated(m_loading); +} diff --git a/logic/lists/LwjglVersionList.h b/logic/lists/LwjglVersionList.h new file mode 100644 index 00000000..638a0b67 --- /dev/null +++ b/logic/lists/LwjglVersionList.h @@ -0,0 +1,117 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include + +class LWJGLVersion; +typedef QSharedPointer PtrLWJGLVersion; + +class LWJGLVersion : public QObject +{ + Q_OBJECT + + LWJGLVersion(const QString &name, const QString &url, QObject *parent = 0) : + QObject(parent), m_name(name), m_url(url) { } +public: + + static PtrLWJGLVersion Create(const QString &name, const QString &url, QObject *parent = 0) + { + return PtrLWJGLVersion(new LWJGLVersion(name, url, parent)); + }; + + QString name() const { return m_name; } + + QString url() const { return m_url; } + +protected: + QString m_name; + QString m_url; +}; + +class LWJGLVersionList : public QAbstractListModel +{ + Q_OBJECT +public: + explicit LWJGLVersionList(QObject *parent = 0); + + static LWJGLVersionList &get(); + + bool isLoaded() { return m_vlist.length() > 0; } + + const PtrLWJGLVersion getVersion(const QString &versionName); + PtrLWJGLVersion at(int index) { return m_vlist[index]; } + const PtrLWJGLVersion at(int index) const { return m_vlist[index]; } + + int count() const { return m_vlist.length(); } + + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual int rowCount(const QModelIndex &parent) const { return count(); } + virtual int columnCount(const QModelIndex &parent) const; + + virtual bool isLoading() const; + virtual bool errored() const { return m_errored; } + + virtual QString lastErrorMsg() const { return m_lastErrorMsg; } + +public slots: + /*! + * Loads the version list. + * This is done asynchronously. On success, the loadListFinished() signal will + * be emitted. The list model will be reset as well, resulting in the modelReset() + * signal being emitted. Note that the model will be reset before loadListFinished() is emitted. + * If loading the list failed, the loadListFailed(QString msg), + * signal will be emitted. + */ + virtual void loadList(); + +signals: + /*! + * Emitted when the list either starts or finishes loading. + * \param loading Whether or not the list is loading. + */ + void loadingStateUpdated(bool loading); + + void loadListFinished(); + + void loadListFailed(QString msg); + +private: + QList m_vlist; + + QNetworkReply *m_netReply; + QNetworkReply *reply; + + bool m_loading; + bool m_errored; + QString m_lastErrorMsg; + + void failed(QString msg); + + void finished(); + + void setLoading(bool loading); + +private slots: + virtual void netRequestComplete(); +}; + diff --git a/logic/lists/MinecraftVersionList.cpp b/logic/lists/MinecraftVersionList.cpp new file mode 100644 index 00000000..80b4fbc0 --- /dev/null +++ b/logic/lists/MinecraftVersionList.cpp @@ -0,0 +1,300 @@ +/* Copyright 2013 Andrew Okin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MinecraftVersionList.h" +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#define MCVLIST_URLBASE "http://s3.amazonaws.com/Minecraft.Download/versions/" +#define ASSETS_URLBASE "http://assets.minecraft.net/" +#define MCN_URLBASE "http://sonicrules.org/mcnweb.py" + +MinecraftVersionList mcVList; + +MinecraftVersionList::MinecraftVersionList(QObject *parent) : + InstVersionList(parent) +{ + +} + +Task *MinecraftVersionList::getLoadTask() +{ + return new MCVListLoadTask(this); +} + +bool MinecraftVersionList::isLoaded() +{ + return m_loaded; +} + +const InstVersionPtr MinecraftVersionList::at(int i) const +{ + return m_vlist.at(i); +} + +int MinecraftVersionList::count() const +{ + return m_vlist.count(); +} + +bool cmpVersions(InstVersionPtr first, InstVersionPtr second) +{ + const InstVersion & left = *first; + const InstVersion & right = *second; + return left > right; +} + +void MinecraftVersionList::sort() +{ + beginResetModel(); + qSort(m_vlist.begin(), m_vlist.end(), cmpVersions); + endResetModel(); +} + +InstVersionPtr MinecraftVersionList::getLatestStable() const +{ + for (int i = 0; i < m_vlist.length(); i++) + { + auto ver = m_vlist.at(i).dynamicCast(); + if (ver->is_latest && !ver->is_snapshot) + { + return m_vlist.at(i); + } + } + return InstVersionPtr(); +} + +MinecraftVersionList &MinecraftVersionList::getMainList() +{ + return mcVList; +} + +void MinecraftVersionList::updateListData(QList versions) +{ + beginResetModel(); + m_vlist = versions; + m_loaded = true; + endResetModel(); + // NOW SORT!! + sort(); +} + +inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname) +{ + QDomNodeList elementList = parent.elementsByTagName(tagname); + if (elementList.count()) + return elementList.at(0).toElement(); + else + return QDomElement(); +} + +inline QDateTime timeFromS3Time(QString str) +{ + return QDateTime::fromString(str, Qt::ISODate); +} + + +MCVListLoadTask::MCVListLoadTask(MinecraftVersionList *vlist) +{ + m_list = vlist; + m_currentStable = NULL; + vlistReply = nullptr; + legacyWhitelist.insert("1.5.2"); + legacyWhitelist.insert("1.5.1"); + legacyWhitelist.insert("1.5"); + legacyWhitelist.insert("1.4.7"); + legacyWhitelist.insert("1.4.6"); + legacyWhitelist.insert("1.4.5"); + legacyWhitelist.insert("1.4.4"); + legacyWhitelist.insert("1.4.2"); + legacyWhitelist.insert("1.3.2"); + legacyWhitelist.insert("1.3.1"); + legacyWhitelist.insert("1.2.5"); + legacyWhitelist.insert("1.2.4"); + legacyWhitelist.insert("1.2.3"); + legacyWhitelist.insert("1.2.2"); + legacyWhitelist.insert("1.2.1"); + legacyWhitelist.insert("1.1"); + legacyWhitelist.insert("1.0.1"); + legacyWhitelist.insert("1.0"); +} + +MCVListLoadTask::~MCVListLoadTask() +{ +} + +void MCVListLoadTask::executeTask() +{ + setStatus("Loading instance version list..."); + auto & worker = NetWorker::spawn(); + vlistReply = worker.get(QNetworkRequest(QUrl(QString(MCVLIST_URLBASE) + "versions.json"))); + connect(vlistReply, SIGNAL(finished()), this, SLOT(list_downloaded())); +} + + +void MCVListLoadTask::list_downloaded() +{ + if(vlistReply->error() != QNetworkReply::QNetworkReply::NoError) + { + vlistReply->deleteLater(); + emitFailed("Failed to load Minecraft main version list" + vlistReply->errorString()); + return; + } + + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(vlistReply->readAll(), &jsonError); + vlistReply->deleteLater(); + + if (jsonError.error != QJsonParseError::NoError) + { + emitFailed("Error parsing version list JSON:" + jsonError.errorString()); + return; + } + + if(!jsonDoc.isObject()) + { + emitFailed("Error parsing version list JSON: jsonDoc is not an object"); + return; + } + + QJsonObject root = jsonDoc.object(); + + // Get the ID of the latest release and the latest snapshot. + if(!root.value("latest").isObject()) + { + emitFailed("Error parsing version list JSON: version list is missing 'latest' object"); + return; + } + + QJsonObject latest = root.value("latest").toObject(); + + QString latestReleaseID = latest.value("release").toString(""); + QString latestSnapshotID = latest.value("snapshot").toString(""); + if(latestReleaseID.isEmpty()) + { + emitFailed("Error parsing version list JSON: latest release field is missing"); + return; + } + if(latestSnapshotID.isEmpty()) + { + emitFailed("Error parsing version list JSON: latest snapshot field is missing"); + return; + } + + // Now, get the array of versions. + if(!root.value("versions").isArray()) + { + emitFailed("Error parsing version list JSON: version list object is missing 'versions' array"); + return; + } + QJsonArray versions = root.value("versions").toArray(); + + QList tempList; + for (int i = 0; i < versions.count(); i++) + { + bool is_snapshot = false; + bool is_latest = false; + + // Load the version info. + if(!versions[i].isObject()) + { + //FIXME: log this somewhere + continue; + } + QJsonObject version = versions[i].toObject(); + QString versionID = version.value("id").toString(""); + QString versionTimeStr = version.value("releaseTime").toString(""); + QString versionTypeStr = version.value("type").toString(""); + if(versionID.isEmpty() || versionTimeStr.isEmpty() || versionTypeStr.isEmpty()) + { + //FIXME: log this somewhere + continue; + } + + // Parse the timestamp. + QDateTime versionTime = timeFromS3Time(versionTimeStr); + if(!versionTime.isValid()) + { + //FIXME: log this somewhere + continue; + } + // Parse the type. + MinecraftVersion::VersionType versionType; + // OneSix or Legacy. use filter to determine type + if (versionTypeStr == "release") + { + versionType = legacyWhitelist.contains(versionID)?MinecraftVersion::Legacy:MinecraftVersion::OneSix; + is_latest = (versionID == latestReleaseID); + is_snapshot = false; + } + else if(versionTypeStr == "snapshot") // It's a snapshot... yay + { + versionType = legacyWhitelist.contains(versionID)?MinecraftVersion::Legacy:MinecraftVersion::OneSix; + is_latest = (versionID == latestSnapshotID); + is_snapshot = true; + } + else if(versionTypeStr == "old_alpha") + { + versionType = MinecraftVersion::Nostalgia; + is_latest = false; + is_snapshot = false; + } + else if(versionTypeStr == "old_beta") + { + versionType = MinecraftVersion::Legacy; + is_latest = false; + is_snapshot = false; + } + else + { + //FIXME: log this somewhere + continue; + } + // Get the download URL. + QString dlUrl = QString(MCVLIST_URLBASE) + versionID + "/"; + + // Now, we construct the version object and add it to the list. + QSharedPointer mcVersion(new MinecraftVersion()); + mcVersion->name = mcVersion->descriptor = versionID; + mcVersion->timestamp = versionTime.toMSecsSinceEpoch(); + mcVersion->download_url = dlUrl; + mcVersion->is_latest = is_latest; + mcVersion->is_snapshot = is_snapshot; + mcVersion->type = versionType; + tempList.append(mcVersion); + } + m_list->updateListData(tempList); + + emitSucceeded(); + return; +} + +// FIXME: we should have a local cache of the version list and a local cache of version data +bool MCVListLoadTask::loadFromVList() +{ +} diff --git a/logic/lists/MinecraftVersionList.h b/logic/lists/MinecraftVersionList.h new file mode 100644 index 00000000..0477379f --- /dev/null +++ b/logic/lists/MinecraftVersionList.h @@ -0,0 +1,83 @@ +/* Copyright 2013 Andrew Okin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include "InstVersionList.h" +#include "logic/tasks/Task.h" +#include "logic/MinecraftVersion.h" + +class MCVListLoadTask; +class QNetworkReply; + +class MinecraftVersionList : public InstVersionList +{ + Q_OBJECT +public: + friend class MCVListLoadTask; + + explicit MinecraftVersionList(QObject *parent = 0); + + virtual Task *getLoadTask(); + virtual bool isLoaded(); + virtual const InstVersionPtr at(int i) const; + virtual int count() const; + virtual void sort(); + + virtual InstVersionPtr getLatestStable() const; + + /*! + * Gets the main version list instance. + */ + static MinecraftVersionList &getMainList(); + + +protected: + QList m_vlist; + + bool m_loaded; + +protected slots: + virtual void updateListData(QList versions); +}; + +class MCVListLoadTask : public Task +{ + Q_OBJECT + +public: + explicit MCVListLoadTask(MinecraftVersionList *vlist); + ~MCVListLoadTask(); + + virtual void executeTask(); + +protected slots: + void list_downloaded(); + +protected: + //! Loads versions from Mojang's official version list. + bool loadFromVList(); + + QNetworkReply *vlistReply; + MinecraftVersionList *m_list; + MinecraftVersion *m_currentStable; + QSet legacyWhitelist; +}; + diff --git a/logic/net/DownloadJob.cpp b/logic/net/DownloadJob.cpp new file mode 100644 index 00000000..ef842dfd --- /dev/null +++ b/logic/net/DownloadJob.cpp @@ -0,0 +1,138 @@ +#include "DownloadJob.h" +#include "pathutils.h" +#include "NetWorker.h" + +DownloadJob::DownloadJob (QUrl url, + QString target_path, + QString expected_md5 ) + :Job() +{ + m_url = url; + m_target_path = target_path; + m_expected_md5 = expected_md5; + + m_check_md5 = m_expected_md5.size(); + m_save_to_file = m_target_path.size(); + m_status = Job_NotStarted; + m_opened_for_saving = false; +} + +JobPtr DownloadJob::create (QUrl url, + QString target_path, + QString expected_md5 ) +{ + return JobPtr ( new DownloadJob ( url, target_path, expected_md5 ) ); +} + +void DownloadJob::start() +{ + if ( m_save_to_file ) + { + QString filename = m_target_path; + m_output_file.setFileName ( filename ); + // if there already is a file and md5 checking is in effect and it can be opened + if ( m_output_file.exists() && m_output_file.open ( QIODevice::ReadOnly ) ) + { + // check the md5 against the expected one + QString hash = QCryptographicHash::hash ( m_output_file.readAll(), QCryptographicHash::Md5 ).toHex().constData(); + m_output_file.close(); + // skip this file if they match + if ( m_check_md5 && hash == m_expected_md5 ) + { + qDebug() << "Skipping " << m_url.toString() << ": md5 match."; + emit finish(); + return; + } + else + { + m_expected_md5 = hash; + } + } + if(!ensurePathExists(filename)) + { + emit fail(); + return; + } + } + qDebug() << "Downloading " << m_url.toString(); + QNetworkRequest request ( m_url ); + request.setRawHeader(QString("If-None-Match").toLatin1(), m_expected_md5.toLatin1()); + + auto &worker = NetWorker::spawn(); + QNetworkReply * rep = worker.get ( request ); + + m_reply = QSharedPointer ( rep, &QObject::deleteLater ); + connect ( rep, SIGNAL ( downloadProgress ( qint64,qint64 ) ), SLOT ( downloadProgress ( qint64,qint64 ) ) ); + connect ( rep, SIGNAL ( finished() ), SLOT ( downloadFinished() ) ); + connect ( rep, SIGNAL ( error ( QNetworkReply::NetworkError ) ), SLOT ( downloadError ( QNetworkReply::NetworkError ) ) ); + connect ( rep, SIGNAL ( readyRead() ), SLOT ( downloadReadyRead() ) ); +} + +void DownloadJob::downloadProgress ( qint64 bytesReceived, qint64 bytesTotal ) +{ + emit progress ( bytesReceived, bytesTotal ); +} + +void DownloadJob::downloadError ( QNetworkReply::NetworkError error ) +{ + // error happened during download. + // TODO: log the reason why + m_status = Job_Failed; +} + +void DownloadJob::downloadFinished() +{ + // if the download succeeded + if ( m_status != Job_Failed ) + { + // nothing went wrong... + m_status = Job_Finished; + // save the data to the downloadable if we aren't saving to file + if ( !m_save_to_file ) + { + m_data = m_reply->readAll(); + } + else + { + m_output_file.close(); + } + + //TODO: check md5 here! + m_reply.clear(); + emit finish(); + return; + } + // else the download failed + else + { + if ( m_save_to_file ) + { + m_output_file.close(); + m_output_file.remove(); + } + m_reply.clear(); + emit fail(); + return; + } +} + +void DownloadJob::downloadReadyRead() +{ + if( m_save_to_file ) + { + if(!m_opened_for_saving) + { + if ( !m_output_file.open ( QIODevice::WriteOnly ) ) + { + /* + * Can't open the file... the job failed + */ + m_reply->abort(); + emit fail(); + return; + } + m_opened_for_saving = true; + } + m_output_file.write ( m_reply->readAll() ); + } +} diff --git a/logic/net/DownloadJob.h b/logic/net/DownloadJob.h new file mode 100644 index 00000000..cbde3852 --- /dev/null +++ b/logic/net/DownloadJob.h @@ -0,0 +1,51 @@ +#pragma once +#include "JobQueue.h" +#include + +/** + * A single file for the downloader/cache to process. + */ +class LIBUTIL_EXPORT DownloadJob : public Job +{ + Q_OBJECT +public: + DownloadJob(QUrl url, + QString rel_target_path = QString(), + QString expected_md5 = QString() + ); + static JobPtr create(QUrl url, QString rel_target_path = QString(), QString expected_md5 = QString()); +public slots: + virtual void start(); + +private slots: + void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);; + void downloadError(QNetworkReply::NetworkError error); + void downloadFinished(); + void downloadReadyRead(); + +public: + /// the network reply + QSharedPointer m_reply; + /// source URL + QUrl m_url; + + /// if true, check the md5sum against a provided md5sum + /// also, if a file exists, perform an md5sum first and don't download only if they don't match + bool m_check_md5; + /// the expected md5 checksum + QString m_expected_md5; + + /// save to file? + bool m_save_to_file; + /// is the saving file already open? + bool m_opened_for_saving; + /// if saving to file, use the one specified in this string + QString m_target_path; + /// this is the output file, if any + QFile m_output_file; + /// if not saving to file, downloaded data is placed here + QByteArray m_data; + + /// The file's status + JobStatus m_status; +}; diff --git a/logic/net/JobQueue.h b/logic/net/JobQueue.h new file mode 100644 index 00000000..26f49307 --- /dev/null +++ b/logic/net/JobQueue.h @@ -0,0 +1,180 @@ +#pragma once +#include +#include "libutil_config.h" + +enum JobStatus +{ + Job_NotStarted, + Job_InProgress, + Job_Finished, + Job_Failed +}; + +class JobList; + +class LIBUTIL_EXPORT Job : public QObject +{ + Q_OBJECT +protected: + explicit Job(): QObject(0){}; +public: + virtual ~Job() {}; +signals: + void finish(); + void fail(); + void progress(qint64 current, qint64 total); +public slots: + virtual void start() = 0; +}; +typedef QSharedPointer JobPtr; + +/** + * A list of jobs, to be processed one by one. + */ +class LIBUTIL_EXPORT JobList : public QObject +{ + friend class JobListQueue; + Q_OBJECT +public: + + JobList() : QObject(0) + { + m_status = Job_NotStarted; + current_job_idx = 0; + } + JobStatus getStatus() + { + return m_status; + } + void add(JobPtr dlable) + { + if(m_status == Job_NotStarted) + m_jobs.append(dlable); + //else there's a bug. TODO: catch the bugs + } + JobPtr getFirstJob() + { + if(m_jobs.size()) + return m_jobs[0]; + else + return JobPtr(); + } + void start() + { + current_job_idx = 0; + auto job = m_jobs[current_job_idx]; + + connect(job.data(), SIGNAL(progress(qint64,qint64)), SLOT(currentJobProgress(qint64,qint64))); + connect(job.data(), SIGNAL(finish()), SLOT(currentJobFinished())); + connect(job.data(), SIGNAL(fail()), SLOT(currentJobFailed())); + job->start(); + emit started(); + } +private slots: + void currentJobFinished() + { + if(current_job_idx == m_jobs.size() - 1) + { + m_status = Job_Finished; + emit finished(); + } + else + { + current_job_idx++; + auto job = m_jobs[current_job_idx]; + connect(job.data(), SIGNAL(progress(qint64,qint64)), SLOT(currentJobProgress(qint64,qint64))); + connect(job.data(), SIGNAL(finish()), SLOT(currentJobFinished())); + connect(job.data(), SIGNAL(fail()), SLOT(currentJobFailed())); + job->start(); + } + } + void currentJobFailed() + { + m_status = Job_Failed; + emit failed(); + } + void currentJobProgress(qint64 current, qint64 total) + { + if(!total) + return; + + int total_jobs = m_jobs.size(); + + if(!total_jobs) + return; + + float job_chunk = 1000.0 / float(total_jobs); + float cur = current; + float tot = total; + float last_chunk = (cur / tot) * job_chunk; + + float list_total = job_chunk * current_job_idx + last_chunk; + emit progress(qint64(list_total), 1000LL); + } +private: + QVector m_jobs; + /// The overall status of this job list + JobStatus m_status; + int current_job_idx; +signals: + void progress(qint64 current, qint64 total); + void started(); + void finished(); + void failed(); +}; +typedef QSharedPointer JobListPtr; + + +/** + * A queue of job lists! The job lists fail or finish as units. + */ +class LIBUTIL_EXPORT JobListQueue : public QObject +{ + Q_OBJECT +public: + JobListQueue(QObject *p = 0): + QObject(p), + currentIndex(0), + is_running(false){} + + void enqueue(JobListPtr job) + { + jobs.enqueue(job); + + // finish or fail, we should catch that and start the next one + connect(job.data(),SIGNAL(finished()), SLOT(startNextJob())); + connect(job.data(),SIGNAL(failed()), SLOT(startNextJob())); + + if(!is_running) + { + QTimer::singleShot(0, this, SLOT(startNextJob())); + } + } + +private slots: + void startNextJob() + { + if (jobs.isEmpty()) + { + currentJobList.clear(); + currentIndex = 0; + is_running = false; + emit finishedAllJobs(); + return; + } + + currentJobList = jobs.dequeue(); + is_running = true; + currentIndex = 0; + currentJobList->start(); + } + +signals: + void finishedAllJobs(); + +private: + JobListPtr currentJobList; + QQueue jobs; + unsigned currentIndex; + bool is_running; +}; diff --git a/logic/net/NetWorker.cpp b/logic/net/NetWorker.cpp new file mode 100644 index 00000000..1eef13d9 --- /dev/null +++ b/logic/net/NetWorker.cpp @@ -0,0 +1,12 @@ +#include "NetWorker.h" +#include + +NetWorker& NetWorker::spawn() +{ + static QThreadStorage storage; + if (!storage.hasLocalData()) + { + storage.setLocalData(new NetWorker()); + } + return *storage.localData(); +} diff --git a/logic/net/NetWorker.h b/logic/net/NetWorker.h new file mode 100644 index 00000000..98374e3b --- /dev/null +++ b/logic/net/NetWorker.h @@ -0,0 +1,20 @@ +/* + _.ooo-._ + .OOOP _ '. + dOOOO (_) \ + OOOOOb | + OOOOOOb. | + OOOOOOOOb | + YOO(_)OOO / + 'OOOOOY _.' + '""""'' +*/ + +#pragma once +#include +class NetWorker : public QNetworkAccessManager +{ + Q_OBJECT +public: + static NetWorker &spawn(); +}; \ No newline at end of file diff --git a/logic/tasks/LoginTask.cpp b/logic/tasks/LoginTask.cpp new file mode 100644 index 00000000..21ac2a5d --- /dev/null +++ b/logic/tasks/LoginTask.cpp @@ -0,0 +1,111 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LoginTask.h" +#include "logic/net/NetWorker.h" + +#include + +#include +#include + +#include +#include + +LoginTask::LoginTask( const UserInfo& uInfo, QObject* parent ) : Task(parent), uInfo(uInfo){} + +void LoginTask::executeTask() +{ + setStatus("Logging in..."); + auto & worker = NetWorker::spawn(); + connect(&worker, SIGNAL(finished(QNetworkReply*)), this, SLOT(processNetReply(QNetworkReply*))); + + QUrl loginURL("https://login.minecraft.net/"); + QNetworkRequest netRequest(loginURL); + netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + + QUrlQuery params; + params.addQueryItem("user", uInfo.username); + params.addQueryItem("password", uInfo.password); + params.addQueryItem("version", "13"); + + netReply = worker.post(netRequest, params.query(QUrl::EncodeSpaces).toUtf8()); +} + +void LoginTask::processNetReply(QNetworkReply *reply) +{ + if(netReply != reply) + return; + // Check for errors. + switch (reply->error()) + { + case QNetworkReply::NoError: + { + // Check the response code. + int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (responseCode == 200) + { + QString responseStr(reply->readAll()); + + QStringList strings = responseStr.split(":"); + if (strings.count() >= 4) + { + bool parseSuccess; + qint64 latestVersion = strings[0].toLongLong(&parseSuccess); + if (parseSuccess) + { + // strings[1] is the download ticket. It isn't used anymore. + QString username = strings[2]; + QString sessionID = strings[3]; + + result = {username, sessionID, latestVersion}; + emitSucceeded(); + } + else + { + emitFailed("Failed to parse Minecraft version string."); + } + } + else + { + if (responseStr.toLower() == "bad login") + emitFailed("Invalid username or password."); + else if (responseStr.toLower() == "old version") + emitFailed("Launcher outdated, please update."); + else + emitFailed("Login failed: " + responseStr); + } + } + else if (responseCode == 503) + { + emitFailed("The login servers are currently unavailable. Check http://help.mojang.com/ for more info."); + } + else + { + emitFailed(QString("Login failed: Unknown HTTP error %1 occurred.").arg(QString::number(responseCode))); + } + break; + } + + case QNetworkReply::OperationCanceledError: + emitFailed("Login canceled."); + break; + + default: + emitFailed("Login failed: " + reply->errorString()); + break; + } +} diff --git a/logic/tasks/LoginTask.h b/logic/tasks/LoginTask.h new file mode 100644 index 00000000..bde672b8 --- /dev/null +++ b/logic/tasks/LoginTask.h @@ -0,0 +1,58 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOGINTASK_H +#define LOGINTASK_H + +#include "Task.h" +#include + +struct UserInfo +{ + QString username; + QString password; +}; + +struct LoginResponse +{ + QString username; + QString sessionID; + qint64 latestVersion; +}; + +class QNetworkReply; + +class LoginTask : public Task +{ + Q_OBJECT +public: + explicit LoginTask(const UserInfo& uInfo, QObject *parent = 0); + LoginResponse getResult() + { + return result; + }; + +protected slots: + void processNetReply(QNetworkReply* reply); + +protected: + void executeTask(); + + LoginResponse result; + QNetworkReply* netReply; + UserInfo uInfo; +}; + +#endif // LOGINTASK_H diff --git a/logic/tasks/Task.cpp b/logic/tasks/Task.cpp new file mode 100644 index 00000000..7c148591 --- /dev/null +++ b/logic/tasks/Task.cpp @@ -0,0 +1,85 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Task.h" + +Task::Task(QObject *parent) : + QObject(parent) +{ + +} + +QString Task::getStatus() const +{ + return status; +} + +void Task::setStatus(const QString &status) +{ + this->status = status; + emitStatusChange(status); +} + +int Task::getProgress() const +{ + return progress; +} + +void Task::setProgress(int progress) +{ + this->progress = progress; + emitProgressChange(progress); +} + +void Task::startTask() +{ + emitStarted(); + executeTask(); +} + +void Task::emitStarted() +{ + running = true; + emit started(); +} + +void Task::emitFailed(QString reason) +{ + running = false; + emit failed(reason); +} + +void Task::emitSucceeded() +{ + running = false; + emit succeeded(); +} + + +bool Task::isRunning() const +{ + return running; +} + + +void Task::emitStatusChange(const QString &status) +{ + emit statusChanged(status); +} + +void Task::emitProgressChange(int progress) +{ + emit progressChanged(progress); +} diff --git a/logic/tasks/Task.h b/logic/tasks/Task.h new file mode 100644 index 00000000..91852b0f --- /dev/null +++ b/logic/tasks/Task.h @@ -0,0 +1,65 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TASK_H +#define TASK_H + +#include +#include + +class Task : public QObject +{ + Q_OBJECT +public: + explicit Task(QObject *parent = 0); + + QString getStatus() const; + int getProgress() const; + bool isRunning() const; + +public slots: + void startTask(); + +protected slots: + void setStatus(const QString& status); + void setProgress(int progress); + +signals: + void started(); + void failed(QString reason); + void succeeded(); + + void statusChanged(Task* task, const QString& status); + void progressChanged(Task* task, int progress); + + void statusChanged(const QString& status); + void progressChanged(int progress); + +protected: + virtual void executeTask() = 0; + + virtual void emitStarted(); + virtual void emitFailed(QString reason); + virtual void emitSucceeded(); + + virtual void emitStatusChange(const QString &status); + virtual void emitProgressChange(int progress); + + QString status; + int progress; + bool running = false; +}; + +#endif // TASK_H diff --git a/main.cpp b/main.cpp index eae6b4ba..72b0f225 100644 --- a/main.cpp +++ b/main.cpp @@ -27,9 +27,9 @@ #include "gui/consolewindow.h" #include "AppSettings.h" -#include "lists/InstanceList.h" -#include "tasks/LoginTask.h" -#include "MinecraftProcess.h" +#include "logic/lists/InstanceList.h" +#include "logic/tasks/LoginTask.h" +#include "logic/MinecraftProcess.h" #include "pathutils.h" #include "cmdutils.h" diff --git a/patchlib/CMakeLists.txt b/patchlib/CMakeLists.txt deleted file mode 100644 index 4130e08f..00000000 --- a/patchlib/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -project(patchlib C) - -set(SRCS -blocksort.c -huffman.c -crctable.c -randtable.c -compress.c -decompress.c -bzlib.c -bspatch.c -) - -add_library(patchlib STATIC ${SRCS}) diff --git a/patchlib/LICENSE-bzip2 b/patchlib/LICENSE-bzip2 deleted file mode 100644 index cc614178..00000000 --- a/patchlib/LICENSE-bzip2 +++ /dev/null @@ -1,42 +0,0 @@ - --------------------------------------------------------------------------- - -This program, "bzip2", the associated library "libbzip2", and all -documentation, are copyright (C) 1996-2010 Julian R Seward. All -rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - -3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - -4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS -OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Julian Seward, jseward@bzip.org -bzip2/libbzip2 version 1.0.6 of 6 September 2010 - --------------------------------------------------------------------------- diff --git a/patchlib/blocksort.c b/patchlib/blocksort.c deleted file mode 100644 index d63dbbf8..00000000 --- a/patchlib/blocksort.c +++ /dev/null @@ -1,1095 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Block sorting machinery ---*/ -/*--- blocksort.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*---------------------------------------------*/ -/*--- Fallback O(N log(N)^2) sorting ---*/ -/*--- algorithm, for repetitive blocks ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -void fallbackSimpleSort ( UInt32* fmap, - UInt32* eclass, - Int32 lo, - Int32 hi ) -{ - Int32 i, j, tmp; - UInt32 ec_tmp; - - if (lo == hi) return; - - if (hi - lo > 3) { - for ( i = hi-4; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) - fmap[j-4] = fmap[j]; - fmap[j-4] = tmp; - } - } - - for ( i = hi-1; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) - fmap[j-1] = fmap[j]; - fmap[j-1] = tmp; - } -} - - -/*---------------------------------------------*/ -#define fswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define fvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - fswap(fmap[yyp1], fmap[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - - -#define fmin(a,b) ((a) < (b)) ? (a) : (b) - -#define fpush(lz,hz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - sp++; } - -#define fpop(lz,hz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; } - -#define FALLBACK_QSORT_SMALL_THRESH 10 -#define FALLBACK_QSORT_STACK_SIZE 100 - - -static -void fallbackQSort3 ( UInt32* fmap, - UInt32* eclass, - Int32 loSt, - Int32 hiSt ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m; - Int32 sp, lo, hi; - UInt32 med, r, r3; - Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; - Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; - - r = 0; - - sp = 0; - fpush ( loSt, hiSt ); - - while (sp > 0) { - - AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); - - fpop ( lo, hi ); - if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { - fallbackSimpleSort ( fmap, eclass, lo, hi ); - continue; - } - - /* Random partitioning. Median of 3 sometimes fails to - avoid bad cases. Median of 9 seems to help but - looks rather expensive. This too seems to work but - is cheaper. Guidance for the magic constants - 7621 and 32768 is taken from Sedgewick's algorithms - book, chapter 35. - */ - r = ((r * 7621) + 1) % 32768; - r3 = r % 3; - if (r3 == 0) med = eclass[fmap[lo]]; else - if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else - med = eclass[fmap[hi]]; - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (1) { - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unLo]] - (Int32)med; - if (n == 0) { - fswap(fmap[unLo], fmap[ltLo]); - ltLo++; unLo++; - continue; - }; - if (n > 0) break; - unLo++; - } - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unHi]] - (Int32)med; - if (n == 0) { - fswap(fmap[unHi], fmap[gtHi]); - gtHi--; unHi--; - continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); - - if (gtHi < ltLo) continue; - - n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); - m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - if (n - lo > hi - m) { - fpush ( lo, n ); - fpush ( m, hi ); - } else { - fpush ( m, hi ); - fpush ( lo, n ); - } - } -} - -#undef fmin -#undef fpush -#undef fpop -#undef fswap -#undef fvswap -#undef FALLBACK_QSORT_SMALL_THRESH -#undef FALLBACK_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - eclass exists for [0 .. nblock-1] - ((UChar*)eclass) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)eclass) [0 .. nblock-1] holds block - All other areas of eclass destroyed - fmap [0 .. nblock-1] holds sorted order - bhtab [ 0 .. 2+(nblock/32) ] destroyed -*/ - -#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) -#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) -#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) -#define WORD_BH(zz) bhtab[(zz) >> 5] -#define UNALIGNED_BH(zz) ((zz) & 0x01f) - -static -void fallbackSort ( UInt32* fmap, - UInt32* eclass, - UInt32* bhtab, - Int32 nblock, - Int32 verb ) -{ - Int32 ftab[257]; - Int32 ftabCopy[256]; - Int32 H, i, j, k, l, r, cc, cc1; - Int32 nNotDone; - Int32 nBhtab; - UChar* eclass8 = (UChar*)eclass; - - /*-- - Initial 1-char radix sort to generate - initial fmap and initial BH bits. - --*/ - if (verb >= 4) - VPrintf0 ( " bucket sorting ...\n" ); - for (i = 0; i < 257; i++) ftab[i] = 0; - for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; - for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; - for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; - - for (i = 0; i < nblock; i++) { - j = eclass8[i]; - k = ftab[j] - 1; - ftab[j] = k; - fmap[k] = i; - } - - nBhtab = 2 + (nblock / 32); - for (i = 0; i < nBhtab; i++) bhtab[i] = 0; - for (i = 0; i < 256; i++) SET_BH(ftab[i]); - - /*-- - Inductively refine the buckets. Kind-of an - "exponential radix sort" (!), inspired by the - Manber-Myers suffix array construction algorithm. - --*/ - - /*-- set sentinel bits for block-end detection --*/ - for (i = 0; i < 32; i++) { - SET_BH(nblock + 2*i); - CLEAR_BH(nblock + 2*i + 1); - } - - /*-- the log(N) loop --*/ - H = 1; - while (1) { - - if (verb >= 4) - VPrintf1 ( " depth %6d has ", H ); - - j = 0; - for (i = 0; i < nblock; i++) { - if (ISSET_BH(i)) j = i; - k = fmap[i] - H; if (k < 0) k += nblock; - eclass[k] = j; - } - - nNotDone = 0; - r = -1; - while (1) { - - /*-- find the next non-singleton bucket --*/ - k = r + 1; - while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (ISSET_BH(k)) { - while (WORD_BH(k) == 0xffffffff) k += 32; - while (ISSET_BH(k)) k++; - } - l = k - 1; - if (l >= nblock) break; - while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (!ISSET_BH(k)) { - while (WORD_BH(k) == 0x00000000) k += 32; - while (!ISSET_BH(k)) k++; - } - r = k - 1; - if (r >= nblock) break; - - /*-- now [l, r] bracket current bucket --*/ - if (r > l) { - nNotDone += (r - l + 1); - fallbackQSort3 ( fmap, eclass, l, r ); - - /*-- scan bucket and generate header bits-- */ - cc = -1; - for (i = l; i <= r; i++) { - cc1 = eclass[fmap[i]]; - if (cc != cc1) { SET_BH(i); cc = cc1; }; - } - } - } - - if (verb >= 4) - VPrintf1 ( "%6d unresolved strings\n", nNotDone ); - - H *= 2; - if (H > nblock || nNotDone == 0) break; - } - - /*-- - Reconstruct the original block in - eclass8 [0 .. nblock-1], since the - previous phase destroyed it. - --*/ - if (verb >= 4) - VPrintf0 ( " reconstructing block ...\n" ); - j = 0; - for (i = 0; i < nblock; i++) { - while (ftabCopy[j] == 0) j++; - ftabCopy[j]--; - eclass8[fmap[i]] = (UChar)j; - } - AssertH ( j < 256, 1005 ); -} - -#undef SET_BH -#undef CLEAR_BH -#undef ISSET_BH -#undef WORD_BH -#undef UNALIGNED_BH - - -/*---------------------------------------------*/ -/*--- The main, O(N^2 log(N)) sorting ---*/ -/*--- algorithm. Faster for "normal" ---*/ -/*--- non-repetitive blocks. ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -Bool mainGtU ( UInt32 i1, - UInt32 i2, - UChar* block, - UInt16* quadrant, - UInt32 nblock, - Int32* budget ) -{ - Int32 k; - UChar c1, c2; - UInt16 s1, s2; - - AssertD ( i1 != i2, "mainGtU" ); - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 9 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 10 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 11 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 12 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - - k = nblock + 8; - - do { - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - - if (i1 >= nblock) i1 -= nblock; - if (i2 >= nblock) i2 -= nblock; - - k -= 8; - (*budget)--; - } - while (k >= 0); - - return False; -} - - -/*---------------------------------------------*/ -/*-- - Knuth's increments seem to work better - than Incerpi-Sedgewick here. Possibly - because the number of elems to sort is - usually small, typically <= 20. ---*/ -static -Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, - 9841, 29524, 88573, 265720, - 797161, 2391484 }; - -static -void mainSimpleSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 lo, - Int32 hi, - Int32 d, - Int32* budget ) -{ - Int32 i, j, h, bigN, hp; - UInt32 v; - - bigN = hi - lo + 1; - if (bigN < 2) return; - - hp = 0; - while (incs[hp] < bigN) hp++; - hp--; - - for (; hp >= 0; hp--) { - h = incs[hp]; - - i = lo + h; - while (True) { - - /*-- copy 1 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 2 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 3 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - if (*budget < 0) return; - } - } -} - - -/*---------------------------------------------*/ -/*-- - The following is an implementation of - an elegant 3-way quicksort for strings, - described in a paper "Fast Algorithms for - Sorting and Searching Strings", by Robert - Sedgewick and Jon L. Bentley. ---*/ - -#define mswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define mvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - mswap(ptr[yyp1], ptr[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - -static -__inline__ -UChar mmed3 ( UChar a, UChar b, UChar c ) -{ - UChar t; - if (a > b) { t = a; a = b; b = t; }; - if (b > c) { - b = c; - if (a > b) b = a; - } - return b; -} - -#define mmin(a,b) ((a) < (b)) ? (a) : (b) - -#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - stackD [sp] = dz; \ - sp++; } - -#define mpop(lz,hz,dz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; \ - dz = stackD [sp]; } - - -#define mnextsize(az) (nextHi[az]-nextLo[az]) - -#define mnextswap(az,bz) \ - { Int32 tz; \ - tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ - tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ - tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } - - -#define MAIN_QSORT_SMALL_THRESH 20 -#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) -#define MAIN_QSORT_STACK_SIZE 100 - -static -void mainQSort3 ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 loSt, - Int32 hiSt, - Int32 dSt, - Int32* budget ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m, med; - Int32 sp, lo, hi, d; - - Int32 stackLo[MAIN_QSORT_STACK_SIZE]; - Int32 stackHi[MAIN_QSORT_STACK_SIZE]; - Int32 stackD [MAIN_QSORT_STACK_SIZE]; - - Int32 nextLo[3]; - Int32 nextHi[3]; - Int32 nextD [3]; - - sp = 0; - mpush ( loSt, hiSt, dSt ); - - while (sp > 0) { - - AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); - - mpop ( lo, hi, d ); - if (hi - lo < MAIN_QSORT_SMALL_THRESH || - d > MAIN_QSORT_DEPTH_THRESH) { - mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); - if (*budget < 0) return; - continue; - } - - med = (Int32) - mmed3 ( block[ptr[ lo ]+d], - block[ptr[ hi ]+d], - block[ptr[ (lo+hi)>>1 ]+d] ); - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (True) { - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unLo]+d]) - med; - if (n == 0) { - mswap(ptr[unLo], ptr[ltLo]); - ltLo++; unLo++; continue; - }; - if (n > 0) break; - unLo++; - } - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unHi]+d]) - med; - if (n == 0) { - mswap(ptr[unHi], ptr[gtHi]); - gtHi--; unHi--; continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "mainQSort3(2)" ); - - if (gtHi < ltLo) { - mpush(lo, hi, d+1 ); - continue; - } - - n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); - m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; - nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; - nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; - - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - - AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); - AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); - - mpush (nextLo[0], nextHi[0], nextD[0]); - mpush (nextLo[1], nextHi[1], nextD[1]); - mpush (nextLo[2], nextHi[2], nextD[2]); - } -} - -#undef mswap -#undef mvswap -#undef mpush -#undef mpop -#undef mmin -#undef mnextsize -#undef mnextswap -#undef MAIN_QSORT_SMALL_THRESH -#undef MAIN_QSORT_DEPTH_THRESH -#undef MAIN_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > N_OVERSHOOT - block32 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)block32) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)block32) [0 .. nblock-1] holds block - All other areas of block32 destroyed - ftab [0 .. 65536 ] destroyed - ptr [0 .. nblock-1] holds sorted order - if (*budget < 0), sorting was abandoned -*/ - -#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) -#define SETMASK (1 << 21) -#define CLEARMASK (~(SETMASK)) - -static -void mainSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - UInt32* ftab, - Int32 nblock, - Int32 verb, - Int32* budget ) -{ - Int32 i, j, k, ss, sb; - Int32 runningOrder[256]; - Bool bigDone[256]; - Int32 copyStart[256]; - Int32 copyEnd [256]; - UChar c1; - Int32 numQSorted; - UInt16 s; - if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); - - /*-- set up the 2-byte frequency table --*/ - for (i = 65536; i >= 0; i--) ftab[i] = 0; - - j = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - quadrant[i-1] = 0; - j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); - ftab[j]++; - quadrant[i-2] = 0; - j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); - ftab[j]++; - quadrant[i-3] = 0; - j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); - ftab[j]++; - } - for (; i >= 0; i--) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - } - - /*-- (emphasises close relationship of block & quadrant) --*/ - for (i = 0; i < BZ_N_OVERSHOOT; i++) { - block [nblock+i] = block[i]; - quadrant[nblock+i] = 0; - } - - if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); - - /*-- Complete the initial radix sort --*/ - for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; - - s = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - s = (s >> 8) | (block[i-1] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-1; - s = (s >> 8) | (block[i-2] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-2; - s = (s >> 8) | (block[i-3] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-3; - } - for (; i >= 0; i--) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - } - - /*-- - Now ftab contains the first loc of every small bucket. - Calculate the running order, from smallest to largest - big bucket. - --*/ - for (i = 0; i <= 255; i++) { - bigDone [i] = False; - runningOrder[i] = i; - } - - { - Int32 vv; - Int32 h = 1; - do h = 3 * h + 1; while (h <= 256); - do { - h = h / 3; - for (i = h; i <= 255; i++) { - vv = runningOrder[i]; - j = i; - while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { - runningOrder[j] = runningOrder[j-h]; - j = j - h; - if (j <= (h - 1)) goto zero; - } - zero: - runningOrder[j] = vv; - } - } while (h != 1); - } - - /*-- - The main sorting loop. - --*/ - - numQSorted = 0; - - for (i = 0; i <= 255; i++) { - - /*-- - Process big buckets, starting with the least full. - Basically this is a 3-step process in which we call - mainQSort3 to sort the small buckets [ss, j], but - also make a big effort to avoid the calls if we can. - --*/ - ss = runningOrder[i]; - - /*-- - Step 1: - Complete the big bucket [ss] by quicksorting - any unsorted small buckets [ss, j], for j != ss. - Hopefully previous pointer-scanning phases have already - completed many of the small buckets [ss, j], so - we don't have to sort them at all. - --*/ - for (j = 0; j <= 255; j++) { - if (j != ss) { - sb = (ss << 8) + j; - if ( ! (ftab[sb] & SETMASK) ) { - Int32 lo = ftab[sb] & CLEARMASK; - Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; - if (hi > lo) { - if (verb >= 4) - VPrintf4 ( " qsort [0x%x, 0x%x] " - "done %d this %d\n", - ss, j, numQSorted, hi - lo + 1 ); - mainQSort3 ( - ptr, block, quadrant, nblock, - lo, hi, BZ_N_RADIX, budget - ); - numQSorted += (hi - lo + 1); - if (*budget < 0) return; - } - } - ftab[sb] |= SETMASK; - } - } - - AssertH ( !bigDone[ss], 1006 ); - - /*-- - Step 2: - Now scan this big bucket [ss] so as to synthesise the - sorted order for small buckets [t, ss] for all t, - including, magically, the bucket [ss,ss] too. - This will avoid doing Real Work in subsequent Step 1's. - --*/ - { - for (j = 0; j <= 255; j++) { - copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; - copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; - } - for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyStart[c1]++ ] = k; - } - for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyEnd[c1]-- ] = k; - } - } - - AssertH ( (copyStart[ss]-1 == copyEnd[ss]) - || - /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. - Necessity for this case is demonstrated by compressing - a sequence of approximately 48.5 million of character - 251; 1.0.0/1.0.1 will then die here. */ - (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), - 1007 ) - - for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; - - /*-- - Step 3: - The [ss] big bucket is now done. Record this fact, - and update the quadrant descriptors. Remember to - update quadrants in the overshoot area too, if - necessary. The "if (i < 255)" test merely skips - this updating for the last bucket processed, since - updating for the last bucket is pointless. - - The quadrant array provides a way to incrementally - cache sort orderings, as they appear, so as to - make subsequent comparisons in fullGtU() complete - faster. For repetitive blocks this makes a big - difference (but not big enough to be able to avoid - the fallback sorting mechanism, exponential radix sort). - - The precise meaning is: at all times: - - for 0 <= i < nblock and 0 <= j <= nblock - - if block[i] != block[j], - - then the relative values of quadrant[i] and - quadrant[j] are meaningless. - - else { - if quadrant[i] < quadrant[j] - then the string starting at i lexicographically - precedes the string starting at j - - else if quadrant[i] > quadrant[j] - then the string starting at j lexicographically - precedes the string starting at i - - else - the relative ordering of the strings starting - at i and j has not yet been determined. - } - --*/ - bigDone[ss] = True; - - if (i < 255) { - Int32 bbStart = ftab[ss << 8] & CLEARMASK; - Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; - Int32 shifts = 0; - - while ((bbSize >> shifts) > 65534) shifts++; - - for (j = bbSize-1; j >= 0; j--) { - Int32 a2update = ptr[bbStart + j]; - UInt16 qVal = (UInt16)(j >> shifts); - quadrant[a2update] = qVal; - if (a2update < BZ_N_OVERSHOOT) - quadrant[a2update + nblock] = qVal; - } - AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); - } - - } - - if (verb >= 4) - VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", - nblock, numQSorted, nblock - numQSorted ); -} - -#undef BIGFREQ -#undef SETMASK -#undef CLEARMASK - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)arr2) [0 .. nblock-1] holds block - arr1 exists for [0 .. nblock-1] - - Post: - ((UChar*)arr2) [0 .. nblock-1] holds block - All other areas of block destroyed - ftab [ 0 .. 65536 ] destroyed - arr1 [0 .. nblock-1] holds sorted order -*/ -void BZ2_blockSort ( EState* s ) -{ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt32* ftab = s->ftab; - Int32 nblock = s->nblock; - Int32 verb = s->verbosity; - Int32 wfact = s->workFactor; - UInt16* quadrant; - Int32 budget; - Int32 budgetInit; - Int32 i; - - if (nblock < 10000) { - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } else { - /* Calculate the location for quadrant, remembering to get - the alignment right. Assumes that &(block[0]) is at least - 2-byte aligned -- this should be ok since block is really - the first section of arr2. - */ - i = nblock+BZ_N_OVERSHOOT; - if (i & 1) i++; - quadrant = (UInt16*)(&(block[i])); - - /* (wfact-1) / 3 puts the default-factor-30 - transition point at very roughly the same place as - with v0.1 and v0.9.0. - Not that it particularly matters any more, since the - resulting compressed stream is now the same regardless - of whether or not we use the main sort or fallback sort. - */ - if (wfact < 1 ) wfact = 1; - if (wfact > 100) wfact = 100; - budgetInit = nblock * ((wfact-1) / 3); - budget = budgetInit; - - mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); - if (verb >= 3) - VPrintf3 ( " %d work, %d block, ratio %5.2f\n", - budgetInit - budget, - nblock, - (float)(budgetInit - budget) / - (float)(nblock==0 ? 1 : nblock) ); - if (budget < 0) { - if (verb >= 2) - VPrintf0 ( " too repetitive; using fallback" - " sorting algorithm\n" ); - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } - } - - s->origPtr = -1; - for (i = 0; i < s->nblock; i++) - if (ptr[i] == 0) - { s->origPtr = i; break; }; - - AssertH( s->origPtr != -1, 1003 ); -} - - -/*-------------------------------------------------------------*/ -/*--- end blocksort.c ---*/ -/*-------------------------------------------------------------*/ - diff --git a/patchlib/bspatch.c b/patchlib/bspatch.c deleted file mode 100644 index e8469edc..00000000 --- a/patchlib/bspatch.c +++ /dev/null @@ -1,303 +0,0 @@ -/*- - * Copyright 2003-2005 Colin Percival - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef _MSC_VER - // bogus 'secure' nonsense - #define _CRT_SECURE_NO_WARNINGS - // bogus signed/unsigned mismatch - #pragma warning( disable: 4018) -#endif - -#ifdef _WIN32 - #include - #define ssize_t size_t -#else - #include -#endif - -#if defined __APPLE__ && defined __MACH__ - typedef unsigned char u_char; -#endif - -#include "bzlib.h" -#include "bspatch.h" -#include -#include -#include -#include - -static off_t offtin(u_char *buf) -{ - off_t y; - - y=buf[7]&0x7F; - y=y*256;y+=buf[6]; - y=y*256;y+=buf[5]; - y=y*256;y+=buf[4]; - y=y*256;y+=buf[3]; - y=y*256;y+=buf[2]; - y=y*256;y+=buf[1]; - y=y*256;y+=buf[0]; - - if(buf[7]&0x80) y=-y; - - return y; -} - -int bspatch(const char * oldfile, const char * newfile, const char * patchfile) -{ - FILE * f, * cpf, * dpf, * epf; - BZFILE * cpfbz2, * dpfbz2, * epfbz2; - int cbz2err, dbz2err, ebz2err; - FILE * temp; - ssize_t oldsize,newsize; - ssize_t bzctrllen,bzdatalen; - unsigned char header[32],buf[8]; - unsigned char *old_contents; - unsigned char *new_contents; - off_t oldpos,newpos; - off_t ctrl[3]; - off_t lenread; - off_t i; - - /* Open patch file */ - if ((f = fopen(patchfile, "rb")) == NULL) - { - //err(1, "fopen(%s)", argv[3]); - return ERR_OTHER; - } - - /* - File format: - 0 8 "BSDIFF40" - 8 8 X - 16 8 Y - 24 8 sizeof(newfile) - 32 X bzip2(control block) - 32+X Y bzip2(diff block) - 32+X+Y ??? bzip2(extra block) - with control block a set of triples (x,y,z) meaning "add x bytes - from oldfile to x bytes from the diff block; copy y bytes from the - extra block; seek forwards in oldfile by z bytes". - */ - - /* Read header */ - if (fread(header, 1, 32, f) < 32) - { - if (feof(f)) - { - //errx(1, "Corrupt patch\n"); - return ERR_CORRUPT_PATCH; - } - //err(1, "fread(%s)", argv[3]); - return ERR_OTHER; - } - - /* Check for appropriate magic */ - if (memcmp(header, "BSDIFF40", 8) != 0) - { - //errx(1, "Corrupt patch\n"); - return ERR_CORRUPT_PATCH; - } - - /* Read lengths from header */ - bzctrllen=offtin(header+8); - bzdatalen=offtin(header+16); - newsize=offtin(header+24); - if((bzctrllen<0) || (bzdatalen<0) || (newsize<0)) - { - //errx(1,"Corrupt patch\n"); - return ERR_CORRUPT_PATCH; - } - - /* Close patch file and re-open it via libbzip2 at the right places */ - if (fclose(f)) - { - //err(1, "fclose(%s)", argv[3]); - return ERR_OTHER; - } - if ((cpf = fopen(patchfile, "rb")) == NULL) - { - //err(1, "fopen(%s)", argv[3]); - return ERR_OTHER; - } - if (fseek(cpf, 32, SEEK_SET)) - { - // err(1, "fseeko(%s, %lld)", argv[3], (long long)32); - return ERR_OTHER; - } - if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL) - { - //errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err); - return ERR_OTHER; - } - if ((dpf = fopen(patchfile, "rb")) == NULL) - { - //err(1, "fopen(%s)", argv[3]); - return ERR_OTHER; - } - if (fseek(dpf, 32 + bzctrllen, SEEK_SET)) - { - //err(1, "fseeko(%s, %lld)", argv[3], (long long)(32 + bzctrllen)); - return ERR_OTHER; - } - if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL) - { - //errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err); - return ERR_OTHER; - } - if ((epf = fopen(patchfile, "rb")) == NULL) - { - //err(1, "fopen(%s)", argv[3]); - return ERR_OTHER; - } - if (fseek(epf, 32 + bzctrllen + bzdatalen, SEEK_SET)) - { - //err(1, "fseeko(%s, %lld)", argv[3], (long long)(32 + bzctrllen + bzdatalen)); - return ERR_OTHER; - } - if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL) - { - //errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err); - return ERR_OTHER; - } - - if((temp=fopen(oldfile,"rb")) == NULL) - { - return ERR_OTHER; - } - if((fseek(temp,0,SEEK_END))!=0) - { - return ERR_OTHER; - } - oldsize = ftell(temp); - if((old_contents=malloc(oldsize+1))==NULL) - { - return ERR_OTHER; - } - rewind(temp); - if(fread(old_contents,oldsize,1,temp)!=1) - { - return ERR_OTHER; - } - if(fclose(temp)==EOF) - { - return ERR_OTHER; - } - if((new_contents=malloc(newsize+1))==NULL) - { - //err(1,NULL); - return ERR_OTHER; - } - - oldpos=0;newpos=0; - while(newposnewsize) - { - //errx(1,"Corrupt patch\n"); - return ERR_CORRUPT_PATCH; - } - - /* Read diff string */ - lenread = BZ2_bzRead(&dbz2err, dpfbz2, new_contents + newpos, ctrl[0]); - if ((lenread < ctrl[0]) || ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END))) - { - //errx(1, "Corrupt patch\n"); - return ERR_CORRUPT_PATCH; - } - - /* Add old data to diff string */ - for(i=0;i=0) && (oldpos+inewsize) - { - //errx(1,"Corrupt patch\n"); - return ERR_CORRUPT_PATCH; - } - - /* Read extra string */ - lenread = BZ2_bzRead(&ebz2err, epfbz2, new_contents + newpos, ctrl[1]); - if ((lenread < ctrl[1]) || ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END))) - { - //errx(1, "Corrupt patch\n"); - return ERR_CORRUPT_PATCH; - } - - /* Adjust pointers */ - newpos+=ctrl[1]; - oldpos+=ctrl[2]; - }; - - /* Clean up the bzip2 reads */ - BZ2_bzReadClose(&cbz2err, cpfbz2); - BZ2_bzReadClose(&dbz2err, dpfbz2); - BZ2_bzReadClose(&ebz2err, epfbz2); - if (fclose(cpf) || fclose(dpf) || fclose(epf)) - { - //err(1, "fclose(%s)", argv[3]); - return ERR_OTHER; - } - - /* Write the new file */ - if( - ((temp=fopen(newfile,"wb"))==NULL) || - (fwrite(new_contents,newsize,1,temp)==0) || - (fclose(temp)==EOF) - ) - { - //err(1,"%s",argv[2]); - return ERR_OTHER; - } - - free(new_contents); - free(old_contents); - - return ERR_NONE; -} diff --git a/patchlib/bspatch.h b/patchlib/bspatch.h deleted file mode 100644 index efb83ee5..00000000 --- a/patchlib/bspatch.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _BSPATCH_H -#define _BSPATCH_H - -#ifdef __cplusplus -extern "C" { -#endif - -enum BSPatchError -{ - ERR_CORRUPT_PATCH, - ERR_OTHER, - ERR_NONE, -}; - -/** - * patch oldfile by using patchfile and write the output to newfile. - * - * Returns ERR_NONE if successful - */ -int bspatch(const char * oldfile, const char * newfile, const char * patchfile); - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/patchlib/bzlib.c b/patchlib/bzlib.c deleted file mode 100644 index e2994b44..00000000 --- a/patchlib/bzlib.c +++ /dev/null @@ -1,1579 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Library top-level functions. ---*/ -/*--- bzlib.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - -/* CHANGES - 0.9.0 -- original version. - 0.9.0a/b -- no changes in this file. - 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). - fixed bzWrite/bzRead to ignore zero-length requests. - fixed bzread to correctly handle read requests after EOF. - wrong parameter order in call to bzDecompressInit in - bzBuffToBuffDecompress. Fixed. -*/ - -#ifdef _MSC_VER - //'function': was declared deprecated - #define _CRT_SECURE_NO_DEPRECATE - #define _SCL_SECURE_NO_DEPRECATE - #pragma warning( disable: 4996 ) -#endif - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -/*--- Compression stuff ---*/ -/*---------------------------------------------------*/ - - -/*---------------------------------------------------*/ -#ifndef BZ_NO_STDIO -void BZ2_bz__AssertH__fail ( int errcode ) -{ - fprintf(stderr, - "\n\nbzip2/libbzip2: internal error number %d.\n" - "This is a bug in bzip2/libbzip2, %s.\n" - "Please report it to me at: jseward@bzip.org. If this happened\n" - "when you were using some program which uses libbzip2 as a\n" - "component, you should also report this bug to the author(s)\n" - "of that program. Please make an effort to report this bug;\n" - "timely and accurate bug reports eventually lead to higher\n" - "quality software. Thanks. Julian Seward, 10 December 2007.\n\n", - errcode, - BZ2_bzlibVersion() - ); - - if (errcode == 1007) { - fprintf(stderr, - "\n*** A special note about internal error number 1007 ***\n" - "\n" - "Experience suggests that a common cause of i.e. 1007\n" - "is unreliable memory or other hardware. The 1007 assertion\n" - "just happens to cross-check the results of huge numbers of\n" - "memory reads/writes, and so acts (unintendedly) as a stress\n" - "test of your memory system.\n" - "\n" - "I suggest the following: try compressing the file again,\n" - "possibly monitoring progress in detail with the -vv flag.\n" - "\n" - "* If the error cannot be reproduced, and/or happens at different\n" - " points in compression, you may have a flaky memory system.\n" - " Try a memory-test program. I have used Memtest86\n" - " (www.memtest86.com). At the time of writing it is free (GPLd).\n" - " Memtest86 tests memory much more thorougly than your BIOSs\n" - " power-on test, and may find failures that the BIOS doesn't.\n" - "\n" - "* If the error can be repeatably reproduced, this is a bug in\n" - " bzip2, and I would very much like to hear about it. Please\n" - " let me know, and, ideally, save a copy of the file causing the\n" - " problem -- without which I will be unable to investigate it.\n" - "\n" - ); - } - - exit(3); -} -#endif - - -/*---------------------------------------------------*/ -static -int bz_config_ok ( void ) -{ - if (sizeof(int) != 4) return 0; - if (sizeof(short) != 2) return 0; - if (sizeof(char) != 1) return 0; - return 1; -} - - -/*---------------------------------------------------*/ -static -void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) -{ - void* v = malloc ( items * size ); - return v; -} - -static -void default_bzfree ( void* opaque, void* addr ) -{ - if (addr != NULL) free ( addr ); -} - - -/*---------------------------------------------------*/ -static -void prepare_new_block ( EState* s ) -{ - Int32 i; - s->nblock = 0; - s->numZ = 0; - s->state_out_pos = 0; - BZ_INITIALISE_CRC ( s->blockCRC ); - for (i = 0; i < 256; i++) s->inUse[i] = False; - s->blockNo++; -} - - -/*---------------------------------------------------*/ -static -void init_RL ( EState* s ) -{ - s->state_in_ch = 256; - s->state_in_len = 0; -} - - -static -Bool isempty_RL ( EState* s ) -{ - if (s->state_in_ch < 256 && s->state_in_len > 0) - return False; else - return True; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressInit) - ( bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 n; - EState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL || - blockSize100k < 1 || blockSize100k > 9 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(EState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - - s->arr1 = NULL; - s->arr2 = NULL; - s->ftab = NULL; - - n = 100000 * blockSize100k; - s->arr1 = BZALLOC( n * sizeof(UInt32) ); - s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); - s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); - - if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - if (s != NULL) BZFREE(s); - return BZ_MEM_ERROR; - } - - s->blockNo = 0; - s->state = BZ_S_INPUT; - s->mode = BZ_M_RUNNING; - s->combinedCRC = 0; - s->blockSize100k = blockSize100k; - s->nblockMAX = 100000 * blockSize100k - 19; - s->verbosity = verbosity; - s->workFactor = workFactor; - - s->block = (UChar*)s->arr2; - s->mtfv = (UInt16*)s->arr1; - s->zbits = NULL; - s->ptr = (UInt32*)s->arr1; - - strm->state = s; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - init_RL ( s ); - prepare_new_block ( s ); - return BZ_OK; -} - - -/*---------------------------------------------------*/ -static -void add_pair_to_block ( EState* s ) -{ - Int32 i; - UChar ch = (UChar)(s->state_in_ch); - for (i = 0; i < s->state_in_len; i++) { - BZ_UPDATE_CRC( s->blockCRC, ch ); - } - s->inUse[s->state_in_ch] = True; - switch (s->state_in_len) { - case 1: - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 2: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 3: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - default: - s->inUse[s->state_in_len-4] = True; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = ((UChar)(s->state_in_len-4)); - s->nblock++; - break; - } -} - - -/*---------------------------------------------------*/ -static -void flush_RL ( EState* s ) -{ - if (s->state_in_ch < 256) add_pair_to_block ( s ); - init_RL ( s ); -} - - -/*---------------------------------------------------*/ -#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ -{ \ - UInt32 zchh = (UInt32)(zchh0); \ - /*-- fast track the common case --*/ \ - if (zchh != zs->state_in_ch && \ - zs->state_in_len == 1) { \ - UChar ch = (UChar)(zs->state_in_ch); \ - BZ_UPDATE_CRC( zs->blockCRC, ch ); \ - zs->inUse[zs->state_in_ch] = True; \ - zs->block[zs->nblock] = (UChar)ch; \ - zs->nblock++; \ - zs->state_in_ch = zchh; \ - } \ - else \ - /*-- general, uncommon cases --*/ \ - if (zchh != zs->state_in_ch || \ - zs->state_in_len == 255) { \ - if (zs->state_in_ch < 256) \ - add_pair_to_block ( zs ); \ - zs->state_in_ch = zchh; \ - zs->state_in_len = 1; \ - } else { \ - zs->state_in_len++; \ - } \ -} - - -/*---------------------------------------------------*/ -static -Bool copy_input_until_stop ( EState* s ) -{ - Bool progress_in = False; - - if (s->mode == BZ_M_RUNNING) { - - /*-- fast track the common case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - } - - } else { - - /*-- general, uncommon case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - /*-- flush/finish end? --*/ - if (s->avail_in_expect == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - s->avail_in_expect--; - } - } - return progress_in; -} - - -/*---------------------------------------------------*/ -static -Bool copy_output_until_stop ( EState* s ) -{ - Bool progress_out = False; - - while (True) { - - /*-- no output space? --*/ - if (s->strm->avail_out == 0) break; - - /*-- block done? --*/ - if (s->state_out_pos >= s->numZ) break; - - progress_out = True; - *(s->strm->next_out) = s->zbits[s->state_out_pos]; - s->state_out_pos++; - s->strm->avail_out--; - s->strm->next_out++; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - return progress_out; -} - - -/*---------------------------------------------------*/ -static -Bool handle_compress ( bz_stream* strm ) -{ - Bool progress_in = False; - Bool progress_out = False; - EState* s = strm->state; - - while (True) { - - if (s->state == BZ_S_OUTPUT) { - progress_out |= copy_output_until_stop ( s ); - if (s->state_out_pos < s->numZ) break; - if (s->mode == BZ_M_FINISHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - prepare_new_block ( s ); - s->state = BZ_S_INPUT; - if (s->mode == BZ_M_FLUSHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - } - - if (s->state == BZ_S_INPUT) { - progress_in |= copy_input_until_stop ( s ); - if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { - flush_RL ( s ); - BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); - s->state = BZ_S_OUTPUT; - } - else - if (s->nblock >= s->nblockMAX) { - BZ2_compressBlock ( s, False ); - s->state = BZ_S_OUTPUT; - } - else - if (s->strm->avail_in == 0) { - break; - } - } - - } - - return progress_in || progress_out; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) -{ - Bool progress; - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - preswitch: - switch (s->mode) { - - case BZ_M_IDLE: - return BZ_SEQUENCE_ERROR; - - case BZ_M_RUNNING: - if (action == BZ_RUN) { - progress = handle_compress ( strm ); - return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; - } - else - if (action == BZ_FLUSH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FLUSHING; - goto preswitch; - } - else - if (action == BZ_FINISH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FINISHING; - goto preswitch; - } - else - return BZ_PARAM_ERROR; - - case BZ_M_FLUSHING: - if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FLUSH_OK; - s->mode = BZ_M_RUNNING; - return BZ_RUN_OK; - - case BZ_M_FINISHING: - if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (!progress) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FINISH_OK; - s->mode = BZ_M_IDLE; - return BZ_STREAM_END; - } - return BZ_OK; /*--not reached--*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) -{ - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - BZFREE(strm->state); - - strm->state = NULL; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/*--- Decompression stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressInit) - ( bz_stream* strm, - int verbosity, - int small ) -{ - DState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL) return BZ_PARAM_ERROR; - if (small != 0 && small != 1) return BZ_PARAM_ERROR; - if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; - - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(DState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - strm->state = s; - s->state = BZ_X_MAGIC_1; - s->bsLive = 0; - s->bsBuff = 0; - s->calculatedCombinedCRC = 0; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - s->smallDecompress = (Bool)small; - s->ll4 = NULL; - s->ll16 = NULL; - s->tt = NULL; - s->currBlockNo = 0; - s->verbosity = verbosity; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_FAST ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - /* restore */ - UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; - UChar c_state_out_ch = s->state_out_ch; - Int32 c_state_out_len = s->state_out_len; - Int32 c_nblock_used = s->nblock_used; - Int32 c_k0 = s->k0; - UInt32* c_tt = s->tt; - UInt32 c_tPos = s->tPos; - char* cs_next_out = s->strm->next_out; - unsigned int cs_avail_out = s->strm->avail_out; - Int32 ro_blockSize100k = s->blockSize100k; - /* end restore */ - - UInt32 avail_out_INIT = cs_avail_out; - Int32 s_save_nblockPP = s->save_nblock+1; - unsigned int total_out_lo32_old; - - while (True) { - - /* try to finish existing run */ - if (c_state_out_len > 0) { - while (True) { - if (cs_avail_out == 0) goto return_notr; - if (c_state_out_len == 1) break; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - c_state_out_len--; - cs_next_out++; - cs_avail_out--; - } - s_state_out_len_eq_one: - { - if (cs_avail_out == 0) { - c_state_out_len = 1; goto return_notr; - }; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - cs_next_out++; - cs_avail_out--; - } - } - /* Only caused by corrupt data stream? */ - if (c_nblock_used > s_save_nblockPP) - return True; - - /* can a new run be started? */ - if (c_nblock_used == s_save_nblockPP) { - c_state_out_len = 0; goto return_notr; - }; - c_state_out_ch = c_k0; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (k1 != c_k0) { - c_k0 = k1; goto s_state_out_len_eq_one; - }; - if (c_nblock_used == s_save_nblockPP) - goto s_state_out_len_eq_one; - - c_state_out_len = 2; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - c_state_out_len = 3; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - BZ_GET_FAST_C(k1); c_nblock_used++; - c_state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST_C(c_k0); c_nblock_used++; - } - - return_notr: - total_out_lo32_old = s->strm->total_out_lo32; - s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); - if (s->strm->total_out_lo32 < total_out_lo32_old) - s->strm->total_out_hi32++; - - /* save */ - s->calculatedBlockCRC = c_calculatedBlockCRC; - s->state_out_ch = c_state_out_ch; - s->state_out_len = c_state_out_len; - s->nblock_used = c_nblock_used; - s->k0 = c_k0; - s->tt = c_tt; - s->tPos = c_tPos; - s->strm->next_out = cs_next_out; - s->strm->avail_out = cs_avail_out; - /* end save */ - } - return False; -} - - - -/*---------------------------------------------------*/ -__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) -{ - Int32 nb, na, mid; - nb = 0; - na = 256; - do { - mid = (nb + na) >> 1; - if (indx >= cftab[mid]) nb = mid; else na = mid; - } - while (na - nb != 1); - return nb; -} - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_SMALL ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) -{ - Bool corrupt; - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - while (True) { - if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; - if (s->state == BZ_X_OUTPUT) { - if (s->smallDecompress) - corrupt = unRLE_obuf_to_output_SMALL ( s ); else - corrupt = unRLE_obuf_to_output_FAST ( s ); - if (corrupt) return BZ_DATA_ERROR; - if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { - BZ_FINALISE_CRC ( s->calculatedBlockCRC ); - if (s->verbosity >= 3) - VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, - s->calculatedBlockCRC ); - if (s->verbosity >= 2) VPrintf0 ( "]" ); - if (s->calculatedBlockCRC != s->storedBlockCRC) - return BZ_DATA_ERROR; - s->calculatedCombinedCRC - = (s->calculatedCombinedCRC << 1) | - (s->calculatedCombinedCRC >> 31); - s->calculatedCombinedCRC ^= s->calculatedBlockCRC; - s->state = BZ_X_BLKHDR_1; - } else { - return BZ_OK; - } - } - if (s->state >= BZ_X_MAGIC_1) { - Int32 r = BZ2_decompress ( s ); - if (r == BZ_STREAM_END) { - if (s->verbosity >= 3) - VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", - s->storedCombinedCRC, s->calculatedCombinedCRC ); - if (s->calculatedCombinedCRC != s->storedCombinedCRC) - return BZ_DATA_ERROR; - return r; - } - if (s->state != BZ_X_OUTPUT) return r; - } - } - - AssertH ( 0, 6001 ); - - return 0; /*NOTREACHED*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) -{ - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->tt != NULL) BZFREE(s->tt); - if (s->ll16 != NULL) BZFREE(s->ll16); - if (s->ll4 != NULL) BZFREE(s->ll4); - - BZFREE(strm->state); - strm->state = NULL; - - return BZ_OK; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ -/*--- File I/O stuff ---*/ -/*---------------------------------------------------*/ - -#define BZ_SETERR(eee) \ -{ \ - if (bzerror != NULL) *bzerror = eee; \ - if (bzf != NULL) bzf->lastErr = eee; \ -} - -typedef - struct { - FILE* handle; - Char buf[BZ_MAX_UNUSED]; - Int32 bufN; - Bool writing; - bz_stream strm; - Int32 lastErr; - Bool initialisedOk; - } - bzFile; - - -/*---------------------------------------------*/ -static Bool myfeof ( FILE* f ) -{ - Int32 c = fgetc ( f ); - if (c == EOF) return True; - ungetc ( c, f ); - return False; -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzWriteOpen) - ( int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 ret; - bzFile* bzf = NULL; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (blockSize100k < 1 || blockSize100k > 9) || - (workFactor < 0 || workFactor > 250) || - (verbosity < 0 || verbosity > 4)) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - bzf->initialisedOk = False; - bzf->bufN = 0; - bzf->handle = f; - bzf->writing = True; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - if (workFactor == 0) workFactor = 30; - ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = 0; - bzf->initialisedOk = True; - return bzf; -} - - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWrite) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return; }; - - bzf->strm.avail_in = len; - bzf->strm.next_in = buf; - - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); - if (ret != BZ_RUN_OK) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (bzf->strm.avail_in == 0) - { BZ_SETERR(BZ_OK); return; }; - } -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWriteClose) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out ) -{ - BZ2_bzWriteClose64 ( bzerror, b, abandon, - nbytes_in, NULL, nbytes_out, NULL ); -} - - -void BZ_API(BZ2_bzWriteClose64) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; - if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; - if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; - if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; - - if ((!abandon) && bzf->lastErr == BZ_OK) { - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); - if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (ret == BZ_STREAM_END) break; - } - } - - if ( !abandon && !ferror ( bzf->handle ) ) { - fflush ( bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (nbytes_in_lo32 != NULL) - *nbytes_in_lo32 = bzf->strm.total_in_lo32; - if (nbytes_in_hi32 != NULL) - *nbytes_in_hi32 = bzf->strm.total_in_hi32; - if (nbytes_out_lo32 != NULL) - *nbytes_out_lo32 = bzf->strm.total_out_lo32; - if (nbytes_out_hi32 != NULL) - *nbytes_out_hi32 = bzf->strm.total_out_hi32; - - BZ_SETERR(BZ_OK); - BZ2_bzCompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzReadOpen) - ( int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused ) -{ - bzFile* bzf = NULL; - int ret; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (small != 0 && small != 1) || - (verbosity < 0 || verbosity > 4) || - (unused == NULL && nUnused != 0) || - (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - - bzf->initialisedOk = False; - bzf->handle = f; - bzf->bufN = 0; - bzf->writing = False; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - while (nUnused > 0) { - bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; - unused = ((void*)( 1 + ((UChar*)(unused)) )); - nUnused--; - } - - ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - - bzf->initialisedOk = True; - return bzf; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) -{ - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - - if (bzf->initialisedOk) - (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzRead) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return 0; }; - - bzf->strm.avail_out = len; - bzf->strm.next_out = buf; - - while (True) { - - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - - if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { - n = fread ( bzf->buf, sizeof(UChar), - BZ_MAX_UNUSED, bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - bzf->bufN = n; - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - } - - ret = BZ2_bzDecompress ( &(bzf->strm) ); - - if (ret != BZ_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return 0; }; - - if (ret == BZ_OK && myfeof(bzf->handle) && - bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) - { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; - - if (ret == BZ_STREAM_END) - { BZ_SETERR(BZ_STREAM_END); - return len - bzf->strm.avail_out; }; - if (bzf->strm.avail_out == 0) - { BZ_SETERR(BZ_OK); return len; }; - - } - - return 0; /*not reached*/ -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadGetUnused) - ( int* bzerror, - BZFILE* b, - void** unused, - int* nUnused ) -{ - bzFile* bzf = (bzFile*)b; - if (bzf == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (bzf->lastErr != BZ_STREAM_END) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (unused == NULL || nUnused == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - - BZ_SETERR(BZ_OK); - *nUnused = bzf->strm.avail_in; - *unused = bzf->strm.next_in; -} -#endif - - -/*---------------------------------------------------*/ -/*--- Misc convenience stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffCompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - blockSize100k < 1 || blockSize100k > 9 || - verbosity < 0 || verbosity > 4 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzCompressInit ( &strm, blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzCompress ( &strm, BZ_FINISH ); - if (ret == BZ_FINISH_OK) goto output_overflow; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzCompressEnd ( &strm ); - return BZ_OK; - - output_overflow: - BZ2_bzCompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - - errhandler: - BZ2_bzCompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffDecompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - (small != 0 && small != 1) || - verbosity < 0 || verbosity > 4) - return BZ_PARAM_ERROR; - - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzDecompress ( &strm ); - if (ret == BZ_OK) goto output_overflow_or_eof; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzDecompressEnd ( &strm ); - return BZ_OK; - - output_overflow_or_eof: - if (strm.avail_out > 0) { - BZ2_bzDecompressEnd ( &strm ); - return BZ_UNEXPECTED_EOF; - } else { - BZ2_bzDecompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - }; - - errhandler: - BZ2_bzDecompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -/*-- - Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -/*-- - return version like "0.9.5d, 4-Sept-1999". ---*/ -const char * BZ_API(BZ2_bzlibVersion)(void) -{ - return BZ_VERSION; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ - -#if defined(_WIN32) || defined(OS2) || defined(MSDOS) -# include -# include -# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) -#else -# define SET_BINARY_MODE(file) -#endif -static -BZFILE * bzopen_or_bzdopen - ( const char *path, /* no use when bzdopen */ - int fd, /* no use when bzdopen */ - const char *mode, - int open_mode) /* bzopen: 0, bzdopen:1 */ -{ - int bzerr; - char unused[BZ_MAX_UNUSED]; - int blockSize100k = 9; - int writing = 0; - char mode2[10] = ""; - FILE *fp = NULL; - BZFILE *bzfp = NULL; - int verbosity = 0; - int workFactor = 30; - int smallMode = 0; - int nUnused = 0; - - if (mode == NULL) return NULL; - while (*mode) { - switch (*mode) { - case 'r': - writing = 0; break; - case 'w': - writing = 1; break; - case 's': - smallMode = 1; break; - default: - if (isdigit((int)(*mode))) { - blockSize100k = *mode-BZ_HDR_0; - } - } - mode++; - } - strcat(mode2, writing ? "w" : "r" ); - strcat(mode2,"b"); /* binary mode */ - - if (open_mode==0) { - if (path==NULL || strcmp(path,"")==0) { - fp = (writing ? stdout : stdin); - SET_BINARY_MODE(fp); - } else { - fp = fopen(path,mode2); - } - } else { -#ifdef BZ_STRICT_ANSI - fp = NULL; -#else - fp = fdopen(fd,mode2); -#endif - } - if (fp == NULL) return NULL; - - if (writing) { - /* Guard against total chaos and anarchy -- JRS */ - if (blockSize100k < 1) blockSize100k = 1; - if (blockSize100k > 9) blockSize100k = 9; - bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, - verbosity,workFactor); - } else { - bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, - unused,nUnused); - } - if (bzfp == NULL) { - if (fp != stdin && fp != stdout) fclose(fp); - return NULL; - } - return bzfp; -} - - -/*---------------------------------------------------*/ -/*-- - open file for read or write. - ex) bzopen("file","w9") - case path="" or NULL => use stdin or stdout. ---*/ -BZFILE * BZ_API(BZ2_bzopen) - ( const char *path, - const char *mode ) -{ - return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); -} - - -/*---------------------------------------------------*/ -BZFILE * BZ_API(BZ2_bzdopen) - ( int fd, - const char *mode ) -{ - return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) -{ - int bzerr, nread; - if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; - nread = BZ2_bzRead(&bzerr,b,buf,len); - if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { - return nread; - } else { - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) -{ - int bzerr; - - BZ2_bzWrite(&bzerr,b,buf,len); - if(bzerr == BZ_OK){ - return len; - }else{ - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzflush) (BZFILE *b) -{ - /* do nothing now... */ - return 0; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzclose) (BZFILE* b) -{ - int bzerr; - FILE *fp; - - if (b==NULL) {return;} - fp = ((bzFile *)b)->handle; - if(((bzFile*)b)->writing){ - BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); - if(bzerr != BZ_OK){ - BZ2_bzWriteClose(NULL,b,1,NULL,NULL); - } - }else{ - BZ2_bzReadClose(&bzerr,b); - } - if(fp!=stdin && fp!=stdout){ - fclose(fp); - } -} - - -/*---------------------------------------------------*/ -/*-- - return last error code ---*/ -static const char *bzerrorstrings[] = { - "OK" - ,"SEQUENCE_ERROR" - ,"PARAM_ERROR" - ,"MEM_ERROR" - ,"DATA_ERROR" - ,"DATA_ERROR_MAGIC" - ,"IO_ERROR" - ,"UNEXPECTED_EOF" - ,"OUTBUFF_FULL" - ,"CONFIG_ERROR" - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ -}; - - -const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) -{ - int err = ((bzFile *)b)->lastErr; - - if(err>0) err = 0; - *errnum = err; - return bzerrorstrings[err*-1]; -} -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/patchlib/bzlib.h b/patchlib/bzlib.h deleted file mode 100644 index 7676f23a..00000000 --- a/patchlib/bzlib.h +++ /dev/null @@ -1,283 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Public header file for the library. ---*/ -/*--- bzlib.h ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#ifndef _BZLIB_H -#define _BZLIB_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define BZ_RUN 0 -#define BZ_FLUSH 1 -#define BZ_FINISH 2 - -#define BZ_OK 0 -#define BZ_RUN_OK 1 -#define BZ_FLUSH_OK 2 -#define BZ_FINISH_OK 3 -#define BZ_STREAM_END 4 -#define BZ_SEQUENCE_ERROR (-1) -#define BZ_PARAM_ERROR (-2) -#define BZ_MEM_ERROR (-3) -#define BZ_DATA_ERROR (-4) -#define BZ_DATA_ERROR_MAGIC (-5) -#define BZ_IO_ERROR (-6) -#define BZ_UNEXPECTED_EOF (-7) -#define BZ_OUTBUFF_FULL (-8) -#define BZ_CONFIG_ERROR (-9) - -typedef - struct { - char *next_in; - unsigned int avail_in; - unsigned int total_in_lo32; - unsigned int total_in_hi32; - - char *next_out; - unsigned int avail_out; - unsigned int total_out_lo32; - unsigned int total_out_hi32; - - void *state; - - void *(*bzalloc)(void *,int,int); - void (*bzfree)(void *,void *); - void *opaque; - } - bz_stream; - - -#ifndef BZ_IMPORT -#define BZ_EXPORT -#endif - -#ifndef BZ_NO_STDIO -/* Need a definitition for FILE */ -#include -#endif - -#ifdef _WIN32 -# include -# ifdef small - /* windows.h define small to char */ -# undef small -# endif -# ifdef BZ_EXPORT -# define BZ_API(func) WINAPI func -# define BZ_EXTERN extern -# else - /* import windows dll dynamically */ -# define BZ_API(func) (WINAPI * func) -# define BZ_EXTERN -# endif -#else -# define BZ_API(func) func -# define BZ_EXTERN extern -#endif - - -/*-- Core (low-level) library functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( - bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompress) ( - bz_stream* strm, - int action - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( - bz_stream *strm, - int verbosity, - int small - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( - bz_stream *strm - ); - - - -/*-- High(er) level library functions --*/ - -#ifndef BZ_NO_STDIO -#define BZ_MAX_UNUSED 5000 - -typedef void BZFILE; - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( - int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( - int* bzerror, - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( - int* bzerror, - BZFILE* b, - void** unused, - int* nUnused - ); - -BZ_EXTERN int BZ_API(BZ2_bzRead) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( - int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN void BZ_API(BZ2_bzWrite) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 - ); -#endif - - -/*-- Utility functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity - ); - - -/*-- - Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ - -BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( - void - ); - -#ifndef BZ_NO_STDIO -BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( - const char *path, - const char *mode - ); - -BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( - int fd, - const char *mode - ); - -BZ_EXTERN int BZ_API(BZ2_bzread) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzwrite) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzflush) ( - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzclose) ( - BZFILE* b - ); - -BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( - BZFILE *b, - int *errnum - ); -#endif - -#ifdef __cplusplus -} -#endif - -#endif - -/*-------------------------------------------------------------*/ -/*--- end bzlib.h ---*/ -/*-------------------------------------------------------------*/ - diff --git a/patchlib/bzlib_private.h b/patchlib/bzlib_private.h deleted file mode 100644 index b134e220..00000000 --- a/patchlib/bzlib_private.h +++ /dev/null @@ -1,510 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Private header file for the library. ---*/ -/*--- bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#ifndef _BZLIB_PRIVATE_H -#define _BZLIB_PRIVATE_H - -#include - -#ifndef BZ_NO_STDIO -#include -#include -#include -#endif - -#include "bzlib.h" - - - -/*-- General stuff. --*/ - -#define BZ_VERSION "1.0.6, 6-Sept-2010" - -typedef char Char; -typedef unsigned char Bool; -typedef unsigned char UChar; -typedef int Int32; -typedef unsigned int UInt32; -typedef short Int16; -typedef unsigned short UInt16; - -#define True ((Bool)1) -#define False ((Bool)0) - -#ifndef __GNUC__ -#define __inline__ /* */ -#endif - -#ifndef BZ_NO_STDIO - -extern void BZ2_bz__AssertH__fail ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } - -#if BZ_DEBUG -#define AssertD(cond,msg) \ - { if (!(cond)) { \ - fprintf ( stderr, \ - "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ - exit(1); \ - }} -#else -#define AssertD(cond,msg) /* */ -#endif - -#define VPrintf0(zf) \ - fprintf(stderr,zf) -#define VPrintf1(zf,za1) \ - fprintf(stderr,zf,za1) -#define VPrintf2(zf,za1,za2) \ - fprintf(stderr,zf,za1,za2) -#define VPrintf3(zf,za1,za2,za3) \ - fprintf(stderr,zf,za1,za2,za3) -#define VPrintf4(zf,za1,za2,za3,za4) \ - fprintf(stderr,zf,za1,za2,za3,za4) -#define VPrintf5(zf,za1,za2,za3,za4,za5) \ - fprintf(stderr,zf,za1,za2,za3,za4,za5) - -#else - -extern void bz_internal_error ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) bz_internal_error ( errcode ); } -#define AssertD(cond,msg) do { } while (0) -#define VPrintf0(zf) do { } while (0) -#define VPrintf1(zf,za1) do { } while (0) -#define VPrintf2(zf,za1,za2) do { } while (0) -#define VPrintf3(zf,za1,za2,za3) do { } while (0) -#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) -#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) - -#endif - - -#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) -#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) - - -/*-- Header bytes. --*/ - -#define BZ_HDR_B 0x42 /* 'B' */ -#define BZ_HDR_Z 0x5a /* 'Z' */ -#define BZ_HDR_h 0x68 /* 'h' */ -#define BZ_HDR_0 0x30 /* '0' */ - -/*-- Constants for the back end. --*/ - -#define BZ_MAX_ALPHA_SIZE 258 -#define BZ_MAX_CODE_LEN 23 - -#define BZ_RUNA 0 -#define BZ_RUNB 1 - -#define BZ_N_GROUPS 6 -#define BZ_G_SIZE 50 -#define BZ_N_ITERS 4 - -#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) - - - -/*-- Stuff for randomising repetitive blocks. --*/ - -extern Int32 BZ2_rNums[512]; - -#define BZ_RAND_DECLS \ - Int32 rNToGo; \ - Int32 rTPos \ - -#define BZ_RAND_INIT_MASK \ - s->rNToGo = 0; \ - s->rTPos = 0 \ - -#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) - -#define BZ_RAND_UPD_MASK \ - if (s->rNToGo == 0) { \ - s->rNToGo = BZ2_rNums[s->rTPos]; \ - s->rTPos++; \ - if (s->rTPos == 512) s->rTPos = 0; \ - } \ - s->rNToGo--; - - - -/*-- Stuff for doing CRCs. --*/ - -extern UInt32 BZ2_crc32Table[256]; - -#define BZ_INITIALISE_CRC(crcVar) \ -{ \ - crcVar = 0xffffffffL; \ -} - -#define BZ_FINALISE_CRC(crcVar) \ -{ \ - crcVar = ~(crcVar); \ -} - -#define BZ_UPDATE_CRC(crcVar,cha) \ -{ \ - crcVar = (crcVar << 8) ^ \ - BZ2_crc32Table[(crcVar >> 24) ^ \ - ((UChar)cha)]; \ -} - - - -/*-- States and modes for compression. --*/ - -#define BZ_M_IDLE 1 -#define BZ_M_RUNNING 2 -#define BZ_M_FLUSHING 3 -#define BZ_M_FINISHING 4 - -#define BZ_S_OUTPUT 1 -#define BZ_S_INPUT 2 - -#define BZ_N_RADIX 2 -#define BZ_N_QSORT 12 -#define BZ_N_SHELL 18 -#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) - - - - -/*-- Structure holding all the compression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* mode this stream is in, and whether inputting */ - /* or outputting data */ - Int32 mode; - Int32 state; - - /* remembers avail_in when flush/finish requested */ - UInt32 avail_in_expect; - - /* for doing the block sorting */ - UInt32* arr1; - UInt32* arr2; - UInt32* ftab; - Int32 origPtr; - - /* aliases for arr1 and arr2 */ - UInt32* ptr; - UChar* block; - UInt16* mtfv; - UChar* zbits; - - /* for deciding when to use the fallback sorting algorithm */ - Int32 workFactor; - - /* run-length-encoding of the input */ - UInt32 state_in_ch; - Int32 state_in_len; - BZ_RAND_DECLS; - - /* input and output limits and current posns */ - Int32 nblock; - Int32 nblockMAX; - Int32 numZ; - Int32 state_out_pos; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - UChar unseqToSeq[256]; - - /* the buffer for bit stream creation */ - UInt32 bsBuff; - Int32 bsLive; - - /* block and combined CRCs */ - UInt32 blockCRC; - UInt32 combinedCRC; - - /* misc administratium */ - Int32 verbosity; - Int32 blockNo; - Int32 blockSize100k; - - /* stuff for coding the MTF values */ - Int32 nMTF; - Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - /* second dimension: only 3 needed; 4 makes index calculations faster */ - UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; - - } - EState; - - - -/*-- externs for compression. --*/ - -extern void -BZ2_blockSort ( EState* ); - -extern void -BZ2_compressBlock ( EState*, Bool ); - -extern void -BZ2_bsInitWrite ( EState* ); - -extern void -BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); - -extern void -BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); - - - -/*-- states for decompression. --*/ - -#define BZ_X_IDLE 1 -#define BZ_X_OUTPUT 2 - -#define BZ_X_MAGIC_1 10 -#define BZ_X_MAGIC_2 11 -#define BZ_X_MAGIC_3 12 -#define BZ_X_MAGIC_4 13 -#define BZ_X_BLKHDR_1 14 -#define BZ_X_BLKHDR_2 15 -#define BZ_X_BLKHDR_3 16 -#define BZ_X_BLKHDR_4 17 -#define BZ_X_BLKHDR_5 18 -#define BZ_X_BLKHDR_6 19 -#define BZ_X_BCRC_1 20 -#define BZ_X_BCRC_2 21 -#define BZ_X_BCRC_3 22 -#define BZ_X_BCRC_4 23 -#define BZ_X_RANDBIT 24 -#define BZ_X_ORIGPTR_1 25 -#define BZ_X_ORIGPTR_2 26 -#define BZ_X_ORIGPTR_3 27 -#define BZ_X_MAPPING_1 28 -#define BZ_X_MAPPING_2 29 -#define BZ_X_SELECTOR_1 30 -#define BZ_X_SELECTOR_2 31 -#define BZ_X_SELECTOR_3 32 -#define BZ_X_CODING_1 33 -#define BZ_X_CODING_2 34 -#define BZ_X_CODING_3 35 -#define BZ_X_MTF_1 36 -#define BZ_X_MTF_2 37 -#define BZ_X_MTF_3 38 -#define BZ_X_MTF_4 39 -#define BZ_X_MTF_5 40 -#define BZ_X_MTF_6 41 -#define BZ_X_ENDHDR_2 42 -#define BZ_X_ENDHDR_3 43 -#define BZ_X_ENDHDR_4 44 -#define BZ_X_ENDHDR_5 45 -#define BZ_X_ENDHDR_6 46 -#define BZ_X_CCRC_1 47 -#define BZ_X_CCRC_2 48 -#define BZ_X_CCRC_3 49 -#define BZ_X_CCRC_4 50 - - - -/*-- Constants for the fast MTF decoder. --*/ - -#define MTFA_SIZE 4096 -#define MTFL_SIZE 16 - - - -/*-- Structure holding all the decompression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* state indicator for this stream */ - Int32 state; - - /* for doing the final run-length decoding */ - UChar state_out_ch; - Int32 state_out_len; - Bool blockRandomised; - BZ_RAND_DECLS; - - /* the buffer for bit stream reading */ - UInt32 bsBuff; - Int32 bsLive; - - /* misc administratium */ - Int32 blockSize100k; - Bool smallDecompress; - Int32 currBlockNo; - Int32 verbosity; - - /* for undoing the Burrows-Wheeler transform */ - Int32 origPtr; - UInt32 tPos; - Int32 k0; - Int32 unzftab[256]; - Int32 nblock_used; - Int32 cftab[257]; - Int32 cftabCopy[257]; - - /* for undoing the Burrows-Wheeler transform (FAST) */ - UInt32 *tt; - - /* for undoing the Burrows-Wheeler transform (SMALL) */ - UInt16 *ll16; - UChar *ll4; - - /* stored and calculated CRCs */ - UInt32 storedBlockCRC; - UInt32 storedCombinedCRC; - UInt32 calculatedBlockCRC; - UInt32 calculatedCombinedCRC; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - Bool inUse16[16]; - UChar seqToUnseq[256]; - - /* for decoding the MTF values */ - UChar mtfa [MTFA_SIZE]; - Int32 mtfbase[256 / MTFL_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - - Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 minLens[BZ_N_GROUPS]; - - /* save area for scalars in the main decompress code */ - Int32 save_i; - Int32 save_j; - Int32 save_t; - Int32 save_alphaSize; - Int32 save_nGroups; - Int32 save_nSelectors; - Int32 save_EOB; - Int32 save_groupNo; - Int32 save_groupPos; - Int32 save_nextSym; - Int32 save_nblockMAX; - Int32 save_nblock; - Int32 save_es; - Int32 save_N; - Int32 save_curr; - Int32 save_zt; - Int32 save_zn; - Int32 save_zvec; - Int32 save_zj; - Int32 save_gSel; - Int32 save_gMinlen; - Int32* save_gLimit; - Int32* save_gBase; - Int32* save_gPerm; - - } - DState; - - - -/*-- Macros for decompression. --*/ - -#define BZ_GET_FAST(cccc) \ - /* c_tPos is unsigned, hence test < 0 is pointless. */ \ - if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ - s->tPos = s->tt[s->tPos]; \ - cccc = (UChar)(s->tPos & 0xff); \ - s->tPos >>= 8; - -#define BZ_GET_FAST_C(cccc) \ - /* c_tPos is unsigned, hence test < 0 is pointless. */ \ - if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \ - c_tPos = c_tt[c_tPos]; \ - cccc = (UChar)(c_tPos & 0xff); \ - c_tPos >>= 8; - -#define SET_LL4(i,n) \ - { if (((i) & 0x1) == 0) \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ - } - -#define GET_LL4(i) \ - ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) - -#define SET_LL(i,n) \ - { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ - SET_LL4(i, n >> 16); \ - } - -#define GET_LL(i) \ - (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) - -#define BZ_GET_SMALL(cccc) \ - /* c_tPos is unsigned, hence test < 0 is pointless. */ \ - if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ - cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ - s->tPos = GET_LL(s->tPos); - - -/*-- externs for decompression. --*/ - -extern Int32 -BZ2_indexIntoF ( Int32, Int32* ); - -extern Int32 -BZ2_decompress ( DState* ); - -extern void -BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, - Int32, Int32, Int32 ); - - -#endif - - -/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ - -#ifdef BZ_NO_STDIO -#ifndef NULL -#define NULL 0 -#endif -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ - diff --git a/patchlib/compress.c b/patchlib/compress.c deleted file mode 100644 index caf76960..00000000 --- a/patchlib/compress.c +++ /dev/null @@ -1,672 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Compression machinery (not incl block sorting) ---*/ -/*--- compress.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -/* CHANGES - 0.9.0 -- original version. - 0.9.0a/b -- no changes in this file. - 0.9.0c -- changed setting of nGroups in sendMTFValues() - so as to do a bit better on small files -*/ - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -/*--- Bit stream I/O ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -void BZ2_bsInitWrite ( EState* s ) -{ - s->bsLive = 0; - s->bsBuff = 0; -} - - -/*---------------------------------------------------*/ -static -void bsFinishWrite ( EState* s ) -{ - while (s->bsLive > 0) { - s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); - s->numZ++; - s->bsBuff <<= 8; - s->bsLive -= 8; - } -} - - -/*---------------------------------------------------*/ -#define bsNEEDW(nz) \ -{ \ - while (s->bsLive >= 8) { \ - s->zbits[s->numZ] \ - = (UChar)(s->bsBuff >> 24); \ - s->numZ++; \ - s->bsBuff <<= 8; \ - s->bsLive -= 8; \ - } \ -} - - -/*---------------------------------------------------*/ -static -__inline__ -void bsW ( EState* s, Int32 n, UInt32 v ) -{ - bsNEEDW ( n ); - s->bsBuff |= (v << (32 - s->bsLive - n)); - s->bsLive += n; -} - - -/*---------------------------------------------------*/ -static -void bsPutUInt32 ( EState* s, UInt32 u ) -{ - bsW ( s, 8, (u >> 24) & 0xffL ); - bsW ( s, 8, (u >> 16) & 0xffL ); - bsW ( s, 8, (u >> 8) & 0xffL ); - bsW ( s, 8, u & 0xffL ); -} - - -/*---------------------------------------------------*/ -static -void bsPutUChar ( EState* s, UChar c ) -{ - bsW( s, 8, (UInt32)c ); -} - - -/*---------------------------------------------------*/ -/*--- The back end proper ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -static -void makeMaps_e ( EState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->unseqToSeq[i] = s->nInUse; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -static -void generateMTFValues ( EState* s ) -{ - UChar yy[256]; - Int32 i, j; - Int32 zPend; - Int32 wr; - Int32 EOB; - - /* - After sorting (eg, here), - s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, - and - ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] - holds the original block data. - - The first thing to do is generate the MTF values, - and put them in - ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. - Because there are strictly fewer or equal MTF values - than block values, ptr values in this area are overwritten - with MTF values only when they are no longer needed. - - The final compressed bitstream is generated into the - area starting at - (UChar*) (&((UChar*)s->arr2)[s->nblock]) - - These storage aliases are set up in bzCompressInit(), - except for the last one, which is arranged in - compressBlock(). - */ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt16* mtfv = s->mtfv; - - makeMaps_e ( s ); - EOB = s->nInUse+1; - - for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; - - wr = 0; - zPend = 0; - for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; - - for (i = 0; i < s->nblock; i++) { - UChar ll_i; - AssertD ( wr <= i, "generateMTFValues(1)" ); - j = ptr[i]-1; if (j < 0) j += s->nblock; - ll_i = s->unseqToSeq[block[j]]; - AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); - - if (yy[0] == ll_i) { - zPend++; - } else { - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - { - register UChar rtmp; - register UChar* ryy_j; - register UChar rll_i; - rtmp = yy[1]; - yy[1] = yy[0]; - ryy_j = &(yy[1]); - rll_i = ll_i; - while ( rll_i != rtmp ) { - register UChar rtmp2; - ryy_j++; - rtmp2 = rtmp; - rtmp = *ryy_j; - *ryy_j = rtmp2; - }; - yy[0] = rtmp; - j = ryy_j - &(yy[0]); - mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; - } - - } - } - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - - mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; - - s->nMTF = wr; -} - - -/*---------------------------------------------------*/ -#define BZ_LESSER_ICOST 0 -#define BZ_GREATER_ICOST 15 - -static -void sendMTFValues ( EState* s ) -{ - Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; - Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; - Int32 nGroups, nBytes; - - /*-- - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - is a global since the decoder also needs it. - - Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - are also globals only used in this proc. - Made global to keep stack frame size small. - --*/ - - - UInt16 cost[BZ_N_GROUPS]; - Int32 fave[BZ_N_GROUPS]; - - UInt16* mtfv = s->mtfv; - - if (s->verbosity >= 3) - VPrintf3( " %d in block, %d after MTF & 1-2 coding, " - "%d+2 syms in use\n", - s->nblock, s->nMTF, s->nInUse ); - - alphaSize = s->nInUse+2; - for (t = 0; t < BZ_N_GROUPS; t++) - for (v = 0; v < alphaSize; v++) - s->len[t][v] = BZ_GREATER_ICOST; - - /*--- Decide how many coding tables to use ---*/ - AssertH ( s->nMTF > 0, 3001 ); - if (s->nMTF < 200) nGroups = 2; else - if (s->nMTF < 600) nGroups = 3; else - if (s->nMTF < 1200) nGroups = 4; else - if (s->nMTF < 2400) nGroups = 5; else - nGroups = 6; - - /*--- Generate an initial set of coding tables ---*/ - { - Int32 nPart, remF, tFreq, aFreq; - - nPart = nGroups; - remF = s->nMTF; - gs = 0; - while (nPart > 0) { - tFreq = remF / nPart; - ge = gs-1; - aFreq = 0; - while (aFreq < tFreq && ge < alphaSize-1) { - ge++; - aFreq += s->mtfFreq[ge]; - } - - if (ge > gs - && nPart != nGroups && nPart != 1 - && ((nGroups-nPart) % 2 == 1)) { - aFreq -= s->mtfFreq[ge]; - ge--; - } - - if (s->verbosity >= 3) - VPrintf5( " initial group %d, [%d .. %d], " - "has %d syms (%4.1f%%)\n", - nPart, gs, ge, aFreq, - (100.0 * (float)aFreq) / (float)(s->nMTF) ); - - for (v = 0; v < alphaSize; v++) - if (v >= gs && v <= ge) - s->len[nPart-1][v] = BZ_LESSER_ICOST; else - s->len[nPart-1][v] = BZ_GREATER_ICOST; - - nPart--; - gs = ge+1; - remF -= aFreq; - } - } - - /*--- - Iterate up to BZ_N_ITERS times to improve the tables. - ---*/ - for (iter = 0; iter < BZ_N_ITERS; iter++) { - - for (t = 0; t < nGroups; t++) fave[t] = 0; - - for (t = 0; t < nGroups; t++) - for (v = 0; v < alphaSize; v++) - s->rfreq[t][v] = 0; - - /*--- - Set up an auxiliary length table which is used to fast-track - the common case (nGroups == 6). - ---*/ - if (nGroups == 6) { - for (v = 0; v < alphaSize; v++) { - s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; - s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; - s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; - } - } - - nSelectors = 0; - totc = 0; - gs = 0; - while (True) { - - /*--- Set group start & end marks. --*/ - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - - /*-- - Calculate the cost of this group as coded - by each of the coding tables. - --*/ - for (t = 0; t < nGroups; t++) cost[t] = 0; - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - register UInt32 cost01, cost23, cost45; - register UInt16 icv; - cost01 = cost23 = cost45 = 0; - -# define BZ_ITER(nn) \ - icv = mtfv[gs+(nn)]; \ - cost01 += s->len_pack[icv][0]; \ - cost23 += s->len_pack[icv][1]; \ - cost45 += s->len_pack[icv][2]; \ - - BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); - BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); - BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); - BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); - BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); - BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); - BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); - BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); - BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); - BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); - -# undef BZ_ITER - - cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; - cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; - cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - UInt16 icv = mtfv[i]; - for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; - } - } - - /*-- - Find the coding table which is best for this group, - and record its identity in the selector table. - --*/ - bc = 999999999; bt = -1; - for (t = 0; t < nGroups; t++) - if (cost[t] < bc) { bc = cost[t]; bt = t; }; - totc += bc; - fave[bt]++; - s->selector[nSelectors] = bt; - nSelectors++; - - /*-- - Increment the symbol frequencies for the selected table. - --*/ - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - -# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ - - BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); - BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); - BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); - BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); - BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); - BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); - BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); - BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); - BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); - BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); - -# undef BZ_ITUR - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) - s->rfreq[bt][ mtfv[i] ]++; - } - - gs = ge+1; - } - if (s->verbosity >= 3) { - VPrintf2 ( " pass %d: size is %d, grp uses are ", - iter+1, totc/8 ); - for (t = 0; t < nGroups; t++) - VPrintf1 ( "%d ", fave[t] ); - VPrintf0 ( "\n" ); - } - - /*-- - Recompute the tables based on the accumulated frequencies. - --*/ - /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See - comment in huffman.c for details. */ - for (t = 0; t < nGroups; t++) - BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), - alphaSize, 17 /*20*/ ); - } - - - AssertH( nGroups < 8, 3002 ); - AssertH( nSelectors < 32768 && - nSelectors <= (2 + (900000 / BZ_G_SIZE)), - 3003 ); - - - /*--- Compute MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; - for (i = 0; i < nGroups; i++) pos[i] = i; - for (i = 0; i < nSelectors; i++) { - ll_i = s->selector[i]; - j = 0; - tmp = pos[j]; - while ( ll_i != tmp ) { - j++; - tmp2 = tmp; - tmp = pos[j]; - pos[j] = tmp2; - }; - pos[0] = tmp; - s->selectorMtf[i] = j; - } - }; - - /*--- Assign actual codes for the tables. --*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); - AssertH ( !(minLen < 1), 3005 ); - BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), - minLen, maxLen, alphaSize ); - } - - /*--- Transmit the mapping table. ---*/ - { - Bool inUse16[16]; - for (i = 0; i < 16; i++) { - inUse16[i] = False; - for (j = 0; j < 16; j++) - if (s->inUse[i * 16 + j]) inUse16[i] = True; - } - - nBytes = s->numZ; - for (i = 0; i < 16; i++) - if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); - - for (i = 0; i < 16; i++) - if (inUse16[i]) - for (j = 0; j < 16; j++) { - if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); - } - - if (s->verbosity >= 3) - VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); - } - - /*--- Now the selectors. ---*/ - nBytes = s->numZ; - bsW ( s, 3, nGroups ); - bsW ( s, 15, nSelectors ); - for (i = 0; i < nSelectors; i++) { - for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); - bsW(s,1,0); - } - if (s->verbosity >= 3) - VPrintf1( "selectors %d, ", s->numZ-nBytes ); - - /*--- Now the coding tables. ---*/ - nBytes = s->numZ; - - for (t = 0; t < nGroups; t++) { - Int32 curr = s->len[t][0]; - bsW ( s, 5, curr ); - for (i = 0; i < alphaSize; i++) { - while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; - while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; - bsW ( s, 1, 0 ); - } - } - - if (s->verbosity >= 3) - VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); - - /*--- And finally, the block data proper ---*/ - nBytes = s->numZ; - selCtr = 0; - gs = 0; - while (True) { - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - AssertH ( s->selector[selCtr] < nGroups, 3006 ); - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - UInt16 mtfv_i; - UChar* s_len_sel_selCtr - = &(s->len[s->selector[selCtr]][0]); - Int32* s_code_sel_selCtr - = &(s->code[s->selector[selCtr]][0]); - -# define BZ_ITAH(nn) \ - mtfv_i = mtfv[gs+(nn)]; \ - bsW ( s, \ - s_len_sel_selCtr[mtfv_i], \ - s_code_sel_selCtr[mtfv_i] ) - - BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); - BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); - BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); - BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); - BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); - BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); - BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); - BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); - BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); - BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); - -# undef BZ_ITAH - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - bsW ( s, - s->len [s->selector[selCtr]] [mtfv[i]], - s->code [s->selector[selCtr]] [mtfv[i]] ); - } - } - - - gs = ge+1; - selCtr++; - } - AssertH( selCtr == nSelectors, 3007 ); - - if (s->verbosity >= 3) - VPrintf1( "codes %d\n", s->numZ-nBytes ); -} - - -/*---------------------------------------------------*/ -void BZ2_compressBlock ( EState* s, Bool is_last_block ) -{ - if (s->nblock > 0) { - - BZ_FINALISE_CRC ( s->blockCRC ); - s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); - s->combinedCRC ^= s->blockCRC; - if (s->blockNo > 1) s->numZ = 0; - - if (s->verbosity >= 2) - VPrintf4( " block %d: crc = 0x%08x, " - "combined CRC = 0x%08x, size = %d\n", - s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); - - BZ2_blockSort ( s ); - } - - s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); - - /*-- If this is the first block, create the stream header. --*/ - if (s->blockNo == 1) { - BZ2_bsInitWrite ( s ); - bsPutUChar ( s, BZ_HDR_B ); - bsPutUChar ( s, BZ_HDR_Z ); - bsPutUChar ( s, BZ_HDR_h ); - bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); - } - - if (s->nblock > 0) { - - bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); - bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); - bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); - - /*-- Now the block's CRC, so it is in a known place. --*/ - bsPutUInt32 ( s, s->blockCRC ); - - /*-- - Now a single bit indicating (non-)randomisation. - As of version 0.9.5, we use a better sorting algorithm - which makes randomisation unnecessary. So always set - the randomised bit to 'no'. Of course, the decoder - still needs to be able to handle randomised blocks - so as to maintain backwards compatibility with - older versions of bzip2. - --*/ - bsW(s,1,0); - - bsW ( s, 24, s->origPtr ); - generateMTFValues ( s ); - sendMTFValues ( s ); - } - - - /*-- If this is the last block, add the stream trailer. --*/ - if (is_last_block) { - - bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); - bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); - bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); - bsPutUInt32 ( s, s->combinedCRC ); - if (s->verbosity >= 2) - VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); - bsFinishWrite ( s ); - } -} - - -/*-------------------------------------------------------------*/ -/*--- end compress.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/patchlib/crctable.c b/patchlib/crctable.c deleted file mode 100644 index 1fea7e94..00000000 --- a/patchlib/crctable.c +++ /dev/null @@ -1,104 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Table for doing CRCs ---*/ -/*--- crctable.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*-- - I think this is an implementation of the AUTODIN-II, - Ethernet & FDDI 32-bit CRC standard. Vaguely derived - from code by Rob Warnock, in Section 51 of the - comp.compression FAQ. ---*/ - -UInt32 BZ2_crc32Table[256] = { - - /*-- Ugly, innit? --*/ - - 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, - 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, - 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, - 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, - 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, - 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, - 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, - 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, - 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, - 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, - 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, - 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, - 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, - 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, - 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, - 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, - 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, - 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, - 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, - 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, - 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, - 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, - 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, - 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, - 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, - 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, - 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, - 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, - 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, - 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, - 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, - 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, - 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, - 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, - 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, - 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, - 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, - 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, - 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, - 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, - 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, - 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, - 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, - 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, - 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, - 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, - 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, - 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, - 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, - 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, - 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, - 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, - 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, - 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, - 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, - 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, - 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, - 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, - 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, - 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, - 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, - 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, - 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, - 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L -}; - - -/*-------------------------------------------------------------*/ -/*--- end crctable.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/patchlib/decompress.c b/patchlib/decompress.c deleted file mode 100644 index 311f5668..00000000 --- a/patchlib/decompress.c +++ /dev/null @@ -1,646 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Decompression machinery ---*/ -/*--- decompress.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -static -void makeMaps_d ( DState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->seqToUnseq[s->nInUse] = i; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -#define RETURN(rrr) \ - { retVal = rrr; goto save_state_and_return; }; - -#define GET_BITS(lll,vvv,nnn) \ - case lll: s->state = lll; \ - while (True) { \ - if (s->bsLive >= nnn) { \ - UInt32 v; \ - v = (s->bsBuff >> \ - (s->bsLive-nnn)) & ((1 << nnn)-1); \ - s->bsLive -= nnn; \ - vvv = v; \ - break; \ - } \ - if (s->strm->avail_in == 0) RETURN(BZ_OK); \ - s->bsBuff \ - = (s->bsBuff << 8) | \ - ((UInt32) \ - (*((UChar*)(s->strm->next_in)))); \ - s->bsLive += 8; \ - s->strm->next_in++; \ - s->strm->avail_in--; \ - s->strm->total_in_lo32++; \ - if (s->strm->total_in_lo32 == 0) \ - s->strm->total_in_hi32++; \ - } - -#define GET_UCHAR(lll,uuu) \ - GET_BITS(lll,uuu,8) - -#define GET_BIT(lll,uuu) \ - GET_BITS(lll,uuu,1) - -/*---------------------------------------------------*/ -#define GET_MTF_VAL(label1,label2,lval) \ -{ \ - if (groupPos == 0) { \ - groupNo++; \ - if (groupNo >= nSelectors) \ - RETURN(BZ_DATA_ERROR); \ - groupPos = BZ_G_SIZE; \ - gSel = s->selector[groupNo]; \ - gMinlen = s->minLens[gSel]; \ - gLimit = &(s->limit[gSel][0]); \ - gPerm = &(s->perm[gSel][0]); \ - gBase = &(s->base[gSel][0]); \ - } \ - groupPos--; \ - zn = gMinlen; \ - GET_BITS(label1, zvec, zn); \ - while (1) { \ - if (zn > 20 /* the longest code */) \ - RETURN(BZ_DATA_ERROR); \ - if (zvec <= gLimit[zn]) break; \ - zn++; \ - GET_BIT(label2, zj); \ - zvec = (zvec << 1) | zj; \ - }; \ - if (zvec - gBase[zn] < 0 \ - || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ - RETURN(BZ_DATA_ERROR); \ - lval = gPerm[zvec - gBase[zn]]; \ -} - - -/*---------------------------------------------------*/ -Int32 BZ2_decompress ( DState* s ) -{ - UChar uc; - Int32 retVal; - Int32 minLen, maxLen; - bz_stream* strm = s->strm; - - /* stuff that needs to be saved/restored */ - Int32 i; - Int32 j; - Int32 t; - Int32 alphaSize; - Int32 nGroups; - Int32 nSelectors; - Int32 EOB; - Int32 groupNo; - Int32 groupPos; - Int32 nextSym; - Int32 nblockMAX; - Int32 nblock; - Int32 es; - Int32 N; - Int32 curr; - Int32 zt; - Int32 zn; - Int32 zvec; - Int32 zj; - Int32 gSel; - Int32 gMinlen; - Int32* gLimit; - Int32* gBase; - Int32* gPerm; - - if (s->state == BZ_X_MAGIC_1) { - /*initialise the save area*/ - s->save_i = 0; - s->save_j = 0; - s->save_t = 0; - s->save_alphaSize = 0; - s->save_nGroups = 0; - s->save_nSelectors = 0; - s->save_EOB = 0; - s->save_groupNo = 0; - s->save_groupPos = 0; - s->save_nextSym = 0; - s->save_nblockMAX = 0; - s->save_nblock = 0; - s->save_es = 0; - s->save_N = 0; - s->save_curr = 0; - s->save_zt = 0; - s->save_zn = 0; - s->save_zvec = 0; - s->save_zj = 0; - s->save_gSel = 0; - s->save_gMinlen = 0; - s->save_gLimit = NULL; - s->save_gBase = NULL; - s->save_gPerm = NULL; - } - - /*restore from the save area*/ - i = s->save_i; - j = s->save_j; - t = s->save_t; - alphaSize = s->save_alphaSize; - nGroups = s->save_nGroups; - nSelectors = s->save_nSelectors; - EOB = s->save_EOB; - groupNo = s->save_groupNo; - groupPos = s->save_groupPos; - nextSym = s->save_nextSym; - nblockMAX = s->save_nblockMAX; - nblock = s->save_nblock; - es = s->save_es; - N = s->save_N; - curr = s->save_curr; - zt = s->save_zt; - zn = s->save_zn; - zvec = s->save_zvec; - zj = s->save_zj; - gSel = s->save_gSel; - gMinlen = s->save_gMinlen; - gLimit = s->save_gLimit; - gBase = s->save_gBase; - gPerm = s->save_gPerm; - - retVal = BZ_OK; - - switch (s->state) { - - GET_UCHAR(BZ_X_MAGIC_1, uc); - if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_2, uc); - if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_3, uc) - if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) - if (s->blockSize100k < (BZ_HDR_0 + 1) || - s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); - s->blockSize100k -= BZ_HDR_0; - - if (s->smallDecompress) { - s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); - s->ll4 = BZALLOC( - ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) - ); - if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); - } else { - s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); - if (s->tt == NULL) RETURN(BZ_MEM_ERROR); - } - - GET_UCHAR(BZ_X_BLKHDR_1, uc); - - if (uc == 0x17) goto endhdr_2; - if (uc != 0x31) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_2, uc); - if (uc != 0x41) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_3, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_4, uc); - if (uc != 0x26) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_5, uc); - if (uc != 0x53) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_6, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - - s->currBlockNo++; - if (s->verbosity >= 2) - VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); - - s->storedBlockCRC = 0; - GET_UCHAR(BZ_X_BCRC_1, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_2, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_3, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_4, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - - GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); - - s->origPtr = 0; - GET_UCHAR(BZ_X_ORIGPTR_1, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_2, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_3, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - - if (s->origPtr < 0) - RETURN(BZ_DATA_ERROR); - if (s->origPtr > 10 + 100000*s->blockSize100k) - RETURN(BZ_DATA_ERROR); - - /*--- Receive the mapping table ---*/ - for (i = 0; i < 16; i++) { - GET_BIT(BZ_X_MAPPING_1, uc); - if (uc == 1) - s->inUse16[i] = True; else - s->inUse16[i] = False; - } - - for (i = 0; i < 256; i++) s->inUse[i] = False; - - for (i = 0; i < 16; i++) - if (s->inUse16[i]) - for (j = 0; j < 16; j++) { - GET_BIT(BZ_X_MAPPING_2, uc); - if (uc == 1) s->inUse[i * 16 + j] = True; - } - makeMaps_d ( s ); - if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); - alphaSize = s->nInUse+2; - - /*--- Now the selectors ---*/ - GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); - if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); - GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); - if (nSelectors < 1) RETURN(BZ_DATA_ERROR); - for (i = 0; i < nSelectors; i++) { - j = 0; - while (True) { - GET_BIT(BZ_X_SELECTOR_3, uc); - if (uc == 0) break; - j++; - if (j >= nGroups) RETURN(BZ_DATA_ERROR); - } - s->selectorMtf[i] = j; - } - - /*--- Undo the MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], tmp, v; - for (v = 0; v < nGroups; v++) pos[v] = v; - - for (i = 0; i < nSelectors; i++) { - v = s->selectorMtf[i]; - tmp = pos[v]; - while (v > 0) { pos[v] = pos[v-1]; v--; } - pos[0] = tmp; - s->selector[i] = tmp; - } - } - - /*--- Now the coding tables ---*/ - for (t = 0; t < nGroups; t++) { - GET_BITS(BZ_X_CODING_1, curr, 5); - for (i = 0; i < alphaSize; i++) { - while (True) { - if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); - GET_BIT(BZ_X_CODING_2, uc); - if (uc == 0) break; - GET_BIT(BZ_X_CODING_3, uc); - if (uc == 0) curr++; else curr--; - } - s->len[t][i] = curr; - } - } - - /*--- Create the Huffman decoding tables ---*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - BZ2_hbCreateDecodeTables ( - &(s->limit[t][0]), - &(s->base[t][0]), - &(s->perm[t][0]), - &(s->len[t][0]), - minLen, maxLen, alphaSize - ); - s->minLens[t] = minLen; - } - - /*--- Now the MTF values ---*/ - - EOB = s->nInUse+1; - nblockMAX = 100000 * s->blockSize100k; - groupNo = -1; - groupPos = 0; - - for (i = 0; i <= 255; i++) s->unzftab[i] = 0; - - /*-- MTF init --*/ - { - Int32 ii, jj, kk; - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - /*-- end MTF init --*/ - - nblock = 0; - GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); - - while (True) { - - if (nextSym == EOB) break; - - if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { - - es = -1; - N = 1; - do { - /* Check that N doesn't get too big, so that es doesn't - go negative. The maximum value that can be - RUNA/RUNB encoded is equal to the block size (post - the initial RLE), viz, 900k, so bounding N at 2 - million should guard against overflow without - rejecting any legitimate inputs. */ - if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR); - if (nextSym == BZ_RUNA) es = es + (0+1) * N; else - if (nextSym == BZ_RUNB) es = es + (1+1) * N; - N = N * 2; - GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); - } - while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); - - es++; - uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; - s->unzftab[uc] += es; - - if (s->smallDecompress) - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->ll16[nblock] = (UInt16)uc; - nblock++; - es--; - } - else - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->tt[nblock] = (UInt32)uc; - nblock++; - es--; - }; - - continue; - - } else { - - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - - /*-- uc = MTF ( nextSym-1 ) --*/ - { - Int32 ii, jj, kk, pp, lno, off; - UInt32 nn; - nn = (UInt32)(nextSym - 1); - - if (nn < MTFL_SIZE) { - /* avoid general-case expense */ - pp = s->mtfbase[0]; - uc = s->mtfa[pp+nn]; - while (nn > 3) { - Int32 z = pp+nn; - s->mtfa[(z) ] = s->mtfa[(z)-1]; - s->mtfa[(z)-1] = s->mtfa[(z)-2]; - s->mtfa[(z)-2] = s->mtfa[(z)-3]; - s->mtfa[(z)-3] = s->mtfa[(z)-4]; - nn -= 4; - } - while (nn > 0) { - s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; - }; - s->mtfa[pp] = uc; - } else { - /* general case */ - lno = nn / MTFL_SIZE; - off = nn % MTFL_SIZE; - pp = s->mtfbase[lno] + off; - uc = s->mtfa[pp]; - while (pp > s->mtfbase[lno]) { - s->mtfa[pp] = s->mtfa[pp-1]; pp--; - }; - s->mtfbase[lno]++; - while (lno > 0) { - s->mtfbase[lno]--; - s->mtfa[s->mtfbase[lno]] - = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; - lno--; - } - s->mtfbase[0]--; - s->mtfa[s->mtfbase[0]] = uc; - if (s->mtfbase[0] == 0) { - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - } - } - /*-- end uc = MTF ( nextSym-1 ) --*/ - - s->unzftab[s->seqToUnseq[uc]]++; - if (s->smallDecompress) - s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else - s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); - nblock++; - - GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); - continue; - } - } - - /* Now we know what nblock is, we can do a better sanity - check on s->origPtr. - */ - if (s->origPtr < 0 || s->origPtr >= nblock) - RETURN(BZ_DATA_ERROR); - - /*-- Set up cftab to facilitate generation of T^(-1) --*/ - /* Check: unzftab entries in range. */ - for (i = 0; i <= 255; i++) { - if (s->unzftab[i] < 0 || s->unzftab[i] > nblock) - RETURN(BZ_DATA_ERROR); - } - /* Actually generate cftab. */ - s->cftab[0] = 0; - for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; - for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; - /* Check: cftab entries in range. */ - for (i = 0; i <= 256; i++) { - if (s->cftab[i] < 0 || s->cftab[i] > nblock) { - /* s->cftab[i] can legitimately be == nblock */ - RETURN(BZ_DATA_ERROR); - } - } - /* Check: cftab entries non-descending. */ - for (i = 1; i <= 256; i++) { - if (s->cftab[i-1] > s->cftab[i]) { - RETURN(BZ_DATA_ERROR); - } - } - - s->state_out_len = 0; - s->state_out_ch = 0; - BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); - s->state = BZ_X_OUTPUT; - if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); - - if (s->smallDecompress) { - - /*-- Make a copy of cftab, used in generation of T --*/ - for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; - - /*-- compute the T vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->ll16[i]); - SET_LL(i, s->cftabCopy[uc]); - s->cftabCopy[uc]++; - } - - /*-- Compute T^(-1) by pointer reversal on T --*/ - i = s->origPtr; - j = GET_LL(i); - do { - Int32 tmp = GET_LL(j); - SET_LL(j, i); - i = j; - j = tmp; - } - while (i != s->origPtr); - - s->tPos = s->origPtr; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_SMALL(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } else { - - /*-- compute the T^(-1) vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->tt[i] & 0xff); - s->tt[s->cftab[uc]] |= (i << 8); - s->cftab[uc]++; - } - - s->tPos = s->tt[s->origPtr] >> 8; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_FAST(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_FAST(s->k0); s->nblock_used++; - } - - } - - RETURN(BZ_OK); - - - - endhdr_2: - - GET_UCHAR(BZ_X_ENDHDR_2, uc); - if (uc != 0x72) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_3, uc); - if (uc != 0x45) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_4, uc); - if (uc != 0x38) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_5, uc); - if (uc != 0x50) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_6, uc); - if (uc != 0x90) RETURN(BZ_DATA_ERROR); - - s->storedCombinedCRC = 0; - GET_UCHAR(BZ_X_CCRC_1, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_2, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_3, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_4, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - - s->state = BZ_X_IDLE; - RETURN(BZ_STREAM_END); - - default: AssertH ( False, 4001 ); - } - - AssertH ( False, 4002 ); - - save_state_and_return: - - s->save_i = i; - s->save_j = j; - s->save_t = t; - s->save_alphaSize = alphaSize; - s->save_nGroups = nGroups; - s->save_nSelectors = nSelectors; - s->save_EOB = EOB; - s->save_groupNo = groupNo; - s->save_groupPos = groupPos; - s->save_nextSym = nextSym; - s->save_nblockMAX = nblockMAX; - s->save_nblock = nblock; - s->save_es = es; - s->save_N = N; - s->save_curr = curr; - s->save_zt = zt; - s->save_zn = zn; - s->save_zvec = zvec; - s->save_zj = zj; - s->save_gSel = gSel; - s->save_gMinlen = gMinlen; - s->save_gLimit = gLimit; - s->save_gBase = gBase; - s->save_gPerm = gPerm; - - return retVal; -} - - -/*-------------------------------------------------------------*/ -/*--- end decompress.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/patchlib/huffman.c b/patchlib/huffman.c deleted file mode 100644 index 2283fdbc..00000000 --- a/patchlib/huffman.c +++ /dev/null @@ -1,205 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Huffman coding low-level stuff ---*/ -/*--- huffman.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*---------------------------------------------------*/ -#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) -#define DEPTHOF(zz1) ((zz1) & 0x000000ff) -#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) - -#define ADDWEIGHTS(zw1,zw2) \ - (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ - (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) - -#define UPHEAP(z) \ -{ \ - Int32 zz, tmp; \ - zz = z; tmp = heap[zz]; \ - while (weight[tmp] < weight[heap[zz >> 1]]) { \ - heap[zz] = heap[zz >> 1]; \ - zz >>= 1; \ - } \ - heap[zz] = tmp; \ -} - -#define DOWNHEAP(z) \ -{ \ - Int32 zz, yy, tmp; \ - zz = z; tmp = heap[zz]; \ - while (True) { \ - yy = zz << 1; \ - if (yy > nHeap) break; \ - if (yy < nHeap && \ - weight[heap[yy+1]] < weight[heap[yy]]) \ - yy++; \ - if (weight[tmp] < weight[heap[yy]]) break; \ - heap[zz] = heap[yy]; \ - zz = yy; \ - } \ - heap[zz] = tmp; \ -} - - -/*---------------------------------------------------*/ -void BZ2_hbMakeCodeLengths ( UChar *len, - Int32 *freq, - Int32 alphaSize, - Int32 maxLen ) -{ - /*-- - Nodes and heap entries run from 1. Entry 0 - for both the heap and nodes is a sentinel. - --*/ - Int32 nNodes, nHeap, n1, n2, i, j, k; - Bool tooLong; - - Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; - Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; - Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; - - for (i = 0; i < alphaSize; i++) - weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; - - while (True) { - - nNodes = alphaSize; - nHeap = 0; - - heap[0] = 0; - weight[0] = 0; - parent[0] = -2; - - for (i = 1; i <= alphaSize; i++) { - parent[i] = -1; - nHeap++; - heap[nHeap] = i; - UPHEAP(nHeap); - } - - AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); - - while (nHeap > 1) { - n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - nNodes++; - parent[n1] = parent[n2] = nNodes; - weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); - parent[nNodes] = -1; - nHeap++; - heap[nHeap] = nNodes; - UPHEAP(nHeap); - } - - AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); - - tooLong = False; - for (i = 1; i <= alphaSize; i++) { - j = 0; - k = i; - while (parent[k] >= 0) { k = parent[k]; j++; } - len[i-1] = j; - if (j > maxLen) tooLong = True; - } - - if (! tooLong) break; - - /* 17 Oct 04: keep-going condition for the following loop used - to be 'i < alphaSize', which missed the last element, - theoretically leading to the possibility of the compressor - looping. However, this count-scaling step is only needed if - one of the generated Huffman code words is longer than - maxLen, which up to and including version 1.0.2 was 20 bits, - which is extremely unlikely. In version 1.0.3 maxLen was - changed to 17 bits, which has minimal effect on compression - ratio, but does mean this scaling step is used from time to - time, enough to verify that it works. - - This means that bzip2-1.0.3 and later will only produce - Huffman codes with a maximum length of 17 bits. However, in - order to preserve backwards compatibility with bitstreams - produced by versions pre-1.0.3, the decompressor must still - handle lengths of up to 20. */ - - for (i = 1; i <= alphaSize; i++) { - j = weight[i] >> 8; - j = 1 + (j / 2); - weight[i] = j << 8; - } - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbAssignCodes ( Int32 *code, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 n, vec, i; - - vec = 0; - for (n = minLen; n <= maxLen; n++) { - for (i = 0; i < alphaSize; i++) - if (length[i] == n) { code[i] = vec; vec++; }; - vec <<= 1; - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbCreateDecodeTables ( Int32 *limit, - Int32 *base, - Int32 *perm, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 pp, i, j, vec; - - pp = 0; - for (i = minLen; i <= maxLen; i++) - for (j = 0; j < alphaSize; j++) - if (length[j] == i) { perm[pp] = j; pp++; }; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; - for (i = 0; i < alphaSize; i++) base[length[i]+1]++; - - for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; - vec = 0; - - for (i = minLen; i <= maxLen; i++) { - vec += (base[i+1] - base[i]); - limit[i] = vec-1; - vec <<= 1; - } - for (i = minLen + 1; i <= maxLen; i++) - base[i] = ((limit[i-1] + 1) << 1) - base[i]; -} - - -/*-------------------------------------------------------------*/ -/*--- end huffman.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/patchlib/randtable.c b/patchlib/randtable.c deleted file mode 100644 index 6d624599..00000000 --- a/patchlib/randtable.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Table for randomising repetitive blocks ---*/ -/*--- randtable.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - - -/*---------------------------------------------*/ -Int32 BZ2_rNums[512] = { - 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, - 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, - 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, - 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, - 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, - 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, - 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, - 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, - 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, - 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, - 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, - 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, - 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, - 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, - 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, - 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, - 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, - 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, - 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, - 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, - 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, - 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 936, 638 -}; - - -/*-------------------------------------------------------------*/ -/*--- end randtable.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/quazip/CMakeLists.txt b/quazip/CMakeLists.txt deleted file mode 100644 index b5a391e9..00000000 --- a/quazip/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -project(quazip) - -# set all include directories for in and out of source builds -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${ZLIB_INCLUDE_DIRS} -) - -# include with QT_USE selected library parts -# INCLUDE(${QT_USE_FILE}) - -file(GLOB SRCS "*.c" "*.cpp") -file(GLOB PUBLIC_HEADERS "*.h") - -# Static link! -ADD_DEFINITIONS(-DQUAZIP_STATIC) - -#qt5_wrap_cpp(MOC_SRCS ${PUBLIC_HEADERS}) -#set(SRCS ${SRCS} ${MOC_SRCS}) - -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -add_library(quazip STATIC ${SRCS}) -target_link_libraries(quazip ${ZLIB_LIBRARIES}) - -#install(FILES ${PUBLIC_HEADERS} DESTINATION include/quazip) -#install(TARGETS quazip LIBRARY DESTINATION ${LIB_DESTINATION} ARCHIVE DESTINATION ${LIB_DESTINATION} RUNTIME DESTINATION ${LIB_DESTINATION}) diff --git a/quazip/JlCompress.cpp b/quazip/JlCompress.cpp deleted file mode 100644 index 69832140..00000000 --- a/quazip/JlCompress.cpp +++ /dev/null @@ -1,516 +0,0 @@ -#include "JlCompress.h" -#include - -static bool copyData(QIODevice &inFile, QIODevice &outFile) -{ - while (!inFile.atEnd()) { - char buf[4096]; - qint64 readLen = inFile.read(buf, 4096); - if (readLen <= 0) - return false; - if (outFile.write(buf, readLen) != readLen) - return false; - } - return true; -} - -/**OK - * Comprime il file fileName, nell'oggetto zip, con il nome fileDest. - * - * La funzione fallisce se: - * * zip==NULL; - * * l'oggetto zip e stato aperto in una modalita non compatibile con l'aggiunta di file; - * * non e possibile aprire il file d'origine; - * * non e possibile creare il file all'interno dell'oggetto zip; - * * si e rilevato un errore nella copia dei dati; - * * non e stato possibile chiudere il file all'interno dell'oggetto zip; - */ -bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) { - // zip: oggetto dove aggiungere il file - // fileName: nome del file reale - // fileDest: nome del file all'interno del file compresso - - // Controllo l'apertura dello zip - if (!zip) return false; - if (zip->getMode()!=QuaZip::mdCreate && - zip->getMode()!=QuaZip::mdAppend && - zip->getMode()!=QuaZip::mdAdd) return false; - - // Apro il file originale - QFile inFile; - inFile.setFileName(fileName); - if(!inFile.open(QIODevice::ReadOnly)) return false; - - // Apro il file risulato - QuaZipFile outFile(zip); - if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, inFile.fileName()))) return false; - - // Copio i dati - if (!copyData(inFile, outFile) || outFile.getZipError()!=UNZ_OK) { - return false; - } - - // Chiudo i file - outFile.close(); - if (outFile.getZipError()!=UNZ_OK) return false; - inFile.close(); - - return true; -} - -/**OK - * Comprime la cartella dir nel file fileCompressed, se recursive e true allora - * comprime anche le sotto cartelle. I nomi dei file preceduti dal path creato - * togliendo il pat della cartella origDir al path della cartella dir. - * Se la funzione fallisce restituisce false e cancella il file che si e tentato - * di creare. - * - * La funzione fallisce se: - * * zip==NULL; - * * l'oggetto zip e stato aperto in una modalita non compatibile con l'aggiunta di file; - * * la cartella dir non esiste; - * * la compressione di una sotto cartella fallisce (1); - * * la compressione di un file fallisce; - * (1) La funzione si richiama in maniera ricorsiva per comprimere le sotto cartelle - * dunque gli errori di compressione di una sotto cartella sono gli stessi di questa - * funzione. - */ -bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive) { - // zip: oggetto dove aggiungere il file - // dir: cartella reale corrente - // origDir: cartella reale originale - // (path(dir)-path(origDir)) = path interno all'oggetto zip - - // Controllo l'apertura dello zip - if (!zip) return false; - if (zip->getMode()!=QuaZip::mdCreate && - zip->getMode()!=QuaZip::mdAppend && - zip->getMode()!=QuaZip::mdAdd) return false; - - // Controllo la cartella - QDir directory(dir); - if (!directory.exists()) return false; - - // Se comprimo anche le sotto cartelle - if (recursive) { - // Per ogni sotto cartella - QFileInfoList files = directory.entryInfoList(QDir::AllDirs|QDir::NoDotAndDotDot); - Q_FOREACH (QFileInfo file, files) { - // Comprimo la sotto cartella - if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive)) return false; - } - } - - // Per ogni file nella cartella - QFileInfoList files = directory.entryInfoList(QDir::Files); - QDir origDirectory(origDir); - Q_FOREACH (QFileInfo file, files) { - // Se non e un file o e il file compresso che sto creando - if(!file.isFile()||file.absoluteFilePath()==zip->getZipName()) continue; - - // Creo il nome relativo da usare all'interno del file compresso - QString filename = origDirectory.relativeFilePath(file.absoluteFilePath()); - - // Comprimo il file - if (!compressFile(zip,file.absoluteFilePath(),filename)) return false; - } - - return true; -} - -/**OK - * Estrae il file fileName, contenuto nell'oggetto zip, con il nome fileDest. - * Se la funzione fallisce restituisce false e cancella il file che si e tentato di estrarre. - * - * La funzione fallisce se: - * * zip==NULL; - * * l'oggetto zip e stato aperto in una modalita non compatibile con l'estrazione di file; - * * non e possibile aprire il file all'interno dell'oggetto zip; - * * non e possibile creare il file estratto; - * * si e rilevato un errore nella copia dei dati (1); - * * non e stato possibile chiudere il file all'interno dell'oggetto zip (1); - * - * (1): prima di uscire dalla funzione cancella il file estratto. - */ -bool JlCompress::extractFile(QuaZip* zip, QString fileName, QString fileDest) { - // zip: oggetto dove aggiungere il file - // filename: nome del file reale - // fileincompress: nome del file all'interno del file compresso - - // Controllo l'apertura dello zip - if (!zip) return false; - if (zip->getMode()!=QuaZip::mdUnzip) return false; - - // Apro il file compresso - if (!fileName.isEmpty()) - zip->setCurrentFile(fileName); - QuaZipFile inFile(zip); - if(!inFile.open(QIODevice::ReadOnly) || inFile.getZipError()!=UNZ_OK) return false; - - // Controllo esistenza cartella file risultato - QDir curDir; - if (!curDir.mkpath(QFileInfo(fileDest).absolutePath())) { - return false; - } - - if (QFileInfo(fileDest).isDir()) - return true; - - // Apro il file risultato - QFile outFile; - outFile.setFileName(fileDest); - if(!outFile.open(QIODevice::WriteOnly)) return false; - - // Copio i dati - if (!copyData(inFile, outFile) || inFile.getZipError()!=UNZ_OK) { - outFile.close(); - removeFile(QStringList(fileDest)); - return false; - } - outFile.close(); - - // Chiudo i file - inFile.close(); - if (inFile.getZipError()!=UNZ_OK) { - removeFile(QStringList(fileDest)); - return false; - } - - return true; -} - -/** - * Rimuove i file il cui nome e specificato all'interno di listFile. - * Restituisce true se tutti i file sono stati cancellati correttamente, attenzione - * perche puo restituire false anche se alcuni file non esistevano e si e tentato - * di cancellarli. - */ -bool JlCompress::removeFile(QStringList listFile) { - bool ret = true; - // Per ogni file - for (int i=0; iopen(QuaZip::mdUnzip)) { - delete zip; - return QStringList(); - } - - // Estraggo i nomi dei file - QStringList lst; - QuaZipFileInfo info; - for(bool more=zip->goToFirstFile(); more; more=zip->goToNextFile()) { - if(!zip->getCurrentFileInfo(&info)) { - delete zip; - return QStringList(); - } - lst << info.name; - //info.name.toLocal8Bit().constData() - } - - // Chiudo il file zip - zip->close(); - if(zip->getZipError()!=0) { - delete zip; - return QStringList(); - } - delete zip; - - return lst; -} - diff --git a/quazip/JlCompress.h b/quazip/JlCompress.h deleted file mode 100644 index 29d6191f..00000000 --- a/quazip/JlCompress.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef JLCOMPRESSFOLDER_H_ -#define JLCOMPRESSFOLDER_H_ - -#include "quazip.h" -#include "quazipfile.h" -#include "quazipfileinfo.h" -#include -#include -#include -#include - -/// Utility class for typical operations. -/** - This class contains a number of useful static functions to perform - simple operations, such as mass ZIP packing or extraction. - */ -class QUAZIP_EXPORT JlCompress { -private: - /// Compress a single file. - /** - \param zip Opened zip to compress the file to. - \param fileName The full path to the source file. - \param fileDest The full name of the file inside the archive. - \return true if success, false otherwise. - */ - static bool compressFile(QuaZip* zip, QString fileName, QString fileDest); - /// Compress a subdirectory. - /** - \param parentZip Opened zip containing the parent directory. - \param dir The full path to the directory to pack. - \param parentDir The full path to the directory corresponding to - the root of the ZIP. - \param recursive Whether to pack sub-directories as well or only - files. - \return true if success, false otherwise. - */ - static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive = true); - /// Extract a single file. - /** - \param zip The opened zip archive to extract from. - \param fileName The full name of the file to extract. - \param fileDest The full path to the destination file. - \return true if success, false otherwise. - */ - static bool extractFile(QuaZip* zip, QString fileName, QString fileDest); - /// Remove some files. - /** - \param listFile The list of files to remove. - \return true if success, false otherwise. - */ - static bool removeFile(QStringList listFile); - -public: - /// Compress a single file. - /** - \param fileCompressed The name of the archive. - \param file The file to compress. - \return true if success, false otherwise. - */ - static bool compressFile(QString fileCompressed, QString file); - /// Compress a list of files. - /** - \param fileCompressed The name of the archive. - \param files The file list to compress. - \return true if success, false otherwise. - */ - static bool compressFiles(QString fileCompressed, QStringList files); - /// Compress a whole directory. - /** - \param fileCompressed The name of the archive. - \param dir The directory to compress. - \param recursive Whether to pack the subdirectories as well, or - just regular files. - \return true if success, false otherwise. - */ - static bool compressDir(QString fileCompressed, QString dir = QString(), bool recursive = true); - -public: - /// Extract a single file. - /** - \param fileCompressed The name of the archive. - \param fileName The file to extract. - \param fileDest The destination file, assumed to be identical to - \a file if left empty. - \return The list of the full paths of the files extracted, empty on failure. - */ - static QString extractFile(QString fileCompressed, QString fileName, QString fileDest = QString()); - /// Extract a list of files. - /** - \param fileCompressed The name of the archive. - \param files The file list to extract. - \param dir The directory to put the files to, the current - directory if left empty. - \return The list of the full paths of the files extracted, empty on failure. - */ - static QStringList extractFiles(QString fileCompressed, QStringList files, QString dir = QString()); - /// Extract a whole archive. - /** - \param fileCompressed The name of the archive. - \param dir The directory to extract to, the current directory if - left empty. - \return The list of the full paths of the files extracted, empty on failure. - */ - static QStringList extractDir(QString fileCompressed, QString dir = QString()); - /// Extract a whole archive, with a list of exceptions (prefixes to ignore). - /** - \param fileCompressed The name of the archive. - \param dir The directory to extract to, the current directory if - left empty. - \param exceptions The list of exception prefixes - \return The list of the full paths of the files extracted, empty on failure. - */ - static QStringList extractWithExceptions(QString fileCompressed, QString dir, QStringList exceptions); - /// Get the file list. - /** - \return The list of the files in the archive, or, more precisely, the - list of the entries, including both files and directories if they - are present separately. - */ - static QStringList getFileList(QString fileCompressed); -}; - -#endif /* JLCOMPRESSFOLDER_H_ */ diff --git a/quazip/crypt.h b/quazip/crypt.h deleted file mode 100644 index 1d6da628..00000000 --- a/quazip/crypt.h +++ /dev/null @@ -1,135 +0,0 @@ -/* crypt.h -- base code for crypt/uncrypt ZIPfile - - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - This code is a modified version of crypting code in Infozip distribution - - 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. - - This code support the "Traditional PKWARE Encryption". - - The new AES encryption added on Zip format by Winzip (see the page - http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong - Encryption is not supported. -*/ - -#include "quazip_global.h" - -#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) - -/*********************************************************************** - * Return the next byte in the pseudo-random sequence - */ -static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab UNUSED) -{ - //(void) pcrc_32_tab; /* avoid "unused parameter" warning */ - 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)(*(pkeys+2)) & 0xffff) | 2; - return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); -} - -/*********************************************************************** - * Update the encryption keys with the next byte of plain text - */ -static int update_keys(unsigned long* pkeys,const unsigned long* 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 long* pkeys,const unsigned long* 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,pcrc_32_tab))) - -#define zencode(pkeys,pcrc_32_tab,c,t) \ - (t=decrypt_byte(pkeys,pcrc_32_tab), 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(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) - const char *passwd; /* password string */ - unsigned char *buf; /* where to write header */ - int bufSize; - unsigned long* pkeys; - const unsigned long* pcrc_32_tab; - unsigned long 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> 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++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); - buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); - return n; -} - -#endif diff --git a/quazip/ioapi.h b/quazip/ioapi.h deleted file mode 100644 index f4c21809..00000000 --- a/quazip/ioapi.h +++ /dev/null @@ -1,77 +0,0 @@ -/* ioapi.h -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - Modified by Sergey A. Tachenov to integrate with Qt. -*/ - -#ifndef _ZLIBIOAPI_H -#define _ZLIBIOAPI_H - - -#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 (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) -#define ZCALLBACK CALLBACK -#else -#define ZCALLBACK -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, voidpf file, 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 uLong (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); -typedef int (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); -typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); -typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); - -typedef struct zlib_filefunc_def_s -{ - open_file_func zopen_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; - - - -void fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); - -#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) -#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) -#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) -#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) -#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) -#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) - - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/quazip/qioapi.cpp b/quazip/qioapi.cpp deleted file mode 100644 index f254c34d..00000000 --- a/quazip/qioapi.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* ioapi.c -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - Modified by Sergey A. Tachenov to integrate with Qt. -*/ - -#include -#include -#include - -#include "zlib.h" -#include "ioapi.h" -#include "quazip_global.h" -#include - - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -voidpf ZCALLBACK qiodevice_open_file_func ( - voidpf opaque UNUSED, - voidpf file, - int mode) -{ - QIODevice *iodevice = reinterpret_cast(file); - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) - iodevice->open(QIODevice::ReadOnly); - else - if (mode & ZLIB_FILEFUNC_MODE_EXISTING) - iodevice->open(QIODevice::ReadWrite); - else - if (mode & ZLIB_FILEFUNC_MODE_CREATE) - iodevice->open(QIODevice::WriteOnly); - - if (iodevice->isOpen()) { - if (iodevice->isSequential()) { - iodevice->close(); - return NULL; - } else { - return iodevice; - } - } else - return NULL; -} - - -uLong ZCALLBACK qiodevice_read_file_func ( - voidpf opaque UNUSED, - voidpf stream, - void* buf, - uLong size) -{ - uLong ret; - ret = (uLong)((QIODevice*)stream)->read((char*)buf,size); - return ret; -} - - -uLong ZCALLBACK qiodevice_write_file_func ( - voidpf opaque UNUSED, - voidpf stream, - const void* buf, - uLong size) -{ - uLong ret; - ret = (uLong)((QIODevice*)stream)->write((char*)buf,size); - return ret; -} - -uLong ZCALLBACK qiodevice_tell_file_func ( - voidpf opaque UNUSED, - voidpf stream) -{ - uLong ret; - ret = ((QIODevice*)stream)->pos(); - return ret; -} - -int ZCALLBACK qiodevice_seek_file_func ( - voidpf opaque UNUSED, - voidpf stream, - uLong offset, - int origin) -{ - uLong qiodevice_seek_result=0; - int ret; - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR : - qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset; - break; - case ZLIB_FILEFUNC_SEEK_END : - qiodevice_seek_result = ((QIODevice*)stream)->size() - offset; - break; - case ZLIB_FILEFUNC_SEEK_SET : - qiodevice_seek_result = offset; - break; - default: return -1; - } - ret = !((QIODevice*)stream)->seek(qiodevice_seek_result); - return ret; -} - -int ZCALLBACK qiodevice_close_file_func ( - voidpf opaque UNUSED, - voidpf stream) -{ - ((QIODevice*)stream)->close(); - return 0; -} - -int ZCALLBACK qiodevice_error_file_func ( - voidpf opaque UNUSED, - voidpf stream) -{ - // can't check for error due to the QIODevice API limitation - return 0; -} - -void fill_qiodevice_filefunc ( - zlib_filefunc_def* pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen_file = qiodevice_open_file_func; - pzlib_filefunc_def->zread_file = qiodevice_read_file_func; - pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func; - pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func; - pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func; - pzlib_filefunc_def->zclose_file = qiodevice_close_file_func; - pzlib_filefunc_def->zerror_file = qiodevice_error_file_func; - pzlib_filefunc_def->opaque = NULL; -} diff --git a/quazip/quaadler32.cpp b/quazip/quaadler32.cpp deleted file mode 100644 index 097899f6..00000000 --- a/quazip/quaadler32.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "quaadler32.h" - -#include "zlib.h" - -QuaAdler32::QuaAdler32() -{ - reset(); -} - -quint32 QuaAdler32::calculate(const QByteArray &data) -{ - return adler32( adler32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() ); -} - -void QuaAdler32::reset() -{ - checksum = adler32(0L, Z_NULL, 0); -} - -void QuaAdler32::update(const QByteArray &buf) -{ - checksum = adler32( checksum, (const Bytef*)buf.data(), buf.size() ); -} - -quint32 QuaAdler32::value() -{ - return checksum; -} diff --git a/quazip/quaadler32.h b/quazip/quaadler32.h deleted file mode 100644 index c5ac0532..00000000 --- a/quazip/quaadler32.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef QUAADLER32_H -#define QUAADLER32_H - -#include - -#include "quachecksum32.h" - -/// Adler32 checksum -/** \class QuaAdler32 quaadler32.h - * This class wrappers the adler32 function with the QuaChecksum32 interface. - * See QuaChecksum32 for more info. - */ -class QUAZIP_EXPORT QuaAdler32 : public QuaChecksum32 -{ - -public: - QuaAdler32(); - - quint32 calculate(const QByteArray &data); - - void reset(); - void update(const QByteArray &buf); - quint32 value(); - -private: - quint32 checksum; -}; - -#endif //QUAADLER32_H diff --git a/quazip/quachecksum32.h b/quazip/quachecksum32.h deleted file mode 100644 index 773ec2a4..00000000 --- a/quazip/quachecksum32.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef QUACHECKSUM32_H -#define QUACHECKSUM32_H - -#include -#include "quazip_global.h" - -/// Checksum interface. -/** \class QuaChecksum32 quachecksum32.h - * This is an interface for 32 bit checksums. - * Classes implementing this interface can calcunate a certin - * checksum in a single step: - * \code - * QChecksum32 *crc32 = new QuaCrc32(); - * rasoult = crc32->calculate(data); - * \endcode - * or by streaming the data: - * \code - * QChecksum32 *crc32 = new QuaCrc32(); - * while(!fileA.atEnd()) - * crc32->update(fileA.read(bufSize)); - * resoultA = crc32->value(); - * crc32->reset(); - * while(!fileB.atEnd()) - * crc32->update(fileB.read(bufSize)); - * resoultB = crc32->value(); - * \endcode - */ -class QUAZIP_EXPORT QuaChecksum32 -{ - -public: - ///Calculates the checksum for data. - /** \a data source data - * \return data checksum - * - * This function has no efect on the value returned by value(). - */ - virtual quint32 calculate(const QByteArray &data) = 0; - - ///Resets the calculation on a checksun for a stream. - virtual void reset() = 0; - - ///Updates the calculated checksum for the stream - /** \a buf next portion of data from the stream - */ - virtual void update(const QByteArray &buf) = 0; - - ///Value of the checksum calculated for the stream passed throw update(). - /** \return checksum - */ - virtual quint32 value() = 0; -}; - -#endif //QUACHECKSUM32_H diff --git a/quazip/quacrc32.cpp b/quazip/quacrc32.cpp deleted file mode 100644 index 9381f24c..00000000 --- a/quazip/quacrc32.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "quacrc32.h" - -#include "zlib.h" - -QuaCrc32::QuaCrc32() -{ - reset(); -} - -quint32 QuaCrc32::calculate(const QByteArray &data) -{ - return crc32( crc32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() ); -} - -void QuaCrc32::reset() -{ - checksum = crc32(0L, Z_NULL, 0); -} - -void QuaCrc32::update(const QByteArray &buf) -{ - checksum = crc32( checksum, (const Bytef*)buf.data(), buf.size() ); -} - -quint32 QuaCrc32::value() -{ - return checksum; -} diff --git a/quazip/quacrc32.h b/quazip/quacrc32.h deleted file mode 100644 index 4c86d566..00000000 --- a/quazip/quacrc32.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef QUACRC32_H -#define QUACRC32_H - -#include "quachecksum32.h" - -///CRC32 checksum -/** \class QuaCrc32 quacrc32.h -* This class wrappers the crc32 function with the QuaChecksum32 interface. -* See QuaChecksum32 for more info. -*/ -class QUAZIP_EXPORT QuaCrc32 : public QuaChecksum32 { - -public: - QuaCrc32(); - - quint32 calculate(const QByteArray &data); - - void reset(); - void update(const QByteArray &buf); - quint32 value(); - -private: - quint32 checksum; -}; - -#endif //QUACRC32_H diff --git a/quazip/quagzipfile.cpp b/quazip/quagzipfile.cpp deleted file mode 100644 index c1c70aad..00000000 --- a/quazip/quagzipfile.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include - -#include "quagzipfile.h" - -class QuaGzipFilePrivate { - friend class QuaGzipFile; - QString fileName; - gzFile gzd; - inline QuaGzipFilePrivate(): gzd(NULL) {} - inline QuaGzipFilePrivate(const QString &fileName): - fileName(fileName), gzd(NULL) {} - template bool open(FileId id, - QIODevice::OpenMode mode, QString &error); - gzFile open(int fd, const char *modeString); - gzFile open(const QString &name, const char *modeString); -}; - -gzFile QuaGzipFilePrivate::open(const QString &name, const char *modeString) -{ - return gzopen(QFile::encodeName(name).constData(), modeString); -} - -gzFile QuaGzipFilePrivate::open(int fd, const char *modeString) -{ - return gzdopen(fd, modeString); -} - -template -bool QuaGzipFilePrivate::open(FileId id, QIODevice::OpenMode mode, - QString &error) -{ - char modeString[2]; - modeString[0] = modeString[1] = '\0'; - if ((mode & QIODevice::ReadOnly) != 0 - && (mode & QIODevice::WriteOnly) != 0) { - error = QuaGzipFile::trUtf8("Opening gzip for both reading" - " and writing is not supported"); - return false; - } else if ((mode & QIODevice::ReadOnly) != 0) { - modeString[0] = 'r'; - } else if ((mode & QIODevice::WriteOnly) != 0) { - modeString[0] = 'w'; - } else { - error = QuaGzipFile::trUtf8("You can open a gzip either for reading" - " or for writing. Which is it?"); - return false; - } - gzd = open(id, modeString); - if (gzd == NULL) { - error = QuaGzipFile::trUtf8("Could not gzopen() file"); - return false; - } - return true; -} - -QuaGzipFile::QuaGzipFile(): -d(new QuaGzipFilePrivate()) -{ -} - -QuaGzipFile::QuaGzipFile(QObject *parent): -QIODevice(parent), -d(new QuaGzipFilePrivate()) -{ -} - -QuaGzipFile::QuaGzipFile(const QString &fileName, QObject *parent): - QIODevice(parent), -d(new QuaGzipFilePrivate(fileName)) -{ -} - -QuaGzipFile::~QuaGzipFile() -{ - if (isOpen()) { - close(); - } - delete d; -} - -void QuaGzipFile::setFileName(const QString& fileName) -{ - d->fileName = fileName; -} - -QString QuaGzipFile::getFileName() const -{ - return d->fileName; -} - -bool QuaGzipFile::isSequential() const -{ - return true; -} - -bool QuaGzipFile::open(QIODevice::OpenMode mode) -{ - QString error; - if (!d->open(d->fileName, mode, error)) { - setErrorString(error); - return false; - } - return QIODevice::open(mode); -} - -bool QuaGzipFile::open(int fd, QIODevice::OpenMode mode) -{ - QString error; - if (!d->open(fd, mode, error)) { - setErrorString(error); - return false; - } - return QIODevice::open(mode); -} - -bool QuaGzipFile::flush() -{ - return gzflush(d->gzd, Z_SYNC_FLUSH) == Z_OK; -} - -void QuaGzipFile::close() -{ - QIODevice::close(); - gzclose(d->gzd); -} - -qint64 QuaGzipFile::readData(char *data, qint64 maxSize) -{ - return gzread(d->gzd, (voidp)data, (unsigned)maxSize); -} - -qint64 QuaGzipFile::writeData(const char *data, qint64 maxSize) -{ - if (maxSize == 0) - return 0; - int written = gzwrite(d->gzd, (voidp)data, (unsigned)maxSize); - if (written == 0) - return -1; - else - return written; -} diff --git a/quazip/quagzipfile.h b/quazip/quagzipfile.h deleted file mode 100644 index 211ceadb..00000000 --- a/quazip/quagzipfile.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef QUAZIP_QUAGZIPFILE_H -#define QUAZIP_QUAGZIPFILE_H - -#include -#include "quazip_global.h" - -#include - -class QuaGzipFilePrivate; - -class QUAZIP_EXPORT QuaGzipFile: public QIODevice { - Q_OBJECT -public: - QuaGzipFile(); - QuaGzipFile(QObject *parent); - QuaGzipFile(const QString &fileName, QObject *parent = NULL); - virtual ~QuaGzipFile(); - void setFileName(const QString& fileName); - QString getFileName() const; - virtual bool isSequential() const; - virtual bool open(QIODevice::OpenMode mode); - virtual bool open(int fd, QIODevice::OpenMode mode); - virtual bool flush(); - virtual void close(); -protected: - virtual qint64 readData(char *data, qint64 maxSize); - virtual qint64 writeData(const char *data, qint64 maxSize); -private: - // not implemented by design to disable copy - QuaGzipFile(const QuaGzipFile &that); - QuaGzipFile& operator=(const QuaGzipFile &that); - QuaGzipFilePrivate *d; -}; - -#endif // QUAZIP_QUAGZIPFILE_H diff --git a/quazip/quaziodevice.cpp b/quazip/quaziodevice.cpp deleted file mode 100644 index 959ca0e8..00000000 --- a/quazip/quaziodevice.cpp +++ /dev/null @@ -1,283 +0,0 @@ -#include "quaziodevice.h" - -#define QUAZIO_INBUFSIZE 4096 -#define QUAZIO_OUTBUFSIZE 4096 - -class QuaZIODevicePrivate { - friend class QuaZIODevice; - QuaZIODevicePrivate(QIODevice *io); - ~QuaZIODevicePrivate(); - QIODevice *io; - z_stream zins; - z_stream zouts; - char *inBuf; - int inBufPos; - int inBufSize; - char *outBuf; - int outBufPos; - int outBufSize; - bool zBufError; - int doFlush(QString &error); -}; - -QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io): - io(io), - inBuf(NULL), - inBufPos(0), - inBufSize(0), - outBuf(NULL), - outBufPos(0), - outBufSize(0), - zBufError(false) -{ - zins.zalloc = (alloc_func) NULL; - zins.zfree = (free_func) NULL; - zins.opaque = NULL; - zouts.zalloc = (alloc_func) NULL; - zouts.zfree = (free_func) NULL; - zouts.opaque = NULL; - inBuf = new char[QUAZIO_INBUFSIZE]; - outBuf = new char[QUAZIO_OUTBUFSIZE]; -#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT - debug.setFileName("debug.out"); - debug.open(QIODevice::WriteOnly); -#endif -#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT - indebug.setFileName("debug.in"); - indebug.open(QIODevice::WriteOnly); -#endif -} - -QuaZIODevicePrivate::~QuaZIODevicePrivate() -{ -#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT - debug.close(); -#endif -#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT - indebug.close(); -#endif - if (inBuf != NULL) - delete[] inBuf; - if (outBuf != NULL) - delete[] outBuf; -} - -int QuaZIODevicePrivate::doFlush(QString &error) -{ - int flushed = 0; - while (outBufPos < outBufSize) { - int more = io->write(outBuf + outBufPos, outBufSize - outBufPos); - if (more == -1) { - error = io->errorString(); - return -1; - } - if (more == 0) - break; - outBufPos += more; - flushed += more; - } - if (outBufPos == outBufSize) { - outBufPos = outBufSize = 0; - } - return flushed; -} - -// #define QUAZIP_ZIODEVICE_DEBUG_OUTPUT -// #define QUAZIP_ZIODEVICE_DEBUG_INPUT -#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT -#include -static QFile debug; -#endif -#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT -#include -static QFile indebug; -#endif - -QuaZIODevice::QuaZIODevice(QIODevice *io, QObject *parent): - QIODevice(parent), - d(new QuaZIODevicePrivate(io)) -{ - connect(io, SIGNAL(readyRead()), SIGNAL(readyRead())); -} - -QuaZIODevice::~QuaZIODevice() -{ - if (isOpen()) - close(); - delete d; -} - -QIODevice *QuaZIODevice::getIoDevice() const -{ - return d->io; -} - -bool QuaZIODevice::open(QIODevice::OpenMode mode) -{ - if ((mode & QIODevice::ReadOnly) != 0) { - if (inflateInit(&d->zins) != Z_OK) { - setErrorString(d->zins.msg); - return false; - } - } - if ((mode & QIODevice::WriteOnly) != 0) { - if (deflateInit(&d->zouts, Z_DEFAULT_COMPRESSION) != Z_OK) { - setErrorString(d->zouts.msg); - return false; - } - } - return QIODevice::open(mode); -} - -void QuaZIODevice::close() -{ - if ((openMode() & QIODevice::ReadOnly) != 0) { - if (inflateEnd(&d->zins) != Z_OK) { - setErrorString(d->zins.msg); - } - } - if ((openMode() & QIODevice::WriteOnly) != 0) { - flush(); - if (deflateEnd(&d->zouts) != Z_OK) { - setErrorString(d->zouts.msg); - } - } - QIODevice::close(); -} - -qint64 QuaZIODevice::readData(char *data, qint64 maxSize) -{ - int read = 0; - while (read < maxSize) { - if (d->inBufPos == d->inBufSize) { - d->inBufPos = 0; - d->inBufSize = d->io->read(d->inBuf, QUAZIO_INBUFSIZE); - if (d->inBufSize == -1) { - d->inBufSize = 0; - setErrorString(d->io->errorString()); - return -1; - } - if (d->inBufSize == 0) - break; - } - while (read < maxSize && d->inBufPos < d->inBufSize) { - d->zins.next_in = (Bytef *) (d->inBuf + d->inBufPos); - d->zins.avail_in = d->inBufSize - d->inBufPos; - d->zins.next_out = (Bytef *) (data + read); - d->zins.avail_out = (uInt) (maxSize - read); // hope it's less than 2GB - int more = 0; - switch (inflate(&d->zins, Z_SYNC_FLUSH)) { - case Z_OK: - read = (char *) d->zins.next_out - data; - d->inBufPos = (char *) d->zins.next_in - d->inBuf; - break; - case Z_STREAM_END: - read = (char *) d->zins.next_out - data; - d->inBufPos = (char *) d->zins.next_in - d->inBuf; - return read; - case Z_BUF_ERROR: // this should never happen, but just in case - if (!d->zBufError) { - qWarning("Z_BUF_ERROR detected with %d/%d in/out, weird", - d->zins.avail_in, d->zins.avail_out); - d->zBufError = true; - } - memmove(d->inBuf, d->inBuf + d->inBufPos, d->inBufSize - d->inBufPos); - d->inBufSize -= d->inBufPos; - d->inBufPos = 0; - more = d->io->read(d->inBuf + d->inBufSize, QUAZIO_INBUFSIZE - d->inBufSize); - if (more == -1) { - setErrorString(d->io->errorString()); - return -1; - } - if (more == 0) - return read; - d->inBufSize += more; - break; - default: - setErrorString(QString::fromLocal8Bit(d->zins.msg)); - return -1; - } - } - } -#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT - indebug.write(data, read); -#endif - return read; -} - -qint64 QuaZIODevice::writeData(const char *data, qint64 maxSize) -{ - int written = 0; - QString error; - if (d->doFlush(error) == -1) { - setErrorString(error); - return -1; - } - while (written < maxSize) { - // there is some data waiting in the output buffer - if (d->outBufPos < d->outBufSize) - return written; - d->zouts.next_in = (Bytef *) (data + written); - d->zouts.avail_in = (uInt) (maxSize - written); // hope it's less than 2GB - d->zouts.next_out = (Bytef *) d->outBuf; - d->zouts.avail_out = QUAZIO_OUTBUFSIZE; - switch (deflate(&d->zouts, Z_NO_FLUSH)) { - case Z_OK: - written = (char *) d->zouts.next_in - data; - d->outBufSize = (char *) d->zouts.next_out - d->outBuf; - break; - default: - setErrorString(QString::fromLocal8Bit(d->zouts.msg)); - return -1; - } - if (d->doFlush(error) == -1) { - setErrorString(error); - return -1; - } - } -#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT - debug.write(data, written); -#endif - return written; -} - -bool QuaZIODevice::flush() -{ - QString error; - if (d->doFlush(error) < 0) { - setErrorString(error); - return false; - } - // can't flush buffer, some data is still waiting - if (d->outBufPos < d->outBufSize) - return true; - Bytef c = 0; - d->zouts.next_in = &c; // fake input buffer - d->zouts.avail_in = 0; // of zero size - do { - d->zouts.next_out = (Bytef *) d->outBuf; - d->zouts.avail_out = QUAZIO_OUTBUFSIZE; - switch (deflate(&d->zouts, Z_SYNC_FLUSH)) { - case Z_OK: - d->outBufSize = (char *) d->zouts.next_out - d->outBuf; - if (d->doFlush(error) < 0) { - setErrorString(error); - return false; - } - if (d->outBufPos < d->outBufSize) - return true; - break; - case Z_BUF_ERROR: // nothing to write? - return true; - default: - setErrorString(QString::fromLocal8Bit(d->zouts.msg)); - return false; - } - } while (d->zouts.avail_out == 0); - return true; -} - -bool QuaZIODevice::isSequential() const -{ - return true; -} diff --git a/quazip/quaziodevice.h b/quazip/quaziodevice.h deleted file mode 100644 index b061cd16..00000000 --- a/quazip/quaziodevice.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef QUAZIP_QUAZIODEVICE_H -#define QUAZIP_QUAZIODEVICE_H - -#include -#include "quazip_global.h" - -#include - -class QuaZIODevicePrivate; - -class QUAZIP_EXPORT QuaZIODevice: public QIODevice { - Q_OBJECT -public: - QuaZIODevice(QIODevice *io, QObject *parent = NULL); - ~QuaZIODevice(); - virtual bool flush(); - virtual bool open(QIODevice::OpenMode); - virtual void close(); - QIODevice *getIoDevice() const; - virtual bool isSequential() const; -protected: - virtual qint64 readData(char *data, qint64 maxSize); - virtual qint64 writeData(const char *data, qint64 maxSize); -private: - QuaZIODevicePrivate *d; -}; -#endif // QUAZIP_QUAZIODEVICE_H diff --git a/quazip/quazip.cpp b/quazip/quazip.cpp deleted file mode 100644 index b6fa92f0..00000000 --- a/quazip/quazip.cpp +++ /dev/null @@ -1,554 +0,0 @@ -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser 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 Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser 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 - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include -#include - -#include "quazip.h" - -/// All the internal stuff for the QuaZip class. -/** - \internal - - This class keeps all the private stuff for the QuaZip class so it can - be changed without breaking binary compatibility, according to the - Pimpl idiom. - */ -class QuaZipPrivate { - friend class QuaZip; - private: - /// The pointer to the corresponding QuaZip instance. - QuaZip *q; - /// The codec for file names. - QTextCodec *fileNameCodec; - /// The codec for comments. - QTextCodec *commentCodec; - /// The archive file name. - QString zipName; - /// The device to access the archive. - QIODevice *ioDevice; - /// The global comment. - QString comment; - /// The open mode. - QuaZip::Mode mode; - union { - /// The internal handle for UNZIP modes. - unzFile unzFile_f; - /// The internal handle for ZIP modes. - zipFile zipFile_f; - }; - /// Whether a current file is set. - bool hasCurrentFile_f; - /// The last error. - int zipError; - /// Whether \ref QuaZip::setDataDescriptorWritingEnabled() "the data descriptor writing mode" is enabled. - bool dataDescriptorWritingEnabled; - /// The constructor for the corresponding QuaZip constructor. - inline QuaZipPrivate(QuaZip *q): - q(q), - fileNameCodec(QTextCodec::codecForLocale()), - commentCodec(QTextCodec::codecForLocale()), - ioDevice(NULL), - mode(QuaZip::mdNotOpen), - hasCurrentFile_f(false), - zipError(UNZ_OK), - dataDescriptorWritingEnabled(true) {} - /// The constructor for the corresponding QuaZip constructor. - inline QuaZipPrivate(QuaZip *q, const QString &zipName): - q(q), - fileNameCodec(QTextCodec::codecForLocale()), - commentCodec(QTextCodec::codecForLocale()), - zipName(zipName), - ioDevice(NULL), - mode(QuaZip::mdNotOpen), - hasCurrentFile_f(false), - zipError(UNZ_OK), - dataDescriptorWritingEnabled(true) {} - /// The constructor for the corresponding QuaZip constructor. - inline QuaZipPrivate(QuaZip *q, QIODevice *ioDevice): - q(q), - fileNameCodec(QTextCodec::codecForLocale()), - commentCodec(QTextCodec::codecForLocale()), - ioDevice(ioDevice), - mode(QuaZip::mdNotOpen), - hasCurrentFile_f(false), - zipError(UNZ_OK), - dataDescriptorWritingEnabled(true) {} - /// Returns either a list of file names or a list of QuaZipFileInfo. - template - bool getFileInfoList(QList *result) const; -}; - -QuaZip::QuaZip(): - p(new QuaZipPrivate(this)) -{ -} - -QuaZip::QuaZip(const QString& zipName): - p(new QuaZipPrivate(this, zipName)) -{ -} - -QuaZip::QuaZip(QIODevice *ioDevice): - p(new QuaZipPrivate(this, ioDevice)) -{ -} - -QuaZip::~QuaZip() -{ - if(isOpen()) - close(); - delete p; -} - -bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi) -{ - p->zipError=UNZ_OK; - if(isOpen()) { - qWarning("QuaZip::open(): ZIP already opened"); - return false; - } - QIODevice *ioDevice = p->ioDevice; - if (ioDevice == NULL) { - if (p->zipName.isEmpty()) { - qWarning("QuaZip::open(): set either ZIP file name or IO device first"); - return false; - } else { - ioDevice = new QFile(p->zipName); - } - } - switch(mode) { - case mdUnzip: - p->unzFile_f=unzOpen2(ioDevice, ioApi); - if(p->unzFile_f!=NULL) { - p->mode=mode; - p->ioDevice = ioDevice; - return true; - } else { - p->zipError=UNZ_OPENERROR; - if (!p->zipName.isEmpty()) - delete ioDevice; - return false; - } - case mdCreate: - case mdAppend: - case mdAdd: - p->zipFile_f=zipOpen2(ioDevice, - mode==mdCreate?APPEND_STATUS_CREATE: - mode==mdAppend?APPEND_STATUS_CREATEAFTER: - APPEND_STATUS_ADDINZIP, - NULL, - ioApi); - if(p->zipFile_f!=NULL) { - p->mode=mode; - p->ioDevice = ioDevice; - return true; - } else { - p->zipError=UNZ_OPENERROR; - if (!p->zipName.isEmpty()) - delete ioDevice; - return false; - } - default: - qWarning("QuaZip::open(): unknown mode: %d", (int)mode); - if (!p->zipName.isEmpty()) - delete ioDevice; - return false; - break; - } -} - -void QuaZip::close() -{ - p->zipError=UNZ_OK; - switch(p->mode) { - case mdNotOpen: - qWarning("QuaZip::close(): ZIP is not open"); - return; - case mdUnzip: - p->zipError=unzClose(p->unzFile_f); - break; - case mdCreate: - case mdAppend: - case mdAdd: - p->zipError=zipClose(p->zipFile_f, - p->comment.isNull() ? NULL - : p->commentCodec->fromUnicode(p->comment).constData()); - break; - default: - qWarning("QuaZip::close(): unknown mode: %d", (int)p->mode); - return; - } - // opened by name, need to delete the internal IO device - if (!p->zipName.isEmpty()) { - delete p->ioDevice; - p->ioDevice = NULL; - } - if(p->zipError==UNZ_OK) - p->mode=mdNotOpen; -} - -void QuaZip::setZipName(const QString& zipName) -{ - if(isOpen()) { - qWarning("QuaZip::setZipName(): ZIP is already open!"); - return; - } - p->zipName=zipName; - p->ioDevice = NULL; -} - -void QuaZip::setIoDevice(QIODevice *ioDevice) -{ - if(isOpen()) { - qWarning("QuaZip::setIoDevice(): ZIP is already open!"); - return; - } - p->ioDevice = ioDevice; - p->zipName = QString(); -} - -int QuaZip::getEntriesCount()const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode"); - return -1; - } - unz_global_info globalInfo; - if((fakeThis->p->zipError=unzGetGlobalInfo(p->unzFile_f, &globalInfo))!=UNZ_OK) - return p->zipError; - return (int)globalInfo.number_entry; -} - -QString QuaZip::getComment()const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode"); - return QString(); - } - unz_global_info globalInfo; - QByteArray comment; - if((fakeThis->p->zipError=unzGetGlobalInfo(p->unzFile_f, &globalInfo))!=UNZ_OK) - return QString(); - comment.resize(globalInfo.size_comment); - if((fakeThis->p->zipError=unzGetGlobalComment(p->unzFile_f, comment.data(), comment.size())) < 0) - return QString(); - fakeThis->p->zipError = UNZ_OK; - return p->commentCodec->toUnicode(comment); -} - -bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs) -{ - p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode"); - return false; - } - if(fileName.isEmpty()) { - p->hasCurrentFile_f=false; - return true; - } - // Unicode-aware reimplementation of the unzLocateFile function - if(p->unzFile_f==NULL) { - p->zipError=UNZ_PARAMERROR; - return false; - } - if(fileName.length()>MAX_FILE_NAME_LENGTH) { - p->zipError=UNZ_PARAMERROR; - return false; - } - bool sens = convertCaseSensitivity(cs) == Qt::CaseSensitive; - QString lower, current; - if(!sens) lower=fileName.toLower(); - p->hasCurrentFile_f=false; - for(bool more=goToFirstFile(); more; more=goToNextFile()) { - current=getCurrentFileName(); - if(current.isEmpty()) return false; - if(sens) { - if(current==fileName) break; - } else { - if(current.toLower()==lower) break; - } - } - return p->hasCurrentFile_f; -} - -bool QuaZip::goToFirstFile() -{ - p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); - return false; - } - p->zipError=unzGoToFirstFile(p->unzFile_f); - p->hasCurrentFile_f=p->zipError==UNZ_OK; - return p->hasCurrentFile_f; -} - -bool QuaZip::goToNextFile() -{ - p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); - return false; - } - p->zipError=unzGoToNextFile(p->unzFile_f); - p->hasCurrentFile_f=p->zipError==UNZ_OK; - if(p->zipError==UNZ_END_OF_LIST_OF_FILE) - p->zipError=UNZ_OK; - return p->hasCurrentFile_f; -} - -bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode"); - return false; - } - unz_file_info info_z; - QByteArray fileName; - QByteArray extra; - QByteArray comment; - if(info==NULL) return false; - if(!isOpen()||!hasCurrentFile()) return false; - if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0))!=UNZ_OK) - return false; - fileName.resize(info_z.size_filename); - extra.resize(info_z.size_file_extra); - comment.resize(info_z.size_file_comment); - if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, NULL, - fileName.data(), fileName.size(), - extra.data(), extra.size(), - comment.data(), comment.size()))!=UNZ_OK) - return false; - info->versionCreated=info_z.version; - info->versionNeeded=info_z.version_needed; - info->flags=info_z.flag; - info->method=info_z.compression_method; - info->crc=info_z.crc; - info->compressedSize=info_z.compressed_size; - info->uncompressedSize=info_z.uncompressed_size; - info->diskNumberStart=info_z.disk_num_start; - info->internalAttr=info_z.internal_fa; - info->externalAttr=info_z.external_fa; - info->name=p->fileNameCodec->toUnicode(fileName); - info->comment=p->commentCodec->toUnicode(comment); - info->extra=extra; - info->dateTime=QDateTime( - QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon+1, info_z.tmu_date.tm_mday), - QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec)); - return true; -} - -QString QuaZip::getCurrentFileName()const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode"); - return QString(); - } - if(!isOpen()||!hasCurrentFile()) return QString(); - QByteArray fileName(MAX_FILE_NAME_LENGTH, 0); - if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, NULL, fileName.data(), fileName.size(), - NULL, 0, NULL, 0))!=UNZ_OK) - return QString(); - return p->fileNameCodec->toUnicode(fileName.constData()); -} - -void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec) -{ - p->fileNameCodec=fileNameCodec; -} - -void QuaZip::setFileNameCodec(const char *fileNameCodecName) -{ - p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName); -} - -QTextCodec *QuaZip::getFileNameCodec()const -{ - return p->fileNameCodec; -} - -void QuaZip::setCommentCodec(QTextCodec *commentCodec) -{ - p->commentCodec=commentCodec; -} - -void QuaZip::setCommentCodec(const char *commentCodecName) -{ - p->commentCodec=QTextCodec::codecForName(commentCodecName); -} - -QTextCodec *QuaZip::getCommentCodec()const -{ - return p->commentCodec; -} - -QString QuaZip::getZipName() const -{ - return p->zipName; -} - -QIODevice *QuaZip::getIoDevice() const -{ - if (!p->zipName.isEmpty()) // opened by name, using an internal QIODevice - return NULL; - return p->ioDevice; -} - -QuaZip::Mode QuaZip::getMode()const -{ - return p->mode; -} - -bool QuaZip::isOpen()const -{ - return p->mode!=mdNotOpen; -} - -int QuaZip::getZipError() const -{ - return p->zipError; -} - -void QuaZip::setComment(const QString& comment) -{ - p->comment=comment; -} - -bool QuaZip::hasCurrentFile()const -{ - return p->hasCurrentFile_f; -} - -unzFile QuaZip::getUnzFile() -{ - return p->unzFile_f; -} - -zipFile QuaZip::getZipFile() -{ - return p->zipFile_f; -} - -void QuaZip::setDataDescriptorWritingEnabled(bool enabled) -{ - p->dataDescriptorWritingEnabled = enabled; -} - -bool QuaZip::isDataDescriptorWritingEnabled() const -{ - return p->dataDescriptorWritingEnabled; -} - -template -TFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok); - -template<> -QuaZipFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok) -{ - QuaZipFileInfo info; - *ok = zip->getCurrentFileInfo(&info); - return info; -} - -template<> -QString QuaZip_getFileInfo(QuaZip *zip, bool *ok) -{ - QString name = zip->getCurrentFileName(); - *ok = !name.isEmpty(); - return name; -} - -template -bool QuaZipPrivate::getFileInfoList(QList *result) const -{ - QuaZipPrivate *fakeThis=const_cast(this); - fakeThis->zipError=UNZ_OK; - if (mode!=QuaZip::mdUnzip) { - qWarning("QuaZip::getFileNameList/getFileInfoList(): " - "ZIP is not open in mdUnzip mode"); - return false; - } - QString currentFile; - if (q->hasCurrentFile()) { - currentFile = q->getCurrentFileName(); - } - if (q->goToFirstFile()) { - do { - bool ok; - result->append(QuaZip_getFileInfo(q, &ok)); - if (!ok) - return false; - } while (q->goToNextFile()); - } - if (zipError != UNZ_OK) - return false; - if (currentFile.isEmpty()) { - if (!q->goToFirstFile()) - return false; - } else { - if (!q->setCurrentFile(currentFile)) - return false; - } - return true; -} - -QStringList QuaZip::getFileNameList() const -{ - QStringList list; - if (p->getFileInfoList(&list)) - return list; - else - return QStringList(); -} - -QList QuaZip::getFileInfoList() const -{ - QList list; - if (p->getFileInfoList(&list)) - return list; - else - return QList(); -} - -Qt::CaseSensitivity QuaZip::convertCaseSensitivity(QuaZip::CaseSensitivity cs) -{ - if (cs == csDefault) { -#ifdef Q_WS_WIN - return Qt::CaseInsensitive; -#else - return Qt::CaseSensitive; -#endif - } else { - return cs == csSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; - } -} diff --git a/quazip/quazip.h b/quazip/quazip.h deleted file mode 100644 index a3ab8e52..00000000 --- a/quazip/quazip.h +++ /dev/null @@ -1,411 +0,0 @@ -#ifndef QUA_ZIP_H -#define QUA_ZIP_H - -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser 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 Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser 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 - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include -#include -#include - -#include "zip.h" -#include "unzip.h" - -#include "quazip_global.h" -#include "quazipfileinfo.h" - -// just in case it will be defined in the later versions of the ZIP/UNZIP -#ifndef UNZ_OPENERROR -// define additional error code -#define UNZ_OPENERROR -1000 -#endif - -class QuaZipPrivate; - -/// ZIP archive. -/** \class QuaZip quazip.h - * This class implements basic interface to the ZIP archive. It can be - * used to read table contents of the ZIP archive and retreiving - * information about the files inside it. - * - * You can also use this class to open files inside archive by passing - * pointer to the instance of this class to the constructor of the - * QuaZipFile class. But see QuaZipFile::QuaZipFile(QuaZip*, QObject*) - * for the possible pitfalls. - * - * This class is indended to provide interface to the ZIP subpackage of - * the ZIP/UNZIP package as well as to the UNZIP subpackage. But - * currently it supports only UNZIP. - * - * The use of this class is simple - just create instance using - * constructor, then set ZIP archive file name using setFile() function - * (if you did not passed the name to the constructor), then open() and - * then use different functions to work with it! Well, if you are - * paranoid, you may also wish to call close before destructing the - * instance, to check for errors on close. - * - * You may also use getUnzFile() and getZipFile() functions to get the - * ZIP archive handle and use it with ZIP/UNZIP package API directly. - * - * This class supports localized file names inside ZIP archive, but you - * have to set up proper codec with setCodec() function. By default, - * locale codec will be used, which is probably ok for UNIX systems, but - * will almost certainly fail with ZIP archives created in Windows. This - * is because Windows ZIP programs have strange habit of using DOS - * encoding for file names in ZIP archives. For example, ZIP archive - * with cyrillic names created in Windows will have file names in \c - * IBM866 encoding instead of \c WINDOWS-1251. I think that calling one - * function is not much trouble, but for true platform independency it - * would be nice to have some mechanism for file name encoding auto - * detection using locale information. Does anyone know a good way to do - * it? - **/ -class QUAZIP_EXPORT QuaZip { - friend class QuaZipPrivate; - public: - /// Useful constants. - enum Constants { - MAX_FILE_NAME_LENGTH=256 /**< Maximum file name length. Taken from - \c UNZ_MAXFILENAMEINZIP constant in - unzip.c. */ - }; - /// Open mode of the ZIP file. - enum Mode { - mdNotOpen, ///< ZIP file is not open. This is the initial mode. - mdUnzip, ///< ZIP file is open for reading files inside it. - mdCreate, ///< ZIP file was created with open() call. - mdAppend, /**< ZIP file was opened in append mode. This refers to - * \c APPEND_STATUS_CREATEAFTER mode in ZIP/UNZIP package - * and means that zip is appended to some existing file - * what is useful when that file contains - * self-extractor code. This is obviously \em not what - * you whant to use to add files to the existing ZIP - * archive. - **/ - mdAdd ///< ZIP file was opened for adding files in the archive. - }; - /// Case sensitivity for the file names. - /** This is what you specify when accessing files in the archive. - * Works perfectly fine with any characters thanks to Qt's great - * unicode support. This is different from ZIP/UNZIP API, where - * only US-ASCII characters was supported. - **/ - enum CaseSensitivity { - csDefault=0, ///< Default for platform. Case sensitive for UNIX, not for Windows. - csSensitive=1, ///< Case sensitive. - csInsensitive=2 ///< Case insensitive. - }; - static Qt::CaseSensitivity convertCaseSensitivity(CaseSensitivity); - private: - QuaZipPrivate *p; - // not (and will not be) implemented - QuaZip(const QuaZip& that); - // not (and will not be) implemented - QuaZip& operator=(const QuaZip& that); - public: - /// Constructs QuaZip object. - /** Call setName() before opening constructed object. */ - QuaZip(); - /// Constructs QuaZip object associated with ZIP file \a zipName. - QuaZip(const QString& zipName); - /// Constructs QuaZip object associated with ZIP file represented by \a ioDevice. - /** The IO device must be seekable, otherwise an error will occur when opening. */ - QuaZip(QIODevice *ioDevice); - /// Destroys QuaZip object. - /** Calls close() if necessary. */ - ~QuaZip(); - /// Opens ZIP file. - /** - * Argument \a mode specifies open mode of the ZIP archive. See Mode - * for details. Note that there is zipOpen2() function in the - * ZIP/UNZIP API which accepts \a globalcomment argument, but it - * does not use it anywhere, so this open() function does not have this - * argument. See setComment() if you need to set global comment. - * - * If the ZIP file is accessed via explicitly set QIODevice, then - * this device is opened in the necessary mode. If the device was - * already opened by some other means, then the behaviour is defined by - * the device implementation, but generally it is not a very good - * idea. For example, QFile will at least issue a warning. - * - * \return \c true if successful, \c false otherwise. - * - * \note ZIP/UNZIP API open calls do not return error code - they - * just return \c NULL indicating an error. But to make things - * easier, quazip.h header defines additional error code \c - * UNZ_ERROROPEN and getZipError() will return it if the open call - * of the ZIP/UNZIP API returns \c NULL. - * - * Argument \a ioApi specifies IO function set for ZIP/UNZIP - * package to use. See unzip.h, zip.h and ioapi.h for details. Note - * that IO API for QuaZip is different from the original package. - * The file path argument was changed to be of type \c voidpf, and - * QuaZip passes a QIODevice pointer there. This QIODevice is either - * set explicitly via setIoDevice() or the QuaZip(QIODevice*) - * constructor, or it is created internally when opening the archive - * by its file name. The default API (qioapi.cpp) just delegates - * everything to the QIODevice API. Not only this allows to use a - * QIODevice instead of file name, but also has a nice side effect - * of raising the file size limit from 2G to 4G. - * - * In short: just forget about the \a ioApi argument and you'll be - * fine. - **/ - bool open(Mode mode, zlib_filefunc_def *ioApi =NULL); - /// Closes ZIP file. - /** Call getZipError() to determine if the close was successful. The - * underlying QIODevice is also closed, regardless of whether it was - * set explicitly or not. */ - void close(); - /// Sets the codec used to encode/decode file names inside archive. - /** This is necessary to access files in the ZIP archive created - * under Windows with non-latin characters in file names. For - * example, file names with cyrillic letters will be in \c IBM866 - * encoding. - **/ - void setFileNameCodec(QTextCodec *fileNameCodec); - /// Sets the codec used to encode/decode file names inside archive. - /** \overload - * Equivalent to calling setFileNameCodec(QTextCodec::codecForName(codecName)); - **/ - void setFileNameCodec(const char *fileNameCodecName); - /// Returns the codec used to encode/decode comments inside archive. - QTextCodec* getFileNameCodec() const; - /// Sets the codec used to encode/decode comments inside archive. - /** This codec defaults to locale codec, which is probably ok. - **/ - void setCommentCodec(QTextCodec *commentCodec); - /// Sets the codec used to encode/decode comments inside archive. - /** \overload - * Equivalent to calling setCommentCodec(QTextCodec::codecForName(codecName)); - **/ - void setCommentCodec(const char *commentCodecName); - /// Returns the codec used to encode/decode comments inside archive. - QTextCodec* getCommentCodec() const; - /// Returns the name of the ZIP file. - /** Returns null string if no ZIP file name has been set, for - * example when the QuaZip instance is set up to use a QIODevice - * instead. - * \sa setZipName(), setIoDevice(), getIoDevice() - **/ - QString getZipName() const; - /// Sets the name of the ZIP file. - /** Does nothing if the ZIP file is open. - * - * Does not reset error code returned by getZipError(). - * \sa setIoDevice(), getIoDevice(), getZipName() - **/ - void setZipName(const QString& zipName); - /// Returns the device representing this ZIP file. - /** Returns null string if no device has been set explicitly, for - * example when opening a ZIP file by name. - * \sa setIoDevice(), getZipName(), setZipName() - **/ - QIODevice *getIoDevice() const; - /// Sets the device representing the ZIP file. - /** Does nothing if the ZIP file is open. - * - * Does not reset error code returned by getZipError(). - * \sa getIoDevice(), getZipName(), setZipName() - **/ - void setIoDevice(QIODevice *ioDevice); - /// Returns the mode in which ZIP file was opened. - Mode getMode() const; - /// Returns \c true if ZIP file is open, \c false otherwise. - bool isOpen() const; - /// Returns the error code of the last operation. - /** Returns \c UNZ_OK if the last operation was successful. - * - * Error code resets to \c UNZ_OK every time you call any function - * that accesses something inside ZIP archive, even if it is \c - * const (like getEntriesCount()). open() and close() calls reset - * error code too. See documentation for the specific functions for - * details on error detection. - **/ - int getZipError() const; - /// Returns number of the entries in the ZIP central directory. - /** Returns negative error code in the case of error. The same error - * code will be returned by subsequent getZipError() call. - **/ - int getEntriesCount() const; - /// Returns global comment in the ZIP file. - QString getComment() const; - /// Sets the global comment in the ZIP file. - /** The comment will be written to the archive on close operation. - * QuaZip makes a distinction between a null QByteArray() comment - * and an empty "" comment in the QuaZip::mdAdd mode. - * A null comment is the default and it means "don't change - * the comment". An empty comment removes the original comment. - * - * \sa open() - **/ - void setComment(const QString& comment); - /// Sets the current file to the first file in the archive. - /** Returns \c true on success, \c false otherwise. Call - * getZipError() to get the error code. - **/ - bool goToFirstFile(); - /// Sets the current file to the next file in the archive. - /** Returns \c true on success, \c false otherwise. Call - * getZipError() to determine if there was an error. - * - * Should be used only in QuaZip::mdUnzip mode. - * - * \note If the end of file was reached, getZipError() will return - * \c UNZ_OK instead of \c UNZ_END_OF_LIST_OF_FILE. This is to make - * things like this easier: - * \code - * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { - * // do something - * } - * if(zip.getZipError()==UNZ_OK) { - * // ok, there was no error - * } - * \endcode - **/ - bool goToNextFile(); - /// Sets current file by its name. - /** Returns \c true if successful, \c false otherwise. Argument \a - * cs specifies case sensitivity of the file name. Call - * getZipError() in the case of a failure to get error code. - * - * This is not a wrapper to unzLocateFile() function. That is - * because I had to implement locale-specific case-insensitive - * comparison. - * - * Here are the differences from the original implementation: - * - * - If the file was not found, error code is \c UNZ_OK, not \c - * UNZ_END_OF_LIST_OF_FILE (see also goToNextFile()). - * - If this function fails, it unsets the current file rather than - * resetting it back to what it was before the call. - * - * If \a fileName is null string then this function unsets the - * current file and return \c true. Note that you should close the - * file first if it is open! See - * QuaZipFile::QuaZipFile(QuaZip*,QObject*) for the details. - * - * Should be used only in QuaZip::mdUnzip mode. - * - * \sa setFileNameCodec(), CaseSensitivity - **/ - bool setCurrentFile(const QString& fileName, CaseSensitivity cs =csDefault); - /// Returns \c true if the current file has been set. - bool hasCurrentFile() const; - /// Retrieves information about the current file. - /** Fills the structure pointed by \a info. Returns \c true on - * success, \c false otherwise. In the latter case structure pointed - * by \a info remains untouched. If there was an error, - * getZipError() returns error code. - * - * Should be used only in QuaZip::mdUnzip mode. - * - * Does nothing and returns \c false in any of the following cases. - * - ZIP is not open; - * - ZIP does not have current file; - * - \a info is \c NULL; - * - * In all these cases getZipError() returns \c UNZ_OK since there - * is no ZIP/UNZIP API call. - **/ - bool getCurrentFileInfo(QuaZipFileInfo* info)const; - /// Returns the current file name. - /** Equivalent to calling getCurrentFileInfo() and then getting \c - * name field of the QuaZipFileInfo structure, but faster and more - * convenient. - * - * Should be used only in QuaZip::mdUnzip mode. - **/ - QString getCurrentFileName()const; - /// Returns \c unzFile handle. - /** You can use this handle to directly call UNZIP part of the - * ZIP/UNZIP package functions (see unzip.h). - * - * \warning When using the handle returned by this function, please - * keep in mind that QuaZip class is unable to detect any changes - * you make in the ZIP file state (e. g. changing current file, or - * closing the handle). So please do not do anything with this - * handle that is possible to do with the functions of this class. - * Or at least return the handle in the original state before - * calling some another function of this class (including implicit - * destructor calls and calls from the QuaZipFile objects that refer - * to this QuaZip instance!). So if you have changed the current - * file in the ZIP archive - then change it back or you may - * experience some strange behavior or even crashes. - **/ - unzFile getUnzFile(); - /// Returns \c zipFile handle. - /** You can use this handle to directly call ZIP part of the - * ZIP/UNZIP package functions (see zip.h). Warnings about the - * getUnzFile() function also apply to this function. - **/ - zipFile getZipFile(); - /// Changes the data descriptor writing mode. - /** - According to the ZIP format specification, a file inside archive - may have a data descriptor immediately following the file - data. This is reflected by a special flag in the local file header - and in the central directory. By default, QuaZIP sets this flag - and writes the data descriptor unless both method and level were - set to 0, in which case it operates in 1.0-compatible mode and - never writes data descriptors. - - By setting this flag to false, it is possible to disable data - descriptor writing, thus increasing compatibility with archive - readers that don't understand this feature of the ZIP file format. - - Setting this flag affects all the QuaZipFile instances that are - opened after this flag is set. - - The data descriptor writing mode is enabled by default. - - \param enabled If \c true, enable local descriptor writing, - disable it otherwise. - - \sa QuaZipFile::setDataDescriptorWritingEnabled() - */ - void setDataDescriptorWritingEnabled(bool enabled); - /// Returns the data descriptor default writing mode. - /** - \sa setDataDescriptorWritingEnabled() - */ - bool isDataDescriptorWritingEnabled() const; - /// Returns a list of files inside the archive. - /** - \return A list of file names or an empty list if there - was an error or if the archive is empty (call getZipError() to - figure out which). - \sa getFileInfoList() - */ - QStringList getFileNameList() const; - /// Returns information list about all files inside the archive. - /** - \return A list of QuaZipFileInfo objects or an empty list if there - was an error or if the archive is empty (call getZipError() to - figure out which). - \sa getFileNameList() - */ - QList getFileInfoList() const; -}; - -#endif diff --git a/quazip/quazip_global.h b/quazip/quazip_global.h deleted file mode 100644 index d9d09ade..00000000 --- a/quazip/quazip_global.h +++ /dev/null @@ -1,55 +0,0 @@ -/** -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser 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 Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser 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 - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - */ - -#ifndef QUAZIP_GLOBAL_H -#define QUAZIP_GLOBAL_H - -#include - -/** - This is automatically defined when building a static library, but when - including QuaZip sources directly into a project, QUAZIP_STATIC should - be defined explicitly to avoid possible troubles with unnecessary - importing/exporting. - */ -#ifdef QUAZIP_STATIC -#define QUAZIP_EXPORT -#else -/** - * When building a DLL with MSVC, QUAZIP_BUILD must be defined. - * qglobal.h takes care of defining Q_DECL_* correctly for msvc/gcc. - */ -#if defined(QUAZIP_BUILD) - #define QUAZIP_EXPORT Q_DECL_EXPORT -#else - #define QUAZIP_EXPORT Q_DECL_IMPORT -#endif -#endif // QUAZIP_STATIC - -#ifdef __GNUC__ -#define UNUSED __attribute__((__unused__)) -#else -#define UNUSED -#endif - -#endif // QUAZIP_GLOBAL_H diff --git a/quazip/quazipdir.cpp b/quazip/quazipdir.cpp deleted file mode 100644 index 02208894..00000000 --- a/quazip/quazipdir.cpp +++ /dev/null @@ -1,507 +0,0 @@ -#include "quazipdir.h" - -#include -#include - -class QuaZipDirPrivate: public QSharedData { - friend class QuaZipDir; -private: - QuaZipDirPrivate(QuaZip *zip, const QString &dir = QString()): - zip(zip), dir(dir), caseSensitivity(QuaZip::csDefault), - filter(QDir::NoFilter), sorting(QDir::NoSort) {} - QuaZip *zip; - QString dir; - QuaZip::CaseSensitivity caseSensitivity; - QDir::Filters filter; - QStringList nameFilters; - QDir::SortFlags sorting; - template - bool entryInfoList(QStringList nameFilters, QDir::Filters filter, - QDir::SortFlags sort, TFileInfoList &result) const; - inline QString simplePath() const {return QDir::cleanPath(dir);} -}; - -QuaZipDir::QuaZipDir(const QuaZipDir &that): - d(that.d) -{ -} - -QuaZipDir::QuaZipDir(QuaZip *zip, const QString &dir): - d(new QuaZipDirPrivate(zip, dir)) -{ - if (d->dir.startsWith('/')) - d->dir = d->dir.mid(1); -} - -QuaZipDir::~QuaZipDir() -{ -} - -bool QuaZipDir::operator==(const QuaZipDir &that) -{ - return d->zip == that.d->zip && d->dir == that.d->dir; -} - -QuaZipDir& QuaZipDir::operator=(const QuaZipDir &that) -{ - this->d = that.d; - return *this; -} - -QString QuaZipDir::operator[](int pos) const -{ - return entryList().at(pos); -} - -QuaZip::CaseSensitivity QuaZipDir::caseSensitivity() const -{ - return d->caseSensitivity; -} - -bool QuaZipDir::cd(const QString &directoryName) -{ - if (directoryName == "/") { - d->dir = ""; - return true; - } - QString dirName = directoryName; - if (dirName.endsWith('/')) - dirName.chop(1); - if (dirName.contains('/')) { - QuaZipDir dir(*this); - if (dirName.startsWith('/')) { -#ifdef QUAZIP_QUAZIPDIR_DEBUG - qDebug("QuaZipDir::cd(%s): going to /", - dirName.toUtf8().constData()); -#endif - if (!dir.cd("/")) - return false; - } - QStringList path = dirName.split('/', QString::SkipEmptyParts); - for (QStringList::const_iterator i = path.constBegin(); - i != path.end(); - ++i) { - const QString &step = *i; -#ifdef QUAZIP_QUAZIPDIR_DEBUG - qDebug("QuaZipDir::cd(%s): going to %s", - dirName.toUtf8().constData(), - step.toUtf8().constData()); -#endif - if (!dir.cd(step)) - return false; - } - d->dir = dir.path(); - return true; - } else { // no '/' - if (dirName == ".") { - return true; - } else if (dirName == "..") { - if (isRoot()) { - return false; - } else { - int slashPos = d->dir.lastIndexOf('/'); - if (slashPos == -1) { - d->dir = ""; - } else { - d->dir = d->dir.left(slashPos); - } - return true; - } - } else { // a simple subdirectory - if (exists(dirName)) { - if (isRoot()) - d->dir = dirName; - else - d->dir += "/" + dirName; - return true; - } else { - return false; - } - } - } -} - -bool QuaZipDir::cdUp() -{ - return cd(".."); -} - -uint QuaZipDir::count() const -{ - return entryList().count(); -} - -QString QuaZipDir::dirName() const -{ - return QDir(d->dir).dirName(); -} - -QuaZipFileInfo QuaZipDir_getFileInfo(QuaZip *zip, bool *ok, - const QString &relativeName, - bool isReal) -{ - QuaZipFileInfo info; - if (isReal) { - *ok = zip->getCurrentFileInfo(&info); - } else { - *ok = true; - info.compressedSize = 0; - info.crc = 0; - info.diskNumberStart = 0; - info.externalAttr = 0; - info.flags = 0; - info.internalAttr = 0; - info.method = 0; - info.uncompressedSize = 0; - info.versionCreated = info.versionNeeded = 0; - } - info.name = relativeName; - return info; -} - -template -void QuaZipDir_convertInfoList(const QList &from, TFileInfoList &to); - -template<> -void QuaZipDir_convertInfoList(const QList &from, QList &to) -{ - to = from; -} - -template<> -void QuaZipDir_convertInfoList(const QList &from, QStringList &to) -{ - to.clear(); - for (QList::const_iterator i = from.constBegin(); - i != from.constEnd(); - ++i) { - to.append(i->name); - } -} - -// utility class to restore the current file -class QuaZipDirRestoreCurrent { -public: - inline QuaZipDirRestoreCurrent(QuaZip *zip): - zip(zip), currentFile(zip->getCurrentFileName()) {} - inline ~QuaZipDirRestoreCurrent() - { - zip->setCurrentFile(currentFile); - } -private: - QuaZip *zip; - QString currentFile; -}; - -class QuaZipDirComparator -{ - private: - QDir::SortFlags sort; - static QString getExtension(const QString &name); - int compareStrings(const QString &string1, const QString &string2); - public: - inline QuaZipDirComparator(QDir::SortFlags sort): sort(sort) {} - bool operator()(const QuaZipFileInfo &info1, const QuaZipFileInfo &info2); -}; - -QString QuaZipDirComparator::getExtension(const QString &name) -{ - if (name.endsWith('.') || name.indexOf('.', 1) == -1) { - return ""; - } else { - return name.mid(name.lastIndexOf('.') + 1); - } - -} - -int QuaZipDirComparator::compareStrings(const QString &string1, - const QString &string2) -{ - if (sort & QDir::LocaleAware) { - if (sort & QDir::IgnoreCase) { - return string1.toLower().localeAwareCompare(string2.toLower()); - } else { - return string1.localeAwareCompare(string2); - } - } else { - return string1.compare(string2, (sort & QDir::IgnoreCase) - ? Qt::CaseInsensitive : Qt::CaseSensitive); - } -} - -bool QuaZipDirComparator::operator()(const QuaZipFileInfo &info1, - const QuaZipFileInfo &info2) -{ - QDir::SortFlags order = sort - & (QDir::Name | QDir::Time | QDir::Size | QDir::Type); - if ((sort & QDir::DirsFirst) == QDir::DirsFirst - || (sort & QDir::DirsLast) == QDir::DirsLast) { - if (info1.name.endsWith('/') && !info2.name.endsWith('/')) - return (sort & QDir::DirsFirst) == QDir::DirsFirst; - else if (!info1.name.endsWith('/') && info2.name.endsWith('/')) - return (sort & QDir::DirsLast) == QDir::DirsLast; - } - bool result; - int extDiff; - switch (order) { - case QDir::Name: - result = compareStrings(info1.name, info2.name) < 0; - break; - case QDir::Type: - extDiff = compareStrings(getExtension(info1.name), - getExtension(info2.name)); - if (extDiff == 0) { - result = compareStrings(info1.name, info2.name) < 0; - } else { - result = extDiff < 0; - } - break; - case QDir::Size: - if (info1.uncompressedSize == info2.uncompressedSize) { - result = compareStrings(info1.name, info2.name) < 0; - } else { - result = info1.uncompressedSize < info2.uncompressedSize; - } - break; - case QDir::Time: - if (info1.dateTime == info2.dateTime) { - result = compareStrings(info1.name, info2.name) < 0; - } else { - result = info1.dateTime < info2.dateTime; - } - break; - default: - qWarning("QuaZipDirComparator(): Invalid sort mode 0x%2X", - static_cast(sort)); - return false; - } - return (sort & QDir::Reversed) ? !result : result; -} - -template -bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters, - QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const -{ - QString basePath = simplePath(); - if (!basePath.isEmpty()) - basePath += "/"; - int baseLength = basePath.length(); - result.clear(); - QuaZipDirRestoreCurrent saveCurrent(zip); - if (!zip->goToFirstFile()) { - return zip->getZipError() == UNZ_OK; - } - QDir::Filters fltr = filter; - if (fltr == QDir::NoFilter) - fltr = this->filter; - if (fltr == QDir::NoFilter) - fltr = QDir::AllEntries; - QStringList nmfltr = nameFilters; - if (nmfltr.isEmpty()) - nmfltr = this->nameFilters; - QSet dirsFound; - QList list; - do { - QString name = zip->getCurrentFileName(); - if (!name.startsWith(basePath)) - continue; - QString relativeName = name.mid(baseLength); - bool isDir = false; - bool isReal = true; - if (relativeName.contains('/')) { - int indexOfSlash = relativeName.indexOf('/'); - // something like "subdir/" - isReal = indexOfSlash == relativeName.length() - 1; - relativeName = relativeName.left(indexOfSlash + 1); - if (dirsFound.contains(relativeName)) - continue; - isDir = true; - } - dirsFound.insert(relativeName); - if ((fltr & QDir::Dirs) == 0 && isDir) - continue; - if ((fltr & QDir::Files) == 0 && !isDir) - continue; - if (!nmfltr.isEmpty() && QDir::match(nmfltr, relativeName)) - continue; - bool ok; - QuaZipFileInfo info = QuaZipDir_getFileInfo(zip, &ok, relativeName, - isReal); - if (!ok) { - return false; - } - list.append(info); - } while (zip->goToNextFile()); - QDir::SortFlags srt = sort; - if (srt == QDir::NoSort) - srt = sorting; -#ifdef QUAZIP_QUAZIPDIR_DEBUG - qDebug("QuaZipDirPrivate::entryInfoList(): before sort:"); - foreach (QuaZipFileInfo info, list) { - qDebug("%s\t%s", info.name.toUtf8().constData(), - info.dateTime.toString(Qt::ISODate).toUtf8().constData()); - } -#endif - if (srt != QDir::NoSort && (srt & QDir::Unsorted) != QDir::Unsorted) { - if (QuaZip::convertCaseSensitivity(caseSensitivity) - == Qt::CaseInsensitive) - srt |= QDir::IgnoreCase; - QuaZipDirComparator lessThan(srt); - qSort(list.begin(), list.end(), lessThan); - } - QuaZipDir_convertInfoList(list, result); - return true; -} - -QList QuaZipDir::entryInfoList(const QStringList &nameFilters, - QDir::Filters filters, QDir::SortFlags sort) const -{ - QList result; - if (d->entryInfoList(nameFilters, filters, sort, result)) - return result; - else - return QList(); -} - -QList QuaZipDir::entryInfoList(QDir::Filters filters, - QDir::SortFlags sort) const -{ - return entryInfoList(QStringList(), filters, sort); -} - -QStringList QuaZipDir::entryList(const QStringList &nameFilters, - QDir::Filters filters, QDir::SortFlags sort) const -{ - QStringList result; - if (d->entryInfoList(nameFilters, filters, sort, result)) - return result; - else - return QStringList(); -} - -QStringList QuaZipDir::entryList(QDir::Filters filters, - QDir::SortFlags sort) const -{ - return entryList(QStringList(), filters, sort); -} - -bool QuaZipDir::exists(const QString &filePath) const -{ - if (filePath == "/") - return true; - QString fileName = filePath; - if (fileName.endsWith('/')) - fileName.chop(1); - if (fileName.contains('/')) { - QFileInfo fileInfo(fileName); -#ifdef QUAZIP_QUAZIPDIR_DEBUG - qDebug("QuaZipDir::exists(): fileName=%s, fileInfo.fileName()=%s, " - "fileInfo.path()=%s", fileName.toUtf8().constData(), - fileInfo.fileName().toUtf8().constData(), - fileInfo.path().toUtf8().constData()); -#endif - QuaZipDir dir(*this); - return dir.cd(fileInfo.path()) && dir.exists(fileInfo.fileName()); - } else { - if (fileName == "..") { - return !isRoot(); - } else if (fileName == ".") { - return true; - } else { - QStringList entries = entryList(QDir::AllEntries, QDir::NoSort); -#ifdef QUAZIP_QUAZIPDIR_DEBUG - qDebug("QuaZipDir::exists(): looking for %s", - fileName.toUtf8().constData()); - for (QStringList::const_iterator i = entries.constBegin(); - i != entries.constEnd(); - ++i) { - qDebug("QuaZipDir::exists(): entry: %s", - i->toUtf8().constData()); - } -#endif - Qt::CaseSensitivity cs = QuaZip::convertCaseSensitivity( - d->caseSensitivity); - if (filePath.endsWith('/')) { - return entries.contains(filePath, cs); - } else { - return entries.contains(fileName, cs) - || entries.contains(fileName + "/", cs); - } - } - } -} - -bool QuaZipDir::exists() const -{ - QDir thisDir(d->dir); - return QuaZipDir(d->zip, thisDir.filePath("..")).exists(thisDir.dirName()); -} - -QString QuaZipDir::filePath(const QString &fileName) const -{ - return QDir(d->dir).filePath(fileName); -} - -QDir::Filters QuaZipDir::filter() -{ - return d->filter; -} - -bool QuaZipDir::isRoot() const -{ - return d->simplePath().isEmpty(); -} - -QStringList QuaZipDir::nameFilters() const -{ - return d->nameFilters; -} - -QString QuaZipDir::path() const -{ - return d->dir; -} - -QString QuaZipDir::relativeFilePath(const QString &fileName) const -{ - return QDir(d->dir).relativeFilePath(fileName); -} - -void QuaZipDir::setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity) -{ - d->caseSensitivity = caseSensitivity; -} - -void QuaZipDir::setFilter(QDir::Filters filters) -{ - d->filter = filters; -} - -void QuaZipDir::setNameFilters(const QStringList &nameFilters) -{ - d->nameFilters = nameFilters; -} - -void QuaZipDir::setPath(const QString &path) -{ - QString newDir = path; - if (newDir == "/") { - d->dir = ""; - } else { - if (newDir.endsWith('/')) - newDir.chop(1); - if (newDir.startsWith('/')) - newDir = newDir.mid(1); - d->dir = newDir; - } -} - -void QuaZipDir::setSorting(QDir::SortFlags sort) -{ - d->sorting = sort; -} - -QDir::SortFlags QuaZipDir::sorting() const -{ - return d->sorting; -} diff --git a/quazip/quazipdir.h b/quazip/quazipdir.h deleted file mode 100644 index e2d70bc8..00000000 --- a/quazip/quazipdir.h +++ /dev/null @@ -1,171 +0,0 @@ -#ifndef QUAZIP_QUAZIPDIR_H -#define QUAZIP_QUAZIPDIR_H - -class QuaZipDirPrivate; - -#include "quazip.h" -#include "quazipfileinfo.h" -#include -#include -#include - -/// Provides ZIP archive navigation. -/** -* This class is modelled after QDir, and is designed to provide similar -* features for ZIP archives. -* -* The only significant difference from QDir is that the root path is not -* '/', but an empty string since that's how the file paths are stored in -* the archive. However, QuaZipDir understands the paths starting with -* '/'. It is important in a few places: -* -* - In the cd() function. -* - In the constructor. -* - In the exists() function. -* -* Note that since ZIP uses '/' on all platforms, the '\' separator is -* not supported. -*/ -class QUAZIP_EXPORT QuaZipDir { -private: - QSharedDataPointer d; -public: - /// The copy constructor. - QuaZipDir(const QuaZipDir &that); - /// Constructs a QuaZipDir instance pointing to the specified directory. - /** - If \a dir is not specified, points to the root of the archive. - The same happens if the \a dir is "/". - */ - QuaZipDir(QuaZip *zip, const QString &dir = QString()); - /// Destructor. - ~QuaZipDir(); - /// The assignment operator. - bool operator==(const QuaZipDir &that); - /// operator!= - /** - \return \c true if either this and \a that use different QuaZip - instances or if they point to different directories. - */ - inline bool operator!=(const QuaZipDir &that) {return !operator==(that);} - /// operator== - /** - \return \c true if both this and \a that use the same QuaZip - instance and point to the same directory. - */ - QuaZipDir& operator=(const QuaZipDir &that); - /// Returns the name of the entry at the specified position. - QString operator[](int pos) const; - /// Returns the current case sensitivity mode. - QuaZip::CaseSensitivity caseSensitivity() const; - /// Changes the 'current' directory. - /** - * If the path starts with '/', it is interpreted as an absolute - * path from the root of the archive. Otherwise, it is interpreted - * as a path relative to the current directory as was set by the - * previous cd() or the constructor. - * - * Note that the subsequent path() call will not return a path - * starting with '/' in all cases. - */ - bool cd(const QString &dirName); - /// Goes up. - bool cdUp(); - /// Returns the number of entries in the directory. - uint count() const; - /// Returns the current directory name. - /** - The name doesn't include the path. - */ - QString dirName() const; - /// Returns the list of the entries in the directory. - /** - \param nameFilters The list of file patterns to list, uses the same - syntax as QDir. - \param filters The entry type filters, only Files and Dirs are - accepted. - \param sort Sorting mode (not supported yet). - */ - QList entryInfoList(const QStringList &nameFilters, - QDir::Filters filters = QDir::NoFilter, - QDir::SortFlags sort = QDir::NoSort) const; - /// Returns the list of the entries in the directory. - /** - \overload - - The same as entryInfoList(QStringList(), filters, sort). - */ - QList entryInfoList(QDir::Filters filters = QDir::NoFilter, - QDir::SortFlags sort = QDir::NoSort) const; - /// Returns the list of the entry names in the directory. - /** - The same as entryInfoList(nameFilters, filters, sort), but only - returns entry names. - */ - QStringList entryList(const QStringList &nameFilters, - QDir::Filters filters = QDir::NoFilter, - QDir::SortFlags sort = QDir::NoSort) const; - /// Returns the list of the entry names in the directory. - /** - \overload - - The same as entryList(QStringList(), filters, sort). - */ - QStringList entryList(QDir::Filters filters = QDir::NoFilter, - QDir::SortFlags sort = QDir::NoSort) const; - /// Returns \c true if the entry with the specified name exists. - /** - The ".." is considered to exist if the current directory - is not root. The "." and "/" are considered to - always exist. Paths starting with "/" are relative to - the archive root, other paths are relative to the current dir. - */ - bool exists(const QString &fileName) const; - /// Return \c true if the directory pointed by this QuaZipDir exists. - bool exists() const; - /// Returns the full path to the specified file. - /** - Doesn't check if the file actually exists. - */ - QString filePath(const QString &fileName) const; - /// Returns the default filter. - QDir::Filters filter(); - /// Returns if the QuaZipDir points to the root of the archive. - /** - Not that the root path is the empty string, not '/'. - */ - bool isRoot() const; - /// Return the default name filter. - QStringList nameFilters() const; - /// Returns the path to the current dir. - /** - The path never starts with '/', and the root path is an empty - string. - */ - QString path() const; - /// Returns the path to the specified file relative to the current dir. - QString relativeFilePath(const QString &fileName) const; - /// Sets the default case sensitivity mode. - void setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity); - /// Sets the default filter. - void setFilter(QDir::Filters filters); - /// Sets the default name filter. - void setNameFilters(const QStringList &nameFilters); - /// Goes to the specified path. - /** - The difference from cd() is that this function never checks if the - path actually exists and doesn't use relative paths, so it's - possible to go to the root directory with setPath(""). - - Note that this function still chops the trailing and/or leading - '/' and treats a single '/' as the root path (path() will still - return an empty string). - */ - void setPath(const QString &path); - /// Sets the default sorting mode. - void setSorting(QDir::SortFlags sort); - /// Returns the default sorting mode. - QDir::SortFlags sorting() const; -}; - -#endif // QUAZIP_QUAZIPDIR_H diff --git a/quazip/quazipfile.cpp b/quazip/quazipfile.cpp deleted file mode 100644 index 323f815e..00000000 --- a/quazip/quazipfile.cpp +++ /dev/null @@ -1,488 +0,0 @@ -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser 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 Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser 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 - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include "quazipfile.h" - -using namespace std; - -/// The implementation class for QuaZip. -/** -\internal - -This class contains all the private stuff for the QuaZipFile class, thus -allowing to preserve binary compatibility between releases, the -technique known as the Pimpl (private implementation) idiom. -*/ -class QuaZipFilePrivate { - friend class QuaZipFile; - private: - /// The pointer to the associated QuaZipFile instance. - QuaZipFile *q; - /// The QuaZip object to work with. - QuaZip *zip; - /// The file name. - QString fileName; - /// Case sensitivity mode. - QuaZip::CaseSensitivity caseSensitivity; - /// Whether this file is opened in the raw mode. - bool raw; - /// Write position to keep track of. - /** - QIODevice::pos() is broken for non-seekable devices, so we need - our own position. - */ - qint64 writePos; - /// Uncompressed size to write along with a raw file. - ulong uncompressedSize; - /// CRC to write along with a raw file. - quint32 crc; - /// Whether \ref zip points to an internal QuaZip instance. - /** - This is true if the archive was opened by name, rather than by - supplying an existing QuaZip instance. - */ - bool internal; - /// The last error. - int zipError; - /// Resets \ref zipError. - inline void resetZipError() const {setZipError(UNZ_OK);} - /// Sets the zip error. - /** - This function is marked as const although it changes one field. - This allows to call it from const functions that don't change - anything by themselves. - */ - void setZipError(int zipError) const; - /// The constructor for the corresponding QuaZipFile constructor. - inline QuaZipFilePrivate(QuaZipFile *q): - q(q), zip(NULL), internal(true), zipError(UNZ_OK) {} - /// The constructor for the corresponding QuaZipFile constructor. - inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName): - q(q), internal(true), zipError(UNZ_OK) - { - zip=new QuaZip(zipName); - } - /// The constructor for the corresponding QuaZipFile constructor. - inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName, - QuaZip::CaseSensitivity cs): - q(q), internal(true), zipError(UNZ_OK) - { - zip=new QuaZip(zipName); - this->fileName=fileName; - if (this->fileName.startsWith('/')) - this->fileName = this->fileName.mid(1); - this->caseSensitivity=cs; - } - /// The constructor for the QuaZipFile constructor accepting a file name. - inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip): - q(q), zip(zip), internal(false), zipError(UNZ_OK) {} - /// The destructor. - inline ~QuaZipFilePrivate() - { - if (internal) - delete zip; - } -}; - -QuaZipFile::QuaZipFile(): - p(new QuaZipFilePrivate(this)) -{ -} - -QuaZipFile::QuaZipFile(QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this)) -{ -} - -QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this, zipName)) -{ -} - -QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName, - QuaZip::CaseSensitivity cs, QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this, zipName, fileName, cs)) -{ -} - -QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this, zip)) -{ -} - -QuaZipFile::~QuaZipFile() -{ - if (isOpen()) - close(); - delete p; -} - -QString QuaZipFile::getZipName() const -{ - return p->zip==NULL ? QString() : p->zip->getZipName(); -} - -QuaZip *QuaZipFile::getZip() const -{ - return p->internal ? NULL : p->zip; -} - -QString QuaZipFile::getActualFileName()const -{ - p->setZipError(UNZ_OK); - if (p->zip == NULL || (openMode() & WriteOnly)) - return QString(); - QString name=p->zip->getCurrentFileName(); - if(name.isNull()) - p->setZipError(p->zip->getZipError()); - return name; -} - -void QuaZipFile::setZipName(const QString& zipName) -{ - if(isOpen()) { - qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name"); - return; - } - if(p->zip!=NULL && p->internal) - delete p->zip; - p->zip=new QuaZip(zipName); - p->internal=true; -} - -void QuaZipFile::setZip(QuaZip *zip) -{ - if(isOpen()) { - qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP"); - return; - } - if(p->zip!=NULL && p->internal) - delete p->zip; - p->zip=zip; - p->fileName=QString(); - p->internal=false; -} - -void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs) -{ - if(p->zip==NULL) { - qWarning("QuaZipFile::setFileName(): call setZipName() first"); - return; - } - if(!p->internal) { - qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip"); - return; - } - if(isOpen()) { - qWarning("QuaZipFile::setFileName(): can not set file name for already opened file"); - return; - } - p->fileName=fileName; - if (p->fileName.startsWith('/')) - p->fileName = p->fileName.mid(1); - p->caseSensitivity=cs; -} - -void QuaZipFilePrivate::setZipError(int zipError) const -{ - QuaZipFilePrivate *fakeThis = const_cast(this); // non-const - fakeThis->zipError=zipError; - if(zipError==UNZ_OK) - q->setErrorString(QString()); - else - q->setErrorString(q->tr("ZIP/UNZIP API error %1").arg(zipError)); -} - -bool QuaZipFile::open(OpenMode mode) -{ - return open(mode, NULL); -} - -bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password) -{ - p->resetZipError(); - if(isOpen()) { - qWarning("QuaZipFile::open(): already opened"); - return false; - } - if(mode&Unbuffered) { - qWarning("QuaZipFile::open(): Unbuffered mode is not supported"); - return false; - } - if((mode&ReadOnly)&&!(mode&WriteOnly)) { - if(p->internal) { - if(!p->zip->open(QuaZip::mdUnzip)) { - p->setZipError(p->zip->getZipError()); - return false; - } - if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) { - p->setZipError(p->zip->getZipError()); - p->zip->close(); - return false; - } - } else { - if(p->zip==NULL) { - qWarning("QuaZipFile::open(): zip is NULL"); - return false; - } - if(p->zip->getMode()!=QuaZip::mdUnzip) { - qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", - (int)mode, (int)p->zip->getMode()); - return false; - } - if(!p->zip->hasCurrentFile()) { - qWarning("QuaZipFile::open(): zip does not have current file"); - return false; - } - } - p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password)); - if(p->zipError==UNZ_OK) { - setOpenMode(mode); - p->raw=raw; - return true; - } else - return false; - } - qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); - return false; -} - -bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info, - const char *password, quint32 crc, - int method, int level, bool raw, - int windowBits, int memLevel, int strategy) -{ - zip_fileinfo info_z; - p->resetZipError(); - if(isOpen()) { - qWarning("QuaZipFile::open(): already opened"); - return false; - } - if((mode&WriteOnly)&&!(mode&ReadOnly)) { - if(p->internal) { - qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach"); - return false; - } - if(p->zip==NULL) { - qWarning("QuaZipFile::open(): zip is NULL"); - return false; - } - if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) { - qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", - (int)mode, (int)p->zip->getMode()); - return false; - } - info_z.tmz_date.tm_year=info.dateTime.date().year(); - info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1; - info_z.tmz_date.tm_mday=info.dateTime.date().day(); - info_z.tmz_date.tm_hour=info.dateTime.time().hour(); - info_z.tmz_date.tm_min=info.dateTime.time().minute(); - info_z.tmz_date.tm_sec=info.dateTime.time().second(); - info_z.dosDate = 0; - info_z.internal_fa=(uLong)info.internalAttr; - info_z.external_fa=(uLong)info.externalAttr; - if (!p->zip->isDataDescriptorWritingEnabled()) - zipClearFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR); - p->setZipError(zipOpenNewFileInZip3(p->zip->getZipFile(), - p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z, - info.extraLocal.constData(), info.extraLocal.length(), - info.extraGlobal.constData(), info.extraGlobal.length(), - p->zip->getCommentCodec()->fromUnicode(info.comment).constData(), - method, level, (int)raw, - windowBits, memLevel, strategy, - password, (uLong)crc)); - if(p->zipError==UNZ_OK) { - p->writePos=0; - setOpenMode(mode); - p->raw=raw; - if(raw) { - p->crc=crc; - p->uncompressedSize=info.uncompressedSize; - } - return true; - } else - return false; - } - qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); - return false; -} - -bool QuaZipFile::isSequential()const -{ - return true; -} - -qint64 QuaZipFile::pos()const -{ - if(p->zip==NULL) { - qWarning("QuaZipFile::pos(): call setZipName() or setZip() first"); - return -1; - } - if(!isOpen()) { - qWarning("QuaZipFile::pos(): file is not open"); - return -1; - } - if(openMode()&ReadOnly) - // QIODevice::pos() is broken for sequential devices, - // but thankfully bytesAvailable() returns the number of - // bytes buffered, so we know how far ahead we are. - return unztell(p->zip->getUnzFile()) - QIODevice::bytesAvailable(); - else - return p->writePos; -} - -bool QuaZipFile::atEnd()const -{ - if(p->zip==NULL) { - qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first"); - return false; - } - if(!isOpen()) { - qWarning("QuaZipFile::atEnd(): file is not open"); - return false; - } - if(openMode()&ReadOnly) - // the same problem as with pos() - return QIODevice::bytesAvailable() == 0 - && unzeof(p->zip->getUnzFile())==1; - else - return true; -} - -qint64 QuaZipFile::size()const -{ - if(!isOpen()) { - qWarning("QuaZipFile::atEnd(): file is not open"); - return -1; - } - if(openMode()&ReadOnly) - return p->raw?csize():usize(); - else - return p->writePos; -} - -qint64 QuaZipFile::csize()const -{ - unz_file_info info_z; - p->setZipError(UNZ_OK); - if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1; - p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); - if(p->zipError!=UNZ_OK) - return -1; - return info_z.compressed_size; -} - -qint64 QuaZipFile::usize()const -{ - unz_file_info info_z; - p->setZipError(UNZ_OK); - if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1; - p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); - if(p->zipError!=UNZ_OK) - return -1; - return info_z.uncompressed_size; -} - -bool QuaZipFile::getFileInfo(QuaZipFileInfo *info) -{ - if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false; - p->zip->getCurrentFileInfo(info); - p->setZipError(p->zip->getZipError()); - return p->zipError==UNZ_OK; -} - -void QuaZipFile::close() -{ - p->resetZipError(); - if(p->zip==NULL||!p->zip->isOpen()) return; - if(!isOpen()) { - qWarning("QuaZipFile::close(): file isn't open"); - return; - } - if(openMode()&ReadOnly) - p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile())); - else if(openMode()&WriteOnly) - if(isRaw()) p->setZipError(zipCloseFileInZipRaw(p->zip->getZipFile(), p->uncompressedSize, p->crc)); - else p->setZipError(zipCloseFileInZip(p->zip->getZipFile())); - else { - qWarning("Wrong open mode: %d", (int)openMode()); - return; - } - if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen); - else return; - if(p->internal) { - p->zip->close(); - p->setZipError(p->zip->getZipError()); - } -} - -qint64 QuaZipFile::readData(char *data, qint64 maxSize) -{ - p->setZipError(UNZ_OK); - qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize); - if (bytesRead < 0) { - p->setZipError((int) bytesRead); - return -1; - } - return bytesRead; -} - -qint64 QuaZipFile::writeData(const char* data, qint64 maxSize) -{ - p->setZipError(ZIP_OK); - p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize)); - if(p->zipError!=ZIP_OK) return -1; - else { - p->writePos+=maxSize; - return maxSize; - } -} - -QString QuaZipFile::getFileName() const -{ - return p->fileName; -} - -QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const -{ - return p->caseSensitivity; -} - -bool QuaZipFile::isRaw() const -{ - return p->raw; -} - -int QuaZipFile::getZipError() const -{ - return p->zipError; -} - -qint64 QuaZipFile::bytesAvailable() const -{ - return size() - pos(); -} diff --git a/quazip/quazipfile.h b/quazip/quazipfile.h deleted file mode 100644 index f6cc41a6..00000000 --- a/quazip/quazipfile.h +++ /dev/null @@ -1,442 +0,0 @@ -#ifndef QUA_ZIPFILE_H -#define QUA_ZIPFILE_H - -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser 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 Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser 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 - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include - -#include "quazip_global.h" -#include "quazip.h" -#include "quazipnewinfo.h" - -class QuaZipFilePrivate; - -/// A file inside ZIP archive. -/** \class QuaZipFile quazipfile.h - * This is the most interesting class. Not only it provides C++ - * interface to the ZIP/UNZIP package, but also integrates it with Qt by - * subclassing QIODevice. This makes possible to access files inside ZIP - * archive using QTextStream or QDataStream, for example. Actually, this - * is the main purpose of the whole QuaZIP library. - * - * You can either use existing QuaZip instance to create instance of - * this class or pass ZIP archive file name to this class, in which case - * it will create internal QuaZip object. See constructors' descriptions - * for details. Writing is only possible with the existing instance. - * - * Note that due to the underlying library's limitation it is not - * possible to use multiple QuaZipFile instances to open several files - * in the same archive at the same time. If you need to write to - * multiple files in parallel, then you should write to temporary files - * first, then pack them all at once when you have finished writing. If - * you need to read multiple files inside the same archive in parallel, - * you should extract them all into a temporary directory first. - * - * \section quazipfile-sequential Sequential or random-access? - * - * At the first thought, QuaZipFile has fixed size, the start and the - * end and should be therefore considered random-access device. But - * there is one major obstacle to making it random-access: ZIP/UNZIP API - * does not support seek() operation and the only way to implement it is - * through reopening the file and re-reading to the required position, - * but this is prohibitively slow. - * - * Therefore, QuaZipFile is considered to be a sequential device. This - * has advantage of availability of the ungetChar() operation (QIODevice - * does not implement it properly for non-sequential devices unless they - * support seek()). Disadvantage is a somewhat strange behaviour of the - * size() and pos() functions. This should be kept in mind while using - * this class. - * - **/ -class QUAZIP_EXPORT QuaZipFile: public QIODevice { - friend class QuaZipFilePrivate; - Q_OBJECT - private: - QuaZipFilePrivate *p; - // these are not supported nor implemented - QuaZipFile(const QuaZipFile& that); - QuaZipFile& operator=(const QuaZipFile& that); - protected: - /// Implementation of the QIODevice::readData(). - qint64 readData(char *data, qint64 maxSize); - /// Implementation of the QIODevice::writeData(). - qint64 writeData(const char *data, qint64 maxSize); - public: - /// Constructs a QuaZipFile instance. - /** You should use setZipName() and setFileName() or setZip() before - * trying to call open() on the constructed object. - **/ - QuaZipFile(); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object. - * - * You should use setZipName() and setFileName() or setZip() before - * trying to call open() on the constructed object. - **/ - QuaZipFile(QObject *parent); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object and \a - * zipName specifies ZIP archive file name. - * - * You should use setFileName() before trying to call open() on the - * constructed object. - * - * QuaZipFile constructed by this constructor can be used for read - * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. - **/ - QuaZipFile(const QString& zipName, QObject *parent =NULL); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object, \a - * zipName specifies ZIP archive file name and \a fileName and \a cs - * specify a name of the file to open inside archive. - * - * QuaZipFile constructed by this constructor can be used for read - * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. - * - * \sa QuaZip::setCurrentFile() - **/ - QuaZipFile(const QString& zipName, const QString& fileName, - QuaZip::CaseSensitivity cs =QuaZip::csDefault, QObject *parent =NULL); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object. - * - * \a zip is the pointer to the existing QuaZip object. This - * QuaZipFile object then can be used to read current file in the - * \a zip or to write to the file inside it. - * - * \warning Using this constructor for reading current file can be - * tricky. Let's take the following example: - * \code - * QuaZip zip("archive.zip"); - * zip.open(QuaZip::mdUnzip); - * zip.setCurrentFile("file-in-archive"); - * QuaZipFile file(&zip); - * file.open(QIODevice::ReadOnly); - * // ok, now we can read from the file - * file.read(somewhere, some); - * zip.setCurrentFile("another-file-in-archive"); // oops... - * QuaZipFile anotherFile(&zip); - * anotherFile.open(QIODevice::ReadOnly); - * anotherFile.read(somewhere, some); // this is still ok... - * file.read(somewhere, some); // and this is NOT - * \endcode - * So, what exactly happens here? When we change current file in the - * \c zip archive, \c file that references it becomes invalid - * (actually, as far as I understand ZIP/UNZIP sources, it becomes - * closed, but QuaZipFile has no means to detect it). - * - * Summary: do not close \c zip object or change its current file as - * long as QuaZipFile is open. Even better - use another constructors - * which create internal QuaZip instances, one per object, and - * therefore do not cause unnecessary trouble. This constructor may - * be useful, though, if you already have a QuaZip instance and do - * not want to access several files at once. Good example: - * \code - * QuaZip zip("archive.zip"); - * zip.open(QuaZip::mdUnzip); - * // first, we need some information about archive itself - * QByteArray comment=zip.getComment(); - * // and now we are going to access files inside it - * QuaZipFile file(&zip); - * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { - * file.open(QIODevice::ReadOnly); - * // do something cool with file here - * file.close(); // do not forget to close! - * } - * zip.close(); - * \endcode - **/ - QuaZipFile(QuaZip *zip, QObject *parent =NULL); - /// Destroys a QuaZipFile instance. - /** Closes file if open, destructs internal QuaZip object (if it - * exists and \em is internal, of course). - **/ - virtual ~QuaZipFile(); - /// Returns the ZIP archive file name. - /** If this object was created by passing QuaZip pointer to the - * constructor, this function will return that QuaZip's file name - * (or null string if that object does not have file name yet). - * - * Otherwise, returns associated ZIP archive file name or null - * string if there are no name set yet. - * - * \sa setZipName() getFileName() - **/ - QString getZipName()const; - /// Returns a pointer to the associated QuaZip object. - /** Returns \c NULL if there is no associated QuaZip or it is - * internal (so you will not mess with it). - **/ - QuaZip* getZip()const; - /// Returns file name. - /** This function returns file name you passed to this object either - * by using - * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) - * or by calling setFileName(). Real name of the file may differ in - * case if you used case-insensitivity. - * - * Returns null string if there is no file name set yet. This is the - * case when this QuaZipFile operates on the existing QuaZip object - * (constructor QuaZipFile(QuaZip*,QObject*) or setZip() was used). - * - * \sa getActualFileName - **/ - QString getFileName() const; - /// Returns case sensitivity of the file name. - /** This function returns case sensitivity argument you passed to - * this object either by using - * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) - * or by calling setFileName(). - * - * Returns unpredictable value if getFileName() returns null string - * (this is the case when you did not used setFileName() or - * constructor above). - * - * \sa getFileName - **/ - QuaZip::CaseSensitivity getCaseSensitivity() const; - /// Returns the actual file name in the archive. - /** This is \em not a ZIP archive file name, but a name of file inside - * archive. It is not necessary the same name that you have passed - * to the - * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*), - * setFileName() or QuaZip::setCurrentFile() - this is the real file - * name inside archive, so it may differ in case if the file name - * search was case-insensitive. - * - * Equivalent to calling getCurrentFileName() on the associated - * QuaZip object. Returns null string if there is no associated - * QuaZip object or if it does not have a current file yet. And this - * is the case if you called setFileName() but did not open the - * file yet. So this is perfectly fine: - * \code - * QuaZipFile file("somezip.zip"); - * file.setFileName("somefile"); - * QString name=file.getName(); // name=="somefile" - * QString actual=file.getActualFileName(); // actual is null string - * file.open(QIODevice::ReadOnly); - * QString actual=file.getActualFileName(); // actual can be "SoMeFiLe" on Windows - * \endcode - * - * \sa getZipName(), getFileName(), QuaZip::CaseSensitivity - **/ - QString getActualFileName()const; - /// Sets the ZIP archive file name. - /** Automatically creates internal QuaZip object and destroys - * previously created internal QuaZip object, if any. - * - * Will do nothing if this file is already open. You must close() it - * first. - **/ - void setZipName(const QString& zipName); - /// Returns \c true if the file was opened in raw mode. - /** If the file is not open, the returned value is undefined. - * - * \sa open(OpenMode,int*,int*,bool,const char*) - **/ - bool isRaw() const; - /// Binds to the existing QuaZip instance. - /** This function destroys internal QuaZip object, if any, and makes - * this QuaZipFile to use current file in the \a zip object for any - * further operations. See QuaZipFile(QuaZip*,QObject*) for the - * possible pitfalls. - * - * Will do nothing if the file is currently open. You must close() - * it first. - **/ - void setZip(QuaZip *zip); - /// Sets the file name. - /** Will do nothing if at least one of the following conditions is - * met: - * - ZIP name has not been set yet (getZipName() returns null - * string). - * - This QuaZipFile is associated with external QuaZip. In this - * case you should call that QuaZip's setCurrentFile() function - * instead! - * - File is already open so setting the name is meaningless. - * - * \sa QuaZip::setCurrentFile - **/ - void setFileName(const QString& fileName, QuaZip::CaseSensitivity cs =QuaZip::csDefault); - /// Opens a file for reading. - /** Returns \c true on success, \c false otherwise. - * Call getZipError() to get error code. - * - * \note Since ZIP/UNZIP API provides buffered reading only, - * QuaZipFile does not support unbuffered reading. So do not pass - * QIODevice::Unbuffered flag in \a mode, or open will fail. - **/ - virtual bool open(OpenMode mode); - /// Opens a file for reading. - /** \overload - * Argument \a password specifies a password to decrypt the file. If - * it is NULL then this function behaves just like open(OpenMode). - **/ - inline bool open(OpenMode mode, const char *password) - {return open(mode, NULL, NULL, false, password);} - /// Opens a file for reading. - /** \overload - * Argument \a password specifies a password to decrypt the file. - * - * An integers pointed by \a method and \a level will receive codes - * of the compression method and level used. See unzip.h. - * - * If raw is \c true then no decompression is performed. - * - * \a method should not be \c NULL. \a level can be \c NULL if you - * don't want to know the compression level. - **/ - bool open(OpenMode mode, int *method, int *level, bool raw, const char *password =NULL); - /// Opens a file for writing. - /** \a info argument specifies information about file. It should at - * least specify a correct file name. Also, it is a good idea to - * specify correct timestamp (by default, current time will be - * used). See QuaZipNewInfo. - * - * The \a password argument specifies the password for crypting. Pass NULL - * if you don't need any crypting. The \a crc argument was supposed - * to be used for crypting too, but then it turned out that it's - * false information, so you need to set it to 0 unless you want to - * use the raw mode (see below). - * - * Arguments \a method and \a level specify compression method and - * level. The only method supported is Z_DEFLATED, but you may also - * specify 0 for no compression. If all of the files in the archive - * use both method 0 and either level 0 is explicitly specified or - * data descriptor writing is disabled with - * QuaZip::setDataDescriptorWritingEnabled(), then the - * resulting archive is supposed to be compatible with the 1.0 ZIP - * format version, should you need that. Except for this, \a level - * has no other effects with method 0. - * - * If \a raw is \c true, no compression is performed. In this case, - * \a crc and uncompressedSize field of the \a info are required. - * - * Arguments \a windowBits, \a memLevel, \a strategy provide zlib - * algorithms tuning. See deflateInit2() in zlib. - **/ - bool open(OpenMode mode, const QuaZipNewInfo& info, - const char *password =NULL, quint32 crc =0, - int method =Z_DEFLATED, int level =Z_DEFAULT_COMPRESSION, bool raw =false, - int windowBits =-MAX_WBITS, int memLevel =DEF_MEM_LEVEL, int strategy =Z_DEFAULT_STRATEGY); - /// Returns \c true, but \ref quazipfile-sequential "beware"! - virtual bool isSequential()const; - /// Returns current position in the file. - /** Implementation of the QIODevice::pos(). When reading, this - * function is a wrapper to the ZIP/UNZIP unztell(), therefore it is - * unable to keep track of the ungetChar() calls (which is - * non-virtual and therefore is dangerous to reimplement). So if you - * are using ungetChar() feature of the QIODevice, this function - * reports incorrect value until you get back characters which you - * ungot. - * - * When writing, pos() returns number of bytes already written - * (uncompressed unless you use raw mode). - * - * \note Although - * \ref quazipfile-sequential "QuaZipFile is a sequential device" - * and therefore pos() should always return zero, it does not, - * because it would be misguiding. Keep this in mind. - * - * This function returns -1 if the file or archive is not open. - * - * Error code returned by getZipError() is not affected by this - * function call. - **/ - virtual qint64 pos()const; - /// Returns \c true if the end of file was reached. - /** This function returns \c false in the case of error. This means - * that you called this function on either not open file, or a file - * in the not open archive or even on a QuaZipFile instance that - * does not even have QuaZip instance associated. Do not do that - * because there is no means to determine whether \c false is - * returned because of error or because end of file was reached. - * Well, on the other side you may interpret \c false return value - * as "there is no file open to check for end of file and there is - * no end of file therefore". - * - * When writing, this function always returns \c true (because you - * are always writing to the end of file). - * - * Error code returned by getZipError() is not affected by this - * function call. - **/ - virtual bool atEnd()const; - /// Returns file size. - /** This function returns csize() if the file is open for reading in - * raw mode, usize() if it is open for reading in normal mode and - * pos() if it is open for writing. - * - * Returns -1 on error, call getZipError() to get error code. - * - * \note This function returns file size despite that - * \ref quazipfile-sequential "QuaZipFile is considered to be sequential device", - * for which size() should return bytesAvailable() instead. But its - * name would be very misguiding otherwise, so just keep in mind - * this inconsistence. - **/ - virtual qint64 size()const; - /// Returns compressed file size. - /** Equivalent to calling getFileInfo() and then getting - * compressedSize field, but more convenient and faster. - * - * File must be open for reading before calling this function. - * - * Returns -1 on error, call getZipError() to get error code. - **/ - qint64 csize()const; - /// Returns uncompressed file size. - /** Equivalent to calling getFileInfo() and then getting - * uncompressedSize field, but more convenient and faster. See - * getFileInfo() for a warning. - * - * File must be open for reading before calling this function. - * - * Returns -1 on error, call getZipError() to get error code. - **/ - qint64 usize()const; - /// Gets information about current file. - /** This function does the same thing as calling - * QuaZip::getCurrentFileInfo() on the associated QuaZip object, - * but you can not call getCurrentFileInfo() if the associated - * QuaZip is internal (because you do not have access to it), while - * you still can call this function in that case. - * - * File must be open for reading before calling this function. - * - * Returns \c false in the case of an error. - **/ - bool getFileInfo(QuaZipFileInfo *info); - /// Closes the file. - /** Call getZipError() to determine if the close was successful. - **/ - virtual void close(); - /// Returns the error code returned by the last ZIP/UNZIP API call. - int getZipError() const; - /// Returns the number of bytes available for reading. - virtual qint64 bytesAvailable() const; -}; - -#endif diff --git a/quazip/quazipfileinfo.h b/quazip/quazipfileinfo.h deleted file mode 100644 index 99540229..00000000 --- a/quazip/quazipfileinfo.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef QUA_ZIPFILEINFO_H -#define QUA_ZIPFILEINFO_H - -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser 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 Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser 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 - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include -#include - -#include "quazip_global.h" - -/// Information about a file inside archive. -/** Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to - * fill this structure. */ -struct QUAZIP_EXPORT QuaZipFileInfo { - /// File name. - QString name; - /// Version created by. - quint16 versionCreated; - /// Version needed to extract. - quint16 versionNeeded; - /// General purpose flags. - quint16 flags; - /// Compression method. - quint16 method; - /// Last modification date and time. - QDateTime dateTime; - /// CRC. - quint32 crc; - /// Compressed file size. - quint32 compressedSize; - /// Uncompressed file size. - quint32 uncompressedSize; - /// Disk number start. - quint16 diskNumberStart; - /// Internal file attributes. - quint16 internalAttr; - /// External file attributes. - quint32 externalAttr; - /// Comment. - QString comment; - /// Extra field. - QByteArray extra; -}; - -#endif diff --git a/quazip/quazipnewinfo.cpp b/quazip/quazipnewinfo.cpp deleted file mode 100644 index ed57e09f..00000000 --- a/quazip/quazipnewinfo.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser 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 Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser 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 - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. -*/ - -#include - -#include "quazipnewinfo.h" - - -QuaZipNewInfo::QuaZipNewInfo(const QString& name): - name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0) -{ -} - -QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file): - name(name), internalAttr(0), externalAttr(0) -{ - QFileInfo info(file); - QDateTime lm = info.lastModified(); - if (!info.exists()) - dateTime = QDateTime::currentDateTime(); - else - dateTime = lm; -} - -void QuaZipNewInfo::setFileDateTime(const QString& file) -{ - QFileInfo info(file); - QDateTime lm = info.lastModified(); - if (info.exists()) - dateTime = lm; -} diff --git a/quazip/quazipnewinfo.h b/quazip/quazipnewinfo.h deleted file mode 100644 index 62159ea7..00000000 --- a/quazip/quazipnewinfo.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef QUA_ZIPNEWINFO_H -#define QUA_ZIPNEWINFO_H - -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser 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 Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser 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 - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include -#include - -#include "quazip_global.h" - -/// Information about a file to be created. -/** This structure holds information about a file to be created inside - * ZIP archive. At least name should be set to something correct before - * passing this structure to - * QuaZipFile::open(OpenMode,const QuaZipNewInfo&,int,int,bool). - **/ -struct QUAZIP_EXPORT QuaZipNewInfo { - /// File name. - /** This field holds file name inside archive, including path relative - * to archive root. - **/ - QString name; - /// File timestamp. - /** This is the last file modification date and time. Will be stored - * in the archive central directory. It is a good practice to set it - * to the source file timestamp instead of archive creating time. Use - * setFileDateTime() or QuaZipNewInfo(const QString&, const QString&). - **/ - QDateTime dateTime; - /// File internal attributes. - quint16 internalAttr; - /// File external attributes. - quint32 externalAttr; - /// File comment. - /** Will be encoded using QuaZip::getCommentCodec(). - **/ - QString comment; - /// File local extra field. - QByteArray extraLocal; - /// File global extra field. - QByteArray extraGlobal; - /// Uncompressed file size. - /** This is only needed if you are using raw file zipping mode, i. e. - * adding precompressed file in the zip archive. - **/ - ulong uncompressedSize; - /// Constructs QuaZipNewInfo instance. - /** Initializes name with \a name, dateTime with current date and - * time. Attributes are initialized with zeros, comment and extra - * field with null values. - **/ - QuaZipNewInfo(const QString& name); - /// Constructs QuaZipNewInfo instance. - /** Initializes name with \a name and dateTime with timestamp of the - * file named \a file. If the \a file does not exists or its timestamp - * is inaccessible (e. g. you do not have read permission for the - * directory file in), uses current date and time. Attributes are - * initialized with zeros, comment and extra field with null values. - * - * \sa setFileDateTime() - **/ - QuaZipNewInfo(const QString& name, const QString& file); - /// Sets the file timestamp from the existing file. - /** Use this function to set the file timestamp from the existing - * file. Use it like this: - * \code - * QuaZipFile zipFile(&zip); - * QFile file("file-to-add"); - * file.open(QIODevice::ReadOnly); - * QuaZipNewInfo info("file-name-in-archive"); - * info.setFileDateTime("file-to-add"); // take the timestamp from file - * zipFile.open(QIODevice::WriteOnly, info); - * \endcode - * - * This function does not change dateTime if some error occured (e. g. - * file is inaccessible). - **/ - void setFileDateTime(const QString& file); -}; - -#endif diff --git a/quazip/unzip.c b/quazip/unzip.c deleted file mode 100644 index 6e115ae6..00000000 --- a/quazip/unzip.c +++ /dev/null @@ -1,1603 +0,0 @@ -/* unzip.c -- IO for uncompress .zip files using zlib - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - Read unzip.h for more info - - Modified by Sergey A. Tachenov to integrate with Qt. -*/ - -/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of -compatibility with older software. The following is from the original crypt.c. Code -woven in by Terry Thorsen 1/2003. -*/ -/* - Copyright (c) 1990-2000 Info-ZIP. All rights reserved. - - See the accompanying file LICENSE, version 2000-Apr-09 or later - (the contents of which are also included in zip.h) for terms of use. - If, for some reason, all these files are missing, the Info-ZIP license - also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html -*/ -/* - crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] - - 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). - */ - - -#include -#include -#include -#include "zlib.h" -#include "unzip.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - - -#ifndef CASESENSITIVITYDEFAULT_NO -# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) -# define CASESENSITIVITYDEFAULT_NO -# endif -#endif - - -#ifndef UNZ_BUFSIZE -#define UNZ_BUFSIZE (16384) -#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 - -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) - - - - -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_info_internal_s -{ - uLong offset_curfile;/* relative offset of local header 4 bytes */ -} unz_file_info_internal; - - -/* file_in_zip_read_info_s contain internal information about a file in zipfile, - when reading and decompress it */ -typedef struct -{ - char *read_buffer; /* internal buffer for compressed data */ - z_stream stream; /* zLib stream structure for inflate */ - - uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ - uLong stream_initialised; /* flag set if stream structure is initialised*/ - - uLong offset_local_extrafield;/* offset of the local extra field */ - uInt size_local_extrafield;/* size of the local extra field */ - uLong pos_local_extrafield; /* position in the local extra field in read*/ - - uLong crc32; /* crc32 of all data uncompressed */ - uLong crc32_wait; /* crc32 we must obtain after decompress all */ - uLong rest_read_compressed; /* number of byte to be decompressed */ - uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ - zlib_filefunc_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - uLong compression_method; /* compression method (0==store) */ - uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - int raw; -} file_in_zip_read_info_s; - - -/* unz_s contain internal information about the zipfile -*/ -typedef struct -{ - zlib_filefunc_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - unz_global_info gi; /* public global information */ - uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - uLong num_file; /* number of the current file in the zipfile*/ - uLong pos_in_central_dir; /* pos of the current file in the central dir*/ - uLong current_file_ok; /* flag about the usability of the current file*/ - uLong central_pos; /* position of the beginning of the central dir*/ - - uLong size_central_dir; /* size of the central directory */ - uLong offset_central_dir; /* offset of start of central directory with - respect to the starting disk number */ - - unz_file_info cur_file_info; /* public info about the current file in zip*/ - unz_file_info_internal cur_file_info_internal; /* private info about it*/ - file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current - file if we are decompressing it */ - int encrypted; -# ifndef NOUNCRYPT - unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; -# endif -} unz_s; - - -#ifndef NOUNCRYPT -#include "crypt.h" -#endif - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ - - -local int unzlocal_getByte OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - int *pi)); - -local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - int *pi; -{ - unsigned char c; - int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); - if (err==1) - { - *pi = (int)c; - return UNZ_OK; - } - else - { - if (ZERROR(*pzlib_filefunc_def,filestream)) - return UNZ_ERRNO; - else - return UNZ_EOF; - } -} - - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int unzlocal_getShort OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int unzlocal_getLong OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<16; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<24; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - - -/* My own strcmpi / strcasecmp */ -local int strcmpcasenosensitive_internal (fileName1,fileName2) - const char* fileName1; - const char* fileName2; -{ - for (;;) - { - char c1=*(fileName1++); - char c2=*(fileName2++); - if ((c1>='a') && (c1<='z')) - c1 -= 0x20; - if ((c2>='a') && (c2<='z')) - c2 -= 0x20; - if (c1=='\0') - return ((c2=='\0') ? 0 : -1); - if (c2=='\0') - return 1; - if (c1c2) - return 1; - } -} - - -#ifdef CASESENSITIVITYDEFAULT_NO -#define CASESENSITIVITYDEFAULTVALUE 2 -#else -#define CASESENSITIVITYDEFAULTVALUE 1 -#endif - -#ifndef STRCMPCASENOSENTIVEFUNCTION -#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal -#endif - -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) - -*/ -extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) - const char* fileName1; - const char* fileName2; - int iCaseSensitivity; -{ - if (iCaseSensitivity==0) - iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; - - if (iCaseSensitivity==1) - return strcmp(fileName1,fileName2); - - return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); -} - -#ifndef BUFREADCOMMENT -#define BUFREADCOMMENT (0x400) -#endif - -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -local uLong unzlocal_SearchCentralDir OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream)); - -local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; -{ - unsigned char* buf; - uLong uSizeFile; - uLong uBackRead; - uLong uMaxBack=0xffff; /* maximum size of global comment */ - uLong uPosFound=0; - - if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - - uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); - if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - return uPosFound; -} - -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer - "zlib/zlib114.zip". - If the zipfile cannot be opened (file doesn't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ -extern unzFile ZEXPORT unzOpen2 (file, pzlib_filefunc_def) - voidpf file; - zlib_filefunc_def* pzlib_filefunc_def; -{ - unz_s us; - unz_s *s; - uLong central_pos,uL; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - uLong number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - - int err=UNZ_OK; - - if (unz_copyright[0]!=' ') - return NULL; - - if (pzlib_filefunc_def==NULL) - fill_qiodevice_filefunc(&us.z_filefunc); - else - us.z_filefunc = *pzlib_filefunc_def; - - us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, - file, - ZLIB_FILEFUNC_MODE_READ | - ZLIB_FILEFUNC_MODE_EXISTING); - if (us.filestream==NULL) - return NULL; - - central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); - if (central_pos==0) - err=UNZ_ERRNO; - - if (ZSEEK(us.z_filefunc, us.filestream, - central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=UNZ_ERRNO; - - /* the signature, already checked */ - if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of this disk */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of the disk with the start of the central directory */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir on this disk */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((number_entry_CD!=us.gi.number_entry) || - (number_disk_with_CD!=0) || - (number_disk!=0)) - err=UNZ_BADZIPFILE; - - /* size of the central directory */ - if (unzlocal_getLong(&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 (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* zipfile comment length */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((central_pospfile_in_zip_read!=NULL) - unzCloseCurrentFile(file); - - ZCLOSE(s->z_filefunc, s->filestream); - TRYFREE(s); - return UNZ_OK; -} - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) - unzFile file; - unz_global_info *pglobal_info; -{ - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - *pglobal_info=s->gi; - return UNZ_OK; -} - - -/* - Translate date/time from Dos format to tm_unz (readable more easilty) -*/ -local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) - uLong ulDosDate; - tm_unz* ptm; -{ - uLong uDate; - uDate = (uLong)(ulDosDate>>16); - ptm->tm_mday = (uInt)(uDate&0x1f) ; - ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; - ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; - - ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); - ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; - ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; -} - -/* - Get Info about the current file in the zipfile, with internal only info -*/ -local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, - unz_file_info *pfile_info, - unz_file_info_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); - -local int unzlocal_GetCurrentFileInfoInternal (file, - pfile_info, - pfile_info_internal, - szFileName, fileNameBufferSize, - extraField, extraFieldBufferSize, - szComment, commentBufferSize) - unzFile file; - unz_file_info *pfile_info; - unz_file_info_internal *pfile_info_internal; - char *szFileName; - uLong fileNameBufferSize; - void *extraField; - uLong extraFieldBufferSize; - char *szComment; - uLong commentBufferSize; -{ - unz_s* s; - unz_file_info file_info; - unz_file_info_internal file_info_internal; - int err=UNZ_OK; - uLong uMagic; - uLong uSeek=0; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (ZSEEK(s->z_filefunc, s->filestream, - s->pos_in_central_dir+s->byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET)!=0) - err=UNZ_ERRNO; - - - /* we check the magic */ - if (err==UNZ_OK) { - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x02014b50) - err=UNZ_BADZIPFILE; - } - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) - err=UNZ_ERRNO; - - unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) - err=UNZ_ERRNO; - - uSeek+=file_info.size_filename; - if ((err==UNZ_OK) && (szFileName!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_filename0) && (fileNameBufferSize>0)) - if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - uSeek -= uSizeRead; - } - - - if ((err==UNZ_OK) && (extraField!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_extraz_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) - uSeek=0; - else - err=UNZ_ERRNO; - } - if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) - if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - uSeek += file_info.size_file_extra - uSizeRead; - } - else - uSeek+=file_info.size_file_extra; - - - if ((err==UNZ_OK) && (szComment!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_commentz_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) - uSeek=0; - else - err=UNZ_ERRNO; - } - if ((file_info.size_file_comment>0) && (commentBufferSize>0)) - if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - uSeek+=file_info.size_file_comment - uSizeRead; - } - else - uSeek+=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; -} - - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. -*/ -extern int ZEXPORT unzGetCurrentFileInfo (file, - pfile_info, - szFileName, fileNameBufferSize, - extraField, extraFieldBufferSize, - szComment, commentBufferSize) - unzFile file; - unz_file_info *pfile_info; - char *szFileName; - uLong fileNameBufferSize; - void *extraField; - uLong extraFieldBufferSize; - char *szComment; - uLong commentBufferSize; -{ - return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, - szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, - szComment,commentBufferSize); -} - -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ -extern int ZEXPORT unzGoToFirstFile (file) - unzFile file; -{ - int err=UNZ_OK; - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - s->pos_in_central_dir=s->offset_central_dir; - s->num_file=0; - err=unzlocal_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; -} - -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ -extern int ZEXPORT unzGoToNextFile (file) - unzFile file; -{ - unz_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_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 = unzlocal_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; -} - - -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzipStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ -extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) - unzFile file; - const char *szFileName; - int iCaseSensitivity; -{ - unz_s* s; - int err; - - /* We remember the 'current' position in the file so that we can jump - * back there if we fail. - */ - unz_file_info cur_file_infoSaved; - unz_file_info_internal cur_file_info_internalSaved; - uLong num_fileSaved; - uLong pos_in_central_dirSaved; - - - if (file==NULL) - return UNZ_PARAMERROR; - - if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) - return UNZ_PARAMERROR; - - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - /* Save the current state */ - num_fileSaved = s->num_file; - pos_in_central_dirSaved = s->pos_in_central_dir; - cur_file_infoSaved = s->cur_file_info; - cur_file_info_internalSaved = s->cur_file_info_internal; - - err = unzGoToFirstFile(file); - - while (err == UNZ_OK) - { - char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; - err = unzGetCurrentFileInfo(file,NULL, - szCurrentFileName,sizeof(szCurrentFileName)-1, - NULL,0,NULL,0); - if (err == UNZ_OK) - { - if (unzStringFileNameCompare(szCurrentFileName, - szFileName,iCaseSensitivity)==0) - return UNZ_OK; - err = unzGoToNextFile(file); - } - } - - /* We failed, so restore the state of the 'current file' to where we - * were. - */ - s->num_file = num_fileSaved ; - s->pos_in_central_dir = pos_in_central_dirSaved ; - s->cur_file_info = cur_file_infoSaved; - s->cur_file_info_internal = cur_file_info_internalSaved; - return err; -} - - -/* -/////////////////////////////////////////// -// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) -// I need random access -// -// Further optimization could be realized by adding an ability -// to cache the directory in memory. The goal being a single -// comprehensive file read to put the file I need in a memory. -*/ - -/* -typedef struct unz_file_pos_s -{ - uLong pos_in_zip_directory; // offset in file - uLong num_of_file; // # of file -} unz_file_pos; -*/ - -extern int ZEXPORT unzGetFilePos(file, file_pos) - unzFile file; - unz_file_pos* file_pos; -{ - unz_s* s; - - if (file==NULL || file_pos==NULL) - return UNZ_PARAMERROR; - s=(unz_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 unzGoToFilePos(file, file_pos) - unzFile file; - unz_file_pos* file_pos; -{ - unz_s* s; - int err; - - if (file==NULL || file_pos==NULL) - return UNZ_PARAMERROR; - s=(unz_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 = unzlocal_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; -} - -/* -// Unzip Helper Functions - should be here? -/////////////////////////////////////////// -*/ - -/* - 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 unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, - poffset_local_extrafield, - psize_local_extrafield) - unz_s* s; - uInt* piSizeVar; - uLong *poffset_local_extrafield; - uInt *psize_local_extrafield; -{ - uLong uMagic,uData,uFlags; - uLong size_filename; - uLong size_extra_field; - int err=UNZ_OK; - - *piSizeVar = 0; - *poffset_local_extrafield = 0; - *psize_local_extrafield = 0; - - if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + - s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - - if (err==UNZ_OK) { - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x04034b50) - err=UNZ_BADZIPFILE; - } - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) - err=UNZ_ERRNO; -/* - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) - err=UNZ_BADZIPFILE; -*/ - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) - err=UNZ_BADZIPFILE; - - if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - - if (unzlocal_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 += (uInt)size_filename; - - if (unzlocal_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 = (uInt)size_extra_field; - - *piSizeVar += (uInt)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 (file, method, level, raw, password) - unzFile file; - int* method; - int* level; - int raw; - const char* password; -{ - int err=UNZ_OK; - uInt iSizeVar; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uLong offset_local_extrafield; /* offset of the local extra field */ - uInt size_local_extrafield; /* size of the local extra field */ -# ifndef NOUNCRYPT - char source[12]; -# else - if (password != NULL) - return UNZ_PARAMERROR; -# endif - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_PARAMERROR; - - if (s->pfile_in_zip_read != NULL) - unzCloseCurrentFile(file); - - if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, - &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) - return UNZ_BADZIPFILE; - - pfile_in_zip_read_info = (file_in_zip_read_info_s*) - ALLOC(sizeof(file_in_zip_read_info_s)); - if (pfile_in_zip_read_info==NULL) - return UNZ_INTERNALERROR; - - pfile_in_zip_read_info->read_buffer=(char*)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; - - if (method!=NULL) - *method = (int)s->cur_file_info.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 ((s->cur_file_info.compression_method!=0) && - (s->cur_file_info.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->compression_method = - s->cur_file_info.compression_method; - pfile_in_zip_read_info->filestream=s->filestream; - pfile_in_zip_read_info->z_filefunc=s->z_filefunc; - pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; - - pfile_in_zip_read_info->stream.total_out = 0; - - if ((s->cur_file_info.compression_method==Z_DEFLATED) && - (!raw)) - { - 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=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); - if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised=1; - 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 = (uInt)0; - - s->pfile_in_zip_read = pfile_in_zip_read_info; - -# ifndef NOUNCRYPT - if (password != NULL) - { - int i; - s->pcrc_32_tab = get_crc_table(); - init_keys(password,s->keys,s->pcrc_32_tab); - if (ZSEEK(s->z_filefunc, s->filestream, - s->pfile_in_zip_read->pos_in_zipfile + - s->pfile_in_zip_read->byte_before_the_zipfile, - SEEK_SET)!=0) - return UNZ_INTERNALERROR; - if(ZREAD(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->pos_in_zipfile+=12; - s->encrypted=1; - } -# endif - - - return UNZ_OK; -} - -extern int ZEXPORT unzOpenCurrentFile (file) - unzFile file; -{ - return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); -} - -extern int ZEXPORT unzOpenCurrentFilePassword (file, password) - unzFile file; - const char* password; -{ - return unzOpenCurrentFile3(file, NULL, NULL, 0, password); -} - -extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw) - 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 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 unzReadCurrentFile (file, buf, len) - unzFile file; - voidp buf; - unsigned len; -{ - int err=UNZ_OK; - uInt iRead = 0; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if ((pfile_in_zip_read_info->read_buffer == NULL)) - return UNZ_END_OF_LIST_OF_FILE; - if (len==0) - return 0; - - pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; - - pfile_in_zip_read_info->stream.avail_out = (uInt)len; - - if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && - (!(pfile_in_zip_read_info->raw))) - pfile_in_zip_read_info->stream.avail_out = - (uInt)pfile_in_zip_read_info->rest_read_uncompressed; - - if ((len>pfile_in_zip_read_info->rest_read_compressed+ - pfile_in_zip_read_info->stream.avail_in) && - (pfile_in_zip_read_info->raw)) - pfile_in_zip_read_info->stream.avail_out = - (uInt)pfile_in_zip_read_info->rest_read_compressed+ - pfile_in_zip_read_info->stream.avail_in; - - while (pfile_in_zip_read_info->stream.avail_out>0) - { - if ((pfile_in_zip_read_info->stream.avail_in==0) && - (pfile_in_zip_read_info->rest_read_compressed>0)) - { - uInt uReadThis = UNZ_BUFSIZE; - if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; - if (uReadThis == 0) - return UNZ_EOF; - if (ZSEEK(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->pos_in_zipfile + - pfile_in_zip_read_info->byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - if (ZREAD(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->read_buffer, - uReadThis)!=uReadThis) - return UNZ_ERRNO; - - -# ifndef NOUNCRYPT - if(s->encrypted) - { - uInt i; - for(i=0;iread_buffer[i] = - zdecode(s->keys,s->pcrc_32_tab, - pfile_in_zip_read_info->read_buffer[i]); - } -# endif - - - pfile_in_zip_read_info->pos_in_zipfile += uReadThis; - - pfile_in_zip_read_info->rest_read_compressed-=uReadThis; - - pfile_in_zip_read_info->stream.next_in = - (Bytef*)pfile_in_zip_read_info->read_buffer; - pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; - } - - if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) - { - uInt uDoCopy,i ; - - if ((pfile_in_zip_read_info->stream.avail_in == 0) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - return (iRead==0) ? UNZ_EOF : iRead; - - if (pfile_in_zip_read_info->stream.avail_out < - pfile_in_zip_read_info->stream.avail_in) - uDoCopy = pfile_in_zip_read_info->stream.avail_out ; - else - uDoCopy = pfile_in_zip_read_info->stream.avail_in ; - - for (i=0;istream.next_out+i) = - *(pfile_in_zip_read_info->stream.next_in+i); - - pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, - pfile_in_zip_read_info->stream.next_out, - uDoCopy); - pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; - pfile_in_zip_read_info->stream.avail_in -= uDoCopy; - pfile_in_zip_read_info->stream.avail_out -= uDoCopy; - pfile_in_zip_read_info->stream.next_out += uDoCopy; - pfile_in_zip_read_info->stream.next_in += uDoCopy; - pfile_in_zip_read_info->stream.total_out += uDoCopy; - iRead += uDoCopy; - } - else - { - uLong uTotalOutBefore,uTotalOutAfter; - const Bytef *bufBefore; - uLong uOutThis; - int flush=Z_SYNC_FLUSH; - - uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; - bufBefore = pfile_in_zip_read_info->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(&pfile_in_zip_read_info->stream,flush); - - if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) - err = Z_DATA_ERROR; - - uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; - uOutThis = uTotalOutAfter-uTotalOutBefore; - - pfile_in_zip_read_info->crc32 = - crc32(pfile_in_zip_read_info->crc32,bufBefore, - (uInt)(uOutThis)); - - pfile_in_zip_read_info->rest_read_uncompressed -= - uOutThis; - - iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); - - if (err==Z_STREAM_END) - return (iRead==0) ? UNZ_EOF : iRead; - if (err!=Z_OK) - break; - } - } - - if (err==Z_OK) - return iRead; - return err; -} - - -/* - Give the current position in uncompressed data -*/ -extern z_off_t ZEXPORT unztell (file) - unzFile file; -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - return (z_off_t)pfile_in_zip_read_info->stream.total_out; -} - - -/* - return 1 if the end of file was reached, 0 elsewhere -*/ -extern int ZEXPORT unzeof (file) - unzFile file; -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - return 1; - else - return 0; -} - - - -/* - 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 that can be read - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ -extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) - unzFile file; - voidp buf; - unsigned len; -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uInt read_now; - uLong size_to_read; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - size_to_read = (pfile_in_zip_read_info->size_local_extrafield - - pfile_in_zip_read_info->pos_local_extrafield); - - if (buf==NULL) - return (int)size_to_read; - - if (len>size_to_read) - read_now = (uInt)size_to_read; - else - read_now = (uInt)len ; - - if (read_now==0) - return 0; - - if (ZSEEK(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->offset_local_extrafield + - pfile_in_zip_read_info->pos_local_extrafield, - ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - if (ZREAD(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - buf,read_now)!=read_now) - return UNZ_ERRNO; - - return (int)read_now; -} - -/* - Close the file in zip opened with unzipOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ -extern int ZEXPORT unzCloseCurrentFile (file) - unzFile file; -{ - int err=UNZ_OK; - - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - 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) - inflateEnd(&pfile_in_zip_read_info->stream); - - pfile_in_zip_read_info->stream_initialised = 0; - TRYFREE(pfile_in_zip_read_info); - - s->pfile_in_zip_read=NULL; - - return err; -} - - -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ -extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) - unzFile file; - char *szComment; - uLong uSizeBuf; -{ - unz_s* s; - uLong uReadThis ; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - uReadThis = uSizeBuf; - if (uReadThis>s->gi.size_comment) - uReadThis = s->gi.size_comment; - - if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - if (uReadThis>0) - { - *szComment='\0'; - if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) - return UNZ_ERRNO; - } - - if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) - *(szComment+s->gi.size_comment)='\0'; - return (int)uReadThis; -} - -/* Additions by RX '2004 */ -extern uLong ZEXPORT unzGetOffset (file) - unzFile file; -{ - unz_s* s; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_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 (file, pos) - unzFile file; - uLong pos; -{ - unz_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - s->pos_in_central_dir = pos; - s->num_file = s->gi.number_entry; /* hack */ - err = unzlocal_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; -} diff --git a/quazip/unzip.h b/quazip/unzip.h deleted file mode 100644 index 33c9dc1a..00000000 --- a/quazip/unzip.h +++ /dev/null @@ -1,356 +0,0 @@ -/* unzip.h -- IO for uncompress .zip files using zlib - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g - WinZip, InfoZip tools and compatible. - - Multi volume ZipFile (span) are not supported. - Encryption compatible with pkzip 2.04g only supported - Old compressions used by old PKZip 1.x are not supported - - - I WAIT FEEDBACK at mail info@winimage.com - Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Modified by Sergey A. Tachenov to integrate with Qt. - - -*/ - -/* for more info about .ZIP format, see - http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip - http://www.info-zip.org/pub/infozip/doc/ - PkWare has also a specification at : - ftp://ftp.pkware.com/probdesc.zip -*/ - -#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 - -#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 -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt 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_info_s -{ - uLong number_entry; /* total number of entries in - the central dir on this disk */ - 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_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; -} unz_file_info; - -extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, - const char* fileName2, - int iCaseSensitivity)); -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) -*/ - - -extern unzFile ZEXPORT unzOpen OF((voidpf file)); -/* - Open a Zip file. path contain whatever zopen_file from the IO API - accepts. For Qt implementation it is a pointer to QIODevice, for - fopen() implementation it's a file name. - If the zipfile cannot be opened (file don't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ - -extern unzFile ZEXPORT unzOpen2 OF((voidpf file, - zlib_filefunc_def* pzlib_filefunc_def)); -/* - Open a Zip file, like unzOpen, but provide a set of file low level API - for read/write the zip file (see ioapi.h) -*/ - -extern int ZEXPORT unzClose OF((unzFile file)); -/* - Close a ZipFile opened with unzipOpen. - If there is files inside the .Zip opened with unzOpenCurrentFile (see later), - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. - return UNZ_OK if there is no problem. */ - -extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, - unz_global_info *pglobal_info)); -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ - - -extern int ZEXPORT unzGetGlobalComment OF((unzFile file, - char *szComment, - uLong uSizeBuf)); -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ - - -/***************************************************************************/ -/* Unzip package allow you browse the directory of the zipfile */ - -extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ - -extern int ZEXPORT unzGoToNextFile OF((unzFile file)); -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ - -extern int ZEXPORT unzLocateFile OF((unzFile file, - const char *szFileName, - int iCaseSensitivity)); -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ - - -/* ****************************************** */ -/* Ryan supplied functions */ -/* unz_file_info contain information about a file in the zipfile */ -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( - unzFile file, - unz_file_pos* file_pos); - -extern int ZEXPORT unzGoToFilePos( - unzFile file, - unz_file_pos* file_pos); - -/* ****************************************** */ - -extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, - unz_file_info *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); -/* - Get Info about the current file - if pfile_info!=NULL, the *pfile_info structure will contain somes info about - the current file - if szFileName!=NULL, the filemane string will be copied in szFileName - (fileNameBufferSize is the size of the buffer) - if extraField!=NULL, the extra field information will be copied in extraField - (extraFieldBufferSize is the size of the buffer). - This is the Central-header version of the extra field - if szComment!=NULL, the comment string of the file will be copied in szComment - (commentBufferSize is the size of the buffer) -*/ - -/***************************************************************************/ -/* for 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. - If there is no error, the return value is UNZ_OK. -*/ - -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 - If there is no error, the return value is UNZ_OK. -*/ - -extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, - int* method, - int* level, - int raw)); -/* - Same than 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 than 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 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 -*/ - -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 z_off_t ZEXPORT unztell OF((unzFile file)); -/* - Give the current position in uncompressed data -*/ - -extern int ZEXPORT unzeof OF((unzFile file)); -/* - return 1 if the end of file was reached, 0 elsewhere -*/ - -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. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ - -/***************************************************************************/ - -/* Get the current file offset */ -extern uLong ZEXPORT unzGetOffset (unzFile file); - -/* Set the current file offset */ -extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); - - - -#ifdef __cplusplus -} -#endif - -#endif /* _unz_H */ diff --git a/quazip/zip.c b/quazip/zip.c deleted file mode 100644 index bf8c0a10..00000000 --- a/quazip/zip.c +++ /dev/null @@ -1,1281 +0,0 @@ -/* zip.c -- IO on .zip files using zlib - Version 1.01e, February 12th, 2005 - - 27 Dec 2004 Rolf Kalbermatter - Modification to zipOpen2 to support globalComment retrieval. - - Copyright (C) 1998-2005 Gilles Vollant - - Read zip.h for more info - - Modified by Sergey A. Tachenov to integrate with Qt. -*/ - - -#include -#include -#include -#include -#include "zlib.h" -#include "zip.h" -#include "quazip_global.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -#ifndef VERSIONMADEBY -# define VERSIONMADEBY (0x031e) /* best for standard pkware crypt */ -#endif - -#ifndef Z_BUFSIZE -#define Z_BUFSIZE (16384) -#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 - -/* -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) -*/ - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -#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"; - - -#define SIZEDATA_INDATABLOCK (4096-(4*4)) - -#define LOCALHEADERMAGIC (0x04034b50) -#define DESCRIPTORHEADERMAGIC (0x08074b50) -#define CENTRALHEADERMAGIC (0x02014b50) -#define ENDHEADERMAGIC (0x06054b50) - -#define FLAG_LOCALHEADER_OFFSET (0x06) -#define CRC_LOCALHEADER_OFFSET (0x0e) - -#define SIZECENTRALHEADER (0x2e) /* 46 */ - -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 alignement */ - 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 */ - int stream_initialised; /* 1 is stream is initialised */ - uInt pos_in_buffered_data; /* last written byte in buffered_data */ - - uLong pos_local_header; /* offset of the local header of the file - currenty writing */ - char* central_header; /* central header data for the current file */ - uLong size_centralheader; /* size of the central header for cur file */ - uLong flag; /* flag of the file currently writing */ - - int method; /* compression method of file currenty wr.*/ - 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 encrypt; -#ifndef NOCRYPT - unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; - int crypt_header_size; -#endif -} curfile_info; - -typedef struct -{ - zlib_filefunc_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - 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.*/ - curfile_info ci; /* info on the file curretly writing */ - - uLong begin_pos; /* position of the beginning of the zipfile */ - uLong add_position_when_writting_offset; - uLong number_entry; -#ifndef NO_ADDFILEINEXISTINGZIP - char *globalcomment; -#endif - unsigned flags; -} zip_internal; - - - -#ifndef NOCRYPT -#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED -#include "crypt.h" -#endif - -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; -} - -local void free_datablock(ldi) - linkedlist_datablock_internal* ldi; -{ - while (ldi!=NULL) - { - linkedlist_datablock_internal* ldinext = ldi->next_datablock; - TRYFREE(ldi); - ldi = ldinext; - } -} - -local void init_linkedlist(ll) - linkedlist_data* ll; -{ - ll->first_block = ll->last_block = NULL; -} - -#if 0 // unused -local void free_linkedlist(ll) - linkedlist_data* ll; -{ - free_datablock(ll->first_block); - ll->first_block = ll->last_block = NULL; -} -#endif - -local int add_data_in_datablock(ll,buf,len) - 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) - { - uInt copy_this; - uInt 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 = (uInt)ldi->avail_in_this_block; - else - copy_this = (uInt)len; - - to_copy = &(ldi->data[ldi->filled_in_this_block]); - - for (i=0;ifilled_in_this_block += copy_this; - ldi->avail_in_this_block -= copy_this; - from_copy += copy_this ; - len -= copy_this; - } - return ZIP_OK; -} - - - -/****************************************************************************/ - -#ifndef NO_ADDFILEINEXISTINGZIP -/* =========================================================================== - Inputs a long in LSB order to the given file - nbByte == 1, 2 or 4 (byte, short or long) -*/ - -local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, uLong x, int nbByte)); -local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong x; - int nbByte; -{ - unsigned char buf[4]; - 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 (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) - return ZIP_ERRNO; - else - return ZIP_OK; -} - -local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); -local void ziplocal_putValue_inmemory (dest, x, nbByte) - void* dest; - uLong 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 uLong ziplocal_TmzDateToDosDate(ptm,dosDate) - const tm_zip* ptm; - uLong dosDate UNUSED; -{ - uLong year = (uLong)ptm->tm_year; - if (year>1980) - year-=1980; - else if (year>80) - year-=80; - 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)); -} - - -/****************************************************************************/ - -local int ziplocal_getByte OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - int *pi)); - -local int ziplocal_getByte(pzlib_filefunc_def,filestream,pi) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - int *pi; -{ - unsigned char c; - int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); - if (err==1) - { - *pi = (int)c; - return ZIP_OK; - } - else - { - if (ZERROR(*pzlib_filefunc_def,filestream)) - return ZIP_ERRNO; - else - return ZIP_EOF; - } -} - - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int ziplocal_getShort OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int ziplocal_getLong OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<16; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<24; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -#ifndef BUFREADCOMMENT -#define BUFREADCOMMENT (0x400) -#endif -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -local uLong ziplocal_SearchCentralDir OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream)); - -local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; -{ - unsigned char* buf; - uLong uSizeFile; - uLong uBackRead; - uLong uMaxBack=0xffff; /* maximum size of global comment */ - uLong uPosFound=0; - - if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - - uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); - if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - return uPosFound; -} -#endif /* !NO_ADDFILEINEXISTINGZIP*/ - -/************************************************************/ -extern zipFile ZEXPORT zipOpen2 (file, append, globalcomment, pzlib_filefunc_def) - voidpf file; - int append; - zipcharpc* globalcomment; - zlib_filefunc_def* pzlib_filefunc_def; -{ - zip_internal ziinit; - zip_internal* zi; - int err=ZIP_OK; - - - if (pzlib_filefunc_def==NULL) - fill_qiodevice_filefunc(&ziinit.z_filefunc); - else - ziinit.z_filefunc = *pzlib_filefunc_def; - - ziinit.filestream = (*(ziinit.z_filefunc.zopen_file)) - (ziinit.z_filefunc.opaque, - file, - (append == APPEND_STATUS_CREATE) ? - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); - - if (ziinit.filestream == NULL) - return NULL; - ziinit.begin_pos = ZTELL(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; - ziinit.flags = ZIP_WRITE_DATA_DESCRIPTOR; - init_linkedlist(&(ziinit.central_dir)); - - - zi = (zip_internal*)ALLOC(sizeof(zip_internal)); - if (zi==NULL) - { - ZCLOSE(ziinit.z_filefunc,ziinit.filestream); - return NULL; - } - - /* now we add file in a zipfile */ -# ifndef NO_ADDFILEINEXISTINGZIP - ziinit.globalcomment = NULL; - if (append == APPEND_STATUS_ADDINZIP) - { - uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - - uLong size_central_dir; /* size of the central directory */ - uLong offset_central_dir; /* offset of start of central directory */ - uLong central_pos,uL; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - uLong number_entry; - uLong number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - uLong size_comment; - - central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); - if (central_pos==0) - err=ZIP_ERRNO; - - if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, - central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=ZIP_ERRNO; - - /* the signature, already checked */ - if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of this disk */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of the disk with the start of the central directory */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central dir on this disk */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central dir */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - if ((number_entry_CD!=number_entry) || - (number_disk_with_CD!=0) || - (number_disk!=0)) - err=ZIP_BADZIPFILE; - - /* size of the central directory */ - if (ziplocal_getLong(&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 (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK) - err=ZIP_ERRNO; - - /* zipfile global comment length */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK) - err=ZIP_ERRNO; - - if ((central_pos0) - { - ziinit.globalcomment = ALLOC(size_comment+1); - if (ziinit.globalcomment) - { - size_comment = ZREAD(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; - - { - uLong size_central_dir_to_read = size_central_dir; - size_t buf_size = SIZEDATA_INDATABLOCK; - void* buf_read = (void*)ALLOC(buf_size); - if (ZSEEK(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)) - { - uLong read_this = SIZEDATA_INDATABLOCK; - if (read_this > size_central_dir_to_read) - read_this = size_central_dir_to_read; - if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,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 (ZSEEK(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 /* !NO_ADDFILEINEXISTINGZIP*/ - - if (err != ZIP_OK) - { -# ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(ziinit.globalcomment); -# endif /* !NO_ADDFILEINEXISTINGZIP*/ - TRYFREE(zi); - return NULL; - } - else - { - *zi = ziinit; - return (zipFile)zi; - } -} - -extern zipFile ZEXPORT zipOpen (file, append) - voidpf file; - int append; -{ - return zipOpen2(file,append,NULL,NULL); -} - -extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting) - zipFile file; - const char* filename; - const zip_fileinfo* zipfi; - const void* extrafield_local; - uInt size_extrafield_local; - const void* extrafield_global; - uInt size_extrafield_global; - const char* comment; - int method; - int level; - int raw; - int windowBits; - int memLevel; - int strategy; - const char* password; - uLong crcForCrypting; -{ - zip_internal* zi; - uInt size_filename; - uInt size_comment; - uInt i; - int err = ZIP_OK; - uLong version_to_extract; - -# ifdef NOCRYPT - if (password != NULL) - return ZIP_PARAMERROR; -# endif - - if (file == NULL) - return ZIP_PARAMERROR; - if ((method!=0) && (method!=Z_DEFLATED)) - return ZIP_PARAMERROR; - - zi = (zip_internal*)file; - - if (zi->in_opened_file_inzip == 1) - { - err = zipCloseFileInZip (file); - if (err != ZIP_OK) - return err; - } - - if (method == 0 - && (level == 0 || (zi->flags & ZIP_WRITE_DATA_DESCRIPTOR) == 0)) - { - version_to_extract = 10; - } - else - { - version_to_extract = 20; - } - - - if (filename==NULL) - filename="-"; - - if (comment==NULL) - size_comment = 0; - else - size_comment = (uInt)strlen(comment); - - size_filename = (uInt)strlen(filename); - - if (zipfi == NULL) - zi->ci.dosDate = 0; - else - { - if (zipfi->dosDate != 0) - zi->ci.dosDate = zipfi->dosDate; - else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); - } - - zi->ci.flag = 0; - 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; - } - if (version_to_extract >= 20 - && (zi->flags & ZIP_WRITE_DATA_DESCRIPTOR) != 0) - zi->ci.flag |= 8; - zi->ci.crc32 = 0; - zi->ci.method = method; - zi->ci.encrypt = 0; - zi->ci.stream_initialised = 0; - zi->ci.pos_in_buffered_data = 0; - zi->ci.raw = raw; - zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ; - zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + - size_extrafield_global + size_comment; - zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); - - ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); - /* version info */ - ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2); - ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)version_to_extract,2); - ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); - ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); - ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); - ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ - ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ - ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ - ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); - ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); - ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); - ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ - - if (zipfi==NULL) - ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); - else - ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); - - if (zipfi==NULL) - ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); - else - ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); - - ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4); - - for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); - - for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = - *(((const char*)extrafield_global)+i); - - for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ - size_extrafield_global+i) = *(comment+i); - if (zi->ci.central_header == NULL) - return ZIP_INTERNALERROR; - - /* write the local header */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)version_to_extract,2); - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2); - - if ((err==ZIP_OK) && (size_filename>0)) - if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) - err = ZIP_ERRNO; - - if ((err==ZIP_OK) && (size_extrafield_local>0)) - if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local) - !=size_extrafield_local) - err = ZIP_ERRNO; - - zi->ci.stream.avail_in = (uInt)0; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - zi->ci.stream.total_in = 0; - zi->ci.stream.total_out = 0; - - if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - zi->ci.stream.zalloc = (alloc_func)0; - zi->ci.stream.zfree = (free_func)0; - zi->ci.stream.opaque = (voidpf)0; - - if (windowBits>0) - windowBits = -windowBits; - - err = deflateInit2(&zi->ci.stream, level, - Z_DEFLATED, windowBits, memLevel, strategy); - - if (err==Z_OK) - zi->ci.stream_initialised = 1; - } -# ifndef NOCRYPT - zi->ci.crypt_header_size = 0; - if ((err==Z_OK) && (password != NULL)) - { - unsigned char bufHead[RAND_HEAD_LEN]; - unsigned int sizeHead; - zi->ci.encrypt = 1; - zi->ci.pcrc_32_tab = get_crc_table(); - /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ - - crcForCrypting = (uLong)zi->ci.dosDate << 16; // ATTANTION! Without this row, you don't unpack your password protected archive in other app. - - sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); - zi->ci.crypt_header_size = sizeHead; - - if (ZWRITE(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 zipOpenNewFileInZip2(file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw) - zipFile file; - const char* filename; - const zip_fileinfo* zipfi; - const void* extrafield_local; - uInt size_extrafield_local; - const void* extrafield_global; - uInt size_extrafield_global; - const char* comment; - int method; - int level; - int raw; -{ - return zipOpenNewFileInZip3 (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); -} - -extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level) - zipFile file; - const char* filename; - const zip_fileinfo* zipfi; - const void* extrafield_local; - uInt size_extrafield_local; - const void* extrafield_global; - uInt size_extrafield_global; - const char* comment; - int method; - int level; -{ - return zipOpenNewFileInZip2 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, 0); -} - -local int zipFlushWriteBuffer(zi) - zip_internal* zi; -{ - int err=ZIP_OK; - - if (zi->ci.encrypt != 0) - { -#ifndef NOCRYPT - uInt i; - int t; - for (i=0;ici.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 - } - if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) - !=zi->ci.pos_in_buffered_data) - err = ZIP_ERRNO; - zi->ci.pos_in_buffered_data = 0; - return err; -} - -extern int ZEXPORT zipWriteInFileInZip (file, buf, len) - zipFile file; - const void* buf; - unsigned len; -{ - zip_internal* zi; - int err=ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - - zi->ci.stream.next_in = (void*)buf; - zi->ci.stream.avail_in = len; - zi->ci.crc32 = crc32(zi->ci.crc32,buf,len); - - while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) - { - if (zi->ci.stream.avail_out == 0) - { - if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - - - if(err != ZIP_OK) - break; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - uLong uTotalOutBefore = zi->ci.stream.total_out; - err=deflate(&zi->ci.stream, Z_NO_FLUSH); - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; - - } - else - { - uInt 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;ici.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 (file, uncompressed_size, crc32) - zipFile file; - uLong uncompressed_size; - uLong crc32; -{ - zip_internal* zi; - uLong compressed_size; - int err=ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - zi->ci.stream.avail_in = 0; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - while (err==ZIP_OK) - { - uLong uTotalOutBefore; - if (zi->ci.stream.avail_out == 0) - { - if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - uTotalOutBefore = zi->ci.stream.total_out; - err=deflate(&zi->ci.stream, Z_FINISH); - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; - } - - if (err==Z_STREAM_END) - err=ZIP_OK; /* this is normal */ - - if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) - if (zipFlushWriteBuffer(zi)==ZIP_ERRNO) - err = ZIP_ERRNO; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - err=deflateEnd(&zi->ci.stream); - zi->ci.stream_initialised = 0; - } - - if (!zi->ci.raw) - { - crc32 = (uLong)zi->ci.crc32; - uncompressed_size = (uLong)zi->ci.stream.total_in; - } - compressed_size = (uLong)zi->ci.stream.total_out; -# ifndef NOCRYPT - compressed_size += zi->ci.crypt_header_size; -# endif - - ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ - ziplocal_putValue_inmemory(zi->ci.central_header+20, - compressed_size,4); /*compr size*/ - if (zi->ci.stream.data_type == Z_ASCII) - ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); - ziplocal_putValue_inmemory(zi->ci.central_header+24, - uncompressed_size,4); /*uncompr size*/ - - 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) - { - uLong cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); - if (ZSEEK(zi->z_filefunc,zi->filestream, - zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ - - if (err==ZIP_OK) /* compressed size, unknown */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); - - if (err==ZIP_OK) /* uncompressed size, unknown */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); - - if (ZSEEK(zi->z_filefunc,zi->filestream, - cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - - if ((zi->ci.flag & 8) != 0) { - /* Write local Descriptor after file data */ - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)DESCRIPTORHEADERMAGIC,4); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ - - if (err==ZIP_OK) /* compressed size, unknown */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); - - if (err==ZIP_OK) /* uncompressed size, unknown */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); - } - - - } - - zi->number_entry ++; - zi->in_opened_file_inzip = 0; - - return err; -} - -extern int ZEXPORT zipCloseFileInZip (file) - zipFile file; -{ - return zipCloseFileInZipRaw (file,0,0); -} - -extern int ZEXPORT zipClose (file, global_comment) - zipFile file; - const char* global_comment; -{ - zip_internal* zi; - int err = 0; - uLong size_centraldir = 0; - uLong centraldir_pos_inzip; - uInt size_global_comment; - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip_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 (global_comment==NULL) - size_global_comment = 0; - else - size_global_comment = (uInt)strlen(global_comment); - - centraldir_pos_inzip = ZTELL(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)) - if (ZWRITE(zi->z_filefunc,zi->filestream, - ldi->data,ldi->filled_in_this_block) - !=ldi->filled_in_this_block ) - err = ZIP_ERRNO; - - size_centraldir += ldi->filled_in_this_block; - ldi = ldi->next_datablock; - } - } - free_datablock(zi->central_dir.first_block); - - if (err==ZIP_OK) /* Magic End */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); - - if (err==ZIP_OK) /* number of this disk */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); - - if (err==ZIP_OK) /* number of the disk with the start of the central directory */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); - - if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); - - if (err==ZIP_OK) /* total number of entries in the central dir */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); - - if (err==ZIP_OK) /* size of the central directory */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); - - if (err==ZIP_OK) /* offset of start of central directory with respect to the - starting disk number */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream, - (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); - - if (err==ZIP_OK) /* zipfile comment length */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); - - if ((err==ZIP_OK) && (size_global_comment>0)) - if (ZWRITE(zi->z_filefunc,zi->filestream, - global_comment,size_global_comment) != size_global_comment) - err = ZIP_ERRNO; - - if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0) - if (err == ZIP_OK) - err = ZIP_ERRNO; - -#ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(zi->globalcomment); -#endif - TRYFREE(zi); - - return err; -} - -extern int ZEXPORT zipSetFlags(zipFile file, unsigned flags) -{ - zip_internal* zi; - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip_internal*)file; - zi->flags |= flags; - return ZIP_OK; -} - -extern int ZEXPORT zipClearFlags(zipFile file, unsigned flags) -{ - zip_internal* zi; - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip_internal*)file; - zi->flags &= ~flags; - return ZIP_OK; -} diff --git a/quazip/zip.h b/quazip/zip.h deleted file mode 100644 index 269ec2da..00000000 --- a/quazip/zip.h +++ /dev/null @@ -1,245 +0,0 @@ -/* zip.h -- IO for compress .zip files using zlib - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - This unzip package allow creates .ZIP file, compatible with PKZip 2.04g - WinZip, InfoZip tools and compatible. - Multi volume ZipFile (span) are not supported. - Encryption compatible with pkzip 2.04g only supported - Old compressions used by old PKZip 1.x are not supported - - For uncompress .zip file, look at unzip.h - - - I WAIT FEEDBACK at mail info@winimage.com - Visit also http://www.winimage.com/zLibDll/unzip.html for evolution - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Modified by Sergey A. Tachenov to integrate with Qt. - - -*/ - -/* for more info about .ZIP format, see - http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip - http://www.info-zip.org/pub/infozip/doc/ - PkWare has also a specification at : - ftp://ftp.pkware.com/probdesc.zip -*/ - -#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 - -#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) - -#define ZIP_WRITE_DATA_DESCRIPTOR 0x8u - -#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 -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt 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 flag; */ /* general purpose bit flag 2 bytes */ - - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ -} zip_fileinfo; - -typedef const char* zipcharpc; - - -#define APPEND_STATUS_CREATE (0) -#define APPEND_STATUS_CREATEAFTER (1) -#define APPEND_STATUS_ADDINZIP (2) - -extern zipFile ZEXPORT zipOpen OF((voidpf file, int append)); -/* - Create a zipfile. - file is whatever the IO API accepts. For Qt IO API it's a pointer to - QIODevice. For fopen() IO API it's a file name (const char*). - 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) - If the zipfile cannot be opened, the return value is NULL. - Else, the return value is a zipFile Handle, usable with other function - of this zip package. -*/ - -/* 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 couse, you can use RAW reading and writing to copy the file you did not want delte -*/ - -extern zipFile ZEXPORT zipOpen2 OF((voidpf file, - int append, - zipcharpc* globalcomment, - zlib_filefunc_def* pzlib_filefunc_def)); - -extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt 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 - if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local - contains the extrafield data the the local header - if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global - contains the extrafield data the the local header - if comment != NULL, comment contain the 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) -*/ - - -extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw)); - -/* - Same than zipOpenNewFileInZip, except if raw=1, we write raw file - */ - -extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCtypting)); - -/* - Same than zipOpenNewFileInZip2, except - windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 - password : crypting password (NULL for no crypting) - crcForCtypting : crc of file to compress (needed for crypting) - */ - - -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)); -/* - Close the current file in the zipfile, for fiel 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 -*/ - -/* - Added by Sergey A. Tachenov to tweak zipping behaviour. - */ -extern int ZEXPORT zipSetFlags(zipFile file, unsigned flags); -extern int ZEXPORT zipClearFlags(zipFile file, unsigned flags); - -#ifdef __cplusplus -} -#endif - -#endif /* _zip_H */ -- cgit v1.2.3