From be95a2a7b1b308673df78d87b6d6e14661dbfd84 Mon Sep 17 00:00:00 2001 From: Wanne Date: Thu, 26 May 2011 11:25:04 +0000 Subject: [PATCH] - Added missing projects "VFS" & "export" to SVN git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@4447 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- ext/VFS/BFVFSConfig.cmake.in | 30 + ext/VFS/CMakeLists.txt | 129 + ext/VFS/COPYING | 502 ++++ ext/VFS/README | 70 + ext/VFS/UseBFVFS.cmake.in | 8 + ext/VFS/build/7z_VS2005.vcproj | 673 +++++ ext/VFS/build/7z_VS2008.vcproj | 674 +++++ ext/VFS/build/7z_VS2010.vcxproj | 278 ++ ext/VFS/build/7z_VS2010.vcxproj.filters | 77 + ext/VFS/build/VFS_VS2005.vcproj | 656 +++++ ext/VFS/build/VFS_VS2008.vcproj | 657 +++++ ext/VFS/build/VFS_VS2010.vcxproj | 284 +++ ext/VFS/build/VFS_VS2010.vcxproj.filters | 241 ++ ext/VFS/ext/7z/CMakeLists.txt | 115 + ext/VFS/ext/7z/doc/7zC.txt | 194 ++ ext/VFS/ext/7z/doc/7zFormat.txt | 471 ++++ ext/VFS/ext/7z/doc/Methods.txt | 146 ++ ext/VFS/ext/7z/doc/history.txt | 266 ++ ext/VFS/ext/7z/doc/lzma.txt | 599 +++++ ext/VFS/ext/7z/src/7z.h | 203 ++ ext/VFS/ext/7z/src/7zAlloc.c | 77 + ext/VFS/ext/7z/src/7zAlloc.h | 24 + ext/VFS/ext/7z/src/7zBuf.c | 36 + ext/VFS/ext/7z/src/7zBuf.h | 39 + ext/VFS/ext/7z/src/7zBuf2.c | 45 + ext/VFS/ext/7z/src/7zCrc.c | 74 + ext/VFS/ext/7z/src/7zCrc.h | 25 + ext/VFS/ext/7z/src/7zCrcOpt.c | 34 + ext/VFS/ext/7z/src/7zDec.c | 444 ++++ ext/VFS/ext/7z/src/7zFile.c | 284 +++ ext/VFS/ext/7z/src/7zFile.h | 83 + ext/VFS/ext/7z/src/7zIn.c | 1398 ++++++++++ ext/VFS/ext/7z/src/7zStream.c | 169 ++ ext/VFS/ext/7z/src/7zVersion.h | 7 + ext/VFS/ext/7z/src/Alloc.c | 127 + ext/VFS/ext/7z/src/Alloc.h | 38 + ext/VFS/ext/7z/src/Bcj2.c | 132 + ext/VFS/ext/7z/src/Bcj2.h | 38 + ext/VFS/ext/7z/src/Bra.c | 133 + ext/VFS/ext/7z/src/Bra.h | 68 + ext/VFS/ext/7z/src/Bra86.c | 85 + ext/VFS/ext/7z/src/BraIA64.c | 67 + ext/VFS/ext/7z/src/CpuArch.c | 182 ++ ext/VFS/ext/7z/src/CpuArch.h | 138 + ext/VFS/ext/7z/src/Delta.c | 62 + ext/VFS/ext/7z/src/Delta.h | 23 + ext/VFS/ext/7z/src/LzFind.c | 761 ++++++ ext/VFS/ext/7z/src/LzFind.h | 115 + ext/VFS/ext/7z/src/LzFindMt.c | 793 ++++++ ext/VFS/ext/7z/src/LzFindMt.h | 105 + ext/VFS/ext/7z/src/LzHash.h | 54 + ext/VFS/ext/7z/src/Lzma2Dec.c | 356 +++ ext/VFS/ext/7z/src/Lzma2Dec.h | 84 + ext/VFS/ext/7z/src/Lzma2Enc.c | 479 ++++ ext/VFS/ext/7z/src/Lzma2Enc.h | 66 + ext/VFS/ext/7z/src/Lzma86.h | 111 + ext/VFS/ext/7z/src/Lzma86Dec.c | 56 + ext/VFS/ext/7z/src/Lzma86Enc.c | 108 + ext/VFS/ext/7z/src/LzmaDec.c | 999 ++++++++ ext/VFS/ext/7z/src/LzmaDec.h | 231 ++ ext/VFS/ext/7z/src/LzmaEnc.c | 2268 +++++++++++++++++ ext/VFS/ext/7z/src/LzmaEnc.h | 80 + ext/VFS/ext/7z/src/LzmaLib.c | 46 + ext/VFS/ext/7z/src/LzmaLib.h | 135 + ext/VFS/ext/7z/src/MtCoder.c | 327 +++ ext/VFS/ext/7z/src/MtCoder.h | 98 + ext/VFS/ext/7z/src/Ppmd.h | 81 + ext/VFS/ext/7z/src/Ppmd7.c | 708 +++++ ext/VFS/ext/7z/src/Ppmd7.h | 140 + ext/VFS/ext/7z/src/Ppmd7Dec.c | 187 ++ ext/VFS/ext/7z/src/Ppmd7Enc.c | 185 ++ ext/VFS/ext/7z/src/Ppmd8.c | 1120 ++++++++ ext/VFS/ext/7z/src/Ppmd8.h | 133 + ext/VFS/ext/7z/src/Ppmd8Dec.c | 155 ++ ext/VFS/ext/7z/src/Ppmd8Enc.c | 161 ++ ext/VFS/ext/7z/src/RotateDefs.h | 20 + ext/VFS/ext/7z/src/Sha256.c | 204 ++ ext/VFS/ext/7z/src/Sha256.h | 30 + ext/VFS/ext/7z/src/Threads.c | 84 + ext/VFS/ext/7z/src/Threads.h | 59 + ext/VFS/ext/7z/src/Types.h | 251 ++ ext/VFS/ext/7z/src/Xz.c | 88 + ext/VFS/ext/7z/src/Xz.h | 256 ++ ext/VFS/ext/7z/src/XzCrc64.c | 33 + ext/VFS/ext/7z/src/XzCrc64.h | 30 + ext/VFS/ext/7z/src/XzDec.c | 873 +++++++ ext/VFS/ext/7z/src/XzEnc.c | 497 ++++ ext/VFS/ext/7z/src/XzEnc.h | 25 + ext/VFS/ext/7z/src/XzIn.c | 306 +++ ext/VFS/ext/utfcpp/doc/ReleaseNotes | 13 + ext/VFS/ext/utfcpp/doc/utf8cpp.html | 1791 +++++++++++++ ext/VFS/ext/utfcpp/source/utf8.h | 34 + ext/VFS/ext/utfcpp/source/utf8/checked.h | 323 +++ ext/VFS/ext/utfcpp/source/utf8/core.h | 358 +++ ext/VFS/ext/utfcpp/source/utf8/unchecked.h | 228 ++ ext/VFS/include/vfs/Aspects/vfs_logging.h | 104 + ext/VFS/include/vfs/Aspects/vfs_settings.h | 40 + .../include/vfs/Aspects/vfs_synchronization.h | 87 + .../include/vfs/Core/File/vfs_buffer_file.h | 73 + ext/VFS/include/vfs/Core/File/vfs_dir_file.h | 76 + ext/VFS/include/vfs/Core/File/vfs_file.h | 113 + ext/VFS/include/vfs/Core/File/vfs_lib_file.h | 78 + .../Core/Interface/vfs_directory_interface.h | 63 + .../vfs/Core/Interface/vfs_file_interface.h | 257 ++ .../Core/Interface/vfs_iterator_interface.h | 88 + .../Core/Interface/vfs_library_interface.h | 59 + .../Core/Interface/vfs_location_interface.h | 160 ++ .../vfs/Core/Location/vfs_directory_tree.h | 85 + .../include/vfs/Core/Location/vfs_lib_dir.h | 66 + .../Core/Location/vfs_uncompressed_lib_base.h | 88 + ext/VFS/include/vfs/Core/vfs.h | 90 + ext/VFS/include/vfs/Core/vfs_debug.h | 90 + ext/VFS/include/vfs/Core/vfs_file_raii.h | 65 + ext/VFS/include/vfs/Core/vfs_init.h | 82 + ext/VFS/include/vfs/Core/vfs_os_functions.h | 107 + ext/VFS/include/vfs/Core/vfs_path.h | 99 + ext/VFS/include/vfs/Core/vfs_profile.h | 92 + ext/VFS/include/vfs/Core/vfs_string.h | 233 ++ ext/VFS/include/vfs/Core/vfs_types.h | 93 + ext/VFS/include/vfs/Core/vfs_vfile.h | 70 + ext/VFS/include/vfs/Core/vfs_vloc.h | 67 + ext/VFS/include/vfs/Ext/7z/vfs_7z_library.h | 52 + .../vfs/Ext/7z/vfs_create_7z_library.h | 89 + ext/VFS/include/vfs/Ext/slf/vfs_slf_library.h | 47 + ext/VFS/include/vfs/Tools/vfs_allocator.h | 94 + ext/VFS/include/vfs/Tools/vfs_file_logger.h | 51 + ext/VFS/include/vfs/Tools/vfs_hp_timer.h | 61 + ext/VFS/include/vfs/Tools/vfs_log.h | 164 ++ ext/VFS/include/vfs/Tools/vfs_parser_tools.h | 80 + ext/VFS/include/vfs/Tools/vfs_profiler.h | 107 + .../vfs/Tools/vfs_property_container.h | 138 + ext/VFS/include/vfs/Tools/vfs_tools.h | 101 + ext/VFS/include/vfs/vfs_config.h | 62 + ext/VFS/src/Aspects/files.cmake | 19 + ext/VFS/src/Aspects/vfs_logging.cpp | 159 ++ ext/VFS/src/Aspects/vfs_settings.cpp | 37 + ext/VFS/src/Aspects/vfs_synchronization.cpp | 72 + ext/VFS/src/CMakeLists.txt | 77 + ext/VFS/src/Core/File/vfs_buffer_file.cpp | 264 ++ ext/VFS/src/Core/File/vfs_dir_file.cpp | 156 ++ ext/VFS/src/Core/File/vfs_file.cpp | 619 +++++ ext/VFS/src/Core/File/vfs_lib_file.cpp | 163 ++ .../Core/Interface/vfs_interface_members.cpp | 116 + .../src/Core/Location/vfs_directory_tree.cpp | 628 +++++ ext/VFS/src/Core/Location/vfs_lib_dir.cpp | 199 ++ .../Location/vfs_uncompressed_lib_base.cpp | 320 +++ ext/VFS/src/Core/files.cmake | 80 + ext/VFS/src/Core/vfs.cpp | 617 +++++ ext/VFS/src/Core/vfs_debug.cpp | 249 ++ ext/VFS/src/Core/vfs_file_raii.cpp | 144 ++ ext/VFS/src/Core/vfs_init.cpp | 351 +++ ext/VFS/src/Core/vfs_os_functions.cpp | 402 +++ ext/VFS/src/Core/vfs_path.cpp | 599 +++++ ext/VFS/src/Core/vfs_profile.cpp | 432 ++++ ext/VFS/src/Core/vfs_string.cpp | 596 +++++ ext/VFS/src/Core/vfs_types.cpp | 34 + ext/VFS/src/Core/vfs_vfile.cpp | 220 ++ ext/VFS/src/Core/vfs_vloc.cpp | 172 ++ ext/VFS/src/Ext/7z/vfs_7z_library.cpp | 269 ++ ext/VFS/src/Ext/7z/vfs_create_7z_library.cpp | 428 ++++ ext/VFS/src/Ext/files.cmake | 30 + ext/VFS/src/Ext/slf/vfs_slf_library.cpp | 179 ++ ext/VFS/src/Tools/files.cmake | 29 + ext/VFS/src/Tools/vfs_allocator.cpp | 41 + ext/VFS/src/Tools/vfs_file_logger.cpp | 59 + ext/VFS/src/Tools/vfs_hp_timer.cpp | 93 + ext/VFS/src/Tools/vfs_log.cpp | 412 +++ ext/VFS/src/Tools/vfs_parser_tools.cpp | 249 ++ ext/VFS/src/Tools/vfs_profiler.cpp | 173 ++ ext/VFS/src/Tools/vfs_property_container.cpp | 798 ++++++ ext/VFS/src/Tools/vfs_tools.cpp | 87 + ext/export/ja2export_VS2005.vcproj | 311 +++ ext/export/ja2export_VS2008.vcproj | 311 +++ ext/export/ja2export_VS2010.vcxproj | 131 + ext/export/ja2export_VS2010.vcxproj.filters | 96 + ext/export/src/export/jsd/export_jsd.cpp | 96 + ext/export/src/export/jsd/export_jsd.h | 25 + ext/export/src/export/jsd/structure.cpp | 293 +++ ext/export/src/export/jsd/structure.h | 11 + ext/export/src/export/slf/export_slf.cpp | 182 ++ ext/export/src/export/slf/export_slf.h | 26 + ext/export/src/export/sti/Image.cpp | 1176 +++++++++ ext/export/src/export/sti/Image.h | 68 + ext/export/src/export/sti/STCI_lib.cpp | 426 ++++ ext/export/src/export/sti/STCI_lib.h | 11 + ext/export/src/export/sti/export_sti.cpp | 207 ++ ext/export/src/export/sti/export_sti.h | 30 + .../src/export/sti/stci_image_utils.cpp | 554 ++++ ext/export/src/export/sti/stci_image_utils.h | 51 + ext/export/src/exporter_base.h | 19 + ext/export/src/init_vfs.cpp | 211 ++ ext/export/src/init_vfs.h | 33 + ext/export/src/ja2/Structure Internals.h | 243 ++ ext/export/src/ja2/Types.h | 103 + ext/export/src/ja2/XMLWriter.cpp | 175 ++ ext/export/src/ja2/XMLWriter.h | 75 + ext/export/src/ja2/himage.cpp | 217 ++ ext/export/src/ja2/himage.h | 206 ++ ext/export/src/ja2/imgfmt.h | 92 + ext/export/src/ja2/sgp_auto_memory.h | 83 + ext/export/src/main.cpp | 115 + ext/export/src/progress_bar.cpp | 32 + ext/export/src/progress_bar.h | 23 + 203 files changed, 44525 insertions(+) create mode 100644 ext/VFS/BFVFSConfig.cmake.in create mode 100644 ext/VFS/CMakeLists.txt create mode 100644 ext/VFS/COPYING create mode 100644 ext/VFS/README create mode 100644 ext/VFS/UseBFVFS.cmake.in create mode 100644 ext/VFS/build/7z_VS2005.vcproj create mode 100644 ext/VFS/build/7z_VS2008.vcproj create mode 100644 ext/VFS/build/7z_VS2010.vcxproj create mode 100644 ext/VFS/build/7z_VS2010.vcxproj.filters create mode 100644 ext/VFS/build/VFS_VS2005.vcproj create mode 100644 ext/VFS/build/VFS_VS2008.vcproj create mode 100644 ext/VFS/build/VFS_VS2010.vcxproj create mode 100644 ext/VFS/build/VFS_VS2010.vcxproj.filters create mode 100644 ext/VFS/ext/7z/CMakeLists.txt create mode 100644 ext/VFS/ext/7z/doc/7zC.txt create mode 100644 ext/VFS/ext/7z/doc/7zFormat.txt create mode 100644 ext/VFS/ext/7z/doc/Methods.txt create mode 100644 ext/VFS/ext/7z/doc/history.txt create mode 100644 ext/VFS/ext/7z/doc/lzma.txt create mode 100644 ext/VFS/ext/7z/src/7z.h create mode 100644 ext/VFS/ext/7z/src/7zAlloc.c create mode 100644 ext/VFS/ext/7z/src/7zAlloc.h create mode 100644 ext/VFS/ext/7z/src/7zBuf.c create mode 100644 ext/VFS/ext/7z/src/7zBuf.h create mode 100644 ext/VFS/ext/7z/src/7zBuf2.c create mode 100644 ext/VFS/ext/7z/src/7zCrc.c create mode 100644 ext/VFS/ext/7z/src/7zCrc.h create mode 100644 ext/VFS/ext/7z/src/7zCrcOpt.c create mode 100644 ext/VFS/ext/7z/src/7zDec.c create mode 100644 ext/VFS/ext/7z/src/7zFile.c create mode 100644 ext/VFS/ext/7z/src/7zFile.h create mode 100644 ext/VFS/ext/7z/src/7zIn.c create mode 100644 ext/VFS/ext/7z/src/7zStream.c create mode 100644 ext/VFS/ext/7z/src/7zVersion.h create mode 100644 ext/VFS/ext/7z/src/Alloc.c create mode 100644 ext/VFS/ext/7z/src/Alloc.h create mode 100644 ext/VFS/ext/7z/src/Bcj2.c create mode 100644 ext/VFS/ext/7z/src/Bcj2.h create mode 100644 ext/VFS/ext/7z/src/Bra.c create mode 100644 ext/VFS/ext/7z/src/Bra.h create mode 100644 ext/VFS/ext/7z/src/Bra86.c create mode 100644 ext/VFS/ext/7z/src/BraIA64.c create mode 100644 ext/VFS/ext/7z/src/CpuArch.c create mode 100644 ext/VFS/ext/7z/src/CpuArch.h create mode 100644 ext/VFS/ext/7z/src/Delta.c create mode 100644 ext/VFS/ext/7z/src/Delta.h create mode 100644 ext/VFS/ext/7z/src/LzFind.c create mode 100644 ext/VFS/ext/7z/src/LzFind.h create mode 100644 ext/VFS/ext/7z/src/LzFindMt.c create mode 100644 ext/VFS/ext/7z/src/LzFindMt.h create mode 100644 ext/VFS/ext/7z/src/LzHash.h create mode 100644 ext/VFS/ext/7z/src/Lzma2Dec.c create mode 100644 ext/VFS/ext/7z/src/Lzma2Dec.h create mode 100644 ext/VFS/ext/7z/src/Lzma2Enc.c create mode 100644 ext/VFS/ext/7z/src/Lzma2Enc.h create mode 100644 ext/VFS/ext/7z/src/Lzma86.h create mode 100644 ext/VFS/ext/7z/src/Lzma86Dec.c create mode 100644 ext/VFS/ext/7z/src/Lzma86Enc.c create mode 100644 ext/VFS/ext/7z/src/LzmaDec.c create mode 100644 ext/VFS/ext/7z/src/LzmaDec.h create mode 100644 ext/VFS/ext/7z/src/LzmaEnc.c create mode 100644 ext/VFS/ext/7z/src/LzmaEnc.h create mode 100644 ext/VFS/ext/7z/src/LzmaLib.c create mode 100644 ext/VFS/ext/7z/src/LzmaLib.h create mode 100644 ext/VFS/ext/7z/src/MtCoder.c create mode 100644 ext/VFS/ext/7z/src/MtCoder.h create mode 100644 ext/VFS/ext/7z/src/Ppmd.h create mode 100644 ext/VFS/ext/7z/src/Ppmd7.c create mode 100644 ext/VFS/ext/7z/src/Ppmd7.h create mode 100644 ext/VFS/ext/7z/src/Ppmd7Dec.c create mode 100644 ext/VFS/ext/7z/src/Ppmd7Enc.c create mode 100644 ext/VFS/ext/7z/src/Ppmd8.c create mode 100644 ext/VFS/ext/7z/src/Ppmd8.h create mode 100644 ext/VFS/ext/7z/src/Ppmd8Dec.c create mode 100644 ext/VFS/ext/7z/src/Ppmd8Enc.c create mode 100644 ext/VFS/ext/7z/src/RotateDefs.h create mode 100644 ext/VFS/ext/7z/src/Sha256.c create mode 100644 ext/VFS/ext/7z/src/Sha256.h create mode 100644 ext/VFS/ext/7z/src/Threads.c create mode 100644 ext/VFS/ext/7z/src/Threads.h create mode 100644 ext/VFS/ext/7z/src/Types.h create mode 100644 ext/VFS/ext/7z/src/Xz.c create mode 100644 ext/VFS/ext/7z/src/Xz.h create mode 100644 ext/VFS/ext/7z/src/XzCrc64.c create mode 100644 ext/VFS/ext/7z/src/XzCrc64.h create mode 100644 ext/VFS/ext/7z/src/XzDec.c create mode 100644 ext/VFS/ext/7z/src/XzEnc.c create mode 100644 ext/VFS/ext/7z/src/XzEnc.h create mode 100644 ext/VFS/ext/7z/src/XzIn.c create mode 100644 ext/VFS/ext/utfcpp/doc/ReleaseNotes create mode 100644 ext/VFS/ext/utfcpp/doc/utf8cpp.html create mode 100644 ext/VFS/ext/utfcpp/source/utf8.h create mode 100644 ext/VFS/ext/utfcpp/source/utf8/checked.h create mode 100644 ext/VFS/ext/utfcpp/source/utf8/core.h create mode 100644 ext/VFS/ext/utfcpp/source/utf8/unchecked.h create mode 100644 ext/VFS/include/vfs/Aspects/vfs_logging.h create mode 100644 ext/VFS/include/vfs/Aspects/vfs_settings.h create mode 100644 ext/VFS/include/vfs/Aspects/vfs_synchronization.h create mode 100644 ext/VFS/include/vfs/Core/File/vfs_buffer_file.h create mode 100644 ext/VFS/include/vfs/Core/File/vfs_dir_file.h create mode 100644 ext/VFS/include/vfs/Core/File/vfs_file.h create mode 100644 ext/VFS/include/vfs/Core/File/vfs_lib_file.h create mode 100644 ext/VFS/include/vfs/Core/Interface/vfs_directory_interface.h create mode 100644 ext/VFS/include/vfs/Core/Interface/vfs_file_interface.h create mode 100644 ext/VFS/include/vfs/Core/Interface/vfs_iterator_interface.h create mode 100644 ext/VFS/include/vfs/Core/Interface/vfs_library_interface.h create mode 100644 ext/VFS/include/vfs/Core/Interface/vfs_location_interface.h create mode 100644 ext/VFS/include/vfs/Core/Location/vfs_directory_tree.h create mode 100644 ext/VFS/include/vfs/Core/Location/vfs_lib_dir.h create mode 100644 ext/VFS/include/vfs/Core/Location/vfs_uncompressed_lib_base.h create mode 100644 ext/VFS/include/vfs/Core/vfs.h create mode 100644 ext/VFS/include/vfs/Core/vfs_debug.h create mode 100644 ext/VFS/include/vfs/Core/vfs_file_raii.h create mode 100644 ext/VFS/include/vfs/Core/vfs_init.h create mode 100644 ext/VFS/include/vfs/Core/vfs_os_functions.h create mode 100644 ext/VFS/include/vfs/Core/vfs_path.h create mode 100644 ext/VFS/include/vfs/Core/vfs_profile.h create mode 100644 ext/VFS/include/vfs/Core/vfs_string.h create mode 100644 ext/VFS/include/vfs/Core/vfs_types.h create mode 100644 ext/VFS/include/vfs/Core/vfs_vfile.h create mode 100644 ext/VFS/include/vfs/Core/vfs_vloc.h create mode 100644 ext/VFS/include/vfs/Ext/7z/vfs_7z_library.h create mode 100644 ext/VFS/include/vfs/Ext/7z/vfs_create_7z_library.h create mode 100644 ext/VFS/include/vfs/Ext/slf/vfs_slf_library.h create mode 100644 ext/VFS/include/vfs/Tools/vfs_allocator.h create mode 100644 ext/VFS/include/vfs/Tools/vfs_file_logger.h create mode 100644 ext/VFS/include/vfs/Tools/vfs_hp_timer.h create mode 100644 ext/VFS/include/vfs/Tools/vfs_log.h create mode 100644 ext/VFS/include/vfs/Tools/vfs_parser_tools.h create mode 100644 ext/VFS/include/vfs/Tools/vfs_profiler.h create mode 100644 ext/VFS/include/vfs/Tools/vfs_property_container.h create mode 100644 ext/VFS/include/vfs/Tools/vfs_tools.h create mode 100644 ext/VFS/include/vfs/vfs_config.h create mode 100644 ext/VFS/src/Aspects/files.cmake create mode 100644 ext/VFS/src/Aspects/vfs_logging.cpp create mode 100644 ext/VFS/src/Aspects/vfs_settings.cpp create mode 100644 ext/VFS/src/Aspects/vfs_synchronization.cpp create mode 100644 ext/VFS/src/CMakeLists.txt create mode 100644 ext/VFS/src/Core/File/vfs_buffer_file.cpp create mode 100644 ext/VFS/src/Core/File/vfs_dir_file.cpp create mode 100644 ext/VFS/src/Core/File/vfs_file.cpp create mode 100644 ext/VFS/src/Core/File/vfs_lib_file.cpp create mode 100644 ext/VFS/src/Core/Interface/vfs_interface_members.cpp create mode 100644 ext/VFS/src/Core/Location/vfs_directory_tree.cpp create mode 100644 ext/VFS/src/Core/Location/vfs_lib_dir.cpp create mode 100644 ext/VFS/src/Core/Location/vfs_uncompressed_lib_base.cpp create mode 100644 ext/VFS/src/Core/files.cmake create mode 100644 ext/VFS/src/Core/vfs.cpp create mode 100644 ext/VFS/src/Core/vfs_debug.cpp create mode 100644 ext/VFS/src/Core/vfs_file_raii.cpp create mode 100644 ext/VFS/src/Core/vfs_init.cpp create mode 100644 ext/VFS/src/Core/vfs_os_functions.cpp create mode 100644 ext/VFS/src/Core/vfs_path.cpp create mode 100644 ext/VFS/src/Core/vfs_profile.cpp create mode 100644 ext/VFS/src/Core/vfs_string.cpp create mode 100644 ext/VFS/src/Core/vfs_types.cpp create mode 100644 ext/VFS/src/Core/vfs_vfile.cpp create mode 100644 ext/VFS/src/Core/vfs_vloc.cpp create mode 100644 ext/VFS/src/Ext/7z/vfs_7z_library.cpp create mode 100644 ext/VFS/src/Ext/7z/vfs_create_7z_library.cpp create mode 100644 ext/VFS/src/Ext/files.cmake create mode 100644 ext/VFS/src/Ext/slf/vfs_slf_library.cpp create mode 100644 ext/VFS/src/Tools/files.cmake create mode 100644 ext/VFS/src/Tools/vfs_allocator.cpp create mode 100644 ext/VFS/src/Tools/vfs_file_logger.cpp create mode 100644 ext/VFS/src/Tools/vfs_hp_timer.cpp create mode 100644 ext/VFS/src/Tools/vfs_log.cpp create mode 100644 ext/VFS/src/Tools/vfs_parser_tools.cpp create mode 100644 ext/VFS/src/Tools/vfs_profiler.cpp create mode 100644 ext/VFS/src/Tools/vfs_property_container.cpp create mode 100644 ext/VFS/src/Tools/vfs_tools.cpp create mode 100644 ext/export/ja2export_VS2005.vcproj create mode 100644 ext/export/ja2export_VS2008.vcproj create mode 100644 ext/export/ja2export_VS2010.vcxproj create mode 100644 ext/export/ja2export_VS2010.vcxproj.filters create mode 100644 ext/export/src/export/jsd/export_jsd.cpp create mode 100644 ext/export/src/export/jsd/export_jsd.h create mode 100644 ext/export/src/export/jsd/structure.cpp create mode 100644 ext/export/src/export/jsd/structure.h create mode 100644 ext/export/src/export/slf/export_slf.cpp create mode 100644 ext/export/src/export/slf/export_slf.h create mode 100644 ext/export/src/export/sti/Image.cpp create mode 100644 ext/export/src/export/sti/Image.h create mode 100644 ext/export/src/export/sti/STCI_lib.cpp create mode 100644 ext/export/src/export/sti/STCI_lib.h create mode 100644 ext/export/src/export/sti/export_sti.cpp create mode 100644 ext/export/src/export/sti/export_sti.h create mode 100644 ext/export/src/export/sti/stci_image_utils.cpp create mode 100644 ext/export/src/export/sti/stci_image_utils.h create mode 100644 ext/export/src/exporter_base.h create mode 100644 ext/export/src/init_vfs.cpp create mode 100644 ext/export/src/init_vfs.h create mode 100644 ext/export/src/ja2/Structure Internals.h create mode 100644 ext/export/src/ja2/Types.h create mode 100644 ext/export/src/ja2/XMLWriter.cpp create mode 100644 ext/export/src/ja2/XMLWriter.h create mode 100644 ext/export/src/ja2/himage.cpp create mode 100644 ext/export/src/ja2/himage.h create mode 100644 ext/export/src/ja2/imgfmt.h create mode 100644 ext/export/src/ja2/sgp_auto_memory.h create mode 100644 ext/export/src/main.cpp create mode 100644 ext/export/src/progress_bar.cpp create mode 100644 ext/export/src/progress_bar.h diff --git a/ext/VFS/BFVFSConfig.cmake.in b/ext/VFS/BFVFSConfig.cmake.in new file mode 100644 index 000000000..123b839f6 --- /dev/null +++ b/ext/VFS/BFVFSConfig.cmake.in @@ -0,0 +1,30 @@ + +## bfVFS version +set(BFVFS_VERSION_MAJOR @BFVFS_VERSION_MAJOR@) +set(BFVFS_VERSION_MINOR @BFVFS_VERSION_MINOR@) +set(BFVFS_VERSION_PATCH @BFVFS_VERSION_PATCH@) + +set(BFVFS_VERSION_STRING "@BFVFS_VERSION_MAJOR@.@BFVFS_VERSION_MINOR@.@BFVFS_VERSION_PATCH@") + +## bfVFS options +set(BFVFS_WITH_7ZIP @BFVFS_WITH_7ZIP@) +set(BFVFS_WITH_SLF @BFVFS_WITH_SLF@) + +## is VFS build as a static or shared library +set(BUILD_BFVFS_SHARED @BUILD_BFVFS_SHARED@) + +## definitions to add via ADD_DEFINITIONS(...) +set(BFVFS_DEFINITIONS "@BFVFS_DEFINITIONS@") + +## include directories +set(BFVFS_INCLUDE_DIRS "@BFVFS_INCLUDE_DIRS@") + +## library directories to include via LINK_DIRECTORIES(...) +set(BFVFS_LIBRARY_DIRS "@BFVFS_LIBRARY_DIRS@") + +## libraries to include via TARGET_LINK_LIBRARIES(...) +set(BFVFS_LIBRARIES "@BFVFS_LIBRARIES@") + +set(BFVFS_RUNTIME_DIRS "@BFVFS_RUNTIME_DIRS@") + +set(BFVFS_FOUND ON) diff --git a/ext/VFS/CMakeLists.txt b/ext/VFS/CMakeLists.txt new file mode 100644 index 000000000..23806e848 --- /dev/null +++ b/ext/VFS/CMakeLists.txt @@ -0,0 +1,129 @@ +cmake_minimum_required(VERSION 2.6) + +project(bfVFS) + +set(BFVFS_VERSION_MAJOR 1) +set(BFVFS_VERSION_MINOR 0) +set(BFVFS_VERSION_PATCH 0) + +## +## determine input/output directories +## +if(BFVFS_INTEGRATED_SOURCE_DIR) + set(BFVFS_SOURCE_DIR ${BFVFS_INTEGRATED_SOURCE_DIR}) +else() + set(BFVFS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +if(BFVFS_INTEGRATED_OUTPUT_DIR) + set(BFVFS_OUTPUT_DIR ${BFVFS_INTEGRATED_OUTPUT_DIR}) +else() + set(BFVFS_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +endif() + + +if(BFVFS_INTEGRATED_LIBRARY_DIR) + set(BFVFS_LIBRARY_DIR ${BFVFS_INTEGRATED_LIBRARY_DIR}) +else() + set(BFVFS_LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/lib) +endif() + +if(BFVFS_INTEGRATED_RUNTIME_DIR) + set(BFVFS_RUNTIME_DIR ${BFVFS_INTEGRATED_RUNTIME_DIR}) +else() + set(BFVFS_RUNTIME_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin) +endif() + +set(BFVFS_INCLUDE_DIR ${BFVFS_SOURCE_DIR}/include) + +## +## set bfVFS "output" variables +## +set(BFVFS_INCLUDE_DIRS ${BFVFS_INCLUDE_DIR}) +set(BFVFS_LIBRARY_DIRS ${BFVFS_LIBRARY_DIR}) +set(BFVFS_RUNTIME_DIRS ${BFVFS_RUNTIME_DIR}) + +## +## Options +## +option(BUILD_BFVFS_SHARED "Build shared libraries" OFF) +option(BFVFS_WITH_SLF "Enable SLF support" ON) +option(BFVFS_WITH_7ZIP "Enable 7-zip support" ON) + +if(BFVFS_WITH_7ZIP) + set(BFVFS_7ZIP_DIR ${BFVFS_SOURCE_DIR}/ext/7z) + + if(BUILD_BFVFS_SHARED) + set(BUILD_BFVFS_7ZIP_SHARED ON) + endif() +endif() + +## +## set include directories for projects +## +include_directories(${BFVFS_INCLUDE_DIRS} + ${BFVFS_SOURCE_DIR}/ext/utfcpp/source +) + +## +## Build 7zip (if selected) +## +if(BFVFS_WITH_7ZIP) + add_subdirectory(${BFVFS_7ZIP_DIR}) +endif() + +## +## Build bfVFS +## +add_subdirectory(src) + +## +## set more "output" variables +## +set(BFVFS_LIBRARIES ${BFVFS_TARGET}) +if(BFVFS_WITH_7ZIP) + set(BFVFS_LIBRARIES ${BFVFS_LIBRARIES} ${BFVFS_7ZIP_TARGET}) +endif() +set(BFVFS_DEFINITIONS ${BFVFS_VFS_DEFINITIONS} ${BFVFS_7ZIP_DEFINITIONS}) + +## +## make bfVFS easier to use in other applications +## +configure_file(${BFVFS_SOURCE_DIR}/BFVFSConfig.cmake.in + ${BFVFS_OUTPUT_DIR}/BFVFSConfig.cmake @ONLY IMMEDIATE) + +configure_file(${BFVFS_SOURCE_DIR}/UseBFVFS.cmake.in + ${BFVFS_OUTPUT_DIR}/UseBFVFS.cmake @ONLY IMMEDIATE) + +## +## debug CMake +## +mark_as_advanced(BFVFS_DEBUG_CMAKE) +option(BFVFS_DEBUG_CMAKE OFF) +if(BFVFS_DEBUG_CMAKE) + message("OPTIONS :") + message(" BUILD_BFVFS_SHARED - " ${BUILD_BFVFS_SHARED}) + message(" BFVFS_WITH_7ZIP - " ${BFVFS_WITH_7ZIP}) + message(" BFVFS_WITH_SLF - " ${BFVFS_WITH_SLF}) + + message("BFVFS_DEFINITIONS :") + foreach(def ${BFVFS_DEFINITIONS}) + message(" " ${def}) + endforeach() + + message("BFVFS_INCLUDE_DIRS :") + foreach(dir ${BFVFS_INCLUDE_DIRS}) + message(" " ${dir}) + endforeach() + + message("BFVFS_LIBRARY_DIRS :") + foreach(dir ${BFVFS_LIBRARY_DIRS}) + message(" " ${dir}) + endforeach() + + message("BFVFS_LIBRARIES :") + foreach(lib ${BFVFS_LIBRARIES}) + message(" " ${lib}) + endforeach() +endif() + diff --git a/ext/VFS/COPYING b/ext/VFS/COPYING new file mode 100644 index 000000000..4362b4915 --- /dev/null +++ b/ext/VFS/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library 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.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ext/VFS/README b/ext/VFS/README new file mode 100644 index 000000000..c685eb6ac --- /dev/null +++ b/ext/VFS/README @@ -0,0 +1,70 @@ +--------------------- +--- Description --- + + The bfVFS library allows an application to link or mount many different + directories from the file system, thus creating a unified application-level + Virtual File System. Additionally, file archives can be used as read-only + locations in the VFS. For now only uncompressed 7-zip ans SLF archives are + supported. + + The library supports multiple platforms and was tested under Windows with + MSVC 2008 and 2010, MinGW and Linux gcc. + +--------------- +--- Build --- + + Instead of system-dependant project or makefiles, bfVFS uses the system- + independant CMake for its configuration (see www.cmake.org). To compile the + source code you can start the CMake GUI (consult the CMake documentation + for that) and choose the source and destination directories. Then, in + multiple configure runs, you can setup the build configuration and finally + generate the system dependant project or makefiles. Both in-source and + out-of-source builds are supported. + + You can select the following options: + + BUILD_BFVFS_SHARED - creates a DLL or a shared library when selected + + BFVFS_WITH_7ZIP - enables support for 7-zip archives, also compiles + the 7z library itself (either as static or shared + library) + + BFVFS_WITH_SLF - enables SLF support + + ** advanced options ** + BFVFS_7ZIP_MT - compiles the 7-zip library with multithreading + support (Windows only) + + BFVFS_DEBUG_CMAKE - prints configuration results + + NOTE: Although in the configuration phase the prefix BFVFS is used, the + code itself uses the shorter VFS_ or vfs_ or vfs:: prefix/namespace. + If you can think of situations where this can lead to a conflict with + other libraries, please inform me about it. + +---------------------------- +--- External libraries --- + + The bfVFS uses two external libraries, "utfcpp" (http://utfcpp.sourceforge.net/) + and "7-zip" (http://www.7-zip.org/). + + utfcpp is used for unicode strings, as C++ does not (yet) support then + natively, and its use is mandatory. + + The 7-zip library is only used for the archive format, compression is not + supported (yet). If you don't want or cannot use the 7-zip library code + you can simple deactivate it in the CMake configuration or remove it from + source tree (see ext/7z). The 7-zip library is the, slightly modified, + C-code portion from the LZMA SDK. The bfVFS library uses the 7-zip library + to read-in 7z archives. Creating uncompressed 7z archives is also suppored, + but self implemented. + + As a second archive format the SLF format is supported (which probably + stands for SirTech Library Format). This is for historical reasons of the + bfVFS library. + +------------------ +--- Feedback --- + + Contact me under john.bf.smith at googlemail.com + or go to http://sourceforge.net/projects/bfvfs/ diff --git a/ext/VFS/UseBFVFS.cmake.in b/ext/VFS/UseBFVFS.cmake.in new file mode 100644 index 000000000..1a639ed6a --- /dev/null +++ b/ext/VFS/UseBFVFS.cmake.in @@ -0,0 +1,8 @@ + +INCLUDE(@BFVFS_OUTPUT_DIR@/BFVFSConfig.cmake) + +ADD_DEFINITIONS(${BFVFS_DEFINITIONS}) + +INCLUDE_DIRECTORIES(${BFVFS_INCLUDE_DIRS}) + +LINK_DIRECTORIES(${BFVFS_LIBRARY_DIRS}) diff --git a/ext/VFS/build/7z_VS2005.vcproj b/ext/VFS/build/7z_VS2005.vcproj new file mode 100644 index 000000000..770de9eaa --- /dev/null +++ b/ext/VFS/build/7z_VS2005.vcproj @@ -0,0 +1,673 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/VFS/build/7z_VS2008.vcproj b/ext/VFS/build/7z_VS2008.vcproj new file mode 100644 index 000000000..c64cb1458 --- /dev/null +++ b/ext/VFS/build/7z_VS2008.vcproj @@ -0,0 +1,674 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/VFS/build/7z_VS2010.vcxproj b/ext/VFS/build/7z_VS2010.vcxproj new file mode 100644 index 000000000..136c06e37 --- /dev/null +++ b/ext/VFS/build/7z_VS2010.vcxproj @@ -0,0 +1,278 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6} + Win32Proj + My7z + 7z + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + ..\..\..\lib\VS2010\$(Configuration)\ + + + ..\..\..\lib\VS2010\$(Configuration)\ + + + ..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;SZIP_STATIC;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;SZIP_STATIC;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;SZIP_STATIC;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;SZIP_STATIC;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;SZIP_STATIC;%(PreprocessorDefinitions) + MultiThreaded + + + + + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/ext/VFS/build/7z_VS2010.vcxproj.filters b/ext/VFS/build/7z_VS2010.vcxproj.filters new file mode 100644 index 000000000..d1193e717 --- /dev/null +++ b/ext/VFS/build/7z_VS2010.vcxproj.filters @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/VFS/build/VFS_VS2005.vcproj b/ext/VFS/build/VFS_VS2005.vcproj new file mode 100644 index 000000000..b3239beba --- /dev/null +++ b/ext/VFS/build/VFS_VS2005.vcproj @@ -0,0 +1,656 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/VFS/build/VFS_VS2008.vcproj b/ext/VFS/build/VFS_VS2008.vcproj new file mode 100644 index 000000000..28adae250 --- /dev/null +++ b/ext/VFS/build/VFS_VS2008.vcproj @@ -0,0 +1,657 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/VFS/build/VFS_VS2010.vcxproj b/ext/VFS/build/VFS_VS2010.vcxproj new file mode 100644 index 000000000..67d877a9a --- /dev/null +++ b/ext/VFS/build/VFS_VS2010.vcxproj @@ -0,0 +1,284 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {463CB476-2798-493F-9CE8-CEAC5ECE5664} + Win32Proj + VFS + VFS + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + ..\..\..\lib\VS2010\$(Configuration)\ + + + ..\..\..\lib\VS2010\$(Configuration)\ + + + ..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;SZIP_STATIC;VFS_STATIC;VFS_WITH_SLF;VFS_WITH_7ZIP;%(PreprocessorDefinitions) + ..\include;..\ext\7z\src;..\ext\utfcpp\source + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;SZIP_STATIC;VFS_STATIC;VFS_WITH_SLF;VFS_WITH_7ZIP;%(PreprocessorDefinitions) + ..\include;..\ext\7z\src;..\ext\utfcpp\source + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;SZIP_STATIC;VFS_STATIC;VFS_WITH_SLF;VFS_WITH_7ZIP;%(PreprocessorDefinitions) + MultiThreaded + ..\include;..\ext\7z\src;..\ext\utfcpp\source + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;SZIP_STATIC;VFS_STATIC;VFS_WITH_SLF;VFS_WITH_7ZIP;%(PreprocessorDefinitions) + MultiThreaded + ..\include;..\ext\7z\src;..\ext\utfcpp\source + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;SZIP_STATIC;VFS_STATIC;VFS_WITH_SLF;VFS_WITH_7ZIP;%(PreprocessorDefinitions) + MultiThreaded + ..\include;..\ext\7z\src;..\ext\utfcpp\source + + + + + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/ext/VFS/build/VFS_VS2010.vcxproj.filters b/ext/VFS/build/VFS_VS2010.vcxproj.filters new file mode 100644 index 000000000..adb659eb0 --- /dev/null +++ b/ext/VFS/build/VFS_VS2010.vcxproj.filters @@ -0,0 +1,241 @@ + + + + + {6c3b13e6-1de1-49b1-a220-9fd9490119ee} + + + {e906ed36-fcb5-449d-9038-bd238d1583f3} + + + {275b4cf2-0a06-4627-b4cc-f5ce7d2d46a7} + + + {4831f68f-56bb-4e7e-8d77-ab21a1a8031f} + + + {93770afd-298c-46b1-95fe-5884cb101700} + + + {db5b3ae9-28da-4e02-a106-662f2cd0b483} + + + {1f6aa1a4-2764-46bf-83d0-de215f92b26a} + + + + + + Tools + + + Tools + + + Tools + + + Tools + + + Tools + + + Tools + + + Tools + + + Tools + + + Ext + + + Ext + + + Ext + + + Aspects + + + Aspects + + + Aspects + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core\File + + + Core\File + + + Core\File + + + Core\Interface + + + Core\Interface + + + Core\Interface + + + Core\Interface + + + Core\Interface + + + Core\Location + + + Core\Location + + + Core\Location + + + Core + + + Core\File + + + + + Tools + + + Tools + + + Tools + + + Tools + + + Tools + + + Tools + + + Tools + + + Tools + + + Ext + + + Ext + + + Ext + + + Aspects + + + Aspects + + + Aspects + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core\Location + + + Core\Location + + + Core\Location + + + Core\Interface + + + Core\File + + + Core\File + + + Core\File + + + Core + + + Core\File + + + \ No newline at end of file diff --git a/ext/VFS/ext/7z/CMakeLists.txt b/ext/VFS/ext/7z/CMakeLists.txt new file mode 100644 index 000000000..caa436e35 --- /dev/null +++ b/ext/VFS/ext/7z/CMakeLists.txt @@ -0,0 +1,115 @@ + +## 7-zip + +if(WIN32) + option(BFVFS_7ZIP_MT "multi-threading support" OFF) + mark_as_advanced(BFVFS_7ZIP_MT) +endif() + +set(INCLUDE_7z + src/7z.h + src/7zBuf.h + src/7zCrc.h + src/7zFile.h + src/7zVersion.h + src/Alloc.h + src/Bcj2.h + src/Bra.h + src/CpuArch.h + src/Delta.h + src/LzFind.h + src/LzHash.h + src/Lzma2Dec.h + src/Lzma2Enc.h + src/Lzma86.h + src/LzmaEnc.h + src/LzmaLib.h + src/Ppmd.h + src/Sha256.h + src/Types.h +# src/Xz.h +# src/XzEnc.h + src/7zAlloc.h +) +if(WIN32 AND BFVFS_7ZIP_MT) + set(INCLUDE_7z ${INCLUDE_7z} + src/LzFindMt.h + src/MtCoder.h + src/Threads.h + ) +endif() + +set(SOURCE_7z + src/7zBuf.c + src/7zBuf2.c + src/7zCrc.c + src/7zCrcOpt.c + src/7zDec.c + src/7zFile.c + src/7zIn.c + src/7zStream.c + src/Alloc.c + src/Bcj2.c + src/Bra.c + src/Bra86.c + src/CpuArch.c + src/Delta.c + src/LzFind.c + src/Lzma2Dec.c + src/Lzma86Dec.c + src/Lzma86Enc.c + src/LzmaDec.c + src/LzmaEnc.c + src/Sha256.c +# src/Xz.c +# src/XzDec.c +# src/XzEnc.c +# src/XzIn.c + src/7zAlloc.c +) +if(WIN32 AND BFVFS_7ZIP_MT) + set(SOURCE_7z ${SOURCE_7z} + src/LzFindMt.c + src/Lzma2Enc.c + src/MtCoder.c + src/Threads.c + ) +endif() + +source_group("" FILES ${INCLUDE_7z} ${SOURCE_7z}) + +#################################################### + +if(BUILD_BFVFS_7ZIP_SHARED) + set(BUILD_SHARED_LIBS ON) + add_definitions(-DSZIP_EXPORT) + set(DEFINITIONS ${DEFINITIONS} -DSZIP_IMPORT) +else() + set(BUILD_SHARED_LIBS OFF) + add_definitions(-DSZIP_STATIC) + set(DEFINITIONS ${DEFINITIONS} -DSZIP_STATIC) +endif() + +if(NOT WIN32 OR NOT BFVFS_7ZIP_MT) + add_definitions(-D_7ZIP_ST) +endif() + +set(BFVFS_7ZIP_TARGET "7z" CACHE INTERNAL "") + +add_library( ${BFVFS_7ZIP_TARGET} ${INCLUDE_7z} ${SOURCE_7z} ) + +set_property( + TARGET ${BFVFS_7ZIP_TARGET} + PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${BFVFS_LIBRARY_DIRS} +) +set_property( + TARGET ${BFVFS_7ZIP_TARGET} + PROPERTY LIBRARY_OUTPUT_DIRECTORY ${BFVFS_LIBRARY_DIRS} +) +set_property( + TARGET ${BFVFS_7ZIP_TARGET} + PROPERTY RUNTIME_OUTPUT_DIRECTORY ${BFVFS_RUNTIME_DIRS} +) +#################################################### + +set(BFVFS_7ZIP_DEFINITIONS ${DEFINITIONS} CACHE INTERNAL "") diff --git a/ext/VFS/ext/7z/doc/7zC.txt b/ext/VFS/ext/7z/doc/7zC.txt new file mode 100644 index 000000000..4ff63250d --- /dev/null +++ b/ext/VFS/ext/7z/doc/7zC.txt @@ -0,0 +1,194 @@ +7z ANSI-C Decoder 4.62 +---------------------- + +7z ANSI-C provides 7z/LZMA decoding. +7z ANSI-C version is simplified version ported from C++ code. + +LZMA is default and general compression method of 7z format +in 7-Zip compression program (www.7-zip.org). LZMA provides high +compression ratio and very fast decompression. + + +LICENSE +------- + +7z ANSI-C Decoder is part of the LZMA SDK. +LZMA SDK is written and placed in the public domain by Igor Pavlov. + +Files +--------------------- + +7zDecode.* - Low level 7z decoding +7zExtract.* - High level 7z decoding +7zHeader.* - .7z format constants +7zIn.* - .7z archive opening +7zItem.* - .7z structures +7zMain.c - Test application + + +How To Use +---------- + +You must download 7-Zip program from www.7-zip.org. + +You can create .7z archive with 7z.exe or 7za.exe: + + 7za.exe a archive.7z *.htm -r -mx -m0fb=255 + +If you have big number of files in archive, and you need fast extracting, +you can use partly-solid archives: + + 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K + +In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only +512KB for extracting one file from such archive. + + +Limitations of current version of 7z ANSI-C Decoder +--------------------------------------------------- + + - It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive. + - It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters. + - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names. + +These limitations will be fixed in future versions. + + +Using 7z ANSI-C Decoder Test application: +----------------------------------------- + +Usage: 7zDec + +: + e: Extract files from archive + l: List contents of archive + t: Test integrity of archive + +Example: + + 7zDec l archive.7z + +lists contents of archive.7z + + 7zDec e archive.7z + +extracts files from archive.7z to current folder. + + +How to use .7z Decoder +---------------------- + +Memory allocation +~~~~~~~~~~~~~~~~~ + +7z Decoder uses two memory pools: +1) Temporary pool +2) Main pool +Such scheme can allow you to avoid fragmentation of allocated blocks. + + +Steps for using 7z decoder +-------------------------- + +Use code at 7zMain.c as example. + +1) Declare variables: + inStream /* implements ILookInStream interface */ + CSzArEx db; /* 7z archive database structure */ + ISzAlloc allocImp; /* memory functions for main pool */ + ISzAlloc allocTempImp; /* memory functions for temporary pool */ + +2) call CrcGenerateTable(); function to initialize CRC structures. + +3) call SzArEx_Init(&db); function to initialize db structures. + +4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive + +This function opens archive "inStream" and reads headers to "db". +All items in "db" will be allocated with "allocMain" functions. +SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions. + +5) List items or Extract items + + Listing code: + ~~~~~~~~~~~~~ + { + UInt32 i; + for (i = 0; i < db.db.NumFiles; i++) + { + CFileItem *f = db.db.Files + i; + printf("%10d %s\n", (int)f->Size, f->Name); + } + } + + Extracting code: + ~~~~~~~~~~~~~~~~ + + SZ_RESULT SzAr_Extract( + CArchiveDatabaseEx *db, + ILookInStream *inStream, + UInt32 fileIndex, /* index of file */ + UInt32 *blockIndex, /* index of solid block */ + Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t *outBufferSize, /* buffer size for output buffer */ + size_t *offset, /* offset of stream for required file in *outBuffer */ + size_t *outSizeProcessed, /* size of file in *outBuffer */ + ISzAlloc *allocMain, + ISzAlloc *allocTemp); + + If you need to decompress more than one file, you can send these values from previous call: + blockIndex, + outBuffer, + outBufferSize, + You can consider "outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + After decompressing you must free "outBuffer": + allocImp.Free(outBuffer); + +6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db". + + + + +Memory requirements for .7z decoding +------------------------------------ + +Memory usage for Archive opening: + - Temporary pool: + - Memory for uncompressed .7z headers + - some other temporary blocks + - Main pool: + - Memory for database: + Estimated size of one file structures in solid archive: + - Size (4 or 8 Bytes) + - CRC32 (4 bytes) + - LastWriteTime (8 bytes) + - Some file information (4 bytes) + - File Name (variable length) + pointer + allocation structures + +Memory usage for archive Decompressing: + - Temporary pool: + - Memory for LZMA decompressing structures + - Main pool: + - Memory for decompressed solid block + - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these + temprorary buffers can be about 15% of solid block size. + + +7z Decoder doesn't allocate memory for compressed blocks. +Instead of this, you must allocate buffer with desired +size before calling 7z Decoder. Use 7zMain.c as example. + + +Defines +------- + +_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr. + + +--- + +http://www.7-zip.org +http://www.7-zip.org/sdk.html +http://www.7-zip.org/support.html diff --git a/ext/VFS/ext/7z/doc/7zFormat.txt b/ext/VFS/ext/7z/doc/7zFormat.txt new file mode 100644 index 000000000..f084c05d6 --- /dev/null +++ b/ext/VFS/ext/7z/doc/7zFormat.txt @@ -0,0 +1,471 @@ +7z Format description (2.30 Beta 25) +----------------------------------- + +This file contains description of 7z archive format. +7z archive can contain files compressed with any method. +See "Methods.txt" for description for defined compressing methods. + + +Format structure Overview +------------------------- + +Some fields can be optional. + +Archive structure +~~~~~~~~~~~~~~~~~ +SignatureHeader +[PackedStreams] +[PackedStreamsForHeaders] +[ + Header + or + { + Packed Header + HeaderInfo + } +] + + + +Header structure +~~~~~~~~~~~~~~~~ +{ + ArchiveProperties + AdditionalStreams + { + PackInfo + { + PackPos + NumPackStreams + Sizes[NumPackStreams] + CRCs[NumPackStreams] + } + CodersInfo + { + NumFolders + Folders[NumFolders] + { + NumCoders + CodersInfo[NumCoders] + { + ID + NumInStreams; + NumOutStreams; + PropertiesSize + Properties[PropertiesSize] + } + NumBindPairs + BindPairsInfo[NumBindPairs] + { + InIndex; + OutIndex; + } + PackedIndices + } + UnPackSize[Folders][Folders.NumOutstreams] + CRCs[NumFolders] + } + SubStreamsInfo + { + NumUnPackStreamsInFolders[NumFolders]; + UnPackSizes[] + CRCs[] + } + } + MainStreamsInfo + { + (Same as in AdditionalStreams) + } + FilesInfo + { + NumFiles + Properties[] + { + ID + Size + Data + } + } +} + +HeaderInfo structure +~~~~~~~~~~~~~~~~~~~~ +{ + (Same as in AdditionalStreams) +} + + + +Notes about Notation and encoding +--------------------------------- + +7z uses little endian encoding. + +7z archive format has optional headers that are marked as +[] +Header +[] + +REAL_UINT64 means real UINT64. + +UINT64 means real UINT64 encoded with the following scheme: + + Size of encoding sequence depends from first byte: + First_Byte Extra_Bytes Value + (binary) + 0xxxxxxx : ( xxxxxxx ) + 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y + 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y + ... + 1111110x BYTE y[6] : ( x << (8 * 6)) + y + 11111110 BYTE y[7] : y + 11111111 BYTE y[8] : y + + + +Property IDs +------------ + +0x00 = kEnd, + +0x01 = kHeader, + +0x02 = kArchiveProperties, + +0x03 = kAdditionalStreamsInfo, +0x04 = kMainStreamsInfo, +0x05 = kFilesInfo, + +0x06 = kPackInfo, +0x07 = kUnPackInfo, +0x08 = kSubStreamsInfo, + +0x09 = kSize, +0x0A = kCRC, + +0x0B = kFolder, + +0x0C = kCodersUnPackSize, +0x0D = kNumUnPackStream, + +0x0E = kEmptyStream, +0x0F = kEmptyFile, +0x10 = kAnti, + +0x11 = kName, +0x12 = kCreationTime, +0x13 = kLastAccessTime, +0x14 = kLastWriteTime, +0x15 = kWinAttributes, +0x16 = kComment, + +0x17 = kEncodedHeader, + + +7z format headers +----------------- + +SignatureHeader +~~~~~~~~~~~~~~~ + BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; + + ArchiveVersion + { + BYTE Major; // now = 0 + BYTE Minor; // now = 2 + }; + + UINT32 StartHeaderCRC; + + StartHeader + { + REAL_UINT64 NextHeaderOffset + REAL_UINT64 NextHeaderSize + UINT32 NextHeaderCRC + } + + +........................... + + +ArchiveProperties +~~~~~~~~~~~~~~~~~ +BYTE NID::kArchiveProperties (0x02) +for (;;) +{ + BYTE PropertyType; + if (aType == 0) + break; + UINT64 PropertySize; + BYTE PropertyData[PropertySize]; +} + + +Digests (NumStreams) +~~~~~~~~~~~~~~~~~~~~~ + BYTE AllAreDefined + if (AllAreDefined == 0) + { + for(NumStreams) + BIT Defined + } + UINT32 CRCs[NumDefined] + + +PackInfo +~~~~~~~~~~~~ + BYTE NID::kPackInfo (0x06) + UINT64 PackPos + UINT64 NumPackStreams + + [] + BYTE NID::kSize (0x09) + UINT64 PackSizes[NumPackStreams] + [] + + [] + BYTE NID::kCRC (0x0A) + PackStreamDigests[NumPackStreams] + [] + + BYTE NID::kEnd + + +Folder +~~~~~~ + UINT64 NumCoders; + for (NumCoders) + { + BYTE + { + 0:3 DecompressionMethod.IDSize + 4: + 0 - IsSimple + 1 - Is not simple + 5: + 0 - No Attributes + 1 - There Are Attributes + 7: + 0 - Last Method in Alternative_Method_List + 1 - There are more alternative methods + } + BYTE DecompressionMethod.ID[DecompressionMethod.IDSize] + if (!IsSimple) + { + UINT64 NumInStreams; + UINT64 NumOutStreams; + } + if (DecompressionMethod[0] != 0) + { + UINT64 PropertiesSize + BYTE Properties[PropertiesSize] + } + } + + NumBindPairs = NumOutStreamsTotal - 1; + + for (NumBindPairs) + { + UINT64 InIndex; + UINT64 OutIndex; + } + + NumPackedStreams = NumInStreamsTotal - NumBindPairs; + if (NumPackedStreams > 1) + for(NumPackedStreams) + { + UINT64 Index; + }; + + + + +Coders Info +~~~~~~~~~~~ + + BYTE NID::kUnPackInfo (0x07) + + + BYTE NID::kFolder (0x0B) + UINT64 NumFolders + BYTE External + switch(External) + { + case 0: + Folders[NumFolders] + case 1: + UINT64 DataStreamIndex + } + + + BYTE ID::kCodersUnPackSize (0x0C) + for(Folders) + for(Folder.NumOutStreams) + UINT64 UnPackSize; + + + [] + BYTE NID::kCRC (0x0A) + UnPackDigests[NumFolders] + [] + + + + BYTE NID::kEnd + + + +SubStreams Info +~~~~~~~~~~~~~~ + BYTE NID::kSubStreamsInfo; (0x08) + + [] + BYTE NID::kNumUnPackStream; (0x0D) + UINT64 NumUnPackStreamsInFolders[NumFolders]; + [] + + + [] + BYTE NID::kSize (0x09) + UINT64 UnPackSizes[] + [] + + + [] + BYTE NID::kCRC (0x0A) + Digests[Number of streams with unknown CRC] + [] + + + BYTE NID::kEnd + + +Streams Info +~~~~~~~~~~~~ + + [] + PackInfo + [] + + + [] + CodersInfo + [] + + + [] + SubStreamsInfo + [] + + BYTE NID::kEnd + + +FilesInfo +~~~~~~~~~ + BYTE NID::kFilesInfo; (0x05) + UINT64 NumFiles + + for (;;) + { + BYTE PropertyType; + if (aType == 0) + break; + + UINT64 Size; + + switch(PropertyType) + { + kEmptyStream: (0x0E) + for(NumFiles) + BIT IsEmptyStream + + kEmptyFile: (0x0F) + for(EmptyStreams) + BIT IsEmptyFile + + kAnti: (0x10) + for(EmptyStreams) + BIT IsAntiFile + + case kCreationTime: (0x12) + case kLastAccessTime: (0x13) + case kLastWriteTime: (0x14) + BYTE AllAreDefined + if (AllAreDefined == 0) + { + for(NumFiles) + BIT TimeDefined + } + BYTE External; + if(External != 0) + UINT64 DataIndex + [] + for(Definded Items) + UINT32 Time + [] + + kNames: (0x11) + BYTE External; + if(External != 0) + UINT64 DataIndex + [] + for(Files) + { + wchar_t Names[NameSize]; + wchar_t 0; + } + [] + + kAttributes: (0x15) + BYTE AllAreDefined + if (AllAreDefined == 0) + { + for(NumFiles) + BIT AttributesAreDefined + } + BYTE External; + if(External != 0) + UINT64 DataIndex + [] + for(Definded Attributes) + UINT32 Attributes + [] + } + } + + +Header +~~~~~~ + BYTE NID::kHeader (0x01) + + [] + ArchiveProperties + [] + + [] + BYTE NID::kAdditionalStreamsInfo; (0x03) + StreamsInfo + [] + + [] + BYTE NID::kMainStreamsInfo; (0x04) + StreamsInfo + [] + + [] + FilesInfo + [] + + BYTE NID::kEnd + + +HeaderInfo +~~~~~~~~~~ + [] + BYTE NID::kEncodedHeader; (0x17) + StreamsInfo for Encoded Header + [] + + +--- +End of document diff --git a/ext/VFS/ext/7z/doc/Methods.txt b/ext/VFS/ext/7z/doc/Methods.txt new file mode 100644 index 000000000..9ed27428d --- /dev/null +++ b/ext/VFS/ext/7z/doc/Methods.txt @@ -0,0 +1,146 @@ +7-Zip method IDs (9.04) +----------------------- + +Each compression or crypto method in 7z has unique binary value (ID). +The length of ID in bytes is arbitrary but it can not exceed 63 bits (8 bytes). + +If you want to add some new ID, you have two ways: +1) Write request for allocating IDs to 7-zip developers. +2) Generate 8-bytes ID: + + 3F ZZ ZZ ZZ ZZ ZZ MM MM + + 3F - Prefix for random IDs (1 byte) + ZZ ZZ ZZ ZZ ZZ - Developer ID (5 bytes). Use real random bytes. + + MM MM - Method ID (2 bytes) + + You can notify 7-Zip developers about your Developer ID / Method ID. + + Note: Use new ID only if old codec can not decode data encoded with new version. + + +List of defined IDs +------------------- + +00 - Copy + +03 - Delta +04 - x86 (BCJ) +05 - PPC (Big Endian) +06 - IA64 +07 - ARM (little endian) +08 - ARM Thumb (little endian) +09 - SPARC +21 - LZMA2 + +02.. - Common + 03 Swap + - 2 Swap2 + - 4 Swap4 + +03.. - 7z + 01 - LZMA + 01 - Version + + 03 - Branch + 01 - x86 + 03 - BCJ + 1B - BCJ2 + 02 - PPC + 05 - PPC (Big Endian) + 03 - Alpha + 01 - Alpha + 04 - IA64 + 01 - IA64 + 05 - ARM + 01 - ARM + 06 - M68 + 05 - M68 (Big Endian) + 07 - ARM Thumb + 01 - ARMT + 08 - SPARC + 05 - SPARC + + 04 - PPMD + 01 - Version + + 7F - + 01 - experimental methods. + + +04.. - Misc + 00 - Reserved + 01 - Zip + 00 - Copy (not used). Use {00} instead + 01 - Shrink + 06 - Implode + 08 - Deflate + 09 - Deflate64 + 12 - BZip2 (not used). Use {04 02 02} instead + 02 - BZip + 02 - BZip2 + 03 - Rar + 01 - Rar15 + 02 - Rar20 + 03 - Rar29 + 04 - Arj + 01 - Arj (1,2,3) + 02 - Arj 4 + 05 - Z + 06 - Lzh + 07 - Reserved for 7z + 08 - Cab + 09 - NSIS + 01 - DeflateNSIS + 02 - BZip2NSIS + + +06.. - Crypto + 00 - + 01 - AES + 0x - AES-128 + 4x - AES-192 + 8x - AES-256 + Cx - AES + + x0 - ECB + x1 - CBC + x2 - CFB + x3 - OFB + + 07 - Reserved + 0F - Reserved + + F0 - Misc Ciphers (Real Ciphers without hashing algo) + + F1 - Misc Ciphers (Combine) + 01 - Zip + 01 - Main Zip crypto algo + 03 - RAR + 02 - + 03 - Rar29 AES-128 + (modified SHA-1) + 07 - 7z + 01 - AES-256 + SHA-256 + +07.. - Hash (subject to change) + 00 - + 01 - CRC + 02 - SHA-1 + 03 - SHA-256 + 04 - SHA-384 + 05 - SHA-512 + + F0 - Misc Hash + + F1 - Misc + 03 - RAR + 03 - Rar29 Password Hashing (modified SHA1) + 07 - 7z + 01 - SHA-256 Password Hashing + + + + +--- +End of document diff --git a/ext/VFS/ext/7z/doc/history.txt b/ext/VFS/ext/7z/doc/history.txt new file mode 100644 index 000000000..3b09fe91e --- /dev/null +++ b/ext/VFS/ext/7z/doc/history.txt @@ -0,0 +1,266 @@ +HISTORY of the LZMA SDK +----------------------- + +9.12 beta 2010-03-24 +------------------------- +- The BUG in LZMA SDK 9.* was fixed: LZMA2 codec didn't work, + if more than 10 threads were used (or more than 20 threads in some modes). + + +9.11 beta 2010-03-15 +------------------------- +- PPMd compression method support + + +9.09 2009-12-12 +------------------------- +- The bug was fixed: + Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c + incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8. +- Some bugs were fixed + + +9.06 2009-08-17 +------------------------- +- Some changes in ANSI-C 7z Decoder interfaces. + + +9.04 2009-05-30 +------------------------- +- LZMA2 compression method support +- xz format support + + +4.65 2009-02-03 +------------------------- +- Some minor fixes + + +4.63 2008-12-31 +------------------------- +- Some minor fixes + + +4.61 beta 2008-11-23 +------------------------- +- The bug in ANSI-C LZMA Decoder was fixed: + If encoded stream was corrupted, decoder could access memory + outside of allocated range. +- Some changes in ANSI-C 7z Decoder interfaces. +- LZMA SDK is placed in the public domain. + + +4.60 beta 2008-08-19 +------------------------- +- Some minor fixes. + + +4.59 beta 2008-08-13 +------------------------- +- The bug was fixed: + LZMA Encoder in fast compression mode could access memory outside of + allocated range in some rare cases. + + +4.58 beta 2008-05-05 +------------------------- +- ANSI-C LZMA Decoder was rewritten for speed optimizations. +- ANSI-C LZMA Encoder was included to LZMA SDK. +- C++ LZMA code now is just wrapper over ANSI-C code. + + +4.57 2007-12-12 +------------------------- +- Speed optimizations in Ñ++ LZMA Decoder. +- Small changes for more compatibility with some C/C++ compilers. + + +4.49 beta 2007-07-05 +------------------------- +- .7z ANSI-C Decoder: + - now it supports BCJ and BCJ2 filters + - now it supports files larger than 4 GB. + - now it supports "Last Write Time" field for files. +- C++ code for .7z archives compressing/decompressing from 7-zip + was included to LZMA SDK. + + +4.43 2006-06-04 +------------------------- +- Small changes for more compatibility with some C/C++ compilers. + + +4.42 2006-05-15 +------------------------- +- Small changes in .h files in ANSI-C version. + + +4.39 beta 2006-04-14 +------------------------- +- The bug in versions 4.33b:4.38b was fixed: + C++ version of LZMA encoder could not correctly compress + files larger than 2 GB with HC4 match finder (-mfhc4). + + +4.37 beta 2005-04-06 +------------------------- +- Fixes in C++ code: code could no be compiled if _NO_EXCEPTIONS was defined. + + +4.35 beta 2005-03-02 +------------------------- +- The bug was fixed in C++ version of LZMA Decoder: + If encoded stream was corrupted, decoder could access memory + outside of allocated range. + + +4.34 beta 2006-02-27 +------------------------- +- Compressing speed and memory requirements for compressing were increased +- LZMA now can use only these match finders: HC4, BT2, BT3, BT4 + + +4.32 2005-12-09 +------------------------- +- Java version of LZMA SDK was included + + +4.30 2005-11-20 +------------------------- +- Compression ratio was improved in -a2 mode +- Speed optimizations for compressing in -a2 mode +- -fb switch now supports values up to 273 +- The bug in 7z_C (7zIn.c) was fixed: + It used Alloc/Free functions from different memory pools. + So if program used two memory pools, it worked incorrectly. +- 7z_C: .7z format supporting was improved +- LZMA# SDK (C#.NET version) was included + + +4.27 (Updated) 2005-09-21 +------------------------- +- Some GUIDs/interfaces in C++ were changed. + IStream.h: + ISequentialInStream::Read now works as old ReadPart + ISequentialOutStream::Write now works as old WritePart + + +4.27 2005-08-07 +------------------------- +- The bug in LzmaDecodeSize.c was fixed: + if _LZMA_IN_CB and _LZMA_OUT_READ were defined, + decompressing worked incorrectly. + + +4.26 2005-08-05 +------------------------- +- Fixes in 7z_C code and LzmaTest.c: + previous versions could work incorrectly, + if malloc(0) returns 0 + + +4.23 2005-06-29 +------------------------- +- Small fixes in C++ code + + +4.22 2005-06-10 +------------------------- +- Small fixes + + +4.21 2005-06-08 +------------------------- +- Interfaces for ANSI-C LZMA Decoder (LzmaDecode.c) were changed +- New additional version of ANSI-C LZMA Decoder with zlib-like interface: + - LzmaStateDecode.h + - LzmaStateDecode.c + - LzmaStateTest.c +- ANSI-C LZMA Decoder now can decompress files larger than 4 GB + + +4.17 2005-04-18 +------------------------- +- New example for RAM->RAM compressing/decompressing: + LZMA + BCJ (filter for x86 code): + - LzmaRam.h + - LzmaRam.cpp + - LzmaRamDecode.h + - LzmaRamDecode.c + - -f86 switch for lzma.exe + + +4.16 2005-03-29 +------------------------- +- The bug was fixed in LzmaDecode.c (ANSI-C LZMA Decoder): + If _LZMA_OUT_READ was defined, and if encoded stream was corrupted, + decoder could access memory outside of allocated range. +- Speed optimization of ANSI-C LZMA Decoder (now it's about 20% faster). + Old version of LZMA Decoder now is in file LzmaDecodeSize.c. + LzmaDecodeSize.c can provide slightly smaller code than LzmaDecode.c +- Small speed optimization in LZMA C++ code +- filter for SPARC's code was added +- Simplified version of .7z ANSI-C Decoder was included + + +4.06 2004-09-05 +------------------------- +- The bug in v4.05 was fixed: + LZMA-Encoder didn't release output stream in some cases. + + +4.05 2004-08-25 +------------------------- +- Source code of filters for x86, IA-64, ARM, ARM-Thumb + and PowerPC code was included to SDK +- Some internal minor changes + + +4.04 2004-07-28 +------------------------- +- More compatibility with some C++ compilers + + +4.03 2004-06-18 +------------------------- +- "Benchmark" command was added. It measures compressing + and decompressing speed and shows rating values. + Also it checks hardware errors. + + +4.02 2004-06-10 +------------------------- +- C++ LZMA Encoder/Decoder code now is more portable + and it can be compiled by GCC on Linux. + + +4.01 2004-02-15 +------------------------- +- Some detection of data corruption was enabled. + LzmaDecode.c / RangeDecoderReadByte + ..... + { + rd->ExtraBytes = 1; + return 0xFF; + } + + +4.00 2004-02-13 +------------------------- +- Original version of LZMA SDK + + + +HISTORY of the LZMA +------------------- + 2001-2008: Improvements to LZMA compressing/decompressing code, + keeping compatibility with original LZMA format + 1996-2001: Development of LZMA compression format + + Some milestones: + + 2001-08-30: LZMA compression was added to 7-Zip + 1999-01-02: First version of 7-Zip was released + + +End of document diff --git a/ext/VFS/ext/7z/doc/lzma.txt b/ext/VFS/ext/7z/doc/lzma.txt new file mode 100644 index 000000000..a2f3477ee --- /dev/null +++ b/ext/VFS/ext/7z/doc/lzma.txt @@ -0,0 +1,599 @@ +LZMA SDK 9.12 +------------- + +LZMA SDK provides the documentation, samples, header files, libraries, +and tools you need to develop applications that use LZMA compression. + +LZMA is default and general compression method of 7z format +in 7-Zip compression program (www.7-zip.org). LZMA provides high +compression ratio and very fast decompression. + +LZMA is an improved version of famous LZ77 compression algorithm. +It was improved in way of maximum increasing of compression ratio, +keeping high decompression speed and low memory requirements for +decompressing. + + + +LICENSE +------- + +LZMA SDK is written and placed in the public domain by Igor Pavlov. + +Some code in LZMA is based on public domain code from another developers: + 1) PPMd var.H (2001): Dmitry Shkarin + 2) SHA-256: Wei Dai (Crypto++ library) + + +LZMA SDK Contents +----------------- + +LZMA SDK includes: + + - ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing + - Compiled file->file LZMA compressing/decompressing program for Windows system + + +UNIX/Linux version +------------------ +To compile C++ version of file->file LZMA encoding, go to directory +C++/7zip/Compress/LZMA_Alone +and call make to recompile it: + make -f makefile.gcc clean all + +In some UNIX/Linux versions you must compile LZMA with static libraries. +To compile with static libraries, you can use +LIB = -lm -static + + +Files +--------------------- +lzma.txt - LZMA SDK description (this file) +7zFormat.txt - 7z Format description +7zC.txt - 7z ANSI-C Decoder description +methods.txt - Compression method IDs for .7z +lzma.exe - Compiled file->file LZMA encoder/decoder for Windows +7zr.exe - 7-Zip with 7z/lzma/xz support. +history.txt - history of the LZMA SDK + + +Source code structure +--------------------- + +C/ - C files + 7zCrc*.* - CRC code + Alloc.* - Memory allocation functions + Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code + LzFind.* - Match finder for LZ (LZMA) encoders + LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding + LzHash.h - Additional file for LZ match finder + LzmaDec.* - LZMA decoding + LzmaEnc.* - LZMA encoding + LzmaLib.* - LZMA Library for DLL calling + Types.h - Basic types for another .c files + Threads.* - The code for multithreading. + + LzmaLib - LZMA Library (.DLL for Windows) + + LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder). + + Archive - files related to archiving + 7z - 7z ANSI-C Decoder + +CPP/ -- CPP files + + Common - common files for C++ projects + Windows - common files for Windows related code + + 7zip - files related to 7-Zip Project + + Common - common files for 7-Zip + + Compress - files related to compression/decompression + + LZMA_Alone - file->file LZMA compression/decompression + + Archive - files related to archiving + + Common - common files for archive handling + 7z - 7z C++ Encoder/Decoder + + Bundles - Modules that are bundles of other modules + + Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2 + Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2 + Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2. + + UI - User Interface files + + Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll + Common - Common UI files + Console - Code for console archiver + + + +CS/ - C# files + 7zip + Common - some common files for 7-Zip + Compress - files related to compression/decompression + LZ - files related to LZ (Lempel-Ziv) compression algorithm + LZMA - LZMA compression/decompression + LzmaAlone - file->file LZMA compression/decompression + RangeCoder - Range Coder (special code of compression/decompression) + +Java/ - Java files + SevenZip + Compression - files related to compression/decompression + LZ - files related to LZ (Lempel-Ziv) compression algorithm + LZMA - LZMA compression/decompression + RangeCoder - Range Coder (special code of compression/decompression) + + +C/C++ source code of LZMA SDK is part of 7-Zip project. +7-Zip source code can be downloaded from 7-Zip's SourceForge page: + + http://sourceforge.net/projects/sevenzip/ + + + +LZMA features +------------- + - Variable dictionary size (up to 1 GB) + - Estimated compressing speed: about 2 MB/s on 2 GHz CPU + - Estimated decompressing speed: + - 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64 + - 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC + - Small memory requirements for decompressing (16 KB + DictionarySize) + - Small code size for decompressing: 5-8 KB + +LZMA decoder uses only integer operations and can be +implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions). + +Some critical operations that affect the speed of LZMA decompression: + 1) 32*16 bit integer multiply + 2) Misspredicted branches (penalty mostly depends from pipeline length) + 3) 32-bit shift and arithmetic operations + +The speed of LZMA decompressing mostly depends from CPU speed. +Memory speed has no big meaning. But if your CPU has small data cache, +overall weight of memory speed will slightly increase. + + +How To Use +---------- + +Using LZMA encoder/decoder executable +-------------------------------------- + +Usage: LZMA inputFile outputFile [...] + + e: encode file + + d: decode file + + b: Benchmark. There are two tests: compressing and decompressing + with LZMA method. Benchmark shows rating in MIPS (million + instructions per second). Rating value is calculated from + measured speed and it is normalized with Intel's Core 2 results. + Also Benchmark checks possible hardware errors (RAM + errors in most cases). Benchmark uses these settings: + (-a1, -d21, -fb32, -mfbt4). You can change only -d parameter. + Also you can change the number of iterations. Example for 30 iterations: + LZMA b 30 + Default number of iterations is 10. + + + + + -a{N}: set compression mode 0 = fast, 1 = normal + default: 1 (normal) + + d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB) + The maximum value for dictionary size is 1 GB = 2^30 bytes. + Dictionary size is calculated as DictionarySize = 2^N bytes. + For decompressing file compressed by LZMA method with dictionary + size D = 2^N you need about D bytes of memory (RAM). + + -fb{N}: set number of fast bytes - [5, 273], default: 128 + Usually big number gives a little bit better compression ratio + and slower compression process. + + -lc{N}: set number of literal context bits - [0, 8], default: 3 + Sometimes lc=4 gives gain for big files. + + -lp{N}: set number of literal pos bits - [0, 4], default: 0 + lp switch is intended for periodical data when period is + equal 2^N. For example, for 32-bit (4 bytes) + periodical data you can use lp=2. Often it's better to set lc0, + if you change lp switch. + + -pb{N}: set number of pos bits - [0, 4], default: 2 + pb switch is intended for periodical data + when period is equal 2^N. + + -mf{MF_ID}: set Match Finder. Default: bt4. + Algorithms from hc* group doesn't provide good compression + ratio, but they often works pretty fast in combination with + fast mode (-a0). + + Memory requirements depend from dictionary size + (parameter "d" in table below). + + MF_ID Memory Description + + bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing. + bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing. + bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing. + hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing. + + -eos: write End Of Stream marker. By default LZMA doesn't write + eos marker, since LZMA decoder knows uncompressed size + stored in .lzma file header. + + -si: Read data from stdin (it will write End Of Stream marker). + -so: Write data to stdout + + +Examples: + +1) LZMA e file.bin file.lzma -d16 -lc0 + +compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K) +and 0 literal context bits. -lc0 allows to reduce memory requirements +for decompression. + + +2) LZMA e file.bin file.lzma -lc0 -lp2 + +compresses file.bin to file.lzma with settings suitable +for 32-bit periodical data (for example, ARM or MIPS code). + +3) LZMA d file.lzma file.bin + +decompresses file.lzma to file.bin. + + +Compression ratio hints +----------------------- + +Recommendations +--------------- + +To increase the compression ratio for LZMA compressing it's desirable +to have aligned data (if it's possible) and also it's desirable to locate +data in such order, where code is grouped in one place and data is +grouped in other place (it's better than such mixing: code, data, code, +data, ...). + + +Filters +------- +You can increase the compression ratio for some data types, using +special filters before compressing. For example, it's possible to +increase the compression ratio on 5-10% for code for those CPU ISAs: +x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC. + +You can find C source code of such filters in C/Bra*.* files + +You can check the compression ratio gain of these filters with such +7-Zip commands (example for ARM code): +No filter: + 7z a a1.7z a.bin -m0=lzma + +With filter for little-endian ARM code: + 7z a a2.7z a.bin -m0=arm -m1=lzma + +It works in such manner: +Compressing = Filter_encoding + LZMA_encoding +Decompressing = LZMA_decoding + Filter_decoding + +Compressing and decompressing speed of such filters is very high, +so it will not increase decompressing time too much. +Moreover, it reduces decompression time for LZMA_decoding, +since compression ratio with filtering is higher. + +These filters convert CALL (calling procedure) instructions +from relative offsets to absolute addresses, so such data becomes more +compressible. + +For some ISAs (for example, for MIPS) it's impossible to get gain from such filter. + + +LZMA compressed file format +--------------------------- +Offset Size Description + 0 1 Special LZMA properties (lc,lp, pb in encoded form) + 1 4 Dictionary size (little endian) + 5 8 Uncompressed size (little endian). -1 means unknown size + 13 Compressed data + + +ANSI-C LZMA Decoder +~~~~~~~~~~~~~~~~~~~ + +Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58. +If you want to use old interfaces you can download previous version of LZMA SDK +from sourceforge.net site. + +To use ANSI-C LZMA Decoder you need the following files: +1) LzmaDec.h + LzmaDec.c + Types.h +LzmaUtil/LzmaUtil.c is example application that uses these files. + + +Memory requirements for LZMA decoding +------------------------------------- + +Stack usage of LZMA decoding function for local variables is not +larger than 200-400 bytes. + +LZMA Decoder uses dictionary buffer and internal state structure. +Internal state structure consumes + state_size = (4 + (1.5 << (lc + lp))) KB +by default (lc=3, lp=0), state_size = 16 KB. + + +How To decompress data +---------------------- + +LZMA Decoder (ANSI-C version) now supports 2 interfaces: +1) Single-call Decompressing +2) Multi-call State Decompressing (zlib-like interface) + +You must use external allocator: +Example: +void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } +void SzFree(void *p, void *address) { p = p; free(address); } +ISzAlloc alloc = { SzAlloc, SzFree }; + +You can use p = p; operator to disable compiler warnings. + + +Single-call Decompressing +------------------------- +When to use: RAM->RAM decompressing +Compile files: LzmaDec.h + LzmaDec.c + Types.h +Compile defines: no defines +Memory Requirements: + - Input buffer: compressed size + - Output buffer: uncompressed size + - LZMA Internal Structures: state_size (16 KB for default settings) + +Interface: + int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + In: + dest - output data + destLen - output data size + src - input data + srcLen - input data size + propData - LZMA properties (5 bytes) + propSize - size of propData buffer (5 bytes) + finishMode - It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + You can use LZMA_FINISH_END, when you know that + current output buffer covers last bytes of stream. + alloc - Memory allocator. + + Out: + destLen - processed output size + srcLen - processed input size + + Output: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). + + If LZMA decoder sees end_marker before reaching output limit, it returns OK result, + and output value of destLen will be less than output buffer size limit. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + + +Multi-call State Decompressing (zlib-like interface) +---------------------------------------------------- + +When to use: file->file decompressing +Compile files: LzmaDec.h + LzmaDec.c + Types.h + +Memory Requirements: + - Buffer for input stream: any size (for example, 16 KB) + - Buffer for output stream: any size (for example, 16 KB) + - LZMA Internal Structures: state_size (16 KB for default settings) + - LZMA dictionary (dictionary size is encoded in LZMA properties header) + +1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header: + unsigned char header[LZMA_PROPS_SIZE + 8]; + ReadFile(inFile, header, sizeof(header) + +2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties + + CLzmaDec state; + LzmaDec_Constr(&state); + res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc); + if (res != SZ_OK) + return res; + +3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop + + LzmaDec_Init(&state); + for (;;) + { + ... + int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode); + ... + } + + +4) Free all allocated structures + LzmaDec_Free(&state, &g_Alloc); + +For full code example, look at C/LzmaUtil/LzmaUtil.c code. + + +How To compress data +-------------------- + +Compile files: LzmaEnc.h + LzmaEnc.c + Types.h + +LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h + +Memory Requirements: + - (dictSize * 11.5 + 6 MB) + state_size + +Lzma Encoder can use two memory allocators: +1) alloc - for small arrays. +2) allocBig - for big arrays. + +For example, you can use Large RAM Pages (2 MB) in allocBig allocator for +better compression speed. Note that Windows has bad implementation for +Large RAM Pages. +It's OK to use same allocator for alloc and allocBig. + + +Single-call Compression with callbacks +-------------------------------------- + +Check C/LzmaUtil/LzmaUtil.c as example, + +When to use: file->file decompressing + +1) you must implement callback structures for interfaces: +ISeqInStream +ISeqOutStream +ICompressProgress +ISzAlloc + +static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } +static void SzFree(void *p, void *address) { p = p; MyFree(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + + CFileSeqInStream inStream; + CFileSeqOutStream outStream; + + inStream.funcTable.Read = MyRead; + inStream.file = inFile; + outStream.funcTable.Write = MyWrite; + outStream.file = outFile; + + +2) Create CLzmaEncHandle object; + + CLzmaEncHandle enc; + + enc = LzmaEnc_Create(&g_Alloc); + if (enc == 0) + return SZ_ERROR_MEM; + + +3) initialize CLzmaEncProps properties; + + LzmaEncProps_Init(&props); + + Then you can change some properties in that structure. + +4) Send LZMA properties to LZMA Encoder + + res = LzmaEnc_SetProps(enc, &props); + +5) Write encoded properties to header + + Byte header[LZMA_PROPS_SIZE + 8]; + size_t headerSize = LZMA_PROPS_SIZE; + UInt64 fileSize; + int i; + + res = LzmaEnc_WriteProperties(enc, header, &headerSize); + fileSize = MyGetFileLength(inFile); + for (i = 0; i < 8; i++) + header[headerSize++] = (Byte)(fileSize >> (8 * i)); + MyWriteFileAndCheck(outFile, header, headerSize) + +6) Call encoding function: + res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable, + NULL, &g_Alloc, &g_Alloc); + +7) Destroy LZMA Encoder Object + LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); + + +If callback function return some error code, LzmaEnc_Encode also returns that code +or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS. + + +Single-call RAM->RAM Compression +-------------------------------- + +Single-call RAM->RAM Compression is similar to Compression with callbacks, +but you provide pointers to buffers instead of pointers to stream callbacks: + +HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) + + + +Defines +------- + +_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code. + +_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for + some structures will be doubled in that case. + +_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit. + +_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type. + + +_7ZIP_PPMD_SUPPPORT - Define it if you don't want to support PPMD method in AMSI-C .7z decoder. + + +C++ LZMA Encoder/Decoder +~~~~~~~~~~~~~~~~~~~~~~~~ +C++ LZMA code use COM-like interfaces. So if you want to use it, +you can study basics of COM/OLE. +C++ LZMA code is just wrapper over ANSI-C code. + + +C++ Notes +~~~~~~~~~~~~~~~~~~~~~~~~ +If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling), +you must check that you correctly work with "new" operator. +7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator. +So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator: +operator new(size_t size) +{ + void *p = ::malloc(size); + if (p == 0) + throw CNewException(); + return p; +} +If you use MSCV that throws exception for "new" operator, you can compile without +"NewHandler.cpp". So standard exception will be used. Actually some code of +7-Zip catches any exception in internal code and converts it to HRESULT code. +So you don't need to catch CNewException, if you call COM interfaces of 7-Zip. + +--- + +http://www.7-zip.org +http://www.7-zip.org/sdk.html +http://www.7-zip.org/support.html diff --git a/ext/VFS/ext/7z/src/7z.h b/ext/VFS/ext/7z/src/7z.h new file mode 100644 index 000000000..e65ab55ce --- /dev/null +++ b/ext/VFS/ext/7z/src/7z.h @@ -0,0 +1,203 @@ +/* 7z.h -- 7z interface +2010-03-11 : Igor Pavlov : Public domain */ + +#ifndef __7Z_H +#define __7Z_H + +#include "7zBuf.h" + +EXTERN_C_BEGIN + +#define k7zStartHeaderSize 0x20 +#define k7zSignatureSize 6 +SZIP_API extern Byte k7zSignature[k7zSignatureSize]; +#define k7zMajorVersion 0 + +enum EIdEnum +{ + k7zIdEnd, + k7zIdHeader, + k7zIdArchiveProperties, + k7zIdAdditionalStreamsInfo, + k7zIdMainStreamsInfo, + k7zIdFilesInfo, + k7zIdPackInfo, + k7zIdUnpackInfo, + k7zIdSubStreamsInfo, + k7zIdSize, + k7zIdCRC, + k7zIdFolder, + k7zIdCodersUnpackSize, + k7zIdNumUnpackStream, + k7zIdEmptyStream, + k7zIdEmptyFile, + k7zIdAnti, + k7zIdName, + k7zIdCTime, + k7zIdATime, + k7zIdMTime, + k7zIdWinAttributes, + k7zIdComment, + k7zIdEncodedHeader, + k7zIdStartPos, + k7zIdDummy +}; + +typedef struct +{ + UInt32 NumInStreams; + UInt32 NumOutStreams; + UInt64 MethodID; + CBuf Props; +} CSzCoderInfo; + +void SzCoderInfo_Init(CSzCoderInfo *p); +void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc); + +typedef struct +{ + UInt32 InIndex; + UInt32 OutIndex; +} CSzBindPair; + +typedef struct +{ + CSzCoderInfo *Coders; + CSzBindPair *BindPairs; + UInt32 *PackStreams; + UInt64 *UnpackSizes; + UInt32 NumCoders; + UInt32 NumBindPairs; + UInt32 NumPackStreams; + int UnpackCRCDefined; + UInt32 UnpackCRC; + + UInt32 NumUnpackStreams; +} CSzFolder; + +void SzFolder_Init(CSzFolder *p); +SZIP_API UInt64 SzFolder_GetUnpackSize(CSzFolder *p); +int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex); +SZIP_API UInt32 SzFolder_GetNumOutStreams(CSzFolder *p); +SZIP_API UInt64 SzFolder_GetUnpackSize(CSzFolder *p); + +SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes, + ILookInStream *stream, UInt64 startPos, + Byte *outBuffer, size_t outSize, ISzAlloc *allocMain); + +typedef struct +{ + UInt32 Low; + UInt32 High; +} CNtfsFileTime; + +typedef struct +{ + CNtfsFileTime MTime; + UInt64 Size; + UInt32 Crc; + UInt32 Attrib; + Byte HasStream; + Byte IsDir; + Byte IsAnti; + Byte CrcDefined; + Byte MTimeDefined; + Byte AttribDefined; +} CSzFileItem; + +void SzFile_Init(CSzFileItem *p); + +typedef struct +{ + UInt64 *PackSizes; + Byte *PackCRCsDefined; + UInt32 *PackCRCs; + CSzFolder *Folders; + CSzFileItem *Files; + UInt32 NumPackStreams; + UInt32 NumFolders; + UInt32 NumFiles; +} CSzAr; + +void SzAr_Init(CSzAr *p); +void SzAr_Free(CSzAr *p, ISzAlloc *alloc); + + +/* + SzExtract extracts file from archive + + *outBuffer must be 0 before first call for each new archive. + + Extracting cache: + If you need to decompress more than one file, you can send + these values from previous call: + *blockIndex, + *outBuffer, + *outBufferSize + You can consider "*outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + If you use external function, you can declare these 3 cache variables + (blockIndex, outBuffer, outBufferSize) as static in that external function. + + Free *outBuffer and set *outBuffer to 0, if you want to flush cache. +*/ + +typedef struct +{ + CSzAr db; + + UInt64 startPosAfterHeader; + UInt64 dataPos; + + UInt32 *FolderStartPackStreamIndex; + UInt64 *PackStreamStartPositions; + UInt32 *FolderStartFileIndex; + UInt32 *FileIndexToFolderIndexMap; + + size_t *FileNameOffsets; /* in 2-byte steps */ + CBuf FileNames; /* UTF-16-LE */ +} CSzArEx; + +SZIP_API void SzArEx_Init(CSzArEx *p); +void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); +SZIP_API UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); +int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); + +/* +if dest == NULL, the return value specifies the required size of the buffer, + in 16-bit characters, including the null-terminating character. +if dest != NULL, the return value specifies the number of 16-bit characters that + are written to the dest, including the null-terminating character. */ + +SZIP_API size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); + +SRes SzArEx_Extract( + const CSzArEx *db, + ILookInStream *inStream, + UInt32 fileIndex, /* index of file */ + UInt32 *blockIndex, /* index of solid block */ + Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t *outBufferSize, /* buffer size for output buffer */ + size_t *offset, /* offset of stream for required file in *outBuffer */ + size_t *outSizeProcessed, /* size of file in *outBuffer */ + ISzAlloc *allocMain, + ISzAlloc *allocTemp); + + +/* +SzArEx_Open Errors: +SZ_ERROR_NO_ARCHIVE +SZ_ERROR_ARCHIVE +SZ_ERROR_UNSUPPORTED +SZ_ERROR_MEM +SZ_ERROR_CRC +SZ_ERROR_INPUT_EOF +SZ_ERROR_FAIL +*/ + +SZIP_API SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp); + +EXTERN_C_END + +#endif diff --git a/ext/VFS/ext/7z/src/7zAlloc.c b/ext/VFS/ext/7z/src/7zAlloc.c new file mode 100644 index 000000000..b5918d000 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zAlloc.c @@ -0,0 +1,77 @@ +/* 7zAlloc.c -- Allocation functions +2008-10-04 : Igor Pavlov : Public domain */ + +#include +#include "7zAlloc.h" + +/* #define _SZ_ALLOC_DEBUG */ +/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ + +#ifdef _SZ_ALLOC_DEBUG + +#ifdef _WIN32 +#include +#endif + +#include +int g_allocCount = 0; +int g_allocCountTemp = 0; + +#endif + +void *SzAlloc(void *p, size_t size) +{ + p = p; + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount); + g_allocCount++; + #endif + return malloc(size); +} + +void SzFree(void *p, void *address) +{ + p = p; + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + { + g_allocCount--; + fprintf(stderr, "\nFree; count = %10d", g_allocCount); + } + #endif + free(address); +} + +void *SzAllocTemp(void *p, size_t size) +{ + p = p; + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp); + g_allocCountTemp++; + #ifdef _WIN32 + return HeapAlloc(GetProcessHeap(), 0, size); + #endif + #endif + return malloc(size); +} + +void SzFreeTemp(void *p, void *address) +{ + p = p; + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + { + g_allocCountTemp--; + fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp); + } + #ifdef _WIN32 + HeapFree(GetProcessHeap(), 0, address); + return; + #endif + #endif + free(address); +} diff --git a/ext/VFS/ext/7z/src/7zAlloc.h b/ext/VFS/ext/7z/src/7zAlloc.h new file mode 100644 index 000000000..b161d90f7 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zAlloc.h @@ -0,0 +1,24 @@ +/* 7zAlloc.h -- Allocation functions +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __7Z_ALLOC_H +#define __7Z_ALLOC_H + +#include +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SZIP_API void *SzAlloc(void *p, size_t size); +SZIP_API void SzFree(void *p, void *address); + +SZIP_API void *SzAllocTemp(void *p, size_t size); +SZIP_API void SzFreeTemp(void *p, void *address); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/7zBuf.c b/ext/VFS/ext/7z/src/7zBuf.c new file mode 100644 index 000000000..a35fa2f98 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zBuf.c @@ -0,0 +1,36 @@ +/* 7zBuf.c -- Byte Buffer +2008-03-28 +Igor Pavlov +Public domain */ + +#include "7zBuf.h" + +void Buf_Init(CBuf *p) +{ + p->data = 0; + p->size = 0; +} + +int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc) +{ + p->size = 0; + if (size == 0) + { + p->data = 0; + return 1; + } + p->data = (Byte *)alloc->Alloc(alloc, size); + if (p->data != 0) + { + p->size = size; + return 1; + } + return 0; +} + +void Buf_Free(CBuf *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->data); + p->data = 0; + p->size = 0; +} diff --git a/ext/VFS/ext/7z/src/7zBuf.h b/ext/VFS/ext/7z/src/7zBuf.h new file mode 100644 index 000000000..88ff0c2f2 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zBuf.h @@ -0,0 +1,39 @@ +/* 7zBuf.h -- Byte Buffer +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __7Z_BUF_H +#define __7Z_BUF_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + Byte *data; + size_t size; +} CBuf; + +void Buf_Init(CBuf *p); +int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc); +void Buf_Free(CBuf *p, ISzAlloc *alloc); + +typedef struct +{ + Byte *data; + size_t size; + size_t pos; +} CDynBuf; + +void DynBuf_Construct(CDynBuf *p); +void DynBuf_SeekToBeg(CDynBuf *p); +int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc); +void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/7zBuf2.c b/ext/VFS/ext/7z/src/7zBuf2.c new file mode 100644 index 000000000..1c8b931a1 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zBuf2.c @@ -0,0 +1,45 @@ +/* 7zBuf2.c -- Byte Buffer +2008-10-04 : Igor Pavlov : Public domain */ + +#include +#include "7zBuf.h" + +void DynBuf_Construct(CDynBuf *p) +{ + p->data = 0; + p->size = 0; + p->pos = 0; +} + +void DynBuf_SeekToBeg(CDynBuf *p) +{ + p->pos = 0; +} + +int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc) +{ + if (size > p->size - p->pos) + { + size_t newSize = p->pos + size; + Byte *data; + newSize += newSize / 4; + data = (Byte *)alloc->Alloc(alloc, newSize); + if (data == 0) + return 0; + p->size = newSize; + memcpy(data, p->data, p->pos); + alloc->Free(alloc, p->data); + p->data = data; + } + memcpy(p->data + p->pos, buf, size); + p->pos += size; + return 1; +} + +void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->data); + p->data = 0; + p->size = 0; + p->pos = 0; +} diff --git a/ext/VFS/ext/7z/src/7zCrc.c b/ext/VFS/ext/7z/src/7zCrc.c new file mode 100644 index 000000000..5801dabfc --- /dev/null +++ b/ext/VFS/ext/7z/src/7zCrc.c @@ -0,0 +1,74 @@ +/* 7zCrc.c -- CRC32 calculation +2009-11-23 : Igor Pavlov : Public domain */ + +#include "7zCrc.h" +#include "CpuArch.h" + +#define kCrcPoly 0xEDB88320 + +#ifdef MY_CPU_LE +#define CRC_NUM_TABLES 8 +#else +#define CRC_NUM_TABLES 1 +#endif + +typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); + +static CRC_FUNC g_CrcUpdate; +UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; + +#if CRC_NUM_TABLES == 1 + +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +static UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +#else + +UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); +UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); + +#endif + +UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) +{ + return g_CrcUpdate(v, data, size, g_CrcTable); +} + +UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) +{ + return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; +} + +void MY_FAST_CALL CrcGenerateTable() +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt32 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); + g_CrcTable[i] = r; + } + #if CRC_NUM_TABLES == 1 + g_CrcUpdate = CrcUpdateT1; + #else + for (; i < 256 * CRC_NUM_TABLES; i++) + { + UInt32 r = g_CrcTable[i - 256]; + g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); + } + g_CrcUpdate = CrcUpdateT4; + #ifdef MY_CPU_X86_OR_AMD64 + if (!CPU_Is_InOrder()) + g_CrcUpdate = CrcUpdateT8; + #endif + #endif +} diff --git a/ext/VFS/ext/7z/src/7zCrc.h b/ext/VFS/ext/7z/src/7zCrc.h new file mode 100644 index 000000000..0af71ae33 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zCrc.h @@ -0,0 +1,25 @@ +/* 7zCrc.h -- CRC32 calculation +2009-11-21 : Igor Pavlov : Public domain */ + +#ifndef __7Z_CRC_H +#define __7Z_CRC_H + +#include "Types.h" + +EXTERN_C_BEGIN + +extern UInt32 g_CrcTable[]; + +/* Call CrcGenerateTable one time before other CRC functions */ +SZIP_API void MY_FAST_CALL CrcGenerateTable(void); + +#define CRC_INIT_VAL 0xFFFFFFFF +#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) +#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size); +SZIP_API UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size); + +EXTERN_C_END + +#endif diff --git a/ext/VFS/ext/7z/src/7zCrcOpt.c b/ext/VFS/ext/7z/src/7zCrcOpt.c new file mode 100644 index 000000000..6205d7161 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zCrcOpt.c @@ -0,0 +1,34 @@ +/* 7zCrcOpt.c -- CRC32 calculation : optimized version +2009-11-23 : Igor Pavlov : Public domain */ + +#include "CpuArch.h" + +#ifdef MY_CPU_LE + +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + v ^= *(const UInt32 *)p; + v = + table[0x300 + (v & 0xFF)] ^ + table[0x200 + ((v >> 8) & 0xFF)] ^ + table[0x100 + ((v >> 16) & 0xFF)] ^ + table[0x000 + ((v >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + return CrcUpdateT4(v, data, size, table); +} + +#endif diff --git a/ext/VFS/ext/7z/src/7zDec.c b/ext/VFS/ext/7z/src/7zDec.c new file mode 100644 index 000000000..efe8a33b3 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zDec.c @@ -0,0 +1,444 @@ +/* 7zDec.c -- Decoding from 7z folder +2010-03-15 : Igor Pavlov : Public domain */ + +#include + +/* #define _7ZIP_PPMD_SUPPPORT */ + +#include "7z.h" + +#include "Bcj2.h" +#include "Bra.h" +#include "CpuArch.h" +#include "LzmaDec.h" +#include "Lzma2Dec.h" +#ifdef _7ZIP_PPMD_SUPPPORT +#include "Ppmd7.h" +#endif + +#define k_Copy 0 +#define k_LZMA2 0x21 +#define k_LZMA 0x30101 +#define k_BCJ 0x03030103 +#define k_BCJ2 0x0303011B + +#ifdef _7ZIP_PPMD_SUPPPORT + +#define k_PPMD 0x30401 + +typedef struct +{ + IByteIn p; + const Byte *cur; + const Byte *end; + const Byte *begin; + UInt64 processed; + Bool extra; + SRes res; + ILookInStream *inStream; +} CByteInToLook; + +static Byte ReadByte(void *pp) +{ + CByteInToLook *p = (CByteInToLook *)pp; + if (p->cur != p->end) + return *p->cur++; + if (p->res == SZ_OK) + { + size_t size = p->cur - p->begin; + p->processed += size; + p->res = p->inStream->Skip(p->inStream, size); + size = (1 << 25); + p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size); + p->cur = p->begin; + p->end = p->begin + size; + if (size != 0) + return *p->cur++;; + } + p->extra = True; + return 0; +} + +static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) +{ + CPpmd7 ppmd; + CByteInToLook s; + SRes res = SZ_OK; + + s.p.Read = ReadByte; + s.inStream = inStream; + s.begin = s.end = s.cur = NULL; + s.extra = False; + s.res = SZ_OK; + s.processed = 0; + + if (coder->Props.size != 5) + return SZ_ERROR_UNSUPPORTED; + + { + unsigned order = coder->Props.data[0]; + UInt32 memSize = GetUi32(coder->Props.data + 1); + if (order < PPMD7_MIN_ORDER || + order > PPMD7_MAX_ORDER || + memSize < PPMD7_MIN_MEM_SIZE || + memSize > PPMD7_MAX_MEM_SIZE) + return SZ_ERROR_UNSUPPORTED; + Ppmd7_Construct(&ppmd); + if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) + return SZ_ERROR_MEM; + Ppmd7_Init(&ppmd, order); + } + { + CPpmd7z_RangeDec rc; + Ppmd7z_RangeDec_CreateVTable(&rc); + rc.Stream = &s.p; + if (!Ppmd7z_RangeDec_Init(&rc)) + res = SZ_ERROR_DATA; + else if (s.extra) + res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); + else + { + SizeT i; + for (i = 0; i < outSize; i++) + { + int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p); + if (s.extra || sym < 0) + break; + outBuffer[i] = (Byte)sym; + } + if (i != outSize) + res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); + else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc)) + res = SZ_ERROR_DATA; + } + } + Ppmd7_Free(&ppmd, allocMain); + return res; +} + +#endif + + +static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) +{ + CLzmaDec state; + SRes res = SZ_OK; + + LzmaDec_Construct(&state); + RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain)); + state.dic = outBuffer; + state.dicBufSize = outSize; + LzmaDec_Init(&state); + + for (;;) + { + Byte *inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); + if (res != SZ_OK) + break; + + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; + ELzmaStatus status; + res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; + if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos)) + { + if (state.dicBufSize != outSize || lookahead != 0 || + (status != LZMA_STATUS_FINISHED_WITH_MARK && + status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) + res = SZ_ERROR_DATA; + break; + } + res = inStream->Skip((void *)inStream, inProcessed); + if (res != SZ_OK) + break; + } + } + + LzmaDec_FreeProbs(&state, allocMain); + return res; +} + +static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) +{ + CLzma2Dec state; + SRes res = SZ_OK; + + Lzma2Dec_Construct(&state); + if (coder->Props.size != 1) + return SZ_ERROR_DATA; + RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain)); + state.decoder.dic = outBuffer; + state.decoder.dicBufSize = outSize; + Lzma2Dec_Init(&state); + + for (;;) + { + Byte *inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); + if (res != SZ_OK) + break; + + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; + ELzmaStatus status; + res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; + if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos)) + { + if (state.decoder.dicBufSize != outSize || lookahead != 0 || + (status != LZMA_STATUS_FINISHED_WITH_MARK)) + res = SZ_ERROR_DATA; + break; + } + res = inStream->Skip((void *)inStream, inProcessed); + if (res != SZ_OK) + break; + } + } + + Lzma2Dec_FreeProbs(&state, allocMain); + return res; +} + +static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) +{ + while (inSize > 0) + { + void *inBuf; + size_t curSize = (1 << 18); + if (curSize > inSize) + curSize = (size_t)inSize; + RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize)); + if (curSize == 0) + return SZ_ERROR_INPUT_EOF; + memcpy(outBuffer, inBuf, curSize); + outBuffer += curSize; + inSize -= curSize; + RINOK(inStream->Skip((void *)inStream, curSize)); + } + return SZ_OK; +} + +static Bool IS_MAIN_METHOD(UInt32 m) +{ + switch(m) + { + case k_Copy: + case k_LZMA: + case k_LZMA2: + #ifdef _7ZIP_PPMD_SUPPPORT + case k_PPMD: + #endif + return True; + } + return False; +} + +static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c) +{ + return + c->NumInStreams == 1 && + c->NumOutStreams == 1 && + c->MethodID <= (UInt32)0xFFFFFFFF && + IS_MAIN_METHOD((UInt32)c->MethodID); +} + +#define IS_BCJ(c) ((c)->MethodID == k_BCJ && (c)->NumInStreams == 1 && (c)->NumOutStreams == 1) +#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1) + +static SRes CheckSupportedFolder(const CSzFolder *f) +{ + if (f->NumCoders < 1 || f->NumCoders > 4) + return SZ_ERROR_UNSUPPORTED; + if (!IS_SUPPORTED_CODER(&f->Coders[0])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumCoders == 1) + { + if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + if (f->NumCoders == 2) + { + if (!IS_BCJ(&f->Coders[1]) || + f->NumPackStreams != 1 || f->PackStreams[0] != 0 || + f->NumBindPairs != 1 || + f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + if (f->NumCoders == 4) + { + if (!IS_SUPPORTED_CODER(&f->Coders[1]) || + !IS_SUPPORTED_CODER(&f->Coders[2]) || + !IS_BCJ2(&f->Coders[3])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumPackStreams != 4 || + f->PackStreams[0] != 2 || + f->PackStreams[1] != 6 || + f->PackStreams[2] != 1 || + f->PackStreams[3] != 0 || + f->NumBindPairs != 3 || + f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 || + f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 || + f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + return SZ_ERROR_UNSUPPORTED; +} + +static UInt64 GetSum(const UInt64 *values, UInt32 index) +{ + UInt64 sum = 0; + UInt32 i; + for (i = 0; i < index; i++) + sum += values[i]; + return sum; +} + +static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, + ILookInStream *inStream, UInt64 startPos, + Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, + Byte *tempBuf[]) +{ + UInt32 ci; + SizeT tempSizes[3] = { 0, 0, 0}; + SizeT tempSize3 = 0; + Byte *tempBuf3 = 0; + + RINOK(CheckSupportedFolder(folder)); + + for (ci = 0; ci < folder->NumCoders; ci++) + { + CSzCoderInfo *coder = &folder->Coders[ci]; + + if (IS_MAIN_METHOD((UInt32)coder->MethodID)) + { + UInt32 si = 0; + UInt64 offset; + UInt64 inSize; + Byte *outBufCur = outBuffer; + SizeT outSizeCur = outSize; + if (folder->NumCoders == 4) + { + UInt32 indices[] = { 3, 2, 0 }; + UInt64 unpackSize = folder->UnpackSizes[ci]; + si = indices[ci]; + if (ci < 2) + { + Byte *temp; + outSizeCur = (SizeT)unpackSize; + if (outSizeCur != unpackSize) + return SZ_ERROR_MEM; + temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); + if (temp == 0 && outSizeCur != 0) + return SZ_ERROR_MEM; + outBufCur = tempBuf[1 - ci] = temp; + tempSizes[1 - ci] = outSizeCur; + } + else if (ci == 2) + { + if (unpackSize > outSize) /* check it */ + return SZ_ERROR_PARAM; + tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); + tempSize3 = outSizeCur = (SizeT)unpackSize; + } + else + return SZ_ERROR_UNSUPPORTED; + } + offset = GetSum(packSizes, si); + inSize = packSizes[si]; + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + + if (coder->MethodID == k_Copy) + { + if (inSize != outSizeCur) /* check it */ + return SZ_ERROR_DATA; + RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); + } + else if (coder->MethodID == k_LZMA) + { + RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); + } + else if (coder->MethodID == k_LZMA2) + { + RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); + } + else + { + #ifdef _7ZIP_PPMD_SUPPPORT + RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); + #else + return SZ_ERROR_UNSUPPORTED; + #endif + } + } + else if (coder->MethodID == k_BCJ) + { + UInt32 state; + if (ci != 1) + return SZ_ERROR_UNSUPPORTED; + x86_Convert_Init(state); + x86_Convert(outBuffer, outSize, 0, &state, 0); + } + else if (coder->MethodID == k_BCJ2) + { + UInt64 offset = GetSum(packSizes, 1); + UInt64 s3Size = packSizes[1]; + SRes res; + if (ci != 3) + return SZ_ERROR_UNSUPPORTED; + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + tempSizes[2] = (SizeT)s3Size; + if (tempSizes[2] != s3Size) + return SZ_ERROR_MEM; + tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); + if (tempBuf[2] == 0 && tempSizes[2] != 0) + return SZ_ERROR_MEM; + res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); + RINOK(res) + + res = Bcj2_Decode( + tempBuf3, tempSize3, + tempBuf[0], tempSizes[0], + tempBuf[1], tempSizes[1], + tempBuf[2], tempSizes[2], + outBuffer, outSize); + RINOK(res) + } + else + return SZ_ERROR_UNSUPPORTED; + } + return SZ_OK; +} + +SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes, + ILookInStream *inStream, UInt64 startPos, + Byte *outBuffer, size_t outSize, ISzAlloc *allocMain) +{ + Byte *tempBuf[3] = { 0, 0, 0}; + int i; + SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos, + outBuffer, (SizeT)outSize, allocMain, tempBuf); + for (i = 0; i < 3; i++) + IAlloc_Free(allocMain, tempBuf[i]); + return res; +} diff --git a/ext/VFS/ext/7z/src/7zFile.c b/ext/VFS/ext/7z/src/7zFile.c new file mode 100644 index 000000000..6d82c79f9 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zFile.c @@ -0,0 +1,284 @@ +/* 7zFile.c -- File IO +2009-11-24 : Igor Pavlov : Public domain */ + +#include "7zFile.h" + +#ifndef USE_WINDOWS_FILE + +#ifndef UNDER_CE +#include +#endif + +#else + +/* + ReadFile and WriteFile functions in Windows have BUG: + If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) + from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES + (Insufficient system resources exist to complete the requested service). + Probably in some version of Windows there are problems with other sizes: + for 32 MB (maybe also for 16 MB). + And message can be "Network connection was lost" +*/ + +#define kChunkSizeMax (1 << 22) + +#endif + +void File_Construct(CSzFile *p) +{ + #ifdef USE_WINDOWS_FILE + p->handle = INVALID_HANDLE_VALUE; + #else + p->file = NULL; + #endif +} + +#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) +static WRes File_Open(CSzFile *p, const char *name, int writeMode) +{ + #ifdef USE_WINDOWS_FILE + p->handle = CreateFileA(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); + #else + p->file = fopen(name, writeMode ? "wb+" : "rb"); + return (p->file != 0) ? 0 : + #ifdef UNDER_CE + 2; /* ENOENT */ + #else + errno; + #endif + #endif +} + +WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } +WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); } +#endif + +#ifdef USE_WINDOWS_FILE +static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) +{ + p->handle = CreateFileW(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); +} +WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } +WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } +#endif + +WRes File_Close(CSzFile *p) +{ + #ifdef USE_WINDOWS_FILE + if (p->handle != INVALID_HANDLE_VALUE) + { + if (!CloseHandle(p->handle)) + return GetLastError(); + p->handle = INVALID_HANDLE_VALUE; + } + #else + if (p->file != NULL) + { + int res = fclose(p->file); + if (res != 0) + return res; + p->file = NULL; + } + #endif + return 0; +} + +WRes File_Read(CSzFile *p, void *data, size_t *size) +{ + size_t originalSize = *size; + if (originalSize == 0) + return 0; + + #ifdef USE_WINDOWS_FILE + + *size = 0; + do + { + DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); + data = (void *)((Byte *)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + if (processed == 0) + break; + } + while (originalSize > 0); + return 0; + + #else + + *size = fread(data, 1, originalSize, p->file); + if (*size == originalSize) + return 0; + return ferror(p->file); + + #endif +} + +WRes File_Write(CSzFile *p, const void *data, size_t *size) +{ + size_t originalSize = *size; + if (originalSize == 0) + return 0; + + #ifdef USE_WINDOWS_FILE + + *size = 0; + do + { + DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); + data = (void *)((Byte *)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + if (processed == 0) + break; + } + while (originalSize > 0); + return 0; + + #else + + *size = fwrite(data, 1, originalSize, p->file); + if (*size == originalSize) + return 0; + return ferror(p->file); + + #endif +} + +WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) +{ + #ifdef USE_WINDOWS_FILE + + LARGE_INTEGER value; + DWORD moveMethod; + value.LowPart = (DWORD)*pos; + value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ + switch (origin) + { + case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; + case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; + case SZ_SEEK_END: moveMethod = FILE_END; break; + default: return ERROR_INVALID_PARAMETER; + } + value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); + if (value.LowPart == 0xFFFFFFFF) + { + WRes res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *pos = ((Int64)value.HighPart << 32) | value.LowPart; + return 0; + + #else + + int moveMethod; + int res; + switch (origin) + { + case SZ_SEEK_SET: moveMethod = SEEK_SET; break; + case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; + case SZ_SEEK_END: moveMethod = SEEK_END; break; + default: return 1; + } + res = fseek(p->file, (long)*pos, moveMethod); + *pos = ftell(p->file); + return res; + + #endif +} + +WRes File_GetLength(CSzFile *p, UInt64 *length) +{ + #ifdef USE_WINDOWS_FILE + + DWORD sizeHigh; + DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); + if (sizeLow == 0xFFFFFFFF) + { + DWORD res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *length = (((UInt64)sizeHigh) << 32) + sizeLow; + return 0; + + #else + + long pos = ftell(p->file); + int res = fseek(p->file, 0, SEEK_END); + *length = ftell(p->file); + fseek(p->file, pos, SEEK_SET); + return res; + + #endif +} + + +/* ---------- FileSeqInStream ---------- */ + +static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size) +{ + CFileSeqInStream *p = (CFileSeqInStream *)pp; + return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ; +} + +void FileSeqInStream_CreateVTable(CFileSeqInStream *p) +{ + p->s.Read = FileSeqInStream_Read; +} + + +/* ---------- FileInStream ---------- */ + +static SRes FileInStream_Read(void *pp, void *buf, size_t *size) +{ + CFileInStream *p = (CFileInStream *)pp; + return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; +} + +static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin) +{ + CFileInStream *p = (CFileInStream *)pp; + return File_Seek(&p->file, pos, origin); +} + +void FileInStream_CreateVTable(CFileInStream *p) +{ + p->s.Read = FileInStream_Read; + p->s.Seek = FileInStream_Seek; +} + + +/* ---------- FileOutStream ---------- */ + +static size_t FileOutStream_Write(void *pp, const void *data, size_t size) +{ + CFileOutStream *p = (CFileOutStream *)pp; + File_Write(&p->file, data, &size); + return size; +} + +void FileOutStream_CreateVTable(CFileOutStream *p) +{ + p->s.Write = FileOutStream_Write; +} diff --git a/ext/VFS/ext/7z/src/7zFile.h b/ext/VFS/ext/7z/src/7zFile.h new file mode 100644 index 000000000..5d857879e --- /dev/null +++ b/ext/VFS/ext/7z/src/7zFile.h @@ -0,0 +1,83 @@ +/* 7zFile.h -- File IO +2009-11-24 : Igor Pavlov : Public domain */ + +#ifndef __7Z_FILE_H +#define __7Z_FILE_H + +#ifdef _WIN32 +#define USE_WINDOWS_FILE +#endif + +#ifdef USE_WINDOWS_FILE +#include +#else +#include +#endif + +#include "Types.h" + +EXTERN_C_BEGIN + +/* ---------- File ---------- */ + +typedef struct +{ + #ifdef USE_WINDOWS_FILE + HANDLE handle; + #else + FILE *file; + #endif +} CSzFile; + +void File_Construct(CSzFile *p); +#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) +WRes InFile_Open(CSzFile *p, const char *name); +WRes OutFile_Open(CSzFile *p, const char *name); +#endif +#ifdef USE_WINDOWS_FILE +WRes InFile_OpenW(CSzFile *p, const WCHAR *name); +WRes OutFile_OpenW(CSzFile *p, const WCHAR *name); +#endif +WRes File_Close(CSzFile *p); + +/* reads max(*size, remain file's size) bytes */ +WRes File_Read(CSzFile *p, void *data, size_t *size); + +/* writes *size bytes */ +WRes File_Write(CSzFile *p, const void *data, size_t *size); + +WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin); +WRes File_GetLength(CSzFile *p, UInt64 *length); + + +/* ---------- FileInStream ---------- */ + +typedef struct +{ + ISeqInStream s; + CSzFile file; +} CFileSeqInStream; + +void FileSeqInStream_CreateVTable(CFileSeqInStream *p); + + +typedef struct +{ + ISeekInStream s; + CSzFile file; +} CFileInStream; + +void FileInStream_CreateVTable(CFileInStream *p); + + +typedef struct +{ + ISeqOutStream s; + CSzFile file; +} CFileOutStream; + +void FileOutStream_CreateVTable(CFileOutStream *p); + +EXTERN_C_END + +#endif diff --git a/ext/VFS/ext/7z/src/7zIn.c b/ext/VFS/ext/7z/src/7zIn.c new file mode 100644 index 000000000..a0c83ee49 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zIn.c @@ -0,0 +1,1398 @@ +/* 7zIn.c -- 7z Input functions +2010-03-11 : Igor Pavlov : Public domain */ + +#include + +#include "7z.h" +#include "7zCrc.h" +#include "CpuArch.h" + +Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; + +#define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; } + +#define NUM_FOLDER_CODERS_MAX 32 +#define NUM_CODER_STREAMS_MAX 32 + +void SzCoderInfo_Init(CSzCoderInfo *p) +{ + Buf_Init(&p->Props); +} + +void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc) +{ + Buf_Free(&p->Props, alloc); + SzCoderInfo_Init(p); +} + +void SzFolder_Init(CSzFolder *p) +{ + p->Coders = 0; + p->BindPairs = 0; + p->PackStreams = 0; + p->UnpackSizes = 0; + p->NumCoders = 0; + p->NumBindPairs = 0; + p->NumPackStreams = 0; + p->UnpackCRCDefined = 0; + p->UnpackCRC = 0; + p->NumUnpackStreams = 0; +} + +void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc) +{ + UInt32 i; + if (p->Coders) + for (i = 0; i < p->NumCoders; i++) + SzCoderInfo_Free(&p->Coders[i], alloc); + IAlloc_Free(alloc, p->Coders); + IAlloc_Free(alloc, p->BindPairs); + IAlloc_Free(alloc, p->PackStreams); + IAlloc_Free(alloc, p->UnpackSizes); + SzFolder_Init(p); +} + +UInt32 SzFolder_GetNumOutStreams(CSzFolder *p) +{ + UInt32 result = 0; + UInt32 i; + for (i = 0; i < p->NumCoders; i++) + result += p->Coders[i].NumOutStreams; + return result; +} + +int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex) +{ + UInt32 i; + for (i = 0; i < p->NumBindPairs; i++) + if (p->BindPairs[i].InIndex == inStreamIndex) + return i; + return -1; +} + + +int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex) +{ + UInt32 i; + for (i = 0; i < p->NumBindPairs; i++) + if (p->BindPairs[i].OutIndex == outStreamIndex) + return i; + return -1; +} + +UInt64 SzFolder_GetUnpackSize(CSzFolder *p) +{ + int i = (int)SzFolder_GetNumOutStreams(p); + if (i == 0) + return 0; + for (i--; i >= 0; i--) + if (SzFolder_FindBindPairForOutStream(p, i) < 0) + return p->UnpackSizes[i]; + /* throw 1; */ + return 0; +} + +void SzFile_Init(CSzFileItem *p) +{ + p->HasStream = 1; + p->IsDir = 0; + p->IsAnti = 0; + p->CrcDefined = 0; + p->MTimeDefined = 0; +} + +void SzAr_Init(CSzAr *p) +{ + p->PackSizes = 0; + p->PackCRCsDefined = 0; + p->PackCRCs = 0; + p->Folders = 0; + p->Files = 0; + p->NumPackStreams = 0; + p->NumFolders = 0; + p->NumFiles = 0; +} + +void SzAr_Free(CSzAr *p, ISzAlloc *alloc) +{ + UInt32 i; + if (p->Folders) + for (i = 0; i < p->NumFolders; i++) + SzFolder_Free(&p->Folders[i], alloc); + + IAlloc_Free(alloc, p->PackSizes); + IAlloc_Free(alloc, p->PackCRCsDefined); + IAlloc_Free(alloc, p->PackCRCs); + IAlloc_Free(alloc, p->Folders); + IAlloc_Free(alloc, p->Files); + SzAr_Init(p); +} + + +void SzArEx_Init(CSzArEx *p) +{ + SzAr_Init(&p->db); + p->FolderStartPackStreamIndex = 0; + p->PackStreamStartPositions = 0; + p->FolderStartFileIndex = 0; + p->FileIndexToFolderIndexMap = 0; + p->FileNameOffsets = 0; + Buf_Init(&p->FileNames); +} + +void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc) +{ + IAlloc_Free(alloc, p->FolderStartPackStreamIndex); + IAlloc_Free(alloc, p->PackStreamStartPositions); + IAlloc_Free(alloc, p->FolderStartFileIndex); + IAlloc_Free(alloc, p->FileIndexToFolderIndexMap); + + IAlloc_Free(alloc, p->FileNameOffsets); + Buf_Free(&p->FileNames, alloc); + + SzAr_Free(&p->db, alloc); + SzArEx_Init(p); +} + +/* +UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const +{ + return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex]; +} + +UInt64 GetFilePackSize(int fileIndex) const +{ + int folderIndex = FileIndexToFolderIndexMap[fileIndex]; + if (folderIndex >= 0) + { + const CSzFolder &folderInfo = Folders[folderIndex]; + if (FolderStartFileIndex[folderIndex] == fileIndex) + return GetFolderFullPackSize(folderIndex); + } + return 0; +} +*/ + +#define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \ + if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; } + +static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc) +{ + UInt32 startPos = 0; + UInt64 startPosSize = 0; + UInt32 i; + UInt32 folderIndex = 0; + UInt32 indexInFolder = 0; + MY_ALLOC(UInt32, p->FolderStartPackStreamIndex, p->db.NumFolders, alloc); + for (i = 0; i < p->db.NumFolders; i++) + { + p->FolderStartPackStreamIndex[i] = startPos; + startPos += p->db.Folders[i].NumPackStreams; + } + + MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc); + + for (i = 0; i < p->db.NumPackStreams; i++) + { + p->PackStreamStartPositions[i] = startPosSize; + startPosSize += p->db.PackSizes[i]; + } + + MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc); + MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc); + + for (i = 0; i < p->db.NumFiles; i++) + { + CSzFileItem *file = p->db.Files + i; + int emptyStream = !file->HasStream; + if (emptyStream && indexInFolder == 0) + { + p->FileIndexToFolderIndexMap[i] = (UInt32)-1; + continue; + } + if (indexInFolder == 0) + { + /* + v3.13 incorrectly worked with empty folders + v4.07: Loop for skipping empty folders + */ + for (;;) + { + if (folderIndex >= p->db.NumFolders) + return SZ_ERROR_ARCHIVE; + p->FolderStartFileIndex[folderIndex] = i; + if (p->db.Folders[folderIndex].NumUnpackStreams != 0) + break; + folderIndex++; + } + } + p->FileIndexToFolderIndexMap[i] = folderIndex; + if (emptyStream) + continue; + indexInFolder++; + if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams) + { + folderIndex++; + indexInFolder = 0; + } + } + return SZ_OK; +} + + +UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder) +{ + return p->dataPos + + p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder]; +} + +int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize) +{ + UInt32 packStreamIndex = p->FolderStartPackStreamIndex[folderIndex]; + CSzFolder *folder = p->db.Folders + folderIndex; + UInt64 size = 0; + UInt32 i; + for (i = 0; i < folder->NumPackStreams; i++) + { + UInt64 t = size + p->db.PackSizes[packStreamIndex + i]; + if (t < size) /* check it */ + return SZ_ERROR_FAIL; + size = t; + } + *resSize = size; + return SZ_OK; +} + + +/* +SRes SzReadTime(const CObjectVector &dataVector, + CObjectVector &files, UInt64 type) +{ + CBoolVector boolVector; + RINOK(ReadBoolVector2(files.Size(), boolVector)) + + CStreamSwitch streamSwitch; + RINOK(streamSwitch.Set(this, &dataVector)); + + for (int i = 0; i < files.Size(); i++) + { + CSzFileItem &file = files[i]; + CArchiveFileTime fileTime; + bool defined = boolVector[i]; + if (defined) + { + UInt32 low, high; + RINOK(SzReadUInt32(low)); + RINOK(SzReadUInt32(high)); + fileTime.dwLowDateTime = low; + fileTime.dwHighDateTime = high; + } + switch(type) + { + case k7zIdCTime: file.IsCTimeDefined = defined; if (defined) file.CTime = fileTime; break; + case k7zIdATime: file.IsATimeDefined = defined; if (defined) file.ATime = fileTime; break; + case k7zIdMTime: file.IsMTimeDefined = defined; if (defined) file.MTime = fileTime; break; + } + } + return SZ_OK; +} +*/ + +static int TestSignatureCandidate(Byte *testBytes) +{ + size_t i; + for (i = 0; i < k7zSignatureSize; i++) + if (testBytes[i] != k7zSignature[i]) + return 0; + return 1; +} + +typedef struct _CSzState +{ + Byte *Data; + size_t Size; +}CSzData; + +static SRes SzReadByte(CSzData *sd, Byte *b) +{ + if (sd->Size == 0) + return SZ_ERROR_ARCHIVE; + sd->Size--; + *b = *sd->Data++; + return SZ_OK; +} + +static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size) +{ + size_t i; + for (i = 0; i < size; i++) + { + RINOK(SzReadByte(sd, data + i)); + } + return SZ_OK; +} + +static SRes SzReadUInt32(CSzData *sd, UInt32 *value) +{ + int i; + *value = 0; + for (i = 0; i < 4; i++) + { + Byte b; + RINOK(SzReadByte(sd, &b)); + *value |= ((UInt32)(b) << (8 * i)); + } + return SZ_OK; +} + +static SRes SzReadNumber(CSzData *sd, UInt64 *value) +{ + Byte firstByte; + Byte mask = 0x80; + int i; + RINOK(SzReadByte(sd, &firstByte)); + *value = 0; + for (i = 0; i < 8; i++) + { + Byte b; + if ((firstByte & mask) == 0) + { + UInt64 highPart = firstByte & (mask - 1); + *value += (highPart << (8 * i)); + return SZ_OK; + } + RINOK(SzReadByte(sd, &b)); + *value |= ((UInt64)b << (8 * i)); + mask >>= 1; + } + return SZ_OK; +} + +static SRes SzReadNumber32(CSzData *sd, UInt32 *value) +{ + UInt64 value64; + RINOK(SzReadNumber(sd, &value64)); + if (value64 >= 0x80000000) + return SZ_ERROR_UNSUPPORTED; + if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2))) + return SZ_ERROR_UNSUPPORTED; + *value = (UInt32)value64; + return SZ_OK; +} + +static SRes SzReadID(CSzData *sd, UInt64 *value) +{ + return SzReadNumber(sd, value); +} + +static SRes SzSkeepDataSize(CSzData *sd, UInt64 size) +{ + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + sd->Size -= (size_t)size; + sd->Data += (size_t)size; + return SZ_OK; +} + +static SRes SzSkeepData(CSzData *sd) +{ + UInt64 size; + RINOK(SzReadNumber(sd, &size)); + return SzSkeepDataSize(sd, size); +} + +static SRes SzReadArchiveProperties(CSzData *sd) +{ + for (;;) + { + UInt64 type; + RINOK(SzReadID(sd, &type)); + if (type == k7zIdEnd) + break; + SzSkeepData(sd); + } + return SZ_OK; +} + +static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute) +{ + for (;;) + { + UInt64 type; + RINOK(SzReadID(sd, &type)); + if (type == attribute) + return SZ_OK; + if (type == k7zIdEnd) + return SZ_ERROR_ARCHIVE; + RINOK(SzSkeepData(sd)); + } +} + +static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) +{ + Byte b = 0; + Byte mask = 0; + size_t i; + MY_ALLOC(Byte, *v, numItems, alloc); + for (i = 0; i < numItems; i++) + { + if (mask == 0) + { + RINOK(SzReadByte(sd, &b)); + mask = 0x80; + } + (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0); + mask >>= 1; + } + return SZ_OK; +} + +static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) +{ + Byte allAreDefined; + size_t i; + RINOK(SzReadByte(sd, &allAreDefined)); + if (allAreDefined == 0) + return SzReadBoolVector(sd, numItems, v, alloc); + MY_ALLOC(Byte, *v, numItems, alloc); + for (i = 0; i < numItems; i++) + (*v)[i] = 1; + return SZ_OK; +} + +static SRes SzReadHashDigests( + CSzData *sd, + size_t numItems, + Byte **digestsDefined, + UInt32 **digests, + ISzAlloc *alloc) +{ + size_t i; + RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, alloc)); + MY_ALLOC(UInt32, *digests, numItems, alloc); + for (i = 0; i < numItems; i++) + if ((*digestsDefined)[i]) + { + RINOK(SzReadUInt32(sd, (*digests) + i)); + } + return SZ_OK; +} + +static SRes SzReadPackInfo( + CSzData *sd, + UInt64 *dataOffset, + UInt32 *numPackStreams, + UInt64 **packSizes, + Byte **packCRCsDefined, + UInt32 **packCRCs, + ISzAlloc *alloc) +{ + UInt32 i; + RINOK(SzReadNumber(sd, dataOffset)); + RINOK(SzReadNumber32(sd, numPackStreams)); + + RINOK(SzWaitAttribute(sd, k7zIdSize)); + + MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc); + + for (i = 0; i < *numPackStreams; i++) + { + RINOK(SzReadNumber(sd, (*packSizes) + i)); + } + + for (;;) + { + UInt64 type; + RINOK(SzReadID(sd, &type)); + if (type == k7zIdEnd) + break; + if (type == k7zIdCRC) + { + RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc)); + continue; + } + RINOK(SzSkeepData(sd)); + } + if (*packCRCsDefined == 0) + { + MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, alloc); + MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, alloc); + for (i = 0; i < *numPackStreams; i++) + { + (*packCRCsDefined)[i] = 0; + (*packCRCs)[i] = 0; + } + } + return SZ_OK; +} + +static SRes SzReadSwitch(CSzData *sd) +{ + Byte external; + RINOK(SzReadByte(sd, &external)); + return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; +} + +static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc) +{ + UInt32 numCoders, numBindPairs, numPackStreams, i; + UInt32 numInStreams = 0, numOutStreams = 0; + + RINOK(SzReadNumber32(sd, &numCoders)); + if (numCoders > NUM_FOLDER_CODERS_MAX) + return SZ_ERROR_UNSUPPORTED; + folder->NumCoders = numCoders; + + MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc); + + for (i = 0; i < numCoders; i++) + SzCoderInfo_Init(folder->Coders + i); + + for (i = 0; i < numCoders; i++) + { + Byte mainByte; + CSzCoderInfo *coder = folder->Coders + i; + { + unsigned idSize, j; + Byte longID[15]; + RINOK(SzReadByte(sd, &mainByte)); + idSize = (unsigned)(mainByte & 0xF); + RINOK(SzReadBytes(sd, longID, idSize)); + if (idSize > sizeof(coder->MethodID)) + return SZ_ERROR_UNSUPPORTED; + coder->MethodID = 0; + for (j = 0; j < idSize; j++) + coder->MethodID |= (UInt64)longID[idSize - 1 - j] << (8 * j); + + if ((mainByte & 0x10) != 0) + { + RINOK(SzReadNumber32(sd, &coder->NumInStreams)); + RINOK(SzReadNumber32(sd, &coder->NumOutStreams)); + if (coder->NumInStreams > NUM_CODER_STREAMS_MAX || + coder->NumOutStreams > NUM_CODER_STREAMS_MAX) + return SZ_ERROR_UNSUPPORTED; + } + else + { + coder->NumInStreams = 1; + coder->NumOutStreams = 1; + } + if ((mainByte & 0x20) != 0) + { + UInt64 propertiesSize = 0; + RINOK(SzReadNumber(sd, &propertiesSize)); + if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc)) + return SZ_ERROR_MEM; + RINOK(SzReadBytes(sd, coder->Props.data, (size_t)propertiesSize)); + } + } + while ((mainByte & 0x80) != 0) + { + RINOK(SzReadByte(sd, &mainByte)); + RINOK(SzSkeepDataSize(sd, (mainByte & 0xF))); + if ((mainByte & 0x10) != 0) + { + UInt32 n; + RINOK(SzReadNumber32(sd, &n)); + RINOK(SzReadNumber32(sd, &n)); + } + if ((mainByte & 0x20) != 0) + { + UInt64 propertiesSize = 0; + RINOK(SzReadNumber(sd, &propertiesSize)); + RINOK(SzSkeepDataSize(sd, propertiesSize)); + } + } + numInStreams += coder->NumInStreams; + numOutStreams += coder->NumOutStreams; + } + + if (numOutStreams == 0) + return SZ_ERROR_UNSUPPORTED; + + folder->NumBindPairs = numBindPairs = numOutStreams - 1; + MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc); + + for (i = 0; i < numBindPairs; i++) + { + CSzBindPair *bp = folder->BindPairs + i; + RINOK(SzReadNumber32(sd, &bp->InIndex)); + RINOK(SzReadNumber32(sd, &bp->OutIndex)); + } + + if (numInStreams < numBindPairs) + return SZ_ERROR_UNSUPPORTED; + + folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs; + MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc); + + if (numPackStreams == 1) + { + for (i = 0; i < numInStreams ; i++) + if (SzFolder_FindBindPairForInStream(folder, i) < 0) + break; + if (i == numInStreams) + return SZ_ERROR_UNSUPPORTED; + folder->PackStreams[0] = i; + } + else + for (i = 0; i < numPackStreams; i++) + { + RINOK(SzReadNumber32(sd, folder->PackStreams + i)); + } + return SZ_OK; +} + +static SRes SzReadUnpackInfo( + CSzData *sd, + UInt32 *numFolders, + CSzFolder **folders, /* for alloc */ + ISzAlloc *alloc, + ISzAlloc *allocTemp) +{ + UInt32 i; + RINOK(SzWaitAttribute(sd, k7zIdFolder)); + RINOK(SzReadNumber32(sd, numFolders)); + { + RINOK(SzReadSwitch(sd)); + + MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc); + + for (i = 0; i < *numFolders; i++) + SzFolder_Init((*folders) + i); + + for (i = 0; i < *numFolders; i++) + { + RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc)); + } + } + + RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize)); + + for (i = 0; i < *numFolders; i++) + { + UInt32 j; + CSzFolder *folder = (*folders) + i; + UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder); + + MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc); + + for (j = 0; j < numOutStreams; j++) + { + RINOK(SzReadNumber(sd, folder->UnpackSizes + j)); + } + } + + for (;;) + { + UInt64 type; + RINOK(SzReadID(sd, &type)); + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + SRes res; + Byte *crcsDefined = 0; + UInt32 *crcs = 0; + res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp); + if (res == SZ_OK) + { + for (i = 0; i < *numFolders; i++) + { + CSzFolder *folder = (*folders) + i; + folder->UnpackCRCDefined = crcsDefined[i]; + folder->UnpackCRC = crcs[i]; + } + } + IAlloc_Free(allocTemp, crcs); + IAlloc_Free(allocTemp, crcsDefined); + RINOK(res); + continue; + } + RINOK(SzSkeepData(sd)); + } +} + +static SRes SzReadSubStreamsInfo( + CSzData *sd, + UInt32 numFolders, + CSzFolder *folders, + UInt32 *numUnpackStreams, + UInt64 **unpackSizes, + Byte **digestsDefined, + UInt32 **digests, + ISzAlloc *allocTemp) +{ + UInt64 type = 0; + UInt32 i; + UInt32 si = 0; + UInt32 numDigests = 0; + + for (i = 0; i < numFolders; i++) + folders[i].NumUnpackStreams = 1; + *numUnpackStreams = numFolders; + + for (;;) + { + RINOK(SzReadID(sd, &type)); + if (type == k7zIdNumUnpackStream) + { + *numUnpackStreams = 0; + for (i = 0; i < numFolders; i++) + { + UInt32 numStreams; + RINOK(SzReadNumber32(sd, &numStreams)); + folders[i].NumUnpackStreams = numStreams; + *numUnpackStreams += numStreams; + } + continue; + } + if (type == k7zIdCRC || type == k7zIdSize) + break; + if (type == k7zIdEnd) + break; + RINOK(SzSkeepData(sd)); + } + + if (*numUnpackStreams == 0) + { + *unpackSizes = 0; + *digestsDefined = 0; + *digests = 0; + } + else + { + *unpackSizes = (UInt64 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt64)); + RINOM(*unpackSizes); + *digestsDefined = (Byte *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(Byte)); + RINOM(*digestsDefined); + *digests = (UInt32 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt32)); + RINOM(*digests); + } + + for (i = 0; i < numFolders; i++) + { + /* + v3.13 incorrectly worked with empty folders + v4.07: we check that folder is empty + */ + UInt64 sum = 0; + UInt32 j; + UInt32 numSubstreams = folders[i].NumUnpackStreams; + if (numSubstreams == 0) + continue; + if (type == k7zIdSize) + for (j = 1; j < numSubstreams; j++) + { + UInt64 size; + RINOK(SzReadNumber(sd, &size)); + (*unpackSizes)[si++] = size; + sum += size; + } + (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum; + } + if (type == k7zIdSize) + { + RINOK(SzReadID(sd, &type)); + } + + for (i = 0; i < *numUnpackStreams; i++) + { + (*digestsDefined)[i] = 0; + (*digests)[i] = 0; + } + + + for (i = 0; i < numFolders; i++) + { + UInt32 numSubstreams = folders[i].NumUnpackStreams; + if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) + numDigests += numSubstreams; + } + + + si = 0; + for (;;) + { + if (type == k7zIdCRC) + { + int digestIndex = 0; + Byte *digestsDefined2 = 0; + UInt32 *digests2 = 0; + SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp); + if (res == SZ_OK) + { + for (i = 0; i < numFolders; i++) + { + CSzFolder *folder = folders + i; + UInt32 numSubstreams = folder->NumUnpackStreams; + if (numSubstreams == 1 && folder->UnpackCRCDefined) + { + (*digestsDefined)[si] = 1; + (*digests)[si] = folder->UnpackCRC; + si++; + } + else + { + UInt32 j; + for (j = 0; j < numSubstreams; j++, digestIndex++) + { + (*digestsDefined)[si] = digestsDefined2[digestIndex]; + (*digests)[si] = digests2[digestIndex]; + si++; + } + } + } + } + IAlloc_Free(allocTemp, digestsDefined2); + IAlloc_Free(allocTemp, digests2); + RINOK(res); + } + else if (type == k7zIdEnd) + return SZ_OK; + else + { + RINOK(SzSkeepData(sd)); + } + RINOK(SzReadID(sd, &type)); + } +} + + +static SRes SzReadStreamsInfo( + CSzData *sd, + UInt64 *dataOffset, + CSzAr *p, + UInt32 *numUnpackStreams, + UInt64 **unpackSizes, /* allocTemp */ + Byte **digestsDefined, /* allocTemp */ + UInt32 **digests, /* allocTemp */ + ISzAlloc *alloc, + ISzAlloc *allocTemp) +{ + for (;;) + { + UInt64 type; + RINOK(SzReadID(sd, &type)); + if ((UInt64)(int)type != type) + return SZ_ERROR_UNSUPPORTED; + switch((int)type) + { + case k7zIdEnd: + return SZ_OK; + case k7zIdPackInfo: + { + RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams, + &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc)); + break; + } + case k7zIdUnpackInfo: + { + RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp)); + break; + } + case k7zIdSubStreamsInfo: + { + RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders, + numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp)); + break; + } + default: + return SZ_ERROR_UNSUPPORTED; + } + } +} + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + if (dest != 0) + { + size_t i; + const Byte *src = p->FileNames.data + (p->FileNameOffsets[fileIndex] * 2); + for (i = 0; i < len; i++) + dest[i] = GetUi16(src + i * 2); + } + return len; +} + +static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes) +{ + UInt32 i; + size_t pos = 0; + for (i = 0; i < numFiles; i++) + { + sizes[i] = pos; + for (;;) + { + if (pos >= size) + return SZ_ERROR_ARCHIVE; + if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0) + break; + pos++; + } + pos++; + } + sizes[i] = pos; + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static SRes SzReadHeader2( + CSzArEx *p, /* allocMain */ + CSzData *sd, + UInt64 **unpackSizes, /* allocTemp */ + Byte **digestsDefined, /* allocTemp */ + UInt32 **digests, /* allocTemp */ + Byte **emptyStreamVector, /* allocTemp */ + Byte **emptyFileVector, /* allocTemp */ + Byte **lwtVector, /* allocTemp */ + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + UInt64 type; + UInt32 numUnpackStreams = 0; + UInt32 numFiles = 0; + CSzFileItem *files = 0; + UInt32 numEmptyStreams = 0; + UInt32 i; + + RINOK(SzReadID(sd, &type)); + + if (type == k7zIdArchiveProperties) + { + RINOK(SzReadArchiveProperties(sd)); + RINOK(SzReadID(sd, &type)); + } + + + if (type == k7zIdMainStreamsInfo) + { + RINOK(SzReadStreamsInfo(sd, + &p->dataPos, + &p->db, + &numUnpackStreams, + unpackSizes, + digestsDefined, + digests, allocMain, allocTemp)); + p->dataPos += p->startPosAfterHeader; + RINOK(SzReadID(sd, &type)); + } + + if (type == k7zIdEnd) + return SZ_OK; + if (type != k7zIdFilesInfo) + return SZ_ERROR_ARCHIVE; + + RINOK(SzReadNumber32(sd, &numFiles)); + p->db.NumFiles = numFiles; + + MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain); + + p->db.Files = files; + for (i = 0; i < numFiles; i++) + SzFile_Init(files + i); + + for (;;) + { + UInt64 type; + UInt64 size; + RINOK(SzReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(SzReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + if ((UInt64)(int)type != type) + { + RINOK(SzSkeepDataSize(sd, size)); + } + else + switch((int)type) + { + case k7zIdName: + { + size_t namesSize; + RINOK(SzReadSwitch(sd)); + namesSize = (size_t)size - 1; + if ((namesSize & 1) != 0) + return SZ_ERROR_ARCHIVE; + if (!Buf_Create(&p->FileNames, namesSize, allocMain)) + return SZ_ERROR_MEM; + MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); + memcpy(p->FileNames.data, sd->Data, namesSize); + RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets)) + RINOK(SzSkeepDataSize(sd, namesSize)); + break; + } + case k7zIdEmptyStream: + { + RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp)); + numEmptyStreams = 0; + for (i = 0; i < numFiles; i++) + if ((*emptyStreamVector)[i]) + numEmptyStreams++; + break; + } + case k7zIdEmptyFile: + { + RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp)); + break; + } + case k7zIdWinAttributes: + { + RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); + RINOK(SzReadSwitch(sd)); + for (i = 0; i < numFiles; i++) + { + CSzFileItem *f = &files[i]; + Byte defined = (*lwtVector)[i]; + f->AttribDefined = defined; + f->Attrib = 0; + if (defined) + { + RINOK(SzReadUInt32(sd, &f->Attrib)); + } + } + IAlloc_Free(allocTemp, *lwtVector); + *lwtVector = NULL; + break; + } + case k7zIdMTime: + { + RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); + RINOK(SzReadSwitch(sd)); + for (i = 0; i < numFiles; i++) + { + CSzFileItem *f = &files[i]; + Byte defined = (*lwtVector)[i]; + f->MTimeDefined = defined; + f->MTime.Low = f->MTime.High = 0; + if (defined) + { + RINOK(SzReadUInt32(sd, &f->MTime.Low)); + RINOK(SzReadUInt32(sd, &f->MTime.High)); + } + } + IAlloc_Free(allocTemp, *lwtVector); + *lwtVector = NULL; + break; + } + default: + { + RINOK(SzSkeepDataSize(sd, size)); + } + } + } + + { + UInt32 emptyFileIndex = 0; + UInt32 sizeIndex = 0; + for (i = 0; i < numFiles; i++) + { + CSzFileItem *file = files + i; + file->IsAnti = 0; + if (*emptyStreamVector == 0) + file->HasStream = 1; + else + file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1); + if (file->HasStream) + { + file->IsDir = 0; + file->Size = (*unpackSizes)[sizeIndex]; + file->Crc = (*digests)[sizeIndex]; + file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex]; + sizeIndex++; + } + else + { + if (*emptyFileVector == 0) + file->IsDir = 1; + else + file->IsDir = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1); + emptyFileIndex++; + file->Size = 0; + file->Crc = 0; + file->CrcDefined = 0; + } + } + } + return SzArEx_Fill(p, allocMain); +} + +static SRes SzReadHeader( + CSzArEx *p, + CSzData *sd, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + UInt64 *unpackSizes = 0; + Byte *digestsDefined = 0; + UInt32 *digests = 0; + Byte *emptyStreamVector = 0; + Byte *emptyFileVector = 0; + Byte *lwtVector = 0; + SRes res = SzReadHeader2(p, sd, + &unpackSizes, &digestsDefined, &digests, + &emptyStreamVector, &emptyFileVector, &lwtVector, + allocMain, allocTemp); + IAlloc_Free(allocTemp, unpackSizes); + IAlloc_Free(allocTemp, digestsDefined); + IAlloc_Free(allocTemp, digests); + IAlloc_Free(allocTemp, emptyStreamVector); + IAlloc_Free(allocTemp, emptyFileVector); + IAlloc_Free(allocTemp, lwtVector); + return res; +} + +static SRes SzReadAndDecodePackedStreams2( + ILookInStream *inStream, + CSzData *sd, + CBuf *outBuffer, + UInt64 baseOffset, + CSzAr *p, + UInt64 **unpackSizes, + Byte **digestsDefined, + UInt32 **digests, + ISzAlloc *allocTemp) +{ + + UInt32 numUnpackStreams = 0; + UInt64 dataStartPos; + CSzFolder *folder; + UInt64 unpackSize; + SRes res; + + RINOK(SzReadStreamsInfo(sd, &dataStartPos, p, + &numUnpackStreams, unpackSizes, digestsDefined, digests, + allocTemp, allocTemp)); + + dataStartPos += baseOffset; + if (p->NumFolders != 1) + return SZ_ERROR_ARCHIVE; + + folder = p->Folders; + unpackSize = SzFolder_GetUnpackSize(folder); + + RINOK(LookInStream_SeekTo(inStream, dataStartPos)); + + if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp)) + return SZ_ERROR_MEM; + + res = SzFolder_Decode(folder, p->PackSizes, + inStream, dataStartPos, + outBuffer->data, (size_t)unpackSize, allocTemp); + RINOK(res); + if (folder->UnpackCRCDefined) + if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC) + return SZ_ERROR_CRC; + return SZ_OK; +} + +static SRes SzReadAndDecodePackedStreams( + ILookInStream *inStream, + CSzData *sd, + CBuf *outBuffer, + UInt64 baseOffset, + ISzAlloc *allocTemp) +{ + CSzAr p; + UInt64 *unpackSizes = 0; + Byte *digestsDefined = 0; + UInt32 *digests = 0; + SRes res; + SzAr_Init(&p); + res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset, + &p, &unpackSizes, &digestsDefined, &digests, + allocTemp); + SzAr_Free(&p, allocTemp); + IAlloc_Free(allocTemp, unpackSizes); + IAlloc_Free(allocTemp, digestsDefined); + IAlloc_Free(allocTemp, digests); + return res; +} + +static SRes SzArEx_Open2( + CSzArEx *p, + ILookInStream *inStream, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + Byte header[k7zStartHeaderSize]; + UInt64 nextHeaderOffset, nextHeaderSize; + size_t nextHeaderSizeT; + UInt32 nextHeaderCRC; + CBuf buffer; + SRes res; + + RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); + + if (!TestSignatureCandidate(header)) + return SZ_ERROR_NO_ARCHIVE; + if (header[6] != k7zMajorVersion) + return SZ_ERROR_UNSUPPORTED; + + nextHeaderOffset = GetUi64(header + 12); + nextHeaderSize = GetUi64(header + 20); + nextHeaderCRC = GetUi32(header + 28); + + p->startPosAfterHeader = k7zStartHeaderSize; + + if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) + return SZ_ERROR_CRC; + + nextHeaderSizeT = (size_t)nextHeaderSize; + if (nextHeaderSizeT != nextHeaderSize) + return SZ_ERROR_MEM; + if (nextHeaderSizeT == 0) + return SZ_OK; + if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || + nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) + return SZ_ERROR_NO_ARCHIVE; + + { + Int64 pos = 0; + RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); + if ((UInt64)pos < nextHeaderOffset || + (UInt64)pos < k7zStartHeaderSize + nextHeaderOffset || + (UInt64)pos < k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) + return SZ_ERROR_INPUT_EOF; + } + + RINOK(LookInStream_SeekTo(inStream, k7zStartHeaderSize + nextHeaderOffset)); + + if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp)) + return SZ_ERROR_MEM; + + res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT); + if (res == SZ_OK) + { + res = SZ_ERROR_ARCHIVE; + if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC) + { + CSzData sd; + UInt64 type; + sd.Data = buffer.data; + sd.Size = buffer.size; + res = SzReadID(&sd, &type); + if (res == SZ_OK) + { + if (type == k7zIdEncodedHeader) + { + CBuf outBuffer; + Buf_Init(&outBuffer); + res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp); + if (res != SZ_OK) + Buf_Free(&outBuffer, allocTemp); + else + { + Buf_Free(&buffer, allocTemp); + buffer.data = outBuffer.data; + buffer.size = outBuffer.size; + sd.Data = buffer.data; + sd.Size = buffer.size; + res = SzReadID(&sd, &type); + } + } + } + if (res == SZ_OK) + { + if (type == k7zIdHeader) + res = SzReadHeader(p, &sd, allocMain, allocTemp); + else + res = SZ_ERROR_UNSUPPORTED; + } + } + } + Buf_Free(&buffer, allocTemp); + return res; +} + +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp) +{ + SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); + if (res != SZ_OK) + SzArEx_Free(p, allocMain); + return res; +} + +SRes SzArEx_Extract( + const CSzArEx *p, + ILookInStream *inStream, + UInt32 fileIndex, + UInt32 *blockIndex, + Byte **outBuffer, + size_t *outBufferSize, + size_t *offset, + size_t *outSizeProcessed, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; + SRes res = SZ_OK; + *offset = 0; + *outSizeProcessed = 0; + if (folderIndex == (UInt32)-1) + { + IAlloc_Free(allocMain, *outBuffer); + *blockIndex = folderIndex; + *outBuffer = 0; + *outBufferSize = 0; + return SZ_OK; + } + + if (*outBuffer == 0 || *blockIndex != folderIndex) + { + CSzFolder *folder = p->db.Folders + folderIndex; + UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); + size_t unpackSize = (size_t)unpackSizeSpec; + UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); + + if (unpackSize != unpackSizeSpec) + return SZ_ERROR_MEM; + *blockIndex = folderIndex; + IAlloc_Free(allocMain, *outBuffer); + *outBuffer = 0; + + RINOK(LookInStream_SeekTo(inStream, startOffset)); + + if (res == SZ_OK) + { + *outBufferSize = unpackSize; + if (unpackSize != 0) + { + *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize); + if (*outBuffer == 0) + res = SZ_ERROR_MEM; + } + if (res == SZ_OK) + { + res = SzFolder_Decode(folder, + p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex], + inStream, startOffset, + *outBuffer, unpackSize, allocTemp); + if (res == SZ_OK) + { + if (folder->UnpackCRCDefined) + { + if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC) + res = SZ_ERROR_CRC; + } + } + } + } + } + if (res == SZ_OK) + { + UInt32 i; + CSzFileItem *fileItem = p->db.Files + fileIndex; + *offset = 0; + for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) + *offset += (UInt32)p->db.Files[i].Size; + *outSizeProcessed = (size_t)fileItem->Size; + if (*offset + *outSizeProcessed > *outBufferSize) + return SZ_ERROR_FAIL; + if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc) + res = SZ_ERROR_CRC; + } + return res; +} diff --git a/ext/VFS/ext/7z/src/7zStream.c b/ext/VFS/ext/7z/src/7zStream.c new file mode 100644 index 000000000..f0959fb07 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zStream.c @@ -0,0 +1,169 @@ +/* 7zStream.c -- 7z Stream functions +2010-03-11 : Igor Pavlov : Public domain */ + +#include + +#include "Types.h" + +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType) +{ + while (size != 0) + { + size_t processed = size; + RINOK(stream->Read(stream, buf, &processed)); + if (processed == 0) + return errorType; + buf = (void *)((Byte *)buf + processed); + size -= processed; + } + return SZ_OK; +} + +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size) +{ + return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); +} + +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf) +{ + size_t processed = 1; + RINOK(stream->Read(stream, buf, &processed)); + return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; +} + +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset) +{ + Int64 t = offset; + return stream->Seek(stream, &t, SZ_SEEK_SET); +} + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size) +{ + const void *lookBuf; + if (*size == 0) + return SZ_OK; + RINOK(stream->Look(stream, &lookBuf, size)); + memcpy(buf, lookBuf, *size); + return stream->Skip(stream, *size); +} + +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType) +{ + while (size != 0) + { + size_t processed = size; + RINOK(stream->Read(stream, buf, &processed)); + if (processed == 0) + return errorType; + buf = (void *)((Byte *)buf + processed); + size -= processed; + } + return SZ_OK; +} + +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size) +{ + return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); +} + +static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size) +{ + SRes res = SZ_OK; + CLookToRead *p = (CLookToRead *)pp; + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size > 0) + { + p->pos = 0; + size2 = LookToRead_BUF_SIZE; + res = p->realStream->Read(p->realStream, p->buf, &size2); + p->size = size2; + } + if (size2 < *size) + *size = size2; + *buf = p->buf + p->pos; + return res; +} + +static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size) +{ + SRes res = SZ_OK; + CLookToRead *p = (CLookToRead *)pp; + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size > 0) + { + p->pos = 0; + if (*size > LookToRead_BUF_SIZE) + *size = LookToRead_BUF_SIZE; + res = p->realStream->Read(p->realStream, p->buf, size); + size2 = p->size = *size; + } + if (size2 < *size) + *size = size2; + *buf = p->buf + p->pos; + return res; +} + +static SRes LookToRead_Skip(void *pp, size_t offset) +{ + CLookToRead *p = (CLookToRead *)pp; + p->pos += offset; + return SZ_OK; +} + +static SRes LookToRead_Read(void *pp, void *buf, size_t *size) +{ + CLookToRead *p = (CLookToRead *)pp; + size_t rem = p->size - p->pos; + if (rem == 0) + return p->realStream->Read(p->realStream, buf, size); + if (rem > *size) + rem = *size; + memcpy(buf, p->buf + p->pos, rem); + p->pos += rem; + *size = rem; + return SZ_OK; +} + +static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin) +{ + CLookToRead *p = (CLookToRead *)pp; + p->pos = p->size = 0; + return p->realStream->Seek(p->realStream, pos, origin); +} + +void LookToRead_CreateVTable(CLookToRead *p, int lookahead) +{ + p->s.Look = lookahead ? + LookToRead_Look_Lookahead : + LookToRead_Look_Exact; + p->s.Skip = LookToRead_Skip; + p->s.Read = LookToRead_Read; + p->s.Seek = LookToRead_Seek; +} + +void LookToRead_Init(CLookToRead *p) +{ + p->pos = p->size = 0; +} + +static SRes SecToLook_Read(void *pp, void *buf, size_t *size) +{ + CSecToLook *p = (CSecToLook *)pp; + return LookInStream_LookRead(p->realStream, buf, size); +} + +void SecToLook_CreateVTable(CSecToLook *p) +{ + p->s.Read = SecToLook_Read; +} + +static SRes SecToRead_Read(void *pp, void *buf, size_t *size) +{ + CSecToRead *p = (CSecToRead *)pp; + return p->realStream->Read(p->realStream, buf, size); +} + +void SecToRead_CreateVTable(CSecToRead *p) +{ + p->s.Read = SecToRead_Read; +} diff --git a/ext/VFS/ext/7z/src/7zVersion.h b/ext/VFS/ext/7z/src/7zVersion.h new file mode 100644 index 000000000..e489bb442 --- /dev/null +++ b/ext/VFS/ext/7z/src/7zVersion.h @@ -0,0 +1,7 @@ +#define MY_VER_MAJOR 9 +#define MY_VER_MINOR 12 +#define MY_VER_BUILD 0 +#define MY_VERSION "9.12 beta" +#define MY_DATE "2010-03-24" +#define MY_COPYRIGHT ": Igor Pavlov : Public domain" +#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE diff --git a/ext/VFS/ext/7z/src/Alloc.c b/ext/VFS/ext/7z/src/Alloc.c new file mode 100644 index 000000000..bb24a772b --- /dev/null +++ b/ext/VFS/ext/7z/src/Alloc.c @@ -0,0 +1,127 @@ +/* Alloc.c -- Memory allocation functions +2008-09-24 +Igor Pavlov +Public domain */ + +#ifdef _WIN32 +#include +#endif +#include + +#include "Alloc.h" + +/* #define _SZ_ALLOC_DEBUG */ + +/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ +#ifdef _SZ_ALLOC_DEBUG +#include +int g_allocCount = 0; +int g_allocCountMid = 0; +int g_allocCountBig = 0; +#endif + +void *MyAlloc(size_t size) +{ + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + { + void *p = malloc(size); + fprintf(stderr, "\nAlloc %10d bytes, count = %10d, addr = %8X", size, g_allocCount++, (unsigned)p); + return p; + } + #else + return malloc(size); + #endif +} + +void MyFree(void *address) +{ + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + fprintf(stderr, "\nFree; count = %10d, addr = %8X", --g_allocCount, (unsigned)address); + #endif + free(address); +} + +#ifdef _WIN32 + +void *MidAlloc(size_t size) +{ + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++); + #endif + return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); +} + +void MidFree(void *address) +{ + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid); + #endif + if (address == 0) + return; + VirtualFree(address, 0, MEM_RELEASE); +} + +#ifndef MEM_LARGE_PAGES +#undef _7ZIP_LARGE_PAGES +#endif + +#ifdef _7ZIP_LARGE_PAGES +SIZE_T g_LargePageSize = 0; +typedef SIZE_T (WINAPI *GetLargePageMinimumP)(); +#endif + +void SetLargePageSize() +{ + #ifdef _7ZIP_LARGE_PAGES + SIZE_T size = 0; + GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP) + GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum"); + if (largePageMinimum == 0) + return; + size = largePageMinimum(); + if (size == 0 || (size & (size - 1)) != 0) + return; + g_LargePageSize = size; + #endif +} + + +void *BigAlloc(size_t size) +{ + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++); + #endif + + #ifdef _7ZIP_LARGE_PAGES + if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18)) + { + void *res = VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)), + MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); + if (res != 0) + return res; + } + #endif + return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); +} + +void BigFree(void *address) +{ + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig); + #endif + + if (address == 0) + return; + VirtualFree(address, 0, MEM_RELEASE); +} + +#endif diff --git a/ext/VFS/ext/7z/src/Alloc.h b/ext/VFS/ext/7z/src/Alloc.h new file mode 100644 index 000000000..6b3f03474 --- /dev/null +++ b/ext/VFS/ext/7z/src/Alloc.h @@ -0,0 +1,38 @@ +/* Alloc.h -- Memory allocation functions +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __COMMON_ALLOC_H +#define __COMMON_ALLOC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void *MyAlloc(size_t size); +void MyFree(void *address); + +#ifdef _WIN32 + +void SetLargePageSize(); + +void *MidAlloc(size_t size); +void MidFree(void *address); +void *BigAlloc(size_t size); +void BigFree(void *address); + +#else + +#define MidAlloc(size) MyAlloc(size) +#define MidFree(address) MyFree(address) +#define BigAlloc(size) MyAlloc(size) +#define BigFree(address) MyFree(address) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/Bcj2.c b/ext/VFS/ext/7z/src/Bcj2.c new file mode 100644 index 000000000..474bdd45d --- /dev/null +++ b/ext/VFS/ext/7z/src/Bcj2.c @@ -0,0 +1,132 @@ +/* Bcj2.c -- Converter for x86 code (BCJ2) +2008-10-04 : Igor Pavlov : Public domain */ + +#include "Bcj2.h" + +#ifdef _LZMA_PROB32 +#define CProb UInt32 +#else +#define CProb UInt16 +#endif + +#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80) +#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)) + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_READ_BYTE (*buffer++) +#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; } +#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \ + { int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }} + +#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; } + +#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE; +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE; + +int Bcj2_Decode( + const Byte *buf0, SizeT size0, + const Byte *buf1, SizeT size1, + const Byte *buf2, SizeT size2, + const Byte *buf3, SizeT size3, + Byte *outBuf, SizeT outSize) +{ + CProb p[256 + 2]; + SizeT inPos = 0, outPos = 0; + + const Byte *buffer, *bufferLim; + UInt32 range, code; + Byte prevByte = 0; + + unsigned int i; + for (i = 0; i < sizeof(p) / sizeof(p[0]); i++) + p[i] = kBitModelTotal >> 1; + + buffer = buf3; + bufferLim = buffer + size3; + RC_INIT2 + + if (outSize == 0) + return SZ_OK; + + for (;;) + { + Byte b; + CProb *prob; + UInt32 bound; + UInt32 ttt; + + SizeT limit = size0 - inPos; + if (outSize - outPos < limit) + limit = outSize - outPos; + while (limit != 0) + { + Byte b = buf0[inPos]; + outBuf[outPos++] = b; + if (IsJ(prevByte, b)) + break; + inPos++; + prevByte = b; + limit--; + } + + if (limit == 0 || outPos == outSize) + break; + + b = buf0[inPos++]; + + if (b == 0xE8) + prob = p + prevByte; + else if (b == 0xE9) + prob = p + 256; + else + prob = p + 257; + + IF_BIT_0(prob) + { + UPDATE_0(prob) + prevByte = b; + } + else + { + UInt32 dest; + const Byte *v; + UPDATE_1(prob) + if (b == 0xE8) + { + v = buf1; + if (size1 < 4) + return SZ_ERROR_DATA; + buf1 += 4; + size1 -= 4; + } + else + { + v = buf2; + if (size2 < 4) + return SZ_ERROR_DATA; + buf2 += 4; + size2 -= 4; + } + dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) | + ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4); + outBuf[outPos++] = (Byte)dest; + if (outPos == outSize) + break; + outBuf[outPos++] = (Byte)(dest >> 8); + if (outPos == outSize) + break; + outBuf[outPos++] = (Byte)(dest >> 16); + if (outPos == outSize) + break; + outBuf[outPos++] = prevByte = (Byte)(dest >> 24); + } + } + return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA; +} diff --git a/ext/VFS/ext/7z/src/Bcj2.h b/ext/VFS/ext/7z/src/Bcj2.h new file mode 100644 index 000000000..d9d857bc3 --- /dev/null +++ b/ext/VFS/ext/7z/src/Bcj2.h @@ -0,0 +1,38 @@ +/* Bcj2.h -- Converter for x86 code (BCJ2) +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __BCJ2_H +#define __BCJ2_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +Conditions: + outSize <= FullOutputSize, + where FullOutputSize is full size of output stream of x86_2 filter. + +If buf0 overlaps outBuf, there are two required conditions: + 1) (buf0 >= outBuf) + 2) (buf0 + size0 >= outBuf + FullOutputSize). + +Returns: + SZ_OK + SZ_ERROR_DATA - Data error +*/ + +int Bcj2_Decode( + const Byte *buf0, SizeT size0, + const Byte *buf1, SizeT size1, + const Byte *buf2, SizeT size2, + const Byte *buf3, SizeT size3, + Byte *outBuf, SizeT outSize); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/Bra.c b/ext/VFS/ext/7z/src/Bra.c new file mode 100644 index 000000000..3b75f0ccb --- /dev/null +++ b/ext/VFS/ext/7z/src/Bra.c @@ -0,0 +1,133 @@ +/* Bra.c -- Converters for RISC code +2008-10-04 : Igor Pavlov : Public domain */ + +#include "Bra.h" + +SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + SizeT i; + if (size < 4) + return 0; + size -= 4; + ip += 8; + for (i = 0; i <= size; i += 4) + { + if (data[i + 3] == 0xEB) + { + UInt32 dest; + UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]); + src <<= 2; + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + dest >>= 2; + data[i + 2] = (Byte)(dest >> 16); + data[i + 1] = (Byte)(dest >> 8); + data[i + 0] = (Byte)dest; + } + } + return i; +} + +SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + SizeT i; + if (size < 4) + return 0; + size -= 4; + ip += 4; + for (i = 0; i <= size; i += 2) + { + if ((data[i + 1] & 0xF8) == 0xF0 && + (data[i + 3] & 0xF8) == 0xF8) + { + UInt32 dest; + UInt32 src = + (((UInt32)data[i + 1] & 0x7) << 19) | + ((UInt32)data[i + 0] << 11) | + (((UInt32)data[i + 3] & 0x7) << 8) | + (data[i + 2]); + + src <<= 1; + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + dest >>= 1; + + data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7)); + data[i + 0] = (Byte)(dest >> 11); + data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7)); + data[i + 2] = (Byte)dest; + i += 2; + } + } + return i; +} + +SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + SizeT i; + if (size < 4) + return 0; + size -= 4; + for (i = 0; i <= size; i += 4) + { + if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1) + { + UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) | + ((UInt32)data[i + 1] << 16) | + ((UInt32)data[i + 2] << 8) | + ((UInt32)data[i + 3] & (~3)); + + UInt32 dest; + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3)); + data[i + 1] = (Byte)(dest >> 16); + data[i + 2] = (Byte)(dest >> 8); + data[i + 3] &= 0x3; + data[i + 3] |= dest; + } + } + return i; +} + +SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + UInt32 i; + if (size < 4) + return 0; + size -= 4; + for (i = 0; i <= size; i += 4) + { + if (data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00 || + data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0) + { + UInt32 src = + ((UInt32)data[i + 0] << 24) | + ((UInt32)data[i + 1] << 16) | + ((UInt32)data[i + 2] << 8) | + ((UInt32)data[i + 3]); + UInt32 dest; + + src <<= 2; + if (encoding) + dest = ip + i + src; + else + dest = src - (ip + i); + dest >>= 2; + + dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000; + + data[i + 0] = (Byte)(dest >> 24); + data[i + 1] = (Byte)(dest >> 16); + data[i + 2] = (Byte)(dest >> 8); + data[i + 3] = (Byte)dest; + } + } + return i; +} diff --git a/ext/VFS/ext/7z/src/Bra.h b/ext/VFS/ext/7z/src/Bra.h new file mode 100644 index 000000000..9c91e332d --- /dev/null +++ b/ext/VFS/ext/7z/src/Bra.h @@ -0,0 +1,68 @@ +/* Bra.h -- Branch converters for executables +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __BRA_H +#define __BRA_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +These functions convert relative addresses to absolute addresses +in CALL instructions to increase the compression ratio. + + In: + data - data buffer + size - size of data + ip - current virtual Instruction Pinter (IP) value + state - state variable for x86 converter + encoding - 0 (for decoding), 1 (for encoding) + + Out: + state - state variable for x86 converter + + Returns: + The number of processed bytes. If you call these functions with multiple calls, + you must start next call with first byte after block of processed bytes. + + Type Endian Alignment LookAhead + + x86 little 1 4 + ARMT little 2 2 + ARM little 4 0 + PPC big 4 0 + SPARC big 4 0 + IA64 little 16 0 + + size must be >= Alignment + LookAhead, if it's not last block. + If (size < Alignment + LookAhead), converter returns 0. + + Example: + + UInt32 ip = 0; + for () + { + ; size must be >= Alignment + LookAhead, if it's not last block + SizeT processed = Convert(data, size, ip, 1); + data += processed; + size -= processed; + ip += processed; + } +*/ + +#define x86_Convert_Init(state) { state = 0; } +SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding); +SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/Bra86.c b/ext/VFS/ext/7z/src/Bra86.c new file mode 100644 index 000000000..93566cb21 --- /dev/null +++ b/ext/VFS/ext/7z/src/Bra86.c @@ -0,0 +1,85 @@ +/* Bra86.c -- Converter for x86 code (BCJ) +2008-10-04 : Igor Pavlov : Public domain */ + +#include "Bra.h" + +#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF) + +const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0}; +const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3}; + +SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) +{ + SizeT bufferPos = 0, prevPosT; + UInt32 prevMask = *state & 0x7; + if (size < 5) + return 0; + ip += 5; + prevPosT = (SizeT)0 - 1; + + for (;;) + { + Byte *p = data + bufferPos; + Byte *limit = data + size - 4; + for (; p < limit; p++) + if ((*p & 0xFE) == 0xE8) + break; + bufferPos = (SizeT)(p - data); + if (p >= limit) + break; + prevPosT = bufferPos - prevPosT; + if (prevPosT > 3) + prevMask = 0; + else + { + prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7; + if (prevMask != 0) + { + Byte b = p[4 - kMaskToBitNumber[prevMask]]; + if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b)) + { + prevPosT = bufferPos; + prevMask = ((prevMask << 1) & 0x7) | 1; + bufferPos++; + continue; + } + } + } + prevPosT = bufferPos; + + if (Test86MSByte(p[4])) + { + UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); + UInt32 dest; + for (;;) + { + Byte b; + int index; + if (encoding) + dest = (ip + (UInt32)bufferPos) + src; + else + dest = src - (ip + (UInt32)bufferPos); + if (prevMask == 0) + break; + index = kMaskToBitNumber[prevMask] * 8; + b = (Byte)(dest >> (24 - index)); + if (!Test86MSByte(b)) + break; + src = dest ^ ((1 << (32 - index)) - 1); + } + p[4] = (Byte)(~(((dest >> 24) & 1) - 1)); + p[3] = (Byte)(dest >> 16); + p[2] = (Byte)(dest >> 8); + p[1] = (Byte)dest; + bufferPos += 5; + } + else + { + prevMask = ((prevMask << 1) & 0x7) | 1; + bufferPos++; + } + } + prevPosT = bufferPos - prevPosT; + *state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7)); + return bufferPos; +} diff --git a/ext/VFS/ext/7z/src/BraIA64.c b/ext/VFS/ext/7z/src/BraIA64.c new file mode 100644 index 000000000..f359f16a3 --- /dev/null +++ b/ext/VFS/ext/7z/src/BraIA64.c @@ -0,0 +1,67 @@ +/* BraIA64.c -- Converter for IA-64 code +2008-10-04 : Igor Pavlov : Public domain */ + +#include "Bra.h" + +static const Byte kBranchTable[32] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 6, 6, 0, 0, 7, 7, + 4, 4, 0, 0, 4, 4, 0, 0 +}; + +SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + SizeT i; + if (size < 16) + return 0; + size -= 16; + for (i = 0; i <= size; i += 16) + { + UInt32 instrTemplate = data[i] & 0x1F; + UInt32 mask = kBranchTable[instrTemplate]; + UInt32 bitPos = 5; + int slot; + for (slot = 0; slot < 3; slot++, bitPos += 41) + { + UInt32 bytePos, bitRes; + UInt64 instruction, instNorm; + int j; + if (((mask >> slot) & 1) == 0) + continue; + bytePos = (bitPos >> 3); + bitRes = bitPos & 0x7; + instruction = 0; + for (j = 0; j < 6; j++) + instruction += (UInt64)data[i + j + bytePos] << (8 * j); + + instNorm = instruction >> bitRes; + if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0) + { + UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF); + UInt32 dest; + src |= ((UInt32)(instNorm >> 36) & 1) << 20; + + src <<= 4; + + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + + dest >>= 4; + + instNorm &= ~((UInt64)(0x8FFFFF) << 13); + instNorm |= ((UInt64)(dest & 0xFFFFF) << 13); + instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20)); + + instruction &= (1 << bitRes) - 1; + instruction |= (instNorm << bitRes); + for (j = 0; j < 6; j++) + data[i + j + bytePos] = (Byte)(instruction >> (8 * j)); + } + } + } + return i; +} diff --git a/ext/VFS/ext/7z/src/CpuArch.c b/ext/VFS/ext/7z/src/CpuArch.c new file mode 100644 index 000000000..c954010c7 --- /dev/null +++ b/ext/VFS/ext/7z/src/CpuArch.c @@ -0,0 +1,182 @@ +/* CpuArch.c -- CPU specific code +2009-12-12: Igor Pavlov : Public domain */ + +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 + +#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__) +#define USE_ASM +#endif + +#if defined(USE_ASM) && !defined(MY_CPU_AMD64) +static UInt32 CheckFlag(UInt32 flag) +{ + #ifdef _MSC_VER + __asm pushfd; + __asm pop EAX; + __asm mov EDX, EAX; + __asm xor EAX, flag; + __asm push EAX; + __asm popfd; + __asm pushfd; + __asm pop EAX; + __asm xor EAX, EDX; + __asm push EDX; + __asm popfd; + __asm and flag, EAX; + #else + __asm__ __volatile__ ( + "pushf\n\t" + "pop %%EAX\n\t" + "movl %%EAX,%%EDX\n\t" + "xorl %0,%%EAX\n\t" + "push %%EAX\n\t" + "popf\n\t" + "pushf\n\t" + "pop %%EAX\n\t" + "xorl %%EDX,%%EAX\n\t" + "push %%EDX\n\t" + "popf\n\t" + "andl %%EAX, %0\n\t": + "=c" (flag) : "c" (flag)); + #endif + return flag; +} +#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; +#else +#define CHECK_CPUID_IS_SUPPORTED +#endif + +static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) +{ + #ifdef USE_ASM + + #ifdef _MSC_VER + + UInt32 a2, b2, c2, d2; + __asm xor EBX, EBX; + __asm xor ECX, ECX; + __asm xor EDX, EDX; + __asm mov EAX, function; + __asm cpuid; + __asm mov a2, EAX; + __asm mov b2, EBX; + __asm mov c2, ECX; + __asm mov d2, EDX; + + *a = a2; + *b = b2; + *c = c2; + *d = d2; + + #else + #ifdef ORIGINAL_7ZIP + __asm__ __volatile__ ( + "cpuid" + : "=a" (*a) , + "=b" (*b) , + "=c" (*c) , + "=d" (*d) + : "0" (function)) ; + #else + // + // Original code doesn't compile on linux for a shared library build + // Use proposed fix from the 7-Zip forum on SourceForge + // http://sourceforge.net/projects/sevenzip/forums/forum/45797/topic/3768042 + // + __asm__ __volatile__("pushl %%ebx \n\t" /* save %ebx */ + "cpuid \n\t" + "movl %%ebx, %1 \n\t" /* save what cpuid just put in %ebx */ + "popl %%ebx \n\t" /* restore the old %ebx */ + : "=a"(*a), "=r"(*b), "=c"(*c), "=d"(*d) + : "a"(function) + : "cc"); + #endif + + #endif + + #else + + int CPUInfo[4]; + __cpuid(CPUInfo, function); + *a = CPUInfo[0]; + *b = CPUInfo[1]; + *c = CPUInfo[2]; + *d = CPUInfo[3]; + + #endif +} + +Bool x86cpuid_CheckAndRead(Cx86cpuid *p) +{ + CHECK_CPUID_IS_SUPPORTED + MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); + MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); + return True; +} + +static UInt32 kVendors[][3] = +{ + { 0x756E6547, 0x49656E69, 0x6C65746E}, + { 0x68747541, 0x69746E65, 0x444D4163}, + { 0x746E6543, 0x48727561, 0x736C7561} +}; + +int x86cpuid_GetFirm(const Cx86cpuid *p) +{ + unsigned i; + for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) + { + const UInt32 *v = kVendors[i]; + if (v[0] == p->vendor[0] && + v[1] == p->vendor[1] && + v[2] == p->vendor[2]) + return (int)i; + } + return -1; +} + +Bool CPU_Is_InOrder() +{ + Cx86cpuid p; + int firm; + UInt32 family, model; + if (!x86cpuid_CheckAndRead(&p)) + return True; + family = x86cpuid_GetFamily(&p); + model = x86cpuid_GetModel(&p); + firm = x86cpuid_GetFirm(&p); + switch (firm) + { + case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C)); + case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); + case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); + } + return True; +} + +#if !defined(MY_CPU_AMD64) && defined(_WIN32) +static Bool CPU_Sys_Is_SSE_Supported() +{ + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (!GetVersionEx(&vi)) + return False; + return (vi.dwMajorVersion >= 5); +} +#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; +#else +#define CHECK_SYS_SSE_SUPPORT +#endif + +Bool CPU_Is_Aes_Supported() +{ + Cx86cpuid p; + CHECK_SYS_SSE_SUPPORT + if (!x86cpuid_CheckAndRead(&p)) + return False; + return (p.c >> 25) & 1; +} + +#endif diff --git a/ext/VFS/ext/7z/src/CpuArch.h b/ext/VFS/ext/7z/src/CpuArch.h new file mode 100644 index 000000000..00e3693cf --- /dev/null +++ b/ext/VFS/ext/7z/src/CpuArch.h @@ -0,0 +1,138 @@ +/* CpuArch.h -- CPU specific code +2010-03-11: Igor Pavlov : Public domain */ + +#ifndef __CPU_ARCH_H +#define __CPU_ARCH_H + +#include "Types.h" + +EXTERN_C_BEGIN + +/* +MY_CPU_LE means that CPU is LITTLE ENDIAN. +If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN). + +MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. +If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform. +*/ + +#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) +#define MY_CPU_AMD64 +#endif + +#if defined(MY_CPU_AMD64) || defined(_M_IA64) +#define MY_CPU_64BIT +#endif + +#if defined(_M_IX86) || defined(__i386__) +#define MY_CPU_X86 +#endif + +#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) +#define MY_CPU_X86_OR_AMD64 +#endif + +#if defined(MY_CPU_X86) || defined(_M_ARM) +#define MY_CPU_32BIT +#endif + +#if defined(_WIN32) && defined(_M_ARM) +#define MY_CPU_ARM_LE +#endif + +#if defined(MY_CPU_X86_OR_AMD64) +#define MY_CPU_LE_UNALIGN +#endif + +#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) +#define MY_CPU_LE +#endif + +#ifdef MY_CPU_LE_UNALIGN + +#define GetUi16(p) (*(const UInt16 *)(p)) +#define GetUi32(p) (*(const UInt32 *)(p)) +#define GetUi64(p) (*(const UInt64 *)(p)) +#define SetUi16(p, d) *(UInt16 *)(p) = (d); +#define SetUi32(p, d) *(UInt32 *)(p) = (d); + +#else + +#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) + +#define GetUi32(p) ( \ + ((const Byte *)(p))[0] | \ + ((UInt32)((const Byte *)(p))[1] << 8) | \ + ((UInt32)((const Byte *)(p))[2] << 16) | \ + ((UInt32)((const Byte *)(p))[3] << 24)) + +#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) + +#define SetUi16(p, d) { UInt32 _x_ = (d); \ + ((Byte *)(p))[0] = (Byte)_x_; \ + ((Byte *)(p))[1] = (Byte)(_x_ >> 8); } + +#define SetUi32(p, d) { UInt32 _x_ = (d); \ + ((Byte *)(p))[0] = (Byte)_x_; \ + ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \ + ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ + ((Byte *)(p))[3] = (Byte)(_x_ >> 24); } + +#endif + +#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) + +#pragma intrinsic(_byteswap_ulong) +#pragma intrinsic(_byteswap_uint64) +#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) +#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) + +#else + +#define GetBe32(p) ( \ + ((UInt32)((const Byte *)(p))[0] << 24) | \ + ((UInt32)((const Byte *)(p))[1] << 16) | \ + ((UInt32)((const Byte *)(p))[2] << 8) | \ + ((const Byte *)(p))[3] ) + +#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) + +#endif + +#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1]) + + +#ifdef MY_CPU_X86_OR_AMD64 + +typedef struct +{ + UInt32 maxFunc; + UInt32 vendor[3]; + UInt32 ver; + UInt32 b; + UInt32 c; + UInt32 d; +} Cx86cpuid; + +enum +{ + CPU_FIRM_INTEL, + CPU_FIRM_AMD, + CPU_FIRM_VIA +}; + +Bool x86cpuid_CheckAndRead(Cx86cpuid *p); +int x86cpuid_GetFirm(const Cx86cpuid *p); + +#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F) +#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F) +#define x86cpuid_GetStepping(p) ((p)->ver & 0xF) + +Bool CPU_Is_InOrder(); +Bool CPU_Is_Aes_Supported(); + +#endif + +EXTERN_C_END + +#endif diff --git a/ext/VFS/ext/7z/src/Delta.c b/ext/VFS/ext/7z/src/Delta.c new file mode 100644 index 000000000..93c93a148 --- /dev/null +++ b/ext/VFS/ext/7z/src/Delta.c @@ -0,0 +1,62 @@ +/* Delta.c -- Delta converter +2009-05-26 : Igor Pavlov : Public domain */ + +#include "Delta.h" + +void Delta_Init(Byte *state) +{ + unsigned i; + for (i = 0; i < DELTA_STATE_SIZE; i++) + state[i] = 0; +} + +static void MyMemCpy(Byte *dest, const Byte *src, unsigned size) +{ + unsigned i; + for (i = 0; i < size; i++) + dest[i] = src[i]; +} + +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + Byte b = data[i]; + data[i] = (Byte)(b - buf[j]); + buf[j] = b; + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); +} + +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + buf[j] = data[i] = (Byte)(buf[j] + data[i]); + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); +} diff --git a/ext/VFS/ext/7z/src/Delta.h b/ext/VFS/ext/7z/src/Delta.h new file mode 100644 index 000000000..776cd4551 --- /dev/null +++ b/ext/VFS/ext/7z/src/Delta.h @@ -0,0 +1,23 @@ +/* Delta.h -- Delta converter +2009-04-15 : Igor Pavlov : Public domain */ + +#ifndef __DELTA_H +#define __DELTA_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DELTA_STATE_SIZE 256 + +void Delta_Init(Byte *state); +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/LzFind.c b/ext/VFS/ext/7z/src/LzFind.c new file mode 100644 index 000000000..f6c9e66d5 --- /dev/null +++ b/ext/VFS/ext/7z/src/LzFind.c @@ -0,0 +1,761 @@ +/* LzFind.c -- Match finder for LZ algorithms +2009-04-22 : Igor Pavlov : Public domain */ + +#include + +#include "LzFind.h" +#include "LzHash.h" + +#define kEmptyHashValue 0 +#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) +#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ +#define kNormalizeMask (~(kNormalizeStepMin - 1)) +#define kMaxHistorySize ((UInt32)3 << 30) + +#define kStartMaxLen 3 + +static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) +{ + if (!p->directInput) + { + alloc->Free(alloc, p->bufferBase); + p->bufferBase = 0; + } +} + +/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ + +static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) +{ + UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; + if (p->directInput) + { + p->blockSize = blockSize; + return 1; + } + if (p->bufferBase == 0 || p->blockSize != blockSize) + { + LzInWindow_Free(p, alloc); + p->blockSize = blockSize; + p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); + } + return (p->bufferBase != 0); +} + +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } +Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } + +UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } + +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) +{ + p->posLimit -= subValue; + p->pos -= subValue; + p->streamPos -= subValue; +} + +static void MatchFinder_ReadBlock(CMatchFinder *p) +{ + if (p->streamEndWasReached || p->result != SZ_OK) + return; + if (p->directInput) + { + UInt32 curSize = 0xFFFFFFFF - p->streamPos; + if (curSize > p->directInputRem) + curSize = (UInt32)p->directInputRem; + p->directInputRem -= curSize; + p->streamPos += curSize; + if (p->directInputRem == 0) + p->streamEndWasReached = 1; + return; + } + for (;;) + { + Byte *dest = p->buffer + (p->streamPos - p->pos); + size_t size = (p->bufferBase + p->blockSize - dest); + if (size == 0) + return; + p->result = p->stream->Read(p->stream, dest, &size); + if (p->result != SZ_OK) + return; + if (size == 0) + { + p->streamEndWasReached = 1; + return; + } + p->streamPos += (UInt32)size; + if (p->streamPos - p->pos > p->keepSizeAfter) + return; + } +} + +void MatchFinder_MoveBlock(CMatchFinder *p) +{ + memmove(p->bufferBase, + p->buffer - p->keepSizeBefore, + (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); + p->buffer = p->bufferBase + p->keepSizeBefore; +} + +int MatchFinder_NeedMove(CMatchFinder *p) +{ + if (p->directInput) + return 0; + /* if (p->streamEndWasReached) return 0; */ + return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); +} + +void MatchFinder_ReadIfRequired(CMatchFinder *p) +{ + if (p->streamEndWasReached) + return; + if (p->keepSizeAfter >= p->streamPos - p->pos) + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) +{ + if (MatchFinder_NeedMove(p)) + MatchFinder_MoveBlock(p); + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_SetDefaultSettings(CMatchFinder *p) +{ + p->cutValue = 32; + p->btMode = 1; + p->numHashBytes = 4; + p->bigHash = 0; +} + +#define kCrcPoly 0xEDB88320 + +void MatchFinder_Construct(CMatchFinder *p) +{ + UInt32 i; + p->bufferBase = 0; + p->directInput = 0; + p->hash = 0; + MatchFinder_SetDefaultSettings(p); + + for (i = 0; i < 256; i++) + { + UInt32 r = i; + int j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); + p->crc[i] = r; + } +} + +static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->hash); + p->hash = 0; +} + +void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) +{ + MatchFinder_FreeThisClassMemory(p, alloc); + LzInWindow_Free(p, alloc); +} + +static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) +{ + size_t sizeInBytes = (size_t)num * sizeof(CLzRef); + if (sizeInBytes / sizeof(CLzRef) != num) + return 0; + return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); +} + +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc) +{ + UInt32 sizeReserv; + if (historySize > kMaxHistorySize) + { + MatchFinder_Free(p, alloc); + return 0; + } + sizeReserv = historySize >> 1; + if (historySize > ((UInt32)2 << 30)) + sizeReserv = historySize >> 2; + sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); + + p->keepSizeBefore = historySize + keepAddBufferBefore + 1; + p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; + /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ + if (LzInWindow_Create(p, sizeReserv, alloc)) + { + UInt32 newCyclicBufferSize = historySize + 1; + UInt32 hs; + p->matchMaxLen = matchMaxLen; + { + p->fixedHashSize = 0; + if (p->numHashBytes == 2) + hs = (1 << 16) - 1; + else + { + hs = historySize - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + hs |= 0xFFFF; /* don't change it! It's required for Deflate */ + if (hs > (1 << 24)) + { + if (p->numHashBytes == 3) + hs = (1 << 24) - 1; + else + hs >>= 1; + } + } + p->hashMask = hs; + hs++; + if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; + if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; + if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; + hs += p->fixedHashSize; + } + + { + UInt32 prevSize = p->hashSizeSum + p->numSons; + UInt32 newSize; + p->historySize = historySize; + p->hashSizeSum = hs; + p->cyclicBufferSize = newCyclicBufferSize; + p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); + newSize = p->hashSizeSum + p->numSons; + if (p->hash != 0 && prevSize == newSize) + return 1; + MatchFinder_FreeThisClassMemory(p, alloc); + p->hash = AllocRefs(newSize, alloc); + if (p->hash != 0) + { + p->son = p->hash + p->hashSizeSum; + return 1; + } + } + } + MatchFinder_Free(p, alloc); + return 0; +} + +static void MatchFinder_SetLimits(CMatchFinder *p) +{ + UInt32 limit = kMaxValForNormalize - p->pos; + UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; + if (limit2 < limit) + limit = limit2; + limit2 = p->streamPos - p->pos; + if (limit2 <= p->keepSizeAfter) + { + if (limit2 > 0) + limit2 = 1; + } + else + limit2 -= p->keepSizeAfter; + if (limit2 < limit) + limit = limit2; + { + UInt32 lenLimit = p->streamPos - p->pos; + if (lenLimit > p->matchMaxLen) + lenLimit = p->matchMaxLen; + p->lenLimit = lenLimit; + } + p->posLimit = p->pos + limit; +} + +void MatchFinder_Init(CMatchFinder *p) +{ + UInt32 i; + for (i = 0; i < p->hashSizeSum; i++) + p->hash[i] = kEmptyHashValue; + p->cyclicBufferPos = 0; + p->buffer = p->bufferBase; + p->pos = p->streamPos = p->cyclicBufferSize; + p->result = SZ_OK; + p->streamEndWasReached = 0; + MatchFinder_ReadBlock(p); + MatchFinder_SetLimits(p); +} + +static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) +{ + return (p->pos - p->historySize - 1) & kNormalizeMask; +} + +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) +{ + UInt32 i; + for (i = 0; i < numItems; i++) + { + UInt32 value = items[i]; + if (value <= subValue) + value = kEmptyHashValue; + else + value -= subValue; + items[i] = value; + } +} + +static void MatchFinder_Normalize(CMatchFinder *p) +{ + UInt32 subValue = MatchFinder_GetSubValue(p); + MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); + MatchFinder_ReduceOffsets(p, subValue); +} + +static void MatchFinder_CheckLimits(CMatchFinder *p) +{ + if (p->pos == kMaxValForNormalize) + MatchFinder_Normalize(p); + if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) + MatchFinder_CheckAndMoveAndRead(p); + if (p->cyclicBufferPos == p->cyclicBufferSize) + p->cyclicBufferPos = 0; + MatchFinder_SetLimits(p); +} + +static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) +{ + son[_cyclicBufferPos] = curMatch; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + return distances; + { + const Byte *pb = cur - delta; + curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; + if (pb[maxLen] == cur[maxLen] && *pb == *cur) + { + UInt32 len = 0; + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + *distances++ = maxLen = len; + *distances++ = delta - 1; + if (len == lenLimit) + return distances; + } + } + } + } +} + +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) +{ + CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + (_cyclicBufferPos << 1); + UInt32 len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return distances; + } + { + CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + UInt32 len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + *distances++ = maxLen = len; + *distances++ = delta - 1; + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + return distances; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) +{ + CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + (_cyclicBufferPos << 1); + UInt32 len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return; + } + { + CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + UInt32 len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + { + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + return; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +#define MOVE_POS \ + ++p->cyclicBufferPos; \ + p->buffer++; \ + if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + +#define MOVE_POS_RET MOVE_POS return offset; + +static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } + +#define GET_MATCHES_HEADER2(minLen, ret_op) \ + UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ + lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ + cur = p->buffer; + +#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) +#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) + +#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue + +#define GET_MATCHES_FOOTER(offset, maxLen) \ + offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ + distances + offset, maxLen) - distances); MOVE_POS_RET; + +#define SKIP_FOOTER \ + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; + +static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 1) +} + +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 2) +} + +static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, delta2, maxLen, offset; + GET_MATCHES_HEADER(3) + + HASH3_CALC; + + delta2 = p->pos - p->hash[hash2Value]; + curMatch = p->hash[kFix3HashSize + hashValue]; + + p->hash[hash2Value] = + p->hash[kFix3HashSize + hashValue] = p->pos; + + + maxLen = 2; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[0] = maxLen; + distances[1] = delta2 - 1; + offset = 2; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + GET_MATCHES_FOOTER(offset, maxLen) +} + +static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + delta2 = p->pos - p->hash[ hash2Value]; + delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; + curMatch = p->hash[kFix4HashSize + hashValue]; + + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + + maxLen = 1; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = delta2 - 1; + offset = 2; + } + if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + { + maxLen = 3; + distances[offset + 1] = delta3 - 1; + offset += 2; + delta2 = delta3; + } + if (offset != 0) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + if (maxLen < 3) + maxLen = 3; + GET_MATCHES_FOOTER(offset, maxLen) +} + +static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + delta2 = p->pos - p->hash[ hash2Value]; + delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; + curMatch = p->hash[kFix4HashSize + hashValue]; + + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + + maxLen = 1; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = delta2 - 1; + offset = 2; + } + if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + { + maxLen = 3; + distances[offset + 1] = delta3 - 1; + offset += 2; + delta2 = delta3; + } + if (offset != 0) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET; + } + } + if (maxLen < 3) + maxLen = 3; + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances + offset, maxLen) - (distances)); + MOVE_POS_RET +} + +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances, 2) - (distances)); + MOVE_POS_RET +} + +static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value; + SKIP_HEADER(3) + HASH3_CALC; + curMatch = p->hash[kFix3HashSize + hashValue]; + p->hash[hash2Value] = + p->hash[kFix3HashSize + hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value, hash3Value; + SKIP_HEADER(4) + HASH4_CALC; + curMatch = p->hash[kFix4HashSize + hashValue]; + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = p->pos; + p->hash[kFix4HashSize + hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value, hash3Value; + SKIP_HEADER(4) + HASH4_CALC; + curMatch = p->hash[kFix4HashSize + hashValue]; + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) +{ + vTable->Init = (Mf_Init_Func)MatchFinder_Init; + vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; + if (!p->btMode) + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + } + else if (p->numHashBytes == 2) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; + } + else if (p->numHashBytes == 3) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; + } + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; + } +} diff --git a/ext/VFS/ext/7z/src/LzFind.h b/ext/VFS/ext/7z/src/LzFind.h new file mode 100644 index 000000000..7ebdfa446 --- /dev/null +++ b/ext/VFS/ext/7z/src/LzFind.h @@ -0,0 +1,115 @@ +/* LzFind.h -- Match finder for LZ algorithms +2009-04-22 : Igor Pavlov : Public domain */ + +#ifndef __LZ_FIND_H +#define __LZ_FIND_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef UInt32 CLzRef; + +typedef struct _CMatchFinder +{ + Byte *buffer; + UInt32 pos; + UInt32 posLimit; + UInt32 streamPos; + UInt32 lenLimit; + + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ + + UInt32 matchMaxLen; + CLzRef *hash; + CLzRef *son; + UInt32 hashMask; + UInt32 cutValue; + + Byte *bufferBase; + ISeqInStream *stream; + int streamEndWasReached; + + UInt32 blockSize; + UInt32 keepSizeBefore; + UInt32 keepSizeAfter; + + UInt32 numHashBytes; + int directInput; + size_t directInputRem; + int btMode; + int bigHash; + UInt32 historySize; + UInt32 fixedHashSize; + UInt32 hashSizeSum; + UInt32 numSons; + SRes result; + UInt32 crc[256]; +} CMatchFinder; + +#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) +#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) + +#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) + +int MatchFinder_NeedMove(CMatchFinder *p); +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); +void MatchFinder_MoveBlock(CMatchFinder *p); +void MatchFinder_ReadIfRequired(CMatchFinder *p); + +void MatchFinder_Construct(CMatchFinder *p); + +/* Conditions: + historySize <= 3 GB + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB +*/ +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc); +void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); + +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + UInt32 *distances, UInt32 maxLen); + +/* +Conditions: + Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. + Mf_GetPointerToCurrentPos_Func's result must be used only before any other function +*/ + +typedef void (*Mf_Init_Func)(void *object); +typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); +typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); +typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); +typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); +typedef void (*Mf_Skip_Func)(void *object, UInt32); + +typedef struct _IMatchFinder +{ + Mf_Init_Func Init; + Mf_GetIndexByte_Func GetIndexByte; + Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; + Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; + Mf_GetMatches_Func GetMatches; + Mf_Skip_Func Skip; +} IMatchFinder; + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); + +void MatchFinder_Init(CMatchFinder *p); +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/LzFindMt.c b/ext/VFS/ext/7z/src/LzFindMt.c new file mode 100644 index 000000000..db95590c3 --- /dev/null +++ b/ext/VFS/ext/7z/src/LzFindMt.c @@ -0,0 +1,793 @@ +/* LzFindMt.c -- multithreaded Match finder for LZ algorithms +2009-09-20 : Igor Pavlov : Public domain */ + +#include "LzHash.h" + +#include "LzFindMt.h" + +void MtSync_Construct(CMtSync *p) +{ + p->wasCreated = False; + p->csWasInitialized = False; + p->csWasEntered = False; + Thread_Construct(&p->thread); + Event_Construct(&p->canStart); + Event_Construct(&p->wasStarted); + Event_Construct(&p->wasStopped); + Semaphore_Construct(&p->freeSemaphore); + Semaphore_Construct(&p->filledSemaphore); +} + +void MtSync_GetNextBlock(CMtSync *p) +{ + if (p->needStart) + { + p->numProcessedBlocks = 1; + p->needStart = False; + p->stopWriting = False; + p->exit = False; + Event_Reset(&p->wasStarted); + Event_Reset(&p->wasStopped); + + Event_Set(&p->canStart); + Event_Wait(&p->wasStarted); + } + else + { + CriticalSection_Leave(&p->cs); + p->csWasEntered = False; + p->numProcessedBlocks++; + Semaphore_Release1(&p->freeSemaphore); + } + Semaphore_Wait(&p->filledSemaphore); + CriticalSection_Enter(&p->cs); + p->csWasEntered = True; +} + +/* MtSync_StopWriting must be called if Writing was started */ + +void MtSync_StopWriting(CMtSync *p) +{ + UInt32 myNumBlocks = p->numProcessedBlocks; + if (!Thread_WasCreated(&p->thread) || p->needStart) + return; + p->stopWriting = True; + if (p->csWasEntered) + { + CriticalSection_Leave(&p->cs); + p->csWasEntered = False; + } + Semaphore_Release1(&p->freeSemaphore); + + Event_Wait(&p->wasStopped); + + while (myNumBlocks++ != p->numProcessedBlocks) + { + Semaphore_Wait(&p->filledSemaphore); + Semaphore_Release1(&p->freeSemaphore); + } + p->needStart = True; +} + +void MtSync_Destruct(CMtSync *p) +{ + if (Thread_WasCreated(&p->thread)) + { + MtSync_StopWriting(p); + p->exit = True; + if (p->needStart) + Event_Set(&p->canStart); + Thread_Wait(&p->thread); + Thread_Close(&p->thread); + } + if (p->csWasInitialized) + { + CriticalSection_Delete(&p->cs); + p->csWasInitialized = False; + } + + Event_Close(&p->canStart); + Event_Close(&p->wasStarted); + Event_Close(&p->wasStopped); + Semaphore_Close(&p->freeSemaphore); + Semaphore_Close(&p->filledSemaphore); + + p->wasCreated = False; +} + +#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } + +static SRes MtSync_Create2(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks) +{ + if (p->wasCreated) + return SZ_OK; + + RINOK_THREAD(CriticalSection_Init(&p->cs)); + p->csWasInitialized = True; + + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart)); + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted)); + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped)); + + RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks)); + RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks)); + + p->needStart = True; + + RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj)); + p->wasCreated = True; + return SZ_OK; +} + +static SRes MtSync_Create(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks) +{ + SRes res = MtSync_Create2(p, startAddress, obj, numBlocks); + if (res != SZ_OK) + MtSync_Destruct(p); + return res; +} + +void MtSync_Init(CMtSync *p) { p->needStart = True; } + +#define kMtMaxValForNormalize 0xFFFFFFFF + +#define DEF_GetHeads2(name, v, action) \ +static void GetHeads ## name(const Byte *p, UInt32 pos, \ +UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ +{ action; for (; numHeads != 0; numHeads--) { \ +const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } + +#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) + +DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), hashMask = hashMask; crc = crc; ) +DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask) +DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask) +DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask) +/* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */ + +void HashThreadFunc(CMatchFinderMt *mt) +{ + CMtSync *p = &mt->hashSync; + for (;;) + { + UInt32 numProcessedBlocks = 0; + Event_Wait(&p->canStart); + Event_Set(&p->wasStarted); + for (;;) + { + if (p->exit) + return; + if (p->stopWriting) + { + p->numProcessedBlocks = numProcessedBlocks; + Event_Set(&p->wasStopped); + break; + } + + { + CMatchFinder *mf = mt->MatchFinder; + if (MatchFinder_NeedMove(mf)) + { + CriticalSection_Enter(&mt->btSync.cs); + CriticalSection_Enter(&mt->hashSync.cs); + { + const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf); + const Byte *afterPtr; + MatchFinder_MoveBlock(mf); + afterPtr = MatchFinder_GetPointerToCurrentPos(mf); + mt->pointerToCurPos -= beforePtr - afterPtr; + mt->buffer -= beforePtr - afterPtr; + } + CriticalSection_Leave(&mt->btSync.cs); + CriticalSection_Leave(&mt->hashSync.cs); + continue; + } + + Semaphore_Wait(&p->freeSemaphore); + + MatchFinder_ReadIfRequired(mf); + if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize)) + { + UInt32 subValue = (mf->pos - mf->historySize - 1); + MatchFinder_ReduceOffsets(mf, subValue); + MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1); + } + { + UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize; + UInt32 num = mf->streamPos - mf->pos; + heads[0] = 2; + heads[1] = num; + if (num >= mf->numHashBytes) + { + num = num - mf->numHashBytes + 1; + if (num > kMtHashBlockSize - 2) + num = kMtHashBlockSize - 2; + mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc); + heads[0] += num; + } + mf->pos += num; + mf->buffer += num; + } + } + + Semaphore_Release1(&p->filledSemaphore); + } + } +} + +void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) +{ + MtSync_GetNextBlock(&p->hashSync); + p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize; + p->hashBufPosLimit += p->hashBuf[p->hashBufPos++]; + p->hashNumAvail = p->hashBuf[p->hashBufPos++]; +} + +#define kEmptyHashValue 0 + +/* #define MFMT_GM_INLINE */ + +#ifdef MFMT_GM_INLINE + +#define NO_INLINE MY_FAST_CALL + +Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes) +{ + do + { + UInt32 *distances = _distances + 1; + UInt32 curMatch = pos - *hash++; + + CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + (_cyclicBufferPos << 1); + UInt32 len0 = 0, len1 = 0; + UInt32 cutValue = _cutValue; + UInt32 maxLen = _maxLen; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + break; + } + { + CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + UInt32 len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + *distances++ = maxLen = len; + *distances++ = delta - 1; + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + break; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } + pos++; + _cyclicBufferPos++; + cur++; + { + UInt32 num = (UInt32)(distances - _distances); + *_distances = num - 1; + _distances += num; + limit -= num; + } + } + while (limit > 0 && --size != 0); + *posRes = pos; + return limit; +} + +#endif + +void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + UInt32 numProcessed = 0; + UInt32 curPos = 2; + UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); + distances[1] = p->hashNumAvail; + while (curPos < limit) + { + if (p->hashBufPos == p->hashBufPosLimit) + { + MatchFinderMt_GetNextBlock_Hash(p); + distances[1] = numProcessed + p->hashNumAvail; + if (p->hashNumAvail >= p->numHashBytes) + continue; + for (; p->hashNumAvail != 0; p->hashNumAvail--) + distances[curPos++] = 0; + break; + } + { + UInt32 size = p->hashBufPosLimit - p->hashBufPos; + UInt32 lenLimit = p->matchMaxLen; + UInt32 pos = p->pos; + UInt32 cyclicBufferPos = p->cyclicBufferPos; + if (lenLimit >= p->hashNumAvail) + lenLimit = p->hashNumAvail; + { + UInt32 size2 = p->hashNumAvail - lenLimit + 1; + if (size2 < size) + size = size2; + size2 = p->cyclicBufferSize - cyclicBufferPos; + if (size2 < size) + size = size2; + } + #ifndef MFMT_GM_INLINE + while (curPos < limit && size-- != 0) + { + UInt32 *startDistances = distances + curPos; + UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], + pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + startDistances + 1, p->numHashBytes - 1) - startDistances); + *startDistances = num - 1; + curPos += num; + cyclicBufferPos++; + pos++; + p->buffer++; + } + #else + { + UInt32 posRes; + curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes); + p->hashBufPos += posRes - pos; + cyclicBufferPos += posRes - pos; + p->buffer += posRes - pos; + pos = posRes; + } + #endif + + numProcessed += pos - p->pos; + p->hashNumAvail -= pos - p->pos; + p->pos = pos; + if (cyclicBufferPos == p->cyclicBufferSize) + cyclicBufferPos = 0; + p->cyclicBufferPos = cyclicBufferPos; + } + } + distances[0] = curPos; +} + +void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) +{ + CMtSync *sync = &p->hashSync; + if (!sync->needStart) + { + CriticalSection_Enter(&sync->cs); + sync->csWasEntered = True; + } + + BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize); + + if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize) + { + UInt32 subValue = p->pos - p->cyclicBufferSize; + MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2); + p->pos -= subValue; + } + + if (!sync->needStart) + { + CriticalSection_Leave(&sync->cs); + sync->csWasEntered = False; + } +} + +void BtThreadFunc(CMatchFinderMt *mt) +{ + CMtSync *p = &mt->btSync; + for (;;) + { + UInt32 blockIndex = 0; + Event_Wait(&p->canStart); + Event_Set(&p->wasStarted); + for (;;) + { + if (p->exit) + return; + if (p->stopWriting) + { + p->numProcessedBlocks = blockIndex; + MtSync_StopWriting(&mt->hashSync); + Event_Set(&p->wasStopped); + break; + } + Semaphore_Wait(&p->freeSemaphore); + BtFillBlock(mt, blockIndex++); + Semaphore_Release1(&p->filledSemaphore); + } + } +} + +void MatchFinderMt_Construct(CMatchFinderMt *p) +{ + p->hashBuf = 0; + MtSync_Construct(&p->hashSync); + MtSync_Construct(&p->btSync); +} + +void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->hashBuf); + p->hashBuf = 0; +} + +void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc) +{ + MtSync_Destruct(&p->hashSync); + MtSync_Destruct(&p->btSync); + MatchFinderMt_FreeMem(p, alloc); +} + +#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) +#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) + +static unsigned MY_STD_CALL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } +static unsigned MY_STD_CALL BtThreadFunc2(void *p) +{ + Byte allocaDummy[0x180]; + int i = 0; + for (i = 0; i < 16; i++) + allocaDummy[i] = (Byte)i; + BtThreadFunc((CMatchFinderMt *)p); + return 0; +} + +SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc) +{ + CMatchFinder *mf = p->MatchFinder; + p->historySize = historySize; + if (kMtBtBlockSize <= matchMaxLen * 4) + return SZ_ERROR_PARAM; + if (p->hashBuf == 0) + { + p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32)); + if (p->hashBuf == 0) + return SZ_ERROR_MEM; + p->btBuf = p->hashBuf + kHashBufferSize; + } + keepAddBufferBefore += (kHashBufferSize + kBtBufferSize); + keepAddBufferAfter += kMtHashBlockSize; + if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc)) + return SZ_ERROR_MEM; + + RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks)); + RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks)); + return SZ_OK; +} + +/* Call it after ReleaseStream / SetStream */ +void MatchFinderMt_Init(CMatchFinderMt *p) +{ + CMatchFinder *mf = p->MatchFinder; + p->btBufPos = p->btBufPosLimit = 0; + p->hashBufPos = p->hashBufPosLimit = 0; + MatchFinder_Init(mf); + p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf); + p->btNumAvailBytes = 0; + p->lzPos = p->historySize + 1; + + p->hash = mf->hash; + p->fixedHashSize = mf->fixedHashSize; + p->crc = mf->crc; + + p->son = mf->son; + p->matchMaxLen = mf->matchMaxLen; + p->numHashBytes = mf->numHashBytes; + p->pos = mf->pos; + p->buffer = mf->buffer; + p->cyclicBufferPos = mf->cyclicBufferPos; + p->cyclicBufferSize = mf->cyclicBufferSize; + p->cutValue = mf->cutValue; +} + +/* ReleaseStream is required to finish multithreading */ +void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) +{ + MtSync_StopWriting(&p->btSync); + /* p->MatchFinder->ReleaseStream(); */ +} + +void MatchFinderMt_Normalize(CMatchFinderMt *p) +{ + MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize); + p->lzPos = p->historySize + 1; +} + +void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) +{ + UInt32 blockIndex; + MtSync_GetNextBlock(&p->btSync); + blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask); + p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize; + p->btBufPosLimit += p->btBuf[p->btBufPos++]; + p->btNumAvailBytes = p->btBuf[p->btBufPos++]; + if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize) + MatchFinderMt_Normalize(p); +} + +const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) +{ + return p->pointerToCurPos; +} + +#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); + +UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) +{ + GET_NEXT_BLOCK_IF_REQUIRED; + return p->btNumAvailBytes; +} + +Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index) +{ + return p->pointerToCurPos[index]; +} + +UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 hash2Value, curMatch2; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH2_CALC + + curMatch2 = hash[hash2Value]; + hash[hash2Value] = lzPos; + + if (curMatch2 >= matchMinPos) + if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + *distances++ = 2; + *distances++ = lzPos - curMatch2 - 1; + } + return distances; +} + +UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, curMatch2, curMatch3; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH3_CALC + + curMatch2 = hash[ hash2Value]; + curMatch3 = hash[kFix3HashSize + hash3Value]; + + hash[ hash2Value] = + hash[kFix3HashSize + hash3Value] = + lzPos; + + if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch2 - 1; + if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) + { + distances[0] = 3; + return distances + 2; + } + distances[0] = 2; + distances += 2; + } + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) + { + *distances++ = 3; + *distances++ = lzPos - curMatch3 - 1; + } + return distances; +} + +/* +UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH4_CALC + + curMatch2 = hash[ hash2Value]; + curMatch3 = hash[kFix3HashSize + hash3Value]; + curMatch4 = hash[kFix4HashSize + hash4Value]; + + hash[ hash2Value] = + hash[kFix3HashSize + hash3Value] = + hash[kFix4HashSize + hash4Value] = + lzPos; + + if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch2 - 1; + if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) + { + distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; + return distances + 2; + } + distances[0] = 2; + distances += 2; + } + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch3 - 1; + if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3]) + { + distances[0] = 4; + return distances + 2; + } + distances[0] = 3; + distances += 2; + } + + if (curMatch4 >= matchMinPos) + if ( + cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] && + cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3] + ) + { + *distances++ = 4; + *distances++ = lzPos - curMatch4 - 1; + } + return distances; +} +*/ + +#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; + +UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + const UInt32 *btBuf = p->btBuf + p->btBufPos; + UInt32 len = *btBuf++; + p->btBufPos += 1 + len; + p->btNumAvailBytes--; + { + UInt32 i; + for (i = 0; i < len; i += 2) + { + *distances++ = *btBuf++; + *distances++ = *btBuf++; + } + } + INCREASE_LZ_POS + return len; +} + +UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + const UInt32 *btBuf = p->btBuf + p->btBufPos; + UInt32 len = *btBuf++; + p->btBufPos += 1 + len; + + if (len == 0) + { + if (p->btNumAvailBytes-- >= 4) + len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances)); + } + else + { + /* Condition: there are matches in btBuf with length < p->numHashBytes */ + UInt32 *distances2; + p->btNumAvailBytes--; + distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances); + do + { + *distances2++ = *btBuf++; + *distances2++ = *btBuf++; + } + while ((len -= 2) != 0); + len = (UInt32)(distances2 - (distances)); + } + INCREASE_LZ_POS + return len; +} + +#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED +#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; +#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0); + +void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER2_MT { p->btNumAvailBytes--; + SKIP_FOOTER_MT +} + +void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(2) + UInt32 hash2Value; + MT_HASH2_CALC + hash[hash2Value] = p->lzPos; + SKIP_FOOTER_MT +} + +void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(3) + UInt32 hash2Value, hash3Value; + MT_HASH3_CALC + hash[kFix3HashSize + hash3Value] = + hash[ hash2Value] = + p->lzPos; + SKIP_FOOTER_MT +} + +/* +void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(4) + UInt32 hash2Value, hash3Value, hash4Value; + MT_HASH4_CALC + hash[kFix4HashSize + hash4Value] = + hash[kFix3HashSize + hash3Value] = + hash[ hash2Value] = + p->lzPos; + SKIP_FOOTER_MT +} +*/ + +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) +{ + vTable->Init = (Mf_Init_Func)MatchFinderMt_Init; + vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos; + vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches; + switch(p->MatchFinder->numHashBytes) + { + case 2: + p->GetHeadsFunc = GetHeads2; + p->MixMatchesFunc = (Mf_Mix_Matches)0; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip; + vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches; + break; + case 3: + p->GetHeadsFunc = GetHeads3; + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip; + break; + default: + /* case 4: */ + p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4; + /* p->GetHeadsFunc = GetHeads4; */ + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip; + break; + /* + default: + p->GetHeadsFunc = GetHeads5; + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip; + break; + */ + } +} diff --git a/ext/VFS/ext/7z/src/LzFindMt.h b/ext/VFS/ext/7z/src/LzFindMt.h new file mode 100644 index 000000000..17ed237d6 --- /dev/null +++ b/ext/VFS/ext/7z/src/LzFindMt.h @@ -0,0 +1,105 @@ +/* LzFindMt.h -- multithreaded Match finder for LZ algorithms +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZ_FIND_MT_H +#define __LZ_FIND_MT_H + +#include "LzFind.h" +#include "Threads.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define kMtHashBlockSize (1 << 13) +#define kMtHashNumBlocks (1 << 3) +#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1) + +#define kMtBtBlockSize (1 << 14) +#define kMtBtNumBlocks (1 << 6) +#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1) + +typedef struct _CMtSync +{ + Bool wasCreated; + Bool needStart; + Bool exit; + Bool stopWriting; + + CThread thread; + CAutoResetEvent canStart; + CAutoResetEvent wasStarted; + CAutoResetEvent wasStopped; + CSemaphore freeSemaphore; + CSemaphore filledSemaphore; + Bool csWasInitialized; + Bool csWasEntered; + CCriticalSection cs; + UInt32 numProcessedBlocks; +} CMtSync; + +typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances); + +/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */ +#define kMtCacheLineDummy 128 + +typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos, + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc); + +typedef struct _CMatchFinderMt +{ + /* LZ */ + const Byte *pointerToCurPos; + UInt32 *btBuf; + UInt32 btBufPos; + UInt32 btBufPosLimit; + UInt32 lzPos; + UInt32 btNumAvailBytes; + + UInt32 *hash; + UInt32 fixedHashSize; + UInt32 historySize; + const UInt32 *crc; + + Mf_Mix_Matches MixMatchesFunc; + + /* LZ + BT */ + CMtSync btSync; + Byte btDummy[kMtCacheLineDummy]; + + /* BT */ + UInt32 *hashBuf; + UInt32 hashBufPos; + UInt32 hashBufPosLimit; + UInt32 hashNumAvail; + + CLzRef *son; + UInt32 matchMaxLen; + UInt32 numHashBytes; + UInt32 pos; + Byte *buffer; + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be historySize + 1 */ + UInt32 cutValue; + + /* BT + Hash */ + CMtSync hashSync; + /* Byte hashDummy[kMtCacheLineDummy]; */ + + /* Hash */ + Mf_GetHeads GetHeadsFunc; + CMatchFinder *MatchFinder; +} CMatchFinderMt; + +void MatchFinderMt_Construct(CMatchFinderMt *p); +void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc); +SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc); +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable); +void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/LzHash.h b/ext/VFS/ext/7z/src/LzHash.h new file mode 100644 index 000000000..b2f0e3c24 --- /dev/null +++ b/ext/VFS/ext/7z/src/LzHash.h @@ -0,0 +1,54 @@ +/* LzHash.h -- HASH functions for LZ algorithms +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZ_HASH_H +#define __LZ_HASH_H + +#define kHash2Size (1 << 10) +#define kHash3Size (1 << 16) +#define kHash4Size (1 << 20) + +#define kFix3HashSize (kHash2Size) +#define kFix4HashSize (kHash2Size + kHash3Size) +#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) + +#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); + +#define HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } + +#define HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } + +#define HASH5_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ + hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ + hash4Value &= (kHash4Size - 1); } + +/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ +#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; + + +#define MT_HASH2_CALC \ + hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); + +#define MT_HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + +#define MT_HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } + +#endif diff --git a/ext/VFS/ext/7z/src/Lzma2Dec.c b/ext/VFS/ext/7z/src/Lzma2Dec.c new file mode 100644 index 000000000..8f2406755 --- /dev/null +++ b/ext/VFS/ext/7z/src/Lzma2Dec.c @@ -0,0 +1,356 @@ +/* Lzma2Dec.c -- LZMA2 Decoder +2009-05-03 : Igor Pavlov : Public domain */ + +/* #define SHOW_DEBUG_INFO */ + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include + +#include "Lzma2Dec.h" + +/* +00000000 - EOS +00000001 U U - Uncompressed Reset Dic +00000010 U U - Uncompressed No Reset +100uuuuu U U P P - LZMA no reset +101uuuuu U U P P - LZMA reset state +110uuuuu U U P P S - LZMA reset state + new prop +111uuuuu U U P P S - LZMA reset state + new prop + reset dic + + u, U - Unpack Size + P - Pack Size + S - Props +*/ + +#define LZMA2_CONTROL_LZMA (1 << 7) +#define LZMA2_CONTROL_COPY_NO_RESET 2 +#define LZMA2_CONTROL_COPY_RESET_DIC 1 +#define LZMA2_CONTROL_EOF 0 + +#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0) + +#define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3) +#define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2) + +#define LZMA2_LCLP_MAX 4 +#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +typedef enum +{ + LZMA2_STATE_CONTROL, + LZMA2_STATE_UNPACK0, + LZMA2_STATE_UNPACK1, + LZMA2_STATE_PACK0, + LZMA2_STATE_PACK1, + LZMA2_STATE_PROP, + LZMA2_STATE_DATA, + LZMA2_STATE_DATA_CONT, + LZMA2_STATE_FINISHED, + LZMA2_STATE_ERROR +} ELzma2State; + +static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) +{ + UInt32 dicSize; + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); + props[0] = (Byte)LZMA2_LCLP_MAX; + props[1] = (Byte)(dicSize); + props[2] = (Byte)(dicSize >> 8); + props[3] = (Byte)(dicSize >> 16); + props[4] = (Byte)(dicSize >> 24); + return SZ_OK; +} + +SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) +{ + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)); + return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); +} + +SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) +{ + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)); + return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); +} + +void Lzma2Dec_Init(CLzma2Dec *p) +{ + p->state = LZMA2_STATE_CONTROL; + p->needInitDic = True; + p->needInitState = True; + p->needInitProp = True; + LzmaDec_Init(&p->decoder); +} + +static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) +{ + switch(p->state) + { + case LZMA2_STATE_CONTROL: + p->control = b; + PRF(printf("\n %4X ", p->decoder.dicPos)); + PRF(printf(" %2X", b)); + if (p->control == 0) + return LZMA2_STATE_FINISHED; + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if ((p->control & 0x7F) > 2) + return LZMA2_STATE_ERROR; + p->unpackSize = 0; + } + else + p->unpackSize = (UInt32)(p->control & 0x1F) << 16; + return LZMA2_STATE_UNPACK0; + + case LZMA2_STATE_UNPACK0: + p->unpackSize |= (UInt32)b << 8; + return LZMA2_STATE_UNPACK1; + + case LZMA2_STATE_UNPACK1: + p->unpackSize |= (UInt32)b; + p->unpackSize++; + PRF(printf(" %8d", p->unpackSize)); + return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; + + case LZMA2_STATE_PACK0: + p->packSize = (UInt32)b << 8; + return LZMA2_STATE_PACK1; + + case LZMA2_STATE_PACK1: + p->packSize |= (UInt32)b; + p->packSize++; + PRF(printf(" %8d", p->packSize)); + return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP: + (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); + + case LZMA2_STATE_PROP: + { + int lc, lp; + if (b >= (9 * 5 * 5)) + return LZMA2_STATE_ERROR; + lc = b % 9; + b /= 9; + p->decoder.prop.pb = b / 5; + lp = b % 5; + if (lc + lp > LZMA2_LCLP_MAX) + return LZMA2_STATE_ERROR; + p->decoder.prop.lc = lc; + p->decoder.prop.lp = lp; + p->needInitProp = False; + return LZMA2_STATE_DATA; + } + } + return LZMA2_STATE_ERROR; +} + +static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) +{ + memcpy(p->dic + p->dicPos, src, size); + p->dicPos += size; + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) + p->checkDicSize = p->prop.dicSize; + p->processedPos += (UInt32)size; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState); + +SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->state != LZMA2_STATE_FINISHED) + { + SizeT dicPos = p->decoder.dicPos; + if (p->state == LZMA2_STATE_ERROR) + return SZ_ERROR_DATA; + if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) + { + if (*srcLen == inSize) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + (*srcLen)++; + p->state = Lzma2Dec_UpdateState(p, *src++); + continue; + } + { + SizeT destSizeCur = dicLimit - dicPos; + SizeT srcSizeCur = inSize - *srcLen; + ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; + + if (p->unpackSize <= destSizeCur) + { + destSizeCur = (SizeT)p->unpackSize; + curFinishMode = LZMA_FINISH_END; + } + + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (*srcLen == inSize) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + if (p->state == LZMA2_STATE_DATA) + { + Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); + if (initDic) + p->needInitProp = p->needInitState = True; + else if (p->needInitDic) + return SZ_ERROR_DATA; + p->needInitDic = False; + LzmaDec_InitDicAndState(&p->decoder, initDic, False); + } + + if (srcSizeCur > destSizeCur) + srcSizeCur = destSizeCur; + + if (srcSizeCur == 0) + return SZ_ERROR_DATA; + + LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur); + + src += srcSizeCur; + *srcLen += srcSizeCur; + p->unpackSize -= (UInt32)srcSizeCur; + p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; + } + else + { + SizeT outSizeProcessed; + SRes res; + + if (p->state == LZMA2_STATE_DATA) + { + int mode = LZMA2_GET_LZMA_MODE(p); + Bool initDic = (mode == 3); + Bool initState = (mode > 0); + if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) + return SZ_ERROR_DATA; + + LzmaDec_InitDicAndState(&p->decoder, initDic, initState); + p->needInitDic = False; + p->needInitState = False; + p->state = LZMA2_STATE_DATA_CONT; + } + if (srcSizeCur > p->packSize) + srcSizeCur = (SizeT)p->packSize; + + res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status); + + src += srcSizeCur; + *srcLen += srcSizeCur; + p->packSize -= (UInt32)srcSizeCur; + + outSizeProcessed = p->decoder.dicPos - dicPos; + p->unpackSize -= (UInt32)outSizeProcessed; + + RINOK(res); + if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) + return res; + + if (srcSizeCur == 0 && outSizeProcessed == 0) + { + if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || + p->unpackSize != 0 || p->packSize != 0) + return SZ_ERROR_DATA; + p->state = LZMA2_STATE_CONTROL; + } + if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + *status = LZMA_STATUS_NOT_FINISHED; + } + } + } + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return SZ_OK; +} + +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen, inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT srcSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->decoder.dicPos == p->decoder.dicBufSize) + p->decoder.dicPos = 0; + dicPos = p->decoder.dicPos; + if (outSize > p->decoder.dicBufSize - dicPos) + { + outSizeCur = p->decoder.dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status); + src += srcSizeCur; + inSize -= srcSizeCur; + *srcLen += srcSizeCur; + outSizeCur = p->decoder.dicPos - dicPos; + memcpy(dest, p->decoder.dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) +{ + CLzma2Dec decoder; + SRes res; + SizeT outSize = *destLen, inSize = *srcLen; + Byte props[LZMA_PROPS_SIZE]; + + Lzma2Dec_Construct(&decoder); + + *destLen = *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + decoder.decoder.dic = dest; + decoder.decoder.dicBufSize = outSize; + + RINOK(Lzma2Dec_GetOldProps(prop, props)); + RINOK(LzmaDec_AllocateProbs(&decoder.decoder, props, LZMA_PROPS_SIZE, alloc)); + + *srcLen = inSize; + res = Lzma2Dec_DecodeToDic(&decoder, outSize, src, srcLen, finishMode, status); + *destLen = decoder.decoder.dicPos; + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + + LzmaDec_FreeProbs(&decoder.decoder, alloc); + return res; +} diff --git a/ext/VFS/ext/7z/src/Lzma2Dec.h b/ext/VFS/ext/7z/src/Lzma2Dec.h new file mode 100644 index 000000000..827698dee --- /dev/null +++ b/ext/VFS/ext/7z/src/Lzma2Dec.h @@ -0,0 +1,84 @@ +/* Lzma2Dec.h -- LZMA2 Decoder +2009-05-03 : Igor Pavlov : Public domain */ + +#ifndef __LZMA2_DEC_H +#define __LZMA2_DEC_H + +#include "LzmaDec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---------- State Interface ---------- */ + +typedef struct +{ + CLzmaDec decoder; + UInt32 packSize; + UInt32 unpackSize; + int state; + Byte control; + Bool needInitDic; + Bool needInitState; + Bool needInitProp; +} CLzma2Dec; + +#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder) +#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc); +#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc); + +SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); +SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); +void Lzma2Dec_Init(CLzma2Dec *p); + + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen or dicLimit). + LZMA_FINISH_ANY - use smallest number of input bytes + LZMA_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + SZ_ERROR_DATA - Data error +*/ + +SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - use smallest number of input bytes + LZMA_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/Lzma2Enc.c b/ext/VFS/ext/7z/src/Lzma2Enc.c new file mode 100644 index 000000000..6f2e280b7 --- /dev/null +++ b/ext/VFS/ext/7z/src/Lzma2Enc.c @@ -0,0 +1,479 @@ +/* Lzma2Enc.c -- LZMA2 Encoder +2010-03-24 : Igor Pavlov : Public domain */ + +/* #include */ +#include + +/* #define _7ZIP_ST */ + +#include "Lzma2Enc.h" + +#ifndef _7ZIP_ST +#include "MtCoder.h" +#else +#define NUM_MT_CODER_THREADS_MAX 1 +#endif + +#define LZMA2_CONTROL_LZMA (1 << 7) +#define LZMA2_CONTROL_COPY_NO_RESET 2 +#define LZMA2_CONTROL_COPY_RESET_DIC 1 +#define LZMA2_CONTROL_EOF 0 + +#define LZMA2_LCLP_MAX 4 + +#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) + +#define LZMA2_PACK_SIZE_MAX (1 << 16) +#define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX +#define LZMA2_UNPACK_SIZE_MAX (1 << 21) +#define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX + +#define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) + + +#define PRF(x) /* x */ + +/* ---------- CLzma2EncInt ---------- */ + +typedef struct +{ + CLzmaEncHandle enc; + UInt64 srcPos; + Byte props; + Bool needInitState; + Bool needInitProp; +} CLzma2EncInt; + +static SRes Lzma2EncInt_Init(CLzma2EncInt *p, const CLzma2EncProps *props) +{ + Byte propsEncoded[LZMA_PROPS_SIZE]; + SizeT propsSize = LZMA_PROPS_SIZE; + RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)); + RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)); + p->srcPos = 0; + p->props = propsEncoded[0]; + p->needInitState = True; + p->needInitProp = True; + return SZ_OK; +} + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, + ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp); +void LzmaEnc_Finish(CLzmaEncHandle pp); +void LzmaEnc_SaveState(CLzmaEncHandle pp); +void LzmaEnc_RestoreState(CLzmaEncHandle pp); + + +static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, + size_t *packSizeRes, ISeqOutStream *outStream) +{ + size_t packSizeLimit = *packSizeRes; + size_t packSize = packSizeLimit; + UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; + unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); + Bool useCopyBlock; + SRes res; + + *packSizeRes = 0; + if (packSize < lzHeaderSize) + return SZ_ERROR_OUTPUT_EOF; + packSize -= lzHeaderSize; + + LzmaEnc_SaveState(p->enc); + res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, + outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); + + PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); + + if (unpackSize == 0) + return res; + + if (res == SZ_OK) + useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); + else + { + if (res != SZ_ERROR_OUTPUT_EOF) + return res; + res = SZ_OK; + useCopyBlock = True; + } + + if (useCopyBlock) + { + size_t destPos = 0; + PRF(printf("################# COPY ")); + while (unpackSize > 0) + { + UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; + if (packSizeLimit - destPos < u + 3) + return SZ_ERROR_OUTPUT_EOF; + outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); + outBuf[destPos++] = (Byte)((u - 1) >> 8); + outBuf[destPos++] = (Byte)(u - 1); + memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); + unpackSize -= u; + destPos += u; + p->srcPos += u; + if (outStream) + { + *packSizeRes += destPos; + if (outStream->Write(outStream, outBuf, destPos) != destPos) + return SZ_ERROR_WRITE; + destPos = 0; + } + else + *packSizeRes = destPos; + /* needInitState = True; */ + } + LzmaEnc_RestoreState(p->enc); + return SZ_OK; + } + { + size_t destPos = 0; + UInt32 u = unpackSize - 1; + UInt32 pm = (UInt32)(packSize - 1); + unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); + + PRF(printf(" ")); + + outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | (u >> 16) & 0x1F); + outBuf[destPos++] = (Byte)(u >> 8); + outBuf[destPos++] = (Byte)u; + outBuf[destPos++] = (Byte)(pm >> 8); + outBuf[destPos++] = (Byte)pm; + + if (p->needInitProp) + outBuf[destPos++] = p->props; + + p->needInitProp = False; + p->needInitState = False; + destPos += packSize; + p->srcPos += unpackSize; + + if (outStream) + if (outStream->Write(outStream, outBuf, destPos) != destPos) + return SZ_ERROR_WRITE; + *packSizeRes = destPos; + return SZ_OK; + } +} + +/* ---------- Lzma2 Props ---------- */ + +void Lzma2EncProps_Init(CLzma2EncProps *p) +{ + LzmaEncProps_Init(&p->lzmaProps); + p->numTotalThreads = -1; + p->numBlockThreads = -1; + p->blockSize = 0; +} + +void Lzma2EncProps_Normalize(CLzma2EncProps *p) +{ + int t1, t1n, t2, t3; + { + CLzmaEncProps lzmaProps = p->lzmaProps; + LzmaEncProps_Normalize(&lzmaProps); + t1n = lzmaProps.numThreads; + } + + t1 = p->lzmaProps.numThreads; + t2 = p->numBlockThreads; + t3 = p->numTotalThreads; + + if (t2 > NUM_MT_CODER_THREADS_MAX) + t2 = NUM_MT_CODER_THREADS_MAX; + + if (t3 <= 0) + { + if (t2 <= 0) + t2 = 1; + t3 = t1n * t2; + } + else if (t2 <= 0) + { + t2 = t3 / t1n; + if (t2 == 0) + { + t1 = 1; + t2 = t3; + } + if (t2 > NUM_MT_CODER_THREADS_MAX) + t2 = NUM_MT_CODER_THREADS_MAX; + } + else if (t1 <= 0) + { + t1 = t3 / t2; + if (t1 == 0) + t1 = 1; + } + else + t3 = t1n * t2; + + p->lzmaProps.numThreads = t1; + p->numBlockThreads = t2; + p->numTotalThreads = t3; + LzmaEncProps_Normalize(&p->lzmaProps); + + if (p->blockSize == 0) + { + UInt32 dictSize = p->lzmaProps.dictSize; + UInt64 blockSize = (UInt64)dictSize << 2; + const UInt32 kMinSize = (UInt32)1 << 20; + const UInt32 kMaxSize = (UInt32)1 << 28; + if (blockSize < kMinSize) blockSize = kMinSize; + if (blockSize > kMaxSize) blockSize = kMaxSize; + if (blockSize < dictSize) blockSize = dictSize; + p->blockSize = (size_t)blockSize; + } +} + +static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) +{ + return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; +} + +/* ---------- Lzma2 ---------- */ + +extern struct _CLzma2Enc; + +typedef struct _CLzma2Enc +{ + Byte propEncoded; + CLzma2EncProps props; + + Byte *outBuf; + + ISzAlloc *alloc; + ISzAlloc *allocBig; + + CLzma2EncInt coders[NUM_MT_CODER_THREADS_MAX]; + + #ifndef _7ZIP_ST + CMtCoder mtCoder; + #endif + +} CLzma2Enc; + + +/* ---------- Lzma2EncThread ---------- */ + +static SRes Lzma2Enc_EncodeMt1(CLzma2EncInt *p, CLzma2Enc *mainEncoder, + ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) +{ + UInt64 packTotal = 0; + SRes res = SZ_OK; + + if (mainEncoder->outBuf == 0) + { + mainEncoder->outBuf = IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); + if (mainEncoder->outBuf == 0) + return SZ_ERROR_MEM; + } + RINOK(Lzma2EncInt_Init(p, &mainEncoder->props)); + RINOK(LzmaEnc_PrepareForLzma2(p->enc, inStream, LZMA2_KEEP_WINDOW_SIZE, + mainEncoder->alloc, mainEncoder->allocBig)); + for (;;) + { + size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; + res = Lzma2EncInt_EncodeSubblock(p, mainEncoder->outBuf, &packSize, outStream); + if (res != SZ_OK) + break; + packTotal += packSize; + res = Progress(progress, p->srcPos, packTotal); + if (res != SZ_OK) + break; + if (packSize == 0) + break; + } + LzmaEnc_Finish(p->enc); + if (res == SZ_OK) + { + Byte b = 0; + if (outStream->Write(outStream, &b, 1) != 1) + return SZ_ERROR_WRITE; + } + return res; +} + +#ifndef _7ZIP_ST + +typedef struct +{ + IMtCoderCallback funcTable; + CLzma2Enc *lzma2Enc; +} CMtCallbackImp; + +static SRes MtCallbackImp_Code(void *pp, unsigned index, Byte *dest, size_t *destSize, + const Byte *src, size_t srcSize, int finished) +{ + CMtCallbackImp *imp = (CMtCallbackImp *)pp; + CLzma2Enc *mainEncoder = imp->lzma2Enc; + CLzma2EncInt *p = &mainEncoder->coders[index]; + + SRes res = SZ_OK; + { + size_t destLim = *destSize; + *destSize = 0; + + if (srcSize != 0) + { + RINOK(Lzma2EncInt_Init(p, &mainEncoder->props)); + + RINOK(LzmaEnc_MemPrepare(p->enc, src, srcSize, LZMA2_KEEP_WINDOW_SIZE, + mainEncoder->alloc, mainEncoder->allocBig)); + + while (p->srcPos < srcSize) + { + size_t packSize = destLim - *destSize; + res = Lzma2EncInt_EncodeSubblock(p, dest + *destSize, &packSize, NULL); + if (res != SZ_OK) + break; + *destSize += packSize; + + if (packSize == 0) + { + res = SZ_ERROR_FAIL; + break; + } + + if (MtProgress_Set(&mainEncoder->mtCoder.mtProgress, index, p->srcPos, *destSize) != SZ_OK) + { + res = SZ_ERROR_PROGRESS; + break; + } + } + LzmaEnc_Finish(p->enc); + if (res != SZ_OK) + return res; + } + if (finished) + { + if (*destSize == destLim) + return SZ_ERROR_OUTPUT_EOF; + dest[(*destSize)++] = 0; + } + } + return res; +} + +#endif + +/* ---------- Lzma2Enc ---------- */ + +CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzma2Enc *p = (CLzma2Enc *)alloc->Alloc(alloc, sizeof(CLzma2Enc)); + if (p == 0) + return NULL; + Lzma2EncProps_Init(&p->props); + Lzma2EncProps_Normalize(&p->props); + p->outBuf = 0; + p->alloc = alloc; + p->allocBig = allocBig; + { + unsigned i; + for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) + p->coders[i].enc = 0; + } + #ifndef _7ZIP_ST + MtCoder_Construct(&p->mtCoder); + #endif + + return p; +} + +void Lzma2Enc_Destroy(CLzma2EncHandle pp) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + unsigned i; + for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) + { + CLzma2EncInt *t = &p->coders[i]; + if (t->enc) + { + LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); + t->enc = 0; + } + } + + #ifndef _7ZIP_ST + MtCoder_Destruct(&p->mtCoder); + #endif + + IAlloc_Free(p->alloc, p->outBuf); + IAlloc_Free(p->alloc, pp); +} + +SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + CLzmaEncProps lzmaProps = props->lzmaProps; + LzmaEncProps_Normalize(&lzmaProps); + if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) + return SZ_ERROR_PARAM; + p->props = *props; + Lzma2EncProps_Normalize(&p->props); + return SZ_OK; +} + +Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + unsigned i; + UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); + for (i = 0; i < 40; i++) + if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) + break; + return (Byte)i; +} + +SRes Lzma2Enc_Encode(CLzma2EncHandle pp, + ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + int i; + + for (i = 0; i < p->props.numBlockThreads; i++) + { + CLzma2EncInt *t = &p->coders[i]; + if (t->enc == NULL) + { + t->enc = LzmaEnc_Create(p->alloc); + if (t->enc == NULL) + return SZ_ERROR_MEM; + } + } + + #ifndef _7ZIP_ST + if (p->props.numBlockThreads <= 1) + #endif + return Lzma2Enc_EncodeMt1(&p->coders[0], p, outStream, inStream, progress); + + #ifndef _7ZIP_ST + + { + CMtCallbackImp mtCallback; + + mtCallback.funcTable.Code = MtCallbackImp_Code; + mtCallback.lzma2Enc = p; + + p->mtCoder.progress = progress; + p->mtCoder.inStream = inStream; + p->mtCoder.outStream = outStream; + p->mtCoder.alloc = p->alloc; + p->mtCoder.mtCallback = &mtCallback.funcTable; + + p->mtCoder.blockSize = p->props.blockSize; + p->mtCoder.destBlockSize = p->props.blockSize + (p->props.blockSize >> 10) + 16; + p->mtCoder.numThreads = p->props.numBlockThreads; + + return MtCoder_Code(&p->mtCoder); + } + #endif +} diff --git a/ext/VFS/ext/7z/src/Lzma2Enc.h b/ext/VFS/ext/7z/src/Lzma2Enc.h new file mode 100644 index 000000000..38830e548 --- /dev/null +++ b/ext/VFS/ext/7z/src/Lzma2Enc.h @@ -0,0 +1,66 @@ +/* Lzma2Enc.h -- LZMA2 Encoder +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZMA2_ENC_H +#define __LZMA2_ENC_H + +#include "LzmaEnc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + CLzmaEncProps lzmaProps; + size_t blockSize; + int numBlockThreads; + int numTotalThreads; +} CLzma2EncProps; + +void Lzma2EncProps_Init(CLzma2EncProps *p); +void Lzma2EncProps_Normalize(CLzma2EncProps *p); + +/* ---------- CLzmaEnc2Handle Interface ---------- */ + +/* Lzma2Enc_* functions can return the following exit codes: +Returns: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - Write callback error + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +typedef void * CLzma2EncHandle; + +CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig); +void Lzma2Enc_Destroy(CLzma2EncHandle p); +SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props); +Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p); +SRes Lzma2Enc_Encode(CLzma2EncHandle p, + ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress); + +/* ---------- One Call Interface ---------- */ + +/* Lzma2Encode +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +/* +SRes Lzma2Encode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); +*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/Lzma86.h b/ext/VFS/ext/7z/src/Lzma86.h new file mode 100644 index 000000000..6425bb8f5 --- /dev/null +++ b/ext/VFS/ext/7z/src/Lzma86.h @@ -0,0 +1,111 @@ +/* Lzma86.h -- LZMA + x86 (BCJ) Filter +2009-08-14 : Igor Pavlov : Public domain */ + +#ifndef __LZMA86_H +#define __LZMA86_H + +#include "Types.h" + +EXTERN_C_BEGIN + +#define LZMA86_SIZE_OFFSET (1 + 5) +#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8) + +/* +It's an example for LZMA + x86 Filter use. +You can use .lzma86 extension, if you write that stream to file. +.lzma86 header adds one additional byte to standard .lzma header. +.lzma86 header (14 bytes): + Offset Size Description + 0 1 = 0 - no filter, pure LZMA + = 1 - x86 filter + LZMA + 1 1 lc, lp and pb in encoded form + 2 4 dictSize (little endian) + 6 8 uncompressed size (little endian) + + +Lzma86_Encode +------------- +level - compression level: 0 <= level <= 9, the default value for "level" is 5. + +dictSize - The dictionary size in bytes. The maximum value is + 128 MB = (1 << 27) bytes for 32-bit version + 1 GB = (1 << 30) bytes for 64-bit version + The default value is 16 MB = (1 << 24) bytes, for level = 5. + It's recommended to use the dictionary that is larger than 4 KB and + that can be calculated as (1 << N) or (3 << N) sizes. + For better compression ratio dictSize must be >= inSize. + +filterMode: + SZ_FILTER_NO - no Filter + SZ_FILTER_YES - x86 Filter + SZ_FILTER_AUTO - it tries both alternatives to select best. + Encoder will use 2 or 3 passes: + 2 passes when FILTER_NO provides better compression. + 3 passes when FILTER_YES provides better compression. + +Lzma86Encode allocates Data with MyAlloc functions. +RAM Requirements for compressing: + RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize + filterMode FilterBlockSize + SZ_FILTER_NO 0 + SZ_FILTER_YES inSize + SZ_FILTER_AUTO inSize + + +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +enum ESzFilterMode +{ + SZ_FILTER_NO, + SZ_FILTER_YES, + SZ_FILTER_AUTO +}; + +SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, + int level, UInt32 dictSize, int filterMode); + + +/* +Lzma86_GetUnpackSize: + In: + src - input data + srcLen - input data size + Out: + unpackSize - size of uncompressed stream + Return code: + SZ_OK - OK + SZ_ERROR_INPUT_EOF - Error in headers +*/ + +SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize); + +/* +Lzma86_Decode: + In: + dest - output data + destLen - output data size + src - input data + srcLen - input data size + Out: + destLen - processed output size + srcLen - processed input size + Return code: + SZ_OK - OK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - unsupported file + SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer +*/ + +SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen); + +EXTERN_C_END + +#endif diff --git a/ext/VFS/ext/7z/src/Lzma86Dec.c b/ext/VFS/ext/7z/src/Lzma86Dec.c new file mode 100644 index 000000000..760a447c8 --- /dev/null +++ b/ext/VFS/ext/7z/src/Lzma86Dec.c @@ -0,0 +1,56 @@ +/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder +2009-08-14 : Igor Pavlov : Public domain */ + +#include "Lzma86.h" + +#include "Alloc.h" +#include "Bra.h" +#include "LzmaDec.h" + +static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } +static void SzFree(void *p, void *address) { p = p; MyFree(address); } + +SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize) +{ + unsigned i; + if (srcLen < LZMA86_HEADER_SIZE) + return SZ_ERROR_INPUT_EOF; + *unpackSize = 0; + for (i = 0; i < sizeof(UInt64); i++) + *unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i); + return SZ_OK; +} + +SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen) +{ + ISzAlloc g_Alloc = { SzAlloc, SzFree }; + SRes res; + int useFilter; + SizeT inSizePure; + ELzmaStatus status; + + if (*srcLen < LZMA86_HEADER_SIZE) + return SZ_ERROR_INPUT_EOF; + + useFilter = src[0]; + + if (useFilter > 1) + { + *destLen = 0; + return SZ_ERROR_UNSUPPORTED; + } + + inSizePure = *srcLen - LZMA86_HEADER_SIZE; + res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure, + src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc); + *srcLen = inSizePure + LZMA86_HEADER_SIZE; + if (res != SZ_OK) + return res; + if (useFilter == 1) + { + UInt32 x86State; + x86_Convert_Init(x86State); + x86_Convert(dest, *destLen, 0, &x86State, 0); + } + return SZ_OK; +} diff --git a/ext/VFS/ext/7z/src/Lzma86Enc.c b/ext/VFS/ext/7z/src/Lzma86Enc.c new file mode 100644 index 000000000..a29c605b4 --- /dev/null +++ b/ext/VFS/ext/7z/src/Lzma86Enc.c @@ -0,0 +1,108 @@ +/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder +2009-08-14 : Igor Pavlov : Public domain */ + +#include + +#include "Lzma86.h" + +#include "Alloc.h" +#include "Bra.h" +#include "LzmaEnc.h" + +#define SZE_OUT_OVERFLOW SZE_DATA_ERROR + +static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } +static void SzFree(void *p, void *address) { p = p; MyFree(address); } + +int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, + int level, UInt32 dictSize, int filterMode) +{ + ISzAlloc g_Alloc = { SzAlloc, SzFree }; + size_t outSize2 = *destLen; + Byte *filteredStream; + Bool useFilter; + int mainResult = SZ_ERROR_OUTPUT_EOF; + CLzmaEncProps props; + LzmaEncProps_Init(&props); + props.level = level; + props.dictSize = dictSize; + + *destLen = 0; + if (outSize2 < LZMA86_HEADER_SIZE) + return SZ_ERROR_OUTPUT_EOF; + + { + int i; + UInt64 t = srcLen; + for (i = 0; i < 8; i++, t >>= 8) + dest[LZMA86_SIZE_OFFSET + i] = (Byte)t; + } + + filteredStream = 0; + useFilter = (filterMode != SZ_FILTER_NO); + if (useFilter) + { + if (srcLen != 0) + { + filteredStream = (Byte *)MyAlloc(srcLen); + if (filteredStream == 0) + return SZ_ERROR_MEM; + memcpy(filteredStream, src, srcLen); + } + { + UInt32 x86State; + x86_Convert_Init(x86State); + x86_Convert(filteredStream, srcLen, 0, &x86State, 1); + } + } + + { + size_t minSize = 0; + Bool bestIsFiltered = False; + + /* passes for SZ_FILTER_AUTO: + 0 - BCJ + LZMA + 1 - LZMA + 2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better. + */ + int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1; + + int i; + for (i = 0; i < numPasses; i++) + { + size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE; + size_t outPropsSize = 5; + SRes curRes; + Bool curModeIsFiltered = (numPasses > 1 && i == numPasses - 1); + if (curModeIsFiltered && !bestIsFiltered) + break; + if (useFilter && i == 0) + curModeIsFiltered = True; + + curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed, + curModeIsFiltered ? filteredStream : src, srcLen, + &props, dest + 1, &outPropsSize, 0, + NULL, &g_Alloc, &g_Alloc); + + if (curRes != SZ_ERROR_OUTPUT_EOF) + { + if (curRes != SZ_OK) + { + mainResult = curRes; + break; + } + if (outSizeProcessed <= minSize || mainResult != SZ_OK) + { + minSize = outSizeProcessed; + bestIsFiltered = curModeIsFiltered; + mainResult = SZ_OK; + } + } + } + dest[0] = (bestIsFiltered ? 1 : 0); + *destLen = LZMA86_HEADER_SIZE + minSize; + } + if (useFilter) + MyFree(filteredStream); + return mainResult; +} diff --git a/ext/VFS/ext/7z/src/LzmaDec.c b/ext/VFS/ext/7z/src/LzmaDec.c new file mode 100644 index 000000000..4fdc11d4b --- /dev/null +++ b/ext/VFS/ext/7z/src/LzmaDec.c @@ -0,0 +1,999 @@ +/* LzmaDec.c -- LZMA Decoder +2009-09-20 : Igor Pavlov : Public domain */ + +#include "LzmaDec.h" + +#include + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_INIT_SIZE 5 + +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p); i = (i + i); A0; } else \ + { UPDATE_1(p); i = (i + i) + 1; A1; } +#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) + +#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define _LZMA_SIZE_OPT */ + +#ifdef _LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + i -= 0x40; } +#endif + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK; i = (i + i); A0; } else \ + { UPDATE_1_CHECK; i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +#define LZMA_DIC_MIN (1 << 12) + +/* First LZMA-symbol is always decoded. +And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization +Out: + Result: + SZ_OK - OK + SZ_ERROR_DATA - Error + p->remainLen: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished + = kMatchSpecLenStart + 1 : Flush marker + = kMatchSpecLenStart + 2 : State Init Marker +*/ + +static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = p->probs; + + unsigned state = p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; + unsigned lc = p->prop.lc; + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = processedPos & pbMask; + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (checkDicSize != 0 || processedPos != 0) + prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + + if (state < kNumLitStates) + { + state -= (state < 4) ? state : 3; + symbol = 1; + do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned offs = 0x100; + state -= (state < 10) ? 3 : 6; + symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + dic[dicPos++] = (Byte)symbol; + processedPos++; + continue; + } + else + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = (1 << kLenNumMidBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, limit, len); + len += offset; + } + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + int numDirectBits = (int)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos + distance - posSlot - 1; + { + UInt32 mask = 1; + unsigned i = 1; + do + { + GET_BIT2(prob + i, i, ; , distance |= mask); + mask <<= 1; + } + while (--numDirectBits != 0); + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits != 0); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + GET_BIT2(prob + i, i, ; , distance |= 1); + GET_BIT2(prob + i, i, ; , distance |= 2); + GET_BIT2(prob + i, i, ; , distance |= 4); + GET_BIT2(prob + i, i, ; , distance |= 8); + } + if (distance == (UInt32)0xFFFFFFFF) + { + len += kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + if (checkDicSize == 0) + { + if (distance >= processedPos) + return SZ_ERROR_DATA; + } + else if (distance >= checkDicSize) + return SZ_ERROR_DATA; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + } + + len += kMatchMinLen; + + if (limit == dicPos) + return SZ_ERROR_DATA; + { + SizeT rem = limit - dicPos; + unsigned curLen = ((rem < len) ? (unsigned)rem : len); + SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + + processedPos += curLen; + + len -= curLen; + if (pos + curLen <= dicBufSize) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = state; + + return SZ_OK; +} + +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte *dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = p->remainLen; + UInt32 rep0 = p->reps[0]; + if (limit - dicPos < len) + len = (unsigned)(limit - dicPos); + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += len; + p->remainLen -= len; + while (len-- != 0) + { + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } +} + +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); + if (p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + if (p->remainLen > kMatchSpecLenStart) + { + p->remainLen = kMatchSpecLenStart; + } + return 0; +} + +typedef enum +{ + DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = buf + inSize; + CLzmaProb *probs = p->probs; + unsigned state = p->state; + ELzmaDummy res; + + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += (LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumMidBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits != 0); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + do + { + GET_BIT_CHECK(prob + i, i); + } + while (--numDirectBits != 0); + } + } + } + } + } + NORMALIZE_CHECK; + return res; +} + + +static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) +{ + p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +{ + p->needFlush = 1; + p->remainLen = 0; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->needInitState = 1; + } + if (initState) + p->needInitState = 1; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + +static void LzmaDec_InitStateReal(CLzmaDec *p) +{ + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); + UInt32 i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + p->needInitState = 0; +} + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + LzmaDec_WriteRem(p, dicLimit); + + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow; + + if (p->needFlush != 0) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + + LzmaDec_InitRc(p, p->tempBuf); + p->tempBufSize = 0; + } + + checkEndMarkNow = 0; + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->needInitState) + LzmaDec_InitStateReal(p); + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte *bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + (*srcLen) += lookAhead; + src += lookAhead; + inSize -= lookAhead; + p->tempBufSize = 0; + } + } + if (p->code == 0) + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; +} + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->probs); + p->probs = 0; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->dic); + p->dic = 0; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = d % 9; + d /= 9; + p->pb = d / 5; + p->lp = d % 5; + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (p->probs == 0 || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); + p->numProbs = numProbs; + if (p->probs == 0) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + dicBufSize = propNew.dicSize; + if (p->dic == 0 || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); + if (p->dic == 0) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc) +{ + CLzmaDec p; + SRes res; + SizeT inSize = *srcLen; + SizeT outSize = *destLen; + *srcLen = *destLen = 0; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + + LzmaDec_Construct(&p); + res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); + if (res != 0) + return res; + p.dic = dest; + p.dicBufSize = outSize; + + LzmaDec_Init(&p); + + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + + (*destLen) = p.dicPos; + LzmaDec_FreeProbs(&p, alloc); + return res; +} diff --git a/ext/VFS/ext/7z/src/LzmaDec.h b/ext/VFS/ext/7z/src/LzmaDec.h new file mode 100644 index 000000000..6741a644b --- /dev/null +++ b/ext/VFS/ext/7z/src/LzmaDec.h @@ -0,0 +1,231 @@ +/* LzmaDec.h -- LZMA Decoder +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_DEC_H +#define __LZMA_DEC_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* #define _LZMA_PROB32 */ +/* _LZMA_PROB32 can increase the speed on some CPUs, + but memory usage for CLzmaDec::probs will be doubled in that case */ + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaProps +{ + unsigned lc, lp, pb; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); + + +/* ---------- LZMA Decoder state ---------- */ + +/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. + Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ + +#define LZMA_REQUIRED_INPUT_MAX 20 + +typedef struct +{ + CLzmaProps prop; + CLzmaProb *probs; + Byte *dic; + const Byte *buf; + UInt32 range, code; + SizeT dicPos; + SizeT dicBufSize; + UInt32 processedPos; + UInt32 checkDicSize; + unsigned state; + UInt32 reps[4]; + unsigned remainLen; + int needFlush; + int needInitState; + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; +} CLzmaDec; + +#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +void LzmaDec_Init(CLzmaDec *p); + +/* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ + +typedef enum +{ + LZMA_FINISH_ANY, /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ +} ELzmaFinishMode; + +/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! + + You must use LZMA_FINISH_END, when you know that current output buffer + covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. + + If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, + and output value of destLen will be less than output buffer size limit. + You can check status result also. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + +typedef enum +{ + LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ +} ELzmaStatus; + +/* ELzmaStatus is used only as output value for function call */ + + +/* ---------- Interfaces ---------- */ + +/* There are 3 levels of interfaces: + 1) Dictionary Interface + 2) Buffer Interface + 3) One Call Interface + You can select any of these interfaces, but don't mix functions from different + groups for same object. */ + + +/* There are two variants to allocate state for Dictionary Interface: + 1) LzmaDec_Allocate / LzmaDec_Free + 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs + You can use variant 2, if you set dictionary buffer manually. + For Buffer Interface you must always use variant 1. + +LzmaDec_Allocate* can return: + SZ_OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); + +SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); + +/* ---------- Dictionary Interface ---------- */ + +/* You can use it, if you want to eliminate the overhead for data copying from + dictionary to some other external buffer. + You must work with CLzmaDec variables directly in this interface. + + STEPS: + LzmaDec_Constr() + LzmaDec_Allocate() + for (each new stream) + { + LzmaDec_Init() + while (it needs more decompression) + { + LzmaDec_DecodeToDic() + use data from CLzmaDec::dic and update CLzmaDec::dicPos + } + } + LzmaDec_Free() +*/ + +/* LzmaDec_DecodeToDic + + The decoding to internal dictionary buffer (CLzmaDec::dic). + You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! + +finishMode: + It has meaning only if the decoding reaches output limit (dicLimit). + LZMA_FINISH_ANY - Decode just dicLimit bytes. + LZMA_FINISH_END - Stream must be finished after dicLimit. + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error +*/ + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- Buffer Interface ---------- */ + +/* It's zlib-like interface. + See LzmaDec_DecodeToDic description for information about STEPS and return results, + but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need + to work with CLzmaDec variables manually. + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). +*/ + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/LzmaEnc.c b/ext/VFS/ext/7z/src/LzmaEnc.c new file mode 100644 index 000000000..1f5dcb58f --- /dev/null +++ b/ext/VFS/ext/7z/src/LzmaEnc.c @@ -0,0 +1,2268 @@ +/* LzmaEnc.c -- LZMA Encoder +2009-11-24 : Igor Pavlov : Public domain */ + +#include + +/* #define SHOW_STAT */ +/* #define SHOW_STAT2 */ + +#if defined(SHOW_STAT) || defined(SHOW_STAT2) +#include +#endif + +#include "LzmaEnc.h" + +#include "LzFind.h" +#ifndef _7ZIP_ST +#include "LzFindMt.h" +#endif + +#ifdef SHOW_STAT +static int ttt = 0; +#endif + +#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) + +#define kBlockSize (9 << 10) +#define kUnpackBlockSize (1 << 18) +#define kMatchArraySize (1 << 21) +#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) + +#define kNumMaxDirectBits (31) + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 +#define kProbInitValue (kBitModelTotal >> 1) + +#define kNumMoveReducingBits 4 +#define kNumBitPriceShiftBits 4 +#define kBitPrice (1 << kNumBitPriceShiftBits) + +void LzmaEncProps_Init(CLzmaEncProps *p) +{ + p->level = 5; + p->dictSize = p->mc = 0; + p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; + p->writeEndMark = 0; +} + +void LzmaEncProps_Normalize(CLzmaEncProps *p) +{ + int level = p->level; + if (level < 0) level = 5; + p->level = level; + if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); + if (p->lc < 0) p->lc = 3; + if (p->lp < 0) p->lp = 0; + if (p->pb < 0) p->pb = 2; + if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); + if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); + if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); + if (p->numHashBytes < 0) p->numHashBytes = 4; + if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + if (p->numThreads < 0) + p->numThreads = + #ifndef _7ZIP_ST + ((p->btMode && p->algo) ? 2 : 1); + #else + 1; + #endif +} + +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) +{ + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + return props.dictSize; +} + +/* #define LZMA_LOG_BSR */ +/* Define it for Intel's CPU */ + + +#ifdef LZMA_LOG_BSR + +#define kDicLogSizeMaxCompress 30 + +#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } + +UInt32 GetPosSlot1(UInt32 pos) +{ + UInt32 res; + BSR2_RET(pos, res); + return res; +} +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } + +#else + +#define kNumLogBits (9 + (int)sizeof(size_t) / 2) +#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + +void LzmaEnc_FastPosInit(Byte *g_FastPos) +{ + int c = 2, slotFast; + g_FastPos[0] = 0; + g_FastPos[1] = 1; + + for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) + { + UInt32 k = (1 << ((slotFast >> 1) - 1)); + UInt32 j; + for (j = 0; j < k; j++, c++) + g_FastPos[c] = (Byte)slotFast; + } +} + +#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ + res = p->g_FastPos[pos >> i] + (i * 2); } +/* +#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ + p->g_FastPos[pos >> 6] + 12 : \ + p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } +*/ + +#define GetPosSlot1(pos) p->g_FastPos[pos] +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } + +#endif + + +#define LZMA_NUM_REPS 4 + +typedef unsigned CState; + +typedef struct +{ + UInt32 price; + + CState state; + int prev1IsChar; + int prev2; + + UInt32 posPrev2; + UInt32 backPrev2; + + UInt32 posPrev; + UInt32 backPrev; + UInt32 backs[LZMA_NUM_REPS]; +} COptimal; + +#define kNumOpts (1 << 12) + +#define kNumLenToPosStates 4 +#define kNumPosSlotBits 6 +#define kDicLogSizeMin 0 +#define kDicLogSizeMax 32 +#define kDistTableSizeMax (kDicLogSizeMax * 2) + + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) +#define kAlignMask (kAlignTableSize - 1) + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) + +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + +#define LZMA_PB_MAX 4 +#define LZMA_LC_MAX 8 +#define LZMA_LP_MAX 4 + +#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) + + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define LZMA_MATCH_LEN_MIN 2 +#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) + +#define kNumStates 12 + +typedef struct +{ + CLzmaProb choice; + CLzmaProb choice2; + CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; + CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; + CLzmaProb high[kLenNumHighSymbols]; +} CLenEnc; + +typedef struct +{ + CLenEnc p; + UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; + UInt32 tableSize; + UInt32 counters[LZMA_NUM_PB_STATES_MAX]; +} CLenPriceEnc; + +typedef struct +{ + UInt32 range; + Byte cache; + UInt64 low; + UInt64 cacheSize; + Byte *buf; + Byte *bufLim; + Byte *bufBase; + ISeqOutStream *outStream; + UInt64 processed; + SRes res; +} CRangeEnc; + +typedef struct +{ + CLzmaProb *litProbs; + + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + + CLenPriceEnc lenEnc; + CLenPriceEnc repLenEnc; + + UInt32 reps[LZMA_NUM_REPS]; + UInt32 state; +} CSaveState; + +typedef struct +{ + IMatchFinder matchFinder; + void *matchFinderObj; + + #ifndef _7ZIP_ST + Bool mtMode; + CMatchFinderMt matchFinderMt; + #endif + + CMatchFinder matchFinderBase; + + #ifndef _7ZIP_ST + Byte pad[128]; + #endif + + UInt32 optimumEndIndex; + UInt32 optimumCurrentIndex; + + UInt32 longestMatchLength; + UInt32 numPairs; + UInt32 numAvail; + COptimal opt[kNumOpts]; + + #ifndef LZMA_LOG_BSR + Byte g_FastPos[1 << kNumLogBits]; + #endif + + UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; + UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; + UInt32 numFastBytes; + UInt32 additionalOffset; + UInt32 reps[LZMA_NUM_REPS]; + UInt32 state; + + UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; + UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; + UInt32 alignPrices[kAlignTableSize]; + UInt32 alignPriceCount; + + UInt32 distTableSize; + + unsigned lc, lp, pb; + unsigned lpMask, pbMask; + + CLzmaProb *litProbs; + + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + + CLenPriceEnc lenEnc; + CLenPriceEnc repLenEnc; + + unsigned lclp; + + Bool fastMode; + + CRangeEnc rc; + + Bool writeEndMark; + UInt64 nowPos64; + UInt32 matchPriceCount; + Bool finished; + Bool multiThread; + + SRes result; + UInt32 dictSize; + UInt32 matchFinderCycles; + + int needInit; + + CSaveState saveState; +} CLzmaEnc; + +void LzmaEnc_SaveState(CLzmaEncHandle pp) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CSaveState *dest = &p->saveState; + int i; + dest->lenEnc = p->lenEnc; + dest->repLenEnc = p->repLenEnc; + dest->state = p->state; + + for (i = 0; i < kNumStates; i++) + { + memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); + memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); + } + for (i = 0; i < kNumLenToPosStates; i++) + memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); + memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); + memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); + memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); + memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); + memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); + memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); + memcpy(dest->reps, p->reps, sizeof(p->reps)); + memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); +} + +void LzmaEnc_RestoreState(CLzmaEncHandle pp) +{ + CLzmaEnc *dest = (CLzmaEnc *)pp; + const CSaveState *p = &dest->saveState; + int i; + dest->lenEnc = p->lenEnc; + dest->repLenEnc = p->repLenEnc; + dest->state = p->state; + + for (i = 0; i < kNumStates; i++) + { + memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); + memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); + } + for (i = 0; i < kNumLenToPosStates; i++) + memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); + memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); + memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); + memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); + memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); + memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); + memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); + memcpy(dest->reps, p->reps, sizeof(p->reps)); + memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); +} + +SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + + if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || + props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30)) + return SZ_ERROR_PARAM; + p->dictSize = props.dictSize; + p->matchFinderCycles = props.mc; + { + unsigned fb = props.fb; + if (fb < 5) + fb = 5; + if (fb > LZMA_MATCH_LEN_MAX) + fb = LZMA_MATCH_LEN_MAX; + p->numFastBytes = fb; + } + p->lc = props.lc; + p->lp = props.lp; + p->pb = props.pb; + p->fastMode = (props.algo == 0); + p->matchFinderBase.btMode = props.btMode; + { + UInt32 numHashBytes = 4; + if (props.btMode) + { + if (props.numHashBytes < 2) + numHashBytes = 2; + else if (props.numHashBytes < 4) + numHashBytes = props.numHashBytes; + } + p->matchFinderBase.numHashBytes = numHashBytes; + } + + p->matchFinderBase.cutValue = props.mc; + + p->writeEndMark = props.writeEndMark; + + #ifndef _7ZIP_ST + /* + if (newMultiThread != _multiThread) + { + ReleaseMatchFinder(); + _multiThread = newMultiThread; + } + */ + p->multiThread = (props.numThreads > 1); + #endif + + return SZ_OK; +} + +static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; +static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; +static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; +static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + +#define IsCharState(s) ((s) < 7) + +#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) + +#define kInfinityPrice (1 << 30) + +static void RangeEnc_Construct(CRangeEnc *p) +{ + p->outStream = 0; + p->bufBase = 0; +} + +#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) + +#define RC_BUF_SIZE (1 << 16) +static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) +{ + if (p->bufBase == 0) + { + p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); + if (p->bufBase == 0) + return 0; + p->bufLim = p->bufBase + RC_BUF_SIZE; + } + return 1; +} + +static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->bufBase); + p->bufBase = 0; +} + +static void RangeEnc_Init(CRangeEnc *p) +{ + /* Stream.Init(); */ + p->low = 0; + p->range = 0xFFFFFFFF; + p->cacheSize = 1; + p->cache = 0; + + p->buf = p->bufBase; + + p->processed = 0; + p->res = SZ_OK; +} + +static void RangeEnc_FlushStream(CRangeEnc *p) +{ + size_t num; + if (p->res != SZ_OK) + return; + num = p->buf - p->bufBase; + if (num != p->outStream->Write(p->outStream, p->bufBase, num)) + p->res = SZ_ERROR_WRITE; + p->processed += num; + p->buf = p->bufBase; +} + +static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) +{ + if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) + { + Byte temp = p->cache; + do + { + Byte *buf = p->buf; + *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); + p->buf = buf; + if (buf == p->bufLim) + RangeEnc_FlushStream(p); + temp = 0xFF; + } + while (--p->cacheSize != 0); + p->cache = (Byte)((UInt32)p->low >> 24); + } + p->cacheSize++; + p->low = (UInt32)p->low << 8; +} + +static void RangeEnc_FlushData(CRangeEnc *p) +{ + int i; + for (i = 0; i < 5; i++) + RangeEnc_ShiftLow(p); +} + +static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) +{ + do + { + p->range >>= 1; + p->low += p->range & (0 - ((value >> --numBits) & 1)); + if (p->range < kTopValue) + { + p->range <<= 8; + RangeEnc_ShiftLow(p); + } + } + while (numBits != 0); +} + +static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) +{ + UInt32 ttt = *prob; + UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; + if (symbol == 0) + { + p->range = newBound; + ttt += (kBitModelTotal - ttt) >> kNumMoveBits; + } + else + { + p->low += newBound; + p->range -= newBound; + ttt -= ttt >> kNumMoveBits; + } + *prob = (CLzmaProb)ttt; + if (p->range < kTopValue) + { + p->range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) +{ + symbol |= 0x100; + do + { + RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); + symbol <<= 1; + } + while (symbol < 0x10000); +} + +static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) +{ + UInt32 offs = 0x100; + symbol |= 0x100; + do + { + matchByte <<= 1; + RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); + symbol <<= 1; + offs &= ~(matchByte ^ symbol); + } + while (symbol < 0x10000); +} + +void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) +{ + UInt32 i; + for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) + { + const int kCyclesBits = kNumBitPriceShiftBits; + UInt32 w = i; + UInt32 bitCount = 0; + int j; + for (j = 0; j < kCyclesBits; j++) + { + w = w * w; + bitCount <<= 1; + while (w >= ((UInt32)1 << 16)) + { + w >>= 1; + bitCount++; + } + } + ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); + } +} + + +#define GET_PRICE(prob, symbol) \ + p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICEa(prob, symbol) \ + ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + +#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + +static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + symbol |= 0x100; + do + { + price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); + symbol <<= 1; + } + while (symbol < 0x10000); + return price; +} + +static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) +{ + UInt32 price = 0; + UInt32 offs = 0x100; + symbol |= 0x100; + do + { + matchByte <<= 1; + price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); + symbol <<= 1; + offs &= ~(matchByte ^ symbol); + } + while (symbol < 0x10000); + return price; +} + + +static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) +{ + UInt32 m = 1; + int i; + for (i = numBitLevels; i != 0;) + { + UInt32 bit; + i--; + bit = (symbol >> i) & 1; + RangeEnc_EncodeBit(rc, probs + m, bit); + m = (m << 1) | bit; + } +} + +static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) +{ + UInt32 m = 1; + int i; + for (i = 0; i < numBitLevels; i++) + { + UInt32 bit = symbol & 1; + RangeEnc_EncodeBit(rc, probs + m, bit); + m = (m << 1) | bit; + symbol >>= 1; + } +} + +static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + symbol |= (1 << numBitLevels); + while (symbol != 1) + { + price += GET_PRICEa(probs[symbol >> 1], symbol & 1); + symbol >>= 1; + } + return price; +} + +static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + UInt32 m = 1; + int i; + for (i = numBitLevels; i != 0; i--) + { + UInt32 bit = symbol & 1; + symbol >>= 1; + price += GET_PRICEa(probs[m], bit); + m = (m << 1) | bit; + } + return price; +} + + +static void LenEnc_Init(CLenEnc *p) +{ + unsigned i; + p->choice = p->choice2 = kProbInitValue; + for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) + p->low[i] = kProbInitValue; + for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) + p->mid[i] = kProbInitValue; + for (i = 0; i < kLenNumHighSymbols; i++) + p->high[i] = kProbInitValue; +} + +static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) +{ + if (symbol < kLenNumLowSymbols) + { + RangeEnc_EncodeBit(rc, &p->choice, 0); + RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); + } + else + { + RangeEnc_EncodeBit(rc, &p->choice, 1); + if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) + { + RangeEnc_EncodeBit(rc, &p->choice2, 0); + RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); + } + else + { + RangeEnc_EncodeBit(rc, &p->choice2, 1); + RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); + } + } +} + +static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) +{ + UInt32 a0 = GET_PRICE_0a(p->choice); + UInt32 a1 = GET_PRICE_1a(p->choice); + UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); + UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); + UInt32 i = 0; + for (i = 0; i < kLenNumLowSymbols; i++) + { + if (i >= numSymbols) + return; + prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); + } + for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) + { + if (i >= numSymbols) + return; + prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); + } + for (; i < numSymbols; i++) + prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); +} + +static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) +{ + LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); + p->counters[posState] = p->tableSize; +} + +static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) +{ + UInt32 posState; + for (posState = 0; posState < numPosStates; posState++) + LenPriceEnc_UpdateTable(p, posState, ProbPrices); +} + +static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) +{ + LenEnc_Encode(&p->p, rc, symbol, posState); + if (updatePrice) + if (--p->counters[posState] == 0) + LenPriceEnc_UpdateTable(p, posState, ProbPrices); +} + + + + +static void MovePos(CLzmaEnc *p, UInt32 num) +{ + #ifdef SHOW_STAT + ttt += num; + printf("\n MovePos %d", num); + #endif + if (num != 0) + { + p->additionalOffset += num; + p->matchFinder.Skip(p->matchFinderObj, num); + } +} + +static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) +{ + UInt32 lenRes = 0, numPairs; + p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); + numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); + #ifdef SHOW_STAT + printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); + ttt++; + { + UInt32 i; + for (i = 0; i < numPairs; i += 2) + printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); + } + #endif + if (numPairs > 0) + { + lenRes = p->matches[numPairs - 2]; + if (lenRes == p->numFastBytes) + { + const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + UInt32 distance = p->matches[numPairs - 1] + 1; + UInt32 numAvail = p->numAvail; + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + { + const Byte *pby2 = pby - distance; + for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); + } + } + } + p->additionalOffset++; + *numDistancePairsRes = numPairs; + return lenRes; +} + + +#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; +#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; +#define IsShortRep(p) ((p)->backPrev == 0) + +static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) +{ + return + GET_PRICE_0(p->isRepG0[state]) + + GET_PRICE_0(p->isRep0Long[state][posState]); +} + +static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) +{ + UInt32 price; + if (repIndex == 0) + { + price = GET_PRICE_0(p->isRepG0[state]); + price += GET_PRICE_1(p->isRep0Long[state][posState]); + } + else + { + price = GET_PRICE_1(p->isRepG0[state]); + if (repIndex == 1) + price += GET_PRICE_0(p->isRepG1[state]); + else + { + price += GET_PRICE_1(p->isRepG1[state]); + price += GET_PRICE(p->isRepG2[state], repIndex - 2); + } + } + return price; +} + +static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) +{ + return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + + GetPureRepPrice(p, repIndex, state, posState); +} + +static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) +{ + UInt32 posMem = p->opt[cur].posPrev; + UInt32 backMem = p->opt[cur].backPrev; + p->optimumEndIndex = cur; + do + { + if (p->opt[cur].prev1IsChar) + { + MakeAsChar(&p->opt[posMem]) + p->opt[posMem].posPrev = posMem - 1; + if (p->opt[cur].prev2) + { + p->opt[posMem - 1].prev1IsChar = False; + p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; + p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; + } + } + { + UInt32 posPrev = posMem; + UInt32 backCur = backMem; + + backMem = p->opt[posPrev].backPrev; + posMem = p->opt[posPrev].posPrev; + + p->opt[posPrev].backPrev = backCur; + p->opt[posPrev].posPrev = cur; + cur = posPrev; + } + } + while (cur != 0); + *backRes = p->opt[0].backPrev; + p->optimumCurrentIndex = p->opt[0].posPrev; + return p->optimumCurrentIndex; +} + +#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) + +static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) +{ + UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; + UInt32 matchPrice, repMatchPrice, normalMatchPrice; + UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; + UInt32 *matches; + const Byte *data; + Byte curByte, matchByte; + if (p->optimumEndIndex != p->optimumCurrentIndex) + { + const COptimal *opt = &p->opt[p->optimumCurrentIndex]; + UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; + *backRes = opt->backPrev; + p->optimumCurrentIndex = opt->posPrev; + return lenRes; + } + p->optimumCurrentIndex = p->optimumEndIndex = 0; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLength; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + if (numAvail < 2) + { + *backRes = (UInt32)(-1); + return 1; + } + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + repMaxIndex = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 lenTest; + const Byte *data2; + reps[i] = p->reps[i]; + data2 = data - (reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + { + repLens[i] = 0; + continue; + } + for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); + repLens[i] = lenTest; + if (lenTest > repLens[repMaxIndex]) + repMaxIndex = i; + } + if (repLens[repMaxIndex] >= p->numFastBytes) + { + UInt32 lenRes; + *backRes = repMaxIndex; + lenRes = repLens[repMaxIndex]; + MovePos(p, lenRes - 1); + return lenRes; + } + + matches = p->matches; + if (mainLen >= p->numFastBytes) + { + *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; + MovePos(p, mainLen - 1); + return mainLen; + } + curByte = *data; + matchByte = *(data - (reps[0] + 1)); + + if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) + { + *backRes = (UInt32)-1; + return 1; + } + + p->opt[0].state = (CState)p->state; + + posState = (position & p->pbMask); + + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + + (!IsCharState(p->state) ? + LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + } + + MakeAsChar(&p->opt[1]); + + matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); + + if (matchByte == curByte) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); + if (shortRepPrice < p->opt[1].price) + { + p->opt[1].price = shortRepPrice; + MakeAsShortRep(&p->opt[1]); + } + } + lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); + + if (lenEnd < 2) + { + *backRes = p->opt[1].backPrev; + return 1; + } + + p->opt[1].posPrev = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + p->opt[0].backs[i] = reps[i]; + + len = lenEnd; + do + p->opt[len--].price = kInfinityPrice; + while (len >= 2); + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 repLen = repLens[i]; + UInt32 price; + if (repLen < 2) + continue; + price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); + do + { + UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; + COptimal *opt = &p->opt[repLen]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = 0; + opt->backPrev = i; + opt->prev1IsChar = False; + } + } + while (--repLen >= 2); + } + + normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); + + len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); + if (len <= mainLen) + { + UInt32 offs = 0; + while (len > matches[offs]) + offs += 2; + for (; ; len++) + { + COptimal *opt; + UInt32 distance = matches[offs + 1]; + + UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; + UInt32 lenToPosState = GetLenToPosState(len); + if (distance < kNumFullDistances) + curAndLenPrice += p->distancesPrices[lenToPosState][distance]; + else + { + UInt32 slot; + GetPosSlot2(distance, slot); + curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; + } + opt = &p->opt[len]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = 0; + opt->backPrev = distance + LZMA_NUM_REPS; + opt->prev1IsChar = False; + } + if (len == matches[offs]) + { + offs += 2; + if (offs == numPairs) + break; + } + } + } + + cur = 0; + + #ifdef SHOW_STAT2 + if (position >= 0) + { + unsigned i; + printf("\n pos = %4X", position); + for (i = cur; i <= lenEnd; i++) + printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); + } + #endif + + for (;;) + { + UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; + UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; + Bool nextIsChar; + Byte curByte, matchByte; + const Byte *data; + COptimal *curOpt; + COptimal *nextOpt; + + cur++; + if (cur == lenEnd) + return Backward(p, backRes, cur); + + newLen = ReadMatchDistances(p, &numPairs); + if (newLen >= p->numFastBytes) + { + p->numPairs = numPairs; + p->longestMatchLength = newLen; + return Backward(p, backRes, cur); + } + position++; + curOpt = &p->opt[cur]; + posPrev = curOpt->posPrev; + if (curOpt->prev1IsChar) + { + posPrev--; + if (curOpt->prev2) + { + state = p->opt[curOpt->posPrev2].state; + if (curOpt->backPrev2 < LZMA_NUM_REPS) + state = kRepNextStates[state]; + else + state = kMatchNextStates[state]; + } + else + state = p->opt[posPrev].state; + state = kLiteralNextStates[state]; + } + else + state = p->opt[posPrev].state; + if (posPrev == cur - 1) + { + if (IsShortRep(curOpt)) + state = kShortRepNextStates[state]; + else + state = kLiteralNextStates[state]; + } + else + { + UInt32 pos; + const COptimal *prevOpt; + if (curOpt->prev1IsChar && curOpt->prev2) + { + posPrev = curOpt->posPrev2; + pos = curOpt->backPrev2; + state = kRepNextStates[state]; + } + else + { + pos = curOpt->backPrev; + if (pos < LZMA_NUM_REPS) + state = kRepNextStates[state]; + else + state = kMatchNextStates[state]; + } + prevOpt = &p->opt[posPrev]; + if (pos < LZMA_NUM_REPS) + { + UInt32 i; + reps[0] = prevOpt->backs[pos]; + for (i = 1; i <= pos; i++) + reps[i] = prevOpt->backs[i - 1]; + for (; i < LZMA_NUM_REPS; i++) + reps[i] = prevOpt->backs[i]; + } + else + { + UInt32 i; + reps[0] = (pos - LZMA_NUM_REPS); + for (i = 1; i < LZMA_NUM_REPS; i++) + reps[i] = prevOpt->backs[i - 1]; + } + } + curOpt->state = (CState)state; + + curOpt->backs[0] = reps[0]; + curOpt->backs[1] = reps[1]; + curOpt->backs[2] = reps[2]; + curOpt->backs[3] = reps[3]; + + curPrice = curOpt->price; + nextIsChar = False; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + curByte = *data; + matchByte = *(data - (reps[0] + 1)); + + posState = (position & p->pbMask); + + curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + curAnd1Price += + (!IsCharState(state) ? + LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + } + + nextOpt = &p->opt[cur + 1]; + + if (curAnd1Price < nextOpt->price) + { + nextOpt->price = curAnd1Price; + nextOpt->posPrev = cur; + MakeAsChar(nextOpt); + nextIsChar = True; + } + + matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); + + if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); + if (shortRepPrice <= nextOpt->price) + { + nextOpt->price = shortRepPrice; + nextOpt->posPrev = cur; + MakeAsShortRep(nextOpt); + nextIsChar = True; + } + } + numAvailFull = p->numAvail; + { + UInt32 temp = kNumOpts - 1 - cur; + if (temp < numAvailFull) + numAvailFull = temp; + } + + if (numAvailFull < 2) + continue; + numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); + + if (!nextIsChar && matchByte != curByte) /* speed optimization */ + { + /* try Literal + rep0 */ + UInt32 temp; + UInt32 lenTest2; + const Byte *data2 = data - (reps[0] + 1); + UInt32 limit = p->numFastBytes + 1; + if (limit > numAvailFull) + limit = numAvailFull; + + for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); + lenTest2 = temp - 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kLiteralNextStates[state]; + UInt32 posStateNext = (position + 1) & p->pbMask; + UInt32 nextRepMatchPrice = curAnd1Price + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 curAndLenPrice; + COptimal *opt; + UInt32 offset = cur + 1 + lenTest2; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = False; + } + } + } + } + + startLen = 2; /* speed optimization */ + { + UInt32 repIndex; + for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) + { + UInt32 lenTest; + UInt32 lenTestTemp; + UInt32 price; + const Byte *data2 = data - (reps[repIndex] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); + while (lenEnd < cur + lenTest) + p->opt[++lenEnd].price = kInfinityPrice; + lenTestTemp = lenTest; + price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); + do + { + UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; + COptimal *opt = &p->opt[cur + lenTest]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur; + opt->backPrev = repIndex; + opt->prev1IsChar = False; + } + } + while (--lenTest >= 2); + lenTest = lenTestTemp; + + if (repIndex == 0) + startLen = lenTest + 1; + + /* if (_maxMode) */ + { + UInt32 lenTest2 = lenTest + 1; + UInt32 limit = lenTest2 + p->numFastBytes; + UInt32 nextRepMatchPrice; + if (limit > numAvailFull) + limit = numAvailFull; + for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); + lenTest2 -= lenTest + 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kRepNextStates[state]; + UInt32 posStateNext = (position + lenTest) & p->pbMask; + UInt32 curAndLenCharPrice = + price + p->repLenEnc.prices[posState][lenTest - 2] + + GET_PRICE_0(p->isMatch[state2][posStateNext]) + + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), + data[lenTest], data2[lenTest], p->ProbPrices); + state2 = kLiteralNextStates[state2]; + posStateNext = (position + lenTest + 1) & p->pbMask; + nextRepMatchPrice = curAndLenCharPrice + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 curAndLenPrice; + COptimal *opt; + UInt32 offset = cur + lenTest + 1 + lenTest2; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + lenTest + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = True; + opt->posPrev2 = cur; + opt->backPrev2 = repIndex; + } + } + } + } + } + } + /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ + if (newLen > numAvail) + { + newLen = numAvail; + for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); + matches[numPairs] = newLen; + numPairs += 2; + } + if (newLen >= startLen) + { + UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); + UInt32 offs, curBack, posSlot; + UInt32 lenTest; + while (lenEnd < cur + newLen) + p->opt[++lenEnd].price = kInfinityPrice; + + offs = 0; + while (startLen > matches[offs]) + offs += 2; + curBack = matches[offs + 1]; + GetPosSlot2(curBack, posSlot); + for (lenTest = /*2*/ startLen; ; lenTest++) + { + UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; + UInt32 lenToPosState = GetLenToPosState(lenTest); + COptimal *opt; + if (curBack < kNumFullDistances) + curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; + else + curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; + + opt = &p->opt[cur + lenTest]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur; + opt->backPrev = curBack + LZMA_NUM_REPS; + opt->prev1IsChar = False; + } + + if (/*_maxMode && */lenTest == matches[offs]) + { + /* Try Match + Literal + Rep0 */ + const Byte *data2 = data - (curBack + 1); + UInt32 lenTest2 = lenTest + 1; + UInt32 limit = lenTest2 + p->numFastBytes; + UInt32 nextRepMatchPrice; + if (limit > numAvailFull) + limit = numAvailFull; + for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); + lenTest2 -= lenTest + 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kMatchNextStates[state]; + UInt32 posStateNext = (position + lenTest) & p->pbMask; + UInt32 curAndLenCharPrice = curAndLenPrice + + GET_PRICE_0(p->isMatch[state2][posStateNext]) + + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), + data[lenTest], data2[lenTest], p->ProbPrices); + state2 = kLiteralNextStates[state2]; + posStateNext = (posStateNext + 1) & p->pbMask; + nextRepMatchPrice = curAndLenCharPrice + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 offset = cur + lenTest + 1 + lenTest2; + UInt32 curAndLenPrice; + COptimal *opt; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + lenTest + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = True; + opt->posPrev2 = cur; + opt->backPrev2 = curBack + LZMA_NUM_REPS; + } + } + } + offs += 2; + if (offs == numPairs) + break; + curBack = matches[offs + 1]; + if (curBack >= kNumFullDistances) + GetPosSlot2(curBack, posSlot); + } + } + } + } +} + +#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) + +static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) +{ + UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; + const Byte *data; + const UInt32 *matches; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLength; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + *backRes = (UInt32)-1; + if (numAvail < 2) + return 1; + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + + repLen = repIndex = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 len; + const Byte *data2 = data - (p->reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + for (len = 2; len < numAvail && data[len] == data2[len]; len++); + if (len >= p->numFastBytes) + { + *backRes = i; + MovePos(p, len - 1); + return len; + } + if (len > repLen) + { + repIndex = i; + repLen = len; + } + } + + matches = p->matches; + if (mainLen >= p->numFastBytes) + { + *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; + MovePos(p, mainLen - 1); + return mainLen; + } + + mainDist = 0; /* for GCC */ + if (mainLen >= 2) + { + mainDist = matches[numPairs - 1]; + while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) + { + if (!ChangePair(matches[numPairs - 3], mainDist)) + break; + numPairs -= 2; + mainLen = matches[numPairs - 2]; + mainDist = matches[numPairs - 1]; + } + if (mainLen == 2 && mainDist >= 0x80) + mainLen = 1; + } + + if (repLen >= 2 && ( + (repLen + 1 >= mainLen) || + (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || + (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) + { + *backRes = repIndex; + MovePos(p, repLen - 1); + return repLen; + } + + if (mainLen < 2 || numAvail <= 2) + return 1; + + p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); + if (p->longestMatchLength >= 2) + { + UInt32 newDistance = matches[p->numPairs - 1]; + if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || + (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || + (p->longestMatchLength > mainLen + 1) || + (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) + return 1; + } + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 len, limit; + const Byte *data2 = data - (p->reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + limit = mainLen - 1; + for (len = 2; len < limit && data[len] == data2[len]; len++); + if (len >= limit) + return 1; + } + *backRes = mainDist + LZMA_NUM_REPS; + MovePos(p, mainLen - 2); + return mainLen; +} + +static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) +{ + UInt32 len; + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); + p->state = kMatchNextStates[p->state]; + len = LZMA_MATCH_LEN_MIN; + LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); + RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); + RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); +} + +static SRes CheckErrors(CLzmaEnc *p) +{ + if (p->result != SZ_OK) + return p->result; + if (p->rc.res != SZ_OK) + p->result = SZ_ERROR_WRITE; + if (p->matchFinderBase.result != SZ_OK) + p->result = SZ_ERROR_READ; + if (p->result != SZ_OK) + p->finished = True; + return p->result; +} + +static SRes Flush(CLzmaEnc *p, UInt32 nowPos) +{ + /* ReleaseMFStream(); */ + p->finished = True; + if (p->writeEndMark) + WriteEndMarker(p, nowPos & p->pbMask); + RangeEnc_FlushData(&p->rc); + RangeEnc_FlushStream(&p->rc); + return CheckErrors(p); +} + +static void FillAlignPrices(CLzmaEnc *p) +{ + UInt32 i; + for (i = 0; i < kAlignTableSize; i++) + p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); + p->alignPriceCount = 0; +} + +static void FillDistancesPrices(CLzmaEnc *p) +{ + UInt32 tempPrices[kNumFullDistances]; + UInt32 i, lenToPosState; + for (i = kStartPosModelIndex; i < kNumFullDistances; i++) + { + UInt32 posSlot = GetPosSlot1(i); + UInt32 footerBits = ((posSlot >> 1) - 1); + UInt32 base = ((2 | (posSlot & 1)) << footerBits); + tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); + } + + for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) + { + UInt32 posSlot; + const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; + UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; + for (posSlot = 0; posSlot < p->distTableSize; posSlot++) + posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); + for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) + posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); + + { + UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; + UInt32 i; + for (i = 0; i < kStartPosModelIndex; i++) + distancesPrices[i] = posSlotPrices[i]; + for (; i < kNumFullDistances; i++) + distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; + } + } + p->matchPriceCount = 0; +} + +void LzmaEnc_Construct(CLzmaEnc *p) +{ + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&p->matchFinderBase); + #ifndef _7ZIP_ST + MatchFinderMt_Construct(&p->matchFinderMt); + p->matchFinderMt.MatchFinder = &p->matchFinderBase; + #endif + + { + CLzmaEncProps props; + LzmaEncProps_Init(&props); + LzmaEnc_SetProps(p, &props); + } + + #ifndef LZMA_LOG_BSR + LzmaEnc_FastPosInit(p->g_FastPos); + #endif + + LzmaEnc_InitPriceTables(p->ProbPrices); + p->litProbs = 0; + p->saveState.litProbs = 0; +} + +CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) +{ + void *p; + p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); + if (p != 0) + LzmaEnc_Construct((CLzmaEnc *)p); + return p; +} + +void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->litProbs); + alloc->Free(alloc, p->saveState.litProbs); + p->litProbs = 0; + p->saveState.litProbs = 0; +} + +void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + #ifndef _7ZIP_ST + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); + #endif + MatchFinder_Free(&p->matchFinderBase, allocBig); + LzmaEnc_FreeLits(p, alloc); + RangeEnc_Free(&p->rc, alloc); +} + +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); + alloc->Free(alloc, p); +} + +static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) +{ + UInt32 nowPos32, startPos32; + if (p->needInit) + { + p->matchFinder.Init(p->matchFinderObj); + p->needInit = 0; + } + + if (p->finished) + return p->result; + RINOK(CheckErrors(p)); + + nowPos32 = (UInt32)p->nowPos64; + startPos32 = nowPos32; + + if (p->nowPos64 == 0) + { + UInt32 numPairs; + Byte curByte; + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + return Flush(p, nowPos32); + ReadMatchDistances(p, &numPairs); + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); + p->state = kLiteralNextStates[p->state]; + curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); + LitEnc_Encode(&p->rc, p->litProbs, curByte); + p->additionalOffset--; + nowPos32++; + } + + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) + for (;;) + { + UInt32 pos, len, posState; + + if (p->fastMode) + len = GetOptimumFast(p, &pos); + else + len = GetOptimum(p, nowPos32, &pos); + + #ifdef SHOW_STAT2 + printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); + #endif + + posState = nowPos32 & p->pbMask; + if (len == 1 && pos == (UInt32)-1) + { + Byte curByte; + CLzmaProb *probs; + const Byte *data; + + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; + curByte = *data; + probs = LIT_PROBS(nowPos32, *(data - 1)); + if (IsCharState(p->state)) + LitEnc_Encode(&p->rc, probs, curByte); + else + LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); + p->state = kLiteralNextStates[p->state]; + } + else + { + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); + if (pos < LZMA_NUM_REPS) + { + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); + if (pos == 0) + { + RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); + RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); + } + else + { + UInt32 distance = p->reps[pos]; + RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); + if (pos == 1) + RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); + else + { + RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); + RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); + if (pos == 3) + p->reps[3] = p->reps[2]; + p->reps[2] = p->reps[1]; + } + p->reps[1] = p->reps[0]; + p->reps[0] = distance; + } + if (len == 1) + p->state = kShortRepNextStates[p->state]; + else + { + LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + p->state = kRepNextStates[p->state]; + } + } + else + { + UInt32 posSlot; + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); + p->state = kMatchNextStates[p->state]; + LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + pos -= LZMA_NUM_REPS; + GetPosSlot(pos, posSlot); + RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); + + if (posSlot >= kStartPosModelIndex) + { + UInt32 footerBits = ((posSlot >> 1) - 1); + UInt32 base = ((2 | (posSlot & 1)) << footerBits); + UInt32 posReduced = pos - base; + + if (posSlot < kEndPosModelIndex) + RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); + else + { + RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); + RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); + p->alignPriceCount++; + } + } + p->reps[3] = p->reps[2]; + p->reps[2] = p->reps[1]; + p->reps[1] = p->reps[0]; + p->reps[0] = pos; + p->matchPriceCount++; + } + } + p->additionalOffset -= len; + nowPos32 += len; + if (p->additionalOffset == 0) + { + UInt32 processed; + if (!p->fastMode) + { + if (p->matchPriceCount >= (1 << 7)) + FillDistancesPrices(p); + if (p->alignPriceCount >= kAlignTableSize) + FillAlignPrices(p); + } + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + break; + processed = nowPos32 - startPos32; + if (useLimits) + { + if (processed + kNumOpts + 300 >= maxUnpackSize || + RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) + break; + } + else if (processed >= (1 << 15)) + { + p->nowPos64 += nowPos32 - startPos32; + return CheckErrors(p); + } + } + } + p->nowPos64 += nowPos32 - startPos32; + return Flush(p, nowPos32); +} + +#define kBigHashDicLimit ((UInt32)1 << 24) + +static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + UInt32 beforeSize = kNumOpts; + Bool btMode; + if (!RangeEnc_Alloc(&p->rc, alloc)) + return SZ_ERROR_MEM; + btMode = (p->matchFinderBase.btMode != 0); + #ifndef _7ZIP_ST + p->mtMode = (p->multiThread && !p->fastMode && btMode); + #endif + + { + unsigned lclp = p->lc + p->lp; + if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) + { + LzmaEnc_FreeLits(p, alloc); + p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); + p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); + if (p->litProbs == 0 || p->saveState.litProbs == 0) + { + LzmaEnc_FreeLits(p, alloc); + return SZ_ERROR_MEM; + } + p->lclp = lclp; + } + } + + p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); + + if (beforeSize + p->dictSize < keepWindowSize) + beforeSize = keepWindowSize - p->dictSize; + + #ifndef _7ZIP_ST + if (p->mtMode) + { + RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); + p->matchFinderObj = &p->matchFinderMt; + MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); + } + else + #endif + { + if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) + return SZ_ERROR_MEM; + p->matchFinderObj = &p->matchFinderBase; + MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); + } + return SZ_OK; +} + +void LzmaEnc_Init(CLzmaEnc *p) +{ + UInt32 i; + p->state = 0; + for (i = 0 ; i < LZMA_NUM_REPS; i++) + p->reps[i] = 0; + + RangeEnc_Init(&p->rc); + + + for (i = 0; i < kNumStates; i++) + { + UInt32 j; + for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) + { + p->isMatch[i][j] = kProbInitValue; + p->isRep0Long[i][j] = kProbInitValue; + } + p->isRep[i] = kProbInitValue; + p->isRepG0[i] = kProbInitValue; + p->isRepG1[i] = kProbInitValue; + p->isRepG2[i] = kProbInitValue; + } + + { + UInt32 num = 0x300 << (p->lp + p->lc); + for (i = 0; i < num; i++) + p->litProbs[i] = kProbInitValue; + } + + { + for (i = 0; i < kNumLenToPosStates; i++) + { + CLzmaProb *probs = p->posSlotEncoder[i]; + UInt32 j; + for (j = 0; j < (1 << kNumPosSlotBits); j++) + probs[j] = kProbInitValue; + } + } + { + for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) + p->posEncoders[i] = kProbInitValue; + } + + LenEnc_Init(&p->lenEnc.p); + LenEnc_Init(&p->repLenEnc.p); + + for (i = 0; i < (1 << kNumAlignBits); i++) + p->posAlignEncoder[i] = kProbInitValue; + + p->optimumEndIndex = 0; + p->optimumCurrentIndex = 0; + p->additionalOffset = 0; + + p->pbMask = (1 << p->pb) - 1; + p->lpMask = (1 << p->lp) - 1; +} + +void LzmaEnc_InitPrices(CLzmaEnc *p) +{ + if (!p->fastMode) + { + FillDistancesPrices(p); + FillAlignPrices(p); + } + + p->lenEnc.tableSize = + p->repLenEnc.tableSize = + p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; + LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); + LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); +} + +static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + UInt32 i; + for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) + if (p->dictSize <= ((UInt32)1 << i)) + break; + p->distTableSize = i * 2; + + p->finished = False; + p->result = SZ_OK; + RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + p->nowPos64 = 0; + return SZ_OK; +} + +static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.stream = inStream; + p->needInit = 1; + p->rc.outStream = outStream; + return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); +} + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, + ISeqInStream *inStream, UInt32 keepWindowSize, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.stream = inStream; + p->needInit = 1; + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) +{ + p->matchFinderBase.directInput = 1; + p->matchFinderBase.bufferBase = (Byte *)src; + p->matchFinderBase.directInputRem = srcLen; +} + +SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + LzmaEnc_SetInputBuf(p, src, srcLen); + p->needInit = 1; + + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +void LzmaEnc_Finish(CLzmaEncHandle pp) +{ + #ifndef _7ZIP_ST + CLzmaEnc *p = (CLzmaEnc *)pp; + if (p->mtMode) + MatchFinderMt_ReleaseStream(&p->matchFinderMt); + #else + pp = pp; + #endif +} + +typedef struct +{ + ISeqOutStream funcTable; + Byte *data; + SizeT rem; + Bool overflow; +} CSeqOutStreamBuf; + +static size_t MyWrite(void *pp, const void *data, size_t size) +{ + CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; + if (p->rem < size) + { + size = p->rem; + p->overflow = True; + } + memcpy(p->data, data, size); + p->rem -= size; + p->data += size; + return size; +} + + +UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); +} + +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; +} + +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + UInt64 nowPos64; + SRes res; + CSeqOutStreamBuf outStream; + + outStream.funcTable.Write = MyWrite; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = False; + p->finished = False; + p->result = SZ_OK; + + if (reInit) + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + nowPos64 = p->nowPos64; + RangeEnc_Init(&p->rc); + p->rc.outStream = &outStream.funcTable; + + res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); + + *unpackSize = (UInt32)(p->nowPos64 - nowPos64); + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + + return res; +} + +static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) +{ + SRes res = SZ_OK; + + #ifndef _7ZIP_ST + Byte allocaDummy[0x300]; + int i = 0; + for (i = 0; i < 16; i++) + allocaDummy[i] = (Byte)i; + #endif + + for (;;) + { + res = LzmaEnc_CodeOneBlock(p, False, 0, 0); + if (res != SZ_OK || p->finished != 0) + break; + if (progress != 0) + { + res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); + if (res != SZ_OK) + { + res = SZ_ERROR_PROGRESS; + break; + } + } + } + LzmaEnc_Finish(p); + return res; +} + +SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); + return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); +} + +SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + int i; + UInt32 dictSize = p->dictSize; + if (*size < LZMA_PROPS_SIZE) + return SZ_ERROR_PARAM; + *size = LZMA_PROPS_SIZE; + props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); + + for (i = 11; i <= 30; i++) + { + if (dictSize <= ((UInt32)2 << i)) + { + dictSize = (2 << i); + break; + } + if (dictSize <= ((UInt32)3 << i)) + { + dictSize = (3 << i); + break; + } + } + + for (i = 0; i < 4; i++) + props[1 + i] = (Byte)(dictSize >> (8 * i)); + return SZ_OK; +} + +SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + SRes res; + CLzmaEnc *p = (CLzmaEnc *)pp; + + CSeqOutStreamBuf outStream; + + LzmaEnc_SetInputBuf(p, src, srcLen); + + outStream.funcTable.Write = MyWrite; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = writeEndMark; + + p->rc.outStream = &outStream.funcTable; + res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); + if (res == SZ_OK) + res = LzmaEnc_Encode2(p, progress); + + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + return res; +} + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); + SRes res; + if (p == 0) + return SZ_ERROR_MEM; + + res = LzmaEnc_SetProps(p, props); + if (res == SZ_OK) + { + res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); + if (res == SZ_OK) + res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, + writeEndMark, progress, alloc, allocBig); + } + + LzmaEnc_Destroy(p, alloc, allocBig); + return res; +} diff --git a/ext/VFS/ext/7z/src/LzmaEnc.h b/ext/VFS/ext/7z/src/LzmaEnc.h new file mode 100644 index 000000000..999f5afff --- /dev/null +++ b/ext/VFS/ext/7z/src/LzmaEnc.h @@ -0,0 +1,80 @@ +/* LzmaEnc.h -- LZMA Encoder +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_ENC_H +#define __LZMA_ENC_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaEncProps +{ + int level; /* 0 <= level <= 9 */ + UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version + (1 << 12) <= dictSize <= (1 << 30) for 64-bit version + default = (1 << 24) */ + int lc; /* 0 <= lc <= 8, default = 3 */ + int lp; /* 0 <= lp <= 4, default = 0 */ + int pb; /* 0 <= pb <= 4, default = 2 */ + int algo; /* 0 - fast, 1 - normal, default = 1 */ + int fb; /* 5 <= fb <= 273, default = 32 */ + int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ + int numHashBytes; /* 2, 3 or 4, default = 4 */ + UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ + unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ + int numThreads; /* 1 or 2, default = 2 */ +} CLzmaEncProps; + +void LzmaEncProps_Init(CLzmaEncProps *p); +void LzmaEncProps_Normalize(CLzmaEncProps *p); +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); + + +/* ---------- CLzmaEncHandle Interface ---------- */ + +/* LzmaEnc_* functions can return the following exit codes: +Returns: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - Write callback error. + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +typedef void * CLzmaEncHandle; + +CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); +SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); +SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +/* ---------- One Call Interface ---------- */ + +/* LzmaEncode +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/LzmaLib.c b/ext/VFS/ext/7z/src/LzmaLib.c new file mode 100644 index 000000000..3e3cf40ae --- /dev/null +++ b/ext/VFS/ext/7z/src/LzmaLib.c @@ -0,0 +1,46 @@ +/* LzmaLib.c -- LZMA library wrapper +2008-08-05 +Igor Pavlov +Public domain */ + +#include "LzmaEnc.h" +#include "LzmaDec.h" +#include "Alloc.h" +#include "LzmaLib.h" + +static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } +static void SzFree(void *p, void *address) { p = p; MyFree(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads /* 1 or 2, default = 2 */ +) +{ + CLzmaEncProps props; + LzmaEncProps_Init(&props); + props.level = level; + props.dictSize = dictSize; + props.lc = lc; + props.lp = lp; + props.pb = pb; + props.fb = fb; + props.numThreads = numThreads; + + return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0, + NULL, &g_Alloc, &g_Alloc); +} + + +MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen, + const unsigned char *props, size_t propsSize) +{ + ELzmaStatus status; + return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc); +} diff --git a/ext/VFS/ext/7z/src/LzmaLib.h b/ext/VFS/ext/7z/src/LzmaLib.h new file mode 100644 index 000000000..55e1e1148 --- /dev/null +++ b/ext/VFS/ext/7z/src/LzmaLib.h @@ -0,0 +1,135 @@ +/* LzmaLib.h -- LZMA library interface +2009-04-07 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_LIB_H +#define __LZMA_LIB_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MY_STDAPI int MY_STD_CALL + +#define LZMA_PROPS_SIZE 5 + +/* +RAM requirements for LZMA: + for compression: (dictSize * 11.5 + 6 MB) + state_size + for decompression: dictSize + state_size + state_size = (4 + (1.5 << (lc + lp))) KB + by default (lc=3, lp=0), state_size = 16 KB. + +LZMA properties (5 bytes) format + Offset Size Description + 0 1 lc, lp and pb in encoded form. + 1 4 dictSize (little endian). +*/ + +/* +LzmaCompress +------------ + +outPropsSize - + In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + + LZMA Encoder will use defult values for any parameter, if it is + -1 for any from: level, loc, lp, pb, fb, numThreads + 0 for dictSize + +level - compression level: 0 <= level <= 9; + + level dictSize algo fb + 0: 16 KB 0 32 + 1: 64 KB 0 32 + 2: 256 KB 0 32 + 3: 1 MB 0 32 + 4: 4 MB 0 32 + 5: 16 MB 1 32 + 6: 32 MB 1 32 + 7+: 64 MB 1 64 + + The default value for "level" is 5. + + algo = 0 means fast method + algo = 1 means normal method + +dictSize - The dictionary size in bytes. The maximum value is + 128 MB = (1 << 27) bytes for 32-bit version + 1 GB = (1 << 30) bytes for 64-bit version + The default value is 16 MB = (1 << 24) bytes. + It's recommended to use the dictionary that is larger than 4 KB and + that can be calculated as (1 << N) or (3 << N) sizes. + +lc - The number of literal context bits (high bits of previous literal). + It can be in the range from 0 to 8. The default value is 3. + Sometimes lc=4 gives the gain for big files. + +lp - The number of literal pos bits (low bits of current position for literals). + It can be in the range from 0 to 4. The default value is 0. + The lp switch is intended for periodical data when the period is equal to 2^lp. + For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's + better to set lc=0, if you change lp switch. + +pb - The number of pos bits (low bits of current position). + It can be in the range from 0 to 4. The default value is 2. + The pb switch is intended for periodical data when the period is equal 2^pb. + +fb - Word size (the number of fast bytes). + It can be in the range from 5 to 273. The default value is 32. + Usually, a big number gives a little bit better compression ratio and + slower compression process. + +numThreads - The number of thereads. 1 or 2. The default value is 2. + Fast mode (algo = 0) can use only 1 thread. + +Out: + destLen - processed output size +Returns: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */ + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* default = (1 << 24) */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads /* 1 or 2, default = 2 */ + ); + +/* +LzmaUncompress +-------------- +In: + dest - output data + destLen - output data size + src - input data + srcLen - input data size +Out: + destLen - processed output size + srcLen - processed input size +Returns: + SZ_OK - OK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation arror + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src) +*/ + +MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen, + const unsigned char *props, size_t propsSize); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/MtCoder.c b/ext/VFS/ext/7z/src/MtCoder.c new file mode 100644 index 000000000..161659199 --- /dev/null +++ b/ext/VFS/ext/7z/src/MtCoder.c @@ -0,0 +1,327 @@ +/* MtCoder.c -- Multi-thread Coder +2010-03-24 : Igor Pavlov : Public domain */ + +#include + +#include "MtCoder.h" + +void LoopThread_Construct(CLoopThread *p) +{ + Thread_Construct(&p->thread); + Event_Construct(&p->startEvent); + Event_Construct(&p->finishedEvent); +} + +void LoopThread_Close(CLoopThread *p) +{ + Thread_Close(&p->thread); + Event_Close(&p->startEvent); + Event_Close(&p->finishedEvent); +} + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE LoopThreadFunc(void *pp) +{ + CLoopThread *p = (CLoopThread *)pp; + for (;;) + { + if (Event_Wait(&p->startEvent) != 0) + return SZ_ERROR_THREAD; + if (p->stop) + return 0; + p->res = p->func(p->param); + if (Event_Set(&p->finishedEvent) != 0) + return SZ_ERROR_THREAD; + } +} + +WRes LoopThread_Create(CLoopThread *p) +{ + p->stop = 0; + RINOK(AutoResetEvent_CreateNotSignaled(&p->startEvent)); + RINOK(AutoResetEvent_CreateNotSignaled(&p->finishedEvent)); + return Thread_Create(&p->thread, LoopThreadFunc, p); +} + +WRes LoopThread_StopAndWait(CLoopThread *p) +{ + p->stop = 1; + if (Event_Set(&p->startEvent) != 0) + return SZ_ERROR_THREAD; + return Thread_Wait(&p->thread); +} + +WRes LoopThread_StartSubThread(CLoopThread *p) { return Event_Set(&p->startEvent); } +WRes LoopThread_WaitSubThread(CLoopThread *p) { return Event_Wait(&p->finishedEvent); } + +static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) +{ + return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; +} + +static void MtProgress_Init(CMtProgress *p, ICompressProgress *progress) +{ + unsigned i; + for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) + p->inSizes[i] = p->outSizes[i] = 0; + p->totalInSize = p->totalOutSize = 0; + p->progress = progress; + p->res = SZ_OK; +} + +static void MtProgress_Reinit(CMtProgress *p, unsigned index) +{ + p->inSizes[index] = 0; + p->outSizes[index] = 0; +} + +#define UPDATE_PROGRESS(size, prev, total) \ + if (size != (UInt64)(Int64)-1) { total += size - prev; prev = size; } + +SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize) +{ + SRes res; + CriticalSection_Enter(&p->cs); + UPDATE_PROGRESS(inSize, p->inSizes[index], p->totalInSize) + UPDATE_PROGRESS(outSize, p->outSizes[index], p->totalOutSize) + if (p->res == SZ_OK) + p->res = Progress(p->progress, p->totalInSize, p->totalOutSize); + res = p->res; + CriticalSection_Leave(&p->cs); + return res; +} + +static void MtProgress_SetError(CMtProgress *p, SRes res) +{ + CriticalSection_Enter(&p->cs); + if (p->res == SZ_OK) + p->res = res; + CriticalSection_Leave(&p->cs); +} + +static void MtCoder_SetError(CMtCoder* p, SRes res) +{ + CriticalSection_Enter(&p->cs); + if (p->res == SZ_OK) + p->res = res; + CriticalSection_Leave(&p->cs); +} + +/* ---------- MtThread ---------- */ + +void CMtThread_Construct(CMtThread *p, CMtCoder *mtCoder) +{ + p->mtCoder = mtCoder; + p->outBuf = 0; + p->inBuf = 0; + Event_Construct(&p->canRead); + Event_Construct(&p->canWrite); + LoopThread_Construct(&p->thread); +} + +#define RINOK_THREAD(x) { if((x) != 0) return SZ_ERROR_THREAD; } + +static void CMtThread_CloseEvents(CMtThread *p) +{ + Event_Close(&p->canRead); + Event_Close(&p->canWrite); +} + +static void CMtThread_Destruct(CMtThread *p) +{ + CMtThread_CloseEvents(p); + + if (Thread_WasCreated(&p->thread.thread)) + { + LoopThread_StopAndWait(&p->thread); + LoopThread_Close(&p->thread); + } + + if (p->mtCoder->alloc) + IAlloc_Free(p->mtCoder->alloc, p->outBuf); + p->outBuf = 0; + + if (p->mtCoder->alloc) + IAlloc_Free(p->mtCoder->alloc, p->inBuf); + p->inBuf = 0; +} + +#define MY_BUF_ALLOC(buf, size, newSize) \ + if (buf == 0 || size != newSize) \ + { IAlloc_Free(p->mtCoder->alloc, buf); \ + size = newSize; buf = IAlloc_Alloc(p->mtCoder->alloc, size); \ + if (buf == 0) return SZ_ERROR_MEM; } + +static SRes CMtThread_Prepare(CMtThread *p) +{ + MY_BUF_ALLOC(p->inBuf, p->inBufSize, p->mtCoder->blockSize) + MY_BUF_ALLOC(p->outBuf, p->outBufSize, p->mtCoder->destBlockSize) + + p->stopReading = False; + p->stopWriting = False; + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canRead)); + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canWrite)); + + return SZ_OK; +} + +static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize) +{ + size_t size = *processedSize; + *processedSize = 0; + while (size != 0) + { + size_t curSize = size; + SRes res = stream->Read(stream, data, &curSize); + *processedSize += curSize; + data += curSize; + size -= curSize; + RINOK(res); + if (curSize == 0) + return SZ_OK; + } + return SZ_OK; +} + +#define GET_NEXT_THREAD(p) &p->mtCoder->threads[p->index == p->mtCoder->numThreads - 1 ? 0 : p->index + 1] + +static SRes MtThread_Process(CMtThread *p, Bool *stop) +{ + CMtThread *next; + *stop = True; + if (Event_Wait(&p->canRead) != 0) + return SZ_ERROR_THREAD; + + next = GET_NEXT_THREAD(p); + + if (p->stopReading) + { + next->stopReading = True; + return Event_Set(&next->canRead) == 0 ? SZ_OK : SZ_ERROR_THREAD; + } + + { + size_t size = p->mtCoder->blockSize; + size_t destSize = p->outBufSize; + + RINOK(FullRead(p->mtCoder->inStream, p->inBuf, &size)); + next->stopReading = *stop = (size != p->mtCoder->blockSize); + if (Event_Set(&next->canRead) != 0) + return SZ_ERROR_THREAD; + + RINOK(p->mtCoder->mtCallback->Code(p->mtCoder->mtCallback, p->index, + p->outBuf, &destSize, p->inBuf, size, *stop)); + + MtProgress_Reinit(&p->mtCoder->mtProgress, p->index); + + if (Event_Wait(&p->canWrite) != 0) + return SZ_ERROR_THREAD; + if (p->stopWriting) + return SZ_ERROR_FAIL; + if (p->mtCoder->outStream->Write(p->mtCoder->outStream, p->outBuf, destSize) != destSize) + return SZ_ERROR_WRITE; + return Event_Set(&next->canWrite) == 0 ? SZ_OK : SZ_ERROR_THREAD; + } +} + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp) +{ + CMtThread *p = (CMtThread *)pp; + for (;;) + { + Bool stop; + CMtThread *next = GET_NEXT_THREAD(p); + SRes res = MtThread_Process(p, &stop); + if (res != SZ_OK) + { + MtCoder_SetError(p->mtCoder, res); + MtProgress_SetError(&p->mtCoder->mtProgress, res); + next->stopReading = True; + next->stopWriting = True; + Event_Set(&next->canRead); + Event_Set(&next->canWrite); + return res; + } + if (stop) + return 0; + } +} + +void MtCoder_Construct(CMtCoder* p) +{ + unsigned i; + p->alloc = 0; + for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) + { + CMtThread *t = &p->threads[i]; + t->index = i; + CMtThread_Construct(t, p); + } + CriticalSection_Init(&p->cs); + CriticalSection_Init(&p->mtProgress.cs); +} + +void MtCoder_Destruct(CMtCoder* p) +{ + unsigned i; + for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) + CMtThread_Destruct(&p->threads[i]); + CriticalSection_Delete(&p->cs); + CriticalSection_Delete(&p->mtProgress.cs); +} + +SRes MtCoder_Code(CMtCoder *p) +{ + unsigned i, numThreads = p->numThreads; + SRes res = SZ_OK; + p->res = SZ_OK; + + MtProgress_Init(&p->mtProgress, p->progress); + + for (i = 0; i < numThreads; i++) + { + RINOK(CMtThread_Prepare(&p->threads[i])); + } + + for (i = 0; i < numThreads; i++) + { + CMtThread *t = &p->threads[i]; + CLoopThread *lt = &t->thread; + + if (!Thread_WasCreated(<->thread)) + { + lt->func = ThreadFunc; + lt->param = t; + + if (LoopThread_Create(lt) != SZ_OK) + { + res = SZ_ERROR_THREAD; + break; + } + } + } + + if (res == SZ_OK) + { + unsigned j; + for (i = 0; i < numThreads; i++) + { + CMtThread *t = &p->threads[i]; + if (LoopThread_StartSubThread(&t->thread) != SZ_OK) + { + res = SZ_ERROR_THREAD; + p->threads[0].stopReading = True; + break; + } + } + + Event_Set(&p->threads[0].canWrite); + Event_Set(&p->threads[0].canRead); + + for (j = 0; j < i; j++) + LoopThread_WaitSubThread(&p->threads[j].thread); + } + + for (i = 0; i < numThreads; i++) + CMtThread_CloseEvents(&p->threads[i]); + return (res == SZ_OK) ? p->res : res; +} diff --git a/ext/VFS/ext/7z/src/MtCoder.h b/ext/VFS/ext/7z/src/MtCoder.h new file mode 100644 index 000000000..705208ed3 --- /dev/null +++ b/ext/VFS/ext/7z/src/MtCoder.h @@ -0,0 +1,98 @@ +/* MtCoder.h -- Multi-thread Coder +2009-11-19 : Igor Pavlov : Public domain */ + +#ifndef __MT_CODER_H +#define __MT_CODER_H + +#include "Threads.h" + +EXTERN_C_BEGIN + +typedef struct +{ + CThread thread; + CAutoResetEvent startEvent; + CAutoResetEvent finishedEvent; + int stop; + + THREAD_FUNC_TYPE func; + LPVOID param; + THREAD_FUNC_RET_TYPE res; +} CLoopThread; + +void LoopThread_Construct(CLoopThread *p); +void LoopThread_Close(CLoopThread *p); +WRes LoopThread_Create(CLoopThread *p); +WRes LoopThread_StopAndWait(CLoopThread *p); +WRes LoopThread_StartSubThread(CLoopThread *p); +WRes LoopThread_WaitSubThread(CLoopThread *p); + +#ifndef _7ZIP_ST +#define NUM_MT_CODER_THREADS_MAX 32 +#else +#define NUM_MT_CODER_THREADS_MAX 1 +#endif + +typedef struct +{ + UInt64 totalInSize; + UInt64 totalOutSize; + ICompressProgress *progress; + SRes res; + CCriticalSection cs; + UInt64 inSizes[NUM_MT_CODER_THREADS_MAX]; + UInt64 outSizes[NUM_MT_CODER_THREADS_MAX]; +} CMtProgress; + +SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize); + +struct _CMtCoder; + +typedef struct +{ + struct _CMtCoder *mtCoder; + Byte *outBuf; + size_t outBufSize; + Byte *inBuf; + size_t inBufSize; + unsigned index; + CLoopThread thread; + + Bool stopReading; + Bool stopWriting; + CAutoResetEvent canRead; + CAutoResetEvent canWrite; +} CMtThread; + +typedef struct +{ + SRes (*Code)(void *p, unsigned index, Byte *dest, size_t *destSize, + const Byte *src, size_t srcSize, int finished); +} IMtCoderCallback; + +typedef struct _CMtCoder +{ + size_t blockSize; + size_t destBlockSize; + unsigned numThreads; + + ISeqInStream *inStream; + ISeqOutStream *outStream; + ICompressProgress *progress; + ISzAlloc *alloc; + + IMtCoderCallback *mtCallback; + CCriticalSection cs; + SRes res; + + CMtProgress mtProgress; + CMtThread threads[NUM_MT_CODER_THREADS_MAX]; +} CMtCoder; + +void MtCoder_Construct(CMtCoder* p); +void MtCoder_Destruct(CMtCoder* p); +SRes MtCoder_Code(CMtCoder *p); + +EXTERN_C_END + +#endif diff --git a/ext/VFS/ext/7z/src/Ppmd.h b/ext/VFS/ext/7z/src/Ppmd.h new file mode 100644 index 000000000..14344a719 --- /dev/null +++ b/ext/VFS/ext/7z/src/Ppmd.h @@ -0,0 +1,81 @@ +/* Ppmd.h -- PPMD codec common code +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#ifndef __PPMD_H +#define __PPMD_H + +#include "Types.h" +#include "CpuArch.h" + +EXTERN_C_BEGIN + +#ifdef MY_CPU_32BIT + #define PPMD_32BIT +#endif + +#define PPMD_INT_BITS 7 +#define PPMD_PERIOD_BITS 7 +#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) + +#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) +#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) +#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) +#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) + +#define PPMD_N1 4 +#define PPMD_N2 4 +#define PPMD_N3 4 +#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) +#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) + +/* SEE-contexts for PPM-contexts with masked symbols */ +typedef struct +{ + UInt16 Summ; /* Freq */ + Byte Shift; /* Speed of Freq change; low Shift is for fast change */ + Byte Count; /* Count to next change of Shift */ +} CPpmd_See; + +#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ + { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); } + +typedef struct +{ + Byte Symbol; + Byte Freq; + UInt16 SuccessorLow; + UInt16 SuccessorHigh; +} CPpmd_State; + +typedef + #ifdef PPMD_32BIT + CPpmd_State * + #else + UInt32 + #endif + CPpmd_State_Ref; + +typedef + #ifdef PPMD_32BIT + void * + #else + UInt32 + #endif + CPpmd_Void_Ref; + +typedef + #ifdef PPMD_32BIT + Byte * + #else + UInt32 + #endif + CPpmd_Byte_Ref; + +#define PPMD_SetAllBitsIn256Bytes(p) \ + { unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \ + p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }} + +EXTERN_C_END + +#endif diff --git a/ext/VFS/ext/7z/src/Ppmd7.c b/ext/VFS/ext/7z/src/Ppmd7.c new file mode 100644 index 000000000..4b160cf03 --- /dev/null +++ b/ext/VFS/ext/7z/src/Ppmd7.c @@ -0,0 +1,708 @@ +/* Ppmd7.c -- PPMdH codec +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include + +#include "Ppmd7.h" + +const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(nu) - 1]) +#define I2U(indx) (p->Indx2Units[indx]) + +#ifdef PPMD_32BIT + #define REF(ptr) (ptr) +#else + #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) +#endif + +#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +#define STATS(ctx) Ppmd7_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +typedef CPpmd7_Context * CTX_PTR; + +struct CPpmd7_Node_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Node_ * + #else + UInt32 + #endif + CPpmd7_Node_Ref; + +typedef struct CPpmd7_Node_ +{ + UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ + UInt16 NU; + CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ + CPpmd7_Node_Ref Prev; +} CPpmd7_Node; + +#ifdef PPMD_32BIT + #define NODE(ptr) (ptr) +#else + #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) +#endif + +void Ppmd7_Construct(CPpmd7 *p) +{ + unsigned i, k, m; + + p->Base = 0; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while(--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 3; i++) + p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 256; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 2; + } + + memset(p->HB2Flag, 0, 0x40); + memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); +} + +void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->Base); + p->Size = 0; + p->Base = 0; +} + +Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc) +{ + if (p->Base == 0 || p->Size != size) + { + Ppmd7_Free(p, alloc); + p->AlignOffset = + #ifdef PPMD_32BIT + (4 - size) & 3; + #else + 4 - (size & 3); + #endif + if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size + #ifndef PPMD_32BIT + + UNIT_SIZE + #endif + )) == 0) + return False; + p->Size = size; + } + return True; +} + +static void InsertNode(CPpmd7 *p, void *node, unsigned indx) +{ + *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; + p->FreeList[indx] = REF(node); +} + +static void *RemoveNode(CPpmd7 *p, unsigned indx) +{ + CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); + p->FreeList[indx] = *node; + return node; +} + +static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + InsertNode(p, ptr, i); +} + +static void GlueFreeBlocks(CPpmd7 *p) +{ + #ifdef PPMD_32BIT + CPpmd7_Node headItem; + CPpmd7_Node_Ref head = &headItem; + #else + CPpmd7_Node_Ref head = p->AlignOffset + p->Size; + #endif + + CPpmd7_Node_Ref n = head; + unsigned i; + + p->GlueCount = 255; + + /* create doubly-linked list of free blocks */ + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + UInt16 nu = I2U(i); + CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd7_Node *node = NODE(next); + node->Next = n; + n = NODE(n)->Prev = next; + next = *(const CPpmd7_Node_Ref *)node; + node->Stamp = 0; + node->NU = (UInt16)nu; + } + } + NODE(head)->Stamp = 1; + NODE(head)->Next = n; + NODE(n)->Prev = head; + if (p->LoUnit != p->HiUnit) + ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; + + /* Glue free blocks */ + while (n != head) + { + CPpmd7_Node *node = NODE(n); + UInt32 nu = (UInt32)node->NU; + for (;;) + { + CPpmd7_Node *node2 = NODE(n) + nu; + nu += node2->NU; + if (node2->Stamp != 0 || nu >= 0x10000) + break; + NODE(node2->Prev)->Next = node2->Next; + NODE(node2->Next)->Prev = node2->Prev; + node->NU = (UInt16)nu; + } + n = node->Next; + } + + /* Fill lists of free blocks */ + for (n = NODE(head)->Next; n != head;) + { + CPpmd7_Node *node = NODE(n); + unsigned nu; + CPpmd7_Node_Ref next = node->Next; + for (nu = node->NU; nu > 128; nu -= 128, node += 128) + InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, node + k, nu - k - 1); + } + InsertNode(p, node, i); + n = next; + } +} + +static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) +{ + unsigned i; + void *retVal; + if (p->GlueCount == 0) + { + GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + } + i = indx; + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + p->GlueCount--; + return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + retVal = RemoveNode(p, i); + SplitBlock(p, retVal, i, indx); + return retVal; +} + +static void *AllocUnits(CPpmd7 *p, unsigned indx) +{ + UInt32 numBytes; + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + numBytes = U2B(I2U(indx)); + if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + { + void *retVal = p->LoUnit; + p->LoUnit += numBytes; + return retVal; + } + return AllocUnitsRare(p, indx); +} + +#define MyMem12Cpy(dest, src, num) \ + { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ + do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } + +static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +{ + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void *ptr = RemoveNode(p, i1); + MyMem12Cpy(ptr, oldPtr, newNU); + InsertNode(p, oldPtr, i0); + return ptr; + } + SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} + +#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) + +static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); +} + +static void RestartModel(CPpmd7 *p) +{ + unsigned i, k, m; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + p->Text = p->Base + p->AlignOffset; + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + p->MinContext->Suffix = 0; + p->MinContext->NumStats = 256; + p->MinContext->SummFreq = 256 + 1; + p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + p->LoUnit += U2B(256 / 2); + p->MinContext->Stats = REF(p->FoundState); + for (i = 0; i < 256; i++) + { + CPpmd_State *s = &p->FoundState[i]; + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + for (i = 0; i < 128; i++) + for (k = 0; k < 8; k++) + { + UInt16 *dest = p->BinSumm[i] + k; + UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); + for (m = 0; m < 64; m += 8) + dest[m] = val; + } + + for (i = 0; i < 25; i++) + for (k = 0; k < 16; k++) + { + CPpmd_See *s = &p->See[i][k]; + s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Count = 4; + } +} + +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) +{ + p->MaxOrder = maxOrder; + RestartModel(p); + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Count = 64; /* unused */ +} + +static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) +{ + CPpmd_State upState; + CTX_PTR c = p->MinContext; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + CPpmd_State *ps[PPMD7_MAX_ORDER]; + unsigned numPs = 0; + + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + if (c->NumStats != 1) + { + for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + } + else + s = ONE_STATE(c); + successor = SUCCESSOR(s); + if (successor != upBranch) + { + c = CTX(successor); + if (numPs == 0) + return c; + break; + } + ps[numPs++] = s; + } + + upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); + SetSuccessor(&upState, upBranch + 1); + + if (c->NumStats == 1) + upState.Freq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != upState.Symbol; s++); + cf = s->Freq - 1; + s0 = c->SummFreq - c->NumStats - cf; + upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); + } + + do + { + /* Create Child */ + CTX_PTR c1; /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (CTX_PTR)RemoveNode(p, 0); + else + { + c1 = (CTX_PTR)AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->NumStats = 1; + *ONE_STATE(c1) = upState; + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; +} + +static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) +{ + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; +} + +static void UpdateModel(CPpmd7 *p) +{ + CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); + CTX_PTR c; + unsigned s0, ns; + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + c = SUFFIX(p->MinContext); + + if (c->NumStats == 1) + { + CPpmd_State *s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + CPpmd_State *s = STATS(c); + if (s->Symbol != p->FoundState->Symbol) + { + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s[0].Freq >= s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + s--; + } + } + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + } + + if (p->OrderFall == 0) + { + p->MinContext = p->MaxContext = CreateSuccessors(p, True); + if (p->MinContext == 0) + { + RestartModel(p); + return; + } + SetSuccessor(p->FoundState, REF(p->MinContext)); + return; + } + + *p->Text++ = p->FoundState->Symbol; + successor = REF(p->Text); + if (p->Text >= p->UnitsStart) + { + RestartModel(p); + return; + } + + if (fSuccessor) + { + if (fSuccessor <= successor) + { + CTX_PTR cs = CreateSuccessors(p, False); + if (cs == NULL) + { + RestartModel(p); + return; + } + fSuccessor = REF(cs); + } + if (--p->OrderFall == 0) + { + successor = fSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + } + else + { + SetSuccessor(p->FoundState, successor); + fSuccessor = REF(p->MinContext); + } + + s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); + + for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 cf, sf; + if ((ns1 = c->NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + /* Expand for one UNIT */ + unsigned oldNU = ns1 >> 1; + unsigned i = U2I(oldNU); + if (i != U2I(oldNU + 1)) + { + void *ptr = AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + RestartModel(p); + return; + } + oldPtr = STATS(c); + MyMem12Cpy(ptr, oldPtr, oldNU); + InsertNode(p, oldPtr, i); + c->Stats = STATS_REF(ptr); + } + } + c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); + } + else + { + CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); + if (!s) + { + RestartModel(p); + return; + } + *s = *ONE_STATE(c); + c->Stats = REF(s); + if (s->Freq < MAX_FREQ / 4 - 1) + s->Freq <<= 1; + else + s->Freq = MAX_FREQ - 4; + c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); + } + cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); + sf = (UInt32)s0 + c->SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf) + (cf >= 4 * sf); + c->SummFreq += 3; + } + else + { + cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); + c->SummFreq = (UInt16)(c->SummFreq + cf); + } + { + CPpmd_State *s = STATS(c) + ns1; + SetSuccessor(s, successor); + s->Symbol = p->FoundState->Symbol; + s->Freq = (Byte)cf; + c->NumStats = (UInt16)(ns1 + 1); + } + } + p->MaxContext = p->MinContext = CTX(fSuccessor); +} + +static void Rescale(CPpmd7 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + { + CPpmd_State tmp = *s; + for (; s != stats; s--) + s[0] = s[-1]; + *s = tmp; + } + escFreq = p->MinContext->SummFreq - s->Freq; + s->Freq += 4; + adder = (p->OrderFall != 0); + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + + i = p->MinContext->NumStats - 1; + do + { + escFreq -= (++s)->Freq; + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq += s->Freq; + if (s[0].Freq > s[-1].Freq) + { + CPpmd_State *s1 = s; + CPpmd_State tmp = *s1; + do + s1[0] = s1[-1]; + while (--s1 != stats && tmp.Freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + unsigned numStats = p->MinContext->NumStats; + unsigned n0, n1; + do { i++; } while ((--s)->Freq == 0); + escFreq += i; + p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); + if (p->MinContext->NumStats == 1) + { + CPpmd_State tmp = *stats; + do + { + tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); + escFreq >>= 1; + } + while (escFreq > 1); + InsertNode(p, stats, U2I(((numStats + 1) >> 1))); + *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + return; + } + n0 = (numStats + 1) >> 1; + n1 = (p->MinContext->NumStats + 1) >> 1; + if (n0 != n1) + p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + } + p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + p->FoundState = STATS(p->MinContext); +} + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) +{ + CPpmd_See *see; + unsigned nonMasked = p->MinContext->NumStats - numMasked; + if (p->MinContext->NumStats != 256) + { + see = p->See[p->NS2Indx[nonMasked - 1]] + + (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + + 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + + 4 * (numMasked > nonMasked) + + p->HiBitsFlag; + { + unsigned r = (see->Summ >> see->Shift); + see->Summ = (UInt16)(see->Summ - r); + *escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + +static void NextContext(CPpmd7 *p) +{ + CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (Byte *)c > p->Text) + p->MinContext = p->MaxContext = c; + else + UpdateModel(p); +} + +void Ppmd7_Update1(CPpmd7 *p) +{ + CPpmd_State *s = p->FoundState; + s->Freq += 4; + p->MinContext->SummFreq += 4; + if (s[0].Freq > s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + p->FoundState = --s; + if (s->Freq > MAX_FREQ) + Rescale(p); + } + NextContext(p); +} + +void Ppmd7_Update1_0(CPpmd7 *p) +{ + p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); + p->RunLength += p->PrevSuccess; + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + NextContext(p); +} + +void Ppmd7_UpdateBin(CPpmd7 *p) +{ + p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); + p->PrevSuccess = 1; + p->RunLength++; + NextContext(p); +} + +void Ppmd7_Update2(CPpmd7 *p) +{ + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + p->RunLength = p->InitRL; + UpdateModel(p); +} diff --git a/ext/VFS/ext/7z/src/Ppmd7.h b/ext/VFS/ext/7z/src/Ppmd7.h new file mode 100644 index 000000000..56e81eb12 --- /dev/null +++ b/ext/VFS/ext/7z/src/Ppmd7.h @@ -0,0 +1,140 @@ +/* Ppmd7.h -- PPMdH compression codec +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +/* This code supports virtual RangeDecoder and includes the implementation +of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H. +If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */ + +#ifndef __PPMD7_H +#define __PPMD7_H + +#include "Ppmd.h" + +EXTERN_C_BEGIN + +#define PPMD7_MIN_ORDER 2 +#define PPMD7_MAX_ORDER 64 + +#define PPMD7_MIN_MEM_SIZE (1 << 11) +#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) + +struct CPpmd7_Context_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Context_ * + #else + UInt32 + #endif + CPpmd7_Context_Ref; + +typedef struct CPpmd7_Context_ +{ + UInt16 NumStats; + UInt16 SummFreq; + CPpmd_State_Ref Stats; + CPpmd7_Context_Ref Suffix; +} CPpmd7_Context; + +#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) + +typedef struct +{ + CPpmd7_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + UInt32 AlignOffset; + + Byte Indx2Units[PPMD_NUM_INDEXES]; + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; + CPpmd_See DummySee, See[25][16]; + UInt16 BinSumm[128][64]; +} CPpmd7; + +void Ppmd7_Construct(CPpmd7 *p); +Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc); +void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc); +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); +#define Ppmd7_WasAllocated(p) ((p)->Base != NULL) + + +/* ---------- Internal Functions ---------- */ + +extern const Byte PPMD7_kExpEscape[16]; + +#ifdef PPMD_32BIT + #define Ppmd7_GetPtr(p, ptr) (ptr) + #define Ppmd7_GetContext(p, ptr) (ptr) + #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) +#else + #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) + #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) +#endif + +void Ppmd7_Update1(CPpmd7 *p); +void Ppmd7_Update1_0(CPpmd7 *p); +void Ppmd7_Update2(CPpmd7 *p); +void Ppmd7_UpdateBin(CPpmd7 *p); + +#define Ppmd7_GetBinSumm(p) \ + &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ + p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ + (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ + 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \ + ((p->RunLength >> 26) & 0x20)] + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); + + +/* ---------- Decode ---------- */ + +typedef struct +{ + UInt32 (*GetThreshold)(void *p, UInt32 total); + void (*Decode)(void *p, UInt32 start, UInt32 size); + UInt32 (*DecodeBit)(void *p, UInt32 size0); +} IPpmd7_RangeDec; + +typedef struct +{ + IPpmd7_RangeDec p; + UInt32 Range; + UInt32 Code; + IByteIn *Stream; +} CPpmd7z_RangeDec; + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p); +Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p); +#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) + +int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc); + + +/* ---------- Encode ---------- */ + +typedef struct +{ + UInt64 Low; + UInt32 Range; + Byte Cache; + UInt64 CacheSize; + IByteOut *Stream; +} CPpmd7z_RangeEnc; + +void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p); +void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p); + +void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); + +EXTERN_C_END + +#endif diff --git a/ext/VFS/ext/7z/src/Ppmd7Dec.c b/ext/VFS/ext/7z/src/Ppmd7Dec.c new file mode 100644 index 000000000..d6608e8b3 --- /dev/null +++ b/ext/VFS/ext/7z/src/Ppmd7Dec.c @@ -0,0 +1,187 @@ +/* Ppmd7Dec.c -- PPMdH Decoder +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Ppmd7.h" + +#define kTopValue (1 << 24) + +Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) +{ + unsigned i; + p->Code = 0; + p->Range = 0xFFFFFFFF; + if (p->Stream->Read((void *)p->Stream) != 0) + return False; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + return (p->Code < 0xFFFFFFFF); +} + +static UInt32 Range_GetThreshold(void *pp, UInt32 total) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + return (p->Code) / (p->Range /= total); +} + +static void Range_Normalize(CPpmd7z_RangeDec *p) +{ + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + p->Range <<= 8; + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + p->Range <<= 8; + } + } +} + +static void Range_Decode(void *pp, UInt32 start, UInt32 size) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + p->Code -= start * p->Range; + p->Range *= size; + Range_Normalize(p); +} + +static UInt32 Range_DecodeBit(void *pp, UInt32 size0) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + UInt32 newBound = (p->Range >> 14) * size0; + UInt32 symbol; + if (p->Code < newBound) + { + symbol = 0; + p->Range = newBound; + } + else + { + symbol = 1; + p->Code -= newBound; + p->Range -= newBound; + } + Range_Normalize(p); + return symbol; +} + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) +{ + p->p.GetThreshold = Range_GetThreshold; + p->p.Decode = Range_Decode; + p->p.DecodeBit = Range_DecodeBit; +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + { + Byte symbol; + rc->Decode(rc, 0, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1_0(p); + return symbol; + } + p->PrevSuccess = 0; + i = p->MinContext->NumStats - 1; + do + { + if ((hiCnt += (++s)->Freq) > count) + { + Byte symbol; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1(p); + return symbol; + } + } + while (--i); + if (count >= p->MinContext->SummFreq) + return -2; + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } while (--i); + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + if (rc->DecodeBit(rc, *prob) == 0) + { + Byte symbol; + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; + Ppmd7_UpdateBin(p); + return symbol; + } + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + for (;;) + { + CPpmd_State *ps[256], *s; + UInt32 freqSum, count, hiCnt; + CPpmd_See *see; + unsigned i, num, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return -1; + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + hiCnt = 0; + s = Ppmd7_GetStats(p, p->MinContext); + i = 0; + num = p->MinContext->NumStats - numMasked; + do + { + int k = (int)(MASK(s->Symbol)); + hiCnt += (s->Freq & k); + ps[i] = s++; + i -= k; + } + while (i != num); + + see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + count = rc->GetThreshold(rc, freqSum); + + if (count < hiCnt) + { + Byte symbol; + CPpmd_State **pps = ps; + for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); + s = *pps; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + Ppmd_See_Update(see); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update2(p); + return symbol; + } + if (count >= freqSum) + return -2; + rc->Decode(rc, hiCnt, freqSum - hiCnt); + see->Summ = (UInt16)(see->Summ + freqSum); + do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); + } +} diff --git a/ext/VFS/ext/7z/src/Ppmd7Enc.c b/ext/VFS/ext/7z/src/Ppmd7Enc.c new file mode 100644 index 000000000..b1fecaed4 --- /dev/null +++ b/ext/VFS/ext/7z/src/Ppmd7Enc.c @@ -0,0 +1,185 @@ +/* Ppmd7Enc.c -- PPMdH Encoder +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Ppmd7.h" + +#define kTopValue (1 << 24) + +void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p) +{ + p->Low = 0; + p->Range = 0xFFFFFFFF; + p->Cache = 0; + p->CacheSize = 1; +} + +static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p) +{ + if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0) + { + Byte temp = p->Cache; + do + { + p->Stream->Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32))); + temp = 0xFF; + } + while(--p->CacheSize != 0); + p->Cache = (Byte)((UInt32)p->Low >> 24); + } + p->CacheSize++; + p->Low = (UInt32)p->Low << 8; +} + +static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total) +{ + p->Low += start * (p->Range /= total); + p->Range *= size; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0) +{ + p->Range = (p->Range >> 14) * size0; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0) +{ + UInt32 newBound = (p->Range >> 14) * size0; + p->Low += newBound; + p->Range -= newBound; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p) +{ + unsigned i; + for (i = 0; i < 5; i++) + RangeEnc_ShiftLow(p); +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + UInt32 sum; + unsigned i; + if (s->Symbol == symbol) + { + RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd7_Update1_0(p); + return; + } + p->PrevSuccess = 0; + sum = s->Freq; + i = p->MinContext->NumStats - 1; + do + { + if ((++s)->Symbol == symbol) + { + RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd7_Update1(p); + return; + } + sum += s->Freq; + } + while (--i); + + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } while (--i); + RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq); + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); + if (s->Symbol == symbol) + { + RangeEnc_EncodeBit_0(rc, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + p->FoundState = s; + Ppmd7_UpdateBin(p); + return; + } + else + { + RangeEnc_EncodeBit_1(rc, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + p->PrevSuccess = 0; + } + } + for (;;) + { + UInt32 escFreq; + CPpmd_See *see; + CPpmd_State *s; + UInt32 sum; + unsigned i, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return; /* EndMarker (symbol = -1) */ + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + + see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq); + s = Ppmd7_GetStats(p, p->MinContext); + sum = 0; + i = p->MinContext->NumStats; + do + { + int cur = s->Symbol; + if (cur == symbol) + { + UInt32 low = sum; + CPpmd_State *s1 = s; + do + { + sum += (s->Freq & (int)(MASK(s->Symbol))); + s++; + } + while (--i); + RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq); + Ppmd_See_Update(see); + p->FoundState = s1; + Ppmd7_Update2(p); + return; + } + sum += (s->Freq & (int)(MASK(cur))); + MASK(cur) = 0; + s++; + } + while (--i); + + RangeEnc_Encode(rc, sum, escFreq, sum + escFreq); + see->Summ = (UInt16)(see->Summ + sum + escFreq); + } +} diff --git a/ext/VFS/ext/7z/src/Ppmd8.c b/ext/VFS/ext/7z/src/Ppmd8.c new file mode 100644 index 000000000..4fe723fe2 --- /dev/null +++ b/ext/VFS/ext/7z/src/Ppmd8.c @@ -0,0 +1,1120 @@ +/* Ppmd8.c -- PPMdI codec +2010-03-24 : Igor Pavlov : Public domain +This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */ + +#include + +#include "Ppmd8.h" + +const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(nu) - 1]) +#define I2U(indx) (p->Indx2Units[indx]) + +#ifdef PPMD_32BIT + #define REF(ptr) (ptr) +#else + #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) +#endif + +#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) + +#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) +#define STATS(ctx) Ppmd8_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +typedef CPpmd8_Context * CTX_PTR; + +struct CPpmd8_Node_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd8_Node_ * + #else + UInt32 + #endif + CPpmd8_Node_Ref; + +typedef struct CPpmd8_Node_ +{ + UInt32 Stamp; + CPpmd8_Node_Ref Next; + UInt32 NU; +} CPpmd8_Node; + +#ifdef PPMD_32BIT + #define NODE(ptr) (ptr) +#else + #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs))) +#endif + +#define EMPTY_NODE 0xFFFFFFFF + +void Ppmd8_Construct(CPpmd8 *p) +{ + unsigned i, k, m; + + p->Base = 0; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while(--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 5; i++) + p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 260; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 4; + } +} + +void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->Base); + p->Size = 0; + p->Base = 0; +} + +Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc) +{ + if (p->Base == 0 || p->Size != size) + { + Ppmd8_Free(p, alloc); + p->AlignOffset = + #ifdef PPMD_32BIT + (4 - size) & 3; + #else + 4 - (size & 3); + #endif + if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size)) == 0) + return False; + p->Size = size; + } + return True; +} + +static void InsertNode(CPpmd8 *p, void *node, unsigned indx) +{ + ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE; + ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx]; + ((CPpmd8_Node *)node)->NU = I2U(indx); + p->FreeList[indx] = REF(node); + p->Stamps[indx]++; +} + +static void *RemoveNode(CPpmd8 *p, unsigned indx) +{ + CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]); + p->FreeList[indx] = node->Next; + p->Stamps[indx]--; + return node; +} + +static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + InsertNode(p, ptr, i); +} + +static void GlueFreeBlocks(CPpmd8 *p) +{ + CPpmd8_Node_Ref head = 0; + CPpmd8_Node_Ref *prev = &head; + unsigned i; + + p->GlueCount = 1 << 13; + memset(p->Stamps, 0, sizeof(p->Stamps)); + + /* Order-0 context is always at top UNIT, so we don't need guard NODE at the end. + All blocks up to p->LoUnit can be free, so we need guard NODE at LoUnit. */ + if (p->LoUnit != p->HiUnit) + ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; + + /* Glue free blocks */ + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd8_Node *node = NODE(next); + if (node->NU != 0) + { + CPpmd8_Node *node2; + *prev = next; + prev = &(node->Next); + while ((node2 = node + node->NU)->Stamp == EMPTY_NODE) + { + node->NU += node2->NU; + node2->NU = 0; + } + } + next = node->Next; + } + } + *prev = 0; + + /* Fill lists of free blocks */ + while (head != 0) + { + CPpmd8_Node *node = NODE(head); + unsigned nu; + head = node->Next; + nu = node->NU; + if (nu == 0) + continue; + for (; nu > 128; nu -= 128, node += 128) + InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, node + k, nu - k - 1); + } + InsertNode(p, node, i); + } +} + +static void *AllocUnitsRare(CPpmd8 *p, unsigned indx) +{ + unsigned i; + void *retVal; + if (p->GlueCount == 0) + { + GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + } + i = indx; + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + p->GlueCount--; + return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + retVal = RemoveNode(p, i); + SplitBlock(p, retVal, i, indx); + return retVal; +} + +static void *AllocUnits(CPpmd8 *p, unsigned indx) +{ + UInt32 numBytes; + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + numBytes = U2B(I2U(indx)); + if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + { + void *retVal = p->LoUnit; + p->LoUnit += numBytes; + return retVal; + } + return AllocUnitsRare(p, indx); +} + +#define MyMem12Cpy(dest, src, num) \ + { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ + do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } + +static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +{ + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void *ptr = RemoveNode(p, i1); + MyMem12Cpy(ptr, oldPtr, newNU); + InsertNode(p, oldPtr, i0); + return ptr; + } + SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} + +static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu) +{ + InsertNode(p, ptr, U2I(nu)); +} + +static void SpecialFreeUnit(CPpmd8 *p, void *ptr) +{ + if ((Byte *)ptr != p->UnitsStart) + InsertNode(p, ptr, 0); + else + { + #ifdef PPMD8_FREEZE_SUPPORT + *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */ + #endif + p->UnitsStart += UNIT_SIZE; + } +} + +static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu) +{ + unsigned indx = U2I(nu); + void *ptr; + if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx]) + return oldPtr; + ptr = RemoveNode(p, indx); + MyMem12Cpy(ptr, oldPtr, nu); + if ((Byte*)oldPtr != p->UnitsStart) + InsertNode(p, oldPtr, indx); + else + p->UnitsStart += U2B(I2U(indx)); + return ptr; +} + +static void ExpandTextArea(CPpmd8 *p) +{ + UInt32 count[PPMD_NUM_INDEXES]; + unsigned i; + memset(count, 0, sizeof(count)); + if (p->LoUnit != p->HiUnit) + ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; + + { + CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart; + for (; node->Stamp == EMPTY_NODE; node += node->NU) + { + node->Stamp = 0; + count[U2I(node->NU)]++; + } + p->UnitsStart = (Byte *)node; + } + + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i]; + while (count[i] != 0) + { + CPpmd8_Node *node = NODE(*next); + while (node->Stamp == 0) + { + *next = node->Next; + node = NODE(*next); + p->Stamps[i]--; + if (--count[i] == 0) + break; + } + next = &node->Next; + } + } +} + +#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) + +static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); +} + +#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); } + +static void RestartModel(CPpmd8 *p) +{ + unsigned i, k, m, r; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + memset(p->Stamps, 0, sizeof(p->Stamps)); + RESET_TEXT(0); + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + p->MinContext->Suffix = 0; + p->MinContext->NumStats = 255; + p->MinContext->Flags = 0; + p->MinContext->SummFreq = 256 + 1; + p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + p->LoUnit += U2B(256 / 2); + p->MinContext->Stats = REF(p->FoundState); + for (i = 0; i < 256; i++) + { + CPpmd_State *s = &p->FoundState[i]; + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + for (i = m = 0; m < 25; m++) + { + while (p->NS2Indx[i] == m) + i++; + for (k = 0; k < 8; k++) + { + UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1)); + UInt16 *dest = p->BinSumm[m] + k; + for (r = 0; r < 64; r += 8) + dest[r] = val; + } + } + + for (i = m = 0; m < 24; m++) + { + while (p->NS2Indx[i + 3] == m + 3) + i++; + for (k = 0; k < 32; k++) + { + CPpmd_See *s = &p->See[m][k]; + s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Count = 7; + } + } +} + +void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod) +{ + p->MaxOrder = maxOrder; + p->RestoreMethod = restoreMethod; + RestartModel(p); + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Count = 64; /* unused */ +} + +static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale) +{ + unsigned i = ctx->NumStats, escFreq, sumFreq, flags; + CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); + ctx->Stats = REF(s); + #ifdef PPMD8_FREEZE_SUPPORT + /* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */ + scale |= (ctx->SummFreq >= ((UInt32)1 << 15)); + #endif + flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40); + escFreq = ctx->SummFreq - s->Freq; + sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale)); + do + { + escFreq -= (++s)->Freq; + sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale)); + flags |= 0x08 * (s->Symbol >= 0x40); + } + while (--i); + ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale)); + ctx->Flags = (Byte)flags; +} + +static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) +{ + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; +} + +static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order) +{ + int i; + unsigned tmp; + CPpmd_State *s; + + if (!ctx->NumStats) + { + s = ONE_STATE(ctx); + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart) + { + if (order < p->MaxOrder) + SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + if (SUCCESSOR(s) || order <= 9) /* O_BOUND */ + return REF(ctx); + } + SpecialFreeUnit(p, ctx); + return 0; + } + + ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1)); + + for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--) + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart) + { + CPpmd_State *s2 = STATS(ctx) + (i--); + SetSuccessor(s, 0); + SwapStates(s, s2); + } + else if (order < p->MaxOrder) + SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + + if (i != ctx->NumStats && order) + { + ctx->NumStats = (Byte)i; + s = STATS(ctx); + if (i < 0) + { + FreeUnits(p, s, tmp); + SpecialFreeUnit(p, ctx); + return 0; + } + if (i == 0) + { + ctx->Flags = (ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40); + *ONE_STATE(ctx) = *s; + FreeUnits(p, s, tmp); + ONE_STATE(ctx)->Freq = (Byte)((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3; + } + else + Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i); + } + return REF(ctx); +} + +#ifdef PPMD8_FREEZE_SUPPORT +static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order) +{ + CPpmd_State *s; + if (!ctx->NumStats) + { + s = ONE_STATE(ctx); + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) + SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + /* Suffix context can be removed already, since different (high-order) + Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */ + if (!SUCCESSOR(s) && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF)) + { + FreeUnits(p, ctx, 1); + return 0; + } + else + return REF(ctx); + } + + for (s = STATS(ctx) + ctx->NumStats; s >= STATS(ctx); s--) + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) + SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + + return REF(ctx); +} +#endif + +static UInt32 GetUsedMemory(const CPpmd8 *p) +{ + UInt32 v = 0; + unsigned i; + for (i = 0; i < PPMD_NUM_INDEXES; i++) + v += p->Stamps[i] * I2U(i); + return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v); +} + +#ifdef PPMD8_FREEZE_SUPPORT + #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor) +#else + #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1) +#endif + +static void RestoreModel(CPpmd8 *p, CTX_PTR c1 + #ifdef PPMD8_FREEZE_SUPPORT + , CTX_PTR fSuccessor + #endif + ) +{ + CTX_PTR c; + CPpmd_State *s; + RESET_TEXT(0); + for (c = p->MaxContext; c != c1; c = SUFFIX(c)) + if (--(c->NumStats) == 0) + { + s = STATS(c); + c->Flags = (c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40); + *ONE_STATE(c) = *s; + SpecialFreeUnit(p, s); + ONE_STATE(c)->Freq = (ONE_STATE(c)->Freq + 11) >> 3; + } + else + Refresh(p, c, (c->NumStats+3) >> 1, 0); + + for (; c != p->MinContext; c = SUFFIX(c)) + if (!c->NumStats) + ONE_STATE(c)->Freq -= ONE_STATE(c)->Freq >> 1; + else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats) + Refresh(p, c, (c->NumStats + 2) >> 1, 1); + + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + p->MaxContext = fSuccessor; + p->GlueCount += !(p->Stamps[1] & 1); + } + else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE) + { + while (p->MaxContext->Suffix) + p->MaxContext = SUFFIX(p->MaxContext); + RemoveBinContexts(p, p->MaxContext, 0); + p->RestoreMethod++; + p->GlueCount = 0; + p->OrderFall = p->MaxOrder; + } + else + #endif + if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1)) + RestartModel(p); + else + { + while (p->MaxContext->Suffix) + p->MaxContext = SUFFIX(p->MaxContext); + do + { + CutOff(p, p->MaxContext, 0); + ExpandTextArea(p); + } + while (GetUsedMemory(p) > 3 * (p->Size >> 2)); + p->GlueCount = 0; + p->OrderFall = p->MaxOrder; + } +} + +static CTX_PTR CreateSuccessors(CPpmd8 *p, Bool skip, CPpmd_State *s1, CTX_PTR c) +{ + CPpmd_State upState; + Byte flags; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + /* fixed over Shkarin's code. Maybe it could work without + 1 too. */ + CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; + unsigned numPs = 0; + + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + if (s1) + { + s = s1; + s1 = NULL; + } + else if (c->NumStats != 0) + { + for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + if (s->Freq < MAX_FREQ - 9) + { + s->Freq++; + c->SummFreq++; + } + } + else + { + s = ONE_STATE(c); + s->Freq += (!SUFFIX(c)->NumStats & (s->Freq < 24)); + } + successor = SUCCESSOR(s); + if (successor != upBranch) + { + c = CTX(successor); + if (numPs == 0) + return c; + break; + } + ps[numPs++] = s; + } + + upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch); + SetSuccessor(&upState, upBranch + 1); + flags = 0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40); + + if (c->NumStats == 0) + upState.Freq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != upState.Symbol; s++); + cf = s->Freq - 1; + s0 = c->SummFreq - c->NumStats - cf; + upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0))); + } + + do + { + /* Create Child */ + CTX_PTR c1; /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (CTX_PTR)RemoveNode(p, 0); + else + { + c1 = (CTX_PTR)AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->NumStats = 0; + c1->Flags = flags; + *ONE_STATE(c1) = upState; + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; +} + +static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c) +{ + CPpmd_State *s = NULL; + CTX_PTR c1 = c; + CPpmd_Void_Ref upBranch = REF(p->Text); + + #ifdef PPMD8_FREEZE_SUPPORT + /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */ + CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; + unsigned numPs = 0; + ps[numPs++] = p->FoundState; + #endif + + SetSuccessor(p->FoundState, upBranch); + p->OrderFall++; + + for (;;) + { + if (s1) + { + c = SUFFIX(c); + s = s1; + s1 = NULL; + } + else + { + if (!c->Suffix) + { + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); + RESET_TEXT(1); + p->OrderFall = 1; + } + #endif + return c; + } + c = SUFFIX(c); + if (c->NumStats) + { + if ((s = STATS(c))->Symbol != p->FoundState->Symbol) + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + else + { + s = ONE_STATE(c); + s->Freq += (s->Freq < 32); + } + } + if (SUCCESSOR(s)) + break; + #ifdef PPMD8_FREEZE_SUPPORT + ps[numPs++] = s; + #endif + SetSuccessor(s, upBranch); + p->OrderFall++; + } + + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + c = CTX(SUCCESSOR(s)); + do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); + RESET_TEXT(1); + p->OrderFall = 1; + return c; + } + else + #endif + if (SUCCESSOR(s) <= upBranch) + { + CTX_PTR successor; + CPpmd_State *s1 = p->FoundState; + p->FoundState = s; + + successor = CreateSuccessors(p, False, NULL, c); + if (successor == NULL) + SetSuccessor(s, 0); + else + SetSuccessor(s, REF(successor)); + p->FoundState = s1; + } + + if (p->OrderFall == 1 && c1 == p->MaxContext) + { + SetSuccessor(p->FoundState, SUCCESSOR(s)); + p->Text--; + } + if (SUCCESSOR(s) == 0) + return NULL; + return CTX(SUCCESSOR(s)); +} + +static void UpdateModel(CPpmd8 *p) +{ + CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); + CTX_PTR c; + unsigned s0, ns, fFreq = p->FoundState->Freq; + Byte flag, fSymbol = p->FoundState->Symbol; + CPpmd_State *s = NULL; + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + c = SUFFIX(p->MinContext); + + if (c->NumStats == 0) + { + s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + s = STATS(c); + if (s->Symbol != p->FoundState->Symbol) + { + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s[0].Freq >= s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + s--; + } + } + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + } + + c = p->MaxContext; + if (p->OrderFall == 0 && fSuccessor) + { + CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext); + if (cs == 0) + { + SetSuccessor(p->FoundState, 0); + RESTORE_MODEL(c, CTX(fSuccessor)); + } + else + { + SetSuccessor(p->FoundState, REF(cs)); + p->MaxContext = cs; + } + return; + } + + *p->Text++ = p->FoundState->Symbol; + successor = REF(p->Text); + if (p->Text >= p->UnitsStart) + { + RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */ + return; + } + + if (!fSuccessor) + { + CTX_PTR cs = ReduceOrder(p, s, p->MinContext); + if (cs == NULL) + { + RESTORE_MODEL(c, 0); + return; + } + fSuccessor = REF(cs); + } + else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart) + { + CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext); + if (cs == NULL) + { + RESTORE_MODEL(c, 0); + return; + } + fSuccessor = REF(cs); + } + + if (--p->OrderFall == 0) + { + successor = fSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + #ifdef PPMD8_FREEZE_SUPPORT + else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + successor = fSuccessor; + RESET_TEXT(0); + p->OrderFall = 0; + } + #endif + + s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq; + flag = 0x08 * (fSymbol >= 0x40); + + for (; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 cf, sf; + if ((ns1 = c->NumStats) != 0) + { + if ((ns1 & 1) != 0) + { + /* Expand for one UNIT */ + unsigned oldNU = (ns1 + 1) >> 1; + unsigned i = U2I(oldNU); + if (i != U2I(oldNU + 1)) + { + void *ptr = AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + RESTORE_MODEL(c, CTX(fSuccessor)); + return; + } + oldPtr = STATS(c); + MyMem12Cpy(ptr, oldPtr, oldNU); + InsertNode(p, oldPtr, i); + c->Stats = STATS_REF(ptr); + } + } + c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns)); + } + else + { + CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); + if (!s) + { + RESTORE_MODEL(c, CTX(fSuccessor)); + return; + } + *s = *ONE_STATE(c); + c->Stats = REF(s); + if (s->Freq < MAX_FREQ / 4 - 1) + s->Freq <<= 1; + else + s->Freq = MAX_FREQ - 4; + c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 2)); + } + cf = 2 * fFreq * (c->SummFreq + 6); + sf = (UInt32)s0 + c->SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf) + (cf >= 4 * sf); + c->SummFreq += 4; + } + else + { + cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf); + c->SummFreq = (UInt16)(c->SummFreq + cf); + } + { + CPpmd_State *s = STATS(c) + ns1 + 1; + SetSuccessor(s, successor); + s->Symbol = fSymbol; + s->Freq = (Byte)cf; + c->Flags |= flag; + c->NumStats = (Byte)(ns1 + 1); + } + } + p->MaxContext = p->MinContext = CTX(fSuccessor); +} + +static void Rescale(CPpmd8 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + { + CPpmd_State tmp = *s; + for (; s != stats; s--) + s[0] = s[-1]; + *s = tmp; + } + escFreq = p->MinContext->SummFreq - s->Freq; + s->Freq += 4; + adder = (p->OrderFall != 0 + #ifdef PPMD8_FREEZE_SUPPORT + || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE + #endif + ); + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + + i = p->MinContext->NumStats; + do + { + escFreq -= (++s)->Freq; + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq += s->Freq; + if (s[0].Freq > s[-1].Freq) + { + CPpmd_State *s1 = s; + CPpmd_State tmp = *s1; + do + s1[0] = s1[-1]; + while (--s1 != stats && tmp.Freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + unsigned numStats = p->MinContext->NumStats; + unsigned n0, n1; + do { i++; } while ((--s)->Freq == 0); + escFreq += i; + p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i); + if (p->MinContext->NumStats == 0) + { + CPpmd_State tmp = *stats; + tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq); + if (tmp.Freq > MAX_FREQ / 3) + tmp.Freq = MAX_FREQ / 3; + InsertNode(p, stats, U2I((numStats + 2) >> 1)); + p->MinContext->Flags = (p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40); + *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + return; + } + n0 = (numStats + 2) >> 1; + n1 = (p->MinContext->NumStats + 2) >> 1; + if (n0 != n1) + p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + p->MinContext->Flags &= ~0x08; + p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40); + i = p->MinContext->NumStats; + do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i); + } + p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + p->MinContext->Flags |= 0x4; + p->FoundState = STATS(p->MinContext); +} + +CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq) +{ + CPpmd_See *see; + if (p->MinContext->NumStats != 0xFF) + { + see = p->See[p->NS2Indx[p->MinContext->NumStats + 2] - 3] + + (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) + + 2 * (2 * (unsigned)p->MinContext->NumStats < + ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) + + p->MinContext->Flags; + { + unsigned r = (see->Summ >> see->Shift); + see->Summ = (UInt16)(see->Summ - r); + *escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + +static void NextContext(CPpmd8 *p) +{ + CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart) + p->MinContext = p->MaxContext = c; + else + { + UpdateModel(p); + p->MinContext = p->MaxContext; + } +} + +void Ppmd8_Update1(CPpmd8 *p) +{ + CPpmd_State *s = p->FoundState; + s->Freq += 4; + p->MinContext->SummFreq += 4; + if (s[0].Freq > s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + p->FoundState = --s; + if (s->Freq > MAX_FREQ) + Rescale(p); + } + NextContext(p); +} + +void Ppmd8_Update1_0(CPpmd8 *p) +{ + p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq); + p->RunLength += p->PrevSuccess; + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + NextContext(p); +} + +void Ppmd8_UpdateBin(CPpmd8 *p) +{ + p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196)); + p->PrevSuccess = 1; + p->RunLength++; + NextContext(p); +} + +void Ppmd8_Update2(CPpmd8 *p) +{ + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + p->RunLength = p->InitRL; + UpdateModel(p); + p->MinContext = p->MaxContext; +} + +/* H->I changes: + NS2Indx + GlewCount, and Glue method + BinSum + See / EscFreq + CreateSuccessors updates more suffix contexts + UpdateModel consts. + PrevSuccess Update +*/ diff --git a/ext/VFS/ext/7z/src/Ppmd8.h b/ext/VFS/ext/7z/src/Ppmd8.h new file mode 100644 index 000000000..6efd4eaf3 --- /dev/null +++ b/ext/VFS/ext/7z/src/Ppmd8.h @@ -0,0 +1,133 @@ +/* Ppmd8.h -- PPMdI codec +2010-03-24 : Igor Pavlov : Public domain +This code is based on: + PPMd var.I (2002): Dmitry Shkarin : Public domain + Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#ifndef __PPMD8_H +#define __PPMD8_H + +#include "Ppmd.h" + +EXTERN_C_BEGIN + +#define PPMD8_MIN_ORDER 2 +#define PPMD8_MAX_ORDER 16 + +struct CPpmd8_Context_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd8_Context_ * + #else + UInt32 + #endif + CPpmd8_Context_Ref; + +typedef struct CPpmd8_Context_ +{ + Byte NumStats; + Byte Flags; + UInt16 SummFreq; + CPpmd_State_Ref Stats; + CPpmd8_Context_Ref Suffix; +} CPpmd8_Context; + +#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) + +/* The BUG in Shkarin's code for FREEZE mode was fixed, but that fixed + code is not compatible with original code for some files compressed + in FREEZE mode. So we disable FREEZE mode support. */ + +enum +{ + PPMD8_RESTORE_METHOD_RESTART, + PPMD8_RESTORE_METHOD_CUT_OFF + #ifdef PPMD8_FREEZE_SUPPORT + , PPMD8_RESTORE_METHOD_FREEZE + #endif +}; + +typedef struct +{ + CPpmd8_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + UInt32 AlignOffset; + unsigned RestoreMethod; + + /* Range Coder */ + UInt32 Range; + UInt32 Code; + UInt32 Low; + union + { + IByteIn *In; + IByteOut *Out; + } Stream; + + Byte Indx2Units[PPMD_NUM_INDEXES]; + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + UInt32 Stamps[PPMD_NUM_INDEXES]; + + Byte NS2BSIndx[256], NS2Indx[260]; + CPpmd_See DummySee, See[24][32]; + UInt16 BinSumm[25][64]; +} CPpmd8; + +void Ppmd8_Construct(CPpmd8 *p); +Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc); +void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc); +void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod); +#define Ppmd8_WasAllocated(p) ((p)->Base != NULL) + + +/* ---------- Internal Functions ---------- */ + +extern const Byte PPMD8_kExpEscape[16]; + +#ifdef PPMD_32BIT + #define Ppmd8_GetPtr(p, ptr) (ptr) + #define Ppmd8_GetContext(p, ptr) (ptr) + #define Ppmd8_GetStats(p, ctx) ((ctx)->Stats) +#else + #define Ppmd8_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd8_GetContext(p, offs) ((CPpmd8_Context *)Ppmd8_GetPtr((p), (offs))) + #define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats))) +#endif + +void Ppmd8_Update1(CPpmd8 *p); +void Ppmd8_Update1_0(CPpmd8 *p); +void Ppmd8_Update2(CPpmd8 *p); +void Ppmd8_UpdateBin(CPpmd8 *p); + +#define Ppmd8_GetBinSumm(p) \ + &p->BinSumm[p->NS2Indx[Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \ + p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \ + p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)] + +CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale); + + +/* ---------- Decode ---------- */ + +Bool Ppmd8_RangeDec_Init(CPpmd8 *p); +#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0) +int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */ + + +/* ---------- Encode ---------- */ + +#define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; } +void Ppmd8_RangeEnc_FlushData(CPpmd8 *p); +void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */ + +EXTERN_C_END + +#endif diff --git a/ext/VFS/ext/7z/src/Ppmd8Dec.c b/ext/VFS/ext/7z/src/Ppmd8Dec.c new file mode 100644 index 000000000..2d2c06cbb --- /dev/null +++ b/ext/VFS/ext/7z/src/Ppmd8Dec.c @@ -0,0 +1,155 @@ +/* Ppmd8Dec.c -- PPMdI Decoder +2010-03-12 : Igor Pavlov : Public domain +This code is based on: + PPMd var.I (2002): Dmitry Shkarin : Public domain + Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#include "Ppmd8.h" + +#define kTop (1 << 24) +#define kBot (1 << 15) + +Bool Ppmd8_RangeDec_Init(CPpmd8 *p) +{ + unsigned i; + p->Low = 0; + p->Range = 0xFFFFFFFF; + p->Code = 0; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); + return (p->Code < 0xFFFFFFFF); +} + +static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total) +{ + return p->Code / (p->Range /= total); +} + +static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size) +{ + start *= p->Range; + p->Low += start; + p->Code -= start; + p->Range *= size; + + while ((p->Low ^ (p->Low + p->Range)) < kTop || + p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)) + { + p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); + p->Range <<= 8; + p->Low <<= 8; + } +} + +#define MASK(sym) ((signed char *)charMask)[sym] + +int Ppmd8_DecodeSymbol(CPpmd8 *p) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 0) + { + CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + { + Byte symbol; + RangeDec_Decode(p, 0, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd8_Update1_0(p); + return symbol; + } + p->PrevSuccess = 0; + i = p->MinContext->NumStats; + do + { + if ((hiCnt += (++s)->Freq) > count) + { + Byte symbol; + RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd8_Update1(p); + return symbol; + } + } + while (--i); + if (count >= p->MinContext->SummFreq) + return -2; + RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt); + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats; + do { MASK((--s)->Symbol) = 0; } while (--i); + } + else + { + UInt16 *prob = Ppmd8_GetBinSumm(p); + if (((p->Code / (p->Range >>= 14)) < *prob)) + { + Byte symbol; + RangeDec_Decode(p, 0, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol; + Ppmd8_UpdateBin(p); + return symbol; + } + RangeDec_Decode(p, *prob, (1 << 14) - *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD8_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + for (;;) + { + CPpmd_State *ps[256], *s; + UInt32 freqSum, count, hiCnt; + CPpmd_See *see; + unsigned i, num, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return -1; + p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + hiCnt = 0; + s = Ppmd8_GetStats(p, p->MinContext); + i = 0; + num = p->MinContext->NumStats - numMasked; + do + { + int k = (int)(MASK(s->Symbol)); + hiCnt += (s->Freq & k); + ps[i] = s++; + i -= k; + } + while (i != num); + + see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + count = RangeDec_GetThreshold(p, freqSum); + + if (count < hiCnt) + { + Byte symbol; + CPpmd_State **pps = ps; + for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); + s = *pps; + RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); + Ppmd_See_Update(see); + p->FoundState = s; + symbol = s->Symbol; + Ppmd8_Update2(p); + return symbol; + } + if (count >= freqSum) + return -2; + RangeDec_Decode(p, hiCnt, freqSum - hiCnt); + see->Summ = (UInt16)(see->Summ + freqSum); + do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); + } +} diff --git a/ext/VFS/ext/7z/src/Ppmd8Enc.c b/ext/VFS/ext/7z/src/Ppmd8Enc.c new file mode 100644 index 000000000..7be55caf5 --- /dev/null +++ b/ext/VFS/ext/7z/src/Ppmd8Enc.c @@ -0,0 +1,161 @@ +/* Ppmd8Enc.c -- PPMdI Encoder +2010-03-12 : Igor Pavlov : Public domain +This code is based on: + PPMd var.I (2002): Dmitry Shkarin : Public domain + Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#include "Ppmd8.h" + +#define kTop (1 << 24) +#define kBot (1 << 15) + +void Ppmd8_RangeEnc_FlushData(CPpmd8 *p) +{ + unsigned i; + for (i = 0; i < 4; i++, p->Low <<= 8 ) + p->Stream.Out->Write(p->Stream.Out, (Byte)(p->Low >> 24)); +} + +static void RangeEnc_Normalize(CPpmd8 *p) +{ + while ((p->Low ^ (p->Low + p->Range)) < kTop || + p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)) + { + p->Stream.Out->Write(p->Stream.Out, (Byte)(p->Low >> 24)); + p->Range <<= 8; + p->Low <<= 8; + } +} + +static void RangeEnc_Encode(CPpmd8 *p, UInt32 start, UInt32 size, UInt32 total) +{ + p->Low += start * (p->Range /= total); + p->Range *= size; + RangeEnc_Normalize(p); +} + +static void RangeEnc_EncodeBit_0(CPpmd8 *p, UInt32 size0) +{ + p->Range >>= 14; + p->Range *= size0; + RangeEnc_Normalize(p); +} + +static void RangeEnc_EncodeBit_1(CPpmd8 *p, UInt32 size0) +{ + p->Low += size0 * (p->Range >>= 14); + p->Range *= ((1 << 14) - size0); + RangeEnc_Normalize(p); +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 0) + { + CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); + UInt32 sum; + unsigned i; + if (s->Symbol == symbol) + { + RangeEnc_Encode(p, 0, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd8_Update1_0(p); + return; + } + p->PrevSuccess = 0; + sum = s->Freq; + i = p->MinContext->NumStats; + do + { + if ((++s)->Symbol == symbol) + { + RangeEnc_Encode(p, sum, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd8_Update1(p); + return; + } + sum += s->Freq; + } + while (--i); + + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats; + do { MASK((--s)->Symbol) = 0; } while (--i); + RangeEnc_Encode(p, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq); + } + else + { + UInt16 *prob = Ppmd8_GetBinSumm(p); + CPpmd_State *s = Ppmd8Context_OneState(p->MinContext); + if (s->Symbol == symbol) + { + RangeEnc_EncodeBit_0(p, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + p->FoundState = s; + Ppmd8_UpdateBin(p); + return; + } + else + { + RangeEnc_EncodeBit_1(p, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD8_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + p->PrevSuccess = 0; + } + } + for (;;) + { + UInt32 escFreq; + CPpmd_See *see; + CPpmd_State *s; + UInt32 sum; + unsigned i, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return; /* EndMarker (symbol = -1) */ + p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + + see = Ppmd8_MakeEscFreq(p, numMasked, &escFreq); + s = Ppmd8_GetStats(p, p->MinContext); + sum = 0; + i = p->MinContext->NumStats + 1; + do + { + int cur = s->Symbol; + if (cur == symbol) + { + UInt32 low = sum; + CPpmd_State *s1 = s; + do + { + sum += (s->Freq & (int)(MASK(s->Symbol))); + s++; + } + while (--i); + RangeEnc_Encode(p, low, s1->Freq, sum + escFreq); + Ppmd_See_Update(see); + p->FoundState = s1; + Ppmd8_Update2(p); + return; + } + sum += (s->Freq & (int)(MASK(cur))); + MASK(cur) = 0; + s++; + } + while (--i); + + RangeEnc_Encode(p, sum, escFreq, sum + escFreq); + see->Summ = (UInt16)(see->Summ + sum + escFreq); + } +} diff --git a/ext/VFS/ext/7z/src/RotateDefs.h b/ext/VFS/ext/7z/src/RotateDefs.h new file mode 100644 index 000000000..ff9b72290 --- /dev/null +++ b/ext/VFS/ext/7z/src/RotateDefs.h @@ -0,0 +1,20 @@ +/* RotateDefs.h -- Rotate functions +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __ROTATE_DEFS_H +#define __ROTATE_DEFS_H + +#ifdef _MSC_VER + +#include +#define rotlFixed(x, n) _rotl((x), (n)) +#define rotrFixed(x, n) _rotr((x), (n)) + +#else + +#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) + +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/Sha256.c b/ext/VFS/ext/7z/src/Sha256.c new file mode 100644 index 000000000..cab4048c6 --- /dev/null +++ b/ext/VFS/ext/7z/src/Sha256.c @@ -0,0 +1,204 @@ +/* Crypto/Sha256.c -- SHA-256 Hash function +2008-11-06 : Igor Pavlov : Public domain +This code is based on public domain code from Wei Dai's Crypto++ library. */ + +#include "Sha256.h" +#include "RotateDefs.h" + +/* define it for speed optimization */ +/* #define _SHA256_UNROLL */ +/* #define _SHA256_UNROLL2 */ + +void Sha256_Init(CSha256 *p) +{ + p->state[0] = 0x6a09e667; + p->state[1] = 0xbb67ae85; + p->state[2] = 0x3c6ef372; + p->state[3] = 0xa54ff53a; + p->state[4] = 0x510e527f; + p->state[5] = 0x9b05688c; + p->state[6] = 0x1f83d9ab; + p->state[7] = 0x5be0cd19; + p->count = 0; +} + +#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22)) +#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25)) +#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3)) +#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10)) + +#define blk0(i) (W[i] = data[i]) +#define blk2(i) (W[i&15] += s1(W[(i-2)&15]) + W[(i-7)&15] + s0(W[(i-15)&15])) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) ((x&y)|(z&(x|y))) + +#define a(i) T[(0-(i))&7] +#define b(i) T[(1-(i))&7] +#define c(i) T[(2-(i))&7] +#define d(i) T[(3-(i))&7] +#define e(i) T[(4-(i))&7] +#define f(i) T[(5-(i))&7] +#define g(i) T[(6-(i))&7] +#define h(i) T[(7-(i))&7] + + +#ifdef _SHA256_UNROLL2 + +#define R(a,b,c,d,e,f,g,h, i) h += S1(e) + Ch(e,f,g) + K[i+j] + (j?blk2(i):blk0(i));\ + d += h; h += S0(a) + Maj(a, b, c) + +#define RX_8(i) \ + R(a,b,c,d,e,f,g,h, i); \ + R(h,a,b,c,d,e,f,g, i+1); \ + R(g,h,a,b,c,d,e,f, i+2); \ + R(f,g,h,a,b,c,d,e, i+3); \ + R(e,f,g,h,a,b,c,d, i+4); \ + R(d,e,f,g,h,a,b,c, i+5); \ + R(c,d,e,f,g,h,a,b, i+6); \ + R(b,c,d,e,f,g,h,a, i+7) + +#else + +#define R(i) h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[i+j] + (j?blk2(i):blk0(i));\ + d(i) += h(i); h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) + +#ifdef _SHA256_UNROLL + +#define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7); + +#endif + +#endif + +const UInt32 K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static void Sha256_Transform(UInt32 *state, const UInt32 *data) +{ + UInt32 W[16]; + unsigned j; + #ifdef _SHA256_UNROLL2 + UInt32 a,b,c,d,e,f,g,h; + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; + #else + UInt32 T[8]; + for (j = 0; j < 8; j++) + T[j] = state[j]; + #endif + + for (j = 0; j < 64; j += 16) + { + #if defined(_SHA256_UNROLL) || defined(_SHA256_UNROLL2) + RX_8(0); RX_8(8); + #else + unsigned i; + for (i = 0; i < 16; i++) { R(i); } + #endif + } + + #ifdef _SHA256_UNROLL2 + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; + #else + for (j = 0; j < 8; j++) + state[j] += T[j]; + #endif + + /* Wipe variables */ + /* memset(W, 0, sizeof(W)); */ + /* memset(T, 0, sizeof(T)); */ +} + +#undef S0 +#undef S1 +#undef s0 +#undef s1 + +static void Sha256_WriteByteBlock(CSha256 *p) +{ + UInt32 data32[16]; + unsigned i; + for (i = 0; i < 16; i++) + data32[i] = + ((UInt32)(p->buffer[i * 4 ]) << 24) + + ((UInt32)(p->buffer[i * 4 + 1]) << 16) + + ((UInt32)(p->buffer[i * 4 + 2]) << 8) + + ((UInt32)(p->buffer[i * 4 + 3])); + Sha256_Transform(p->state, data32); +} + +void Sha256_Update(CSha256 *p, const Byte *data, size_t size) +{ + UInt32 curBufferPos = (UInt32)p->count & 0x3F; + while (size > 0) + { + p->buffer[curBufferPos++] = *data++; + p->count++; + size--; + if (curBufferPos == 64) + { + curBufferPos = 0; + Sha256_WriteByteBlock(p); + } + } +} + +void Sha256_Final(CSha256 *p, Byte *digest) +{ + UInt64 lenInBits = (p->count << 3); + UInt32 curBufferPos = (UInt32)p->count & 0x3F; + unsigned i; + p->buffer[curBufferPos++] = 0x80; + while (curBufferPos != (64 - 8)) + { + curBufferPos &= 0x3F; + if (curBufferPos == 0) + Sha256_WriteByteBlock(p); + p->buffer[curBufferPos++] = 0; + } + for (i = 0; i < 8; i++) + { + p->buffer[curBufferPos++] = (Byte)(lenInBits >> 56); + lenInBits <<= 8; + } + Sha256_WriteByteBlock(p); + + for (i = 0; i < 8; i++) + { + *digest++ = (Byte)(p->state[i] >> 24); + *digest++ = (Byte)(p->state[i] >> 16); + *digest++ = (Byte)(p->state[i] >> 8); + *digest++ = (Byte)(p->state[i]); + } + Sha256_Init(p); +} diff --git a/ext/VFS/ext/7z/src/Sha256.h b/ext/VFS/ext/7z/src/Sha256.h new file mode 100644 index 000000000..971c4f6e9 --- /dev/null +++ b/ext/VFS/ext/7z/src/Sha256.h @@ -0,0 +1,30 @@ +/* Sha256.h -- SHA-256 Hash +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __CRYPTO_SHA256_H +#define __CRYPTO_SHA256_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SHA256_DIGEST_SIZE 32 + +typedef struct +{ + UInt32 state[8]; + UInt64 count; + Byte buffer[64]; +} CSha256; + +void Sha256_Init(CSha256 *p); +void Sha256_Update(CSha256 *p, const Byte *data, size_t size); +void Sha256_Final(CSha256 *p, Byte *digest); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/Threads.c b/ext/VFS/ext/7z/src/Threads.c new file mode 100644 index 000000000..4be44fb0f --- /dev/null +++ b/ext/VFS/ext/7z/src/Threads.c @@ -0,0 +1,84 @@ +/* Threads.c -- multithreading library +2009-09-20 : Igor Pavlov : Public domain */ + +#ifndef _WIN32_WCE +#include +#endif + +#include "Threads.h" + +static WRes GetError() +{ + DWORD res = GetLastError(); + return (res) ? (WRes)(res) : 1; +} + +WRes HandleToWRes(HANDLE h) { return (h != 0) ? 0 : GetError(); } +WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); } + +WRes HandlePtr_Close(HANDLE *p) +{ + if (*p != NULL) + if (!CloseHandle(*p)) + return GetError(); + *p = NULL; + return 0; +} + +WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE); } + +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) +{ + unsigned threadId; /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ + *p = + #ifdef UNDER_CE + CreateThread(0, 0, func, param, 0, &threadId); + #else + (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId); + #endif + /* maybe we must use errno here, but probably GetLastError() is also OK. */ + return HandleToWRes(*p); +} + +WRes Event_Create(CEvent *p, BOOL manualReset, int signaled) +{ + *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL); + return HandleToWRes(*p); +} + +WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); } +WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); } + +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); } +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); } +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); } +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); } + + +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) +{ + *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL); + return HandleToWRes(*p); +} + +static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) + { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); } +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num) + { return Semaphore_Release(p, (LONG)num, NULL); } +WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); } + +WRes CriticalSection_Init(CCriticalSection *p) +{ + /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */ + #ifdef _MSC_VER + __try + #endif + { + InitializeCriticalSection(p); + /* InitializeCriticalSectionAndSpinCount(p, 0); */ + } + #ifdef _MSC_VER + __except (EXCEPTION_EXECUTE_HANDLER) { return 1; } + #endif + return 0; +} diff --git a/ext/VFS/ext/7z/src/Threads.h b/ext/VFS/ext/7z/src/Threads.h new file mode 100644 index 000000000..6a7afa829 --- /dev/null +++ b/ext/VFS/ext/7z/src/Threads.h @@ -0,0 +1,59 @@ +/* Threads.h -- multithreading library +2009-03-27 : Igor Pavlov : Public domain */ + +#ifndef __7Z_THREADS_H +#define __7Z_THREADS_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +WRes HandlePtr_Close(HANDLE *h); +WRes Handle_WaitObject(HANDLE h); + +typedef HANDLE CThread; +#define Thread_Construct(p) *(p) = NULL +#define Thread_WasCreated(p) (*(p) != NULL) +#define Thread_Close(p) HandlePtr_Close(p) +#define Thread_Wait(p) Handle_WaitObject(*(p)) +typedef unsigned THREAD_FUNC_RET_TYPE; +#define THREAD_FUNC_CALL_TYPE MY_STD_CALL +#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE +typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); + +typedef HANDLE CEvent; +typedef CEvent CAutoResetEvent; +typedef CEvent CManualResetEvent; +#define Event_Construct(p) *(p) = NULL +#define Event_IsCreated(p) (*(p) != NULL) +#define Event_Close(p) HandlePtr_Close(p) +#define Event_Wait(p) Handle_WaitObject(*(p)) +WRes Event_Set(CEvent *p); +WRes Event_Reset(CEvent *p); +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); + +typedef HANDLE CSemaphore; +#define Semaphore_Construct(p) (*p) = NULL +#define Semaphore_Close(p) HandlePtr_Close(p) +#define Semaphore_Wait(p) Handle_WaitObject(*(p)) +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); +WRes Semaphore_Release1(CSemaphore *p); + +typedef CRITICAL_SECTION CCriticalSection; +WRes CriticalSection_Init(CCriticalSection *p); +#define CriticalSection_Delete(p) DeleteCriticalSection(p) +#define CriticalSection_Enter(p) EnterCriticalSection(p) +#define CriticalSection_Leave(p) LeaveCriticalSection(p) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/Types.h b/ext/VFS/ext/7z/src/Types.h new file mode 100644 index 000000000..c60c1563b --- /dev/null +++ b/ext/VFS/ext/7z/src/Types.h @@ -0,0 +1,251 @@ +/* Types.h -- Basic types +2010-03-11 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#include + +#ifdef _WIN32 +#include +#endif + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +//#ifdef __cplusplus +#if defined(_WIN32) && defined(_MSC_VER) +# if !defined(SZIP_STATIC) +# if defined(SZIP_EXPORT) +# define SZIP_API __declspec(dllexport) +# else +# define SZIP_API __declspec(dllimport) +# endif +# else +# define SZIP_API +# endif +#else +# define SZIP_API +#endif + +EXTERN_C_BEGIN + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + +#ifdef _WIN32 +typedef DWORD WRes; +#else +typedef int WRes; +#endif + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int Bool; +#define True 1 +#define False 0 + + +#ifdef _WIN32 +#define MY_STD_CALL __stdcall +#else +#define MY_STD_CALL +#endif + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define MY_NO_INLINE __declspec(noinline) +#else +#define MY_NO_INLINE +#endif + +#define MY_CDECL __cdecl +#define MY_FAST_CALL __fastcall + +#else + +#define MY_CDECL +#define MY_FAST_CALL + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct +{ + Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ +} IByteIn; + +typedef struct +{ + void (*Write)(void *p, Byte b); +} IByteOut; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +} ISeqInStream; + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); + +typedef struct +{ + size_t (*Write)(void *p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +} ISeqOutStream; + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ISeekInStream; + +typedef struct +{ + SRes (*Look)(void *p, const void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(void *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(void *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ILookInStream; + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); + +#define LookToRead_BUF_SIZE (1 << 14) + +typedef struct +{ + ILookInStream s; + ISeekInStream *realStream; + size_t pos; + size_t size; + Byte buf[LookToRead_BUF_SIZE]; +} CLookToRead; + +SZIP_API void LookToRead_CreateVTable(CLookToRead *p, int lookahead); +SZIP_API void LookToRead_Init(CLookToRead *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + +typedef struct +{ + SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +} ICompressProgress; + +typedef struct +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ +} ISzAlloc; + +#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) +#define IAlloc_Free(p, a) (p)->Free((p), a) + +EXTERN_C_END + +#endif diff --git a/ext/VFS/ext/7z/src/Xz.c b/ext/VFS/ext/7z/src/Xz.c new file mode 100644 index 000000000..0bdf047c7 --- /dev/null +++ b/ext/VFS/ext/7z/src/Xz.c @@ -0,0 +1,88 @@ +/* Xz.c - Xz +2009-04-15 : Igor Pavlov : Public domain */ + +#include "7zCrc.h" +#include "CpuArch.h" +#include "Xz.h" +#include "XzCrc64.h" + +Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 }; +Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; + +unsigned Xz_WriteVarInt(Byte *buf, UInt64 v) +{ + unsigned i = 0; + do + { + buf[i++] = (Byte)((v & 0x7F) | 0x80); + v >>= 7; + } + while (v != 0); + buf[i - 1] &= 0x7F; + return i; +} + +void Xz_Construct(CXzStream *p) +{ + p->numBlocks = p->numBlocksAllocated = 0; + p->blocks = 0; + p->flags = 0; +} + +void Xz_Free(CXzStream *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->blocks); + p->numBlocks = p->numBlocksAllocated = 0; + p->blocks = 0; +} + +unsigned XzFlags_GetCheckSize(CXzStreamFlags f) +{ + int t = XzFlags_GetCheckType(f); + return (t == 0) ? 0 : (4 << ((t - 1) / 3)); +} + +void XzCheck_Init(CXzCheck *p, int mode) +{ + p->mode = mode; + switch (mode) + { + case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break; + case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break; + case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break; + } +} + +void XzCheck_Update(CXzCheck *p, const void *data, size_t size) +{ + switch (p->mode) + { + case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break; + case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break; + case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break; + } +} + +int XzCheck_Final(CXzCheck *p, Byte *digest) +{ + switch (p->mode) + { + case XZ_CHECK_CRC32: + SetUi32(digest, CRC_GET_DIGEST(p->crc)); + break; + case XZ_CHECK_CRC64: + { + int i; + UInt64 v = CRC64_GET_DIGEST(p->crc64); + for (i = 0; i < 8; i++, v >>= 8) + digest[i] = (Byte)(v & 0xFF); + break; + } + case XZ_CHECK_SHA256: + Sha256_Final(&p->sha, digest); + break; + default: + return 0; + } + return 1; +} diff --git a/ext/VFS/ext/7z/src/Xz.h b/ext/VFS/ext/7z/src/Xz.h new file mode 100644 index 000000000..65359712d --- /dev/null +++ b/ext/VFS/ext/7z/src/Xz.h @@ -0,0 +1,256 @@ +/* Xz.h - Xz interface +2009-04-15 : Igor Pavlov : Public domain */ + +#ifndef __XZ_H +#define __XZ_H + +#include "Sha256.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define XZ_ID_Subblock 1 +#define XZ_ID_Delta 3 +#define XZ_ID_X86 4 +#define XZ_ID_PPC 5 +#define XZ_ID_IA64 6 +#define XZ_ID_ARM 7 +#define XZ_ID_ARMT 8 +#define XZ_ID_SPARC 9 +#define XZ_ID_LZMA2 0x21 + +unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value); +unsigned Xz_WriteVarInt(Byte *buf, UInt64 v); + +/* ---------- xz block ---------- */ + +#define XZ_BLOCK_HEADER_SIZE_MAX 1024 + +#define XZ_NUM_FILTERS_MAX 4 +#define XZ_BF_NUM_FILTERS_MASK 3 +#define XZ_BF_PACK_SIZE (1 << 6) +#define XZ_BF_UNPACK_SIZE (1 << 7) + +#define XZ_FILTER_PROPS_SIZE_MAX 20 + +typedef struct +{ + UInt64 id; + UInt32 propsSize; + Byte props[XZ_FILTER_PROPS_SIZE_MAX]; +} CXzFilter; + +typedef struct +{ + UInt64 packSize; + UInt64 unpackSize; + Byte flags; + CXzFilter filters[XZ_NUM_FILTERS_MAX]; +} CXzBlock; + +#define XzBlock_GetNumFilters(p) (((p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1) +#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0) +#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0) + +SRes XzBlock_Parse(CXzBlock *p, const Byte *header); +SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes); + +/* ---------- xz stream ---------- */ + +#define XZ_SIG_SIZE 6 +#define XZ_FOOTER_SIG_SIZE 2 + +extern Byte XZ_SIG[XZ_SIG_SIZE]; +extern Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; + +#define XZ_STREAM_FLAGS_SIZE 2 +#define XZ_STREAM_CRC_SIZE 4 + +#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE) +#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4) + +#define XZ_CHECK_MASK 0xF +#define XZ_CHECK_NO 0 +#define XZ_CHECK_CRC32 1 +#define XZ_CHECK_CRC64 4 +#define XZ_CHECK_SHA256 10 + +typedef struct +{ + int mode; + UInt32 crc; + UInt64 crc64; + CSha256 sha; +} CXzCheck; + +void XzCheck_Init(CXzCheck *p, int mode); +void XzCheck_Update(CXzCheck *p, const void *data, size_t size); +int XzCheck_Final(CXzCheck *p, Byte *digest); + +typedef UInt16 CXzStreamFlags; + +#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK) +#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK) +#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32) +unsigned XzFlags_GetCheckSize(CXzStreamFlags f); + +SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf); +SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream); + +typedef struct +{ + UInt64 unpackSize; + UInt64 totalSize; +} CXzBlockSizes; + +typedef struct +{ + CXzStreamFlags flags; + size_t numBlocks; + size_t numBlocksAllocated; + CXzBlockSizes *blocks; + UInt64 startOffset; +} CXzStream; + +void Xz_Construct(CXzStream *p); +void Xz_Free(CXzStream *p, ISzAlloc *alloc); + +#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1) + +UInt64 Xz_GetUnpackSize(const CXzStream *p); +UInt64 Xz_GetPackSize(const CXzStream *p); + +typedef struct +{ + size_t num; + size_t numAllocated; + CXzStream *streams; +} CXzs; + +void Xzs_Construct(CXzs *p); +void Xzs_Free(CXzs *p, ISzAlloc *alloc); +SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc); + +UInt64 Xzs_GetNumBlocks(const CXzs *p); +UInt64 Xzs_GetUnpackSize(const CXzs *p); + +typedef enum +{ + CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ + CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + CODER_STATUS_NOT_FINISHED, /* stream was not finished */ + CODER_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ +} ECoderStatus; + +typedef enum +{ + CODER_FINISH_ANY, /* finish at any point */ + CODER_FINISH_END /* block must be finished at the end */ +} ECoderFinishMode; + +typedef struct _IStateCoder +{ + void *p; + void (*Free)(void *p, ISzAlloc *alloc); + SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAlloc *alloc); + void (*Init)(void *p); + SRes (*Code)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished); +} IStateCoder; + +#define MIXCODER_NUM_FILTERS_MAX 4 + +typedef struct +{ + ISzAlloc *alloc; + Byte *buf; + int numCoders; + int finished[MIXCODER_NUM_FILTERS_MAX - 1]; + size_t pos[MIXCODER_NUM_FILTERS_MAX - 1]; + size_t size[MIXCODER_NUM_FILTERS_MAX - 1]; + UInt64 ids[MIXCODER_NUM_FILTERS_MAX]; + IStateCoder coders[MIXCODER_NUM_FILTERS_MAX]; +} CMixCoder; + +void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc); +void MixCoder_Free(CMixCoder *p); +void MixCoder_Init(CMixCoder *p); +SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId); +SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcWasFinished, + ECoderFinishMode finishMode, ECoderStatus *status); + +typedef enum +{ + XZ_STATE_STREAM_HEADER, + XZ_STATE_STREAM_INDEX, + XZ_STATE_STREAM_INDEX_CRC, + XZ_STATE_STREAM_FOOTER, + XZ_STATE_STREAM_PADDING, + XZ_STATE_BLOCK_HEADER, + XZ_STATE_BLOCK, + XZ_STATE_BLOCK_FOOTER +} EXzState; + +typedef struct +{ + EXzState state; + UInt32 pos; + unsigned alignPos; + unsigned indexPreSize; + + CXzStreamFlags streamFlags; + + UInt32 blockHeaderSize; + UInt64 packSize; + UInt64 unpackSize; + + UInt64 numBlocks; + UInt64 indexSize; + UInt64 indexPos; + UInt64 padSize; + + UInt64 numStreams; + + UInt32 crc; + CMixCoder decoder; + CXzBlock block; + CXzCheck check; + CSha256 sha; + Byte shaDigest[SHA256_DIGEST_SIZE]; + Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; +} CXzUnpacker; + +SRes XzUnpacker_Create(CXzUnpacker *p, ISzAlloc *alloc); +void XzUnpacker_Free(CXzUnpacker *p); + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - use smallest number of input bytes + LZMA_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + + +SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, /* int srcWasFinished, */ int finishMode, + ECoderStatus *status); + +Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/XzCrc64.c b/ext/VFS/ext/7z/src/XzCrc64.c new file mode 100644 index 000000000..b99495d40 --- /dev/null +++ b/ext/VFS/ext/7z/src/XzCrc64.c @@ -0,0 +1,33 @@ +/* XzCrc64.c -- CRC64 calculation +2009-04-15 : Igor Pavlov : Public domain */ + +#include "XzCrc64.h" + +#define kCrc64Poly 0xC96C5795D7870F42 +UInt64 g_Crc64Table[256]; + +void MY_FAST_CALL Crc64GenerateTable(void) +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt64 r = i; + int j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ ((UInt64)kCrc64Poly & ~((r & 1) - 1)); + g_Crc64Table[i] = r; + } +} + +UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 ; size--, p++) + v = CRC64_UPDATE_BYTE(v, *p); + return v; +} + +UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size) +{ + return CRC64_GET_DIGEST(Crc64Update(CRC64_INIT_VAL, data, size)); +} diff --git a/ext/VFS/ext/7z/src/XzCrc64.h b/ext/VFS/ext/7z/src/XzCrc64.h new file mode 100644 index 000000000..3cd1526a4 --- /dev/null +++ b/ext/VFS/ext/7z/src/XzCrc64.h @@ -0,0 +1,30 @@ +/* XzCrc64.c -- CRC64 calculation +2009-04-15 : Igor Pavlov : Public domain */ + +#ifndef __XZ_CRC64_H +#define __XZ_CRC64_H + +#include + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern UInt64 g_Crc64Table[]; + +void MY_FAST_CALL Crc64GenerateTable(void); + +#define CRC64_INIT_VAL 0xFFFFFFFFFFFFFFFF +#define CRC64_GET_DIGEST(crc) ((crc) ^ 0xFFFFFFFFFFFFFFFF) +#define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size); +UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/XzDec.c b/ext/VFS/ext/7z/src/XzDec.c new file mode 100644 index 000000000..14a459e11 --- /dev/null +++ b/ext/VFS/ext/7z/src/XzDec.c @@ -0,0 +1,873 @@ +/* XzDec.c -- Xz Decode +2009-06-08 : Igor Pavlov : Public domain */ + +/* #define XZ_DUMP */ + +#ifdef XZ_DUMP +#include +#endif + +#include +#include + +#include "7zCrc.h" +#include "Alloc.h" +#include "Bra.h" +#include "CpuArch.h" +#include "Delta.h" +#include "Lzma2Dec.h" + +#ifdef USE_SUBBLOCK +#include "SbDec.h" +#endif + +#include "Xz.h" + +#define XZ_CHECK_SIZE_MAX 64 + +#define CODER_BUF_SIZE (1 << 17) + +unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value) +{ + int i, limit; + *value = 0; + limit = (maxSize > 9) ? 9 : (int)maxSize; + + for (i = 0; i < limit;) + { + Byte b = p[i]; + *value |= (UInt64)(b & 0x7F) << (7 * i++); + if ((b & 0x80) == 0) + return (b == 0 && i != 1) ? 0 : i; + } + return 0; +} + +/* ---------- BraState ---------- */ + +#define BRA_BUF_SIZE (1 << 14) + +typedef struct +{ + size_t bufPos; + size_t bufConv; + size_t bufTotal; + + UInt32 methodId; + int encodeMode; + UInt32 delta; + UInt32 ip; + UInt32 x86State; + Byte deltaState[DELTA_STATE_SIZE]; + + Byte buf[BRA_BUF_SIZE]; +} CBraState; + +void BraState_Free(void *pp, ISzAlloc *alloc) +{ + alloc->Free(alloc, pp); +} + +SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) +{ + CBraState *p = ((CBraState *)pp); + alloc = alloc; + p->encodeMode = 0; + p->ip = 0; + if (p->methodId == XZ_ID_Delta) + { + if (propSize != 1) + return SZ_ERROR_UNSUPPORTED; + p->delta = (unsigned)props[0] + 1; + } + else + { + if (propSize == 4) + { + UInt32 v = GetUi32(props); + switch(p->methodId) + { + case XZ_ID_PPC: + case XZ_ID_ARM: + case XZ_ID_SPARC: + if ((v & 3) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + case XZ_ID_ARMT: + if ((v & 1) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + case XZ_ID_IA64: + if ((v & 0xF) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + } + p->ip = v; + } + else if (propSize != 0) + return SZ_ERROR_UNSUPPORTED; + } + return SZ_OK; +} + +void BraState_Init(void *pp) +{ + CBraState *p = ((CBraState *)pp); + p->bufPos = p->bufConv = p->bufTotal = 0; + x86_Convert_Init(p->x86State); + if (p->methodId == XZ_ID_Delta) + Delta_Init(p->deltaState); +} + +#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: p->bufConv = isa ## _Convert(p->buf, p->bufTotal, p->ip, p->encodeMode); break; + +static SRes BraState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished) +{ + CBraState *p = ((CBraState *)pp); + SizeT destLenOrig = *destLen; + SizeT srcLenOrig = *srcLen; + *destLen = 0; + *srcLen = 0; + finishMode = finishMode; + *wasFinished = 0; + while (destLenOrig > 0) + { + if (p->bufPos != p->bufConv) + { + size_t curSize = p->bufConv - p->bufPos; + if (curSize > destLenOrig) + curSize = destLenOrig; + memcpy(dest, p->buf + p->bufPos, curSize); + p->bufPos += curSize; + *destLen += curSize; + dest += curSize; + destLenOrig -= curSize; + continue; + } + p->bufTotal -= p->bufPos; + memmove(p->buf, p->buf + p->bufPos, p->bufTotal); + p->bufPos = 0; + p->bufConv = 0; + { + size_t curSize = BRA_BUF_SIZE - p->bufTotal; + if (curSize > srcLenOrig) + curSize = srcLenOrig; + memcpy(p->buf + p->bufTotal, src, curSize); + *srcLen += curSize; + src += curSize; + srcLenOrig -= curSize; + p->bufTotal += curSize; + } + if (p->bufTotal == 0) + break; + switch(p->methodId) + { + case XZ_ID_Delta: + if (p->encodeMode) + Delta_Encode(p->deltaState, p->delta, p->buf, p->bufTotal); + else + Delta_Decode(p->deltaState, p->delta, p->buf, p->bufTotal); + p->bufConv = p->bufTotal; + break; + case XZ_ID_X86: + p->bufConv = x86_Convert(p->buf, p->bufTotal, p->ip, &p->x86State, p->encodeMode); + break; + CASE_BRA_CONV(PPC) + CASE_BRA_CONV(IA64) + CASE_BRA_CONV(ARM) + CASE_BRA_CONV(ARMT) + CASE_BRA_CONV(SPARC) + default: + return SZ_ERROR_UNSUPPORTED; + } + p->ip += (UInt32)p->bufConv; + + if (p->bufConv == 0) + { + if (!srcWasFinished) + break; + p->bufConv = p->bufTotal; + } + } + if (p->bufTotal == p->bufPos && srcLenOrig == 0 && srcWasFinished) + *wasFinished = 1; + return SZ_OK; +} + +SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, ISzAlloc *alloc) +{ + CBraState *decoder; + if (id != XZ_ID_Delta && + id != XZ_ID_X86 && + id != XZ_ID_PPC && + id != XZ_ID_IA64 && + id != XZ_ID_ARM && + id != XZ_ID_ARMT && + id != XZ_ID_SPARC) + return SZ_ERROR_UNSUPPORTED; + p->p = 0; + decoder = alloc->Alloc(alloc, sizeof(CBraState)); + if (decoder == 0) + return SZ_ERROR_MEM; + decoder->methodId = (UInt32)id; + p->p = decoder; + p->Free = BraState_Free; + p->SetProps = BraState_SetProps; + p->Init = BraState_Init; + p->Code = BraState_Code; + return SZ_OK; +} + +/* ---------- SbState ---------- */ + +#ifdef USE_SUBBLOCK + +static void SbState_Free(void *pp, ISzAlloc *alloc) +{ + CSubblockDec *p = (CSubblockDec *)pp; + SubblockDec_Free(p, alloc); + alloc->Free(alloc, pp); +} + +static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) +{ + pp = pp; + props = props; + alloc = alloc; + return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED; +} + +static void SbState_Init(void *pp) +{ + SubblockDec_Init((CSubblockDec *)pp); +} + +static SRes SbState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished) +{ + ECoderStatus status; + SRes res = SubblockDec_Decode((CSubblockDec *)pp, dest, destLen, src, srcLen, finishMode, &status); + srcWasFinished = srcWasFinished; + *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK); + return res; +} + +SRes SbState_SetFromMethod(IStateCoder *p, ISzAlloc *alloc) +{ + CSubblockDec *decoder; + p->p = 0; + decoder = alloc->Alloc(alloc, sizeof(CSubblockDec)); + if (decoder == 0) + return SZ_ERROR_MEM; + p->p = decoder; + p->Free = SbState_Free; + p->SetProps = SbState_SetProps; + p->Init = SbState_Init; + p->Code = SbState_Code; + SubblockDec_Construct(decoder); + return SZ_OK; +} +#endif + +/* ---------- Lzma2State ---------- */ + +static void Lzma2State_Free(void *pp, ISzAlloc *alloc) +{ + Lzma2Dec_Free((CLzma2Dec *)pp, alloc); + alloc->Free(alloc, pp); +} + +static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) +{ + if (propSize != 1) + return SZ_ERROR_UNSUPPORTED; + return Lzma2Dec_Allocate((CLzma2Dec *)pp, props[0], alloc); +} + +static void Lzma2State_Init(void *pp) +{ + Lzma2Dec_Init((CLzma2Dec *)pp); +} + +static SRes Lzma2State_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished) +{ + ELzmaStatus status; + /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */ + SRes res = Lzma2Dec_DecodeToBuf((CLzma2Dec *)pp, dest, destLen, src, srcLen, finishMode, &status); + srcWasFinished = srcWasFinished; + *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK); + return res; +} + +static SRes Lzma2State_SetFromMethod(IStateCoder *p, ISzAlloc *alloc) +{ + CLzma2Dec *decoder = alloc->Alloc(alloc, sizeof(CLzma2Dec)); + p->p = decoder; + if (decoder == 0) + return SZ_ERROR_MEM; + p->Free = Lzma2State_Free; + p->SetProps = Lzma2State_SetProps; + p->Init = Lzma2State_Init; + p->Code = Lzma2State_Code; + Lzma2Dec_Construct(decoder); + return SZ_OK; +} + + +void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc) +{ + int i; + p->alloc = alloc; + p->buf = 0; + p->numCoders = 0; + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) + p->coders[i].p = NULL; +} + +void MixCoder_Free(CMixCoder *p) +{ + int i; + for (i = 0; i < p->numCoders; i++) + { + IStateCoder *sc = &p->coders[i]; + if (p->alloc && sc->p) + sc->Free(sc->p, p->alloc); + } + p->numCoders = 0; + if (p->buf) + p->alloc->Free(p->alloc, p->buf); +} + +void MixCoder_Init(CMixCoder *p) +{ + int i; + for (i = 0; i < p->numCoders - 1; i++) + { + p->size[i] = 0; + p->pos[i] = 0; + p->finished[i] = 0; + } + for (i = 0; i < p->numCoders; i++) + { + IStateCoder *coder = &p->coders[i]; + coder->Init(coder->p); + } +} + +SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId) +{ + IStateCoder *sc = &p->coders[coderIndex]; + p->ids[coderIndex] = methodId; + switch(methodId) + { + case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, p->alloc); + #ifdef USE_SUBBLOCK + case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc); + #endif + } + if (coderIndex == 0) + return SZ_ERROR_UNSUPPORTED; + return BraState_SetFromMethod(sc, methodId, p->alloc); +} + +SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcWasFinished, + ECoderFinishMode finishMode, ECoderStatus *status) +{ + SizeT destLenOrig = *destLen; + SizeT srcLenOrig = *srcLen; + Bool allFinished = True; + *destLen = 0; + *srcLen = 0; + *status = CODER_STATUS_NOT_FINISHED; + + if (p->buf == 0) + { + p->buf = p->alloc->Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1)); + if (p->buf == 0) + return SZ_ERROR_MEM; + } + + if (p->numCoders != 1) + finishMode = CODER_FINISH_ANY; + + for (;;) + { + Bool processed = False; + int i; + /* + if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY) + break; + */ + + for (i = 0; i < p->numCoders; i++) + { + SRes res; + IStateCoder *coder = &p->coders[i]; + Byte *destCur; + SizeT destLenCur, srcLenCur; + const Byte *srcCur; + int srcFinishedCur; + int encodingWasFinished; + + if (i == 0) + { + srcCur = src; + srcLenCur = srcLenOrig - *srcLen; + srcFinishedCur = srcWasFinished; + } + else + { + srcCur = p->buf + (CODER_BUF_SIZE * (i - 1)) + p->pos[i - 1]; + srcLenCur = p->size[i - 1] - p->pos[i - 1]; + srcFinishedCur = p->finished[i - 1]; + } + + if (i == p->numCoders - 1) + { + destCur = dest; + destLenCur = destLenOrig - *destLen; + } + else + { + if (p->pos[i] != p->size[i]) + continue; + destCur = p->buf + (CODER_BUF_SIZE * i); + destLenCur = CODER_BUF_SIZE; + } + + res = coder->Code(coder->p, destCur, &destLenCur, srcCur, &srcLenCur, srcFinishedCur, finishMode, &encodingWasFinished); + + if (!encodingWasFinished) + allFinished = False; + + if (i == 0) + { + *srcLen += srcLenCur; + src += srcLenCur; + } + else + { + p->pos[i - 1] += srcLenCur; + } + + if (i == p->numCoders - 1) + { + *destLen += destLenCur; + dest += destLenCur; + } + else + { + p->size[i] = destLenCur; + p->pos[i] = 0; + p->finished[i] = encodingWasFinished; + } + + if (res != SZ_OK) + return res; + + if (destLenCur != 0 || srcLenCur != 0) + processed = True; + } + if (!processed) + break; + } + if (allFinished) + *status = CODER_STATUS_FINISHED_WITH_MARK; + return SZ_OK; +} + +SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf) +{ + *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE); + if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) != + GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE)) + return SZ_ERROR_NO_ARCHIVE; + return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED; +} + +static Bool Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf) +{ + return + indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) && + (GetUi32(buf) == CrcCalc(buf + 4, 6) && + flags == GetBe16(buf + 8) && + memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0); +} + +#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ + { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ + if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; } + + +SRes XzBlock_Parse(CXzBlock *p, const Byte *header) +{ + unsigned pos; + int numFilters, i; + UInt32 headerSize = (UInt32)header[0] << 2; + + if (CrcCalc(header, headerSize) != GetUi32(header + headerSize)) + return SZ_ERROR_ARCHIVE; + + pos = 1; + if (pos == headerSize) + return SZ_ERROR_ARCHIVE; + p->flags = header[pos++]; + + if (XzBlock_HasPackSize(p)) + { + READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize); + if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63) + return SZ_ERROR_ARCHIVE; + } + + if (XzBlock_HasUnpackSize(p)) + READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize); + + numFilters = XzBlock_GetNumFilters(p); + for (i = 0; i < numFilters; i++) + { + CXzFilter *filter = p->filters + i; + UInt64 size; + READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id); + READ_VARINT_AND_CHECK(header, pos, headerSize, &size); + if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX) + return SZ_ERROR_ARCHIVE; + filter->propsSize = (UInt32)size; + memcpy(filter->props, header + pos, (size_t)size); + pos += (unsigned)size; + + #ifdef XZ_DUMP + printf("\nf[%d] = %2X: ", i, filter->id); + { + int i; + for (i = 0; i < size; i++) + printf(" %2X", filter->props[i]); + } + #endif + } + + while (pos < headerSize) + if (header[pos++] != 0) + return SZ_ERROR_ARCHIVE; + return SZ_OK; +} + +SRes XzDec_Init(CMixCoder *p, const CXzBlock *block) +{ + int i; + Bool needReInit = True; + int numFilters = XzBlock_GetNumFilters(block); + if (numFilters == p->numCoders) + { + for (i = 0; i < numFilters; i++) + if (p->ids[i] != block->filters[numFilters - 1 - i].id) + break; + needReInit = (i != numFilters); + } + if (needReInit) + { + MixCoder_Free(p); + p->numCoders = numFilters; + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &block->filters[numFilters - 1 - i]; + RINOK(MixCoder_SetFromMethod(p, i, f->id)); + } + } + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &block->filters[numFilters - 1 - i]; + IStateCoder *sc = &p->coders[i]; + RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc)); + } + MixCoder_Init(p); + return SZ_OK; +} + +SRes XzUnpacker_Create(CXzUnpacker *p, ISzAlloc *alloc) +{ + MixCoder_Construct(&p->decoder, alloc); + p->state = XZ_STATE_STREAM_HEADER; + p->pos = 0; + p->numStreams = 0; + return SZ_OK; +} + +void XzUnpacker_Free(CXzUnpacker *p) +{ + MixCoder_Free(&p->decoder); +} + +SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int finishMode, ECoderStatus *status) +{ + SizeT destLenOrig = *destLen; + SizeT srcLenOrig = *srcLen; + *destLen = 0; + *srcLen = 0; + *status = CODER_STATUS_NOT_SPECIFIED; + for (;;) + { + SizeT srcRem = srcLenOrig - *srcLen; + + if (p->state == XZ_STATE_BLOCK) + { + SizeT destLen2 = destLenOrig - *destLen; + SizeT srcLen2 = srcLenOrig - *srcLen; + SRes res; + if (srcLen2 == 0 && destLen2 == 0) + { + *status = CODER_STATUS_NOT_FINISHED; + return SZ_OK; + } + + res = MixCoder_Code(&p->decoder, dest, &destLen2, src, &srcLen2, False, finishMode, status); + XzCheck_Update(&p->check, dest, destLen2); + + (*srcLen) += srcLen2; + src += srcLen2; + p->packSize += srcLen2; + + (*destLen) += destLen2; + dest += destLen2; + p->unpackSize += destLen2; + + RINOK(res); + + if (*status == CODER_STATUS_FINISHED_WITH_MARK) + { + Byte temp[32]; + unsigned num = Xz_WriteVarInt(temp, p->packSize + p->blockHeaderSize + XzFlags_GetCheckSize(p->streamFlags)); + num += Xz_WriteVarInt(temp + num, p->unpackSize); + Sha256_Update(&p->sha, temp, num); + p->indexSize += num; + p->numBlocks++; + + p->state = XZ_STATE_BLOCK_FOOTER; + p->pos = 0; + p->alignPos = 0; + } + else if (srcLen2 == 0 && destLen2 == 0) + return SZ_OK; + + continue; + } + + if (srcRem == 0) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + switch(p->state) + { + case XZ_STATE_STREAM_HEADER: + { + if (p->pos < XZ_STREAM_HEADER_SIZE) + { + if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos]) + return SZ_ERROR_NO_ARCHIVE; + p->buf[p->pos++] = *src++; + (*srcLen)++; + } + else + { + RINOK(Xz_ParseHeader(&p->streamFlags, p->buf)); + p->state = XZ_STATE_BLOCK_HEADER; + Sha256_Init(&p->sha); + p->indexSize = 0; + p->numBlocks = 0; + p->pos = 0; + } + break; + } + + case XZ_STATE_BLOCK_HEADER: + { + if (p->pos == 0) + { + p->buf[p->pos++] = *src++; + (*srcLen)++; + if (p->buf[0] == 0) + { + p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks); + p->indexPos = p->indexPreSize; + p->indexSize += p->indexPreSize; + Sha256_Final(&p->sha, p->shaDigest); + Sha256_Init(&p->sha); + p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize); + p->state = XZ_STATE_STREAM_INDEX; + } + p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4; + } + else if (p->pos != p->blockHeaderSize) + { + UInt32 cur = p->blockHeaderSize - p->pos; + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + } + else + { + RINOK(XzBlock_Parse(&p->block, p->buf)); + p->state = XZ_STATE_BLOCK; + p->packSize = 0; + p->unpackSize = 0; + XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags)); + RINOK(XzDec_Init(&p->decoder, &p->block)); + } + break; + } + + case XZ_STATE_BLOCK_FOOTER: + { + if (((p->packSize + p->alignPos) & 3) != 0) + { + (*srcLen)++; + p->alignPos++; + if (*src++ != 0) + return SZ_ERROR_CRC; + } + else + { + UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags); + UInt32 cur = checkSize - p->pos; + if (cur != 0) + { + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + } + else + { + Byte digest[XZ_CHECK_SIZE_MAX]; + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0) + return SZ_ERROR_CRC; + } + } + break; + } + + case XZ_STATE_STREAM_INDEX: + { + if (p->pos < p->indexPreSize) + { + (*srcLen)++; + if (*src++ != p->buf[p->pos++]) + return SZ_ERROR_CRC; + } + else + { + if (p->indexPos < p->indexSize) + { + UInt64 cur = p->indexSize - p->indexPos; + if (srcRem > cur) + srcRem = (SizeT)cur; + p->crc = CrcUpdate(p->crc, src, srcRem); + Sha256_Update(&p->sha, src, srcRem); + (*srcLen) += srcRem; + src += srcRem; + p->indexPos += srcRem; + } + else if ((p->indexPos & 3) != 0) + { + Byte b = *src++; + p->crc = CRC_UPDATE_BYTE(p->crc, b); + (*srcLen)++; + p->indexPos++; + p->indexSize++; + if (b != 0) + return SZ_ERROR_CRC; + } + else + { + Byte digest[SHA256_DIGEST_SIZE]; + p->state = XZ_STATE_STREAM_INDEX_CRC; + p->indexSize += 4; + p->pos = 0; + Sha256_Final(&p->sha, digest); + if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0) + return SZ_ERROR_CRC; + } + } + break; + } + + case XZ_STATE_STREAM_INDEX_CRC: + { + if (p->pos < 4) + { + (*srcLen)++; + p->buf[p->pos++] = *src++; + } + else + { + p->state = XZ_STATE_STREAM_FOOTER; + p->pos = 0; + if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf)) + return SZ_ERROR_CRC; + } + break; + } + + case XZ_STATE_STREAM_FOOTER: + { + UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos; + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + if (p->pos == XZ_STREAM_FOOTER_SIZE) + { + p->state = XZ_STATE_STREAM_PADDING; + p->numStreams++; + p->padSize = 0; + if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf)) + return SZ_ERROR_CRC; + } + break; + } + + case XZ_STATE_STREAM_PADDING: + { + if (*src != 0) + { + if (((UInt32)p->padSize & 3) != 0) + return SZ_ERROR_NO_ARCHIVE; + p->pos = 0; + p->state = XZ_STATE_STREAM_HEADER; + } + else + { + (*srcLen)++; + src++; + p->padSize++; + } + break; + } + } + } + /* + if (p->state == XZ_STATE_FINISHED) + *status = CODER_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + */ +} + +Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p) +{ + return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0); +} diff --git a/ext/VFS/ext/7z/src/XzEnc.c b/ext/VFS/ext/7z/src/XzEnc.c new file mode 100644 index 000000000..e6101406c --- /dev/null +++ b/ext/VFS/ext/7z/src/XzEnc.c @@ -0,0 +1,497 @@ +/* XzEnc.c -- Xz Encode +2009-06-04 : Igor Pavlov : Public domain */ + +#include +#include + +#include "7zCrc.h" +#include "Alloc.h" +#include "Bra.h" +#include "CpuArch.h" +#ifdef USE_SUBBLOCK +#include "SbEnc.h" +#endif + +#include "XzEnc.h" + +static void *SzBigAlloc(void *p, size_t size) { p = p; return BigAlloc(size); } +static void SzBigFree(void *p, void *address) { p = p; BigFree(address); } +static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; + +static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } +static void SzFree(void *p, void *address) { p = p; MyFree(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +#define XzBlock_ClearFlags(p) (p)->flags = 0; +#define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1); +#define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE; +#define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE; + +static SRes WriteBytes(ISeqOutStream *s, const void *buf, UInt32 size) +{ + return (s->Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE; +} + +static SRes WriteBytesAndCrc(ISeqOutStream *s, const void *buf, UInt32 size, UInt32 *crc) +{ + *crc = CrcUpdate(*crc, buf, size); + return WriteBytes(s, buf, size); +} + +SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s) +{ + UInt32 crc; + Byte header[XZ_STREAM_HEADER_SIZE]; + memcpy(header, XZ_SIG, XZ_SIG_SIZE); + header[XZ_SIG_SIZE] = (Byte)(f >> 8); + header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF); + crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE); + SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc); + return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); +} + +SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s) +{ + Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; + + unsigned pos = 1; + int numFilters, i; + header[pos++] = p->flags; + + if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); + if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); + numFilters = XzBlock_GetNumFilters(p); + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &p->filters[i]; + pos += Xz_WriteVarInt(header + pos, f->id); + pos += Xz_WriteVarInt(header + pos, f->propsSize); + memcpy(header + pos, f->props, f->propsSize); + pos += f->propsSize; + } + while((pos & 3) != 0) + header[pos++] = 0; + header[0] = (Byte)(pos >> 2); + SetUi32(header + pos, CrcCalc(header, pos)); + return WriteBytes(s, header, pos + 4); +} + +SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s) +{ + Byte buf[32]; + UInt64 globalPos; + { + UInt32 crc = CRC_INIT_VAL; + unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks); + size_t i; + + globalPos = pos; + buf[0] = 0; + RINOK(WriteBytesAndCrc(s, buf, pos, &crc)); + for (i = 0; i < p->numBlocks; i++) + { + const CXzBlockSizes *block = &p->blocks[i]; + pos = Xz_WriteVarInt(buf, block->totalSize); + pos += Xz_WriteVarInt(buf + pos, block->unpackSize); + globalPos += pos; + RINOK(WriteBytesAndCrc(s, buf, pos, &crc)); + } + pos = ((unsigned)globalPos & 3); + if (pos != 0) + { + buf[0] = buf[1] = buf[2] = 0; + RINOK(WriteBytesAndCrc(s, buf, 4 - pos, &crc)); + globalPos += 4 - pos; + } + { + SetUi32(buf, CRC_GET_DIGEST(crc)); + RINOK(WriteBytes(s, buf, 4)); + globalPos += 4; + } + } + + { + UInt32 indexSize = (UInt32)((globalPos >> 2) - 1); + SetUi32(buf + 4, indexSize); + buf[8] = (Byte)(p->flags >> 8); + buf[9] = (Byte)(p->flags & 0xFF); + SetUi32(buf, CrcCalc(buf + 4, 6)); + memcpy(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE); + return WriteBytes(s, buf, 12); + } +} + +SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc) +{ + if (p->blocks == 0 || p->numBlocksAllocated == p->numBlocks) + { + size_t num = (p->numBlocks + 1) * 2; + size_t newSize = sizeof(CXzBlockSizes) * num; + CXzBlockSizes *blocks; + if (newSize / sizeof(CXzBlockSizes) != num) + return SZ_ERROR_MEM; + blocks = alloc->Alloc(alloc, newSize); + if (blocks == 0) + return SZ_ERROR_MEM; + if (p->numBlocks != 0) + { + memcpy(blocks, p->blocks, p->numBlocks * sizeof(CXzBlockSizes)); + Xz_Free(p, alloc); + } + p->blocks = blocks; + p->numBlocksAllocated = num; + } + { + CXzBlockSizes *block = &p->blocks[p->numBlocks++]; + block->totalSize = totalSize; + block->unpackSize = unpackSize; + } + return SZ_OK; +} + +/* ---------- CSeqCheckInStream ---------- */ + +typedef struct +{ + ISeqInStream p; + ISeqInStream *realStream; + UInt64 processed; + CXzCheck check; +} CSeqCheckInStream; + +void SeqCheckInStream_Init(CSeqCheckInStream *p, int mode) +{ + p->processed = 0; + XzCheck_Init(&p->check, mode); +} + +void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) +{ + XzCheck_Final(&p->check, digest); +} + +static SRes SeqCheckInStream_Read(void *pp, void *data, size_t *size) +{ + CSeqCheckInStream *p = (CSeqCheckInStream *)pp; + SRes res = p->realStream->Read(p->realStream, data, size); + XzCheck_Update(&p->check, data, *size); + p->processed += *size; + return res; +} + +/* ---------- CSeqSizeOutStream ---------- */ + +typedef struct +{ + ISeqOutStream p; + ISeqOutStream *realStream; + UInt64 processed; +} CSeqSizeOutStream; + +static size_t MyWrite(void *pp, const void *data, size_t size) +{ + CSeqSizeOutStream *p = (CSeqSizeOutStream *)pp; + size = p->realStream->Write(p->realStream, data, size); + p->processed += size; + return size; +} + +/* ---------- CSeqInFilter ---------- */ + +/* +typedef struct _IFilter +{ + void *p; + void (*Free)(void *p, ISzAlloc *alloc); + SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAlloc *alloc); + void (*Init)(void *p); + size_t (*Filter)(void *p, Byte *data, SizeT destLen); +} IFilter; + +#define FILT_BUF_SIZE (1 << 19) + +typedef struct +{ + ISeqInStream p; + ISeqInStream *realStream; + UInt32 x86State; + UInt32 ip; + UInt64 processed; + CXzCheck check; + Byte buf[FILT_BUF_SIZE]; + UInt32 bufferPos; + UInt32 convertedPosBegin; + UInt32 convertedPosEnd; + IFilter *filter; +} CSeqInFilter; + +static SRes SeqInFilter_Read(void *pp, void *data, size_t *size) +{ + CSeqInFilter *p = (CSeqInFilter *)pp; + size_t remSize = *size; + *size = 0; + + while (remSize > 0) + { + int i; + if (p->convertedPosBegin != p->convertedPosEnd) + { + UInt32 sizeTemp = p->convertedPosEnd - p->convertedPosBegin; + if (remSize < sizeTemp) + sizeTemp = (UInt32)remSize; + memmove(data, p->buf + p->convertedPosBegin, sizeTemp); + p->convertedPosBegin += sizeTemp; + data = (void *)((Byte *)data + sizeTemp); + remSize -= sizeTemp; + *size += sizeTemp; + break; + } + for (i = 0; p->convertedPosEnd + i < p->bufferPos; i++) + p->buf[i] = p->buf[i + p->convertedPosEnd]; + p->bufferPos = i; + p->convertedPosBegin = p->convertedPosEnd = 0; + { + size_t processedSizeTemp = FILT_BUF_SIZE - p->bufferPos; + RINOK(p->realStream->Read(p->realStream, p->buf + p->bufferPos, &processedSizeTemp)); + p->bufferPos = p->bufferPos + (UInt32)processedSizeTemp; + } + p->convertedPosEnd = (UInt32)p->filter->Filter(p->filter->p, p->buf, p->bufferPos); + if (p->convertedPosEnd == 0) + { + if (p->bufferPos == 0) + break; + else + { + p->convertedPosEnd = p->bufferPos; + continue; + } + } + if (p->convertedPosEnd > p->bufferPos) + { + for (; p->bufferPos < p->convertedPosEnd; p->bufferPos++) + p->buf[p->bufferPos] = 0; + p->convertedPosEnd = (UInt32)p->filter->Filter(p->filter->p, p->buf, p->bufferPos); + } + } + return SZ_OK; +} +*/ + +/* +typedef struct +{ + ISeqInStream p; + ISeqInStream *realStream; + CMixCoder mixCoder; + Byte buf[FILT_BUF_SIZE]; + UInt32 bufPos; + UInt32 bufSize; +} CMixCoderSeqInStream; + +static SRes CMixCoderSeqInStream_Read(void *pp, void *data, size_t *size) +{ + CMixCoderSeqInStream *p = (CMixCoderSeqInStream *)pp; + SRes res = SZ_OK; + size_t remSize = *size; + *size = 0; + while (remSize > 0) + { + if (p->bufPos == p->bufSize) + { + size_t curSize; + p->bufPos = p->bufSize = 0; + if (*size != 0) + break; + curSize = FILT_BUF_SIZE; + RINOK(p->realStream->Read(p->realStream, p->buf, &curSize)); + p->bufSize = (UInt32)curSize; + } + { + SizeT destLen = remSize; + SizeT srcLen = p->bufSize - p->bufPos; + res = MixCoder_Code(&p->mixCoder, data, &destLen, p->buf + p->bufPos, &srcLen, 0); + data = (void *)((Byte *)data + destLen); + remSize -= destLen; + *size += destLen; + p->bufPos += srcLen; + } + } + return res; +} +*/ + +#ifdef USE_SUBBLOCK +typedef struct +{ + ISeqInStream p; + CSubblockEnc sb; + UInt64 processed; +} CSbEncInStream; + +void SbEncInStream_Init(CSbEncInStream *p) +{ + p->processed = 0; + SubblockEnc_Init(&p->sb); +} + +static SRes SbEncInStream_Read(void *pp, void *data, size_t *size) +{ + CSbEncInStream *p = (CSbEncInStream *)pp; + SRes res = SubblockEnc_Read(&p->sb, data, size); + p->processed += *size; + return res; +} +#endif + +typedef struct +{ + /* CMixCoderSeqInStream inStream; */ + CLzma2EncHandle lzma2; + #ifdef USE_SUBBLOCK + CSbEncInStream sb; + #endif + ISzAlloc *alloc; + ISzAlloc *bigAlloc; +} CLzma2WithFilters; + + +static void Lzma2WithFilters_Construct(CLzma2WithFilters *p, ISzAlloc *alloc, ISzAlloc *bigAlloc) +{ + p->alloc = alloc; + p->bigAlloc = bigAlloc; + p->lzma2 = NULL; + #ifdef USE_SUBBLOCK + p->sb.p.Read = SbEncInStream_Read; + SubblockEnc_Construct(&p->sb.sb, p->alloc); + #endif +} + +static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p) +{ + p->lzma2 = Lzma2Enc_Create(p->alloc, p->bigAlloc); + if (p->lzma2 == 0) + return SZ_ERROR_MEM; + return SZ_OK; +} + +static void Lzma2WithFilters_Free(CLzma2WithFilters *p) +{ + #ifdef USE_SUBBLOCK + SubblockEnc_Free(&p->sb.sb); + #endif + if (p->lzma2) + { + Lzma2Enc_Destroy(p->lzma2); + p->lzma2 = NULL; + } +} + +static SRes Xz_Compress(CXzStream *xz, + CLzma2WithFilters *lzmaf, + ISeqOutStream *outStream, + ISeqInStream *inStream, + const CLzma2EncProps *lzma2Props, + Bool useSubblock, + ICompressProgress *progress) +{ + xz->flags = XZ_CHECK_CRC32; + + RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, lzma2Props)); + RINOK(Xz_WriteHeader(xz->flags, outStream)); + + { + CSeqCheckInStream checkInStream; + CSeqSizeOutStream seqSizeOutStream; + CXzBlock block; + int filterIndex = 0; + + XzBlock_ClearFlags(&block); + XzBlock_SetNumFilters(&block, 1 + (useSubblock ? 1 : 0)); + + if (useSubblock) + { + CXzFilter *f = &block.filters[filterIndex++]; + f->id = XZ_ID_Subblock; + f->propsSize = 0; + } + + { + CXzFilter *f = &block.filters[filterIndex++]; + f->id = XZ_ID_LZMA2; + f->propsSize = 1; + f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2); + } + + seqSizeOutStream.p.Write = MyWrite; + seqSizeOutStream.realStream = outStream; + seqSizeOutStream.processed = 0; + + RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.p)); + + checkInStream.p.Read = SeqCheckInStream_Read; + checkInStream.realStream = inStream; + SeqCheckInStream_Init(&checkInStream, XzFlags_GetCheckType(xz->flags)); + + #ifdef USE_SUBBLOCK + if (useSubblock) + { + lzmaf->sb.sb.inStream = &checkInStream.p; + SubblockEnc_Init(&lzmaf->sb.sb); + } + #endif + + { + UInt64 packPos = seqSizeOutStream.processed; + SRes res = Lzma2Enc_Encode(lzmaf->lzma2, &seqSizeOutStream.p, + #ifdef USE_SUBBLOCK + useSubblock ? &lzmaf->sb.p: + #endif + &checkInStream.p, + progress); + RINOK(res); + block.unpackSize = checkInStream.processed; + block.packSize = seqSizeOutStream.processed - packPos; + } + + { + unsigned padSize = 0; + Byte buf[128]; + while((((unsigned)block.packSize + padSize) & 3) != 0) + buf[padSize++] = 0; + SeqCheckInStream_GetDigest(&checkInStream, buf + padSize); + RINOK(WriteBytes(&seqSizeOutStream.p, buf, padSize + XzFlags_GetCheckSize(xz->flags))); + RINOK(Xz_AddIndexRecord(xz, block.unpackSize, seqSizeOutStream.processed - padSize, &g_Alloc)); + } + } + return Xz_WriteFooter(xz, outStream); +} + +SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, + const CLzma2EncProps *lzma2Props, Bool useSubblock, + ICompressProgress *progress) +{ + SRes res; + CXzStream xz; + CLzma2WithFilters lzmaf; + Xz_Construct(&xz); + Lzma2WithFilters_Construct(&lzmaf, &g_Alloc, &g_BigAlloc); + res = Lzma2WithFilters_Create(&lzmaf); + if (res == SZ_OK) + res = Xz_Compress(&xz, &lzmaf, outStream, inStream, + lzma2Props, useSubblock, progress); + Lzma2WithFilters_Free(&lzmaf); + Xz_Free(&xz, &g_Alloc); + return res; +} + +SRes Xz_EncodeEmpty(ISeqOutStream *outStream) +{ + SRes res; + CXzStream xz; + Xz_Construct(&xz); + res = Xz_WriteHeader(xz.flags, outStream); + if (res == SZ_OK) + res = Xz_WriteFooter(&xz, outStream); + Xz_Free(&xz, &g_Alloc); + return res; +} diff --git a/ext/VFS/ext/7z/src/XzEnc.h b/ext/VFS/ext/7z/src/XzEnc.h new file mode 100644 index 000000000..aad9aa4ef --- /dev/null +++ b/ext/VFS/ext/7z/src/XzEnc.h @@ -0,0 +1,25 @@ +/* XzEnc.h -- Xz Encode +2009-04-15 : Igor Pavlov : Public domain */ + +#ifndef __XZ_ENC_H +#define __XZ_ENC_H + +#include "Lzma2Enc.h" + +#include "Xz.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, + const CLzma2EncProps *lzma2Props, Bool useSubblock, + ICompressProgress *progress); + +SRes Xz_EncodeEmpty(ISeqOutStream *outStream); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/VFS/ext/7z/src/XzIn.c b/ext/VFS/ext/7z/src/XzIn.c new file mode 100644 index 000000000..356d01937 --- /dev/null +++ b/ext/VFS/ext/7z/src/XzIn.c @@ -0,0 +1,306 @@ +/* XzIn.c - Xz input +2009-06-19 : Igor Pavlov : Public domain */ + +#include + +#include "7zCrc.h" +#include "CpuArch.h" +#include "Xz.h" + +SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream) +{ + Byte sig[XZ_STREAM_HEADER_SIZE]; + RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE)); + if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0) + return SZ_ERROR_NO_ARCHIVE; + return Xz_ParseHeader(p, sig); +} + +#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ + { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ + if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; } + +SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes) +{ + Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; + unsigned headerSize; + *headerSizeRes = 0; + RINOK(SeqInStream_ReadByte(inStream, &header[0])); + headerSize = ((unsigned)header[0] << 2) + 4; + if (headerSize == 0) + { + *headerSizeRes = 1; + *isIndex = True; + return SZ_OK; + } + + *isIndex = False; + *headerSizeRes = headerSize; + RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1)); + return XzBlock_Parse(p, header); +} + +#define ADD_SIZE_CHECH(size, val) \ + { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; } + +UInt64 Xz_GetUnpackSize(const CXzStream *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->numBlocks; i++) + ADD_SIZE_CHECH(size, p->blocks[i].unpackSize); + return size; +} + +UInt64 Xz_GetPackSize(const CXzStream *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->numBlocks; i++) + ADD_SIZE_CHECH(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3); + return size; +} + +/* +SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream) +{ + return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f)); +} +*/ + +static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAlloc *alloc) +{ + size_t i, numBlocks, crcStartPos, pos = 1; + UInt32 crc; + + if (size < 5 || buf[0] != 0) + return SZ_ERROR_ARCHIVE; + + size -= 4; + crc = CrcCalc(buf, size); + if (crc != GetUi32(buf + size)) + return SZ_ERROR_ARCHIVE; + + { + UInt64 numBlocks64; + READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64); + numBlocks = (size_t)numBlocks64; + if (numBlocks != numBlocks64 || numBlocks * 2 > size) + return SZ_ERROR_ARCHIVE; + } + + crcStartPos = pos; + Xz_Free(p, alloc); + if (numBlocks != 0) + { + p->numBlocks = numBlocks; + p->numBlocksAllocated = numBlocks; + p->blocks = alloc->Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks); + if (p->blocks == 0) + return SZ_ERROR_MEM; + for (i = 0; i < numBlocks; i++) + { + CXzBlockSizes *block = &p->blocks[i]; + READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize); + READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize); + if (block->totalSize == 0) + return SZ_ERROR_ARCHIVE; + } + } + while ((pos & 3) != 0) + if (buf[pos++] != 0) + return SZ_ERROR_ARCHIVE; + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAlloc *alloc) +{ + SRes res; + size_t size; + Byte *buf; + if (indexSize > ((UInt32)1 << 31)) + return SZ_ERROR_UNSUPPORTED; + size = (size_t)indexSize; + if (size != indexSize) + return SZ_ERROR_UNSUPPORTED; + buf = alloc->Alloc(alloc, size); + if (buf == 0) + return SZ_ERROR_MEM; + res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); + if (res == SZ_OK) + res = Xz_ReadIndex2(p, buf, size, alloc); + alloc->Free(alloc, buf); + return res; +} + +static SRes SeekFromCur(ILookInStream *inStream, Int64 *res) +{ + return inStream->Seek(inStream, res, SZ_SEEK_CUR); +} + +static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc) +{ + UInt64 indexSize; + Byte buf[XZ_STREAM_FOOTER_SIZE]; + + if ((*startOffset & 3) != 0 || *startOffset < XZ_STREAM_FOOTER_SIZE) + return SZ_ERROR_NO_ARCHIVE; + *startOffset = -XZ_STREAM_FOOTER_SIZE; + RINOK(SeekFromCur(stream, startOffset)); + + RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE)); + + if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0) + { + Int64 i = 0; + *startOffset += XZ_STREAM_FOOTER_SIZE; + for (;;) + { + int j; + size_t processedSize; + #define TEMP_BUF_SIZE (1 << 10) + Byte tempBuf[TEMP_BUF_SIZE]; + if (*startOffset < XZ_STREAM_FOOTER_SIZE || i > (1 << 16)) + return SZ_ERROR_NO_ARCHIVE; + processedSize = (*startOffset > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)*startOffset; + i += processedSize; + *startOffset = -(Int64)processedSize; + RINOK(SeekFromCur(stream, startOffset)); + RINOK(LookInStream_Read2(stream, tempBuf, processedSize, SZ_ERROR_NO_ARCHIVE)); + for (j = (int)processedSize; j >= 0; j--) + if (tempBuf[j -1] != 0) + break; + if (j != 0) + { + if ((j & 3) != 0) + return SZ_ERROR_NO_ARCHIVE; + *startOffset += j; + if (*startOffset < XZ_STREAM_FOOTER_SIZE) + return SZ_ERROR_NO_ARCHIVE; + *startOffset -= XZ_STREAM_FOOTER_SIZE; + RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET)); + RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE)); + if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0) + return SZ_ERROR_NO_ARCHIVE; + break; + } + } + } + + p->flags = (CXzStreamFlags)GetBe16(buf + 8); + + if (!XzFlags_IsSupported(p->flags)) + return SZ_ERROR_UNSUPPORTED; + + if (GetUi32(buf) != CrcCalc(buf + 4, 6)) + return SZ_ERROR_ARCHIVE; + + indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2; + + *startOffset = -(Int64)(indexSize + XZ_STREAM_FOOTER_SIZE); + RINOK(SeekFromCur(stream, startOffset)); + + RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)); + + { + UInt64 totalSize = Xz_GetPackSize(p); + UInt64 sum = XZ_STREAM_HEADER_SIZE + totalSize + indexSize; + if (totalSize == XZ_SIZE_OVERFLOW || + sum >= ((UInt64)1 << 63) || + totalSize >= ((UInt64)1 << 63)) + return SZ_ERROR_ARCHIVE; + *startOffset = -(Int64)sum; + RINOK(SeekFromCur(stream, startOffset)); + } + { + CXzStreamFlags headerFlags; + CSecToRead secToRead; + SecToRead_CreateVTable(&secToRead); + secToRead.realStream = stream; + + RINOK(Xz_ReadHeader(&headerFlags, &secToRead.s)); + return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; + } +} + + +/* ---------- Xz Streams ---------- */ + +void Xzs_Construct(CXzs *p) +{ + p->num = p->numAllocated = 0; + p->streams = 0; +} + +void Xzs_Free(CXzs *p, ISzAlloc *alloc) +{ + size_t i; + for (i = 0; i < p->num; i++) + Xz_Free(&p->streams[i], alloc); + alloc->Free(alloc, p->streams); + p->num = p->numAllocated = 0; + p->streams = 0; +} + +UInt64 Xzs_GetNumBlocks(const CXzs *p) +{ + UInt64 num = 0; + size_t i; + for (i = 0; i < p->num; i++) + num += p->streams[i].numBlocks; + return num; +} + +UInt64 Xzs_GetUnpackSize(const CXzs *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->num; i++) + ADD_SIZE_CHECH(size, Xz_GetUnpackSize(&p->streams[i])); + return size; +} + +/* +UInt64 Xzs_GetPackSize(const CXzs *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->num; i++) + ADD_SIZE_CHECH(size, Xz_GetTotalSize(&p->streams[i])); + return size; +} +*/ + +SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc) +{ + Int64 endOffset = 0; + RINOK(stream->Seek(stream, &endOffset, SZ_SEEK_END)); + *startOffset = endOffset; + for (;;) + { + CXzStream st; + SRes res; + Xz_Construct(&st); + res = Xz_ReadBackward(&st, stream, startOffset, alloc); + st.startOffset = *startOffset; + RINOK(res); + if (p->num == p->numAllocated) + { + size_t newNum = p->num + p->num / 4 + 1; + Byte *data = (Byte *)alloc->Alloc(alloc, newNum * sizeof(CXzStream)); + if (data == 0) + return SZ_ERROR_MEM; + p->numAllocated = newNum; + memcpy(data, p->streams, p->num * sizeof(CXzStream)); + alloc->Free(alloc, p->streams); + p->streams = (CXzStream *)data; + } + p->streams[p->num++] = st; + if (*startOffset == 0) + break; + RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET)); + if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK) + return SZ_ERROR_PROGRESS; + } + return SZ_OK; +} diff --git a/ext/VFS/ext/utfcpp/doc/ReleaseNotes b/ext/VFS/ext/utfcpp/doc/ReleaseNotes new file mode 100644 index 000000000..8b1915e6c --- /dev/null +++ b/ext/VFS/ext/utfcpp/doc/ReleaseNotes @@ -0,0 +1,13 @@ +utf8 cpp library +Release 2.3 + +This is a relatively minor feature release based on reports from users of the library. There are also improvements in documentation: exception classes are documented. + +Changes from version 2.2.4 +- Feature request [2857462]: Proposed minor extension: safe version of is_bom. +- Feature request [2885695]: "Group" utf8 exceptions. +- Bug fix [2906315]: < instead != in utf8to32. +- Bug fix [2915657]: 64bit portability issue. +- Bug fix [2960112]: is_bom wording fix. + +Files included in the release: utf8.h, core.h, checked.h, unchecked.h, utf8cpp.html, ReleaseNotes diff --git a/ext/VFS/ext/utfcpp/doc/utf8cpp.html b/ext/VFS/ext/utfcpp/doc/utf8cpp.html new file mode 100644 index 000000000..14b224e32 --- /dev/null +++ b/ext/VFS/ext/utfcpp/doc/utf8cpp.html @@ -0,0 +1,1791 @@ + + + + + + + + + UTF8-CPP: UTF-8 with C++ in a Portable Way + + + + +

+ UTF8-CPP: UTF-8 with C++ in a Portable Way +

+

+ The Sourceforge project page +

+ +

+ Introduction +

+

+ Many C++ developers miss an easy and portable way of handling Unicode encoded + strings. The original C++ Standard (known as C++98 or C++03) is Unicode agnostic, + and while some work is being done to introduce Unicode to the next incarnation + called C++0x, for the moment nothing of the sort is available. In the meantime, + developers use third party libraries like ICU, OS specific capabilities, or simply + roll out their own solutions. +

+

+ In order to easily handle UTF-8 encoded Unicode strings, I came up with a small + generic library. For anybody used to work with STL algorithms and iterators, it should be + easy and natural to use. The code is freely available for any purpose - check out + the license at the beginning of the utf8.h file. If you run into + bugs or performance issues, please let me know and I'll do my best to address them. +

+

+ The purpose of this article is not to offer an introduction to Unicode in general, + and UTF-8 in particular. If you are not familiar with Unicode, be sure to check out + Unicode Home Page or some other source of + information for Unicode. Also, it is not my aim to advocate the use of UTF-8 + encoded strings in C++ programs; if you want to handle UTF-8 encoded strings from + C++, I am sure you have good reasons for it. +

+

+ Examples of use +

+

+ Introductionary Sample +

+

+ To illustrate the use of the library, let's start with a small but complete program + that opens a file containing UTF-8 encoded text, reads it line by line, checks each line + for invalid UTF-8 byte sequences, and converts it to UTF-16 encoding and back to UTF-8: +

+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+#include "utf8.h"
+using namespace std;
+int main(int argc, char** argv)
+{
+    if (argc != 2) {
+        cout << "\nUsage: docsample filename\n";
+        return 0;
+    }
+
+    const char* test_file_path = argv[1];
+    // Open the test file (contains UTF-8 encoded text)
+    ifstream fs8(test_file_path);
+    if (!fs8.is_open()) {
+    cout << "Could not open " << test_file_path << endl;
+    return 0;
+    }
+
+    unsigned line_count = 1;
+    string line;
+    // Play with all the lines in the file
+    while (getline(fs8, line)) {
+       // check for invalid utf-8 (for a simple yes/no check, there is also utf8::is_valid function)
+        string::iterator end_it = utf8::find_invalid(line.begin(), line.end());
+        if (end_it != line.end()) {
+            cout << "Invalid UTF-8 encoding detected at line " << line_count << "\n";
+            cout << "This part is fine: " << string(line.begin(), end_it) << "\n";
+        }
+
+        // Get the line length (at least for the valid part)
+        int length = utf8::distance(line.begin(), end_it);
+        cout << "Length of line " << line_count << " is " << length <<  "\n";
+
+        // Convert it to utf-16
+        vector<unsigned short> utf16line;
+        utf8::utf8to16(line.begin(), end_it, back_inserter(utf16line));
+
+        // And back to utf-8
+        string utf8line; 
+        utf8::utf16to8(utf16line.begin(), utf16line.end(), back_inserter(utf8line));
+
+        // Confirm that the conversion went OK:
+        if (utf8line != string(line.begin(), end_it))
+            cout << "Error in UTF-16 conversion at line: " << line_count << "\n";        
+
+        line_count++;
+    }
+    return 0;
+}
+
+

+ In the previous code sample, for each line we performed + a detection of invalid UTF-8 sequences with find_invalid; the number + of characters (more precisely - the number of Unicode code points, including the end + of line and even BOM if there is one) in each line was + determined with a use of utf8::distance; finally, we have converted + each line to UTF-16 encoding with utf8to16 and back to UTF-8 with + utf16to8. +

+

Checking if a file contains valid UTF-8 text

+

+Here is a function that checks whether the content of a file is valid UTF-8 encoded text without +reading the content into the memory: +

+
    
+bool valid_utf8_file(iconst char* file_name)
+{
+    ifstream ifs(file_name);
+    if (!ifs)
+        return false; // even better, throw here
+
+    istreambuf_iterator<char> it(ifs.rdbuf());
+    istreambuf_iterator<char> eos;
+
+    return utf8::is_valid(it, eos);
+}
+
+

+Because the function utf8::is_valid() works with input iterators, we were able +to pass an istreambuf_iterator to it and read the content of the file directly +without loading it to the memory first.

+

+Note that other functions that take input iterator arguments can be used in a similar way. For +instance, to read the content of a UTF-8 encoded text file and convert the text to UTF-16, just +do something like: +

+
+    utf8::utf8to16(it, eos, back_inserter(u16string));
+
+

Ensure that a string contains valid UTF-8 text

+

+If we have some text that "probably" contains UTF-8 encoded text and we want to +replace any invalid UTF-8 sequence with a replacement character, something like +the following function may be used: +

+
+void fix_utf8_string(std::string& str)
+{
+    std::string temp;
+    utf8::replace_invalid(str.begin(), str.end(), back_inserter(temp));
+    str = temp;
+}
+
+

The function will replace any invalid UTF-8 sequence with a Unicode replacement character. +There is an overloaded function that enables the caller to supply their own replacement character. +

+

+ Reference +

+

+ Functions From utf8 Namespace +

+

+ utf8::append +

+

+ Available in version 1.0 and later. +

+

+ Encodes a 32 bit code point as a UTF-8 sequence of octets and appends the sequence + to a UTF-8 string. +

+
+template <typename octet_iterator>
+octet_iterator append(uint32_t cp, octet_iterator result);
+   
+
+

+ octet_iterator: an output iterator.
+ cp: a 32 bit integer representing a code point to append to the + sequence.
+ result: an output iterator to the place in the sequence where to + append the code point.
+ Return value: an iterator pointing to the place + after the newly appended sequence. +

+

+ Example of use: +

+
+unsigned char u[5] = {0,0,0,0,0};
+unsigned char* end = append(0x0448, u);
+assert (u[0] == 0xd1 && u[1] == 0x88 && u[2] == 0 && u[3] == 0 && u[4] == 0);
+
+

+ Note that append does not allocate any memory - it is the burden of + the caller to make sure there is enough memory allocated for the operation. To make + things more interesting, append can add anywhere between 1 and 4 + octets to the sequence. In practice, you would most often want to use + std::back_inserter to ensure that the necessary memory is allocated. +

+

+ In case of an invalid code point, a utf8::invalid_code_point exception + is thrown. +

+

+ utf8::next +

+

+ Available in version 1.0 and later. +

+

+ Given the iterator to the beginning of the UTF-8 sequence, it returns the code + point and moves the iterator to the next position. +

+
+template <typename octet_iterator> 
+uint32_t next(octet_iterator& it, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + beginning of the next code point.
+ end: end of the UTF-8 sequence to be processed. If it + gets equal to end during the extraction of a code point, an + utf8::not_enough_room exception is thrown.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = next(w, twochars + 6);
+assert (cp == 0x65e5);
+assert (w == twochars + 3);
+
+

+ This function is typically used to iterate through a UTF-8 encoded string. +

+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. +

+

+ utf8::peek_next +

+

+ Available in version 2.1 and later. +

+

+ Given the iterator to the beginning of the UTF-8 sequence, it returns the code + point for the following sequence without changing the value of the iterator. +

+
+template <typename octet_iterator> 
+uint32_t peek_next(octet_iterator it, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ it: an iterator pointing to the beginning of an UTF-8 + encoded code point.
+ end: end of the UTF-8 sequence to be processed. If it + gets equal to end during the extraction of a code point, an + utf8::not_enough_room exception is thrown.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = peek_next(w, twochars + 6);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. +

+

+ utf8::prior +

+

+ Available in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 sequence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator> 
+uint32_t prior(octet_iterator& it, octet_iterator start);
+   
+
+

+ octet_iterator: a bidirectional iterator.
+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ start: an iterator to the beginning of the sequence where the search + for the beginning of a code point is performed. It is a + safety measure to prevent passing the beginning of the string in the search for a + UTF-8 lead octet.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+unsigned char* w = twochars + 3;
+int cp = prior (w, twochars);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ This function has two purposes: one is two iterate backwards through a UTF-8 + encoded string. Note that it is usually a better idea to iterate forward instead, + since utf8::next is faster. The second purpose is to find a beginning + of a UTF-8 sequence if we have a random position within a string. +

+

+ it will typically point to the beginning of + a code point, and start will point to the + beginning of the string to ensure we don't go backwards too far. it is + decreased until it points to a lead UTF-8 octet, and then the UTF-8 sequence + beginning with that octet is decoded to a 32 bit representation and returned. +

+

+ In case pass_end is reached before a UTF-8 lead octet is hit, or if an + invalid UTF-8 sequence is started by the lead octet, an invalid_utf8 + exception is thrown. +

+

+ utf8::previous +

+

+ Deprecated in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator> 
+uint32_t previous(octet_iterator& it, octet_iterator pass_start);
+   
+
+

+ octet_iterator: a random access iterator.
+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ pass_start: an iterator to the point in the sequence where the search + for the beginning of a code point is aborted if no result was reached. It is a + safety measure to prevent passing the beginning of the string in the search for a + UTF-8 lead octet.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+unsigned char* w = twochars + 3;
+int cp = previous (w, twochars - 1);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ utf8::previous is deprecated, and utf8::prior should + be used instead, although the existing code can continue using this function. + The problem is the parameter pass_start that points to the position + just before the beginning of the sequence. Standard containers don't have the + concept of "pass start" and the function can not be used with their iterators. +

+

+ it will typically point to the beginning of + a code point, and pass_start will point to the octet just before the + beginning of the string to ensure we don't go backwards too far. it is + decreased until it points to a lead UTF-8 octet, and then the UTF-8 sequence + beginning with that octet is decoded to a 32 bit representation and returned. +

+

+ In case pass_end is reached before a UTF-8 lead octet is hit, or if an + invalid UTF-8 sequence is started by the lead octet, an invalid_utf8 + exception is thrown +

+

+ utf8::advance +

+

+ Available in version 1.0 and later. +

+

+ Advances an iterator by the specified number of code points within an UTF-8 + sequence. +

+
+template <typename octet_iterator, typename distance_type> 
+void advance (octet_iterator& it, distance_type n, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ distance_type: an integral type convertible to octet_iterator's difference type.
+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + nth following code point.
+ n: a positive integer that shows how many code points we want to + advance.
+ end: end of the UTF-8 sequence to be processed. If it + gets equal to end during the extraction of a code point, an + utf8::not_enough_room exception is thrown.
+

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+unsigned char* w = twochars;
+advance (w, 2, twochars + 6);
+assert (w == twochars + 5);
+
+

+ This function works only "forward". In case of a negative n, there is + no effect. +

+

+ In case of an invalid code point, a utf8::invalid_code_point exception + is thrown. +

+

+ utf8::distance +

+

+ Available in version 1.0 and later. +

+

+ Given the iterators to two UTF-8 encoded code points in a seqence, returns the + number of code points between them. +

+
+template <typename octet_iterator> 
+typename std::iterator_traits<octet_iterator>::difference_type distance (octet_iterator first, octet_iterator last);
+   
+
+

+ octet_iterator: an input iterator.
+ first: an iterator to a beginning of a UTF-8 encoded code point.
+ last: an iterator to a "post-end" of the last UTF-8 encoded code + point in the sequence we are trying to determine the length. It can be the + beginning of a new code point, or not.
+ Return value the distance between the iterators, + in code points. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+size_t dist = utf8::distance(twochars, twochars + 5);
+assert (dist == 2);
+
+

+ This function is used to find the length (in code points) of a UTF-8 encoded + string. The reason it is called distance, rather than, say, + length is mainly because developers are used that length is an + O(1) function. Computing the length of an UTF-8 string is a linear operation, and + it looked better to model it after std::distance algorithm. +

+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. If last does not point to the past-of-end of a UTF-8 seqence, + a utf8::not_enough_room exception is thrown. +

+

+ utf8::utf16to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-16 encoded string to UTF-8. +

+
+template <typename u16bit_iterator, typename octet_iterator>
+octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result);
+   
+
+

+ u16bit_iterator: an input iterator.
+ octet_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-16 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-16 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+unsigned short utf16string[] = {0x41, 0x0448, 0x65e5, 0xd834, 0xdd1e};
+vector<unsigned char> utf8result;
+utf16to8(utf16string, utf16string + 5, back_inserter(utf8result));
+assert (utf8result.size() == 10);    
+
+

+ In case of invalid UTF-16 sequence, a utf8::invalid_utf16 exception is + thrown. +

+

+ utf8::utf8to16 +

+

+ Available in version 1.0 and later. +

+

+ Converts an UTF-8 encoded string to UTF-16 +

+
+template <typename u16bit_iterator, typename octet_iterator>
+u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result);
+   
+
+

+ octet_iterator: an input iterator.
+ u16bit_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert. < br /> end: an iterator pointing to + pass-the-end of the UTF-8 encoded string to convert.
+ result: an output iterator to the place in the UTF-16 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-16 string. +

+

+ Example of use: +

+
+char utf8_with_surrogates[] = "\xe6\x97\xa5\xd1\x88\xf0\x9d\x84\x9e";
+vector <unsigned short> utf16result;
+utf8to16(utf8_with_surrogates, utf8_with_surrogates + 9, back_inserter(utf16result));
+assert (utf16result.size() == 4);
+assert (utf16result[2] == 0xd834);
+assert (utf16result[3] == 0xdd1e);
+
+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. If end does not point to the past-of-end of a UTF-8 seqence, a + utf8::not_enough_room exception is thrown. +

+

+ utf8::utf32to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-32 encoded string to UTF-8. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result);
+   
+
+

+ octet_iterator: an output iterator.
+ u32bit_iterator: an input iterator.
+ start: an iterator pointing to the beginning of the UTF-32 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-32 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+int utf32string[] = {0x448, 0x65E5, 0x10346, 0};
+vector<unsigned char> utf8result;
+utf32to8(utf32string, utf32string + 3, back_inserter(utf8result));
+assert (utf8result.size() == 9);
+
+

+ In case of invalid UTF-32 string, a utf8::invalid_code_point exception + is thrown. +

+

+ utf8::utf8to32 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-8 encoded string to UTF-32. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result);
+   
+
+

+ octet_iterator: an input iterator.
+ u32bit_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-8 encoded string + to convert.
+ result: an output iterator to the place in the UTF-32 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-32 string. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+vector<int> utf32result;
+utf8to32(twochars, twochars + 5, back_inserter(utf32result));
+assert (utf32result.size() == 2);
+
+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. If end does not point to the past-of-end of a UTF-8 seqence, a + utf8::not_enough_room exception is thrown. +

+

+ utf8::find_invalid +

+

+ Available in version 1.0 and later. +

+

+ Detects an invalid sequence within a UTF-8 string. +

+
+template <typename octet_iterator> 
+octet_iterator find_invalid(octet_iterator start, octet_iterator end);
+
+

+ octet_iterator: an input iterator.
+ start: an iterator pointing to the beginning of the UTF-8 string to + test for validity.
+ end: an iterator pointing to pass-the-end of the UTF-8 string to test + for validity.
+ Return value: an iterator pointing to the first + invalid octet in the UTF-8 string. In case none were found, equals + end. +

+

+ Example of use: +

+
+char utf_invalid[] = "\xe6\x97\xa5\xd1\x88\xfa";
+char* invalid = find_invalid(utf_invalid, utf_invalid + 6);
+assert (invalid == utf_invalid + 5);
+
+

+ This function is typically used to make sure a UTF-8 string is valid before + processing it with other functions. It is especially important to call it if before + doing any of the unchecked operations on it. +

+

+ utf8::is_valid +

+

+ Available in version 1.0 and later. +

+

+ Checks whether a sequence of octets is a valid UTF-8 string. +

+
+template <typename octet_iterator> 
+bool is_valid(octet_iterator start, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ start: an iterator pointing to the beginning of the UTF-8 string to + test for validity.
+ end: an iterator pointing to pass-the-end of the UTF-8 string to test + for validity.
+ Return value: true if the sequence + is a valid UTF-8 string; false if not. +

+ Example of use: +
+char utf_invalid[] = "\xe6\x97\xa5\xd1\x88\xfa";
+bool bvalid = is_valid(utf_invalid, utf_invalid + 6);
+assert (bvalid == false);
+
+

+ is_valid is a shorthand for find_invalid(start, end) == + end;. You may want to use it to make sure that a byte seqence is a valid + UTF-8 string without the need to know where it fails if it is not valid. +

+

+ utf8::replace_invalid +

+

+ Available in version 2.0 and later. +

+

+ Replaces all invalid UTF-8 sequences within a string with a replacement marker. +

+
+template <typename octet_iterator, typename output_iterator>
+output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement);
+template <typename octet_iterator, typename output_iterator>
+output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out);
+   
+
+

+ octet_iterator: an input iterator.
+ output_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-8 string to + look for invalid UTF-8 sequences.
+ end: an iterator pointing to pass-the-end of the UTF-8 string to look + for invalid UTF-8 sequences.
+ out: An output iterator to the range where the result of replacement + is stored.
+ replacement: A Unicode code point for the replacement marker. The + version without this parameter assumes the value 0xfffd
+ Return value: An iterator pointing to the place + after the UTF-8 string with replaced invalid sequences. +

+

+ Example of use: +

+
+char invalid_sequence[] = "a\x80\xe0\xa0\xc0\xaf\xed\xa0\x80z";
+vector<char> replace_invalid_result;
+replace_invalid (invalid_sequence, invalid_sequence + sizeof(invalid_sequence), back_inserter(replace_invalid_result), '?');
+bvalid = is_valid(replace_invalid_result.begin(), replace_invalid_result.end());
+assert (bvalid);
+char* fixed_invalid_sequence = "a????z";
+assert (std::equal(replace_invalid_result.begin(), replace_invalid_result.end(), fixed_invalid_sequence));
+
+

+ replace_invalid does not perform in-place replacement of invalid + sequences. Rather, it produces a copy of the original string with the invalid + sequences replaced with a replacement marker. Therefore, out must not + be in the [start, end] range. +

+

+ If end does not point to the past-of-end of a UTF-8 sequence, a + utf8::not_enough_room exception is thrown. +

+

+ utf8::starts_with_bom +

+

+ Available in version 2.3 and later. Relaces deprecated is_bom() function. +

+

+ Checks whether an octet sequence starts with a UTF-8 byte order mark (BOM) +

+
+template <typename octet_iterator> 
+bool starts_with_bom (octet_iterator it, octet_iterator end);
+
+

+ octet_iterator: an input iterator.
+ it: beginning of the octet sequence to check
+ end: pass-end of the sequence to check
+ Return value: true if the sequence + starts with a UTF-8 byte order mark; false if not. +

+

+ Example of use: +

+
+unsigned char byte_order_mark[] = {0xef, 0xbb, 0xbf};
+bool bbom = starts_with_bom(byte_order_mark, byte_order_mark + sizeof(byte_order_mark));
+assert (bbom == true);
+
+

+ The typical use of this function is to check the first three bytes of a file. If + they form the UTF-8 BOM, we want to skip them before processing the actual UTF-8 + encoded text. +

+

+ utf8::is_bom +

+

+ Available in version 1.0 and later. Deprecated in version 2.3. starts_with_bom() should be used + instead. +

+

+ Checks whether a sequence of three octets is a UTF-8 byte order mark (BOM) +

+
+template <typename octet_iterator> 
+bool is_bom (octet_iterator it);  // Deprecated
+
+

+ octet_iterator: an input iterator.
+ it: beginning of the 3-octet sequence to check
+ Return value: true if the sequence + is UTF-8 byte order mark; false if not. +

+

+ Example of use: +

+
+unsigned char byte_order_mark[] = {0xef, 0xbb, 0xbf};
+bool bbom = is_bom(byte_order_mark, byte_order_mark + sizeof(byte_order_mark));
+assert (bbom == true);
+
+

+ The typical use of this function is to check the first three bytes of a file. If + they form the UTF-8 BOM, we want to skip them before processing the actual UTF-8 + encoded text. +

+

+ If a sequence is + shorter than three bytes, an invalid iterator will be dereferenced. Therefore, this function is deprecated + in favor of starts_with_bom()that takes the end of sequence as an argument. +

+

+ Types From utf8 Namespace +

+

utf8::exception +

+

+ Available in version 2.3 and later. +

+

+ Base class for the exceptions thrown by UTF CPP library functions. +

+
+class exception : public std::exception {};
+
+

+ Example of use: +

+
+try {
+  code_that_uses_utf_cpp_library();
+}
+catch(const utf8::exception& utfcpp_ex) {
+  cerr << utfcpp_ex.what();
+}
+
+ +

utf8::invalid_code_point +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP functions such as advance and next if an UTF-8 sequence represents and invalid code point. +

+ +
+class invalid_code_point : public exception {
+public: 
+    uint32_t code_point() const;
+};
+
+
+

+ Member function code_point() can be used to determine the invalid code point that + caused the exception to be thrown. +

+

utf8::invalid_utf8 +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP functions such as next and prior if an invalid UTF-8 sequence + is detected during decoding. +

+ +
+class invalid_utf8 : public exception {
+public: 
+    uint8_t utf8_octet() const;
+};
+
+ +

+ Member function utf8_octet() can be used to determine the beginning of the byte + sequence that caused the exception to be thrown. +

+ +

utf8::invalid_utf16 +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP function utf16to8 if an invalid UTF-16 sequence + is detected during decoding. +

+ +
+class invalid_utf16 : public exception {
+public: 
+    uint16_t utf16_word() const;
+};
+
+ +

+ Member function utf16_word() can be used to determine the UTF-16 code unit + that caused the exception to be thrown. +

+

utf8::not_enough_room +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP functions such as next if the end of the decoded UTF-8 sequence + was reached before the code point was decoded. +

+ +
+class not_enough_room : public exception {};
+
+

+ utf8::iterator +

+

+ Available in version 2.0 and later. +

+

+ Adapts the underlying octet iterator to iterate over the sequence of code points, + rather than raw octets. +

+
+template <typename octet_iterator>
+class iterator;
+
+ +
Member functions
+
+
iterator();
the deafult constructor; the underlying octet_iterator is + constructed with its default constructor. +
explicit iterator (const octet_iterator& octet_it, + const octet_iterator& range_start, + const octet_iterator& range_end);
a constructor + that initializes the underlying octet_iterator with octet_it + and sets the range in which the iterator is considered valid. +
octet_iterator base () const;
returns the + underlying octet_iterator. +
uint32_t operator * () const;
decodes the utf-8 sequence + the underlying octet_iterator is pointing to and returns the code point. +
bool operator == (const iterator& rhs) + const;
returns true + if the two underlaying iterators are equal. +
bool operator != (const iterator& rhs) + const;
returns true + if the two underlaying iterators are not equal. +
iterator& operator ++ ();
the prefix increment - moves + the iterator to the next UTF-8 encoded code point. +
iterator operator ++ (int);
+ the postfix increment - moves the iterator to the next UTF-8 encoded code point and returns the current one. +
iterator& operator -- ();
the prefix decrement - moves + the iterator to the previous UTF-8 encoded code point. +
iterator operator -- (int);
+ the postfix decrement - moves the iterator to the previous UTF-8 encoded code point and returns the current one. +
+

+ Example of use: +

+
+char* threechars = "\xf0\x90\x8d\x86\xe6\x97\xa5\xd1\x88";
+utf8::iterator<char*> it(threechars, threechars, threechars + 9);
+utf8::iterator<char*> it2 = it;
+assert (it2 == it);
+assert (*it == 0x10346);
+assert (*(++it) == 0x65e5);
+assert ((*it++) == 0x65e5);
+assert (*it == 0x0448);
+assert (it != it2);
+utf8::iterator<char*> endit (threechars + 9, threechars, threechars + 9);  
+assert (++it == endit);
+assert (*(--it) == 0x0448);
+assert ((*it--) == 0x0448);
+assert (*it == 0x65e5);
+assert (--it == utf8::iterator<char*>(threechars, threechars, threechars + 9));
+assert (*it == 0x10346);
+
+

+ The purpose of utf8::iterator adapter is to enable easy iteration as well as the use of STL + algorithms with UTF-8 encoded strings. Increment and decrement operators are implemented in terms of + utf8::next() and utf8::prior() functions. +

+

+ Note that utf8::iterator adapter is a checked iterator. It operates on the range specified in + the constructor; any attempt to go out of that range will result in an exception. Even the comparison operators + require both iterator object to be constructed against the same range - otherwise an exception is thrown. Typically, + the range will be determined by sequence container functions begin and end, i.e.: +

+
+std::string s = "example";
+utf8::iterator i (s.begin(), s.begin(), s.end());
+
+

+ Functions From utf8::unchecked Namespace +

+

+ utf8::unchecked::append +

+

+ Available in version 1.0 and later. +

+

+ Encodes a 32 bit code point as a UTF-8 sequence of octets and appends the sequence + to a UTF-8 string. +

+
+template <typename octet_iterator>
+octet_iterator append(uint32_t cp, octet_iterator result);
+   
+
+

+ cp: A 32 bit integer representing a code point to append to the + sequence.
+ result: An output iterator to the place in the sequence where to + append the code point.
+ Return value: An iterator pointing to the place + after the newly appended sequence. +

+

+ Example of use: +

+
+unsigned char u[5] = {0,0,0,0,0};
+unsigned char* end = unchecked::append(0x0448, u);
+assert (u[0] == 0xd1 && u[1] == 0x88 && u[2] == 0 && u[3] == 0 && u[4] == 0);
+
+

+ This is a faster but less safe version of utf8::append. It does not + check for validity of the supplied code point, and may produce an invalid UTF-8 + sequence. +

+

+ utf8::unchecked::next +

+

+ Available in version 1.0 and later. +

+

+ Given the iterator to the beginning of a UTF-8 sequence, it returns the code point + and moves the iterator to the next position. +

+
+template <typename octet_iterator>
+uint32_t next(octet_iterator& it);
+   
+
+

+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + beginning of the next code point.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = unchecked::next(w);
+assert (cp == 0x65e5);
+assert (w == twochars + 3);
+
+

+ This is a faster but less safe version of utf8::next. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::peek_next +

+

+ Available in version 2.1 and later. +

+

+ Given the iterator to the beginning of a UTF-8 sequence, it returns the code point. +

+
+template <typename octet_iterator>
+uint32_t peek_next(octet_iterator it);
+   
+
+

+ it: an iterator pointing to the beginning of an UTF-8 + encoded code point.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = unchecked::peek_next(w);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ This is a faster but less safe version of utf8::peek_next. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::prior +

+

+ Available in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator>
+uint32_t prior(octet_iterator& it);
+   
+
+

+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars + 3;
+int cp = unchecked::prior (w);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ This is a faster but less safe version of utf8::prior. It does not + check for validity of the supplied UTF-8 sequence and offers no boundary checking. +

+

+ utf8::unchecked::previous (deprecated, see utf8::unchecked::prior) +

+

+ Deprecated in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator>
+uint32_t previous(octet_iterator& it);
+   
+
+

+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars + 3;
+int cp = unchecked::previous (w);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ The reason this function is deprecated is just the consistency with the "checked" + versions, where prior should be used instead of previous. + In fact, unchecked::previous behaves exactly the same as + unchecked::prior +

+

+ This is a faster but less safe version of utf8::previous. It does not + check for validity of the supplied UTF-8 sequence and offers no boundary checking. +

+

+ utf8::unchecked::advance +

+

+ Available in version 1.0 and later. +

+

+ Advances an iterator by the specified number of code points within an UTF-8 + sequence. +

+
+template <typename octet_iterator, typename distance_type>
+void advance (octet_iterator& it, distance_type n);
+   
+
+

+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + nth following code point.
+ n: a positive integer that shows how many code points we want to + advance.
+

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+unchecked::advance (w, 2);
+assert (w == twochars + 5);
+
+

+ This function works only "forward". In case of a negative n, there is + no effect. +

+

+ This is a faster but less safe version of utf8::advance. It does not + check for validity of the supplied UTF-8 sequence and offers no boundary checking. +

+

+ utf8::unchecked::distance +

+

+ Available in version 1.0 and later. +

+

+ Given the iterators to two UTF-8 encoded code points in a seqence, returns the + number of code points between them. +

+
+template <typename octet_iterator>
+typename std::iterator_traits<octet_iterator>::difference_type distance (octet_iterator first, octet_iterator last);
+
+

+ first: an iterator to a beginning of a UTF-8 encoded code point.
+ last: an iterator to a "post-end" of the last UTF-8 encoded code + point in the sequence we are trying to determine the length. It can be the + beginning of a new code point, or not.
+ Return value the distance between the iterators, + in code points. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+size_t dist = utf8::unchecked::distance(twochars, twochars + 5);
+assert (dist == 2);
+
+

+ This is a faster but less safe version of utf8::distance. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::utf16to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-16 encoded string to UTF-8. +

+
+template <typename u16bit_iterator, typename octet_iterator>
+octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-16 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-16 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+unsigned short utf16string[] = {0x41, 0x0448, 0x65e5, 0xd834, 0xdd1e};
+vector<unsigned char> utf8result;
+unchecked::utf16to8(utf16string, utf16string + 5, back_inserter(utf8result));
+assert (utf8result.size() == 10);    
+
+

+ This is a faster but less safe version of utf8::utf16to8. It does not + check for validity of the supplied UTF-16 sequence. +

+

+ utf8::unchecked::utf8to16 +

+

+ Available in version 1.0 and later. +

+

+ Converts an UTF-8 encoded string to UTF-16 +

+
+template <typename u16bit_iterator, typename octet_iterator>
+u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert. < br /> end: an iterator pointing to + pass-the-end of the UTF-8 encoded string to convert.
+ result: an output iterator to the place in the UTF-16 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-16 string. +

+

+ Example of use: +

+
+char utf8_with_surrogates[] = "\xe6\x97\xa5\xd1\x88\xf0\x9d\x84\x9e";
+vector <unsigned short> utf16result;
+unchecked::utf8to16(utf8_with_surrogates, utf8_with_surrogates + 9, back_inserter(utf16result));
+assert (utf16result.size() == 4);
+assert (utf16result[2] == 0xd834);
+assert (utf16result[3] == 0xdd1e);
+
+

+ This is a faster but less safe version of utf8::utf8to16. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::utf32to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-32 encoded string to UTF-8. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-32 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-32 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+int utf32string[] = {0x448, 0x65e5, 0x10346, 0};
+vector<unsigned char> utf8result;
+utf32to8(utf32string, utf32string + 3, back_inserter(utf8result));
+assert (utf8result.size() == 9);
+
+

+ This is a faster but less safe version of utf8::utf32to8. It does not + check for validity of the supplied UTF-32 sequence. +

+

+ utf8::unchecked::utf8to32 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-8 encoded string to UTF-32. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-8 encoded string + to convert.
+ result: an output iterator to the place in the UTF-32 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-32 string. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+vector<int> utf32result;
+unchecked::utf8to32(twochars, twochars + 5, back_inserter(utf32result));
+assert (utf32result.size() == 2);
+
+

+ This is a faster but less safe version of utf8::utf8to32. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ Types From utf8::unchecked Namespace +

+

+ utf8::iterator +

+

+ Available in version 2.0 and later. +

+

+ Adapts the underlying octet iterator to iterate over the sequence of code points, + rather than raw octets. +

+
+template <typename octet_iterator>
+class iterator;
+
+ +
Member functions
+
+
iterator();
the deafult constructor; the underlying octet_iterator is + constructed with its default constructor. +
explicit iterator (const octet_iterator& octet_it); +
a constructor + that initializes the underlying octet_iterator with octet_it +
octet_iterator base () const;
returns the + underlying octet_iterator. +
uint32_t operator * () const;
decodes the utf-8 sequence + the underlying octet_iterator is pointing to and returns the code point. +
bool operator == (const iterator& rhs) + const;
returns true + if the two underlaying iterators are equal. +
bool operator != (const iterator& rhs) + const;
returns true + if the two underlaying iterators are not equal. +
iterator& operator ++ ();
the prefix increment - moves + the iterator to the next UTF-8 encoded code point. +
iterator operator ++ (int);
+ the postfix increment - moves the iterator to the next UTF-8 encoded code point and returns the current one. +
iterator& operator -- ();
the prefix decrement - moves + the iterator to the previous UTF-8 encoded code point. +
iterator operator -- (int);
+ the postfix decrement - moves the iterator to the previous UTF-8 encoded code point and returns the current one. +
+

+ Example of use: +

+
+char* threechars = "\xf0\x90\x8d\x86\xe6\x97\xa5\xd1\x88";
+utf8::unchecked::iterator<char*> un_it(threechars);
+utf8::unchecked::iterator<char*> un_it2 = un_it;
+assert (un_it2 == un_it);
+assert (*un_it == 0x10346);
+assert (*(++un_it) == 0x65e5);
+assert ((*un_it++) == 0x65e5);
+assert (*un_it == 0x0448);
+assert (un_it != un_it2);
+utf8::::unchecked::iterator<char*> un_endit (threechars + 9);  
+assert (++un_it == un_endit);
+assert (*(--un_it) == 0x0448);
+assert ((*un_it--) == 0x0448);
+assert (*un_it == 0x65e5);
+assert (--un_it == utf8::unchecked::iterator<char*>(threechars));
+assert (*un_it == 0x10346);
+
+

+ This is an unchecked version of utf8::iterator. It is faster in many cases, but offers + no validity or range checks. +

+

+ Points of interest +

+

+ Design goals and decisions +

+

+ The library was designed to be: +

+
    +
  1. + Generic: for better or worse, there are many C++ string classes out there, and + the library should work with as many of them as possible. +
  2. +
  3. + Portable: the library should be portable both accross different platforms and + compilers. The only non-portable code is a small section that declares unsigned + integers of different sizes: three typedefs. They can be changed by the users of + the library if they don't match their platform. The default setting should work + for Windows (both 32 and 64 bit), and most 32 bit and 64 bit Unix derivatives. +
  4. +
  5. + Lightweight: follow the "pay only for what you use" guidline. +
  6. +
  7. + Unintrusive: avoid forcing any particular design or even programming style on the + user. This is a library, not a framework. +
  8. +
+

+ Alternatives +

+

+ In case you want to look into other means of working with UTF-8 strings from C++, + here is the list of solutions I am aware of: +

+
    +
  1. + ICU Library. It is very powerful, + complete, feature-rich, mature, and widely used. Also big, intrusive, + non-generic, and doesn't play well with the Standard Library. I definitelly + recommend looking at ICU even if you don't plan to use it. +
  2. +
  3. + Glib::ustring. + A class specifically made to work with UTF-8 strings, and also feel like + std::string. If you prefer to have yet another string class in your + code, it may be worth a look. Be aware of the licensing issues, though. +
  4. +
  5. + Platform dependent solutions: Windows and POSIX have functions to convert strings + from one encoding to another. That is only a subset of what my library offers, + but if that is all you need it may be good enough, especially given the fact that + these functions are mature and tested in production. +
  6. +
+

+ Conclusion +

+

+ Until Unicode becomes officially recognized by the C++ Standard Library, we need to + use other means to work with UTF-8 strings. Template functions I describe in this + article may be a good step in this direction. +

+ +
    +
  1. + The Unicode Consortium. +
  2. +
  3. + ICU Library. +
  4. +
  5. + UTF-8 at Wikipedia +
  6. +
  7. + UTF-8 and Unicode FAQ for + Unix/Linux +
  8. +
+ + diff --git a/ext/VFS/ext/utfcpp/source/utf8.h b/ext/VFS/ext/utfcpp/source/utf8.h new file mode 100644 index 000000000..4e4451403 --- /dev/null +++ b/ext/VFS/ext/utfcpp/source/utf8.h @@ -0,0 +1,34 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "utf8/checked.h" +#include "utf8/unchecked.h" + +#endif // header guard diff --git a/ext/VFS/ext/utfcpp/source/utf8/checked.h b/ext/VFS/ext/utfcpp/source/utf8/checked.h new file mode 100644 index 000000000..a1d203536 --- /dev/null +++ b/ext/VFS/ext/utfcpp/source/utf8/checked.h @@ -0,0 +1,323 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" +#include + +namespace utf8 +{ + // Base for the exceptions that may be thrown from the library + class exception : public std::exception { + }; + + // Exceptions that may be thrown from the library functions. + class invalid_code_point : public exception { + uint32_t cp; + public: + invalid_code_point(uint32_t cp) : cp(cp) {} + virtual const char* what() const throw() { return "Invalid code point"; } + uint32_t code_point() const {return cp;} + }; + + class invalid_utf8 : public exception { + uint8_t u8; + public: + invalid_utf8 (uint8_t u) : u8(u) {} + virtual const char* what() const throw() { return "Invalid UTF-8"; } + uint8_t utf8_octet() const {return u8;} + }; + + class invalid_utf16 : public exception { + uint16_t u16; + public: + invalid_utf16 (uint16_t u) : u16(u) {} + virtual const char* what() const throw() { return "Invalid UTF-16"; } + uint16_t utf16_word() const {return u16;} + }; + + class not_enough_room : public exception { + public: + virtual const char* what() const throw() { return "Not enough space"; } + }; + + /// The library API - functions intended to be called by the users + + template + output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) + { + while (start != end) { + octet_iterator sequence_start = start; + internal::utf_error err_code = internal::validate_next(start, end); + switch (err_code) { + case internal::UTF8_OK : + for (octet_iterator it = sequence_start; it != start; ++it) + *out++ = *it; + break; + case internal::NOT_ENOUGH_ROOM: + throw not_enough_room(); + case internal::INVALID_LEAD: + append (replacement, out); + ++start; + break; + case internal::INCOMPLETE_SEQUENCE: + case internal::OVERLONG_SEQUENCE: + case internal::INVALID_CODE_POINT: + append (replacement, out); + ++start; + // just one replacement mark for the sequence + while (internal::is_trail(*start) && start != end) + ++start; + break; + } + } + return out; + } + + template + inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) + { + static const uint32_t replacement_marker = internal::mask16(0xfffd); + return replace_invalid(start, end, out, replacement_marker); + } + + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (!internal::is_code_point_valid(cp)) + throw invalid_code_point(cp); + + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + uint32_t next(octet_iterator& it, octet_iterator end) + { + uint32_t cp = 0; + internal::utf_error err_code = internal::validate_next(it, end, &cp); + switch (err_code) { + case internal::UTF8_OK : + break; + case internal::NOT_ENOUGH_ROOM : + throw not_enough_room(); + case internal::INVALID_LEAD : + case internal::INCOMPLETE_SEQUENCE : + case internal::OVERLONG_SEQUENCE : + throw invalid_utf8(*it); + case internal::INVALID_CODE_POINT : + throw invalid_code_point(cp); + } + return cp; + } + + template + uint32_t peek_next(octet_iterator it, octet_iterator end) + { + return next(it, end); + } + + template + uint32_t prior(octet_iterator& it, octet_iterator start) + { + octet_iterator end = it; + while (internal::is_trail(*(--it))) + if (it < start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + octet_iterator temp = it; + return next(temp, end); + } + + /// Deprecated in versions that include "prior" + template + uint32_t previous(octet_iterator& it, octet_iterator pass_start) + { + octet_iterator end = it; + while (internal::is_trail(*(--it))) + if (it == pass_start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + octet_iterator temp = it; + return next(temp, end); + } + + template + void advance (octet_iterator& it, distance_type n, octet_iterator end) + { + for (distance_type i = 0; i < n; ++i) + next(it, end); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + next(first, last); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = internal::mask16(*start++); + // Take care of surrogate pairs first + if (internal::is_lead_surrogate(cp)) { + if (start != end) { + uint32_t trail_surrogate = internal::mask16(*start++); + if (internal::is_trail_surrogate(trail_surrogate)) + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + else + throw invalid_utf16(static_cast(trail_surrogate)); + } + else + throw invalid_utf16(static_cast(cp)); + + } + // Lone trail surrogate + else if (internal::is_trail_surrogate(cp)) + throw invalid_utf16(static_cast(cp)); + + result = append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start != end) { + uint32_t cp = next(start, end); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start != end) + (*result++) = next(start, end); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + octet_iterator range_start; + octet_iterator range_end; + public: + iterator () {}; + explicit iterator (const octet_iterator& octet_it, + const octet_iterator& range_start, + const octet_iterator& range_end) : + it(octet_it), range_start(range_start), range_end(range_end) + { + if (it < range_start || it > range_end) + throw std::out_of_range("Invalid utf-8 iterator position"); + } + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return next(temp, range_end); + } + bool operator == (const iterator& rhs) const + { + if (range_start != rhs.range_start || range_end != rhs.range_end) + throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + next(it, range_end); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + next(it, range_end); + return temp; + } + iterator& operator -- () + { + prior(it, range_start); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + prior(it, range_start); + return temp; + } + }; // class iterator + +} // namespace utf8 + +#endif //header guard + + diff --git a/ext/VFS/ext/utfcpp/source/utf8/core.h b/ext/VFS/ext/utfcpp/source/utf8/core.h new file mode 100644 index 000000000..ec709f120 --- /dev/null +++ b/ext/VFS/ext/utfcpp/source/utf8/core.h @@ -0,0 +1,358 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include + +namespace utf8 +{ + // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers + // You may need to change them to match your system. + // These typedefs have the same names as ones from cstdint, or boost/cstdint + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + +// Helper code - not intended to be directly called by the library users. May be changed at any time +namespace internal +{ + // Unicode constants + // Leading (high) surrogates: 0xd800 - 0xdbff + // Trailing (low) surrogates: 0xdc00 - 0xdfff + const uint16_t LEAD_SURROGATE_MIN = 0xd800u; + const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; + const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; + const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; + const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); + const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; + + // Maximum valid value for a Unicode code point + const uint32_t CODE_POINT_MAX = 0x0010ffffu; + + template + inline uint8_t mask8(octet_type oc) + { + return static_cast(0xff & oc); + } + template + inline uint16_t mask16(u16_type oc) + { + return static_cast(0xffff & oc); + } + template + inline bool is_trail(octet_type oc) + { + return ((mask8(oc) >> 6) == 0x2); + } + + template + inline bool is_lead_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); + } + + template + inline bool is_trail_surrogate(u16 cp) + { + return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_code_point_valid(u32 cp) + { + return (cp <= CODE_POINT_MAX && !is_surrogate(cp) && cp != 0xfffe && cp != 0xffff); + } + + template + inline typename std::iterator_traits::difference_type + sequence_length(octet_iterator lead_it) + { + uint8_t lead = mask8(*lead_it); + if (lead < 0x80) + return 1; + else if ((lead >> 5) == 0x6) + return 2; + else if ((lead >> 4) == 0xe) + return 3; + else if ((lead >> 3) == 0x1e) + return 4; + else + return 0; + } + + template + inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) + { + if (cp < 0x80) { + if (length != 1) + return true; + } + else if (cp < 0x800) { + if (length != 2) + return true; + } + else if (cp < 0x10000) { + if (length != 3) + return true; + } + + return false; + } + + enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; + + /// get_sequence_x functions decode utf-8 sequences of the length x + + template + utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + if (it != end) { + if (code_point) + *code_point = mask8(*it); + return UTF8_OK; + } + return NOT_ENOUGH_ROOM; + } + + template + utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 12) & 0xffff) + ((mask8(*it) << 6) & 0xfff); + if (++it != end) { + if (is_trail(*it)) { + cp += (*it) & 0x3f; + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 18) & 0x1fffff) + ((mask8(*it) << 12) & 0x3ffff); + if (++it != end) { + if (is_trail(*it)) { + cp += (mask8(*it) << 6) & 0xfff; + if (++it != end) { + if (is_trail(*it)) { + cp += (*it) & 0x3f; + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + // Save the original value of it so we can go back in case of failure + // Of course, it does not make much sense with i.e. stream iterators + octet_iterator original_it = it; + + uint32_t cp = 0; + // Determine the sequence length based on the lead octet + typedef typename std::iterator_traits::difference_type octet_difference_type; + octet_difference_type length = sequence_length(it); + if (length == 0) + return INVALID_LEAD; + + // Now that we have a valid sequence length, get trail octets and calculate the code point + utf_error err = UTF8_OK; + switch (length) { + case 1: + err = get_sequence_1(it, end, &cp); + break; + case 2: + err = get_sequence_2(it, end, &cp); + break; + case 3: + err = get_sequence_3(it, end, &cp); + break; + case 4: + err = get_sequence_4(it, end, &cp); + break; + } + + if (err == UTF8_OK) { + // Decoding succeeded. Now, security checks... + if (is_code_point_valid(cp)) { + if (!is_overlong_sequence(cp, length)){ + // Passed! Return here. + if (code_point) + *code_point = cp; + ++it; + return UTF8_OK; + } + else + err = OVERLONG_SEQUENCE; + } + else + err = INVALID_CODE_POINT; + } + + // Failure branch - restore the original value of the iterator + it = original_it; + return err; + } + + template + inline utf_error validate_next(octet_iterator& it, octet_iterator end) { + return validate_next(it, end, 0); + } + +} // namespace internal + + /// The library API - functions intended to be called by the users + + // Byte order mark + const uint8_t bom[] = {0xef, 0xbb, 0xbf}; + + template + octet_iterator find_invalid(octet_iterator start, octet_iterator end) + { + octet_iterator result = start; + while (result != end) { + internal::utf_error err_code = internal::validate_next(result, end); + if (err_code != internal::UTF8_OK) + return result; + } + return result; + } + + template + inline bool is_valid(octet_iterator start, octet_iterator end) + { + return (find_invalid(start, end) == end); + } + + template + inline bool starts_with_bom (octet_iterator it, octet_iterator end) + { + return ( + ((it != end) && (internal::mask8(*it++)) == bom[0]) && + ((it != end) && (internal::mask8(*it++)) == bom[1]) && + ((it != end) && (internal::mask8(*it)) == bom[2]) + ); + } + + //Deprecated in release 2.3 + template + inline bool is_bom (octet_iterator it) + { + return ( + (internal::mask8(*it++)) == bom[0] && + (internal::mask8(*it++)) == bom[1] && + (internal::mask8(*it)) == bom[2] + ); + } +} // namespace utf8 + +#endif // header guard + + diff --git a/ext/VFS/ext/utfcpp/source/utf8/unchecked.h b/ext/VFS/ext/utfcpp/source/utf8/unchecked.h new file mode 100644 index 000000000..2f3eb4d1d --- /dev/null +++ b/ext/VFS/ext/utfcpp/source/utf8/unchecked.h @@ -0,0 +1,228 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" + +namespace utf8 +{ + namespace unchecked + { + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + uint32_t next(octet_iterator& it) + { + uint32_t cp = internal::mask8(*it); + typename std::iterator_traits::difference_type length = utf8::internal::sequence_length(it); + switch (length) { + case 1: + break; + case 2: + it++; + cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); + break; + case 3: + ++it; + cp = ((cp << 12) & 0xffff) + ((internal::mask8(*it) << 6) & 0xfff); + ++it; + cp += (*it) & 0x3f; + break; + case 4: + ++it; + cp = ((cp << 18) & 0x1fffff) + ((internal::mask8(*it) << 12) & 0x3ffff); + ++it; + cp += (internal::mask8(*it) << 6) & 0xfff; + ++it; + cp += (*it) & 0x3f; + break; + } + ++it; + return cp; + } + + template + uint32_t peek_next(octet_iterator it) + { + return next(it); + } + + template + uint32_t prior(octet_iterator& it) + { + while (internal::is_trail(*(--it))) ; + octet_iterator temp = it; + return next(temp); + } + + // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) + template + inline uint32_t previous(octet_iterator& it) + { + return prior(it); + } + + template + void advance (octet_iterator& it, distance_type n) + { + for (distance_type i = 0; i < n; ++i) + next(it); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + next(first); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = internal::mask16(*start++); + // Take care of surrogate pairs first + if (internal::is_lead_surrogate(cp)) { + uint32_t trail_surrogate = internal::mask16(*start++); + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + } + result = append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start < end) { + uint32_t cp = next(start); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start < end) + (*result++) = next(start); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + public: + iterator () {}; + explicit iterator (const octet_iterator& octet_it): it(octet_it) {} + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return next(temp); + } + bool operator == (const iterator& rhs) const + { + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + std::advance(it, internal::sequence_length(it)); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + std::advance(it, internal::sequence_length(it)); + return temp; + } + iterator& operator -- () + { + prior(it); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + prior(it); + return temp; + } + }; // class iterator + + } // namespace utf8::unchecked +} // namespace utf8 + + +#endif // header guard + diff --git a/ext/VFS/include/vfs/Aspects/vfs_logging.h b/ext/VFS/include/vfs/Aspects/vfs_logging.h new file mode 100644 index 000000000..4b1c52a01 --- /dev/null +++ b/ext/VFS/include/vfs/Aspects/vfs_logging.h @@ -0,0 +1,104 @@ +/* + * bfVFS : vfs/Aspects/vfs_logging.h + * - Logging interface and macros that will be used to report errors/warnings to the using program + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef VFS_LOGGING_H +#define VFS_LOGGING_H + +#include + +namespace vfs +{ + class String; + namespace Aspects + { + enum LogType { LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG }; + + class ILogger + { + public: + virtual void Msg(const wchar_t* msg) = 0; + virtual void Msg(const char* msg) = 0; + }; + + VFS_API void setLogger(LogType type, ILogger* logger); + VFS_API ILogger* getLogger(LogType type); + + VFS_API void setLogger( ILogger* info_logger, ILogger* warning_logger, ILogger* error_logger, ILogger* debug_logger ); + + void Debug(vfs::String const& msg); + void Debug(const wchar_t* msg); + void Debug(const char* msg); + + void Info(vfs::String const& msg); + void Info(const wchar_t* msg); + void Info(const char* msg); + + void Warning(vfs::String const& msg); + void Warning(const wchar_t* msg); + void Warning(const char* msg); + + void Error(vfs::String const& msg); + void Error(const wchar_t* msg); + void Error(const char* msg); + }; +}; + +#if !defined VFS_DISABLE_LOGGING + +# if !defined VFS_LOG_DEBUG +# define VFS_LOG_DEBUG(msg) (vfs::Aspects::Debug(msg)) +# endif + +# if !defined VFS_LOG_INFO +# define VFS_LOG_INFO(msg) (vfs::Aspects::Info(msg)) +# endif + +# if !defined VFS_LOG_WARNING +# define VFS_LOG_WARNING(msg) (vfs::Aspects::Warning(msg)) +# endif + +# if !defined VFS_LOG_ERROR +# define VFS_LOG_ERROR(msg) (vfs::Aspects::Error(msg)) +# endif + +#else + +# if !defined VFS_LOG_DEBUG +# define VFS_LOG_DEBUG(msg) +# endif + +# if !defined VFS_LOG_INFO +# define VFS_LOG_INFO(msg) +# endif + +# if !defined VFS_LOG_WARNING +# define VFS_LOG_WARNING(msg) +# endif + +# if !defined VFS_LOG_ERROR +# define VFS_LOG_ERROR(msg) +# endif + +#endif // VFS_DISABLE_LOGGING + +#endif // VFS_LOGGING_H diff --git a/ext/VFS/include/vfs/Aspects/vfs_settings.h b/ext/VFS/include/vfs/Aspects/vfs_settings.h new file mode 100644 index 000000000..99b7fa59a --- /dev/null +++ b/ext/VFS/include/vfs/Aspects/vfs_settings.h @@ -0,0 +1,40 @@ +/* + * bfVFS : vfs/Aspects/vfs_settings.h + * - library runtime settings, + * - e.g., to use Unicode strings or regular for file names + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_SETTIGNS_H_ +#define _VFS_SETTIGNS_H_ + +#include + +namespace vfs +{ + class VFS_API Settings + { + public: + static void setUseUnicode(bool useUnicode); + static bool getUseUnicode(); + }; +} + +#endif // _VFS_SETTIGNS_H_ diff --git a/ext/VFS/include/vfs/Aspects/vfs_synchronization.h b/ext/VFS/include/vfs/Aspects/vfs_synchronization.h new file mode 100644 index 000000000..b502ec7cf --- /dev/null +++ b/ext/VFS/include/vfs/Aspects/vfs_synchronization.h @@ -0,0 +1,87 @@ +/* + * bfVFS : vfs/Aspects/vfs_synchronization.h + * - Interface for Mutexes and Locks, implementation can or has to be provided by the using program + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef VFS_SYNCHRONIZATION_H +#define VFS_SYNCHRONIZATION_H + +#include + +namespace vfs +{ + namespace Aspects + { + class IMutex + { + public: + virtual void lock() {}; + virtual void unlock() {}; + }; + + class IMutexFactory + { + public: + virtual IMutex* createMutex() = 0; + }; + + VFS_API void setMutexFactory(IMutexFactory* mutex_factory); + VFS_API IMutexFactory* getMutexFactory(); + + class Mutex + { + public: + Mutex(); + ~Mutex(); + + void lock(); + void unlock(); + private: + int _locked; + IMutex* _mutex; + }; + + class ScopedLock + { + public: + ScopedLock(Mutex& mutex) : _mutex(mutex) { + this->_mutex.lock(); + } + ~ScopedLock(){ + this->_mutex.unlock(); + } + private: + Mutex& _mutex; + }; + } +} + +#ifdef VFS_SYNCHRONIZE +# if !defined VFS_LOCK +# define VFS_LOCK(mutex) vfs::Aspects::ScopedLock _scoped_lock(mutex) +# endif +#else +# if !defined VFS_LOCK +# define VFS_LOCK(mutex) +# endif +#endif + +#endif // VFS_SYNCHRONIZATION_H diff --git a/ext/VFS/include/vfs/Core/File/vfs_buffer_file.h b/ext/VFS/include/vfs/Core/File/vfs_buffer_file.h new file mode 100644 index 000000000..006278ad2 --- /dev/null +++ b/ext/VFS/include/vfs/Core/File/vfs_buffer_file.h @@ -0,0 +1,73 @@ +/* + * bfVFS : vfs/Core/File/vfs_buffer_file.h + * - Buffer in RAM, implements File interface to unify usage of file and memory + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_MEMORY_FILE_H_ +#define _VFS_MEMORY_FILE_H_ + +#include +#include + +namespace vfs +{ + class VFS_API CBufferFile : public vfs::TFileTemplate + { + typedef vfs::TFileTemplate tBaseClass; + public : + CBufferFile(); + CBufferFile(vfs::Path const& filename); + virtual ~CBufferFile(); + + virtual vfs::FileAttributes getAttributes(); + + virtual void close(); + virtual vfs::size_t getSize(); + + virtual bool isOpenRead(); + virtual bool openRead(); + virtual vfs::size_t read(vfs::Byte* data, vfs::size_t bytesToRead); + + virtual vfs::size_t getReadPosition(); + virtual void setReadPosition(vfs::size_t positionInBytes); + virtual void setReadPosition(vfs::offset_t offsetInBytes, vfs::IBaseFile::ESeekDir seekDir); + + virtual bool isOpenWrite(); + virtual bool openWrite(bool bCreateWhenNotExist = false, bool bTruncate = false); + virtual vfs::size_t write(const vfs::Byte* data, vfs::size_t bytesToWrite); + + virtual vfs::size_t getWritePosition(); + virtual void setWritePosition(vfs::size_t positionInBytes); + virtual void setWritePosition(vfs::offset_t offsetInBytes, vfs::IBaseFile::ESeekDir seekDir); + + virtual bool deleteFile(); + + // convenience method + void copyToBuffer(vfs::tReadableFile& rFile); + protected: + std::stringstream m_buffer; + bool m_isOpen_read, m_isOpen_write; + }; + +} // end namespace + +#endif // _VFS_MEMORY_FILE_H_ + diff --git a/ext/VFS/include/vfs/Core/File/vfs_dir_file.h b/ext/VFS/include/vfs/Core/File/vfs_dir_file.h new file mode 100644 index 000000000..8558c7ac5 --- /dev/null +++ b/ext/VFS/include/vfs/Core/File/vfs_dir_file.h @@ -0,0 +1,76 @@ +/* + * bfVFS : vfs/Core/File/vfs_dir_file.h + * - read/read-write files for usage in vfs locations + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_DIR_FILE_H_ +#define _VFS_DIR_FILE_H_ + +#include + +#include +#include +#include + +namespace vfs +{ + class VFS_API CReadOnlyDirFile : public vfs::CReadOnlyFile + { + protected: + typedef vfs::TDirectory tLocation; + public: + CReadOnlyDirFile(vfs::Path const& filename, tLocation *directory); + virtual ~CReadOnlyDirFile(); + + virtual vfs::FileAttributes getAttributes(); + + virtual vfs::Path getPath(); + + virtual bool openRead(); + + virtual bool _getRealPath(vfs::Path& path); + private: + tLocation* _location; + }; + + class VFS_API CDirFile : public vfs::CFile + { + typedef vfs::TDirectory tLocation; + public: + CDirFile(vfs::Path const& filename, tLocation *directory); + virtual ~CDirFile(); + + virtual vfs::FileAttributes getAttributes(); + + virtual vfs::Path getPath(); + virtual bool deleteFile(); + + virtual bool openRead(); + virtual bool openWrite(bool createWhenNotExist = false, bool truncate = false); + + virtual bool _getRealPath(vfs::Path& path); + private: + tLocation* _location; + }; +} // end namespace + +#endif // _VFS_DIR_FILE_H_ + diff --git a/ext/VFS/include/vfs/Core/File/vfs_file.h b/ext/VFS/include/vfs/Core/File/vfs_file.h new file mode 100644 index 000000000..7aeb212d5 --- /dev/null +++ b/ext/VFS/include/vfs/Core/File/vfs_file.h @@ -0,0 +1,113 @@ +/* + * bfVFS : vfs/Core/File/vfs_file.h + * - File with read/read-write access + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_FILE_H_ +#define _VFS_FILE_H_ + +#include +#include +#include + +#ifdef WIN32 +# include "windows.h" +#else +# include +#endif + +typedef std::basic_fstream wfstream; + +namespace vfs +{ + /******************************************************************/ + /******************************************************************/ + + template + class VFS_API TFile : public vfs::TFileTemplate + { + typedef vfs::TFileTemplate tBaseClass; + public : + TFile(vfs::Path const& filename); + virtual ~TFile(); + + virtual vfs::FileAttributes getAttributes(); + + virtual void close(); + virtual vfs::size_t getSize(); + + virtual bool isOpenRead(); + virtual bool openRead(); + virtual vfs::size_t read(vfs::Byte* data, vfs::size_t bytesToRead); + + virtual vfs::size_t getReadPosition(); + virtual void setReadPosition(vfs::size_t positionInBytes); + virtual void setReadPosition(vfs::offset_t offsetInBytes, vfs::IBaseFile::ESeekDir seekDir); + + protected: + bool _internalOpenRead(vfs::Path const& path); + protected: + bool m_isOpen_read; +#ifdef WIN32 + HANDLE m_file; +#else + FILE* m_file; +#endif + //vfs::Aspects::Mutex m_mutex; + }; + + /******************************************************************/ + /******************************************************************/ + + // implements the IWritable interface for TFile + class VFS_API CFile : public vfs::TFile + { + typedef vfs::TFile tBaseClass; + public : + CFile(vfs::Path const& filename); + virtual ~CFile(); + + virtual void close(); + + virtual bool isOpenWrite(); + virtual bool openWrite(bool createWhenNotExist = false, bool truncate = false); + virtual vfs::size_t write(const vfs::Byte* data, vfs::size_t bytesToWrite); + + virtual vfs::size_t getWritePosition(); + virtual void setWritePosition(vfs::size_t positionInBytes); + virtual void setWritePosition(vfs::offset_t offsetInBytes, vfs::IBaseFile::ESeekDir seekDir); + + virtual bool deleteFile(); + protected: + bool _internalOpenWrite(vfs::Path const& path, bool createWhenNotExist = false, bool truncate = false); + protected: + bool m_isOpen_write; + }; + + /******************************************************************/ + /******************************************************************/ + + typedef vfs::TFile CReadOnlyFile; // needs explicit template instantiation + +} // end namespace + +#endif // _VFS_FILE_H_ + diff --git a/ext/VFS/include/vfs/Core/File/vfs_lib_file.h b/ext/VFS/include/vfs/Core/File/vfs_lib_file.h new file mode 100644 index 000000000..e6b7e769e --- /dev/null +++ b/ext/VFS/include/vfs/Core/File/vfs_lib_file.h @@ -0,0 +1,78 @@ +/* + * bfVFS : vfs/Core/File/vfs_lib_file.h + * - read/read-write files for usage in vfs locations (libraries) + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_LIB_FILE_H_ +#define _VFS_LIB_FILE_H_ + +#include +#include +#include +#include + +namespace vfs +{ + + class ILibrary; + + class CLibFile : public vfs::TFileTemplate + { + typedef vfs::TFileTemplate tBaseClass; + typedef vfs::TLocationTemplate tLocation; + public: + CLibFile(); + static CLibFile* create(vfs::Path const& filename, + tLocation *location, + vfs::ILibrary *library, + vfs::ObjBlockAllocator* allocator = NULL); + + // don't delete objects that YOU have not created with 'new' + // dtor has to remain public to be usable at all + virtual ~CLibFile(); + + virtual vfs::FileAttributes getAttributes(); + + virtual void close(); + + virtual vfs::Path getPath(); + + virtual bool isOpenRead(); + virtual bool openRead(); + virtual vfs::size_t read(vfs::Byte* pData, vfs::size_t bytesToRead); + + virtual vfs::size_t getReadPosition(); + virtual void setReadPosition(vfs::size_t positionInBytes); + virtual void setReadPosition(vfs::offset_t offsetInBytes, vfs::IBaseFile::ESeekDir seekDir); + + virtual vfs::size_t getSize(); + protected: + bool m_isOpen_read; + ILibrary* m_library; + tLocation* m_location; + private: + static vfs::ObjBlockAllocator* _lfile_pool; + }; + +} // end namespace + +#endif // _VFS_LIB_FILE_H_ + diff --git a/ext/VFS/include/vfs/Core/Interface/vfs_directory_interface.h b/ext/VFS/include/vfs/Core/Interface/vfs_directory_interface.h new file mode 100644 index 000000000..a3417cadc --- /dev/null +++ b/ext/VFS/include/vfs/Core/Interface/vfs_directory_interface.h @@ -0,0 +1,63 @@ +/* + * bfVFS : vfs/Core/Interface/vfs_directory_interface.h + * - partially implements Location interface for file system directories + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_DIRECTORY_INTERFACE_H_ +#define _VFS_DIRECTORY_INTERFACE_H_ + +#include + +namespace vfs +{ + template + class TDirectory : public vfs::TLocationTemplate + { + public: + typedef typename vfs::TLocationTemplate tBaseClass; + typedef typename tBaseClass::tFileType tFileType; + typedef typename tBaseClass::tWriteType tWriteType; + + TDirectory(vfs::Path const& mountPoint, vfs::Path const& realPath) + : tBaseClass(mountPoint), m_realPath(realPath) + {}; + virtual ~TDirectory() + {}; + + vfs::Path const& getRealPath() + { + return m_realPath; + } + + virtual tFileType* addFile(vfs::Path const& sFilename, bool bDeleteOldFile=false) = 0; + virtual bool addFile(typename tBaseClass::tFileType* pFile, bool bDeleteOldFile=false) = 0; + + virtual bool createSubDirectory(vfs::Path const& sSubDirPath) = 0; + virtual bool deleteDirectory(vfs::Path const& sDirPath) = 0; + virtual bool deleteFileFromDirectory(vfs::Path const& sFileName) = 0; + protected: + const vfs::Path m_realPath; + private: + void operator=(TDirectory const& t); + }; +} + +#endif // _VFS_DIRECTORY_INTERFACE_H_ diff --git a/ext/VFS/include/vfs/Core/Interface/vfs_file_interface.h b/ext/VFS/include/vfs/Core/Interface/vfs_file_interface.h new file mode 100644 index 000000000..d371ea68d --- /dev/null +++ b/ext/VFS/include/vfs/Core/Interface/vfs_file_interface.h @@ -0,0 +1,257 @@ +/* + * bfVFS : vfs/Core/Interface/vfs_file_interface.h + * - generic interface for read/write files + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_FILE_INTERFACE_H_ +#define _VFS_FILE_INTERFACE_H_ + +#include +#include + +#include + +namespace vfs +{ + /** + * FileAttributes + */ + class VFS_API FileAttributes + { + public: + enum Attributes { + ATTRIB_INVALID = 0, + ATTRIB_ARCHIVE = 1, + ATTRIB_DIRECTORY = 2, + ATTRIB_HIDDEN = 4, + ATTRIB_NORMAL = 8, + ATTRIB_READONLY = 16, + ATTRIB_SYSTEM = 32, + ATTRIB_TEMPORARY = 64, + ATTRIB_COMPRESSED = 128, + ATTRIB_OFFLINE = 256, + }; + enum LocationType { + LT_NONE = 0, + LT_LIBRARY = 1, + LT_DIRECTORY = 2, + LT_READONLY_DIRECTORY = 4, + }; + public: + FileAttributes(); + FileAttributes(vfs::UInt32 attribs, LocationType location); + + vfs::UInt32 getAttrib() const; + vfs::UInt32 getLocation() const; + + bool isAttribSet(vfs::UInt32 attribs) const; + bool isAttribNotSet(vfs::UInt32 attribs) const; + + bool isLocation(vfs::UInt32 location) const; + private: + void operator=(vfs::FileAttributes const& attr); + + const vfs::UInt32 _attribs; + const vfs::UInt32 _location; + }; + + /** + * IBaseFile + */ + class VFS_API IBaseFile + { + public: + enum ESeekDir + { + SD_BEGIN, + SD_CURRENT, + SD_END, + }; + public: + IBaseFile(vfs::Path const& filename); + virtual ~IBaseFile(); + + virtual vfs::FileAttributes getAttributes() = 0; + + vfs::Path const& getName(); + virtual vfs::Path getPath(); + + virtual bool implementsWritable() = 0; + virtual bool implementsReadable() = 0; + + virtual void close() = 0; + virtual vfs::size_t getSize() = 0; + + virtual bool _getRealPath(vfs::Path& path); + protected: + vfs::Path m_filename; + }; + + /** + * IReadType , IReadable + */ + class IReadType{}; + class IReadable : public vfs::IReadType + { + public: + virtual bool isOpenRead() = 0; + virtual bool openRead() = 0; + virtual vfs::size_t read(vfs::Byte* data, vfs::size_t bytesToRead) = 0; + + virtual vfs::size_t getReadPosition() = 0; + virtual void setReadPosition(vfs::size_t positionInBytes) = 0; + virtual void setReadPosition(vfs::offset_t offsetInBytes, vfs::IBaseFile::ESeekDir seekDir) = 0; + }; + //class NonReadable : public IReadType{}; + + /** + * IWriteType , IWritable + */ + class IWriteType{}; + class IWritable : public vfs::IWriteType + { + public: + virtual bool isOpenWrite() = 0; + virtual bool openWrite(bool createWhenNotExist = false, bool truncate = false) = 0; + virtual vfs::size_t write(const vfs::Byte* data, vfs::size_t bytesToWrite) = 0; + + virtual vfs::size_t getWritePosition() = 0; + virtual void setWritePosition(vfs::size_t positionInBytes) = 0; + virtual void setWritePosition(vfs::offset_t offsetInBytes, vfs::IBaseFile::ESeekDir seekDir) = 0; + + virtual bool deleteFile() = 0; + }; + //class NonWritable: public IWriteType{}; + + /******************************************************************/ + /******************************************************************/ + + /** + * IFileTemplate + */ + template + class VFS_API TFileTemplate : public vfs::IBaseFile, public ReadType, public WriteType + { + public: + typedef ReadType read_type; + typedef WriteType write_type; + + typedef vfs::TFileTemplate write_file_type; + typedef vfs::TFileTemplate read_file_type; + public: + TFileTemplate(vfs::Path const& fileName) + : vfs::IBaseFile(fileName), ReadType(), WriteType() + {}; + virtual ~TFileTemplate() + {}; + virtual bool implementsWritable() + { + return typeid(write_type) == typeid(vfs::IWritable); + } + virtual bool implementsReadable() + { + return typeid(read_type) == typeid(vfs::IReadable); + } + }; + + /** + * TReadableFile + */ + template + class TReadableFile : public vfs::TFileTemplate + { + typedef vfs::TFileTemplate tBaseClass; + public: + typedef vfs::TReadableFile read_file_type; + + ///////////////////////////////////////// + TReadableFile(vfs::Path const& sFilename) + : tBaseClass(sFilename) + {}; + virtual ~TReadableFile(){}; + + ///////////////////////////////////////// + read_file_type* operator=(vfs::IBaseFile const& t) + { + return read_file_type::cast(t); + } + + ///////////////////////////////////////// + static read_file_type* cast(vfs::IBaseFile* bf) + { + if(bf && bf->implementsReadable()) + { + return static_cast(bf); + } + return NULL; + } + protected: + TReadableFile(); + }; + + /** + * TWritableFile + */ + template + class TWritableFile : public vfs::TFileTemplate + { + typedef vfs::TFileTemplate tBaseClass; + public: + typedef vfs::TWritableFile write_file_type; + + ///////////////////////////////////////// + TWritableFile(vfs::Path const& sFilename) + : tBaseClass(sFilename) + {}; + virtual ~TWritableFile(){}; + + ///////////////////////////////////////// + write_file_type& operator=(vfs::IBaseFile const& t) + { + return *write_file_type::cast(t); + } + + ///////////////////////////////////////// + static write_file_type* cast(IBaseFile* bf) + { + if(bf && bf->implementsWritable()) + { + return static_cast(bf); + } + return NULL; + } + protected: + TWritableFile(); + }; + + + /******************************************************************/ + /******************************************************************/ + + /** + * typedef's + */ + typedef vfs::TReadableFile tReadableFile; + typedef vfs::TWritableFile tWritableFile; + +} // end namespace + +#endif // _VFS_FILE_INTERFACE_H_ diff --git a/ext/VFS/include/vfs/Core/Interface/vfs_iterator_interface.h b/ext/VFS/include/vfs/Core/Interface/vfs_iterator_interface.h new file mode 100644 index 000000000..6c3a86458 --- /dev/null +++ b/ext/VFS/include/vfs/Core/Interface/vfs_iterator_interface.h @@ -0,0 +1,88 @@ +/* + * bfVFS : vfs/Core/Interface/vfs_iterator_interface.h + * - generic interface to iterate over files in locations + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_ITERATOR_INTERFACE_H_ +#define _VFS_ITERATOR_INTERFACE_H_ + +namespace vfs +{ + template + class VFS_API TIterator + { + public: + class IImplementation + { + friend class TIterator; + public: + virtual ~IImplementation() {}; + virtual T* value() = 0; + virtual void next() = 0; + protected: + virtual IImplementation* clone() = 0; + }; + public: + TIterator() : _obj(NULL), _iter_impl(NULL) {}; + TIterator(IImplementation* impl) : _obj(NULL), _iter_impl(impl) + { + if(_iter_impl) + { + _obj = _iter_impl->value(); + } + } + ~TIterator() + { + if(_iter_impl) delete _iter_impl; + }; + TIterator& operator=(TIterator const& t) + { + _obj = t._obj; + _iter_impl = NULL; + if(t._iter_impl) + { + _iter_impl = t._iter_impl->clone(); + } + return *this; + } + ////////////////////////////// + T* value() { return _obj; }; + bool end() { return _obj == NULL; }; + void next() + { + if(_iter_impl) + { + _iter_impl->next(); + _obj = _iter_impl->value(); + if(!_obj) + { + delete _iter_impl; + _iter_impl = NULL; + } + } + } + private: + T* _obj; + IImplementation* _iter_impl; + }; +} + +#endif // _VFS_ITERATOR_INTERFACE_H_ diff --git a/ext/VFS/include/vfs/Core/Interface/vfs_library_interface.h b/ext/VFS/include/vfs/Core/Interface/vfs_library_interface.h new file mode 100644 index 000000000..164e5add2 --- /dev/null +++ b/ext/VFS/include/vfs/Core/Interface/vfs_library_interface.h @@ -0,0 +1,59 @@ +/* + * bfVFS : vfs/Core/Interface/vfs_library_interface.h + * - partially implements Location interface for archive files + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_LIBRARY_INTERFACE_H_ +#define _VFS_LIBRARY_INTERFACE_H_ + +#include + +namespace vfs +{ + class VFS_API ILibrary : public vfs::TLocationTemplate + { + typedef vfs::TLocationTemplate tBaseClass; + public: + ILibrary(vfs::tReadableFile *libraryFile, vfs::Path const& mountPoint, bool ownFile = false); + virtual ~ILibrary(); + + virtual bool init() = 0; + virtual void closeLibrary() = 0; + + virtual void close(tFileType *fileHandle) = 0; + virtual bool openRead(tFileType *fileHandle) = 0; + virtual vfs::size_t read(tFileType *fileHandle, vfs::Byte* data, vfs::size_t bytesToRead) = 0; + + virtual vfs::size_t getReadPosition(tFileType *fileHandle) = 0; + virtual void setReadPosition(tFileType *fileHandle, vfs::size_t positionInBytes) = 0; + virtual void setReadPosition(tFileType *fileHandle, vfs::offset_t offsetInBytes, IBaseFile::ESeekDir seekDir) = 0; + + virtual vfs::size_t getSize(tFileType *pFileHandle) = 0; + + vfs::Path const& getName(); + protected: + bool m_ownLibFile; + vfs::tReadableFile* m_libraryFile; + }; + +} + +#endif // _VFS_LIBRARY_INTERFACE_H_ diff --git a/ext/VFS/include/vfs/Core/Interface/vfs_location_interface.h b/ext/VFS/include/vfs/Core/Interface/vfs_location_interface.h new file mode 100644 index 000000000..158643726 --- /dev/null +++ b/ext/VFS/include/vfs/Core/Interface/vfs_location_interface.h @@ -0,0 +1,160 @@ +/* + * bfVFS : vfs/Core/Interface/vfs_location_interface.h + * - generic Location interface that allows retrieval of a file from a real location + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_LOCATION_INTERFACE_H_ +#define _VFS_LOCATION_INTERFACE_H_ + +#include +#include +#include +#include + +#include +#include +#include + +namespace vfs +{ + class VFS_API IBaseLocation + { + public: + typedef TIterator Iterator; + + virtual ~IBaseLocation() + {}; + + virtual bool implementsWritable() = 0; + virtual bool implementsReadable() = 0; + + virtual vfs::Path const& getPath() = 0; + virtual bool fileExists(vfs::Path const& sFileName) = 0; + virtual vfs::IBaseFile* getFile(vfs::Path const& sFileName) = 0; + + virtual Iterator begin() = 0; + virtual void getSubDirList(std::list& rlSubDirs) = 0; + }; + + /** + * TLocation + */ + template + class VFS_API TLocationTemplate : public IBaseLocation + { + public: + typedef vfs::TLocationTemplate tLocationType; + typedef vfs::TFileTemplate tFileType; + typedef ReadType tReadType; + typedef WriteType tWriteType; + typedef std::list > tListFilesWithPath; + public: + TLocationTemplate(vfs::Path const& mountPoint) + : m_mountPoint(mountPoint) + {}; + virtual ~TLocationTemplate() + {}; + + // has to be virtual , or the types of the caller (not the real object) will be tested + virtual bool implementsWritable() + { + return typeid(tWriteType) == typeid(vfs::IWritable); + } + virtual bool implementsReadable() + { + return typeid(tReadType) == typeid(vfs::IReadable); + } + + vfs::Path const& getMountPoint() + { + return m_mountPoint; + } + + /** + * TLocationTemplate interface + */ + virtual vfs::Path const& getPath() + { + return m_mountPoint; + } + + virtual bool fileExists(vfs::Path const& sFileName) = 0; + virtual vfs::IBaseFile* getFile(vfs::Path const& sFileName) = 0; + virtual tFileType* getFileTyped(vfs::Path const& rFileName) = 0; + protected: + vfs::Path m_mountPoint; + }; + +/**************************************************************************************/ +/**************************************************************************************/ + + template + class TReadLocation : public TLocationTemplate + { + public: + typedef TReadLocation tLocationType; + + static tLocationType* cast(vfs::IBaseLocation* bl) + { + if(bl && bl->implementsReadable()) + { + return static_cast(bl); + } + return NULL; + } + public: + TReadLocation(vfs::Path const& sLocalPath) + : vfs::TLocationTemplate(sLocalPath) + {}; + virtual ~TReadLocation(){}; + }; + + template + class TWriteLocation : public vfs::TLocationTemplate + { + public: + typedef TWriteLocation tLocationType; + + static tLocationType* cast(vfs::IBaseLocation* bl) + { + if(bl && bl->implementsWritable()) + { + return static_cast(bl); + } + return NULL; + } + public: + TWriteLocation(vfs::Path const& sLocalPath) + : vfs::TLocationTemplate(sLocalPath) + {}; + virtual ~TWriteLocation(){}; + }; + + /**************************************************************************************/ + /**************************************************************************************/ + + typedef TReadLocation tReadLocation; + typedef TWriteLocation tWriteLocation; + +} // end namespace + +#endif // _VFS_LOCATION_INTERFACE_H_ + diff --git a/ext/VFS/include/vfs/Core/Location/vfs_directory_tree.h b/ext/VFS/include/vfs/Core/Location/vfs_directory_tree.h new file mode 100644 index 000000000..9109f4b60 --- /dev/null +++ b/ext/VFS/include/vfs/Core/Location/vfs_directory_tree.h @@ -0,0 +1,85 @@ +/* + * bfVFS : vfs/Core/Location/vfs_directory_tree.h + * - class for directories in a File System, implements Directory interface + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_DIRECTORY_H_ +#define _VFS_DIRECTORY_H_ + +#include +#include +#include + +#include +#include + +namespace vfs +{ + + /** + * IDirectory + */ + template + class TDirectoryTree : public vfs::TDirectory + { + typedef std::map::tWriteType>*, vfs::Path::Less> tDirCatalogue; + + class IterImpl; + public: + typedef vfs::TDirectory tBaseClass; + typedef typename tBaseClass::tWriteType tWriteType; + typedef typename tBaseClass::tFileType tFileType; + + typedef TIterator Iterator; + TDirectoryTree(vfs::Path const& sMountPoint, vfs::Path const& sRealPath); + virtual ~TDirectoryTree(); + + bool init(); + + /** + * TDirectory interface + */ + virtual tFileType* addFile(vfs::Path const& sFilename, bool bDeleteOldFile=false); + virtual bool addFile(tFileType* pFile, bool bDeleteOldFile=false); + + virtual bool createSubDirectory(vfs::Path const& sSubDirPath); + virtual bool deleteDirectory(vfs::Path const& sDirPath); + virtual bool deleteFileFromDirectory(vfs::Path const& sFileName); + + /** + * TLocation interface + */ + virtual bool fileExists(vfs::Path const& sFileName); + virtual vfs::IBaseFile* getFile(vfs::Path const& sFileName); + virtual tFileType* getFileTyped(vfs::Path const& sFileName); + virtual void getSubDirList(std::list& rlSubDirs); + + virtual Iterator begin(); + protected: + tDirCatalogue m_catDirs; + }; + + typedef TDirectoryTree CDirectoryTree; + typedef TDirectoryTree CReadOnlyDirectoryTree; + +} // end namespace + +#endif // _VFS_DIRECTORY_H_ diff --git a/ext/VFS/include/vfs/Core/Location/vfs_lib_dir.h b/ext/VFS/include/vfs/Core/Location/vfs_lib_dir.h new file mode 100644 index 000000000..a0472df8e --- /dev/null +++ b/ext/VFS/include/vfs/Core/Location/vfs_lib_dir.h @@ -0,0 +1,66 @@ +/* + * bfVFS : vfs/Core/Location/vfs_lib_dir.h + * - class for readonly (sub)directories in archives/libraries + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_LIB_DIR_H_ +#define _VFS_LIB_DIR_H_ + +#include + +namespace vfs +{ + + class CLibDirectory : public vfs::TDirectory + { + typedef vfs::TDirectory tBaseClass; + typedef std::map tFileCatalogue; + + class IterImpl; + public: + CLibDirectory(vfs::Path const& sLocalPath, vfs::Path const& sRealPath); + virtual ~CLibDirectory(); + + /** + * TDirectory interface + */ + virtual tFileType* addFile(vfs::Path const& filename, bool deleteOldFile=false); + virtual bool addFile(tFileType* file, bool deleteOldFile=false); + virtual bool deleteFileFromDirectory(vfs::Path const& filename); + virtual bool createSubDirectory(vfs::Path const& subDirPath); + virtual bool deleteDirectory(vfs::Path const& dirPath); + + /** + * TLocation interface + */ + virtual bool fileExists(vfs::Path const& filename); + virtual vfs::IBaseFile* getFile(vfs::Path const& filename); + virtual tFileType* getFileTyped(vfs::Path const& filename); + virtual void getSubDirList(std::list& rlSubDirs); + + virtual Iterator begin(); + protected: + tFileCatalogue m_files; + }; + +} // -end- namespace + +#endif // _VFS_LIB_DIR_H_ diff --git a/ext/VFS/include/vfs/Core/Location/vfs_uncompressed_lib_base.h b/ext/VFS/include/vfs/Core/Location/vfs_uncompressed_lib_base.h new file mode 100644 index 000000000..2e7fd5df6 --- /dev/null +++ b/ext/VFS/include/vfs/Core/Location/vfs_uncompressed_lib_base.h @@ -0,0 +1,88 @@ +/* + * bfVFS : vfs/Core/Location/vfs_uncompressed_lib_base.h + * - partially implements library interface for uncompressed archive files + * - initialization is done in format-specific sub-classes + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_UNCOMPRESSED_LIB_BASE_H_ +#define _VFS_UNCOMPRESSED_LIB_BASE_H_ + +#include +#include +#include + +namespace vfs +{ + + class VFS_API CUncompressedLibraryBase : public vfs::ILibrary + { + protected: + typedef std::map*, vfs::Path::Less> tDirCatalogue; + struct SFileData + { + SFileData(vfs::size_t const& fileSize, vfs::size_t const& fileOffset) + : _fileSize(fileSize), _fileOffset(fileOffset), _currentReadPosition(0) + {}; + vfs::size_t _fileSize, _fileOffset, _currentReadPosition; + }; + typedef std::map tFileData; + + class IterImpl; + public: + CUncompressedLibraryBase(vfs::tReadableFile *libraryFile, vfs::Path const& mountPoint, bool ownFile = false); + virtual ~CUncompressedLibraryBase(); + + /** + * TLocation interface + */ + virtual bool fileExists(vfs::Path const& filename); + virtual vfs::IBaseFile* getFile(vfs::Path const& filename); + virtual tFileType* getFileTyped(vfs::Path const& filename); + virtual void getSubDirList(std::list& rlSubDirs); + + /** + * ILibrary interface + */ + virtual bool init() = 0; + virtual void closeLibrary(); + + virtual void close(tFileType *fileHandle); + virtual bool openRead(tFileType *fileHandle); + virtual vfs::size_t read(tFileType *fileHandle, vfs::Byte* data, vfs::size_t bytesToRead); + + virtual vfs::size_t getReadPosition(tFileType *fileHandle); + virtual void setReadPosition(tFileType *fileHandle, vfs::size_t positionInBytes); + virtual void setReadPosition(tFileType *fileHandle, vfs::offset_t offsetInBytes, IBaseFile::ESeekDir seekDir); + + virtual vfs::size_t getSize(tFileType *fileHandle); + + virtual Iterator begin(); + protected: + tDirCatalogue m_dirs; + tFileData m_fileData; + vfs::UInt32 m_numberOfOpenedFiles; + private: + SFileData& _fileDataFromHandle(tFileType* handle); + }; +} // end namespace + +#endif // _VFS_UNCOMPRESSED_LIB_BASE_H_ + diff --git a/ext/VFS/include/vfs/Core/vfs.h b/ext/VFS/include/vfs/Core/vfs.h new file mode 100644 index 000000000..9e52ad656 --- /dev/null +++ b/ext/VFS/include/vfs/Core/vfs.h @@ -0,0 +1,90 @@ +/* + * bfVFS : vfs/Core/vfs.h + * - primary interface for the using program, get files from the VFS internal storage + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_H_ +#define _VFS_H_ + +#include +#include +#include +#include +#include + +#include + +namespace vfs +{ + class CProfileStack; + + class VFS_API CVirtualFileSystem + { + typedef std::map tVFS; + + class CRegularIterator; + class CMatchingIterator; + public: + typedef TIterator Iterator; + + ~CVirtualFileSystem(); + + static CVirtualFileSystem* getVFS(); + static void shutdownVFS(); + + vfs::CProfileStack* getProfileStack(); + + vfs::CVirtualLocation* getVirtualLocation(vfs::Path const& sPath, bool bCreate = false); + bool addLocation(vfs::IBaseLocation* pLocation, vfs::CVirtualProfile *pProfile); + + bool fileExists(vfs::Path const& rLocalFilePath, vfs::CVirtualFile::ESearchFile eSF = vfs::CVirtualFile::SF_TOP ); + bool fileExists(vfs::Path const& rLocalFilePath, std::string const& sProfileName); + + vfs::IBaseFile* getFile(vfs::Path const& rLocalFilePath, vfs::CVirtualFile::ESearchFile eSF = vfs::CVirtualFile::SF_TOP ); + vfs::IBaseFile* getFile(vfs::Path const& rLocalFilePath, vfs::String const& sProfileName); + + vfs::tReadableFile* getReadFile(vfs::Path const& rLocalFilePath, vfs::CVirtualFile::ESearchFile eSF = vfs::CVirtualFile::SF_TOP ); + vfs::tReadableFile* getReadFile(vfs::Path const& rLocalFilePath, vfs::String const& sProfileName); + + vfs::tWritableFile* getWriteFile(vfs::Path const& rLocalFilePath, vfs::CVirtualFile::ESearchFile eSF = vfs::CVirtualFile::SF_TOP ); + vfs::tWritableFile* getWriteFile(vfs::Path const& rLocalFilePath, vfs::String const& sProfileName); + + bool removeFileFromFS(vfs::Path const& sFilePath); + bool removeDirectoryFromFS(vfs::Path const& sDir); + bool createNewFile(vfs::Path const& sFileName); + + Iterator begin(); + Iterator begin(vfs::Path const& sPattern); + private: + vfs::CProfileStack m_oProfileStack; + tVFS m_mapFS; + private: + CVirtualFileSystem(); + static CVirtualFileSystem* m_pSingleton; + }; + + VFS_API bool canWrite(); +} // end namespace + +VFS_API vfs::CVirtualFileSystem* getVFS(); + + +#endif // _VFS_H_ diff --git a/ext/VFS/include/vfs/Core/vfs_debug.h b/ext/VFS/include/vfs/Core/vfs_debug.h new file mode 100644 index 000000000..7cd285ada --- /dev/null +++ b/ext/VFS/include/vfs/Core/vfs_debug.h @@ -0,0 +1,90 @@ + /* + * bfVFS : vfs/Core/vfs_dfebug.h + * - Exception class and throw macros, used to notify the using program of unexpected situations + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_DEBUG_H_ +#define _VFS_DEBUG_H_ + +#include + +#include +#include +#include + +#ifdef _MSC_VER +class VFS_API std::exception; +#endif + +namespace vfs +{ + class VFS_API Exception : public std::exception + { + public: + Exception(vfs::String const& text, vfs::String const& function, int line, const char* file); + Exception(vfs::String const& text, vfs::String const& function, int line, const char* file, std::exception& ex); + + virtual ~Exception() throw(); + + virtual const char* what() const throw(); + + vfs::String getLastEntryString() const; + vfs::String getExceptionString() const; + + struct SEntry + { + vfs::String time; + vfs::String message; + vfs::String function; + int line; + vfs::String file; + }; + typedef std::list CALLSTACK; + CALLSTACK m_CallStack; + }; +} + +#ifdef WIN32 +#define _FUNCTION_FORMAT_ __FUNCTION__ +#else +//#define _FUNCTION_FORMAT_ __FUNCTION__ +#define _FUNCTION_FORMAT_ __PRETTY_FUNCTION__ +#endif + +#define VFS_THROW(message) throw vfs::Exception((message), _FUNCTION_FORMAT_, __LINE__, __FILE__) +#define VFS_RETHROW(message,ex) throw vfs::Exception((message), _FUNCTION_FORMAT_, __LINE__, __FILE__, (ex)) + +#define VFS_THROW_IFF(boolexpr,message) if(!(boolexpr)){VFS_THROW((message));} + +#define VFS_TRYCATCH_RETHROW(expr,message) \ +{ \ + try { (expr); } \ + catch(std::exception &ex){ throw vfs::Exception((message),_FUNCTION_FORMAT_,__LINE__,__FILE__, ex); } \ +} + +#define VFS_IGNOREEXCEPTION(expr, log) \ +{ \ + try{ (expr); } \ + catch(std::exception& ex){ \ + if(log) VFS_LOG_ERROR(ex.what()); } \ +} + +#endif // _VFS_DEBUG_H_ diff --git a/ext/VFS/include/vfs/Core/vfs_file_raii.h b/ext/VFS/include/vfs/Core/vfs_file_raii.h new file mode 100644 index 000000000..4b76f592f --- /dev/null +++ b/ext/VFS/include/vfs/Core/vfs_file_raii.h @@ -0,0 +1,65 @@ +/* + * bfVFS : vfs/Core/vfs_file_raii.h + * - RAII classes to open files for reading/writing + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_FILE_RAII_H_ +#define _VFS_FILE_RAII_H_ + +#include +#include + +namespace vfs +{ + class VFS_API COpenReadFile + { + public: + COpenReadFile(vfs::Path const& sPath, vfs::CVirtualFile::ESearchFile eSF = vfs::CVirtualFile::SF_TOP); + COpenReadFile(vfs::tReadableFile *pFile); + ~COpenReadFile(); + + vfs::tReadableFile* operator->(); + vfs::tReadableFile& file(); + void release(); + private: + vfs::tReadableFile* m_pFile; + }; + + class VFS_API COpenWriteFile + { + public: + COpenWriteFile( vfs::Path const& sPath, + bool bCreate = false, + bool bTruncate = false, + vfs::CVirtualFile::ESearchFile eSF = vfs::CVirtualFile::SF_STOP_ON_WRITABLE_PROFILE); + COpenWriteFile(vfs::tWritableFile *pFile); + ~COpenWriteFile(); + + vfs::tWritableFile* operator->(); + vfs::tWritableFile& file(); + void release(); + private: + vfs::tWritableFile* m_pFile; + }; + +} // end namespace + +#endif // _VFS_FILE_RAII_H_ diff --git a/ext/VFS/include/vfs/Core/vfs_init.h b/ext/VFS/include/vfs/Core/vfs_init.h new file mode 100644 index 000000000..00b978fbe --- /dev/null +++ b/ext/VFS/include/vfs/Core/vfs_init.h @@ -0,0 +1,82 @@ +/* + * bfVFS : vfs/Core/vfs_init.h + * - initialization functions/classes + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_INIT_H_ +#define _VFS_INIT_H_ + +#include +#include +#include + +namespace vfs_init +{ + class VFS_API Location + { + public: + Location(); + + bool m_optional; + vfs::String m_type; + vfs::Path m_path, m_vfs_path; + vfs::Path m_mount_point; + }; + + class VFS_API Profile + { + public: + Profile(); + ~Profile(); + + void addLocation(Location* loc, bool own = false); + + //////////////////////////////////////////////// + typedef std::list > t_locations; + t_locations locations; + + vfs::String m_name; + vfs::Path m_root; + bool m_writable; + }; + + class VFS_API VfsConfig + { + public: + typedef std::list > t_profiles; + ~VfsConfig(); + + t_profiles profiles; + void addProfile(Profile* prof, bool own = false); + void appendConfig(VfsConfig& conf); + }; + + //////////////////////////////////////////////////////////////////////////// + + VFS_API bool initWriteProfile(vfs::CVirtualProfile &rProf); + + VFS_API bool initVirtualFileSystem(vfs::Path const& vfs_ini); + VFS_API bool initVirtualFileSystem(std::list const& vfs_ini_list); + VFS_API bool initVirtualFileSystem(vfs::PropertyContainer& props); + VFS_API bool initVirtualFileSystem(vfs_init::VfsConfig const& conf); +}; + +#endif // _VFS_INIT_H_ diff --git a/ext/VFS/include/vfs/Core/vfs_os_functions.h b/ext/VFS/include/vfs/Core/vfs_os_functions.h new file mode 100644 index 000000000..82e21d489 --- /dev/null +++ b/ext/VFS/include/vfs/Core/vfs_os_functions.h @@ -0,0 +1,107 @@ +/* + * bfVFS : vfs/Core/os_functions.h + * - abstractions for OS dependant code + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_OS_FUNCTIONS_H_ +#define _VFS_OS_FUNCTIONS_H_ + +#ifdef WIN32 + #include +#else + #include + #include + #include + #include +#endif + +#include +#include +#include + +namespace vfs +{ + namespace OS + { + class VFS_API CIterateDirectory + { + public: + enum EFileAttribute + { + FA_DIRECTORY, + FA_FILE + }; + public: + CIterateDirectory(vfs::Path const& sPath, vfs::String const& searchPattern); + ~CIterateDirectory(); + + bool nextFile(vfs::String &fileName, CIterateDirectory::EFileAttribute &attrib); + private: + #ifdef WIN32 + HANDLE fSearchHandle; + union + { + WIN32_FIND_DATAA fFileInfoA; + WIN32_FIND_DATAW fFileInfoW; + }; + #else + struct direct **files; + int count, current_pos; + #endif + bool fFirstRequest; + }; + + class FileAttributes + { + public: + enum Attributes + { + ATTRIB_INVALID = 0, + ATTRIB_ARCHIVE = 1, + ATTRIB_DIRECTORY = 2, + ATTRIB_HIDDEN = 4, + ATTRIB_NORMAL = 8, + ATTRIB_READONLY = 16, + ATTRIB_SYSTEM = 32, + ATTRIB_TEMPORARY = 64, + ATTRIB_COMPRESSED = 128, + ATTRIB_OFFLINE = 256, + }; + bool getFileAttributes(vfs::Path const& sDir, vfs::UInt32& uiAttribs); + }; + + + VFS_API bool checkRealDirectory(vfs::Path const& sDir); + VFS_API bool createRealDirectory(vfs::Path const& sDir); + + VFS_API bool deleteRealFile(vfs::Path const& sDir); + + VFS_API void getExecutablePath(vfs::Path& sDir, vfs::Path& sFile); + VFS_API void getCurrentDirectory(vfs::Path& sDir); + VFS_API void setCurrectDirectory(vfs::Path const& sPath); + + VFS_API bool getEnv(vfs::String const& key, vfs::String& value); + }; // end namespace OS + +} // end namespace vfs + +#endif // _VFS_OS_FUNCTIONS_H_ + diff --git a/ext/VFS/include/vfs/Core/vfs_path.h b/ext/VFS/include/vfs/Core/vfs_path.h new file mode 100644 index 000000000..337dcf551 --- /dev/null +++ b/ext/VFS/include/vfs/Core/vfs_path.h @@ -0,0 +1,99 @@ +/* + * bfVFS : vfs/Core/vfs_path.h + * - Path class, stores and validates a file/directory path string, offers meaningful path operations + * - path comparison functions (operator overloading) + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_PATH_H_ +#define _VFS_PATH_H_ + +#include +#include + +namespace vfs +{ + class VFS_API Path + { + public: + class VFS_API Less{ + public: + bool operator()(vfs::Path const& s1, vfs::Path const& s2) const; + }; + class Equal{ + public: + bool operator()(vfs::Path const& s1, vfs::Path const& s2) const; + }; + public: + Path(); + Path(const char* sPath); + Path(std::string const& sPath); + Path(const wchar_t* sPath); + Path(vfs::String const& sPath); + + const vfs::String::char_t* c_str() const; + const vfs::String::str_t& c_wcs() const; + const vfs::String::str_t& operator()() const; + + std::string to_string() const; + + Path& operator+=(Path const& p); + Path& operator+=(vfs::String const& p); + + bool empty() const; + + vfs::String::size_t length() const; + + void doCheck(); + bool expandEnv(); + + void splitLast(vfs::Path &rsHead, vfs::Path &rsLast) const; + void splitFirst(vfs::Path &rsFirst, vfs::Path &rsTail) const; + + bool extension(vfs::String &sExt) const; + + bool operator==(vfs::Path const& p2); + private: + vfs::String::str_t _path; + struct SeparatorPosition + { + SeparatorPosition() : first(vfs::npos), last(vfs::npos) {} + vfs::size_t first, last; + } _sep; + }; +} + +template<> +VFS_API BuildString& BuildString::add(vfs::Path const& value); +template<> +VFS_API BuildString& BuildString::operator<< (vfs::Path const& value); + +// add only valid Path objects +VFS_API vfs::Path operator+(vfs::Path const& p1, vfs::Path const& p2); + +VFS_API bool operator==(vfs::Path const& p1, vfs::Path const& p2); +// compare path with string (that can be an invalid path) +// use with care as these strings can be different from the internal representation although they seem to be equal +VFS_API bool operator==(vfs::Path const& p1, vfs::String const& p2); +VFS_API bool operator==(vfs::Path const& p1, vfs::String::str_t const& p2); +VFS_API bool operator==(vfs::Path const& p1, const vfs::String::char_t* p2); + +#endif // _VFS_PATH_H_ + diff --git a/ext/VFS/include/vfs/Core/vfs_profile.h b/ext/VFS/include/vfs/Core/vfs_profile.h new file mode 100644 index 000000000..714062f79 --- /dev/null +++ b/ext/VFS/include/vfs/Core/vfs_profile.h @@ -0,0 +1,92 @@ +/* + * bfVFS : vfs/Core/vfs_profile.h + * - Virtual Profile, container for real file system locations or archives + * - Profile Stack, orders profiles in a linear fashion (top-bottom) + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_PROFILE_H_ +#define _VFS_PROFILE_H_ + +#include +#include +#include +#include + +namespace vfs +{ + class VFS_API CVirtualProfile + { + typedef std::map tLocations; + typedef std::set tUniqueLoc; + + class IterImpl; + class FileIterImpl; + public: + typedef TIterator Iterator; + typedef TIterator FileIterator; + + CVirtualProfile(vfs::String const& profile_name, vfs::Path profile_root, bool writable = false); + ~CVirtualProfile(); + + const vfs::String cName; + const vfs::Path cRoot; + const bool cWritable; + + Iterator begin(); + FileIterator files(vfs::Path const& sPattern); + + void addLocation(vfs::IBaseLocation* pLoc); + vfs::IBaseLocation* getLocation(vfs::Path const& sPath) const; + vfs::IBaseFile* getFile(vfs::Path const& sPath) const; + private: + void operator=(vfs::CVirtualProfile const& vprof); + tLocations m_mapLocations; + tUniqueLoc m_setLocations; + }; + + class VFS_API CProfileStack + { + class IterImpl; + public: + typedef vfs::TIterator Iterator; + + CProfileStack(); + ~CProfileStack(); + + CVirtualProfile* getWriteProfile(); + CVirtualProfile* getProfile(vfs::String const& sName) const; + + CVirtualProfile* topProfile() const; + /** + * All files from the top profile will be removed from the VFS and the profile object will be deleted. + */ + bool popProfile(); + void pushProfile(CVirtualProfile* pProfile); + + Iterator begin(); + private: + typedef std::list t_profiles; + t_profiles m_profiles; + }; + +} // end namespace + +#endif diff --git a/ext/VFS/include/vfs/Core/vfs_string.h b/ext/VFS/include/vfs/Core/vfs_string.h new file mode 100644 index 000000000..d3319a9d7 --- /dev/null +++ b/ext/VFS/include/vfs/Core/vfs_string.h @@ -0,0 +1,233 @@ +/* + * bfVFS : vfs/Core/vfs_string.h + * - string class that allows conversions to/from Unicode representation (uses wchar_t internally) + * - comparison, concatenation, stream output class/functions + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_STRING_H_ +#define _VFS_STRING_H_ + +#include +#include +#include + +namespace vfs +{ + // simple UTF8 wrapper, uses utf8 implementation from http://utfcpp.sourceforge.net/ + class VFS_API String + { + friend VFS_API bool operator<(vfs::String const& s1, vfs::String const& s2); + public: + typedef std::wstring str_t; + typedef str_t::value_type char_t; + typedef str_t::value_type* ptr_t; + + typedef str_t::size_type size_t; + //////////////////////////////////////////////////////////////////// + static bool less(const vfs::String::char_t* s1, const vfs::String::char_t* s2); + static bool equal(const vfs::String::char_t* s1, const vfs::String::char_t* s2); + // case sensitive + static bool lessCase(const vfs::String::char_t* s1, const vfs::String::char_t* s2); + static bool equalCase(const vfs::String::char_t* s1, const vfs::String::char_t* s2); + + template + class Op{ + public: + bool operator()(const vfs::String& s1, const vfs::String& s2) const + { + return funName(s1.c_str(),s2.c_str()); + } + }; + typedef Op Less; + typedef Op LessCase; + typedef Op Equal; + typedef Op EqualCase; + public: + String(); + String(const char* str); + String(std::string const& str); + String(const wchar_t* str); + String(std::wstring const& str); + + //////////////////////////////////////////////////////////////////// + static vfs::String::str_t as_utf16(const char* str); + static void as_utf16(const char* str, vfs::String::str_t &str16); + static vfs::String::str_t as_utf16(std::string const& str); + static void as_utf16(std::string const& str, vfs::String::str_t &str16); + // fast conversion without creating an internal copy + static std::string as_utf8(vfs::String const& str); + static std::string as_utf8(std::wstring const& str); + // if 'strlen' is 0, length is determined automatically + static std::string as_utf8(const wchar_t* str, vfs::String::size_t strlength=0); + // + static std::string narrow(wchar_t const* str, vfs::String::size_t length); + static vfs::String::size_t narrow(wchar_t const* src_str, vfs::String::size_t src_len, char* dst_str, vfs::String::size_t dst_len); + static vfs::String::size_t narrow(std::wstring const& src, std::string& dst); + // + static std::wstring widen(char const* str, vfs::String::size_t length); + static vfs::String::size_t widen(char const* src_str, vfs::String::size_t src_len, wchar_t* dst_str, vfs::String::size_t dst_len); + static vfs::String::size_t widen(std::string const& src, std::wstring& dst); + + // convenience method, for the case it should be used in generic code (overloading) + static std::string as_utf8(std::string const& str); + + //////////////////////////////////////////////////////////////////// + // convert string to UTF8 encoding + inline std::string utf8() const { return as_utf8(_str); } + + // returns const reference to copy or compare string + inline std::wstring const& c_wcs() const { return _str; } + + inline const wchar_t* c_str() const { return _str.c_str(); } + + // returns reference to modify string + inline std::wstring& r_wcs() { return _str; } + + + //////////////////////////////////////////////////////////////////// + bool empty() const; + vfs::String::size_t length() const; + + //////////////////////////////////////////////////////////////////// + vfs::String operator+(vfs::String const& str); + vfs::String operator+=(vfs::String const& str); + private: + str_t _str; + }; + +} // namespace vfs + +namespace vfs +{ + VFS_API bool operator<(vfs::String const& s1, vfs::String const& s2); +} + +VFS_API std::wostream& operator<<(std::wostream& out, vfs::String const& str); +VFS_API std::wostream& operator<<(std::wostream& out, vfs::String::str_t const& str); +VFS_API std::wostream& operator<<(std::wostream& out, const vfs::String::char_t* str); + +namespace vfs +{ + // explicit compare + namespace StrCmp + { + // case IN-sensitive + VFS_API bool Equal(const char* s1, const char* s2); + VFS_API bool Equal(std::string const& s1, std::string const& s2); + VFS_API bool Equal(std::string const& s1, const char* s2); + VFS_API bool Equal(const char* s1, std::string const& s2); + // + VFS_API bool Equal(const wchar_t* s1, const wchar_t* s2); + VFS_API bool Equal(std::wstring const& s1, std::wstring const& s2); + VFS_API bool Equal(std::wstring const& s1, const wchar_t* s2); + VFS_API bool Equal(const wchar_t* s1, std::wstring const& s2); + // + VFS_API bool Equal(vfs::String const& s1, vfs::String const& s2); + VFS_API bool Equal(vfs::String const& s1, std::wstring const& s2); + VFS_API bool Equal(std::wstring const& s1, vfs::String const& s2); + VFS_API bool Equal(vfs::String const& s1, const wchar_t* s2); + VFS_API bool Equal(const wchar_t* s1, vfs::String const& s2); + // case Sensitive + VFS_API bool EqualCase(const char* s1, const char* s2); + VFS_API bool EqualCase(std::string const& s1, std::string const& s2); + VFS_API bool EqualCase(std::string const& s1, const char* s2); + VFS_API bool EqualCase(const char* s1, std::string const& s2); + // + VFS_API bool EqualCase(const wchar_t* s1, const wchar_t* s2); + VFS_API bool EqualCase(std::wstring const& s1, std::wstring const& s2); + VFS_API bool EqualCase(std::wstring const& s1, const wchar_t* s2); + VFS_API bool EqualCase(const wchar_t* s1, std::wstring const& s2); + // + VFS_API bool EqualCase(vfs::String const& s1, vfs::String const& s2); + VFS_API bool EqualCase(vfs::String const& s1, std::wstring const& s2); + VFS_API bool EqualCase(std::wstring const& s1, vfs::String const& s2); + VFS_API bool EqualCase(vfs::String const& s1, const wchar_t* s2); + VFS_API bool EqualCase(const wchar_t* s1, vfs::String const& s2); + } + +} // namespace vfs + +class VFS_API BuildString +{ +public: + enum _cget{cget}; + enum _wget{wget}; + BuildString() + {} + + std::string operator<<(_cget) + { + return vfs::String::as_utf8(_strstr.str()); + } + std::wstring operator<<(_wget) + { + return _strstr.str(); + } + + BuildString(BuildString const& bs) + { + _strstr.str(bs._strstr.str()); + } + + template + BuildString(T const& t) + { + add(t); + } + template + BuildString& add(T const& value) + { + _strstr << value; + return *this; + } + template + BuildString& operator<<(T const& value) + { + _strstr << value; + return *this; + } + + vfs::String::str_t get() + { + return _strstr.str(); + } +private: + std::basic_stringstream _strstr; +}; + +typedef BuildString _BS; + +template<> +VFS_API BuildString& BuildString::add(vfs::String const& value); +template<> +VFS_API BuildString& BuildString::add(std::string const& value); +template<> +VFS_API BuildString& BuildString::add(const char* const& value); + +template<> +VFS_API BuildString& BuildString::operator<< (vfs::String const& value); +template<> +VFS_API BuildString& BuildString::operator<< (std::string const& value); +template<> +VFS_API BuildString& BuildString::operator<< (const char* const& value); + + +#endif // _VFS_STRING_H_ diff --git a/ext/VFS/include/vfs/Core/vfs_types.h b/ext/VFS/include/vfs/Core/vfs_types.h new file mode 100644 index 000000000..131b78674 --- /dev/null +++ b/ext/VFS/include/vfs/Core/vfs_types.h @@ -0,0 +1,93 @@ +/* + * bfVFS : vfs/Core/vfs_types.h + * - basic integer types, "incomplete" list of useful constant strings + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_TYPES_H_ +#define _VFS_TYPES_H_ + +#include + +#ifdef __linux__ +# include +#endif + +namespace vfs +{ +#ifdef WIN32 + typedef unsigned __int64 UInt64; + typedef unsigned __int32 UInt32; + typedef unsigned __int16 UInt16; + typedef unsigned __int8 UInt8; + typedef unsigned __int8 UByte; + + typedef __int64 Int64; + typedef __int32 Int32; + typedef __int16 Int16; + typedef __int8 Int8; + typedef __int8 Byte; +#elif __linux__ + typedef uint64_t UInt64; + typedef uint32_t UInt32; + typedef uint16_t UInt16; + typedef uint8_t UInt8; + typedef uint8_t UByte; + + typedef int64_t Int64; + typedef int32_t Int32; + typedef int16_t Int16; + typedef int8_t Int8; + typedef char Byte; +#endif + + typedef ::size_t size_t; + typedef ::off_t offset_t; + + extern const vfs::size_t npos; +} + +namespace vfs +{ + namespace Const + { + inline const vfs::String::str_t EMPTY() { return L""; }; + //inline const vfs::String::char_t EMPTY_CHAR() { return L''; }; + + inline const vfs::String::str_t DOT() { return L"."; }; + inline const vfs::String::char_t DOT_CHAR() { return L'.'; }; + + inline const vfs::String::str_t DOTDOT() { return L".."; }; + inline const vfs::String::str_t DOTSVN() { return L".svn"; }; + + inline const vfs::String::str_t STAR() { return L"*"; }; + inline const vfs::String::str_t DSTAR() { return L"**"; }; + +#ifdef WIN32 + inline const vfs::String::str_t SEPARATOR() { return L"\\"; }; + inline const vfs::String::char_t SEPARATOR_CHAR() { return L'\\'; }; +#else + inline const vfs::String::str_t SEPARATOR() { return L"/"; }; + inline const vfs::String::char_t SEPARATOR_CHAR() { return L'/'; }; +#endif + } +} + +#endif // _VFS_TYPES_H_ diff --git a/ext/VFS/include/vfs/Core/vfs_vfile.h b/ext/VFS/include/vfs/Core/vfs_vfile.h new file mode 100644 index 000000000..23a838096 --- /dev/null +++ b/ext/VFS/include/vfs/Core/vfs_vfile.h @@ -0,0 +1,70 @@ +/* + * bfVFS : vfs/Core/vfs_vfile.h + * - Virtual File, handles access to files from different VFS profiles + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_VFILE_H_ +#define _VFS_VFILE_H_ + +#include +#include +#include + +#define VFILE_BLOCK_CREATE + +namespace vfs +{ + class VFS_API CVirtualFile + { + public: + enum ESearchFile + { + SF_TOP, + SF_FIRST_WRITABLE, + SF_STOP_ON_WRITABLE_PROFILE, + }; + public: + CVirtualFile(); + ~CVirtualFile(); + void destroy(); + static CVirtualFile* create(vfs::Path const& sFilePath, vfs::CProfileStack& rPStack); + + vfs::Path const& path(); + void add(vfs::IBaseFile *pFile, vfs::String sProfileName, bool bReplace = false); + bool remove(vfs::IBaseFile *pFile); + ////////////////////////////////////////////////// + vfs::IBaseFile* file(ESearchFile eSearch); + vfs::IBaseFile* file(vfs::String const& sProfileName); + ////////////////////////////////////////////////// + private: + vfs::Path _path; + vfs::String _top_pname; + vfs::IBaseFile* _top_file; + CProfileStack* _pstack; + private: + vfs::UInt32 _myID; +#ifdef VFILE_BLOCK_CREATE + static ObjBlockAllocator* _vfile_pool; +#endif + }; +} // end namspace + +#endif // _VFS_VFILE_H_ diff --git a/ext/VFS/include/vfs/Core/vfs_vloc.h b/ext/VFS/include/vfs/Core/vfs_vloc.h new file mode 100644 index 000000000..1c4135cad --- /dev/null +++ b/ext/VFS/include/vfs/Core/vfs_vloc.h @@ -0,0 +1,67 @@ +/* + * bfVFS : vfs/Core/vfs_vloc.h + * - Virtual Location, stores Virtual Files + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_VLOC_H_ +#define _VFS_VLOC_H_ + +#include +#include +#include + +#include + +namespace vfs +{ + class CVirtualFile; + + class VFS_API CVirtualLocation + { + class VFileIterator; + typedef std::map tVFiles; + public: + typedef vfs::TIterator Iterator; + + CVirtualLocation(vfs::Path const& sPath); + ~CVirtualLocation(); + + const vfs::Path cPath; + + void setIsExclusive(bool exclusive); + bool getIsExclusive(); + + void addFile(vfs::IBaseFile* pile, vfs::String const& profileName); + vfs::IBaseFile* getFile(vfs::Path const& filename, vfs::String const& profileName = "") const; + vfs::CVirtualFile* getVirtualFile(vfs::Path const& filename); + + bool removeFile(vfs::IBaseFile* file); + + Iterator iterate(); + private: + void operator=(vfs::CVirtualLocation const& vloc); + + bool m_exclusive; + tVFiles m_VFiles; + }; +} // end namespace + +#endif // _VFS_VLOC_H_ diff --git a/ext/VFS/include/vfs/Ext/7z/vfs_7z_library.h b/ext/VFS/include/vfs/Ext/7z/vfs_7z_library.h new file mode 100644 index 000000000..5ba637bf9 --- /dev/null +++ b/ext/VFS/include/vfs/Ext/7z/vfs_7z_library.h @@ -0,0 +1,52 @@ +/* + * bfVFS : vfs/Ext/7z/vfs_7z_library.h + * - implements Library interface, creates library object from uncompressed 7-zip archive files + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_7Z_LIBRARY_H_ +#define _VFS_7Z_LIBRARY_H_ + +#ifdef VFS_WITH_7ZIP + +#include +#include + +namespace vfs +{ + class VFS_API CUncompressed7zLibrary : public vfs::CUncompressedLibraryBase + { + public: + CUncompressed7zLibrary(tReadableFile *libraryFile, + vfs::Path const& mountPoint, + bool ownFile = false, + vfs::ObjBlockAllocator* allocator=NULL); + virtual ~CUncompressed7zLibrary(); + + virtual bool init(); + private: + vfs::ObjBlockAllocator* _allocator; + }; +} // end namespace + +#endif // VFS_WITH_7ZIP + +#endif // _VFS_7Z_LIBRARY_H_ + diff --git a/ext/VFS/include/vfs/Ext/7z/vfs_create_7z_library.h b/ext/VFS/include/vfs/Ext/7z/vfs_create_7z_library.h new file mode 100644 index 000000000..0dfe78730 --- /dev/null +++ b/ext/VFS/include/vfs/Ext/7z/vfs_create_7z_library.h @@ -0,0 +1,89 @@ +/* + * bfVFS : vfs/Ext/7z/vfs_create_7z_library.h + * - writes uncompressed 7z archive file + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_CREATE_7Z_LIBRARY_H_ +#define _VFS_CREATE_7Z_LIBRARY_H_ + +#ifdef VFS_WITH_7ZIP + +#include +#include +#include +#include + +namespace vfs +{ + class VFS_API CCreateUncompressed7zLibrary + { + public: + CCreateUncompressed7zLibrary(); + virtual ~CCreateUncompressed7zLibrary(); + + bool addFile(vfs::tReadableFile* pFile); + + bool writeLibrary(vfs::Path const& sLibName); + bool writeLibrary(vfs::tWritableFile* pFile); + protected: + bool writeSignatureHeader(std::ostream& out); + bool writeNextHeader(std::ostream& out); + bool writeMainStreamsInfo(std::ostream &out); + bool writePackInfo(std::ostream& out); + bool writeUnPackInfo(std::ostream& out); + bool writeSubStreamsInfo(std::ostream& out); + bool writeFolder(std::ostream& out); + bool writeFilesInfo(std::ostream& out); + private: + vfs::size_t writeFileName(std::ostream& out, vfs::String const& filename); + + protected: + vfs::tWritableFile* m_pLibFile; + + struct SFileInfo + { + SFileInfo() + : name(L""), CRC(0), offset(0), size(0), time_creation(0), time_last_access(0), time_write(0) + {}; + ////// + vfs::String::str_t name; + vfs::UInt32 CRC; + vfs::UInt64 offset; + vfs::UInt64 size; + vfs::UInt64 time_creation,time_last_access,time_write; + }; + typedef std::map tDirInfo; + + std::list m_lFileInfo; + tDirInfo m_mapDirInfo; + + // keeping pointers to files to write their contents lates is not enough, + // as the file may only exist for a short time + std::stringstream m_ssFileStream; + + std::stringstream m_ssInfoStream; + }; +} // end namespace + +#endif // VFS_WITH_7ZIP + +#endif // _VFS_CREATE_7Z_LIBRARY_H_ + diff --git a/ext/VFS/include/vfs/Ext/slf/vfs_slf_library.h b/ext/VFS/include/vfs/Ext/slf/vfs_slf_library.h new file mode 100644 index 000000000..db7138afc --- /dev/null +++ b/ext/VFS/include/vfs/Ext/slf/vfs_slf_library.h @@ -0,0 +1,47 @@ +/* + * bfVFS : vfs/Ext/slf/vfs_slf_library.h + * - implements Library interface, creates library object from SLF archive files + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_SLF_LIBRARY_H_ +#define _VFS_SLF_LIBRARY_H_ + +#ifdef VFS_WITH_SLF + +#include + +namespace vfs +{ + class VFS_API CSLFLibrary : public vfs::CUncompressedLibraryBase + { + public: + CSLFLibrary(tReadableFile *pLibraryFile, vfs::Path const& sMountPoint, bool bOwnFile = false); + virtual ~CSLFLibrary(); + + virtual bool init(); + }; + +} // end namespace + +#endif // VFS_WITH_SLF + +#endif // _VFS_SLF_LIBRARY_H_ + diff --git a/ext/VFS/include/vfs/Tools/vfs_allocator.h b/ext/VFS/include/vfs/Tools/vfs_allocator.h new file mode 100644 index 000000000..2cab8ae41 --- /dev/null +++ b/ext/VFS/include/vfs/Tools/vfs_allocator.h @@ -0,0 +1,94 @@ +/* + * bfVFS : vfs/Tools/vfs_allocator.h + * - allocator class to reserve memory blockwise for a larger amount of objects (that have constant size) + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_ALLOCATOR_H_ +#define _VFS_ALLOCATOR_H_ + +#include +#include + +namespace vfs +{ + // needs to be destructible + class VFS_API IAllocator + { + public: + virtual ~IAllocator() {}; + }; + + template + class VFS_API ObjBlockAllocator : public IAllocator + { + public: + ObjBlockAllocator(unsigned int blockSize=1024) + : IAllocator(), BLOCK_SIZE(blockSize), _ObjNew(0) {}; + const unsigned int BLOCK_SIZE; + /// + T* New(unsigned int *ID = NULL) + { + unsigned int block_id = _ObjNew/BLOCK_SIZE; + unsigned int file_id = _ObjNew % BLOCK_SIZE; + if(block_id >= _ObjPool.size()) + { + tBlock* b = new tBlock(); + b->resize(BLOCK_SIZE); + _ObjPool.push_back(b); + } + tBlock* block = _ObjPool[block_id]; + T* obj = &(*block)[file_id]; + if(ID) + { + *ID = _ObjNew; + } + _ObjNew++; + return obj; + } + /// + virtual ~ObjBlockAllocator() + { + for(unsigned int i = 0; i < _ObjPool.size(); ++i) + { + delete _ObjPool[i]; + } + } + private: + void operator=(ObjBlockAllocator const& t); + + typedef std::vector tBlock; + std::vector _ObjPool; + unsigned int _ObjNew; + }; + + + class VFS_API ObjectAllocator + { + public: + static void registerAllocator(IAllocator* allocator); + + static void clear(); + private: + static std::vector _valloc; + }; +} // namespace vfs + +#endif // _VFS_ALLOCATOR_H_ diff --git a/ext/VFS/include/vfs/Tools/vfs_file_logger.h b/ext/VFS/include/vfs/Tools/vfs_file_logger.h new file mode 100644 index 000000000..4480cfc62 --- /dev/null +++ b/ext/VFS/include/vfs/Tools/vfs_file_logger.h @@ -0,0 +1,51 @@ +/* + * bfVFS : vfs/Tools/vfs_file_logger.h + * - implements Logging iterface in the Aspects module by using the vfs::Log class + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_FILE_LOGGER_H_ +#define _VFS_FILE_LOGGER_H_ + +#include +#include +#include +#include + +namespace vfs +{ + class VFS_API FileLogger : public vfs::Aspects::ILogger + { + public: + FileLogger(vfs::Path const& log_file, bool append = false, vfs::Log::EFlushMode flush_mode = vfs::Log::FLUSH_ON_ENDL); + FileLogger(vfs::tWritableFile* file, bool append = false, vfs::Log::EFlushMode flush_mode = vfs::Log::FLUSH_ON_ENDL); + ~FileLogger(); + + virtual void Msg(const wchar_t* msg); + virtual void Msg(const char* msg); + + void Msg(vfs::String const& msg); + private: + Log& m_log; + HPTimer m_clock; + }; +} + +#endif // _VFS_FILE_LOGGER_H_ diff --git a/ext/VFS/include/vfs/Tools/vfs_hp_timer.h b/ext/VFS/include/vfs/Tools/vfs_hp_timer.h new file mode 100644 index 000000000..dd198cf51 --- /dev/null +++ b/ext/VFS/include/vfs/Tools/vfs_hp_timer.h @@ -0,0 +1,61 @@ +/* + * bfVFS : vfs/Tools/vfs_hp_timer.h + * - high performance/precision timer, used by profiler + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_HP_TIMER_ +#define _VFS_HP_TIMER_ + +#include + +#ifdef WIN32 + #include +#elif __linux__ + #include +#endif + +namespace vfs +{ + class VFS_API HPTimer + { + public: + HPTimer(); + ~HPTimer(); + + void startTimer(); + void stopTimer(); + + long long ticks(); + double running(); + + double getElapsedTimeInSeconds(); + protected: + bool is_running; + #ifdef WIN32 + LARGE_INTEGER ticksPerSecond; + LARGE_INTEGER tick,tick2; + #elif __linux__ + timeval t1,t2; + #endif + }; +} + +#endif // _VFS_HP_TIMER_ diff --git a/ext/VFS/include/vfs/Tools/vfs_log.h b/ext/VFS/include/vfs/Tools/vfs_log.h new file mode 100644 index 000000000..20fc21fbd --- /dev/null +++ b/ext/VFS/include/vfs/Tools/vfs_log.h @@ -0,0 +1,164 @@ +/* + * bfVFS : vfs/Tools/vfs_log.h + * - simple file logger + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_LOG_H_ +#define _VFS_LOG_H_ + +#include +#include +#include +#include +#include +#include + +namespace vfs +{ + class VFS_API IRefCountable + { + public: + IRefCountable() : _ref_count(1) {} + virtual ~IRefCountable() {} + + virtual int Reserve() { return Register(); } + virtual int Release() { return UnRegister(); } + virtual int RefCount() { return GetRefCount(); } + + protected: + int Register() { + return ++_ref_count; + } + int UnRegister() { + int tmp_count = --_ref_count; + if(_ref_count <= 0) { + delete this; + } + return tmp_count; + } + int GetRefCount() { + return _ref_count; + } + private: + int _ref_count; + }; + + class VFS_API Log : public IRefCountable + { + public: + enum EFlushMode + { + FLUSH_ON_DELETE, + FLUSH_ON_ENDL, + FLUSH_BUFFER, + FLUSH_IMMEDIATELY, + }; + enum _endl{endl}; + public: + + Log(vfs::Path const& fileName, bool use_vfs_file, bool append = false, EFlushMode flushMode = FLUSH_ON_DELETE); + Log(vfs::tWritableFile* file, bool append = false, EFlushMode flushMode = FLUSH_ON_DELETE); + virtual ~Log(); + + // reimplemented for synchronization + virtual int Reserve(); + virtual int Release(); + virtual int RefCount(); + + // don't explicitely call destroy if you haven't explicitely created the object + void destroy(); + + void releaseFile(); + + static Log* create(vfs::Path const& fileName, bool append = false, EFlushMode flushMode = FLUSH_ON_DELETE); + static Log* create(vfs::tWritableFile* file, bool append = false, EFlushMode flushMode = FLUSH_ON_DELETE); + static void flushReleaseAll(); + static void flushDeleteAll(); + + static vfs::String const& getSharedString(); + static void setSharedString(vfs::String const& str); + + Log& operator<<(vfs::UInt64 const& t); + Log& operator<<(vfs::UInt32 const& t); + Log& operator<<(vfs::UInt16 const& t); + Log& operator<<(vfs::UInt8 const& t); + + Log& operator<<(vfs::Int64 const& t); + Log& operator<<(vfs::Int32 const& t); + Log& operator<<(vfs::Int16 const& t); + Log& operator<<(vfs::Int8 const& t); + +#ifdef _MSC_VER + Log& operator<<(DWORD const& t); +#endif + Log& operator<<(float const& t); + Log& operator<<(double const& t); + + Log& operator<<(const char* t); + Log& operator<<(const wchar_t* t); + Log& operator<<(std::string const& t); + Log& operator<<(std::wstring const& t); + Log& operator<<(vfs::String const& t); + + Log& operator<<(void* const& t); + + Log& operator<<(vfs::Log::_endl const& endl); + + void setAppend(bool append = true); + void setBufferSize(vfs::UInt32 bufferSize); + + + void lock(); + void unlock(); + + void flush(); + EFlushMode flushMode(); + void flushMode(EFlushMode fmode); + + private: + void _test_flush(bool force=false); + + template + Log& pushNumber(T_ const& t) + { + _buffer << toString(t); + _buffer_size += sizeof(T_); + _test_flush(); + return *this; + } + private: + vfs::Path _filename; + vfs::tWritableFile* _file; + bool _own_file; + bool _first_write; + EFlushMode _flush_mode; + bool _append; + ::size_t _buffer_size, _buffer_test_size; + std::stringstream _buffer; + + vfs::Aspects::Mutex _mutex; + private: + static std::list& _logs(); + static vfs::String _shared_id_str; + }; +} // end namespace vfs + +#endif // _VFS_LOG_H_ diff --git a/ext/VFS/include/vfs/Tools/vfs_parser_tools.h b/ext/VFS/include/vfs/Tools/vfs_parser_tools.h new file mode 100644 index 000000000..38bf53b2f --- /dev/null +++ b/ext/VFS/include/vfs/Tools/vfs_parser_tools.h @@ -0,0 +1,80 @@ +/* + * bfVFS : vfs/Tools/vfs_parser_tools.h + * - read file line-wise, + * - split string into tokens, + * - simple pattern matching + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_PARSER_TOOLS_H_ +#define _VFS_PARSER_TOOLS_H_ + +#include +#include + +#include + +namespace vfs +{ + class VFS_API CReadLine + { + static const vfs::size_t BUFFER_SIZE = 1024; + public: + CReadLine(vfs::tReadableFile& rFile); + ~CReadLine(); + + bool fillBuffer(); + bool fromBuffer(std::string& line); + bool getLine(std::string& line); + private: + vfs::Byte _buffer[BUFFER_SIZE+1]; + vfs::tReadableFile& _file; + vfs::size_t _bytes_left; + vfs::size_t _buffer_pos; + vfs::size_t _buffer_last; + bool _eof; + + void operator=(CReadLine const& rl); + }; + + /**************************************************************/ + /**************************************************************/ + + class VFS_API CTokenizer + { + public: + CTokenizer(vfs::String const& str); + ~CTokenizer(); + + bool next(vfs::String& token, vfs::String::char_t delimeter = L','); + private: + const vfs::String m_list; + vfs::String::size_t m_current, m_next; + + void operator=(CTokenizer const& str); + }; + + VFS_API bool matchPattern(vfs::String const& sPattern, vfs::String const& sStr); + VFS_API bool matchPattern(vfs::String const& sPattern, vfs::String::str_t const& sStr); + +} // namespace vfs + +#endif // _VFS_PARSER_TOOLS_H_ + diff --git a/ext/VFS/include/vfs/Tools/vfs_profiler.h b/ext/VFS/include/vfs/Tools/vfs_profiler.h new file mode 100644 index 000000000..55067953c --- /dev/null +++ b/ext/VFS/include/vfs/Tools/vfs_profiler.h @@ -0,0 +1,107 @@ +/* + * bfVFS : vfs/Tools/vfs_profiler.h + * - basic profiler class and macros to measure execution time of code blocks + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_PROFILER_H_ +#define _VFS_PROFILER_H_ + +#include +#include +#include + +#include +#include + +#define DO_PROFILE 1 +#if DO_PROFILE +# define REGISTERMARKER(id,name) static vfs::Profiler::tMarkerID id = vfs::Profiler::getProfiler().registerMarker(name) +# define STARTMARKER(id) (vfs::Profiler::getProfiler().startMarker(id)) +# define STOPMARKER(id,success) (vfs::Profiler::getProfiler().stopMarker(id,success)) + +# define DUMPPROFILERSTATSTOFILE(file) vfs::Profiler::getProfiler().printProfilerState(file) +#else +# define REGISTERMARKER(id,name) +# define STARTMARKER(id) +# define STOPMARKER(id,success) + +# define DUMPPROFILERSTATSTOFILE(file) +#endif + +namespace vfs +{ + class VFS_API Profiler + { + public: + typedef unsigned int tMarkerID; + static Profiler& getProfiler(); + + void clear(); + + tMarkerID registerMarker(const char *marker); + + void startMarker(tMarkerID id); + void stopMarker(tMarkerID id, bool success); + + bool printProfilerState(vfs::Path const& file); + private: + Profiler(); + + struct MARKER + { + MARKER() : call_count(0), success_count(0), fail_count(0), time(0.0) {}; + std::string markername; + unsigned long call_count; + unsigned long success_count; + unsigned long fail_count; + long double time; + HPTimer timer; + }; + std::vector m_vMarker; + unsigned int _nextMarker; + }; + + class VFS_API ProfileMarker + { + public: + ProfileMarker(Profiler::tMarkerID id, bool default_exit=true) + : _id(id), _exit_success(default_exit) + { + STARTMARKER(_id); + } + ~ProfileMarker() + { + STOPMARKER(_id,_exit_success); + } + void exit(bool success) + { + _exit_success = success; + } + private: + Profiler::tMarkerID _id; + bool _exit_success; + }; + + VFS_API void DumpProfileState(vfs::Path const& path); + +} // namespace vfs + +#endif // _VFS_PROFILER_H_ diff --git a/ext/VFS/include/vfs/Tools/vfs_property_container.h b/ext/VFS/include/vfs/Tools/vfs_property_container.h new file mode 100644 index 000000000..2e0b34930 --- /dev/null +++ b/ext/VFS/include/vfs/Tools/vfs_property_container.h @@ -0,0 +1,138 @@ +/* + * bfVFS : vfs/Tools/vfs_property_container.h + * - key-value map with capability to convert values to other types + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_PROPERTY_CONTAINER_H_ +#define _VFS_PROPERTY_CONTAINER_H_ + +#include +#include + +#include +#include +#include +#include +#include + +namespace vfs +{ + class PropertyContainer + { + public: + class TagMap + { + typedef std::map tTagMap; + public: + TagMap(); + vfs::String const& container(vfs::String::char_t* container = NULL); + vfs::String const& section(vfs::String::char_t* section = NULL); + vfs::String const& sectionID(vfs::String::char_t* section_id = NULL); + vfs::String const& key(vfs::String::char_t* key = NULL); + vfs::String const& keyID(vfs::String::char_t* key_id = NULL); + private: + tTagMap _map; + }; + public: + VFS_API PropertyContainer(){}; + VFS_API ~PropertyContainer(){}; + + VFS_API void clearContainer(); + + VFS_API bool initFromIniFile(vfs::Path const& sFileName); + VFS_API bool initFromIniFile(vfs::tReadableFile *pFile); + VFS_API bool writeToIniFile(vfs::Path const& sFileName, bool bCreateNew = false); + + // these functions are not implemented + bool initFromXMLFile(vfs::Path const& sFileName, TagMap& tagmap); + bool writeToXMLFile(vfs::Path const& sFileName, TagMap& tagmap); + + VFS_API void printProperties(std::ostream &out); + + VFS_API bool hasProperty(vfs::String const& sSection, vfs::String const& sKey); + // + VFS_API vfs::String const& getStringProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::String const& sDefaultValue=L""); + VFS_API bool getStringProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::String& sValue, vfs::String const& sDefaultValue=L""); + VFS_API bool getStringProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::String::char_t* sValue, vfs::size_t len, vfs::String const& sDefaultValue=L""); + // + VFS_API vfs::Int64 getIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::Int64 iDefaultValue); + VFS_API vfs::Int64 getIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::Int64 iDefaultValue, vfs::Int64 iMinValue, vfs::Int64 iMaxValue); + // + VFS_API vfs::UInt64 getUIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::UInt64 iDefaultValue); + VFS_API vfs::UInt64 getUIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::UInt64 iDefaultValue, vfs::UInt64 iMinValue, vfs::UInt64 iMaxValue); + // + VFS_API double getFloatProperty(vfs::String const& sSection, vfs::String const& sKey, double fDefaultValue); + VFS_API double getFloatProperty(vfs::String const& sSection, vfs::String const& sKey, double fDefaultValue, double fMinValue, double fMaxValue); + // + VFS_API bool getBoolProperty(vfs::String const& sSection, vfs::String const& sKey, bool bDefaultValue); + // + VFS_API bool getStringListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list &lValueList, vfs::String sDefaultValue); + VFS_API bool getIntListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list &lValueList, vfs::Int64 iDefaultValue); + VFS_API bool getUIntListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list &lValueList, vfs::UInt64 iDefaultValue); + VFS_API bool getFloatListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list &lValueList, double fDefaultValue); + VFS_API bool getBoolListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list &lValueList, bool bDefaultValue); + // + VFS_API void setStringProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::String const& sValue); + // + VFS_API void setIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::Int64 const& iValue); + VFS_API void setUIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::UInt64 const& iValue); + VFS_API void setFloatProperty(vfs::String const& sSection, vfs::String const& sKey, double const& fValue); + VFS_API void setBoolProperty(vfs::String const& sSection, vfs::String const& sKey, bool const& bValue); + // + VFS_API void setStringListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list const& slValue); + VFS_API void setIntListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list const& ilValue); + VFS_API void setUIntListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list const& ilValue); + VFS_API void setFloatListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list const& flValue); + VFS_API void setBoolListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list const& blValue); + private: + enum EOperation + { + Error, Set, Add, + }; + bool extractSection(vfs::String::str_t const& readStr, vfs::size_t startPos, vfs::String::str_t& sSection); + EOperation extractKeyValue(vfs::String::str_t const &readStr, vfs::size_t startPos, vfs::String::str_t& sKey, vfs::String::str_t& sValue); + private: + class Section + { + friend class PropertyContainer; + typedef std::map tProps; + public: + bool has(vfs::String const& key); + bool add(vfs::String const& key, vfs::String const& value); + bool value(vfs::String const& key, vfs::String& value); + vfs::String& value(vfs::String const& key); + void print(std::ostream& out, vfs::String::str_t sPrefix = L""); + void clear(); + private: + tProps mapProps; + }; + typedef std::map tSections; + + bool getValueForKey(vfs::String const& sSection, vfs::String const& sKey, vfs::String &sValue); + + Section& section(vfs::String const& sSection); + + tSections m_mapProps; + }; + +} // namespace vfs + +#endif // _VFS_PROPERTY_CONTAINER_H_ diff --git a/ext/VFS/include/vfs/Tools/vfs_tools.h b/ext/VFS/include/vfs/Tools/vfs_tools.h new file mode 100644 index 000000000..cabda2866 --- /dev/null +++ b/ext/VFS/include/vfs/Tools/vfs_tools.h @@ -0,0 +1,101 @@ +/* + * bfVFS : vfs/Tools/vfs_tools.h + * - simple from/to string (list) conversion functions, + * - remove leading/trailing whitspace characters in a string + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_TOOLS_H_ +#define _VFS_TOOLS_H_ + +#include + +#include +#include + +namespace vfs +{ + template + std::basic_string toString(ValueType const& rVal) + { + std::basic_stringstream tss; + if( !(tss << std::fixed << rVal)) + { + return std::basic_string(); + } + return tss.str(); + } + + template + bool convertTo(vfs::String const& sStr, T_ &rVal) + { + std::wstringstream ss; + ss.str(sStr.c_wcs()); + if(!(ss >> rVal)) + { + return false; + } + return true; + } + + template + vfs::String toStringList(std::list const& rValList) + { + std::wstringstream ss; + typename std::list::const_iterator cit = rValList.begin(); + if(cit != rValList.end()) + { + ss << *cit; + cit++; + for(;cit != rValList.end(); ++cit) + { + ss << L" , " << *cit; + } + } + if(!ss) + { + return L""; + } + return ss.str(); + } + + template<> + VFS_API vfs::String toStringList(std::list const& rValList); + + //////////////////////////////////////////////////////////////////////////////////////////// + + // remove leading and trailing white characters; + template + VFS_API StringType trimString(StringType const& sStr, vfs::size_t iMinPos, vfs::size_t iMaxPos); + + // explicit instantiations : std::string, std::wstring, vfs::String + template<> + VFS_API std::string trimString(std::string const& sStr, vfs::size_t iMinPos, vfs::size_t iMaxPos); + + template<> + VFS_API std::wstring trimString(std::wstring const& sStr, vfs::size_t iMinPos, vfs::size_t iMaxPos); + + template<> + VFS_API vfs::String trimString(vfs::String const& sStr, vfs::size_t iMinPos, vfs::size_t iMaxPos); + + +} // namespace vfs + +#endif // _TOOLS_H_ diff --git a/ext/VFS/include/vfs/vfs_config.h b/ext/VFS/include/vfs/vfs_config.h new file mode 100644 index 000000000..fca4c587d --- /dev/null +++ b/ext/VFS/include/vfs/vfs_config.h @@ -0,0 +1,62 @@ +/* + * bfVFS : vfs_config.h + * - define basic library macros, especially the DLL interface macros + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VFS_CONFIG_H_ +#define _VFS_CONFIG_H_ + +#ifdef WIN32 +#ifdef _MSC_VER +# ifndef PRINT_DLL_INTERFACE_WARNING +# pragma warning ( disable : 4251 ) +# endif +#endif +#endif + +#if defined(_WIN32) && defined(_MSC_VER) + // VFS_STATIC overrides VFS_EXPORT +# ifdef VFS_STATIC +# define VFS_API +# endif + +# ifndef VFS_STATIC +# ifdef VFS_EXPORT +# define VFS_API __declspec(dllexport) +# else +# define VFS_API __declspec(dllimport) +# endif +# endif +#else +# define VFS_API +#endif + +#define VFS_VERSION_MAJOR 1 +#define VFS_VERSION_MINOR 0 +#define VFS_VERSION_PATCH 0 + +#if defined VFS_NO_LOGGING +# define LOG_INFO(x) +# define LOG_WARNING(y) +# define LOG_ERROR(z) +#endif + +#endif // _VFS_CONFIG_H_ diff --git a/ext/VFS/src/Aspects/files.cmake b/ext/VFS/src/Aspects/files.cmake new file mode 100644 index 000000000..e0f754018 --- /dev/null +++ b/ext/VFS/src/Aspects/files.cmake @@ -0,0 +1,19 @@ + +## Aspects + +set(INCLUDE_Aspects + ${MOD_INCLUDE}/vfs_logging.h + ${MOD_INCLUDE}/vfs_settings.h + ${MOD_INCLUDE}/vfs_synchronization.h +) +set(SOURCE_Aspects + ${MOD_SOURCE}/vfs_logging.cpp + ${MOD_SOURCE}/vfs_settings.cpp + ${MOD_SOURCE}/vfs_synchronization.cpp +) +source_group( "Aspects" FILES ${INCLUDE_Aspects} ${SOURCE_Aspects} ) + +set(${mod}_files + ${INCLUDE_Aspects} ${SOURCE_Aspects} + CACHE INTERNAL "" +) diff --git a/ext/VFS/src/Aspects/vfs_logging.cpp b/ext/VFS/src/Aspects/vfs_logging.cpp new file mode 100644 index 000000000..0daafc799 --- /dev/null +++ b/ext/VFS/src/Aspects/vfs_logging.cpp @@ -0,0 +1,159 @@ +/* + * bfVFS : vfs/Aspects/vfs_logging.cpp + * - Logging interface and macros that will be used to report errors/warnings to the using program + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +static vfs::Aspects::ILogger* s_LogDebug = 0; +static vfs::Aspects::ILogger* s_LogInfo = 0; +static vfs::Aspects::ILogger* s_LogWarning = 0; +static vfs::Aspects::ILogger* s_LogError = 0; + +void vfs::Aspects::setLogger( ILogger* info_logger, ILogger* warning_logger, ILogger* error_logger, ILogger* debug_logger ) +{ + setLogger(LOG_INFO, info_logger); + setLogger(LOG_WARNING, warning_logger); + setLogger(LOG_ERROR, error_logger); + setLogger(LOG_DEBUG, debug_logger); +} + + +void vfs::Aspects::setLogger(vfs::Aspects::LogType type, vfs::Aspects::ILogger* logger) +{ + switch (type) + { + case vfs::Aspects::LOG_INFO : + s_LogInfo = logger; + break; + case vfs::Aspects::LOG_WARNING : + s_LogWarning = logger; + break; + case vfs::Aspects::LOG_ERROR : + s_LogError = logger; + break; + case vfs::Aspects::LOG_DEBUG : + s_LogDebug = logger; + break; + } +} + +vfs::Aspects::ILogger* vfs::Aspects::getLogger(vfs::Aspects::LogType type) +{ + switch (type) + { + case vfs::Aspects::LOG_DEBUG : return s_LogDebug; + case vfs::Aspects::LOG_INFO : return s_LogInfo; + case vfs::Aspects::LOG_WARNING : return s_LogWarning; + case vfs::Aspects::LOG_ERROR : return s_LogError; + } + return 0; +} + +void vfs::Aspects::Debug(vfs::String const& msg) +{ + if(s_LogDebug) + { + s_LogDebug->Msg(msg.c_str()); + } +} +void vfs::Aspects::Debug(const wchar_t* msg) +{ + if(s_LogDebug) + { + s_LogDebug->Msg(msg); + } +} +void vfs::Aspects::Debug(const char* msg) +{ + if(s_LogDebug) + { + s_LogDebug->Msg(msg); + } +} + + +void vfs::Aspects::Info(vfs::String const& msg) +{ + if(s_LogInfo) + { + s_LogInfo->Msg(msg.c_str()); + } +} +void vfs::Aspects::Info(const wchar_t* msg) +{ + if(s_LogInfo) + { + s_LogInfo->Msg(msg); + } +} +void vfs::Aspects::Info(const char* msg) +{ + if(s_LogInfo) + { + s_LogInfo->Msg(msg); + } +} + +void vfs::Aspects::Warning(vfs::String const& msg) +{ + if(s_LogWarning) + { + s_LogWarning->Msg(msg.c_str()); + } +} +void vfs::Aspects::Warning(const wchar_t* msg) +{ + if(s_LogWarning) + { + s_LogWarning->Msg(msg); + } +} +void vfs::Aspects::Warning(const char* msg) +{ + if(s_LogWarning) + { + s_LogWarning->Msg(msg); + } +} + +void vfs::Aspects::Error(vfs::String const& msg) +{ + if(s_LogError) + { + s_LogError->Msg(msg.c_str()); + } +} +void vfs::Aspects::Error(const wchar_t* msg) +{ + if(s_LogError) + { + s_LogError->Msg(msg); + } +} +void vfs::Aspects::Error(const char* msg) +{ + if(s_LogError) + { + s_LogError->Msg(msg); + } +} diff --git a/ext/VFS/src/Aspects/vfs_settings.cpp b/ext/VFS/src/Aspects/vfs_settings.cpp new file mode 100644 index 000000000..c5a3ce5e2 --- /dev/null +++ b/ext/VFS/src/Aspects/vfs_settings.cpp @@ -0,0 +1,37 @@ +/* + * bfVFS : vfs/Aspects/vfs_settings.cpp + * - library runtime settings, + * - e.g., to use Unicode strings or regular for file names + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +static bool s_UseUnicode = true; + +void vfs::Settings::setUseUnicode(bool useUnicode) +{ + s_UseUnicode = useUnicode; +} + +bool vfs::Settings::getUseUnicode() +{ + return s_UseUnicode; +} diff --git a/ext/VFS/src/Aspects/vfs_synchronization.cpp b/ext/VFS/src/Aspects/vfs_synchronization.cpp new file mode 100644 index 000000000..e564f65dc --- /dev/null +++ b/ext/VFS/src/Aspects/vfs_synchronization.cpp @@ -0,0 +1,72 @@ +/* + * bfVFS : vfs/Aspects/vfs_synchronization.cpp + * - Interface for Mutexes and Locks, implementation can or has to be provided by the using program + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +static vfs::Aspects::IMutexFactory* s_mutex_factory = 0; + +void vfs::Aspects::setMutexFactory(IMutexFactory* mutex_factory) +{ + s_mutex_factory = mutex_factory; +} +vfs::Aspects::IMutexFactory* vfs::Aspects::getMutexFactory() +{ + return s_mutex_factory; +} + + +vfs::Aspects::Mutex::Mutex() : _locked(0) +{ + if(s_mutex_factory) + { + _mutex = s_mutex_factory->createMutex(); + } + else + { + _mutex = new IMutex(); + } +} + +vfs::Aspects::Mutex::~Mutex() +{ + if(_mutex) + { + _mutex->unlock(); + delete _mutex; + } +} + +void vfs::Aspects::Mutex::lock() +{ + _mutex->lock(); + _locked++; +} + +void vfs::Aspects::Mutex::unlock() +{ + if(_locked > 0) + { + _locked--; + _mutex->unlock(); + } +} diff --git a/ext/VFS/src/CMakeLists.txt b/ext/VFS/src/CMakeLists.txt new file mode 100644 index 000000000..871ed5098 --- /dev/null +++ b/ext/VFS/src/CMakeLists.txt @@ -0,0 +1,77 @@ +#################################################### + +set(INCLUDE_bfvfs_config + ${BFVFS_INCLUDE_DIR}/vfs/vfs_config.h +) +source_group("" FILES ${INCLUDE_bfvfs_config}) + +set(BFVFS_files ${INCLUDE_bfvfs_config}) + + +## +## iterate over bfVFS modules and add files +## +set(BFVFS_MODULES "Aspects" "Core" "Ext" "Tools") + +foreach(mod ${BFVFS_MODULES}) + set( MOD_INCLUDE ${BFVFS_INCLUDE_DIR}/vfs/${mod} ) + set( MOD_SOURCE ${mod} ) + + include( ${mod}/files.cmake ) + set(BFVFS_files ${BFVFS_files} ${${mod}_files}) +endforeach() + +if(BFVFS_WITH_7ZIP) + set(DEFINITIONS ${DEFINITIONS} "-DVFS_WITH_7ZIP") + add_definitions(-DVFS_WITH_7ZIP ${BFVFS_7ZIP_DEFINITIONS}) + include_directories(${BFVFS_7ZIP_DIR}/src) +endif() + +if(BFVFS_WITH_SLF) + set(DEFINITIONS ${DEFINITIONS} "-DVFS_WITH_SLF") + add_definitions(-DVFS_WITH_SLF) +endif() + +#################################################### + +if(WIN32) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +if(BUILD_BFVFS_SHARED) + set(BUILD_SHARED_LIBS ON) + add_definitions(-DVFS_EXPORT) + set(DEFINITIONS ${DEFINITIONS} -DVFS_IMPORT) +else() + set(BUILD_SHARED_LIBS OFF) + add_definitions(-DVFS_STATIC) + set(DEFINITIONS ${DEFINITIONS} -DVFS_STATIC) +endif() + +set(BFVFS_TARGET "bfVFS" CACHE INTERNAL "") +add_library( ${BFVFS_TARGET} ${BFVFS_files} ) + +set_property( + TARGET ${BFVFS_TARGET} + PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${BFVFS_LIBRARY_DIRS} +) +set_property( + TARGET ${BFVFS_TARGET} + PROPERTY LIBRARY_OUTPUT_DIRECTORY ${BFVFS_LIBRARY_DIRS} +) +set_property( + TARGET ${BFVFS_TARGET} + PROPERTY RUNTIME_OUTPUT_DIRECTORY ${BFVFS_RUNTIME_DIRS} +) + +if(BUILD_BFVFS_SHARED) + if(MINGW) + set(CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} "-enable-auto-import") + endif() + + if(BFVFS_WITH_7ZIP) + target_link_libraries(${BFVFS_TARGET} ${BFVFS_7ZIP_TARGET}) + endif() +endif() + +set(BFVFS_VFS_DEFINITIONS ${DEFINITIONS} CACHE INTERNAL "") diff --git a/ext/VFS/src/Core/File/vfs_buffer_file.cpp b/ext/VFS/src/Core/File/vfs_buffer_file.cpp new file mode 100644 index 000000000..81857b046 --- /dev/null +++ b/ext/VFS/src/Core/File/vfs_buffer_file.cpp @@ -0,0 +1,264 @@ +/* + * bfVFS : vfs/Core/File/vfs_buffer_file.cpp + * - Buffer in RAM, implements File interface to unify usage of file and memory + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include + +#define ERROR_FILE(msg) (_BS(L"[") << this->getPath() << L"] - " << (msg) << _BS::wget) + +#ifdef _DEBUG + #define IS_FILE_VALID() VFS_THROW_IFF( m_buffer.good(), ERROR_FILE(L"invalid file object") ); +#else + #define IS_FILE_VALID() VFS_THROW_IFF( m_buffer.good(), ERROR_FILE(L"invalid file object") ); +#endif + +static inline std::ios::seekdir _seekDir(vfs::IBaseFile::ESeekDir seekDir) +{ + if(seekDir == vfs::IBaseFile::SD_BEGIN) + { + return std::ios::beg; + } + else if(seekDir == vfs::IBaseFile::SD_CURRENT) + { + return std::ios::cur; + } + else if(seekDir == vfs::IBaseFile::SD_END) + { + return std::ios::end; + } + VFS_THROW(_BS(L"Unknown seek direction [") << seekDir << L"]" << _BS::wget); +} + +/////////////////////////////////////////////////// + +vfs::CBufferFile::CBufferFile() +: tBaseClass(vfs::Path()), m_isOpen_read(false), m_isOpen_write(false) +{ + m_buffer.str(""); +} + +vfs::CBufferFile::CBufferFile(vfs::Path const& fileName) +: tBaseClass(fileName), m_isOpen_read(false), m_isOpen_write(false) +{ + m_buffer.str(""); +} + +vfs::CBufferFile::~CBufferFile() +{ + m_buffer.str(""); + m_buffer.clear(); +} + +vfs::FileAttributes vfs::CBufferFile::getAttributes() +{ + return vfs::FileAttributes(vfs::FileAttributes::ATTRIB_NORMAL, vfs::FileAttributes::LT_NONE); +} + +void vfs::CBufferFile::close() +{ + m_buffer.clear(); + m_isOpen_read = false; + m_isOpen_write = false; + IS_FILE_VALID(); +} +vfs::size_t vfs::CBufferFile::getSize() +{ + IS_FILE_VALID(); + + std::streampos size = 0; + if(!m_buffer.str().empty()) + { + std::streampos current_position = m_buffer.tellg(); + m_buffer.seekg(0,std::ios::end); + size = m_buffer.tellg(); + m_buffer.seekg(current_position,std::ios::beg); + } + + IS_FILE_VALID(); + return (vfs::size_t)size; +} + +bool vfs::CBufferFile::isOpenRead() +{ + return m_isOpen_read; +} + +bool vfs::CBufferFile::openRead() +{ + if(!m_buffer.good()) + { + return false; + } + return m_isOpen_read = true; +} +vfs::size_t vfs::CBufferFile::read(vfs::Byte* data, vfs::size_t bytesToRead) +{ + if(!m_buffer.eof()) + { + IS_FILE_VALID(); + VFS_THROW_IFF(m_isOpen_read || this->openRead(), ERROR_FILE(L"open error")); + + m_buffer.read(static_cast(data), bytesToRead); + std::streamsize bytesRead = m_buffer.gcount(); + + VFS_THROW_IFF( m_buffer.good() || m_buffer.eof(), ERROR_FILE(L"read error") ); + return (vfs::size_t)bytesRead; + } + return 0; +} + +vfs::size_t vfs::CBufferFile::getReadPosition() +{ + IS_FILE_VALID(); + VFS_THROW_IFF(m_isOpen_read || this->openRead(), ERROR_FILE(L"open error")); + + return (vfs::size_t)m_buffer.tellg(); +} + +void vfs::CBufferFile::setReadPosition(vfs::size_t positionInBytes) +{ + IS_FILE_VALID(); + VFS_THROW_IFF( m_isOpen_read || this->openRead(), ERROR_FILE(L"open error") ); + + m_buffer.seekg((std::streamoff)positionInBytes); + + IS_FILE_VALID(); +} +void vfs::CBufferFile::setReadPosition(vfs::offset_t offsetInBytes, IBaseFile::ESeekDir seekDir) +{ + IS_FILE_VALID(); + VFS_THROW_IFF( m_isOpen_read || this->openRead(), ERROR_FILE(L"open error") ); + + std::ios::seekdir ioSeekDir; + VFS_TRYCATCH_RETHROW(ioSeekDir = _seekDir(seekDir), ERROR_FILE(L"seek error")); + m_buffer.seekg(offsetInBytes, ioSeekDir); + + IS_FILE_VALID(); +} + +bool vfs::CBufferFile::isOpenWrite() +{ + return m_isOpen_write; +} + +bool vfs::CBufferFile::openWrite(bool bCreateWhenNotExist, bool bTruncate) +{ + if( !m_buffer.good() ) + return false; + if( m_isOpen_write ) + return true; + + if(bTruncate) + { + m_buffer.str(""); + m_buffer.clear(); + } + m_isOpen_write = m_buffer.good(); + return m_isOpen_write; +} + +vfs::size_t vfs::CBufferFile::write(const vfs::Byte* data, vfs::size_t bytesToWrite) +{ + IS_FILE_VALID(); + VFS_THROW_IFF( m_isOpen_write || this->openWrite(), ERROR_FILE(L"open error") ); + + std::streampos start = 0; + if(!m_buffer.str().empty()) + { + start = m_buffer.tellp(); + } + VFS_THROW_IFF( m_buffer.write(data, bytesToWrite), ERROR_FILE(L"write error") ); + std::streampos bytesWritten = m_buffer.tellp() - start; + + IS_FILE_VALID(); + + return (vfs::size_t)bytesWritten; +} + +vfs::size_t vfs::CBufferFile::getWritePosition() +{ + IS_FILE_VALID(); + VFS_THROW_IFF( m_isOpen_write || this->openWrite(), ERROR_FILE(L"open error") ); + + return (vfs::size_t)m_buffer.tellp(); +} + +void vfs::CBufferFile::setWritePosition(vfs::size_t positionInBytes) +{ + IS_FILE_VALID(); + VFS_THROW_IFF( m_isOpen_write || this->openWrite(), ERROR_FILE(L"open error") ); + + m_buffer.seekp((std::streamoff)positionInBytes); + + IS_FILE_VALID(); +} + +void vfs::CBufferFile::setWritePosition(vfs::offset_t offsetInBytes, IBaseFile::ESeekDir seekDir) +{ + IS_FILE_VALID(); + VFS_THROW_IFF( m_isOpen_write || this->openWrite(), ERROR_FILE(L"open error") ); + + std::ios::seekdir ioSeekDir; + VFS_TRYCATCH_RETHROW( ioSeekDir = _seekDir(seekDir), ERROR_FILE(L"seek error") ); + m_buffer.seekp(offsetInBytes, ioSeekDir); + + IS_FILE_VALID(); +} + +void vfs::CBufferFile::copyToBuffer(vfs::tReadableFile& rFile) +{ + try + { + bool needToClose = !rFile.isOpenRead(); + vfs::COpenReadFile readfile(&rFile); + if(!needToClose) + { + readfile.release(); + } + + typedef std::vector tByteVector; + + vfs::size_t size = rFile.getSize(); + if(size > 0) + { + tByteVector vBuffer(size); + + rFile.read(&vBuffer[0], size); + this->write(&vBuffer[0], size); + } + } + catch(std::exception& ex) + { + VFS_RETHROW(ERROR_FILE(L""), ex); + } +} + + +bool vfs::CBufferFile::deleteFile() +{ + m_buffer.clear(); + m_buffer.str(""); + return m_buffer.good(); +} diff --git a/ext/VFS/src/Core/File/vfs_dir_file.cpp b/ext/VFS/src/Core/File/vfs_dir_file.cpp new file mode 100644 index 000000000..2a4ce56af --- /dev/null +++ b/ext/VFS/src/Core/File/vfs_dir_file.cpp @@ -0,0 +1,156 @@ +/* + * bfVFS : vfs/Core/File/vfs_dir_file.cpp + * - read/read-write files for usage in vfs locations (directories) + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include + +vfs::CReadOnlyDirFile::CReadOnlyDirFile(vfs::Path const& filename, tLocation *directory) +: vfs::CReadOnlyFile(filename), _location(directory) +{ +} + +vfs::CReadOnlyDirFile::~CReadOnlyDirFile() +{ +} + +vfs::Path vfs::CReadOnlyDirFile::getPath() +{ + if(_location) + { + return _location->getPath() + m_filename; + } + else + { + return m_filename; + } +} + +bool vfs::CReadOnlyDirFile::_getRealPath(vfs::Path& path) +{ + if(_location) + { + path = _location->getRealPath() + m_filename; + return true; + } + return false; +} + + +vfs::FileAttributes vfs::CReadOnlyDirFile::getAttributes() +{ + vfs::FileAttributes _attribs = vfs::CReadOnlyFile::getAttributes(); + + vfs::UInt32 attr = _attribs.getAttrib(); + attr |= vfs::FileAttributes::ATTRIB_READONLY; + + return vfs::FileAttributes(attr, vfs::FileAttributes::LT_READONLY_DIRECTORY); +} + +bool vfs::CReadOnlyDirFile::openRead() +{ + vfs::Path filename; + if(!_getRealPath(filename)) + { + return false; + } + return _internalOpenRead(filename); +} + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// + +vfs::CDirFile::CDirFile(vfs::Path const& filename, tLocation *directory) +: CFile(filename), _location(directory) +{ +} + +vfs::CDirFile::~CDirFile() +{ +} + +vfs::Path vfs::CDirFile::getPath() +{ + if(_location) + { + return _location->getPath() + m_filename; + } + else + { + return m_filename; + } +} + +bool vfs::CDirFile::deleteFile() +{ + this->close(); + vfs::Path fname; + if(_getRealPath(fname)) + { + return vfs::OS::deleteRealFile(fname); + } + return false; +} + + +bool vfs::CDirFile::_getRealPath(vfs::Path& path) +{ + if(_location) + { + path = _location->getRealPath() + m_filename; + return true; + } + return false; +} + + +vfs::FileAttributes vfs::CDirFile::getAttributes() +{ + vfs::FileAttributes _attribs = vfs::CFile::getAttributes(); + + return vfs::FileAttributes(_attribs.getAttrib(), vfs::FileAttributes::LT_DIRECTORY); +} + +bool vfs::CDirFile::openRead() +{ + vfs::Path filename; + if(!_getRealPath(filename)) + { + return false; + } + return _internalOpenRead(filename); +} + +bool vfs::CDirFile::openWrite(bool createWhenNotExist, bool truncate) +{ + vfs::Path filename; + if(!_getRealPath(filename)) + { + return false; + } + return _internalOpenWrite(filename, createWhenNotExist, truncate); +} + + diff --git a/ext/VFS/src/Core/File/vfs_file.cpp b/ext/VFS/src/Core/File/vfs_file.cpp new file mode 100644 index 000000000..6c46cc4ff --- /dev/null +++ b/ext/VFS/src/Core/File/vfs_file.cpp @@ -0,0 +1,619 @@ +/* + * bfVFS : vfs/Core/File/vfs_file.cpp + * - File with read/read-write access + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include + +#include + +#define ERROR_FILE(msg) (_BS(L"[") << this->getPath() << L"] - " << (msg) << _BS::wget) + +static inline bool hasAttrib(vfs::UInt32 const& attrib, vfs::UInt32 Attribs) +{ + return attrib == (attrib & Attribs); +} + +static inline void copyAttributes(vfs::UInt32 osFileAttributes, vfs::UInt32& vfsFileAttributes) +{ + if(vfs::OS::FileAttributes::ATTRIB_ARCHIVE == (vfs::OS::FileAttributes::ATTRIB_ARCHIVE & osFileAttributes)) + { + vfsFileAttributes |= vfs::FileAttributes::ATTRIB_ARCHIVE; + } + if(vfs::OS::FileAttributes::ATTRIB_COMPRESSED == (vfs::OS::FileAttributes::ATTRIB_COMPRESSED & osFileAttributes)) + { + vfsFileAttributes |= vfs::FileAttributes::ATTRIB_COMPRESSED; + } + if(vfs::OS::FileAttributes::ATTRIB_DIRECTORY == (vfs::OS::FileAttributes::ATTRIB_DIRECTORY & osFileAttributes)) + { + vfsFileAttributes |= vfs::FileAttributes::ATTRIB_DIRECTORY; + } + if(vfs::OS::FileAttributes::ATTRIB_HIDDEN == (vfs::OS::FileAttributes::ATTRIB_HIDDEN & osFileAttributes)) + { + vfsFileAttributes |= vfs::FileAttributes::ATTRIB_HIDDEN; + } + if(vfs::OS::FileAttributes::ATTRIB_NORMAL == (vfs::OS::FileAttributes::ATTRIB_NORMAL & osFileAttributes)) + { + vfsFileAttributes |= vfs::FileAttributes::ATTRIB_NORMAL; + } + if(vfs::OS::FileAttributes::ATTRIB_OFFLINE == (vfs::OS::FileAttributes::ATTRIB_OFFLINE & osFileAttributes)) + { + vfsFileAttributes |= vfs::FileAttributes::ATTRIB_OFFLINE; + } + if(vfs::OS::FileAttributes::ATTRIB_READONLY == (vfs::OS::FileAttributes::ATTRIB_READONLY & osFileAttributes)) + { + vfsFileAttributes |= vfs::FileAttributes::ATTRIB_READONLY; + } + if(vfs::OS::FileAttributes::ATTRIB_SYSTEM == (vfs::OS::FileAttributes::ATTRIB_SYSTEM & osFileAttributes)) + { + vfsFileAttributes |= vfs::FileAttributes::ATTRIB_SYSTEM; + } + if(vfs::OS::FileAttributes::ATTRIB_TEMPORARY == (vfs::OS::FileAttributes::ATTRIB_TEMPORARY & osFileAttributes)) + { + vfsFileAttributes |= vfs::FileAttributes::ATTRIB_TEMPORARY; + } +} + +#ifdef WIN32 + static inline DWORD _seekDir(vfs::IBaseFile::ESeekDir seekDir) + { + if(seekDir == vfs::IBaseFile::SD_BEGIN) + { + return FILE_BEGIN; + } + else if(seekDir == vfs::IBaseFile::SD_CURRENT) + { + return FILE_CURRENT; + } + else if(seekDir == vfs::IBaseFile::SD_END) + { + return FILE_END; + } + VFS_THROW(_BS(L"Unknown seek direction [") << seekDir << L"]" << _BS::wget); + } +#else + static inline int _seekDir(vfs::IBaseFile::ESeekDir seekDir) + { + if(seekDir == vfs::IBaseFile::SD_BEGIN) + { + return SEEK_SET; + } + else if(seekDir == vfs::IBaseFile::SD_CURRENT) + { + return SEEK_CUR; + } + else if(seekDir == vfs::IBaseFile::SD_END) + { + return SEEK_END; + } + VFS_THROW(_BS(L"Unknown seek direction [") << seekDir << L"]" << _BS::wget); + } +#endif + +template +vfs::TFile::TFile(vfs::Path const& filename) +: tBaseClass(filename), m_isOpen_read(false), m_file(0) +{ +} + +template +vfs::TFile::~TFile() +{ + //VFS_LOCK(m_mutex); +#ifndef WIN32 + if(m_file)clearerr(m_file); +#endif + if(m_isOpen_read) + { + this->close(); + } +} + +template +void vfs::TFile::close() +{ + //VFS_LOCK(m_mutex); + if(m_file) + { +#ifdef WIN32 + if(!CloseHandle(m_file)) + { + DWORD err = GetLastError(); + if(err != NO_ERROR) + { + VFS_THROW( ERROR_FILE(_BS(L"Could not close file : ") << err << _BS::wget) ); + } + } +#else + //clearerr(m_file); + fflush(m_file); + int error = fclose(m_file); + if(error) + { + //const char* error_str = perror(error); + VFS_THROW( ERROR_FILE(_BS(L"Could not close file : ") << error << _BS::wget) ); + } +#endif + m_file = NULL; + } + m_isOpen_read = false; +} + +template +vfs::FileAttributes vfs::TFile::getAttributes() +{ + //VFS_LOCK(m_mutex); + vfs::Path fullpath; + VFS_THROW_IFF(this->_getRealPath(fullpath), ERROR_FILE(L"")); + + vfs::UInt32 osFileAttributes = 0; + vfs::OS::FileAttributes fa; + VFS_THROW_IFF( fa.getFileAttributes(fullpath, osFileAttributes), ERROR_FILE(L"Could not read file attributes") ); + + vfs::UInt32 _attribs = vfs::FileAttributes::ATTRIB_INVALID; + copyAttributes(osFileAttributes, _attribs); + + if(!this->implementsWritable()) + { + _attribs &= ~vfs::FileAttributes::ATTRIB_NORMAL; + _attribs |= vfs::FileAttributes::ATTRIB_READONLY; + } + + return vfs::FileAttributes(_attribs, vfs::FileAttributes::LT_NONE); +} + +template +bool vfs::TFile::isOpenRead() +{ + //VFS_LOCK(m_mutex); + return m_isOpen_read; +} + +template +bool vfs::TFile::_internalOpenRead(vfs::Path const& path) +{ + //VFS_LOCK(m_mutex); + if( m_isOpen_read ) + return true; +#ifdef WIN32 + m_file = vfs::Settings::getUseUnicode() ? + CreateFileW(path.c_str(),GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL) : + CreateFileA(vfs::String::narrow(path.c_str(),path.length()).c_str(),GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + DWORD err = GetLastError(); + if(err != NO_ERROR && err != ERROR_ALREADY_EXISTS) + { + VFS_LOG_ERROR( ERROR_FILE(_BS(L"Error when opening file : ") << err << _BS::wget) ); + return m_isOpen_read = false; + } + return m_isOpen_read = true; +#else + m_file = fopen(path.to_string().c_str(), "r"); + return m_isOpen_read = (m_file != NULL); +#endif +} + +template +bool vfs::TFile::openRead() +{ + //VFS_LOCK(m_mutex); + return _internalOpenRead(this->m_filename); +} + +template +vfs::size_t vfs::TFile::read(vfs::Byte* pData, vfs::size_t bytesToRead) +{ + //VFS_LOCK(m_mutex); + VFS_THROW_IFF( m_isOpen_read, ERROR_FILE(L"file not opened") ); +#ifdef WIN32 + DWORD has_read = 0; + if(!ReadFile(m_file, pData, bytesToRead, &has_read, NULL)) + { + DWORD err = GetLastError(); + if(err != NO_ERROR && err != ERROR_HANDLE_EOF) + { + VFS_THROW( ERROR_FILE(_BS(L"read error : ") << err << _BS::wget) ); + } + } +#else + size_t has_read = fread(pData,1,bytesToRead,m_file); + if(has_read != bytesToRead) + { + int error = ferror(m_file); + if(error) + { + VFS_THROW( ERROR_FILE(_BS(L"read error : ") << error << _BS::wget) ); + } + clearerr(m_file); + } +#endif + return has_read; +} + +template +vfs::size_t vfs::TFile::getReadPosition() +{ + //VFS_LOCK(m_mutex); + VFS_THROW_IFF( m_isOpen_read, ERROR_FILE(L"file not opened") ); +#ifdef WIN32 + LARGE_INTEGER current_position,zero; + zero.QuadPart = 0; + if(!SetFilePointerEx(m_file, zero, ¤t_position, FILE_CURRENT)) + { + DWORD err = GetLastError(); + if(err != NO_ERROR) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << err << _BS::wget) ); + } + } + return (vfs::size_t)current_position.QuadPart; +#else + long int pos = ftell(m_file); + if(pos == -1L) + { + int error = ferror(m_file); + if(error) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << error << _BS::wget) ); + } + } + return (vfs::size_t)pos; +#endif +} + +template +void vfs::TFile::setReadPosition(vfs::size_t positionInBytes) +{ + //VFS_LOCK(m_mutex); + VFS_THROW_IFF( m_isOpen_read, ERROR_FILE(L"file not opened") ); +#ifdef WIN32 + LARGE_INTEGER pos; + pos.QuadPart = positionInBytes; + if(!SetFilePointerEx(m_file, pos, NULL, FILE_BEGIN)) + { + DWORD err = GetLastError(); + if(err != NO_ERROR) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << err << _BS::wget) ); + } + } +#else + int error = fseek(m_file,positionInBytes,SEEK_SET); + if(error) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << error << _BS::wget) ); + } +#endif +} + +template +void vfs::TFile::setReadPosition(vfs::offset_t offsetInBytes, IBaseFile::ESeekDir seekDir) +{ + //VFS_LOCK(m_mutex); + VFS_THROW_IFF( m_isOpen_read, ERROR_FILE(L"file not opened") ); +#ifdef WIN32 + DWORD ioSeekDir; + VFS_TRYCATCH_RETHROW( ioSeekDir = _seekDir(seekDir), ERROR_FILE(L"seek error")); + + LARGE_INTEGER offset; + offset.QuadPart = offsetInBytes; + if(!SetFilePointerEx(m_file, offset, NULL, ioSeekDir)) + { + DWORD err = GetLastError(); + if(err != NO_ERROR) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << err << _BS::wget) ); + } + } +#else + int ioSeekDir; + VFS_TRYCATCH_RETHROW( ioSeekDir = _seekDir(seekDir), ERROR_FILE(L"seek error")); + int error = fseek(m_file, offsetInBytes, ioSeekDir); + if(error) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << error << _BS::wget) ); + } +#endif +} + +/********************************************************************************/ +/********************************************************************************/ + + +vfs::CFile::CFile(vfs::Path const& filename) +: tBaseClass(filename), m_isOpen_write(false) +{ +} + +vfs::CFile::~CFile() +{ + //VFS_LOCK(m_mutex); + if(m_isOpen_read || m_isOpen_write) + { + this->close(); + } +} + +void vfs::CFile::close() +{ + //VFS_LOCK(m_mutex); + tBaseClass::close(); + m_isOpen_write = false; +} + +bool vfs::CFile::deleteFile() +{ + //VFS_LOCK(m_mutex); + this->close(); + return vfs::OS::deleteRealFile(m_filename); +} + +bool vfs::CFile::isOpenWrite() +{ + //VFS_LOCK(m_mutex); + return m_isOpen_write; +} + +bool vfs::CFile::_internalOpenWrite(vfs::Path const& path, bool createWhenNotExist, bool truncate) +{ + //VFS_LOCK(m_mutex); + if( m_isOpen_write ) + return true; +#ifdef WIN32 + DWORD Mode = 0; + if(createWhenNotExist) + { + Mode |= OPEN_ALWAYS; + } + else + { + Mode |= OPEN_EXISTING; + } + if(truncate) + { + Mode |= TRUNCATE_EXISTING; + } + + m_file = vfs::Settings::getUseUnicode() ? + CreateFileW(path.c_str(),GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL,Mode,FILE_ATTRIBUTE_NORMAL,NULL) : + CreateFileA(vfs::String::narrow(path.c_str(),path.length()).c_str(),GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL,Mode,FILE_ATTRIBUTE_NORMAL,NULL); + DWORD err = GetLastError(); + if(truncate && err == ERROR_FILE_NOT_FOUND) + { + Mode = CREATE_ALWAYS; + m_file = vfs::Settings::getUseUnicode() ? + CreateFileW(path.c_str(),GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,Mode,FILE_ATTRIBUTE_NORMAL,NULL) : + CreateFileA(vfs::String::narrow(path.c_str(),path.length()).c_str(),GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL,Mode,FILE_ATTRIBUTE_NORMAL,NULL); + err = GetLastError(); + } + if(err != NO_ERROR && err != ERROR_ALREADY_EXISTS) + { + VFS_LOG_ERROR(_BS(L"Error when opening file - ") << path << L" - [" << err << L"]" << _BS::wget); + return m_isOpen_write = false; + } + return m_isOpen_write = true; +#else + m_file = fopen(path.to_string().c_str(), "r+"); + if( (!m_file && createWhenNotExist) || (m_file && truncate)) + { + m_file = fopen(path.to_string().c_str(), "w"); + } + + return m_isOpen_write = (m_file != NULL); +#endif +} + +bool vfs::CFile::openWrite(bool createWhenNotExist, bool truncate) +{ + //VFS_LOCK(m_mutex); + return _internalOpenWrite(m_filename, createWhenNotExist, truncate); +} + +vfs::size_t vfs::CFile::write(const vfs::Byte* data, vfs::size_t bytesToWrite) +{ + //VFS_LOCK(m_mutex); + VFS_THROW_IFF( m_isOpen_write, ERROR_FILE(L"file not opened") ); +#ifdef WIN32 + DWORD has_written = 0; + if(!WriteFile(m_file, data, bytesToWrite, &has_written, NULL)) + { + DWORD err = GetLastError(); + if(err != NO_ERROR) + { + VFS_THROW(_BS(L"write error : ") << err << _BS::wget); + } + } +#else + size_t has_written = fwrite(data, 1, bytesToWrite, m_file); + if(has_written != bytesToWrite) + { + int error = ferror(m_file); + if(error) + { + VFS_THROW(_BS(L"write error : ") << error << _BS::wget); + } + } + +#endif + return (vfs::size_t)has_written; +} + +vfs::size_t vfs::CFile::getWritePosition() +{ + //VFS_LOCK(m_mutex); + VFS_THROW_IFF( m_isOpen_write, ERROR_FILE(L"file not opened") ); +#ifdef WIN32 + LARGE_INTEGER current_position, zero; + zero.QuadPart = 0; + if(!SetFilePointerEx(m_file, zero, ¤t_position, FILE_CURRENT)) + { + DWORD err = GetLastError(); + if(err != NO_ERROR) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << err << _BS::wget) ); + } + } + return (vfs::size_t)current_position.QuadPart; +#else + long int pos = ftell(m_file); + if(pos == -1L) + { + int error = ferror(m_file); + if(error) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << error << _BS::wget) ); + } + } + return (vfs::size_t)pos; +#endif +} + +void vfs::CFile::setWritePosition(vfs::size_t positionInBytes) +{ + //VFS_LOCK(m_mutex); + VFS_THROW_IFF( m_isOpen_write, ERROR_FILE(L"file not opened") ); +#ifdef WIN32 + LARGE_INTEGER pos; + pos.QuadPart = positionInBytes; + if(!SetFilePointerEx(m_file, pos, NULL, FILE_CURRENT)) + { + DWORD err = GetLastError(); + if(err != NO_ERROR) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << err << _BS::wget) ); + } + } +#else + int error = fseek(m_file,positionInBytes,SEEK_SET); + if(error) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << error << _BS::wget) ); + } +#endif +} + +void vfs::CFile::setWritePosition(vfs::offset_t offsetInBytes, vfs::IBaseFile::ESeekDir seekDir) +{ + //VFS_LOCK(m_mutex); + VFS_THROW_IFF( m_isOpen_write, ERROR_FILE(L"file not opened") ); +#ifdef WIN32 + DWORD ioSeekDir; + VFS_TRYCATCH_RETHROW( ioSeekDir = _seekDir(seekDir), ERROR_FILE(L"seek error")); + + LARGE_INTEGER offset; + offset.QuadPart = offsetInBytes; + if(!SetFilePointerEx(m_file, offset, NULL, ioSeekDir)) + { + DWORD err = GetLastError(); + if(err != NO_ERROR) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << err << _BS::wget) ); + } + } +#else + int ioSeekDir; + VFS_TRYCATCH_RETHROW( ioSeekDir = _seekDir(seekDir), ERROR_FILE(L"seek error")); + int error = fseek(m_file, offsetInBytes, ioSeekDir); + if(error) + { + VFS_THROW( ERROR_FILE(_BS(L"set position error : ") << error << _BS::wget) ); + } +#endif +} + +template +vfs::size_t vfs::TFile::getSize() +{ + //VFS_LOCK(m_mutex); +#ifdef WIN32 + bool was_open = false; + if(m_file) + { + was_open = true; + } + else + { + VFS_THROW_IFF(this->openRead(),ERROR_FILE(L"could not open file")); + } + vfs::size_t size; +# ifdef _MSC_VER + LARGE_INTEGER li_size; + if(!GetFileSizeEx(m_file, &li_size)) + { + DWORD err = GetLastError(); + if(err != NO_ERROR) + { + VFS_THROW( ERROR_FILE(_BS(L"get size error : ") << err << _BS::wget) ); + } + } + size = (vfs::size_t)li_size.QuadPart; +# else + DWORD low_part, high_part; + low_part = GetFileSize(m_file, &high_part); + if(low_part == INVALID_FILE_SIZE) + { + DWORD err = GetLastError(); + if(err != NO_ERROR) + { + VFS_THROW( ERROR_FILE(_BS(L"get size error : ") << err << _BS::wget) ); + } + } + size = low_part; +# endif + if(!was_open) + { + this->close(); + } + return size; +#else + // if file was alredy opened, keep it open, otherwise close it + bool closeAtExit = !m_isOpen_read; + + VFS_THROW_IFF( m_isOpen_read || this->openRead(), ERROR_FILE(L"could not open file") ) + + // save current position + long int current_position = ftell(m_file); + + // move to end of the file + fseek(m_file, 0, SEEK_END); + long int file_size = ftell(m_file); + + // move to old position + fseek(m_file, current_position, SEEK_SET); + VFS_THROW_IFF(current_position == ftell(m_file), ERROR_FILE(L"could not restore seek position")); + + if(closeAtExit) + { + this->close(); + } + return (vfs::size_t)file_size; +#endif +} + +/******************************************************************/ +/******************************************************************/ + +template class vfs::TFile; +template class vfs::TFile; + diff --git a/ext/VFS/src/Core/File/vfs_lib_file.cpp b/ext/VFS/src/Core/File/vfs_lib_file.cpp new file mode 100644 index 000000000..ded9d36e8 --- /dev/null +++ b/ext/VFS/src/Core/File/vfs_lib_file.cpp @@ -0,0 +1,163 @@ +/* + * bfVFS : vfs/Core/File/vfs_lib_file.cpp + * - read/read-write files for usage in vfs locations (libraries) + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + + +#define ERROR_FILE(msg) (_BS(L"[") << this->getPath()() << L"] - " << msg << _BS::wget) + +vfs::ObjBlockAllocator* vfs::CLibFile::_lfile_pool = NULL; + +vfs::CLibFile* vfs::CLibFile::create(vfs::Path const& filename, + tLocation *location, + ILibrary *library, + vfs::ObjBlockAllocator* allocator) +{ +#if 0 + vfs::CLibFile* pFile = new vfs::CLibFile(); +#else + vfs::CLibFile* pFile; + if(allocator) + { + pFile = allocator->New(); + } + else + { + if(!_lfile_pool) + { + _lfile_pool = new vfs::ObjBlockAllocator(); + vfs::ObjectAllocator::registerAllocator(_lfile_pool); + } + pFile = _lfile_pool->New(); + } +#endif + pFile->m_filename = filename; + pFile->m_location = location; + pFile->m_library = library; + return pFile; +} + +vfs::CLibFile::CLibFile() +: tBaseClass(L""), + m_isOpen_read(false), + m_library(NULL), + m_location(NULL) +{ +}; + +vfs::CLibFile::~CLibFile() +{ +} + +void vfs::CLibFile::close() +{ + if(m_isOpen_read) + { + m_library->close(this); + m_isOpen_read = false; + } +} + +vfs::FileAttributes vfs::CLibFile::getAttributes() +{ + return vfs::FileAttributes(vfs::FileAttributes::ATTRIB_NORMAL | vfs::FileAttributes::ATTRIB_READONLY, + vfs::FileAttributes::LT_LIBRARY); +} + +vfs::Path vfs::CLibFile::getPath() +{ + if(m_location) + { + return m_location->getPath() + m_filename; + } + else + { + return m_filename; + } +} +bool vfs::CLibFile::isOpenRead() +{ + return m_isOpen_read; +} + +bool vfs::CLibFile::openRead() +{ + if(!m_isOpen_read) + { + VFS_TRYCATCH_RETHROW(m_isOpen_read = m_library->openRead(this), ERROR_FILE(L"read open error")); + } + return m_isOpen_read; +} + +vfs::size_t vfs::CLibFile::read(vfs::Byte* data, vfs::size_t bytesToRead) +{ + VFS_THROW_IFF( m_isOpen_read, ERROR_FILE(L"file not opened") ); + try + { + return m_library->read(this, data, bytesToRead); + } + catch(std::exception& ex) + { + VFS_RETHROW(ERROR_FILE(L"read error"), ex); + } +} + +vfs::size_t vfs::CLibFile::getReadPosition() +{ + VFS_THROW_IFF( m_isOpen_read, ERROR_FILE(L"file not opened") ); + try + { + return m_library->getReadPosition(this); + } + catch(std::exception& ex) + { + VFS_RETHROW(ERROR_FILE(L"library error"), ex); + } +} + + +void vfs::CLibFile::setReadPosition(vfs::size_t uiPositionInBytes) +{ + VFS_THROW_IFF( m_isOpen_read, ERROR_FILE(L"file not opened") ); + VFS_TRYCATCH_RETHROW(m_library->setReadPosition(this,uiPositionInBytes), ERROR_FILE(L"library error") ); +} + +void vfs::CLibFile::setReadPosition(vfs::offset_t offsetInBytes, IBaseFile::ESeekDir seekDir) +{ + VFS_THROW_IFF( m_isOpen_read, ERROR_FILE(L"file not opened") ); + VFS_TRYCATCH_RETHROW(m_library->setReadPosition(this, offsetInBytes, seekDir), ERROR_FILE(L"library error")); +} + +vfs::size_t vfs::CLibFile::getSize() +{ + VFS_THROW_IFF( m_isOpen_read || this->openRead(), ERROR_FILE(L"could not open file") ); + try + { + return m_library->getSize(this); + } + catch(std::exception& ex) + { + VFS_RETHROW(ERROR_FILE(L"library error"), ex); + } +} diff --git a/ext/VFS/src/Core/Interface/vfs_interface_members.cpp b/ext/VFS/src/Core/Interface/vfs_interface_members.cpp new file mode 100644 index 000000000..465f4666b --- /dev/null +++ b/ext/VFS/src/Core/Interface/vfs_interface_members.cpp @@ -0,0 +1,116 @@ +/* + * bfVFS : vfs/Core/Interface/vfs_interface_members.cpp + * - non-generic code from the interface header files + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +/********************************************************************** + * vfs::FileAttributes + */ +vfs::FileAttributes::FileAttributes() +: _attribs(ATTRIB_NORMAL), _location(LT_NONE) +{ +}; + +vfs::FileAttributes::FileAttributes(vfs::UInt32 attribs, LocationType location) +: _attribs(attribs), _location(location) +{ +}; + +vfs::UInt32 vfs::FileAttributes::getAttrib() const +{ + return _attribs; +}; + +vfs::UInt32 vfs::FileAttributes::getLocation() const +{ + return _location; +}; + +bool vfs::FileAttributes::isAttribSet(vfs::UInt32 attribs) const +{ + return attribs == (attribs & _attribs); +}; + +bool vfs::FileAttributes::isAttribNotSet(vfs::UInt32 attribs) const +{ + return 0 == (attribs & _attribs); +}; + +bool vfs::FileAttributes::isLocation(vfs::UInt32 location) const +{ + return location == (location & _location); +}; + +/********************************************************************** + * vfs::IBaseFile + */ + +vfs::IBaseFile::IBaseFile(vfs::Path const& filename) +: m_filename(filename) +{}; + +vfs::IBaseFile::~IBaseFile() +{}; + +vfs::Path const& vfs::IBaseFile::getName() +{ + return m_filename; +}; + +vfs::Path vfs::IBaseFile::getPath() +{ + return this->getName(); +}; + + +bool vfs::IBaseFile::_getRealPath(vfs::Path& path) +{ + return false; +} + +/********************************************************************** + * vfs::ILibrary + */ + +vfs::ILibrary::ILibrary(vfs::tReadableFile *libraryFile, vfs::Path const& mountPoint, bool ownFile) +: tBaseClass(mountPoint), m_ownLibFile(ownFile), m_libraryFile(libraryFile) +{ +} + +vfs::ILibrary::~ILibrary() +{ + if(m_libraryFile && m_ownLibFile) + { + m_libraryFile->close(); + delete m_libraryFile; + m_libraryFile = NULL; + } +} + +vfs::Path const& vfs::ILibrary::getName() +{ + return m_libraryFile->getName(); +} + +/**********************************************************************/ diff --git a/ext/VFS/src/Core/Location/vfs_directory_tree.cpp b/ext/VFS/src/Core/Location/vfs_directory_tree.cpp new file mode 100644 index 000000000..98e925c12 --- /dev/null +++ b/ext/VFS/src/Core/Location/vfs_directory_tree.cpp @@ -0,0 +1,628 @@ +/* + * bfVFS : vfs/Core/Location/vfs_directory_tree.cpp + * - class for directories in a File System, implements Directory interface + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include +#include +#include + +#define ERROR_FILE(msg) (_BS(msg) << L" : " << pFile->getPath() << _BS::wget) + +namespace vfs +{ + template + class TSubDir : public vfs::TDirectory::tWriteType> + { + typedef vfs::TDirectory::tWriteType> tBaseClass; + typedef typename tBaseClass::tFileType tFileType; + + typedef std::map tFileCatalogue; + public: + typedef vfs::IBaseLocation::Iterator Iterator; + + ///////////////////////////////////////////////////////////////////// + class IterImpl : public vfs::IBaseLocation::Iterator::IImplementation + { + friend class TSubDir; + typedef vfs::IBaseLocation::Iterator::IImplementation tBaseClass; + + IterImpl(TSubDir* dir): _dir(dir) + { + VFS_THROW_IFF(_dir, L""); + _iter = _dir->m_mapFiles.begin(); + } + public: + IterImpl() : tBaseClass(), _dir(NULL) + {}; + virtual ~IterImpl() + {}; + + virtual tFileType* value() + { + if(_iter != _dir->m_mapFiles.end()) + { + return _iter->second; + } + return NULL; + } + virtual void next() + { + if(_iter != _dir->m_mapFiles.end()) + { + _iter++; + } + } + protected: + tBaseClass* clone() + { + IterImpl* iter = new IterImpl(); + iter->_dir = _dir; + iter->_iter = _iter; + return iter; + } + private: + TSubDir* _dir; + typename tFileCatalogue::iterator _iter; + }; + ///////////////////////////////////////////////////////////////////// + public: + TSubDir(vfs::Path const& sMountPoint, vfs::Path const& sRealPath) + : tBaseClass(sMountPoint,sRealPath) + {}; + + virtual ~TSubDir(); + + virtual bool fileExists(vfs::Path const& rFileName); + virtual vfs::IBaseFile* getFile(vfs::Path const& rFileName); + virtual tFileType* getFileTyped(vfs::Path const& rFileName); + + virtual tFileType* addFile(vfs::Path const& sFilename, bool bDeleteOldFile=false); + virtual bool addFile(tFileType* pFile, bool bDeleteOldFile=false); + + virtual bool createSubDirectory(vfs::Path const& sSubDirPath); + virtual bool deleteDirectory(vfs::Path const& sDirPath); + virtual bool deleteFileFromDirectory(vfs::Path const& sFileName); + + virtual void getSubDirList(std::list& rlSubDirs); + + virtual Iterator begin(); + private: + tFileCatalogue m_mapFiles; + }; + + template<> + vfs::TSubDir::tFileType* vfs::TSubDir::addFile(vfs::Path const& sFilename, bool bDeleteOldFile); + template<> + vfs::TSubDir::tFileType* vfs::TSubDir::addFile(vfs::Path const& sFilename, bool bDeleteOldFile); + + template<> + bool vfs::TSubDir::deleteDirectory(vfs::Path const& sDirPath); + template<> + bool vfs::TSubDir::deleteDirectory(vfs::Path const& sDirPath); + + template<> + bool vfs::TSubDir::deleteFileFromDirectory(vfs::Path const& rFileName); + template<> + bool vfs::TSubDir::deleteFileFromDirectory(vfs::Path const& rFileName); +} + +/********************************************************/ + +template +vfs::TSubDir::~TSubDir() +{ + typename tFileCatalogue::iterator it = m_mapFiles.begin(); + for(; it != m_mapFiles.end(); ++it) + { + if(it->second) + { + it->second->close(); + delete it->second; + } + } + m_mapFiles.clear(); +} + +template +bool vfs::TSubDir::fileExists(vfs::Path const& sFileName) +{ + typename tFileCatalogue::iterator it = m_mapFiles.find(sFileName); + bool success = (it != m_mapFiles.end()) && (it->second != NULL); + return success; +} + +template +vfs::IBaseFile* vfs::TSubDir::getFile(vfs::Path const& sFileName) +{ + return getFileTyped(sFileName); +} + +template +typename vfs::TSubDir::tFileType* vfs::TSubDir::getFileTyped(vfs::Path const& sFileName) +{ + typename tFileCatalogue::iterator it = m_mapFiles.find(sFileName); + if(it != m_mapFiles.end()) + { + return it->second; + } + return NULL; +} + +template<> +vfs::TSubDir::tFileType* vfs::TSubDir::addFile(vfs::Path const& sFilename, bool bDeleteOldFile) +{ + tFileType* pFile = m_mapFiles[sFilename]; + if(pFile) + { + if(!bDeleteOldFile) + { + // not allowed to replace old file + return NULL; + } + delete pFile; + } + pFile = new vfs::CReadOnlyDirFile(sFilename,this); + m_mapFiles[sFilename] = pFile; + + return pFile; +} + +template<> +vfs::TSubDir::tFileType* vfs::TSubDir::addFile(vfs::Path const& sFilename, bool bDeleteOldFile) +{ + tFileType* pFile = m_mapFiles[sFilename]; + if(pFile) + { + if(!bDeleteOldFile) + { + // not allowed to replace old file + return NULL; + } + delete pFile; + } + pFile = new vfs::CDirFile(sFilename,this); + m_mapFiles[sFilename] = pFile; + + return pFile; +} + +template +bool vfs::TSubDir::addFile(tFileType* pFile, bool bDeleteOldFile) +{ + if(!pFile) + { + return false; + } + tFileType* pOldFile = m_mapFiles[pFile->getName()]; + if( pOldFile && (pOldFile != pFile) ) + { + if(bDeleteOldFile) + { + pOldFile->close(); + delete pOldFile; + } + } + m_mapFiles[pFile->getName()] = pFile; + return true; +} + +template<> +bool vfs::TSubDir::deleteDirectory(vfs::Path const& sDirPath) +{ + if( !(this->m_mountPoint == sDirPath) ) + { + return false; + } + tFileCatalogue::iterator it = m_mapFiles.begin(); + for(; it != m_mapFiles.end(); ++it) + { + tFileType* pFile = it->second; + if(pFile) + { + pFile->close(); + if(!pFile->deleteFile()) + { + VFS_THROW( ERROR_FILE(L"Could not delete file") ); + } + delete pFile; + } + } + m_mapFiles.clear(); + return true; +} + +template<> +bool vfs::TSubDir::deleteDirectory(vfs::Path const& sDirPath) +{ + return false; +} + +template<> +bool vfs::TSubDir::deleteFileFromDirectory(vfs::Path const& rFileName) +{ + tFileCatalogue::iterator it = m_mapFiles.find(rFileName); + if( it != m_mapFiles.end() ) + { + tFileType* pFile = it->second; + if(pFile) + { + pFile->close(); + VFS_THROW_IFF(pFile->deleteFile(), ERROR_FILE(L"Could not delete file")); + delete pFile; + } + m_mapFiles.erase(it); + return true; + } + return false; +} + +template<> +bool vfs::TSubDir::deleteFileFromDirectory(vfs::Path const& rFileName) +{ + return false; +} + +template +bool vfs::TSubDir::createSubDirectory(vfs::Path const& sSubDirPath) +{ + return false; +} + +template +void vfs::TSubDir::getSubDirList(std::list& rlSubDirs) +{ +} + +template +typename vfs::TSubDir::Iterator vfs::TSubDir::begin() +{ + return Iterator(new IterImpl(this)); +} + +/********************************************************************************************/ +/********************************************************************************************/ +/********************************************************************************************/ + +template +class vfs::TDirectoryTree::IterImpl : public vfs::IBaseLocation::Iterator::IImplementation +{ + typedef vfs::IBaseLocation::Iterator::IImplementation tBaseClass; + typedef vfs::TDirectoryTree tDirTree; +public: + IterImpl(tDirTree& tree); + virtual ~IterImpl(); + + virtual typename tDirTree::tFileType* value(); + virtual void next(); +protected: + virtual tBaseClass* clone() + { + IterImpl* iter = new IterImpl(_tree); + iter->_subdir_iter = _subdir_iter; + iter->_file_iter = _file_iter; + return iter; + } +private: + void operator=(typename vfs::TDirectoryTree::IterImpl const& tree); + tDirTree& _tree; + typename tDirTree::tDirCatalogue::iterator _subdir_iter; + typename tDirTree::tLocationType::Iterator _file_iter; +}; + +template +vfs::TDirectoryTree::IterImpl::IterImpl(vfs::TDirectoryTree& tree) +: tBaseClass(), _tree(tree) +{ + _subdir_iter = _tree.m_catDirs.begin(); + if(_subdir_iter != _tree.m_catDirs.end()) + { + TSubDir *sdir = dynamic_cast*>(_subdir_iter->second); + typename TSubDir::Iterator it = sdir->begin(); + _file_iter = it; + if(_file_iter.end()) + { + next(); + } + } +} + +template +vfs::TDirectoryTree::IterImpl::~IterImpl() +{ +} + +template +typename vfs::TDirectoryTree::tFileType* vfs::TDirectoryTree::IterImpl::value() +{ + if(!_file_iter.end()) + { + return static_cast::tFileType*>(_file_iter.value()); + } + return NULL; +} + +template +void vfs::TDirectoryTree::IterImpl::next() +{ + if(!_file_iter.end()) + { + _file_iter.next(); + } + // need to loop for the case when one or many sub directories are empty + while(_file_iter.end()) + { + if(_subdir_iter == _tree.m_catDirs.end()) + { + break; + } + else + { + _subdir_iter++; + if(_subdir_iter != _tree.m_catDirs.end()) + { + _file_iter = _subdir_iter->second->begin(); + } + } + } + return; +} + +/*****************************************************************************/ +/*****************************************************************************/ + +template +vfs::TDirectoryTree::TDirectoryTree(vfs::Path const& sMountPoint, vfs::Path const& sRealPath) +: tBaseClass(sMountPoint,sRealPath) +{}; + + +template +vfs::TDirectoryTree::~TDirectoryTree() +{ + typename tDirCatalogue::iterator it = m_catDirs.begin(); + for(;it != m_catDirs.end(); ++it) + { + delete it->second; + it->second = NULL; + } + m_catDirs.clear(); +} + +template +bool vfs::TDirectoryTree::init() +{ + // contains local path + typedef vfs::TSubDir tSubDir; + typedef std::pair tDirs; + std::queue qSubDirs; + qSubDirs.push(tDirs(vfs::Path(vfs::Const::EMPTY()),new tSubDir(this->m_mountPoint, this->m_realPath))); + + m_catDirs[this->m_mountPoint] = qSubDirs.front().second; + + vfs::String sFilename; + tSubDir *pCurrentDir; + vfs::Path oCurDir; + while(!qSubDirs.empty()) + { + pCurrentDir = qSubDirs.front().second; + oCurDir = this->m_realPath; + if( !qSubDirs.front().first.empty()) + { + oCurDir += qSubDirs.front().first; + } + + try + { + vfs::OS::CIterateDirectory::EFileAttribute eFA; + vfs::OS::CIterateDirectory iterFS(oCurDir, vfs::Const::STAR()); + while ( iterFS.nextFile(sFilename, eFA) ) + { + if (StrCmp::Equal(vfs::Const::DOT(),sFilename) || StrCmp::Equal(vfs::Const::DOTDOT(),sFilename) || StrCmp::Equal(vfs::Const::DOTSVN(),sFilename) ) + { + continue; + } + if (eFA == vfs::OS::CIterateDirectory::FA_DIRECTORY) + { + vfs::Path sLocal = qSubDirs.front().first + sFilename; + + vfs::Path temp = this->m_mountPoint+sLocal; + tSubDir *pNewDir = new tSubDir(sLocal, this->m_realPath+sLocal); + qSubDirs.push(tDirs(sLocal,pNewDir)); + m_catDirs[temp] = pNewDir; + } + else + { + pCurrentDir->addFile(vfs::Path(sFilename)); + } + } + } + catch(std::exception &ex) + { + // probably directory doesn't exist. abort or continue??? + // -> abort AND continue + VFS_LOG_WARNING(ex.what()); + return false; + } + qSubDirs.pop(); + } + return true; +} + +template +typename vfs::TDirectoryTree::tFileType* vfs::TDirectoryTree::addFile(vfs::Path const& sFilename, bool bDeleteOldFile) +{ + vfs::Path sDir,sFile; + sFilename.splitLast(sDir,sFile); + typename tDirCatalogue::iterator it = m_catDirs.find(sDir); + if(it == m_catDirs.end()) + { + vfs::Path sTemp,sCreateDir,sLeft,sRight = sDir; + while(!sRight.empty()) + { + sRight.splitFirst(sLeft,sTemp); + sRight = sTemp; + sCreateDir += sLeft; + if(!this->createSubDirectory(sCreateDir)) + { + VFS_THROW(_BS(L"could not create directory : ") << sCreateDir << _BS::wget); + } + } + it = m_catDirs.find(sDir); + if(it == m_catDirs.end()) + { + return NULL; + } + } + if(it->second) + { + return it->second->addFile(sFile,bDeleteOldFile); + } + return NULL; +} + +template +bool vfs::TDirectoryTree::addFile(tFileType* pFile, bool bDeleteOldFile) +{ + // no files from outside + // these files are not connected with the correct directory object + return false; +} + +template +bool vfs::TDirectoryTree::deleteDirectory(vfs::Path const& sDirPath) +{ + typename tDirCatalogue::iterator it = m_catDirs.find(sDirPath); + if(it == m_catDirs.end()) + { + // no such directory + return false; + } + if(it->second) + { + return it->second->deleteDirectory(sDirPath); + } + return false; +} + +template +bool vfs::TDirectoryTree::deleteFileFromDirectory(vfs::Path const& sFileName) +{ + vfs::Path sDir,sFile; + sFileName.splitLast(sDir,sFile); + typename tDirCatalogue::iterator it = m_catDirs.find(sDir); + if(it == m_catDirs.end()) + { + // no such directory + return false; + } + if(it->second) + { + return it->second->deleteFileFromDirectory(sFile); + } + return false; +} + +/** + * IVFSLocation interface + */ +template +bool vfs::TDirectoryTree::fileExists(vfs::Path const& sFileName) +{ + vfs::Path sDir, sFile; + sFileName.splitLast(sDir, sFile); + typename tDirCatalogue::iterator it = m_catDirs.find(sDir); + if(it == m_catDirs.end()) + { + // no such directory + return false; + } + if(it->second) + { + return it->second->fileExists(sFile); + } + return false; +} + +template +vfs::IBaseFile* vfs::TDirectoryTree::getFile(vfs::Path const& sFileName) +{ + return getFileTyped(sFileName); +} + +template +typename vfs::TDirectoryTree::tFileType* vfs::TDirectoryTree::getFileTyped(vfs::Path const& sFileName) +{ + vfs::Path sDir, sFile; + sFileName.splitLast(sDir, sFile); + typename tDirCatalogue::iterator it = m_catDirs.find(sDir); + if(it == m_catDirs.end()) + { + // no such directory + return NULL; + } + if(it->second) + { + return it->second->getFileTyped(sFile); + } + return NULL; +} + +template +bool vfs::TDirectoryTree::createSubDirectory(vfs::Path const& sSubDirPath) +{ + if(vfs::OS::createRealDirectory( this->m_realPath + sSubDirPath )) + { + if( m_catDirs[sSubDirPath] == NULL) + { + m_catDirs[sSubDirPath] = new vfs::TSubDir(sSubDirPath, this->m_realPath + sSubDirPath); + } + return true; + } + return false; +} + +template +void vfs::TDirectoryTree::getSubDirList(std::list& rlSubDirs) +{ + typename tDirCatalogue::iterator it = m_catDirs.begin(); + for(;it != m_catDirs.end(); ++it) + { + rlSubDirs.push_back(it->first); + } +} + +template +typename vfs::TDirectoryTree::Iterator vfs::TDirectoryTree::begin() +{ + return Iterator(new IterImpl(*this)); +} + +/*****************************************************************************/ +/*****************************************************************************/ + +template class vfs::TDirectoryTree; // explicit template class instantiation +template class vfs::TDirectoryTree; // explicit template class instantiation + diff --git a/ext/VFS/src/Core/Location/vfs_lib_dir.cpp b/ext/VFS/src/Core/Location/vfs_lib_dir.cpp new file mode 100644 index 000000000..711acb5de --- /dev/null +++ b/ext/VFS/src/Core/Location/vfs_lib_dir.cpp @@ -0,0 +1,199 @@ +/* + * bfVFS : vfs/Core/Location/vfs_lib_dir.cpp + * - class for readonly (sub)directories in archives/libraries + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +class vfs::CLibDirectory::IterImpl : public vfs::IBaseLocation::Iterator::IImplementation +{ + typedef vfs::IBaseLocation::Iterator::IImplementation tBaseClass; +public: + IterImpl(CLibDirectory& lib); + virtual ~IterImpl(); + virtual vfs::CLibDirectory::tFileType* value(); + virtual void next(); +protected: + virtual tBaseClass* clone(); +private: + void operator=(vfs::CLibDirectory::IterImpl const& iter); + + vfs::CLibDirectory& _lib; + vfs::CLibDirectory::tFileCatalogue::iterator _iter; +}; + +vfs::CLibDirectory::IterImpl::IterImpl(CLibDirectory& lib) +: tBaseClass(), _lib(lib) +{ + _iter = _lib.m_files.begin(); +} + +vfs::CLibDirectory::IterImpl::~IterImpl() +{ +} + +vfs::CLibDirectory::tFileType* vfs::CLibDirectory::IterImpl::value() +{ + if(_iter != _lib.m_files.end()) + { + return _iter->second; + } + return NULL; +} + +void vfs::CLibDirectory::IterImpl::next() +{ + if(_iter != _lib.m_files.end()) + { + _iter++; + } +} + +vfs::CLibDirectory::IterImpl::tBaseClass* vfs::CLibDirectory::IterImpl::clone() +{ + IterImpl* iter = new IterImpl(_lib); + iter->_iter = _iter; + return iter; +} + +/***************************************************************************/ +/***************************************************************************/ + +vfs::CLibDirectory::CLibDirectory(vfs::Path const& sLocalPath, vfs::Path const& sRealPath) +: tBaseClass(sLocalPath,sRealPath) +{ +} + +vfs::CLibDirectory::~CLibDirectory() +{ + tFileCatalogue::iterator it = m_files.begin(); + for(; it != m_files.end(); ++it) + { + // don't delete objects here + //delete it->second; + } + m_files.clear(); +} + +vfs::CLibDirectory::tFileType* vfs::CLibDirectory::addFile(vfs::Path const& filename, bool deleteOldFile) +{ + return NULL; +} + +bool vfs::CLibDirectory::addFile(tFileType* file, bool deleteOldFile) +{ + if(!file) + { + return false; + } + vfs::Path const& name = file->getName(); + tFileType* oldFile = m_files[name]; + if(oldFile && (oldFile != file) ) + { + if(deleteOldFile) + { + delete oldFile; + m_files[name] = file; + } + else + { + return false; + } + } + m_files[name] = file; + return true; +} + +bool vfs::CLibDirectory::deleteDirectory(vfs::Path const& dirPath) +{ + //if( !(m_mountPoint == dirPath) ) + //{ + // return false; + //} + //if(implementsWritable()) + //{ + // tFileCatalogue::iterator it = m_files.begin(); + // for(; it != m_files.end(); ++it) + // { + // //delete it->second; + // } + // m_files.clear(); + // return true; + //} + VFS_LOG_ERROR(L"called 'deleteDirectory', 'vfs::CLibDirectory' doesn't implement the IWritable interface"); + return false; +} + +bool vfs::CLibDirectory::deleteFileFromDirectory(vfs::Path const& filename) +{ + //if(implementsWritable()) + //{ + // tFileCatalogue::iterator it = m_files.find(filename); + // if(it != m_files.end()) + // { + // delete it->second; + // m_files.erase(it); + // return true; + // } + //} + VFS_LOG_ERROR(L"called 'deleteFileFromDirectory', 'vfs::CLibDirectory' doesn't implement the IWritable interface"); + return false; +} + +bool vfs::CLibDirectory::fileExists(vfs::Path const& filename) +{ + return (m_files[filename] != NULL); +} + +vfs::IBaseFile* vfs::CLibDirectory::getFile(vfs::Path const& filename) +{ + return getFileTyped(filename); +} + +vfs::CLibDirectory::tFileType* vfs::CLibDirectory::getFileTyped(vfs::Path const& filename) +{ + tFileCatalogue::iterator it = m_files.find(filename); + if(it != m_files.end()) + { + return it->second; + } + return NULL; +} + +bool vfs::CLibDirectory::createSubDirectory(vfs::Path const& subDirPath) +{ + // libraries are readonly + return false; +} + +void vfs::CLibDirectory::getSubDirList(std::list& rlSubDirs) +{ + // nothing +} + +vfs::CLibDirectory::Iterator vfs::CLibDirectory::begin() +{ + return Iterator(new IterImpl(*this)); +} + +/***************************************************************************/ +/***************************************************************************/ diff --git a/ext/VFS/src/Core/Location/vfs_uncompressed_lib_base.cpp b/ext/VFS/src/Core/Location/vfs_uncompressed_lib_base.cpp new file mode 100644 index 000000000..a6a628d12 --- /dev/null +++ b/ext/VFS/src/Core/Location/vfs_uncompressed_lib_base.cpp @@ -0,0 +1,320 @@ +/* + * bfVFS : vfs/Core/Location/vfs_uncompressed_lib_base.cpp + * - partially implements library interface for uncompressed archive files + * - initialization is done in format-specific sub-classes + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +/********************************************************************************************/ +vfs::CUncompressedLibraryBase::SFileData& vfs::CUncompressedLibraryBase::_fileDataFromHandle(tFileType* handle) +{ + tFileData::iterator it = m_fileData.find(handle); + if(it != m_fileData.end()) + { + return it->second; + } + VFS_THROW(L"Invalid file handle"); +} +/********************************************************************************************/ +/********************************************************************************************/ + +class vfs::CUncompressedLibraryBase::IterImpl : public vfs::IBaseLocation::Iterator::IImplementation +{ + typedef vfs::IBaseLocation::Iterator::IImplementation tBaseClass; +public: + IterImpl(CUncompressedLibraryBase& lib); + virtual ~IterImpl(); + virtual tFileType* value(); + virtual void next(); +protected: + virtual tBaseClass* clone() + { + IterImpl* iter = new IterImpl(*_lib); + iter->_iter = _iter; + return iter; + } +private: + vfs::CUncompressedLibraryBase* _lib; + vfs::CUncompressedLibraryBase::tFileData::iterator _iter; +}; + + +vfs::CUncompressedLibraryBase::IterImpl::IterImpl(vfs::CUncompressedLibraryBase &lib) +: tBaseClass(), _lib(&lib) +{ + _iter = _lib->m_fileData.begin(); +} +vfs::CUncompressedLibraryBase::IterImpl::~IterImpl() +{ +} + +vfs::CUncompressedLibraryBase::tFileType* vfs::CUncompressedLibraryBase::IterImpl::value() +{ + if(_iter != _lib->m_fileData.end()) + { + return _iter->first; + } + return NULL; +} + +void vfs::CUncompressedLibraryBase::IterImpl::next() +{ + if(_iter != _lib->m_fileData.end()) + { + _iter++; + } +} + +/************************************************************************/ +/************************************************************************/ + +vfs::CUncompressedLibraryBase::CUncompressedLibraryBase(vfs::tReadableFile *libraryFile, vfs::Path const& mountPoint, bool ownFile) +: vfs::ILibrary(libraryFile,mountPoint,ownFile), m_numberOfOpenedFiles(0) +{ +} + +vfs::CUncompressedLibraryBase::~CUncompressedLibraryBase() +{ + this->closeLibrary(); + // delete sub dirs from catalogue + tDirCatalogue::iterator it = m_dirs.begin(); + for(; it != m_dirs.end(); ++it) + { + delete it->second; + } + // LibData is invalid + // just clear it, since the file handles were deleted before + m_fileData.clear(); + m_dirs.clear(); +} + +void vfs::CUncompressedLibraryBase::closeLibrary() +{ + tFileData::iterator it = m_fileData.begin(); + for(; it != m_fileData .end(); ++it) + { + // what if closing of (at least) one file fails?? continue or not?? + // in the end, these are not real files! + VFS_IGNOREEXCEPTION(it->first->close(), true); + } +} + +bool vfs::CUncompressedLibraryBase::fileExists(vfs::Path const& filename) +{ + vfs::Path sDir,sFile; + filename.splitLast(sDir,sFile); + tDirCatalogue::iterator it = m_dirs.find(sDir); + if(it != m_dirs.end()) + { + return it->second->fileExists(sFile); + } + return false; +} + +vfs::IBaseFile* vfs::CUncompressedLibraryBase::getFile(vfs::Path const& filename) +{ + return getFileTyped(filename); +} + +vfs::CUncompressedLibraryBase::tFileType* vfs::CUncompressedLibraryBase::getFileTyped(vfs::Path const& filename) +{ + vfs::Path sDir,sFile; + filename.splitLast(sDir,sFile); + tDirCatalogue::iterator it = m_dirs.find(sDir); + if(it != m_dirs.end()) + { + return it->second->getFileTyped(sFile); + } + return NULL; +} + +void vfs::CUncompressedLibraryBase::close(tFileType *fileHandle) +{ + try + { + SFileData& file = _fileDataFromHandle(fileHandle); + + // reset read position + // can't do this when opening file, + // because you could try to open a file when it is already open and would so reset the read position + file._currentReadPosition = 0; + if(m_numberOfOpenedFiles > 0) + { + m_numberOfOpenedFiles--; + if(m_numberOfOpenedFiles == 0) + { + m_libraryFile->close(); + } + } + } + catch(std::exception& ex) + { + VFS_RETHROW(L"", ex); + } +} +bool vfs::CUncompressedLibraryBase::openRead(tFileType *fileHandle) +{ + try + { + _fileDataFromHandle(fileHandle); + } + catch(std::exception& ex) + { + VFS_RETHROW(L"", ex); + } + + m_numberOfOpenedFiles++; + if(m_numberOfOpenedFiles == 1) + { + if(!m_libraryFile->isOpenRead() && !m_libraryFile->openRead()) + { + return false; + } + } + // already open + return true; +} + +vfs::size_t vfs::CUncompressedLibraryBase::read(tFileType *fileHandle, vfs::Byte* data, vfs::size_t bytesToRead) +{ + try + { + SFileData& file = _fileDataFromHandle(fileHandle); + + if( (file._currentReadPosition + bytesToRead) > file._fileSize ) + { + bytesToRead = file._fileSize - file._currentReadPosition; + } + if(bytesToRead == 0) + { + // eof + return 0; + } + // set lib-file's read-location to match location of lib-file + m_libraryFile->setReadPosition(file._fileOffset + file._currentReadPosition, IBaseFile::SD_BEGIN); + + vfs::size_t bytesRead = m_libraryFile->read(data, bytesToRead); + VFS_THROW_IFF( bytesToRead == bytesRead, L"Number of bytes doesn't match" ); + file._currentReadPosition += bytesRead; + return bytesRead; + } + catch(std::exception& ex) + { + VFS_RETHROW(L"", ex); + } +} + +vfs::size_t vfs::CUncompressedLibraryBase::getReadPosition(tFileType *fileHandle) +{ + try + { + return _fileDataFromHandle(fileHandle)._currentReadPosition; + } + catch(std::exception& ex) + { + VFS_RETHROW(L"", ex); + } +} + +void vfs::CUncompressedLibraryBase::setReadPosition(tFileType *fileHandle, vfs::size_t positionInBytes) +{ + try + { + SFileData& file = _fileDataFromHandle(fileHandle); + if( positionInBytes > file._fileSize ) + { + positionInBytes = file._fileSize; + } + + // positionInBytes is offset to file-offset + file._currentReadPosition = positionInBytes; + } + catch(std::exception& ex) + { + VFS_RETHROW(L"", ex); + } +} + +static inline vfs::offset_t clampReadPosition(vfs::offset_t const& off, vfs::size_t const& size) +{ + return ( off < 0 ) ? ( 0 ) : ( (vfs::size_t)off > size ? size : off ); +} + +void vfs::CUncompressedLibraryBase::setReadPosition(tFileType *fileHandle, vfs::offset_t offsetInBytes, IBaseFile::ESeekDir seekDir) +{ + try + { + SFileData& file = _fileDataFromHandle(fileHandle); + + if(seekDir == IBaseFile::SD_BEGIN) + { + file._currentReadPosition = clampReadPosition(offsetInBytes, file._fileSize); + } + else if(seekDir == IBaseFile::SD_CURRENT) + { + vfs::offset_t pos = file._currentReadPosition + offsetInBytes; + file._currentReadPosition = clampReadPosition(pos, file._fileSize); + } + else if(seekDir == IBaseFile::SD_END) + { + vfs::offset_t pos = file._currentReadPosition + offsetInBytes; + file._currentReadPosition = clampReadPosition(pos, file._fileSize); + } + else + { + VFS_THROW(L"Unknown seek direction"); + } + } + catch(std::exception& ex) + { + VFS_RETHROW(L"", ex); + } +} + +vfs::size_t vfs::CUncompressedLibraryBase::getSize(tFileType *fileHandle) +{ + try + { + return _fileDataFromHandle(fileHandle)._fileSize; + } + catch(std::exception& ex) + { + VFS_RETHROW(L"", ex); + } +} + +void vfs::CUncompressedLibraryBase::getSubDirList(std::list& rlSubDirs) +{ + tDirCatalogue::iterator it = m_dirs.begin(); + for(;it != m_dirs.end(); ++it) + { + rlSubDirs.push_back(it->first); + } +} + +vfs::CUncompressedLibraryBase::Iterator vfs::CUncompressedLibraryBase::begin() +{ + return Iterator(new IterImpl(*this)); +} + + + diff --git a/ext/VFS/src/Core/files.cmake b/ext/VFS/src/Core/files.cmake new file mode 100644 index 000000000..ce3081332 --- /dev/null +++ b/ext/VFS/src/Core/files.cmake @@ -0,0 +1,80 @@ + +## Core + +## +set(INCLUDE_Core_root + ${MOD_INCLUDE}/vfs.h + ${MOD_INCLUDE}/vfs_debug.h + ${MOD_INCLUDE}/vfs_file_raii.h + ${MOD_INCLUDE}/vfs_init.h + ${MOD_INCLUDE}/vfs_os_functions.h + ${MOD_INCLUDE}/vfs_path.h + ${MOD_INCLUDE}/vfs_profile.h + ${MOD_INCLUDE}/vfs_string.h + ${MOD_INCLUDE}/vfs_types.h + ${MOD_INCLUDE}/vfs_vfile.h + ${MOD_INCLUDE}/vfs_vloc.h +) +set(SOURCE_Core_root + ${MOD_SOURCE}/vfs.cpp + ${MOD_SOURCE}/vfs_debug.cpp + ${MOD_SOURCE}/vfs_file_raii.cpp + ${MOD_SOURCE}/vfs_init.cpp + ${MOD_SOURCE}/vfs_os_functions.cpp + ${MOD_SOURCE}/vfs_path.cpp + ${MOD_SOURCE}/vfs_profile.cpp + ${MOD_SOURCE}/vfs_string.cpp + ${MOD_SOURCE}/vfs_types.cpp + ${MOD_SOURCE}/vfs_vfile.cpp + ${MOD_SOURCE}/vfs_vloc.cpp +) +source_group("Core" FILES ${INCLUDE_Core_root} ${SOURCE_Core_root}) + +## +set(INCLUDE_Core_File + ${MOD_INCLUDE}/File/vfs_buffer_file.h + ${MOD_INCLUDE}/File/vfs_dir_file.h + ${MOD_INCLUDE}/File/vfs_file.h + ${MOD_INCLUDE}/File/vfs_lib_file.h +) +set(SOURCE_Core_File + ${MOD_SOURCE}/File/vfs_buffer_file.cpp + ${MOD_SOURCE}/File/vfs_dir_file.cpp + ${MOD_SOURCE}/File/vfs_file.cpp + ${MOD_SOURCE}/File/vfs_lib_file.cpp +) +source_group("Core\\File" FILES ${INCLUDE_Core_File} ${SOURCE_Core_File}) + +## +set(INCLUDE_Core_Interface + ${MOD_INCLUDE}/Interface/vfs_directory_interface.h + ${MOD_INCLUDE}/Interface/vfs_file_interface.h + ${MOD_INCLUDE}/Interface/vfs_iterator_interface.h + ${MOD_INCLUDE}/Interface/vfs_library_interface.h + ${MOD_INCLUDE}/Interface/vfs_location_interface.h +) +set(SOURCE_Core_Interface + ${MOD_SOURCE}/Interface/vfs_interface_members.cpp +) +source_group("Core\\Interface" FILES ${INCLUDE_Core_Interface} ${SOURCE_Core_Interface}) + +## +set(INCLUDE_Core_Location + ${MOD_INCLUDE}/Location/vfs_directory_tree.h + ${MOD_INCLUDE}/Location/vfs_lib_dir.h + ${MOD_INCLUDE}/Location/vfs_uncompressed_lib_base.h +) +set(SOURCE_Core_Location + ${MOD_SOURCE}/Location/vfs_directory_tree.cpp + ${MOD_SOURCE}/Location/vfs_lib_dir.cpp + ${MOD_SOURCE}/Location/vfs_uncompressed_lib_base.cpp +) +source_group("Core\\Location" FILES ${INCLUDE_Core_Location} ${SOURCE_Core_Location}) + +set(${mod}_files + ${INCLUDE_Core_root} ${SOURCE_Core_root} + ${INCLUDE_Core_File} ${SOURCE_Core_File} + ${INCLUDE_Core_Interface} ${SOURCE_Core_Interface} + ${INCLUDE_Core_Location} ${SOURCE_Core_Location} + CACHE INTERNAL "" +) \ No newline at end of file diff --git a/ext/VFS/src/Core/vfs.cpp b/ext/VFS/src/Core/vfs.cpp new file mode 100644 index 000000000..811deb75c --- /dev/null +++ b/ext/VFS/src/Core/vfs.cpp @@ -0,0 +1,617 @@ +/* + * bfVFS : vfs/Core/vfs.cpp + * - primary interface for the using program, get files from the VFS internal storage + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +template class vfs::TIterator; // explicit instantiation + +/********************************************************************/ +/********************************************************************/ + +class vfs::CVirtualFileSystem::CRegularIterator : public vfs::CVirtualFileSystem::Iterator::IImplementation +{ + friend class vfs::CVirtualFileSystem; + typedef vfs::CVirtualFileSystem::Iterator::IImplementation tBaseClass; + + CRegularIterator(vfs::CVirtualFileSystem* pVFS); +public: + CRegularIterator() : tBaseClass(), m_VFS(NULL) + {}; + virtual ~CRegularIterator() + {}; + + virtual vfs::tReadableFile* value(); + virtual void next(); +protected: + virtual tBaseClass* clone() + { + CRegularIterator* iter = new CRegularIterator(); + iter->m_VFS = m_VFS; + iter->_vloc_iter = _vloc_iter; + iter->_vfile_iter = _vfile_iter; + return iter; + } +private: + vfs::CVirtualFileSystem* m_VFS; + vfs::CVirtualFileSystem::tVFS::iterator _vloc_iter; + vfs::CVirtualLocation::Iterator _vfile_iter; +}; + +vfs::CVirtualFileSystem::CRegularIterator::CRegularIterator(vfs::CVirtualFileSystem* pVFS) +: tBaseClass(), m_VFS(pVFS) +{ + _vloc_iter = m_VFS->m_mapFS.begin(); + if(_vloc_iter != m_VFS->m_mapFS.end()) + { + _vfile_iter = _vloc_iter->second->iterate(); + } +} + +vfs::tReadableFile* vfs::CVirtualFileSystem::CRegularIterator::value() +{ + bool bExclusiveVLoc = false; + if(_vloc_iter != m_VFS->m_mapFS.end()) + { + bExclusiveVLoc = _vloc_iter->second->getIsExclusive(); + } + if(!_vfile_iter.end()) + { + vfs::CVirtualFile* pVFile = _vfile_iter.value(); + if(pVFile) + { + if(bExclusiveVLoc) + { + return vfs::tReadableFile::cast(pVFile->file(vfs::CVirtualFile::SF_STOP_ON_WRITABLE_PROFILE)); + } + else + { + return vfs::tReadableFile::cast(pVFile->file(vfs::CVirtualFile::SF_TOP)); + } + } + } + return NULL; +} +void vfs::CVirtualFileSystem::CRegularIterator::next() +{ + if(!_vfile_iter.end()) + { + _vfile_iter.next(); + } + while(_vfile_iter.end()) + { + if(_vloc_iter != m_VFS->m_mapFS.end()) + { + _vloc_iter++; + if(_vloc_iter != m_VFS->m_mapFS.end()) + { + _vfile_iter = _vloc_iter->second->iterate(); + } + } + else + { + return; + } + } +} + +/********************************************************************/ +/********************************************************************/ + +class vfs::CVirtualFileSystem::CMatchingIterator : public vfs::CVirtualFileSystem::Iterator::IImplementation +{ + friend class vfs::CVirtualFileSystem; + typedef vfs::CVirtualFileSystem::Iterator::IImplementation tBaseClass; + + CMatchingIterator(vfs::Path const& sPattern, vfs::CVirtualFileSystem* pVFS); +public: + CMatchingIterator() : tBaseClass(), m_VFS(NULL) + {}; + virtual ~CMatchingIterator() + {}; + + virtual vfs::tReadableFile* value(); + virtual void next(); +protected: + virtual tBaseClass* clone() + { + CMatchingIterator* iter = new CMatchingIterator(); + iter->m_sLocPattern = m_sLocPattern; + iter->m_sFilePattern = m_sFilePattern; + iter->m_VFS = m_VFS; + iter->_vloc_iter = _vloc_iter; + iter->_vfile_iter = _vfile_iter; + return iter; + } +private: + bool nextLocationMatch(); + bool nextFileMatch(); +private: + vfs::Path m_sLocPattern, m_sFilePattern; + vfs::CVirtualFileSystem* m_VFS; + vfs::CVirtualFileSystem::tVFS::iterator _vloc_iter; + vfs::CVirtualLocation::Iterator _vfile_iter; +}; + +vfs::CVirtualFileSystem::CMatchingIterator::CMatchingIterator(vfs::Path const& sPattern, vfs::CVirtualFileSystem* pVFS) +: tBaseClass(), m_VFS(pVFS) +{ + if(sPattern() == vfs::Const::STAR()) + { + m_sLocPattern = vfs::Path(vfs::Const::STAR()); + m_sFilePattern = vfs::Path(vfs::Const::STAR()); + } + else + { + sPattern.splitLast(m_sLocPattern,m_sFilePattern); + } + + _vloc_iter = m_VFS->m_mapFS.begin(); + while(_vloc_iter != m_VFS->m_mapFS.end()) + { + if( matchPattern(m_sLocPattern(),_vloc_iter->second->cPath()) ) + { + bool bExclusiveVLoc = _vloc_iter->second->getIsExclusive(); + _vfile_iter = _vloc_iter->second->iterate(); + while(!_vfile_iter.end()) + { + vfs::IBaseFile* pFile = NULL; + if(bExclusiveVLoc) + { + pFile = _vfile_iter.value()->file(vfs::CVirtualFile::SF_STOP_ON_WRITABLE_PROFILE); + } + else + { + pFile = _vfile_iter.value()->file(vfs::CVirtualFile::SF_TOP); + } + if(pFile) + { + vfs::Path const& filename = pFile->getName(); + if( matchPattern(m_sFilePattern(),filename()) ) + { + return; + } + } + _vfile_iter.next(); + } + } + _vloc_iter++; + } +} + +vfs::tReadableFile* vfs::CVirtualFileSystem::CMatchingIterator::value() +{ + bool bExclusiveVLoc = false; + if( _vloc_iter != m_VFS->m_mapFS.end() ) + { + bExclusiveVLoc = _vloc_iter->second->getIsExclusive(); + } + if(!_vfile_iter.end()) + { + vfs::CVirtualFile* pVFile = _vfile_iter.value(); + if(pVFile) + { + vfs::IBaseFile* pFile = NULL; + if(bExclusiveVLoc) + { + pFile = _vfile_iter.value()->file(vfs::CVirtualFile::SF_STOP_ON_WRITABLE_PROFILE); + } + else + { + pFile = _vfile_iter.value()->file(vfs::CVirtualFile::SF_TOP); + } + return vfs::tReadableFile::cast(pFile); + } + } + return NULL; +} + +bool vfs::CVirtualFileSystem::CMatchingIterator::nextLocationMatch() +{ + while(_vloc_iter != m_VFS->m_mapFS.end()) + { + _vloc_iter++; + if(_vloc_iter != m_VFS->m_mapFS.end()) + { + if(matchPattern(m_sLocPattern(),_vloc_iter->second->cPath())) + { + return true; + } + } + } + return false; +} +bool vfs::CVirtualFileSystem::CMatchingIterator::nextFileMatch() +{ + bool bExclusiveVLoc = false; + if( _vloc_iter != m_VFS->m_mapFS.end() ) + { + bExclusiveVLoc = _vloc_iter->second->getIsExclusive(); + } + while(!_vfile_iter.end()) + { + _vfile_iter.next(); + if(!_vfile_iter.end()) + { + vfs::IBaseFile* pFile = NULL; + if(bExclusiveVLoc) + { + pFile = _vfile_iter.value()->file(vfs::CVirtualFile::SF_STOP_ON_WRITABLE_PROFILE); + } + else + { + pFile = _vfile_iter.value()->file(vfs::CVirtualFile::SF_TOP); + } + if(pFile) + { + vfs::Path const& filename = pFile->getName(); + if(matchPattern(m_sFilePattern(),filename())) + { + return true; + } + } + } + } + return false; +} + +void vfs::CVirtualFileSystem::CMatchingIterator::next() +{ + if(nextFileMatch()) + { + return; + } + while(nextLocationMatch()) + { + _vfile_iter = _vloc_iter->second->iterate(); + if(!_vfile_iter.end()) + { + bool bExclusiveVLoc = _vloc_iter->second->getIsExclusive(); + vfs::IBaseFile* pFile = NULL; + if(bExclusiveVLoc) + { + pFile = _vfile_iter.value()->file(vfs::CVirtualFile::SF_STOP_ON_WRITABLE_PROFILE); + } + else + { + pFile = _vfile_iter.value()->file(vfs::CVirtualFile::SF_TOP); + } + if(pFile && matchPattern(m_sFilePattern(),pFile->getName()())) + { + return; + } + else if(nextFileMatch()) + { + return; + } + } + } +} + +/********************************************************************/ +/********************************************************************/ + +bool vfs::canWrite() +{ + vfs::CVirtualProfile *prof = getVFS()->getProfileStack()->topProfile(); + return prof && prof->cWritable; +} + +vfs::CVirtualFileSystem* getVFS() +{ + return vfs::CVirtualFileSystem::getVFS(); +} + +vfs::CVirtualFileSystem* vfs::CVirtualFileSystem::m_pSingleton = NULL; + +vfs::CVirtualFileSystem* vfs::CVirtualFileSystem::getVFS() +{ + if(!m_pSingleton) + { + m_pSingleton = new CVirtualFileSystem(); + } + return m_pSingleton; +} + +void vfs::CVirtualFileSystem::shutdownVFS() +{ + if(m_pSingleton) + { + delete m_pSingleton; + m_pSingleton = NULL; + } +} + + +vfs::CVirtualFileSystem::CVirtualFileSystem() +{ +} + +vfs::CVirtualFileSystem::~CVirtualFileSystem() +{ + tVFS::iterator it = m_mapFS.begin(); + for(; it != m_mapFS.end(); ++it) + { + delete it->second; + } + m_mapFS.clear(); +} + +vfs::CProfileStack* vfs::CVirtualFileSystem::getProfileStack() +{ + return &m_oProfileStack; +} + +vfs::CVirtualFileSystem::Iterator vfs::CVirtualFileSystem::begin() +{ + return Iterator(new vfs::CVirtualFileSystem::CRegularIterator(this)); +} + +vfs::CVirtualFileSystem::Iterator vfs::CVirtualFileSystem::begin(vfs::Path const& sPattern) +{ + return Iterator(new vfs::CVirtualFileSystem::CMatchingIterator(sPattern,this)); +} + +bool vfs::CVirtualFileSystem::addLocation(vfs::IBaseLocation* pLocation, vfs::CVirtualProfile *pProfile) +{ + VFS_THROW_IFF(pLocation != NULL, L"Invalid location object"); + VFS_THROW_IFF(pProfile!= NULL, L"Invalid location object"); + + std::list lSubDirs; + pLocation->getSubDirList(lSubDirs); + std::list::const_iterator sd_cit = lSubDirs.begin(); + for(;sd_cit != lSubDirs.end(); ++sd_cit) + { + this->getVirtualLocation(*sd_cit, true); + } + + vfs::IBaseLocation::Iterator it = pLocation->begin(); + for(; !it.end(); it.next()) + { + vfs::IBaseFile *pFile = it.value(); + vfs::Path const& sPath = pFile->getPath(); + vfs::Path dir,file; + sPath.splitLast(dir,file); + + CVirtualLocation* pLoc = this->getVirtualLocation(dir,true); + pLoc->addFile(pFile, pProfile->cName); + } + return true; +} + +vfs::tReadableFile* vfs::CVirtualFileSystem::getReadFile(vfs::Path const& rLocalFilePath, vfs::CVirtualFile::ESearchFile eSF) +{ + return vfs::tReadableFile::cast(this->getFile(rLocalFilePath,eSF)); +} + +vfs::tWritableFile* vfs::CVirtualFileSystem::getWriteFile(vfs::Path const& rLocalFilePath, vfs::CVirtualFile::ESearchFile eSF) +{ + return vfs::tWritableFile::cast(this->getFile(rLocalFilePath,eSF)); +} + +vfs::IBaseFile* vfs::CVirtualFileSystem::getFile(vfs::Path const& rLocalFilePath, vfs::CVirtualFile::ESearchFile eSF) +{ + VFS_LOG_DEBUG( (L"Get file : " + rLocalFilePath()).c_str() ); + vfs::Path sDir,sFile; + rLocalFilePath.splitLast(sDir,sFile); + + vfs::CVirtualLocation* pVLoc = this->getVirtualLocation(sDir); + if(pVLoc) + { + vfs::CVirtualFile *pVFile = pVLoc->getVirtualFile(sFile); + if(pVFile) + { + if(pVLoc->getIsExclusive()) + { + return pVFile->file(vfs::CVirtualFile::SF_STOP_ON_WRITABLE_PROFILE); + } + return pVFile->file(eSF); + } + } + VFS_LOG_DEBUG( _BS(L"Could not find file : ") << rLocalFilePath << _BS::wget ); + return NULL; +} + +vfs::tReadableFile* vfs::CVirtualFileSystem::getReadFile(vfs::Path const& rLocalFilePath, vfs::String const& sProfileName) +{ + return vfs::tReadableFile::cast(this->getFile(rLocalFilePath, sProfileName)); +} + +vfs::tWritableFile* vfs::CVirtualFileSystem::getWriteFile(vfs::Path const& rLocalFilePath, vfs::String const& sProfileName) +{ + return vfs::tWritableFile::cast(this->getFile(rLocalFilePath, sProfileName)); +} + +vfs::IBaseFile* vfs::CVirtualFileSystem::getFile(vfs::Path const& rLocalFilePath, vfs::String const& sProfileName) +{ + vfs::Path sDir,sFile; + rLocalFilePath.splitLast(sDir,sFile); + + tVFS::iterator it_loc = m_mapFS.find(sDir); + if(it_loc == m_mapFS.end()) + { + return NULL; + } + vfs::CVirtualLocation* pVLoc = it_loc->second; + if(pVLoc) + { + return pVLoc->getFile(sFile,sProfileName); + } + return NULL; +} + +bool vfs::CVirtualFileSystem::fileExists(vfs::Path const& rLocalFilePath, std::string const& sProfileName) +{ + return this->getFile(rLocalFilePath, sProfileName) != NULL; +} + +bool vfs::CVirtualFileSystem::fileExists(vfs::Path const& rLocalFilePath, vfs::CVirtualFile::ESearchFile eSF) +{ + return this->getFile(rLocalFilePath, eSF) != NULL; +} + +vfs::CVirtualLocation* vfs::CVirtualFileSystem::getVirtualLocation(vfs::Path const& sPath, bool bCreate) +{ + tVFS::iterator it = m_mapFS.find(sPath); + if(it == m_mapFS.end()) + { + if(bCreate) + { + vfs::CVirtualLocation* pVLoc = new vfs::CVirtualLocation(sPath); + m_mapFS.insert(std::make_pair(sPath,pVLoc)); + return pVLoc; + } + return NULL; + } + return it->second; +} + +bool vfs::CVirtualFileSystem::removeDirectoryFromFS(vfs::Path const& sDir) +{ + vfs::Path pattern = sDir + "*"; + std::list files; + + Iterator it = this->begin(pattern); + for(; !it.end(); it.next()) + { + if(it.value()->implementsWritable()) + { + files.push_back(it.value()->getPath()); + } + } + bool success = true; + std::list::iterator fit = files.begin(); + for(; fit != files.end(); ++fit) + { + success &= this->removeFileFromFS(*fit); + } + return success; +} + +bool vfs::CVirtualFileSystem::removeFileFromFS(vfs::Path const& sFilePath) +{ + vfs::Path sPath,sFile; + sFilePath.splitLast(sPath,sFile); + vfs::CVirtualProfile *pProf = m_oProfileStack.getWriteProfile(); + if(pProf) + { + vfs::IBaseLocation *pBL = pProf->getLocation(sPath); + if(pBL && pBL->implementsWritable()) + { + vfs::TDirectory *pDir = dynamic_cast*>(pBL); + if(pDir) + { + bool bSuccess = false; + // remove file from virtual structures first + vfs::IBaseFile* file = pDir->getFile(sFilePath); + if(file) + { + vfs::Path sDir,sFile; + sFilePath.splitLast(sDir,sFile); + vfs::CVirtualLocation *pVLoc = this->getVirtualLocation(sDir); + if(pVLoc) + { + bSuccess = pVLoc->removeFile(file); + } + } + // delete actual file + return bSuccess && pDir->deleteFileFromDirectory(sFilePath); + } + } + } + return false; +} + +bool vfs::CVirtualFileSystem::createNewFile(vfs::Path const& sFilename) +{ + vfs::Path sPath,sFile; + sFilename.splitLast(sPath,sFile); + vfs::CVirtualProfile *pProf = m_oProfileStack.getWriteProfile(); + if(pProf) + { + bool bIsExclusive = false; + bool bNewLocation = false; + vfs::IBaseLocation *pProfLoc = pProf->getLocation(sPath); + if(!pProfLoc) + { + // try to find closest match + vfs::Path sTemp, sCreateDir, sRight, sLeft = sPath; + while(!pProfLoc && !sLeft.empty()) + { + sLeft.splitLast(sTemp,sRight); + sLeft = sTemp; + sCreateDir = sRight + sCreateDir; + pProfLoc = pProf->getLocation(sLeft); + } + // see if the closest match is exclusive + // if yes, then the the new path is a subdirectory and has to be exclusive too + vfs::CVirtualLocation *pVLoc = this->getVirtualLocation(sLeft,true); + if(pVLoc) + { + bIsExclusive = pVLoc->getIsExclusive(); + } + //else + //{ + // VFS_THROW(L"location (closest match) should exist"); + //} + bNewLocation = true; + } + if(pProfLoc && pProfLoc->implementsWritable()) + { + // create file and add to location + vfs::TDirectory *pDir = dynamic_cast*>(pProfLoc); + vfs::IBaseFile* pFile = pDir->addFile(sFilename); + if(bNewLocation) + { + pProf->addLocation(pProfLoc); + } + if(pFile) + { + CVirtualLocation* pLoc = this->getVirtualLocation(sPath,true); + if(bIsExclusive) + { + pLoc->setIsExclusive(bIsExclusive); + } + pLoc->addFile(pFile,pProf->cName); + return true; + } + } + } + // throw ? + return false; +} + +/************************************************************************************************/ diff --git a/ext/VFS/src/Core/vfs_debug.cpp b/ext/VFS/src/Core/vfs_debug.cpp new file mode 100644 index 000000000..13b46cac0 --- /dev/null +++ b/ext/VFS/src/Core/vfs_debug.cpp @@ -0,0 +1,249 @@ +/* + * bfVFS : vfs/Core/vfs_dfebug.cpp + * - Exception class and throw macros, used to notify the using program of unexpected situations + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +vfs::Exception::Exception(vfs::String const& text, vfs::String const& function, int line, const char* file) +: std::exception() //(text.utf8().c_str()) +{ + VFS_LOG_ERROR( text.c_str() ); + + time_t rawtime; + time ( &rawtime ); + std::string datetime(ctime(&rawtime)); + + SEntry en; + en.message = text; + en.line = line; + en.file = file; + en.function = function; + VFS_IGNOREEXCEPTION(en.time = vfs::String(datetime.substr(0,datetime.length()-1)), false); + m_CallStack.push_back(en); +}; + +vfs::Exception::Exception(vfs::String const& text, vfs::String const& function, int line, const char* file, std::exception& ex) +: std::exception() //(text.utf8().c_str()) +{ + VFS_LOG_ERROR( text.c_str() ); + + if(dynamic_cast(&ex)) + { + vfs::Exception& vfs_ex = *static_cast(&ex); + m_CallStack.insert(m_CallStack.end(), vfs_ex.m_CallStack.begin(), vfs_ex.m_CallStack.end()); + } + else + { + SEntry en; + en.line = -1; + en.file = ""; + en.function = ""; + en.time = ""; + VFS_IGNOREEXCEPTION( en.message = vfs::String(ex.what()), false ); + + m_CallStack.push_back(en); + } + + time_t rawtime; + time ( &rawtime ); + std::string datetime(ctime(&rawtime)); + + SEntry en; + en.message = text; + en.line = line; + en.file = file; + en.function = function; + VFS_IGNOREEXCEPTION(en.time = vfs::String(datetime.substr(0,datetime.length()-1)), false); + + m_CallStack.push_back(en); +}; + + + + +vfs::Exception::~Exception() throw() +{ +} + +vfs::String vfs::Exception::getLastEntryString() const +{ + if(!m_CallStack.empty()) + { + CALLSTACK::const_reverse_iterator rit = m_CallStack.rbegin(); + std::wstringstream wss; + wss << rit->file.c_wcs() + << L" (l. " + << rit->line + << ") : [" + << rit->function.c_wcs() + << L"] - " + << rit->message.c_wcs(); + return wss.str(); + } + return ""; +} + +const char* vfs::Exception::what() const throw() +{ + static std::string msg; + msg = ""; + if(!m_CallStack.empty()) + { + //msg = m_CallStack.front().message.utf8(); + msg = this->getExceptionString().utf8(); + } + return msg.c_str(); +} + + +vfs::String vfs::Exception::getExceptionString() const +{ + if(!m_CallStack.empty()) + { + std::wstringstream wss; + CALLSTACK::const_reverse_iterator rit = m_CallStack.rbegin(); + for(; rit != m_CallStack.rend(); ++rit) + { + wss << L"========== " << rit->time << L" ==========\r\n"; + wss << L"File : " << rit->file << L"\r\n"; + wss << L"Line : " << rit->line << L"\r\n"; + wss << L"Location : " << rit->function << L"\r\n\r\n"; + wss << L" " << rit->message << L"\r\n"; + } + return wss.str(); + } + return L""; +} +// +//void vfs::Exception::writeFile(vfs::Path const& sPath) +//{ +// try +// { +// vfs::COpenWriteFile oFile(sPath,true,true); +// vfs::String s = this->getExceptionString(); +// oFile->write(s.utf8().c_str(), s.length()); +// oFile->close(); +// } +// catch(vfs::Exception &ex) +// { +// vfs::Exception ex2(L"Could not write exception file into VFS", +// _FUNCTION_FORMAT_,__LINE__,__FILE__, ex); +// vfs::Exception out("Writing exception to disc failed : is there no writable profile?", +// _FUNCTION_FORMAT_,__LINE__,__FILE__, *this); +// +// out.m_CallStack.insert(out.m_CallStack.begin(), ex.m_CallStack.begin(), ex.m_CallStack.end()); +// +// vfs::Path sDir,sFile; +// sPath.splitLast(sDir,sFile); +// vfs::CFile oFile(sFile); +// +// try +// { +// // can also fail, but there is only so much we can do +// vfs::COpenWriteFile file( vfs::tWritableFile::cast(&oFile) ); +// vfs::String s = out.getExceptionString(); +// file->write(s.utf8().c_str(), s.length()); +// } +// catch(std::exception &fex) +// { +// VFS_RETHROW(L"Could write exception file at all",fex); +// } +// } +//} +// + +// +//void logException(vfs::Exception const& ex) +//{ +// static bool is_logging = false; +// if(is_logging) +// { +// // drop message +// return; +// } +// ////////////////// +// is_logging = true; +// ////////////////// +// +// static vfs::Log& exlog = *vfs::Log::create(L"game_exceptions.log", false, vfs::Log::FLUSH_IMMEDIATELY); +// try +// { +// exlog << ">>>>>>>>>>>>>>>>>>>>>" << vfs::Log::endl; +// exlog << ex.getExceptionString(); +// exlog << "<<<<<<<<<<<<<<<<<<<<<" << vfs::Log::endl << vfs::Log::endl; +// } +// catch(...) +// { +// // don't throw at all +// } +// +// ////////////////// +// is_logging = false; +// ////////////////// +//} +// +//void logException(std::exception const& ex) +//{ +// logException(ex.what()); +//} +// +//void logException(const wchar_t* ex) +//{ +// logException(vfs::String::as_utf8(ex).c_str()); +//} +// +//void logException(const char* ex) +//{ +// static bool is_logging = false; +// if(is_logging) +// { +// // drop message +// return; +// } +// ////////////////// +// is_logging = true; +// ////////////////// +// +// static vfs::Log& exlog = *vfs::Log::create(L"game_exceptions.log", false, vfs::Log::FLUSH_IMMEDIATELY); +// try +// { +// exlog << ">>>>>>>>>>>>>>>>>>>>>" << vfs::Log::endl; +// exlog << ex; +// exlog << "<<<<<<<<<<<<<<<<<<<<<" << vfs::Log::endl << vfs::Log::endl; +// } +// catch(...) +// { +// // don't throw at all +// } +// +// ////////////////// +// is_logging = false; +// //////////////////} +//} diff --git a/ext/VFS/src/Core/vfs_file_raii.cpp b/ext/VFS/src/Core/vfs_file_raii.cpp new file mode 100644 index 000000000..fa47c1f9a --- /dev/null +++ b/ext/VFS/src/Core/vfs_file_raii.cpp @@ -0,0 +1,144 @@ +/* + * bfVFS : vfs/Core/vfs_file_raii.cpp + * - RAII classes to open files for reading/writing + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include +/********************************************************************************************/ +/********************************************************************************************/ + +vfs::COpenReadFile::COpenReadFile(vfs::Path const& sPath, vfs::CVirtualFile::ESearchFile eSF) +{ + vfs::IBaseFile *pFile = getVFS()->getFile(sPath,eSF); + VFS_THROW_IFF(pFile, _BS(L"file \"") << sPath << L"\" does not exist" << _BS::wget); + + m_pFile = vfs::tReadableFile::cast(pFile); + + VFS_THROW_IFF(m_pFile, _BS(L"File \"") << sPath << L"\" is not readable" << _BS::wget); + + VFS_THROW_IFF(m_pFile->openRead(), _BS(L"Could not open file : ") << m_pFile->getPath() << _BS::wget); +} + +vfs::COpenReadFile::COpenReadFile(vfs::tReadableFile *pFile) +{ + try + { + m_pFile = pFile; + VFS_THROW_IFF(m_pFile, L"Invalid file object"); + + VFS_THROW_IFF(m_pFile->openRead(), _BS(L"Could not open file : ") << pFile->getPath() << _BS::wget); + } + catch(std::exception &ex) + { + VFS_RETHROW(L"",ex); + } +} +vfs::COpenReadFile::~COpenReadFile() +{ + if(m_pFile) + { + m_pFile->close(); + m_pFile = NULL; + } +} + +vfs::tReadableFile* vfs::COpenReadFile::operator->() +{ + return m_pFile; +} + +vfs::tReadableFile& vfs::COpenReadFile::file() +{ + return *m_pFile; +} + +void vfs::COpenReadFile::release() +{ + m_pFile = NULL; +} + +/**************************************************************************/ + +vfs::COpenWriteFile::COpenWriteFile(vfs::Path const& sPath, + bool bCreate, + bool bTruncate, + vfs::CVirtualFile::ESearchFile eSF) +{ + vfs::IBaseFile *pFile = getVFS()->getFile(sPath,eSF); + if(!pFile && bCreate) + { + if(getVFS()->createNewFile(sPath)) + { + pFile = getVFS()->getFile(sPath,eSF); + } + else + { + VFS_THROW(_BS(L"Could not create VFS file \"") << sPath << L"\"" << _BS::wget); + } + } + VFS_THROW_IFF(pFile, _BS(L"File \"") << sPath << L"\" not found" << _BS::wget); + + m_pFile = vfs::tWritableFile::cast(pFile); + + VFS_THROW_IFF(m_pFile, _BS(L"File \"") << sPath << L"\" exists, but is not writable" << _BS::wget); + + VFS_THROW_IFF(m_pFile->openWrite(bCreate,bTruncate), _BS(L"File \"") << sPath << L"\" could not be opened for writing" << _BS::wget); +} +vfs::COpenWriteFile::COpenWriteFile(vfs::tWritableFile *pFile) +{ + try + { + m_pFile = pFile; + VFS_THROW_IFF(m_pFile, L"Invalid file object"); + VFS_THROW_IFF(m_pFile->openWrite(true,false), _BS(L"Could not open file : ") << m_pFile->getPath() << _BS::wget); + } + catch(std::exception& ex) + { + VFS_RETHROW(L"",ex); + }; +} +vfs::COpenWriteFile::~COpenWriteFile() +{ + if(m_pFile) + { + m_pFile->close(); + m_pFile = NULL; + } +} + +vfs::tWritableFile* vfs::COpenWriteFile::operator->() +{ + return m_pFile; +} + +vfs::tWritableFile& vfs::COpenWriteFile::file() +{ + return *m_pFile; +} + +void vfs::COpenWriteFile::release() +{ + m_pFile = NULL; +} + diff --git a/ext/VFS/src/Core/vfs_init.cpp b/ext/VFS/src/Core/vfs_init.cpp new file mode 100644 index 000000000..bf94ccd71 --- /dev/null +++ b/ext/VFS/src/Core/vfs_init.cpp @@ -0,0 +1,351 @@ +/* + * bfVFS : vfs/Core/vfs_init.cpp + * - initialization functions/classes + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#ifdef VFS_WITH_SLF +# include +#endif +#ifdef VFS_WITH_7ZIP +# include +# include +#endif + +#include +#include + +#include +#include + +///////////////////////////////// + +vfs_init::Location::Location() +: m_optional(false) +{ +}; + +///////////////////////////////// + +vfs_init::Profile::Profile() +: m_writable(false) +{ +}; + +vfs_init::Profile::~Profile() +{ + t_locations::iterator it = locations.begin(); + for(;it != locations.end(); ++it) + { + if(it->first) delete it->second; + } + locations.clear(); +} + +void vfs_init::Profile::addLocation(Location* loc, bool own) +{ + locations.push_back(std::make_pair(own,loc)); +} + +///////////////////////////////// + +vfs_init::VfsConfig::~VfsConfig() +{ + t_profiles::iterator it = profiles.begin(); + for(;it != profiles.end(); ++it) + { + if(it->first) delete it->second; + } +} + +void vfs_init::VfsConfig::addProfile(Profile* prof, bool own) +{ + profiles.push_back(std::make_pair(own,prof)); +} + +void vfs_init::VfsConfig::appendConfig(VfsConfig& conf) +{ + VfsConfig::t_profiles::iterator it = conf.profiles.begin(); + for(; it != conf.profiles.end(); ++it) + { + // even if the other object owns its profiles, this one does not + profiles.push_back(std::make_pair(false,it->second)); + } +} + +/********************************************************************/ +/********************************************************************/ + +bool vfs_init::initVirtualFileSystem(vfs::Path const& vfs_ini) +{ + std::list li; + li.push_back(vfs_ini); + return initVirtualFileSystem(li); +} +bool vfs_init::initVirtualFileSystem(std::list const& vfs_ini_list) +{ + vfs::PropertyContainer oVFSProps; + std::list::const_iterator clit = vfs_ini_list.begin(); + for(; clit != vfs_ini_list.end(); ++clit) + { + oVFSProps.initFromIniFile(*clit); + } + return initVirtualFileSystem(oVFSProps); +} +bool vfs_init::initVirtualFileSystem(vfs::PropertyContainer& oVFSProps) +{ + VFS_LOG_INFO(L"Processing VFS configuration"); + vfs_init::VfsConfig conf; + + std::list lProfiles, lLocSections; + + oVFSProps.getStringListProperty(L"vfs_config",L"PROFILES",lProfiles,L""); + if(lProfiles.empty()) + { + VFS_LOG_ERROR(L"no profiles specified"); + return false; + } + + std::list::const_iterator prof_cit = lProfiles.begin(); + for(; prof_cit != lProfiles.end(); ++prof_cit) + { + vfs::String sProfSection = vfs::String("PROFILE_") + vfs::String(*prof_cit); + + vfs_init::Profile *prof = new vfs_init::Profile(); + prof->m_name = oVFSProps.getStringProperty(sProfSection,L"NAME",L""); + prof->m_root = oVFSProps.getStringProperty(sProfSection,L"PROFILE_ROOT",L""); + prof->m_writable = oVFSProps.getBoolProperty(sProfSection,L"WRITE",false); + + lLocSections.clear(); + oVFSProps.getStringListProperty(sProfSection,L"LOCATIONS",lLocSections,L""); + + std::list::iterator loc_it = lLocSections.begin(); + for(; loc_it != lLocSections.end(); ++loc_it) + { + vfs::String sLocSection = vfs::String("LOC_") + vfs::String(*loc_it); + + vfs_init::Location *loc = new vfs_init::Location(); + loc->m_path = oVFSProps.getStringProperty(sLocSection,L"PATH",L""); + loc->m_vfs_path = oVFSProps.getStringProperty(sLocSection,L"VFS_PATH",L""); + loc->m_mount_point = oVFSProps.getStringProperty(sLocSection,L"MOUNT_POINT",L""); + loc->m_type = oVFSProps.getStringProperty(sLocSection,L"TYPE",L"NOT_FOUND"); + loc->m_optional = oVFSProps.getBoolProperty(sLocSection,L"OPTIONAL",false); + + prof->addLocation(loc,true); + } + conf.addProfile(prof,true); + } + return initVirtualFileSystem(conf); +} + +bool vfs_init::initWriteProfile(vfs::CVirtualProfile &rProf) +{ + typedef vfs::TDirectory tWDir; + tWDir *pDir = NULL; + vfs::IBaseLocation *pLoc = rProf.getLocation(vfs::Path(vfs::Const::EMPTY())); + if(pLoc) + { + pDir = dynamic_cast(pLoc); + } + else + { + VFS_LOG_WARNING(_BS(L"Could not find location (\"\") for profile '") << rProf.cName << L"'" << _BS::wget ); + VFS_LOG_WARNING(_BS(L"Trying to initialize profile root : ") << rProf.cRoot << _BS::wget ); + vfs::CDirectoryTree *pDirTree = NULL; + pDirTree = new vfs::CDirectoryTree(vfs::Path(vfs::Const::EMPTY()),rProf.cRoot); + if(!pDirTree->init()) + { + return false; + } + VFS_TRYCATCH_RETHROW( rProf.addLocation(pDirTree), L"" ); + getVFS()->addLocation(pDirTree, &rProf); + pDir = pDirTree; + } + return pDir != NULL; +} + + +bool vfs_init::initVirtualFileSystem(vfs_init::VfsConfig const& conf) +{ + VFS_LOG_INFO(L"Initializing Virtual File System"); + + vfs::CVirtualFileSystem *pVFS = getVFS(); + + if(conf.profiles.empty()) + { + return false; + } + vfs_init::VfsConfig::t_profiles::const_iterator prof_it = conf.profiles.begin(); + for(; prof_it != conf.profiles.end(); ++prof_it) + { + vfs_init::Profile* prof = prof_it->second; + VFS_LOG_INFO(_BS(L" Reading profile : ") << prof->m_name << _BS::wget); + + vfs::Path profileRoot = prof->m_root; + + bool bIsWritable = prof->m_writable; + + vfs::CProfileStack *pPS = pVFS->getProfileStack(); + vfs::CVirtualProfile *pProf = pPS->getProfile(prof->m_name); + if(!pProf) + { + pProf = new vfs::CVirtualProfile(prof->m_name, profileRoot, bIsWritable); + pPS->pushProfile(pProf); + } + else + { + VFS_THROW_IFF(pProf->cWritable == bIsWritable, L"profile already exists, but their write properties differ"); + VFS_THROW_IFF(pProf->cRoot == profileRoot, L"profile already exists, but their root directories differ"); + continue; + } + + + vfs_init::Profile::t_locations::iterator loc_it = prof->locations.begin(); + loc_it = prof->locations.begin(); + for(; loc_it != prof->locations.end(); ++loc_it) + { + vfs_init::Location *loc = loc_it->second; + + bool bOptional = loc->m_optional; + if(vfs::StrCmp::Equal(loc->m_type,L"LIBRARY")) + { + vfs::tReadableFile *pLibFile = NULL; + bool bOwnFile = false; + + vfs::Path fullpath = profileRoot + loc->m_path; + VFS_LOG_INFO( _BS(L" library : \"") << fullpath << L"\"" << _BS::wget ); + + if(!loc->m_path.empty()) + { + // try regular file + pLibFile = vfs::tReadableFile::cast( new vfs::CFile(fullpath) ); + bOwnFile = true; + } + if(!pLibFile && !loc->m_vfs_path.empty()) + { + // if regular file doesn't exist, try to find it in the (partially initialized) VFS + pLibFile = pVFS->getReadFile(profileRoot + loc->m_vfs_path); + } + if(pLibFile) + { + vfs::String full_str = pLibFile->getName()(); + vfs::String ext = full_str.c_wcs().substr(full_str.length()-3,3); + vfs::ILibrary *pLib = NULL; + if(vfs::StrCmp::Equal(ext,L"slf")) + { +#ifdef VFS_WITH_SLF + pLib = new vfs::CSLFLibrary( pLibFile, loc->m_mount_point ); +#else + VFS_LOG_ERROR(L"Trying to init slf library : SLF support disabled"); + continue; +#endif + } + else if(vfs::StrCmp::Equal(ext,L".7z")) + { +#ifdef VFS_WITH_7ZIP + pLib = new vfs::CUncompressed7zLibrary( pLibFile, loc->m_mount_point ); +#else + VFS_LOG_ERROR(L"Trying to init 7z library : 7zip support disabled"); + continue; +#endif + } + else + { + VFS_THROW(_BS(L"File [") << loc->m_path << L"] in not an SLF or 7z library" << _BS::wget); + } + if(!pLib->init()) + { + if(!bOptional) + { + VFS_THROW(_BS(L"Could not initialize library [ ") << loc->m_path << L" ]" << + L" in : profile [ " << prof->m_name << L" ]," << + L" path [ " << fullpath << L" ]" << _BS::wget); + } + } + else + { + pProf->addLocation(pLib); + pVFS->addLocation(vfs::tReadLocation::cast(pLib), pProf); + } + } + else + { + VFS_THROW(_BS(L"File not found : ") << loc->m_path << _BS::wget); + } + } + else if(vfs::StrCmp::Equal(loc->m_type,L"DIRECTORY")) + { + vfs::Path fullpath = profileRoot + loc->m_path; + VFS_LOG_INFO( _BS(L" directory : \"") << fullpath << L"\"" << _BS::wget ); + + vfs::IBaseLocation *pDirLocation = NULL; + bool init_success = false; + if(bIsWritable) + { + vfs::CDirectoryTree *pDirTree = new vfs::CDirectoryTree(loc->m_mount_point, fullpath); + init_success = pDirTree->init(); + pDirLocation = pDirTree; + } + else + { + vfs::CReadOnlyDirectoryTree *pDirTree = new vfs::CReadOnlyDirectoryTree(loc->m_mount_point, fullpath); + init_success = pDirTree->init(); + pDirLocation = pDirTree; + } + if(!init_success) + { + VFS_THROW(_BS(L"Could not initialize directory [\"") << loc->m_path << L"\"]" << + L" in : profile [\"" << prof->m_name << L"\"]," << + L" path [\"" << fullpath << L"\"]" << _BS::wget); + } + else + { + pProf->addLocation(pDirLocation); + pVFS->addLocation(pDirLocation, pProf); + } + } + } + if(bIsWritable) + { + vfs::CProfileStack *pPS = pVFS->getProfileStack(); + vfs::CVirtualProfile *pProf = pPS->getProfile(prof->m_name); + if(!pProf) + { + pProf = new vfs::CVirtualProfile(prof->m_name,profileRoot,true); + pPS->pushProfile(pProf); + } + else if(!pProf->cWritable) + { + VFS_THROW(_BS(L"Profile [") << prof->m_name << L"] is supposed to be writable!" << _BS::wget); + } + initWriteProfile(*pProf); + } + } + + return true; +} + diff --git a/ext/VFS/src/Core/vfs_os_functions.cpp b/ext/VFS/src/Core/vfs_os_functions.cpp new file mode 100644 index 000000000..82e7accc7 --- /dev/null +++ b/ext/VFS/src/Core/vfs_os_functions.cpp @@ -0,0 +1,402 @@ +/* + * bfVFS : vfs/Core/os_functions.cpp + * - abstractions for OS dependant code + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifndef WIN32 +# include "errno.h" +# include "sys/stat.h" +#endif + +vfs::OS::CIterateDirectory::CIterateDirectory(vfs::Path const& sPath, vfs::String const& searchPattern) +{ +#ifdef WIN32 + if(!vfs::Settings::getUseUnicode()) + { + std::string s; + vfs::String::narrow((sPath+searchPattern).c_wcs(), s); + fSearchHandle = FindFirstFileA(s.c_str(), &fFileInfoA); + } + else + { + fSearchHandle = FindFirstFileW((sPath+searchPattern).c_wcs().c_str(), &fFileInfoW); + } + if (fSearchHandle == INVALID_HANDLE_VALUE) + { + DWORD error = GetLastError(); + VFS_THROW(_BS(L"Error accessing path [") << (sPath+searchPattern) << L"], error code : " << error << _BS::wget); + } +#else + count = scandir(vfs::String::as_utf8(sPath()).c_str(),&files,NULL,NULL); + if(count == -1) + { + vfs::String err = strerror(errno); + VFS_THROW(err); + } + current_pos = 0; +#endif + fFirstRequest = true; +} + +vfs::OS::CIterateDirectory::~CIterateDirectory() +{ +#ifdef WIN32 + FindClose(fSearchHandle); +#else +#endif +} + +bool vfs::OS::CIterateDirectory::nextFile(vfs::String &fileName, CIterateDirectory::EFileAttribute &attrib) +{ +#ifdef WIN32 + VFS_THROW_IFF(fSearchHandle != INVALID_HANDLE_VALUE, L"Invalid Handle Value"); + if (fFirstRequest) + { + fFirstRequest = false; + } + //else + { + if(!vfs::Settings::getUseUnicode()) + { + if( !FindNextFileA(fSearchHandle, &fFileInfoA) ) + { + return false; + } + fileName.r_wcs().assign( vfs::String::widen( fFileInfoA.cFileName, strlen(fFileInfoA.cFileName) ) ); + attrib = (fFileInfoA.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? CIterateDirectory::FA_DIRECTORY : CIterateDirectory::FA_FILE; + } + else + { + if ( !FindNextFileW(fSearchHandle, &fFileInfoW) ) + { + return false; + } + fileName.r_wcs().assign(fFileInfoW.cFileName); + attrib = (fFileInfoW.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? CIterateDirectory::FA_DIRECTORY : CIterateDirectory::FA_FILE; + } + } + return true; +#else + if(current_pos < count) + { + struct dirent* entry = files[current_pos]; + fileName = vfs::String(entry->d_name); + attrib = (entry->d_type == DT_DIR) ? CIterateDirectory::FA_DIRECTORY : CIterateDirectory::FA_FILE; + current_pos++; + return true; + } + return false; +#endif +} + +bool vfs::OS::checkRealDirectory(vfs::Path const& sDir) +{ +#ifdef WIN32 + bool bDirExists = false; + if(!vfs::Settings::getUseUnicode()) + { + WIN32_FIND_DATAA fd; + memset(&fd,0,sizeof(WIN32_FIND_DATAA)); + + std::string s; + vfs::String::narrow(sDir.c_wcs(), s); + + HANDLE hFile = FindFirstFileA( s.c_str(), &fd); + if(hFile == INVALID_HANDLE_VALUE) + { + DWORD error = GetLastError(); + VFS_LOG_ERROR(_BS(L"Directory [") << sDir << L"] does not exist : " << error << _BS::wget); + } + + bDirExists = (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0; + + FindClose(hFile); + } + else + { + WIN32_FIND_DATAW fd; + memset(&fd,0,sizeof(WIN32_FIND_DATAW)); + HANDLE hFile = FindFirstFileW( sDir.c_str(), &fd); + if(hFile == INVALID_HANDLE_VALUE) + { + DWORD error = GetLastError(); + VFS_LOG_ERROR(_BS(L"Directory [") << sDir << L"] does not exist : " << error << _BS::wget); + } + + bDirExists = (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0; + + FindClose(hFile); + } + return bDirExists; +#else + int result = access(sDir.to_string().c_str(), F_OK /*0400*/); + if(result == -1) + { + vfs::String err = strerror(errno); + VFS_LOG_ERROR(err.c_str()); + return false; + } + return true; +#endif +} + +bool vfs::OS::createRealDirectory(vfs::Path const& sDir) +{ +#ifdef WIN32 + BOOL success; + vfs::String::str_t const& str = sDir.c_wcs(); + success = vfs::Settings::getUseUnicode() ? + CreateDirectoryW(sDir.c_str(),NULL) : + CreateDirectoryA( vfs::String::narrow( str.c_str(), str.length() ).c_str(), NULL ); + if(success == 0) + { + DWORD error = GetLastError(); + if(error == ERROR_ALREADY_EXISTS) + { + return true; + } + + VFS_LOG_ERROR((_BS("Could not create directory [") << sDir << L"] : " << error).get()); + + return false; + } + return true; +#else + int result = mkdir(sDir.to_string().c_str(), S_IRWXU | S_IRGRP /*0777*/); + if(result == -1 && errno != EEXIST) + { + vfs::String err = strerror(errno); + VFS_THROW(err); + } + return true; +#endif +} + +bool vfs::OS::FileAttributes::getFileAttributes(vfs::Path const& sDir, vfs::UInt32& uiAttribs) +{ +#ifdef WIN32 + DWORD attribs = vfs::Settings::getUseUnicode() ? + GetFileAttributesW(sDir.c_str()) : + GetFileAttributesA(vfs::String::narrow(sDir.c_str(), sDir.length()).c_str()); + + if(attribs == INVALID_FILE_ATTRIBUTES) + { + DWORD error = GetLastError(); + VFS_LOG_ERROR(_BS(L"Invalid File Attributes : ") << error << _BS::wget); + return false; + } + + for(vfs::UInt32 attribMask = 0x80000000; attribMask > 0; attribMask >>= 1) + { + switch(attribs & attribMask) + { + case FILE_ATTRIBUTE_ARCHIVE: + uiAttribs |= ATTRIB_ARCHIVE; + break; + case FILE_ATTRIBUTE_DIRECTORY: + uiAttribs |= ATTRIB_DIRECTORY; + break; + case FILE_ATTRIBUTE_HIDDEN: + uiAttribs |= ATTRIB_HIDDEN; + break; + case FILE_ATTRIBUTE_NORMAL: + uiAttribs |= ATTRIB_NORMAL; + break; + case FILE_ATTRIBUTE_READONLY: + uiAttribs |= ATTRIB_READONLY; + break; + case FILE_ATTRIBUTE_SYSTEM: + uiAttribs |= ATTRIB_SYSTEM; + break; + case FILE_ATTRIBUTE_TEMPORARY: + uiAttribs |= ATTRIB_TEMPORARY; + break; + case FILE_ATTRIBUTE_COMPRESSED: + uiAttribs |= ATTRIB_COMPRESSED; + break; + case FILE_ATTRIBUTE_OFFLINE: + uiAttribs |= ATTRIB_OFFLINE; + break; + } + } +#else +#endif + return true; +} + +bool vfs::OS::deleteRealFile(vfs::Path const& sDir) +{ +#ifdef WIN32 + BOOL del = vfs::Settings::getUseUnicode() ? + DeleteFileW( sDir.c_str() ) : + DeleteFileA( vfs::String::narrow(sDir.c_str(), sDir.length()).c_str() ); + if(!del) + { + DWORD err = GetLastError(); + if(err != NO_ERROR) + { + VFS_LOG_ERROR(L"Could not delete file"); + } + } + return (del != FALSE); +#else + return (remove( vfs::String::as_utf8(sDir()).c_str() ) == 0); +#endif +} + +void vfs::OS::getExecutablePath(vfs::Path& sDir, vfs::Path& sFile) +{ +#ifdef WIN32 + DWORD error; + if(!vfs::Settings::getUseUnicode()) + { + char path[256]; + if( 0 != (error = ::GetModuleFileNameA(NULL, path, 256)) ) + { + vfs::Path(vfs::String::widen(path,256)).splitLast(sDir, sFile); + } + } + else + { + wchar_t path[256]; + if( 0 != (error = ::GetModuleFileNameW(NULL, path, 256)) ) + { + vfs::Path(path).splitLast(sDir, sFile); + } + } + if(error == 0) + { + DWORD code = GetLastError(); + VFS_THROW(_BS(L"Could not get current directory [") << + (!vfs::Settings::getUseUnicode() ? L"no unicode" : L"unicode") << + L"], error code : " << code << _BS::wget); + } +#else + char buf[256]; + ssize_t size = readlink("/proc/self/exe", buf, 256); + if(size == -1) + { + vfs::String err = strerror(errno); + VFS_THROW(err); + } + buf[size] = 0; + vfs::Path exedir(buf); + exedir.splitLast(sDir, sFile); +#endif +} + +void vfs::OS::getCurrentDirectory(vfs::Path& sPath) +{ +#ifdef WIN32 + DWORD error; + vfs::Path path; + if( !vfs::Settings::getUseUnicode() ) + { + char path[256]; + if( 0 != (error = ::GetCurrentDirectoryA(256, path)) ) + { + sPath = vfs::Path(vfs::String::widen(path,256)); + } + } + else + { + wchar_t path[256]; + if( 0 != (error = ::GetCurrentDirectoryW(256, path)) ) + { + sPath = vfs::Path(path); + } + } + if(error == 0) + { + DWORD code = GetLastError(); + VFS_THROW(_BS(L"Could not determine current directory ") << + (!vfs::Settings::getUseUnicode() ? L"[no unicode]" : L"[unicode]") << + L", error code : " << _BS::wget); + } +#else + char* cwd = getcwd(NULL,0); + if(!cwd) + { + vfs::String err = strerror(errno); + VFS_THROW(err); + } + sPath = cwd; + free(cwd); +#endif +} + +void vfs::OS::setCurrectDirectory(vfs::Path const& sPath) +{ +#ifdef WIN32 + if(!vfs::Settings::getUseUnicode()) + { + std::string str; + vfs::String::narrow( sPath.c_wcs(), str ); + VFS_THROW_IFF( ::SetCurrentDirectoryA( str.c_str() ) == TRUE, + _BS(L"Could not set current directory [no unicode] : ") << sPath << _BS::wget ); + } + else + { + VFS_THROW_IFF( ::SetCurrentDirectoryW( sPath.c_str() ) == TRUE, + _BS(L"Could not set current directory [unicode] : ") << sPath <<_BS::wget ); + } +#else + if(chdir(sPath.to_string().c_str()) != 0) + { + vfs::String err = strerror(errno); + VFS_THROW(err); + } +#endif +} + +bool vfs::OS::getEnv(vfs::String const& key, vfs::String& value) +{ +#ifdef _MSC_VER + wchar_t *val_buf = NULL; + ::size_t buf_len; + errno_t err = _wdupenv_s(&val_buf,&buf_len, key.c_str()); + if(err == 0 && val_buf) + { + // success + value = val_buf; + free(val_buf); + } + return err == 0; +#else + char* val_buf = getenv(key.utf8().c_str()); + if(val_buf) + { + value = val_buf; + return true; + } + return false; +#endif +} diff --git a/ext/VFS/src/Core/vfs_path.cpp b/ext/VFS/src/Core/vfs_path.cpp new file mode 100644 index 000000000..a373cbeb0 --- /dev/null +++ b/ext/VFS/src/Core/vfs_path.cpp @@ -0,0 +1,599 @@ +/* + * bfVFS : vfs/Core/vfs_path.cpp + * - Path class, stores and validates a file/directory path string, offers meaningful path operations + * - path comparison functions (operator overloading) + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include + +#include +#include + +typedef struct{ vfs::String::size_t start, end; } t_env; + +bool vfs::Path::expandEnv() +{ + vfs::String::ptr_t raw_ptr = &_path[0]; + std::stack pos; + vfs::Int32 pos_start = -1, pos_end = -1, pos_current = 0; + while(*raw_ptr != 0) + { + if(*raw_ptr == L'$') + { + pos_start = pos_current; + } + else if(pos_start >= 0) + { + if(*raw_ptr == '(' && pos_current == (pos_start+1)) + { + // ensure the syntax $(VARNAME) is followed + pos_end = pos_start; + } + //else + //{ + // pos_start = pos_end = -1; + //} + else if(pos_start == pos_end && *raw_ptr == ')') + { + pos_end = pos_current; + } + // + if(pos_end >= 0 && pos_start != pos_end) + { + t_env e; + e.start = pos_start; + e.end = pos_end; + pos.push(e); + pos_start = pos_end = -1; + } + } + pos_current++; + raw_ptr++; + } + if(!pos.empty()) + { + while(!pos.empty()) + { + t_env v = pos.top(); + vfs::String var_name = _path.substr(v.start+2, v.end-v.start-2); + vfs::String var_value; + if(!vfs::OS::getEnv(var_name, var_value)) + { + VFS_LOG_WARNING(_BS(L"Could not expand environment variable : ") << var_name << _BS::wget); + return false; + } + _path.replace(v.start,v.end-v.start+1,var_value.c_wcs()); + pos.pop(); + } + doCheck(); + } + return true; +} + +static void unifySeparators(vfs::String::str_t &sPath) +{ + vfs::String::char_t &raw = sPath[0]; + vfs::String::ptr_t raw_ptr = &raw; + while(*raw_ptr != 0) + { + if(*raw_ptr == '\\' || *raw_ptr == '/') + { + *raw_ptr = vfs::Const::SEPARATOR_CHAR(); + } + raw_ptr++; + } +} + +/** + * call after unifying separators + */ +static vfs::UInt32 removeSeparators(vfs::String::str_t &str) +{ + vfs::UInt32 sepcount = 0; + vfs::Int32 numsep = 0; + ::size_t put_pos = 0; + ::size_t len = str.length(); + vfs::String::char_t& raw = str[0]; + vfs::String::ptr_t old_ptr = &raw; + vfs::String::ptr_t new_ptr = &raw; + vfs::String::ptr_t last_ptr = &raw; + vfs::String::char_t sep = vfs::Const::SEPARATOR_CHAR(); + while(*old_ptr != 0) + { + if(*old_ptr == sep) + { + numsep++; + if(numsep == 1) + { + sepcount++; + } + } + else + { + // we have normal text (again) + numsep = 0; + } + if(numsep <= 1) + { + *new_ptr = *old_ptr; + last_ptr = new_ptr++; + put_pos++; + } + old_ptr++; + } + if(*last_ptr == sep) + { + put_pos--; + if(sepcount>0) + { + sepcount--; + } + } + if(put_pos < len) + { + str.erase(put_pos); + } + return sepcount; +} + +static void removeLastSeparator(vfs::String::str_t &str) +{ + if( *str.rbegin() == vfs::Const::SEPARATOR_CHAR() ) + { + str.erase( str.length()-1); + } +} + +static void removeDots(vfs::String::str_t &str, vfs::UInt32 number_of_separators) +{ + vfs::String::char_t& raw = str[0]; + vfs::String::ptr_t old_ptr = &raw; + vfs::String::ptr_t new_ptr = &raw; + vfs::String::size_t LENGTH = str.length(); + bool dirty = false; + + // see if we start with ./ (not . as this might be a hidden files on unix systems) + if( (LENGTH > 1) && (*old_ptr == vfs::Const::DOT_CHAR()) && (*(old_ptr+1) == vfs::Const::SEPARATOR_CHAR()) ) + { + old_ptr += 2; + dirty = true; + } + + std::vector sub_strings; + sub_strings.resize(number_of_separators); + int pos=0; + + if(*old_ptr != 0 && *old_ptr == vfs::Const::SEPARATOR_CHAR()) + { + if(!dirty) + { + // in-place : just move along + new_ptr++; + old_ptr++; + } + else + { + *new_ptr++ = *old_ptr++; + } + } + else + { + } + sub_strings[pos++] = new_ptr; + + while(*old_ptr != 0) + { + if(*old_ptr != vfs::Const::SEPARATOR_CHAR()) + { + if(!dirty) + { + new_ptr++; + old_ptr++; + } + else + { + *new_ptr++ = *old_ptr++; + } + continue; + } + + *new_ptr++ = *old_ptr++; + sub_strings[pos++] = new_ptr; + + if((&raw+3) < old_ptr) + { + if( (*(old_ptr-4) == vfs::Const::SEPARATOR_CHAR()) && + (*(old_ptr-3) == vfs::Const::DOT_CHAR()) && + (*(old_ptr-2) == vfs::Const::DOT_CHAR()) && + (*(old_ptr-1) == vfs::Const::SEPARATOR_CHAR()) ) + { + if(pos > 1) + { + new_ptr = sub_strings[pos-3]; + pos -= 2; + dirty = true; + } + } + else if((*(old_ptr-3) == vfs::Const::SEPARATOR_CHAR()) && + (*(old_ptr-2) == vfs::Const::DOT_CHAR()) && + (*(old_ptr-1) == vfs::Const::SEPARATOR_CHAR()) ) + { + if(pos > 0) + { + new_ptr = sub_strings[pos-2]; + pos -= 1; + dirty = true; + } + } + } + else if((&raw+2) < old_ptr) + { + if( (*(old_ptr-3) == vfs::Const::SEPARATOR_CHAR()) && + (*(old_ptr-2) == vfs::Const::DOT_CHAR()) && + (*(old_ptr-1) == vfs::Const::SEPARATOR_CHAR()) ) + { + if(pos > 0) + { + new_ptr = sub_strings[pos-2]; + pos -= 1; + dirty = true; + } + } + } + } + + ::size_t ttt = (new_ptr - &raw); + if(ttt < LENGTH) + { + str.erase(ttt); + } +} + +static void getFirstLastSeparator(const vfs::String::char_t* sPath, vfs::size_t &iFirst, vfs::size_t &iLast) +{ + iFirst = vfs::npos; + iLast = vfs::npos; + const vfs::String::char_t* ptr = sPath; + vfs::size_t pos = 0; + while(*ptr != 0) + { + if(*ptr == vfs::Const::SEPARATOR_CHAR()) + { + if(iFirst == vfs::npos) + { + iFirst = pos; + } + iLast = pos; + } + pos++; + ptr++; + } +} + +////////////////////////////////////////////////////////////////////// +bool vfs::Path::Less::operator ()(vfs::Path const& s1, vfs::Path const& s2) const +{ + return vfs::String::less(s1._path.c_str(), s2._path.c_str()); +} +bool vfs::Path::Equal::operator ()(vfs::Path const& s1, vfs::Path const& s2) const +{ + return vfs::String::equal(s1._path.c_str(), s2._path.c_str()); +} +////////////////////////////////////////////////////////////////////// + +vfs::Path::Path() +{ +} + +vfs::Path::Path(vfs::String const& sPath) +: _path(sPath.c_wcs()) +{ + doCheck(); +} + +vfs::Path::Path(const char* sPath) +{ + if(vfs::Settings::getUseUnicode()) + { + vfs::String::as_utf16(sPath,_path); + } + else + { + vfs::String::widen(std::string(sPath),_path); + } + doCheck(); +} + +vfs::Path::Path(std::string const& sPath) +{ + if(vfs::Settings::getUseUnicode()) + { + vfs::String::as_utf16(sPath,_path); + } + else + { + vfs::String::widen(sPath,_path); + } + doCheck(); +} + +vfs::Path::Path(const wchar_t* sPath) +: _path(sPath) +{ + doCheck(); +} + +const vfs::String::char_t* vfs::Path::c_str() const +{ + return _path.c_str(); +} + +const vfs::String::str_t& vfs::Path::c_wcs() const +{ + return _path; +} + +const vfs::String::str_t& vfs::Path::operator()() const +{ + return _path; +} + +std::string vfs::Path::to_string() const +{ + if(vfs::Settings::getUseUnicode()) + { + return vfs::String::as_utf8(_path); + } + else + { + std::string s; + vfs::String::narrow(_path,s); + return s; + } +} + +bool vfs::Path::empty() const +{ + // is there a case where a non-empty string can become empty after a check? + // if it is so then i don't care + return _path.empty(); +} +vfs::String::size_t vfs::Path::length() const +{ + return _path.length(); +} + + +void vfs::Path::doCheck() +{ + if(!_path.empty()) + { + unifySeparators(_path); + + vfs::UInt32 number_of_separators = removeSeparators(_path); + + if(number_of_separators>0) + { + removeDots(_path,number_of_separators+1); + getFirstLastSeparator(_path.c_str(),_sep.first,_sep.last); + } + } +} + +static void pathSplitLast(vfs::String::str_t const& path, + vfs::String::str_t &head, + vfs::String::str_t &last, + vfs::size_t const& sep_first, + vfs::size_t const& sep_last) +{ + if(path.empty()) + { + return; + } + if(&head == &path || &last == &path) + { + VFS_THROW(L"cannot use output parameters that are equal to 'this'"); + } +#if 1 + // use results from "GetFirstLastSeparator(..)" + if(sep_last != vfs::npos) + { + head.assign(path.substr(0,sep_last)); + last.assign(path.substr(sep_last+1, path.length()-sep_last-1)); + return; + } +#else + vfs::String::size_t position = path.length(); + while(--position != vfs::npos) + { + vfs::String::char_t const& c = path.at(position); + if(c == '\\' || c == '/') + { + break; + } + } + if(position != vfs::npos) + { + head.assign(path.substr(0,position++)); + last.assign(path.substr(position,path.length()-position)); + return; + } +#endif + head.assign(vfs::Const::EMPTY()); + last.assign(path); +} + + +void vfs::Path::splitLast(vfs::Path &rsHead, vfs::Path &rsLast) const +{ + + pathSplitLast(_path, rsHead._path, rsLast._path, _sep.first, _sep.last); + getFirstLastSeparator(rsHead.c_str(), rsHead._sep.first, rsHead._sep.last); + getFirstLastSeparator(rsLast.c_str(), rsLast._sep.first, rsLast._sep.last); + // no need to check, as the original path is already checked + //rPath.DoCheck(); + //rFile.DoCheck(); +} + +static void pathSplitFirst(vfs::String::str_t const& path, + vfs::String::str_t &first, + vfs::String::str_t &tail, + vfs::size_t const& sep_first, + vfs::size_t const& sep_last) +{ + if(path.empty()) + { + return; + } + if(&first == &path || &tail == &path) + { + VFS_THROW(L"cannot use output parameters that are equal to 'this'"); + } + +#if 1 + // use results from "GetFirstLastSeparator(..)" + if(sep_first != vfs::npos) + { + first.assign(path.substr(0,sep_first)); + tail.assign(path.substr(sep_first+1, path.length()-sep_first-1)); + return; + } +#else + vfs::String::size_t position = 0; + while(position < path.length()) + { + vfs::String::char_t const& c = path.at(position); + if(c == '\\' || c == '/') + { + break; + } + position++; + } + if(position < path.length()) + { + first.assign(path.substr(0,position++)); + tail.assign(path.substr(position,path.length()-position)); + return; + } +#endif + first.assign(path); + tail.assign(vfs::Const::EMPTY()); +} + +void vfs::Path::splitFirst(vfs::Path &rsFirst, vfs::Path &rsTail) const +{ + pathSplitFirst(_path, rsFirst._path, rsTail._path, _sep.first, _sep.last); + getFirstLastSeparator(rsFirst.c_str(), rsFirst._sep.first, rsFirst._sep.last); + getFirstLastSeparator(rsTail.c_str(), rsTail._sep.first, rsTail._sep.last); + // no need to check, as the original path is already checked + //rPath.doCheck(); + //rFile.doCheck(); +} + +bool vfs::Path::extension(vfs::String &sExt) const +{ + if(_path.empty()) + { + return false; + } + vfs::String::size_t SIZE = _path.length(); + if(_path.at(SIZE-1) == L'.') + { + // not an extension + return false; + } + for(vfs::String::size_t i=SIZE-2; i > 0; i--) + { + if(_path.at(i) == L'.') + { + sExt.r_wcs().assign(&_path.at(i+1),SIZE-i-1); + return true; + } + } + return false; +} + +vfs::Path& vfs::Path::operator+=(vfs::String const& p) +{ + return *this += vfs::Path(p); +} + +vfs::Path& vfs::Path::operator+=(vfs::Path const& p) +{ + if(_path.empty()) + { + _path = p._path; + } + else if(!p.empty()) + { + _path += vfs::Const::SEPARATOR(); + _path += p._path; + getFirstLastSeparator(_path.c_str(),_sep.first,_sep.last); + } + return *this; +} + +vfs::Path operator+(vfs::Path const& p1, vfs::Path const& p2) +{ + vfs::Path newpath = p1; + newpath += p2; + return newpath; +} + +bool vfs::Path::operator==(vfs::Path const& p2) +{ + return vfs::String::equal(_path.c_str(), p2._path.c_str()); +} + +bool operator==(vfs::Path const& p1, vfs::Path const& p2) +{ + return vfs::StrCmp::Equal(p1.c_str(), p2.c_str()); +} +bool operator==(vfs::Path const& p1, vfs::String const& p2) +{ + return vfs::StrCmp::Equal(p1.c_str(), p2); +} +bool operator==(vfs::Path const& p1, vfs::String::str_t const& p2) +{ + return vfs::StrCmp::Equal(p1.c_str(), p2); +} +bool operator==(vfs::Path const& p1, const vfs::String::char_t* p2) +{ + return vfs::StrCmp::Equal(p1.c_str(), p2); +} + +template<> +BuildString& BuildString::add(vfs::Path const& value) +{ + this->add(value.c_str()); + return *this; +} + +template<> +BuildString& BuildString::operator<< (vfs::Path const& value) +{ + this->add(value.c_str()); + return *this; +} diff --git a/ext/VFS/src/Core/vfs_profile.cpp b/ext/VFS/src/Core/vfs_profile.cpp new file mode 100644 index 000000000..ea0fee10e --- /dev/null +++ b/ext/VFS/src/Core/vfs_profile.cpp @@ -0,0 +1,432 @@ +/* + * bfVFS : vfs/Core/vfs_profile.cpp + * - Virtual Profile, container for real file system locations or archives + * - Profile Stack, orders profiles in a linear fashion (top-bottom) + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include + + +class vfs::CVirtualProfile::IterImpl : public vfs::CVirtualProfile::Iterator::IImplementation +{ + friend class vfs::CVirtualProfile; + typedef vfs::CVirtualProfile::Iterator::IImplementation tBaseClass; + + IterImpl(CVirtualProfile* profile) : tBaseClass(), m_profile(profile) + { + VFS_THROW_IFF(profile, L""); + // only unique locations + _loc_iter = m_profile->m_setLocations.begin(); + } +public: + IterImpl() : tBaseClass(), m_profile(NULL) + {}; + virtual ~IterImpl() + {}; + ////// + virtual vfs::IBaseLocation* value() + { + if(_loc_iter != m_profile->m_setLocations.end()) + { + return *_loc_iter; + } + return NULL; + } + virtual void next() + { + if(_loc_iter != m_profile->m_setLocations.end()) + { + _loc_iter++; + } + } +protected: + virtual tBaseClass* clone() + { + IterImpl* iter = new IterImpl(); + iter->m_profile = m_profile; + iter->_loc_iter = _loc_iter; + return iter; + } +private: + vfs::CVirtualProfile* m_profile; + vfs::CVirtualProfile::tUniqueLoc::iterator _loc_iter; +}; + +/***************************************************************************/ +/***************************************************************************/ + +class vfs::CVirtualProfile::FileIterImpl : public vfs::CVirtualProfile::FileIterator::IImplementation +{ + friend class vfs::CVirtualProfile; + typedef vfs::CVirtualProfile::FileIterator::IImplementation tBaseClass; + FileIterImpl(vfs::Path const& sPattern, CVirtualProfile* profile); + +public: + FileIterImpl() : tBaseClass(), m_profile(NULL) + {}; + virtual ~FileIterImpl() + {}; + ///// + virtual vfs::IBaseFile* value() + { + return file; + } + virtual void next(); +protected: + virtual tBaseClass* clone() + { + FileIterImpl* iter2 = new FileIterImpl(); + iter2->m_pattern = m_pattern; + iter2->m_profile = m_profile; + iter2->iter = iter; + iter2->fiter = fiter; + iter2->file = file; + return iter2; + } +private: + vfs::Path m_pattern; + vfs::CVirtualProfile* m_profile; + vfs::CVirtualProfile::Iterator iter; + vfs::IBaseLocation::Iterator fiter; + vfs::IBaseFile* file; +}; + +vfs::CVirtualProfile::FileIterImpl::FileIterImpl(vfs::Path const& sPattern, CVirtualProfile* profile) +: tBaseClass(), m_pattern(sPattern), m_profile(profile) +{ + VFS_THROW_IFF(profile, L""); + iter = m_profile->begin(); + while(!iter.end()) + { + fiter = iter.value()->begin(); + while(!fiter.end()) + { + file = fiter.value(); + if( matchPattern(m_pattern(), file->getPath()()) ) + { + return; + } + fiter.next(); + } + iter.next(); + } + file = NULL; +} + +void vfs::CVirtualProfile::FileIterImpl::next() +{ + if(!fiter.end()) + { + fiter.next(); + } + while(!iter.end()) + { + while(!fiter.end()) + { + file = fiter.value(); + if( matchPattern(m_pattern(), file->getPath()()) ) + { + return; + } + fiter.next(); + } + iter.next(); + if(!iter.end()) + { + fiter = iter.value()->begin(); + } + } + file = NULL; +} + +/***************************************************************************/ +/***************************************************************************/ + +vfs::CVirtualProfile::CVirtualProfile(vfs::String const& profile_name, vfs::Path profile_root, bool writable) +: cName(profile_name), cRoot(profile_root), cWritable(writable) +{ +} + +vfs::CVirtualProfile::~CVirtualProfile() +{ + tUniqueLoc::iterator it = m_setLocations.begin(); + for(; it != m_setLocations.end(); ++it) + { + delete (*it); + //(*it) = NULL; + } + m_setLocations.clear(); + m_mapLocations.clear(); +}; + +vfs::CVirtualProfile::Iterator vfs::CVirtualProfile::begin() +{ + return Iterator(new IterImpl(this)); +} + +vfs::CVirtualProfile::FileIterator vfs::CVirtualProfile::files(vfs::Path const& sPattern) +{ + return FileIterator( new FileIterImpl(sPattern, this)); +} + +void vfs::CVirtualProfile::addLocation(vfs::IBaseLocation* pLoc) +{ + if(pLoc) + { + m_setLocations.insert(pLoc); + std::list lDirs; + pLoc->getSubDirList(lDirs); + std::list::const_iterator cit = lDirs.begin(); + for(;cit != lDirs.end(); ++cit) + { + vfs::IBaseLocation *pOldLoc = m_mapLocations[*cit]; + if(!pOldLoc) + { + m_mapLocations[*cit] = pLoc; + } + else if(pOldLoc == pLoc) + { + // seems to be an update. do nothing + } + else + { + VFS_LOG_WARNING((L"Another location is already mapped to '" + ((*cit)()) + L"' [keeping old location]").c_str()); + //VFS_THROW(L"Location already taken"); + } + } + } +} + +vfs::IBaseLocation* vfs::CVirtualProfile::getLocation(vfs::Path const& sPath) const +{ + tLocations::const_iterator it = m_mapLocations.find(sPath); + if(it != m_mapLocations.end()) + { + return it->second; + } + return NULL; +} + +vfs::IBaseFile* vfs::CVirtualProfile::getFile(vfs::Path const& sPath) const +{ + vfs::Path sDir,sFile; + sPath.splitLast(sDir,sFile); + tLocations::const_iterator it = m_mapLocations.find(sDir); + if(it != m_mapLocations.end()) + { + return it->second->getFile(sPath); + } + return NULL; +} + + +/***************************************************************************/ +/***************************************************************************/ + +class vfs::CProfileStack::IterImpl : public vfs::CProfileStack::Iterator::IImplementation +{ + friend class CProfileStack; + typedef CProfileStack::Iterator::IImplementation tBaseClass; + + IterImpl(CProfileStack* pPStack) : tBaseClass(), m_pPStack(pPStack) + { + VFS_THROW_IFF(m_pPStack, L""); + _prof_iter = m_pPStack->m_profiles.begin(); + } +public: + IterImpl() : tBaseClass(), m_pPStack(NULL) + {}; + ~IterImpl() + {}; + ////// + virtual vfs::CVirtualProfile* value() + { + if(_prof_iter != m_pPStack->m_profiles.end()) + { + return *_prof_iter; + } + return NULL; + } + virtual void next() + { + if(_prof_iter != m_pPStack->m_profiles.end()) + { + _prof_iter++; + } + } +protected: + virtual tBaseClass* clone() + { + IterImpl* iter = new IterImpl(); + iter->m_pPStack = m_pPStack; + iter->_prof_iter = _prof_iter; + return iter; + } +private: + vfs::CProfileStack* m_pPStack; + std::list::iterator _prof_iter; +}; + +/***************************************************************************/ +/***************************************************************************/ +vfs::CProfileStack::CProfileStack() +{ +} + +vfs::CProfileStack::~CProfileStack() +{ + t_profiles::iterator it = m_profiles.begin(); + for(; it != m_profiles.end(); ++it) + { + delete (*it); + (*it) = NULL; + } + m_profiles.clear(); +} + +vfs::CVirtualProfile* vfs::CProfileStack::getProfile(vfs::String const& sName) const +{ + t_profiles::const_iterator it = m_profiles.begin(); + for(;it != m_profiles.end(); ++it) + { + if( StrCmp::EqualCase((*it)->cName, sName) ) + { + return *it; + } + } + return NULL; +} + +vfs::CVirtualProfile* vfs::CProfileStack::getWriteProfile() +{ + t_profiles::const_iterator it = m_profiles.begin(); + for(;it != m_profiles.end(); ++it) + { + if((*it)->cWritable) + { + return *it; + } + } + return NULL; +} + +vfs::CVirtualProfile* vfs::CProfileStack::topProfile() const +{ + if(!m_profiles.empty()) + { + return m_profiles.front(); + } + return NULL; +} + +bool vfs::CProfileStack::popProfile() +{ + // there might be some files in this profile that are referenced in a Log object + // we need to it to release the file + vfs::Log::flushReleaseAll(); + // an observer pattern would probably be the better solution, + // but for now lets do it this way + + vfs::CVirtualProfile* prof = this->topProfile(); + if(prof) + { + vfs::CVirtualProfile::Iterator loc_it = prof->begin(); + for(; !loc_it.end(); loc_it.next()) + { + vfs::IBaseLocation* loc = loc_it.value(); + vfs::IBaseLocation::Iterator f_it = loc->begin(); + for(; !f_it.end(); f_it.next()) + { + vfs::IBaseFile* file = f_it.value(); + vfs::Path sDir, sFile; + if(file) + { + file->getPath().splitLast(sDir,sFile); + vfs::CVirtualLocation* vloc = getVFS()->getVirtualLocation(sDir); + if(vloc) + { + if( !vloc->removeFile(file) ) + { + VFS_THROW(_BS(L"Could not remove file [") << file->getPath() + << L"] in Profile [" << prof->cName << L"]" << _BS::wget); + } + } + else + { + VFS_THROW(_BS(L"Virtual location [") << sDir + << L"] doesn't exist. Maybe the VFS was not properly setup." << _BS::wget); + } + } + else + { + VFS_THROW(_BS(L"File is NULL during iteration over files in location [") + << loc->getPath() << L"]" << _BS::wget); + } + } + } + // delete only when nothing went wrong + this->m_profiles.pop_front(); + delete prof; + } + return true; +} + +void vfs::CProfileStack::pushProfile(CVirtualProfile* pProfile) +{ + if(!getProfile(pProfile->cName)) + { + if(pProfile->cWritable) + { + m_profiles.push_front(pProfile); + } + else + { + t_profiles::iterator pit = m_profiles.begin(); + while(pit != m_profiles.end() && (*pit)->cWritable) + { + pit++; + } + //if(pit != m_profiles.end()) + { + m_profiles.insert(pit,pProfile); + } + //else + //{ + // m_profiles.push_front(pProfile); + //} + } + return; + } + VFS_THROW(L"A profile with this name already exists"); +} + +vfs::CProfileStack::Iterator vfs::CProfileStack::begin() +{ + return Iterator(new IterImpl(this)); +} + diff --git a/ext/VFS/src/Core/vfs_string.cpp b/ext/VFS/src/Core/vfs_string.cpp new file mode 100644 index 000000000..3f1fea84f --- /dev/null +++ b/ext/VFS/src/Core/vfs_string.cpp @@ -0,0 +1,596 @@ +/* + * bfVFS : vfs/Core/vfs_string.cpp + * - string class that allows conversions to/from Unicode representation (uses wchar_t internally) + * - comparison, concatenation, stream output class/functions + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include +#include +#include + +#include +//////////////////////////////////////////////////////////////////// + +namespace _StrCmp +{ + //////////////////////////////////////////////////////////////// + static inline void Advance( const char*& s1, const char*& s2 ) + { + while (*s1 && *s2 && toupper(*s1) == toupper(*s2)) + { + ++s1; + ++s2; + } + } + static inline void Advance( const wchar_t*& s1, const wchar_t*& s2 ) + { + // should be 'towupper' + while (*s1 && *s2 && toupper(*s1) == toupper(*s2)) + { + ++s1; + ++s2; + } + } + template + static inline void AdvanceCase( const CharType*& s1, const CharType*& s2 ) + { + while (*s1 && *s2 && (*s1 == *s2)) + { + ++s1; + ++s2; + } + } + //////////////////////////////////////////////////////////////// + template + static inline bool Equal( const CharType* s1, const CharType* s2 ) + { + return !(*s1 || *s2); + } + //////////////////////////////////////////////////////////////// + static inline bool Less( const wchar_t* s1, const wchar_t* s2 ) + { + if (!*s1) return *s2 != 0; + if (!*s2) return false; + // should be 'towupper' + return toupper(*s1) < toupper(*s2); + } + static inline bool Less( const char* s1, const char* s2 ) + { + if (!*s1) return *s2 != 0; + if (!*s2) return false; + return toupper(*s1) < toupper(*s2); + } + template + static inline bool LessCase( const CharType* s1, const CharType* s2 ) + { + if (!*s1) return *s2 != 0; + if (!*s2) return false; + return (*s1) < (*s2); + } +} + +//////////////////////////////////////////////////////////////////// + +bool vfs::String::lessCase(const vfs::String::char_t* s1, const vfs::String::char_t* s2) +{ + _StrCmp::AdvanceCase(s1,s2); + return _StrCmp::LessCase(s1,s2); + +} + +bool vfs::String::less(const vfs::String::char_t* s1, const vfs::String::char_t* s2) +{ + _StrCmp::Advance(s1,s2); + return _StrCmp::Less(s1,s2); +} + +bool vfs::String::equalCase(const vfs::String::char_t* s1, const vfs::String::char_t* s2) +{ + _StrCmp::AdvanceCase(s1,s2); + return _StrCmp::Equal(s1,s2); +} + +bool vfs::String::equal(const vfs::String::char_t* s1, const vfs::String::char_t* s2) +{ + _StrCmp::Advance(s1,s2); + return _StrCmp::Equal(s1,s2); +} + +//////////////////////////////////////////////////////////////////// +/// class constructors +//////////////////////////////////////////////////////////////////// +vfs::String::String() +{ +} +vfs::String::String(const char* str) +{ + vfs::String::as_utf16(str,_str); +} +vfs::String::String(std::string const& str) +{ + vfs::String::as_utf16(str,_str); +} +vfs::String::String(const wchar_t* str) +{ + _str.assign(str); +} +vfs::String::String(std::wstring const& str) +{ + _str.assign(str); +} + +//////////////////////////////////////////////////////////////////// +/// static class methods +//////////////////////////////////////////////////////////////////// +vfs::String::str_t vfs::String::as_utf16(std::string const& str) +{ + vfs::String::str_t s; + vfs::String::as_utf16(str, s); + return s; +} +void vfs::String::as_utf16(std::string const& str, vfs::String::str_t &str16) +{ + try + { + ::size_t d = utf8::distance(str.begin(), str.end()); + if(d > 0) + { + str16.resize(d); + utf8::utf8to16(str.begin(), str.end(), &str16[0]); + } + } + catch(utf8::invalid_utf8& ex) + { + utf8::uint8_t c = ex.utf8_octet(); + VFS_THROW( _BS(L"Invalid UTF8 character '") << (wchar_t)c << L"'=" << (unsigned char)c <<_BS::wget ); + } + catch(utf8::not_enough_room &ex) + { + std::wstring err; + VFS_IGNOREEXCEPTION(vfs::String::as_utf16(ex.what(),err), true); + VFS_THROW( _BS(L"Incomplete UTF8 string [") << err << L"]" << _BS::wget ); + } + catch(...) + { + VFS_THROW(L"Unicode error"); + } +} + +vfs::String::str_t vfs::String::as_utf16(const char* str) +{ + vfs::String::str_t s; + vfs::String::as_utf16(str, s); + return s; +} +void vfs::String::as_utf16(const char* str, vfs::String::str_t &str16) +{ + if(str == NULL) + { + return; + } + try + { + ::size_t len = strlen(str); + ::size_t d = utf8::distance(str,str+len); + if(d > 0) + { + str16.resize(d); + utf8::utf8to16(str, str+len, &str16[0]); + } + } + catch(utf8::invalid_utf8& ex) + { + utf8::uint8_t c = ex.utf8_octet(); + VFS_THROW( _BS(L"Invalid UTF8 character '") << (wchar_t)c << L"'=" << (unsigned char)c << _BS::wget ); + } + catch(utf8::not_enough_room &ex) + { + std::wstring err; + VFS_IGNOREEXCEPTION(vfs::String::as_utf16(ex.what(), err), true); + VFS_THROW( _BS(L"Incomplete UTF8 string [") << err << L"]" << _BS::wget ); + } +} + +std::string vfs::String::as_utf8(vfs::String const& str) +{ + return str.utf8(); +} +std::string vfs::String::as_utf8(std::wstring const& str) +{ + if(str.empty()) + { + return ""; + } +#if 0 + std::string s; + utf8::utf16to8(str.begin(), str.end(), std::back_inserter(s)); +#else + const int UTF8_MAX_CHARS = 4; + std::vector buffer(str.length()+UTF8_MAX_CHARS); + ::size_t pos_in=0, pos_out=0; + while(pos_in < str.length()) + { + if( (pos_out+UTF8_MAX_CHARS) >= buffer.size() ) + { + buffer.resize(buffer.size()+str.length()); + } + pos_out = utf8::append(str.at(pos_in++), &buffer[pos_out]) - &buffer[0]; + } + std::string s(&buffer[0],pos_out); +#endif + return s; +} + +// if 'strlength' is 0, length is determined automatically +std::string vfs::String::as_utf8(const wchar_t* str, vfs::String::size_t strlength) +{ + std::string s; + if(str != NULL) + { + ::size_t len = strlength; + if(len == 0) + { + len = wcslen(str); + } + if(len != 0) + { + utf8::utf16to8(str,str+len,std::back_inserter(s)); + } + } + return s; +} + +// convenience method, for the case it should be used in generic code (overloading) +std::string vfs::String::as_utf8(std::string const& str) +{ + return str; +} + +vfs::String::size_t vfs::String::narrow(std::wstring const& src, std::string& dst) +{ + vfs::String::size_t len = vfs::String::narrow(src.c_str(),src.length(),NULL,0); + if(len > 0) + { + dst.resize(len); + return vfs::String::narrow(src.c_str(),src.length(),&dst[0],len); + } + return 0; +} +std::string vfs::String::narrow(wchar_t const* str, vfs::String::size_t length) +{ + std::string s; + vfs::String::size_t len = vfs::String::narrow(str,length,NULL,0); + if(len > 0) + { + s.resize(len); + vfs::String::narrow(str,length,&s[0],len); + } + return s; +} +vfs::String::size_t vfs::String::narrow(wchar_t const* src_str, vfs::String::size_t src_len, char* dst_str, vfs::String::size_t dst_len) +{ + if(src_str && src_len>0) + { + if(!dst_str || dst_len==0) + { + return wcstombs(NULL, src_str, src_len); + } + return wcstombs(dst_str, src_str, std::min(src_len,dst_len)); + } + return 0; +} +// +std::wstring vfs::String::widen(char const* str, vfs::String::size_t length) +{ + std::wstring ws; + vfs::String::size_t len = vfs::String::widen(str,length,NULL,0); + if(len > 0) + { + ws.resize(len); + vfs::String::widen(str,length,&ws[0],len); + } + return ws; +} +vfs::String::size_t vfs::String::widen(std::string const& src, std::wstring& dst) +{ + vfs::String::size_t len = vfs::String::widen(src.c_str(),src.length(),NULL,0); + if(len > 0) + { + dst.resize(len); + return vfs::String::widen(src.c_str(),src.length(),&dst[0],len); + } + return 0; +} +vfs::String::size_t vfs::String::widen(char const* src_str, size_t src_len, wchar_t* dst_str, size_t dst_len) +{ + if(src_str && src_len>0) + { + if(!dst_str || dst_len==0) + { + return mbstowcs(NULL, src_str, src_len); + } + return mbstowcs(dst_str, src_str, std::min(src_len,dst_len)); + } + return 0; +} + + +//////////////////////////////////////////////////////////////////// +bool vfs::String::empty() const +{ + return _str.empty(); +} +vfs::String::size_t vfs::String::length() const +{ + return _str.length(); +} + +vfs::String vfs::String::operator+(vfs::String const& str) +{ + return vfs::String(_str + str._str); +} +vfs::String vfs::String::operator+=(vfs::String const& str) +{ + _str += str._str; + return vfs::String(_str); +} + +//////////////////////////////////////////////////////////////// + +bool vfs::operator<(vfs::String const& s1, vfs::String const& s2) +{ + return s1._str < s2._str; +} + +std::wostream& operator<<(std::wostream& out, vfs::String const& str) +{ + out.write(str.c_str(), (std::streamsize)str.length()); + return out; +} + +std::wostream& operator<<(std::wostream& out, vfs::String::str_t const& str) +{ + out.write(str.c_str(), (std::streamsize)str.length()); + return out; +} + +std::wostream& operator<<(std::wostream& out, const vfs::String::char_t* str) +{ + out.write(str, (std::streamsize)wcslen(str)); + return out; +} + +/*****************************************************************************************/ +/*****************************************************************************************/ + +// case IN-sensitive +bool vfs::StrCmp::Equal(const char* s1, const char* s2) +{ + _StrCmp::Advance(s1,s2); + return _StrCmp::Equal(s1,s2); +} +bool vfs::StrCmp::Equal(std::string const& s1, std::string const& s2) +{ + const char* p1 = s1.c_str(); + const char* p2 = s2.c_str(); + _StrCmp::Advance(p1,p2); + return _StrCmp::Equal(p1,p2); +} +bool vfs::StrCmp::Equal(std::string const& s1, const char* s2) +{ + const char* p1 = s1.c_str(); + _StrCmp::Advance(p1,s2); + return _StrCmp::Equal(p1,s2); +} +bool vfs::StrCmp::Equal(const char* s1, std::string const& s2) +{ + const char* p2 = s2.c_str(); + _StrCmp::Advance(s1,p2); + return _StrCmp::Equal(s1,p2); +} +// +bool vfs::StrCmp::Equal(const wchar_t* s1, const wchar_t* s2) +{ + _StrCmp::Advance(s1,s2); + return _StrCmp::Equal(s1,s2); +} +bool vfs::StrCmp::Equal(std::wstring const& s1, std::wstring const& s2) +{ + const wchar_t* p1 = s1.c_str(); + const wchar_t* p2 = s2.c_str(); + _StrCmp::Advance(p1,p2); + return _StrCmp::Equal(p1,p2); +} +bool vfs::StrCmp::Equal(std::wstring const& s1, const wchar_t* s2) +{ + const wchar_t* p1 = s1.c_str(); + _StrCmp::Advance(p1,s2); + return _StrCmp::Equal(p1,s2); +} +bool vfs::StrCmp::Equal(const wchar_t* s1, std::wstring const& s2) +{ + const wchar_t* p2 = s2.c_str(); + _StrCmp::Advance(s1,p2); + return _StrCmp::Equal(s1,p2); +} +// +bool vfs::StrCmp::Equal(vfs::String const& s1, vfs::String const& s2) +{ + const wchar_t* p1 = s1.c_str(); + const wchar_t* p2 = s2.c_str(); + _StrCmp::Advance(p1,p2); + return _StrCmp::Equal(p1,p2); +} +bool vfs::StrCmp::Equal(vfs::String const& s1, std::wstring const& s2) +{ + const wchar_t* p1 = s1.c_str(); + const wchar_t* p2 = s2.c_str(); + _StrCmp::Advance(p1,p2); + return _StrCmp::Equal(p1,p2); +} +bool vfs::StrCmp::Equal(std::wstring const& s1, vfs::String const& s2) +{ + const wchar_t* p1 = s1.c_str(); + const wchar_t* p2 = s2.c_str(); + _StrCmp::Advance(p1,p2); + return _StrCmp::Equal(p1,p2); +} +bool vfs::StrCmp::Equal(vfs::String const& s1, const wchar_t* s2) +{ + const wchar_t* p1 = s1.c_str(); + _StrCmp::Advance(p1,s2); + return _StrCmp::Equal(p1,s2); +} +bool vfs::StrCmp::Equal(const wchar_t* s1, vfs::String const& s2) +{ + const wchar_t* p2 = s2.c_str(); + _StrCmp::Advance(s1,p2); + return _StrCmp::Equal(s1,p2); +} +// case Sensitive +bool vfs::StrCmp::EqualCase(const char* s1, const char* s2) +{ + _StrCmp::AdvanceCase(s1,s2); + return _StrCmp::Equal(s1,s2); +} +bool vfs::StrCmp::EqualCase(std::string const& s1, std::string const& s2) +{ + const char* p1 = s1.c_str(); + const char* p2 = s2.c_str(); + _StrCmp::AdvanceCase(p1,p2); + return _StrCmp::Equal(p1,p2); +} +bool vfs::StrCmp::EqualCase(std::string const& s1, const char* s2) +{ + const char* p1 = s1.c_str(); + _StrCmp::AdvanceCase(p1,s2); + return _StrCmp::Equal(p1,s2); +} +bool vfs::StrCmp::EqualCase(const char* s1, std::string const& s2) +{ + const char* p2 = s2.c_str(); + _StrCmp::AdvanceCase(s1,p2); + return _StrCmp::Equal(s1,p2); +} +// +bool vfs::StrCmp::EqualCase(const wchar_t* s1, const wchar_t* s2) +{ + _StrCmp::AdvanceCase(s1,s2); + return _StrCmp::Equal(s1,s2); +} +bool vfs::StrCmp::EqualCase(std::wstring const& s1, std::wstring const& s2) +{ + const wchar_t* p1 = s1.c_str(); + const wchar_t* p2 = s2.c_str(); + _StrCmp::AdvanceCase(p1,p2); + return _StrCmp::Equal(p1,p2); +} +bool vfs::StrCmp::EqualCase(std::wstring const& s1, const wchar_t* s2) +{ + const wchar_t* p1 = s1.c_str(); + _StrCmp::AdvanceCase(p1,s2); + return _StrCmp::Equal(p1,s2); +} +bool vfs::StrCmp::EqualCase(const wchar_t* s1, std::wstring const& s2) +{ + const wchar_t* p2 = s2.c_str(); + _StrCmp::AdvanceCase(s1,p2); + return _StrCmp::Equal(s1,p2); +} +// +bool vfs::StrCmp::EqualCase(vfs::String const& s1, vfs::String const& s2) +{ + const wchar_t* p1 = s1.c_str(); + const wchar_t* p2 = s2.c_str(); + _StrCmp::AdvanceCase(p1,p2); + return _StrCmp::Equal(p1,p2); +} +bool vfs::StrCmp::EqualCase(vfs::String const& s1, std::wstring const& s2) +{ + const wchar_t* p1 = s1.c_str(); + const wchar_t* p2 = s2.c_str(); + _StrCmp::AdvanceCase(p1,p2); + return _StrCmp::Equal(p1,p2); +} +bool vfs::StrCmp::EqualCase(std::wstring const& s1, vfs::String const& s2) +{ + const wchar_t* p1 = s1.c_str(); + const wchar_t* p2 = s2.c_str(); + _StrCmp::AdvanceCase(p1,p2); + return _StrCmp::Equal(p1,p2); +} +bool vfs::StrCmp::EqualCase(vfs::String const& s1, const wchar_t* s2) +{ + const wchar_t* p1 = s1.c_str(); + _StrCmp::AdvanceCase(p1,s2); + return _StrCmp::Equal(p1,s2); +} +bool vfs::StrCmp::EqualCase(const wchar_t* s1, vfs::String const& s2) +{ + const wchar_t* p2 = s2.c_str(); + _StrCmp::AdvanceCase(s1,p2); + return _StrCmp::Equal(s1,p2); +} + +/*****************************************************************************************/ +/*****************************************************************************************/ + +template<> +BuildString& BuildString::add(vfs::String const& value) +{ + this->add(value.c_str()); + return *this; +} +template<> +BuildString& BuildString::add(std::string const& value) +{ + this->add(vfs::String::as_utf16(value)); + return *this; +} +template<> +BuildString& BuildString::add(const char* const& value) +{ + this->add(vfs::String::as_utf16(value)); + return *this; +} + +template<> +BuildString& BuildString::operator<< (vfs::String const& value) +{ + this->add(value.c_str()); + return *this; +} +template<> +BuildString& BuildString::operator<< (std::string const& value) +{ + this->add(vfs::String::as_utf16(value)); + return *this; +} +template<> +BuildString& BuildString::operator<< (const char* const& value) +{ + this->add(vfs::String::as_utf16(value)); + return *this; +} + diff --git a/ext/VFS/src/Core/vfs_types.cpp b/ext/VFS/src/Core/vfs_types.cpp new file mode 100644 index 000000000..99d798eaf --- /dev/null +++ b/ext/VFS/src/Core/vfs_types.cpp @@ -0,0 +1,34 @@ +/* + * bfVFS : vfs/Core/vfs_types.cpp + * - basic integer types, "incomplete" list of useful constant strings + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +////////////////////////////////////////////////////////////////////// + +namespace vfs +{ + const vfs::size_t npos = vfs::size_t(-1); +} + +////////////////////////////////////////////////////////////////////// + diff --git a/ext/VFS/src/Core/vfs_vfile.cpp b/ext/VFS/src/Core/vfs_vfile.cpp new file mode 100644 index 000000000..d7b5f7eef --- /dev/null +++ b/ext/VFS/src/Core/vfs_vfile.cpp @@ -0,0 +1,220 @@ +/* + * bfVFS : vfs/Core/vfs_vfile.cpp + * - Virtual File, handles access to files from different VFS profiles + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +// static member +vfs::ObjBlockAllocator* vfs::CVirtualFile::_vfile_pool = NULL; + +vfs::CVirtualFile* vfs::CVirtualFile::create(vfs::Path const& sFilePath, vfs::CProfileStack& rPStack) +{ + unsigned int ID=0; +#ifdef VFILE_BLOCK_CREATE + if(!_vfile_pool) + { + _vfile_pool = new ObjBlockAllocator(); + vfs::ObjectAllocator::registerAllocator(_vfile_pool); + } + CVirtualFile* file = _vfile_pool->New(&ID); +#else + CVirtualFile* file = new CVirtualFile(); +#endif + file->_path = sFilePath; + file->_pstack = &rPStack; + file->_myID = ID; + return file; +} + +void vfs::CVirtualFile::destroy() +{ +#ifndef VFILE_BLOCK_CREATE + delete this; +#endif +} + + +vfs::CVirtualFile::CVirtualFile() +: _path(L""), _top_pname(L"_INVALID_"), _top_file(NULL), _pstack(NULL), _myID(vfs::UInt32(-1)) +{ +}; + +vfs::CVirtualFile::~CVirtualFile() +{ +} + +vfs::Path const& vfs::CVirtualFile::path() +{ + return _path; +} + +void vfs::CVirtualFile::add(vfs::IBaseFile *pFile, vfs::String sProfileName, bool bReplace) +{ + if(pFile) + { + // if there is no file then just set it + // if bReplace is set to true then override all other settings and just set the file + if(!_top_file || bReplace) + { + _top_file = pFile; + _top_pname = sProfileName; + return; + } + // file already set, but new file is? the same object + if(pFile == _top_file) + { + VFS_THROW_IFF( StrCmp::Equal(sProfileName,_top_pname), L"same file, different profile name"); + } + // OK, not the same file, but these two different files are supposed to have the same filename + VFS_THROW_IFF( _top_file->getName() == pFile->getName(), L"different filenames"); + // set new file only when its profile is on top of the current file's profile + bool bFoundOld = false, bFoundNew = false; + vfs::CProfileStack::Iterator it = _pstack->begin(); + for(; !it.end(); it.next()) + { + if(_top_pname == it.value()->cName) + { + bFoundOld = true; + break; + } + else if(sProfileName == it.value()->cName) + { + bFoundNew = true; + break; + } + } + if(bFoundNew && !bFoundOld) + { + _top_file = pFile; + _top_pname = sProfileName; + } + } +} + +/** + * @returns : returns true if pFile is not top file or top file could be replaced with another file + * returns false if there is no more files with given name. in this case object should be destroyed + */ +bool vfs::CVirtualFile::remove(vfs::IBaseFile *pFile) +{ + if(_top_file == pFile) + { + if(_path == pFile->getPath()) + { + // need to replace '_top_file' + vfs::CProfileStack::Iterator prof_it = _pstack->begin(); + for(; !prof_it.end(); prof_it.next()) + { + CVirtualProfile *pProf = prof_it.value(); + if(pProf) + { + vfs::IBaseFile *file = pProf->getFile(_path); + if(file && (file != pFile)) + { + _top_file = file; + _top_pname = pProf->cName; + return true; + } + } + } + // no more files + _top_file = NULL; + _top_pname = ""; + return false; + } + else + { + VFS_THROW(L"Same file object but different file paths? WTH?"); + } + } + return true; +} + +vfs::IBaseFile* vfs::CVirtualFile::file(ESearchFile eSearch) +{ + if(eSearch == SF_TOP) + { + return _top_file; + } + else if(eSearch == SF_FIRST_WRITABLE) + { + CVirtualProfile *pVProf = _pstack->getWriteProfile(); + if(pVProf) + { + return pVProf->getFile(_path); + } + } + else if(eSearch == SF_STOP_ON_WRITABLE_PROFILE) + { + vfs::CProfileStack::Iterator prof_it = _pstack->begin(); + for(; !prof_it.end(); prof_it.next()) + { + CVirtualProfile *pProf = prof_it.value(); + if(pProf) + { + if(pProf->cWritable) + { + return pProf->getFile(_path); + } + else + { + vfs::IBaseFile *pFile = pProf->getFile(_path); + if(pFile) + { + return pFile; + } + } + } + } + } + return NULL; +} + +vfs::IBaseFile* vfs::CVirtualFile::file(vfs::String const& sProfileName) +{ + if(sProfileName == _top_pname) + { + return vfs::tReadableFile::cast(_top_file); + } + else + { + CVirtualProfile* pProf = _pstack->getProfile(sProfileName); + if(pProf) + { + CVirtualProfile::Iterator loc_it = pProf->begin(); + for(; !loc_it.end(); loc_it.next()) + { + if(loc_it.value() && loc_it.value()->fileExists(_path)) + { + if(loc_it.value()) + { + return loc_it.value()->getFile(_path); + } + } + } + } + } + return NULL; +} + diff --git a/ext/VFS/src/Core/vfs_vloc.cpp b/ext/VFS/src/Core/vfs_vloc.cpp new file mode 100644 index 000000000..5665fd19d --- /dev/null +++ b/ext/VFS/src/Core/vfs_vloc.cpp @@ -0,0 +1,172 @@ +/* + * bfVFS : vfs/Core/vfs_vloc.cpp + * - Virtual Location, stores Virtual Files + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +/************************************************************************/ + +class vfs::CVirtualLocation::VFileIterator : public vfs::CVirtualLocation::Iterator::IImplementation +{ + friend class vfs::CVirtualLocation; + typedef vfs::CVirtualLocation::Iterator::IImplementation tBaseClass; + + VFileIterator(vfs::CVirtualLocation* pLoc): tBaseClass(), m_pLoc(pLoc) + { + VFS_THROW_IFF(pLoc, L""); + _vfile_iter = m_pLoc->m_VFiles.begin(); + } +public: + VFileIterator() : tBaseClass(), m_pLoc(NULL) + {}; + virtual ~VFileIterator() + {}; + virtual vfs::CVirtualFile* value() + { + if(m_pLoc && _vfile_iter != m_pLoc->m_VFiles.end()) + { + return _vfile_iter->second; + } + return NULL; + } + virtual void next() + { + if(m_pLoc && _vfile_iter != m_pLoc->m_VFiles.end()) + { + _vfile_iter++; + } + } +protected: + virtual tBaseClass* clone() + { + VFileIterator* iter = new VFileIterator(m_pLoc); + iter->_vfile_iter = _vfile_iter; + return iter; + } +private: + vfs::CVirtualLocation* m_pLoc; + vfs::CVirtualLocation::tVFiles::iterator _vfile_iter; +}; + +/************************************************************************/ + +vfs::CVirtualLocation::CVirtualLocation(vfs::Path const& path) +: cPath(path), m_exclusive(false) +{}; + +vfs::CVirtualLocation::~CVirtualLocation() +{ + tVFiles::iterator it = m_VFiles.begin(); + for(; it != m_VFiles.end(); ++it) + { + it->second->destroy(); + } + m_VFiles.clear(); +} + +void vfs::CVirtualLocation::setIsExclusive(bool exclusive) +{ + m_exclusive = exclusive; +} +bool vfs::CVirtualLocation::getIsExclusive() +{ + return m_exclusive; +} + +void vfs::CVirtualLocation::addFile(vfs::IBaseFile* file, vfs::String const& profileName) +{ + vfs::CVirtualFile *pVFile = NULL; + tVFiles::iterator it = m_VFiles.find(file->getName()); + if(it == m_VFiles.end()) + { + vfs::Path fp = file->getPath(); + vfs::CProfileStack& stack = *(getVFS()->getProfileStack()); + pVFile = vfs::CVirtualFile::create(fp,stack); + it = m_VFiles.insert(m_VFiles.end(), std::pair(file->getName(),pVFile)); + } + it->second->add(file,profileName,true); +} + +vfs::IBaseFile* vfs::CVirtualLocation::getFile(vfs::Path const& filename, vfs::String const& profileName) const +{ + tVFiles::const_iterator cit = m_VFiles.find(filename); + if(cit != m_VFiles.end() && cit->second) + { + if(profileName.empty()) + { + if(m_exclusive) + { + return cit->second->file(vfs::CVirtualFile::SF_STOP_ON_WRITABLE_PROFILE); + } + else + { + return cit->second->file(vfs::CVirtualFile::SF_TOP); + } + } + else + { + // you know what you are doing + return cit->second->file(profileName); + } + } + return NULL; +} +vfs::CVirtualFile* vfs::CVirtualLocation::getVirtualFile(vfs::Path const& filename) +{ + tVFiles::const_iterator cit = m_VFiles.find(filename); + if(cit != m_VFiles.end()) + { + return cit->second; + } + return NULL; +} + +bool vfs::CVirtualLocation::removeFile(vfs::IBaseFile* file) +{ + if(file) + { + vfs::Path sDir,sFile; + file->getPath().splitLast(sDir,sFile); + tVFiles::iterator it = m_VFiles.find(sFile); + if(it != m_VFiles.end()) + { + if(!it->second->remove(file)) + { + //CVirtualFile* vfile = it->second; + //delete vfile; + m_VFiles.erase(it); + } + return true; + } + } + return false; +} + + +vfs::CVirtualLocation::Iterator vfs::CVirtualLocation::iterate() +{ + return Iterator(new VFileIterator(this)); +} + diff --git a/ext/VFS/src/Ext/7z/vfs_7z_library.cpp b/ext/VFS/src/Ext/7z/vfs_7z_library.cpp new file mode 100644 index 000000000..5686ec2cd --- /dev/null +++ b/ext/VFS/src/Ext/7z/vfs_7z_library.cpp @@ -0,0 +1,269 @@ +/* + * bfVFS : vfs/Ext/7z/vfs_7z_library.cpp + * - implements Library interface, creates library object from uncompressed 7-zip archive files + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef VFS_WITH_7ZIP + +#include +#include +#include +#include + +namespace sz +{ +extern "C" +{ +#include <7z.h> +#include <7zCrc.h> +#include <7zAlloc.h> +//#include +//#include +//#include +} +} + +/********************************************************************************************/ +/*** my 7z extensions ***/ +/********************************************************************************************/ + +namespace szExt +{ + typedef struct CSzVfsFile + { + vfs::tReadableFile* file; + } CSzVfsFile; + + typedef struct CVfsFileInStream + { + sz::ISeekInStream s; + CSzVfsFile file; + } CVfsFileInStream; + + + static sz::SRes VfsFileInStream_Read(void *pp, void *buf, ::size_t *size) + { + CVfsFileInStream *p = (CVfsFileInStream *)pp; + ::size_t to_read = *size; + sz::SRes res; + try + { + *size = (::size_t)p->file.file->read((vfs::Byte*)buf,to_read); + res = SZ_OK; + } + catch(std::exception &ex) + { + VFS_LOG_ERROR(ex.what()); + res = SZ_ERROR_READ; + } + return res; + } + + static sz::SRes VfsFileInStream_Seek(void *pp, sz::Int64 *pos, sz::ESzSeek origin) + { + CVfsFileInStream *p = (CVfsFileInStream *)pp; + + vfs::IBaseFile::ESeekDir eSD; + switch (origin) + { + case sz::SZ_SEEK_SET: + eSD = vfs::IBaseFile::SD_BEGIN; + break; + case sz::SZ_SEEK_CUR: + eSD = vfs::IBaseFile::SD_CURRENT; + break; + case sz::SZ_SEEK_END: + eSD = vfs::IBaseFile::SD_END; + break; + default: + return SZ_ERROR_PARAM; + } + vfs::offset_t _pos = (vfs::offset_t)(*pos); + sz::SRes res; + try + { + p->file.file->setReadPosition(_pos,eSD); + *pos = p->file.file->getReadPosition(); + res = SZ_OK; + } + catch(std::exception& ex) + { + VFS_LOG_ERROR(ex.what()); + res = SZ_ERROR_READ; + } + return res; + } + + void VfsFileInStream_CreateVTable(CVfsFileInStream *p) + { + p->s.Read = VfsFileInStream_Read; + p->s.Seek = VfsFileInStream_Seek; + } +}; // end namespace szExt + +/********************************************************************************************/ +/********************************************************************************************/ +/********************************************************************************************/ + +vfs::CUncompressed7zLibrary::CUncompressed7zLibrary( + tReadableFile *libraryFile, + vfs::Path const& mountPoint, + bool ownFile, + vfs::ObjBlockAllocator* allocator) +: vfs::CUncompressedLibraryBase(libraryFile, mountPoint, ownFile), _allocator(allocator) +{ +} + +vfs::CUncompressed7zLibrary::~CUncompressed7zLibrary() +{ +} + + +#define k_Copy 0 + +sz::UInt64 GetSum(const sz::UInt64 *values, sz::UInt32 index) +{ + sz::UInt64 sum = 0; + sz::UInt32 i; + for (i = 0; i < index; i++) + { + sum += values[i]; + } + return sum; +} + +bool vfs::CUncompressed7zLibrary::init() +{ + if(!m_libraryFile) + { + return false; + } + try + { + szExt::CVfsFileInStream archiveStream; + sz::CLookToRead lookStream; + sz::CSzArEx db; + sz::SRes res; + sz::ISzAlloc allocImp; + sz::ISzAlloc allocTempImp; + + vfs::COpenReadFile rfile(m_libraryFile); + + archiveStream.file.file = m_libraryFile; + + szExt::VfsFileInStream_CreateVTable(&archiveStream); + sz::LookToRead_CreateVTable(&lookStream, False); + + lookStream.realStream = &archiveStream.s; + sz::LookToRead_Init(&lookStream); + + allocImp.Alloc = sz::SzAlloc; + allocImp.Free = sz::SzFree; + + allocTempImp.Alloc = sz::SzAllocTemp; + allocTempImp.Free = sz::SzFreeTemp; + + sz::CrcGenerateTable(); + + sz::SzArEx_Init(&db); + if( SZ_OK != (res = sz::SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp)) ) + { + VFS_THROW(_BS(L"Could not open 7z archive [") << m_libraryFile->getPath() << L"]" << _BS::wget); + } + + vfs::TDirectory* pLD = NULL; + vfs::Path oDir, oFile; + vfs::Path oDirPath; + + const size_t FBUFFER_SIZE = 1024; + std::vector fname_buffer; + fname_buffer.resize(FBUFFER_SIZE); + for(vfs::UInt32 i = 0; i < db.db.NumFiles; i++) + { + sz::CSzFileItem *f = db.db.Files + i; + if (f->IsDir) + { + continue; + } + size_t fsize = SzArEx_GetFileNameUtf16(&db, i, NULL); + if(fsize >= fname_buffer.size()) + { + fname_buffer.resize(fsize + 32); + } + fsize = SzArEx_GetFileNameUtf16(&db, i, &fname_buffer[0]); + fname_buffer[fsize] = 0; + vfs::Path sPath((wchar_t*)&fname_buffer[0]); + sPath.splitLast(oDir,oFile); + oDirPath = m_mountPoint; + if(!oDir.empty()) + { + oDirPath += oDir; + } + + // determine offset and size + sz::UInt32 folderIndex = db.FileIndexToFolderIndexMap[i]; + + sz::CSzFolder *folder = db.db.Folders + folderIndex; + sz::UInt64 unpackSizeSpec = sz::SzFolder_GetUnpackSize(folder); + size_t unpackSize = (size_t)unpackSizeSpec; + sz::UInt64 startOffset = sz::SzArEx_GetFolderStreamPos(&db, folderIndex, 0); + + //const sz::UInt64 *packSizes = db.db.PackSizes + db.FolderStartPackStreamIndex[folderIndex]; + + //CSzCoderInfo *coder = &folder->Coders[0]; + //if (coder->MethodID == k_Copy) + //{ + // UInt32 si = 0; + // UInt64 offset; + // UInt64 inSize; + // offset = GetSum(packSizes, si); + // inSize = packSizes[si]; + //} + + // get or create according directory object + tDirCatalogue::iterator it = m_dirs.find(oDirPath); + if(it != m_dirs.end()) + { + pLD = it->second; + } + else + { + pLD = new vfs::CLibDirectory(oDir,oDirPath); + m_dirs.insert(std::make_pair(oDirPath,pLD)); + } + // create file + vfs::CLibFile *pFile = vfs::CLibFile::create(oFile,pLD,this,_allocator); + // add file to directory + VFS_THROW_IFF( pLD->addFile(pFile), L"" ); + + // link file data struct to file object + m_fileData.insert(std::make_pair(pFile,SFileData(unpackSize, (vfs::size_t)startOffset))); + } + return true; + } + catch(std::exception& ex) + { + VFS_LOG_ERROR(ex.what()); + return false; + } +} + +#endif // VFS_WITH_7ZIP diff --git a/ext/VFS/src/Ext/7z/vfs_create_7z_library.cpp b/ext/VFS/src/Ext/7z/vfs_create_7z_library.cpp new file mode 100644 index 000000000..90788b92c --- /dev/null +++ b/ext/VFS/src/Ext/7z/vfs_create_7z_library.cpp @@ -0,0 +1,428 @@ +/* + * bfVFS : vfs/Ext/7z/vfs_create_7z_library.cpp + * - writes uncompressed 7z archive file + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef VFS_WITH_7ZIP + +#include + +#include + +#include +#include +#include + +namespace sz +{ +extern "C" +{ +#include <7zCrc.h> +#include <7z.h> +//#include "Archive/7z/7zIn.h" +} +}; + +#include +#include + +/******************************************************************************************/ +/******************************************************************************************/ +/******************************************************************************************/ +namespace szExt +{ + inline ::size_t WRITEBYTE(std::ostream& out, sz::Byte const& value) + { + out.write((char*)&value,sizeof(sz::Byte)); + return 1; + } + template + inline ::size_t WRITEALL(std::ostream& out, T const& value) + { + out.write((char*)&value,sizeof(T)); + return sizeof(T); + } + template + inline ::size_t WRITEBUFFER(std::ostream& out, T* value, ::size_t num_elements) + { + out.write((char*)value, num_elements*sizeof(T)); + return num_elements*sizeof(T); + } + + /** + * "compress" numbers by removing heading zero-bytes + * - add additional byte that represents a bit-vector of bytes within a 64-bit/8-byte number + * - if the number is smaller than 128, use the extra byte to store the value + */ + template + inline ::size_t WRITE(std::ostream& out, T const& value) + { + ::size_t count = 0; + sz::Byte data[8]; + sz::Byte firstByte = 0; + sz::Byte* b = (sz::Byte*)&value; + ::size_t SIZE = sizeof(T); + b+= SIZE-1; + vfs::Int32 i; + for(i = (vfs::Int32)(SIZE-1); i>=0; --i) + { + if( (*b & 0xFF) != 0) + { + break; + } + b--; + } + if(i < 0) + { + count += WRITEBYTE(out,0); + return count; + } + if(i == 0) + { + if(*b >= 0x80) + { + count += WRITEBYTE(out,0x80); + } + count += WRITEBYTE(out,*b); + return count; + } + vfs::Int32 num = 0; + for(;i >= 0; --i) + { + firstByte |= 1 << (8 - i - 1); + data[i] = *b--; + num++; + } + count += WRITEBYTE(out,firstByte); + count += WRITEBUFFER(out,data,num); + return count; + } +} +/******************************************************************************************/ +/******************************************************************************************/ +/******************************************************************************************/ + +vfs::CCreateUncompressed7zLibrary::CCreateUncompressed7zLibrary() +: m_pLibFile(NULL) +{ + sz::CrcGenerateTable(); +} + +vfs::CCreateUncompressed7zLibrary::~CCreateUncompressed7zLibrary() +{ + m_pLibFile = NULL; + + m_lFileInfo.clear(); + m_mapDirInfo.clear(); +} + +bool vfs::CCreateUncompressed7zLibrary::addFile(vfs::tReadableFile* pFile) +{ + if(!pFile) + { + // at least nothing bad happened + return true; + } + try + { + vfs::COpenReadFile infile(pFile); + } + catch(std::exception &ex) + { + std::wstringstream wss; + wss << L"Could not open File \"" << pFile->getPath()() << L"\""; + VFS_RETHROW(wss.str().c_str(), ex); + } + SFileInfo fi; + vfs::Path filename = pFile->getPath(); + fi.name = filename.c_wcs(); + fi.size = pFile->getSize(); + if(m_lFileInfo.empty()) + { + fi.offset = 0; + } + else + { + SFileInfo const& fic = m_lFileInfo.back(); + fi.offset = fic.offset + fic.size; + } + + typedef std::vector tByteVector; + tByteVector data( (tByteVector::size_type)fi.size ); + VFS_THROW_IFF(fi.size == pFile->read(&data[0], (vfs::size_t)fi.size), L""); + fi.CRC = sz::CrcCalc(&data[0],(::size_t)fi.size); + m_ssFileStream.write(&data[0],(std::streamsize)fi.size); + + m_lFileInfo.push_back(fi); + + vfs::Path path,dummy; + filename.splitLast(path,dummy); + if(!path.empty()) + { + tDirInfo::iterator it_find = m_mapDirInfo.find(path.c_wcs()); + if(it_find == m_mapDirInfo.end()) + { + SFileInfo dir; + dir.name = path.c_wcs(); + dir.offset = 0; + dir.size = 0; + dir.time_creation = 0; + dir.time_last_access = 0; + dir.time_write = 0; + m_mapDirInfo.insert(std::make_pair(dir.name,dir)); + } + } + return true; +} + +bool vfs::CCreateUncompressed7zLibrary::writeLibrary(vfs::Path const& sLibName) +{ + vfs::COpenWriteFile outfile(sLibName,true); + return writeLibrary(&outfile.file()); +} +bool vfs::CCreateUncompressed7zLibrary::writeLibrary(vfs::tWritableFile* pFile) +{ + if(!pFile) + { + return false; + } + if(m_lFileInfo.empty()) + { + return false; + } + m_pLibFile = pFile; + if(!m_pLibFile->isOpenWrite() && !m_pLibFile->openWrite(true,true)) + { + return false; + } + // + writeNextHeader(m_ssInfoStream); + // + std::stringstream ssSigHeader; + writeSignatureHeader(ssSigHeader); + // + m_pLibFile->write(ssSigHeader.str().c_str() , (vfs::size_t)ssSigHeader.str().length()); + // + m_pLibFile->write(m_ssFileStream.str().c_str() , (vfs::size_t)m_ssFileStream.str().length()); + // + m_pLibFile->write(m_ssInfoStream.str().c_str() , (vfs::size_t)m_ssInfoStream.str().length()); + + return true; +} + +/**************************************************************************************/ + +bool vfs::CCreateUncompressed7zLibrary::writeSignatureHeader(std::ostream& out) +{ + ::size_t count=0; + + // #define k7zSignatureSize -> not in namespace sz + count += szExt::WRITEBUFFER(out, sz::k7zSignature, k7zSignatureSize); + + sz::Byte Major = 0, Minor = 2; + count += szExt::WRITEALL(out, (sz::Byte)Major ); + count += szExt::WRITEALL(out, (sz::Byte)Minor ); + + sz::UInt32 StartHeaderCRC, NextHeaderCRC; + + SFileInfo const& fi = m_lFileInfo.back(); + sz::UInt64 NextHeaderOffset = fi.offset + fi.size; + sz::UInt64 NextHeaderSize = m_ssInfoStream.str().length()*sizeof(char); + NextHeaderCRC = sz::CrcCalc(m_ssInfoStream.str().c_str(),(::size_t)NextHeaderSize); + + std::stringstream sstemp; + count += szExt::WRITEALL(sstemp, (sz::UInt64)NextHeaderOffset ); + count += szExt::WRITEALL(sstemp, (sz::UInt64)NextHeaderSize ); + count += szExt::WRITEALL(sstemp, (sz::UInt32)NextHeaderCRC ); + StartHeaderCRC = sz::CrcCalc(sstemp.str().c_str(), sstemp.str().length()*sizeof(char)); + + count += szExt::WRITEALL(out, (sz::UInt32)StartHeaderCRC ); + out << sstemp.str(); + + return true; +} +bool vfs::CCreateUncompressed7zLibrary::writeNextHeader(std::ostream& out) +{ + szExt::WRITE(out, (sz::Byte)sz::k7zIdHeader); + + // this->WriteArchiveProperties(out); + + // this->WriteAdditionalStreamsInfo(out) + + // + this->writeMainStreamsInfo(out); + + // + this->writeFilesInfo(out); + + szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd ); + + return true; +} + +bool vfs::CCreateUncompressed7zLibrary::writeMainStreamsInfo(std::ostream& out) +{ + szExt::WRITE(out, (sz::Byte)sz::k7zIdMainStreamsInfo ); + + this->writePackInfo(out); + + this->writeUnPackInfo(out); + + this->writeSubStreamsInfo(out); + + szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd ); + + return true; +} + + +bool vfs::CCreateUncompressed7zLibrary::writePackInfo(std::ostream& out) +{ + szExt::WRITE(out, (sz::Byte)sz::k7zIdPackInfo ); + szExt::WRITE(out, (sz::UInt64)0 ); // data offset + szExt::WRITE(out, (sz::UInt32)m_lFileInfo.size() ); + + szExt::WRITE(out, (sz::Byte)sz::k7zIdSize ); + std::list::iterator it = m_lFileInfo.begin(); + for(;it != m_lFileInfo.end(); ++it) + { + szExt::WRITE(out, (sz::UInt64)it->size ); + } + + szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd ); + return true; +} +bool vfs::CCreateUncompressed7zLibrary::writeUnPackInfo(std::ostream& out) +{ + szExt::WRITE(out, (sz::Byte)sz::k7zIdUnpackInfo ); + + szExt::WRITE(out, (sz::Byte)sz::k7zIdFolder ); + szExt::WRITE(out, (sz::UInt64)m_lFileInfo.size() ); + szExt::WRITE(out, (sz::Byte)0 ); // External + + std::list::iterator fit = m_lFileInfo.begin(); + for(;fit != m_lFileInfo.end(); ++fit) + { + this->writeFolder(out); + } + + szExt::WRITE(out, (sz::Byte)sz::k7zIdCodersUnpackSize ); + fit = m_lFileInfo.begin(); + for(;fit != m_lFileInfo.end(); ++fit) + { + szExt::WRITE(out, (sz::UInt64)fit->size ); + } + + szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd ); + + return true; +} +bool vfs::CCreateUncompressed7zLibrary::writeSubStreamsInfo(std::ostream& out) +{ + szExt::WRITE(out, (sz::Byte)sz::k7zIdSubStreamsInfo ); + szExt::WRITE(out, (sz::Byte)sz::k7zIdCRC ); + + szExt::WRITE(out, (sz::Byte)1 ); // early out - all CRCs defined + std::list::iterator fit = m_lFileInfo.begin(); + for(;fit != m_lFileInfo.end(); ++fit ) + { + szExt::WRITEALL(out, (sz::UInt32)fit->CRC); + } + + szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd ); + return true; +} + +bool vfs::CCreateUncompressed7zLibrary::writeFolder(std::ostream& out) +{ + szExt::WRITE(out, (sz::UInt32)1 ); // NumCoders + + szExt::WRITE(out, (sz::Byte)1 ); // MainByte + + szExt::WRITE(out, (sz::Byte)0 ); // Methods + + return true; +} +bool vfs::CCreateUncompressed7zLibrary::writeFilesInfo(std::ostream& out) +{ + szExt::WRITE(out, (sz::Byte)sz::k7zIdFilesInfo ); + + vfs::UInt64 num_files = (m_lFileInfo.size()+m_mapDirInfo.size()); + szExt::WRITE(out, (sz::UInt64)num_files ); + + // empty stream -> pack info in bit-vector + szExt::WRITE(out, (sz::Byte)sz::k7zIdEmptyStream ); + sz::UInt64 num_empty64 = num_files/8 + (num_files%8 == 0 ? 0 : 1); + ::size_t num_empty = (::size_t)num_empty64; + VFS_THROW_IFF(num_empty == num_empty64, L"WTF"); + + sz::Byte *empty_vector = new sz::Byte[num_empty]; + memset(empty_vector,0,(::size_t)num_empty); + for(::size_t e=m_lFileInfo.size(); e < num_files; ++e) + { + ::size_t index = e / 8; + empty_vector[index] |= 1 << (7 - e%8); + } + szExt::WRITE(out, (sz::UInt64)num_empty ); // size + szExt::WRITEBUFFER(out, empty_vector, (::size_t)num_empty); + delete[] empty_vector; + + // names + szExt::WRITE(out, (sz::Byte)sz::k7zIdName ); + ::size_t count = 0; + std::stringstream name_stream; + count += szExt::WRITE(name_stream, (sz::Byte)0 ); // switch + std::list::iterator fit = m_lFileInfo.begin(); + for(;fit != m_lFileInfo.end(); ++fit) + { + count += (::size_t)this->writeFileName(name_stream, fit->name); + } + std::map::iterator dit = m_mapDirInfo.begin(); + for(;dit != m_mapDirInfo.end(); ++dit) + { + count += (::size_t)this->writeFileName(name_stream, dit->second.name); + } + szExt::WRITE(out, (sz::UInt64)count ); // size + szExt::WRITEBUFFER(out, name_stream.str().c_str(), name_stream.str().length() ); + + //szExt::WRITE(out, (sz::Byte)sz::k7zIdEmptyFile ); + //szExt::WRITE(out, (sz::Byte)sz::k7zIdCTime ); // create + //szExt::WRITE(out, (sz::Byte)sz::k7zIdATime ); // last access + //szExt::WRITE(out, (sz::Byte)sz::k7zIdMTime ); // write + + //szExt::WRITE(out, (sz::Byte)sz::k7zIdWinAttributes ); + + szExt::WRITE(out, (sz::Byte)sz::k7zIdEnd ); + + return true; +} + +vfs::size_t vfs::CCreateUncompressed7zLibrary::writeFileName(std::ostream& out, vfs::String const& filename) +{ + ::size_t count = 0; + VFS_THROW_IFF(filename.length(), L"zero length name"); + count += szExt::WRITEBUFFER(out, filename.c_str(), filename.length()); + count += szExt::WRITE(out, (sz::Byte)0); + count += szExt::WRITE(out, (sz::Byte)0); + return (vfs::size_t)count; +} + +#endif // VFS_WITH_7ZIP diff --git a/ext/VFS/src/Ext/files.cmake b/ext/VFS/src/Ext/files.cmake new file mode 100644 index 000000000..90aeb2122 --- /dev/null +++ b/ext/VFS/src/Ext/files.cmake @@ -0,0 +1,30 @@ + +## Ext + +if(BFVFS_WITH_7ZIP) + set(INCLUDE_Ext_7zip + ${MOD_INCLUDE}/7z/vfs_7z_library.h + ${MOD_INCLUDE}/7z/vfs_create_7z_library.h + ) + set(SOURCE_Ext_7zip + ${MOD_SOURCE}/7z/vfs_7z_library.cpp + ${MOD_SOURCE}/7z/vfs_create_7z_library.cpp + ) + source_group("Ext" FILES ${INCLUDE_Ext_7zip} ${SOURCE_Ext_7zip}) +endif() + +if(BFVFS_WITH_SLF) + set(INCLUDE_Ext_slf + ${MOD_INCLUDE}/slf/vfs_slf_library.h + ) + set(SOURCE_Ext_slf + ${MOD_SOURCE}/slf/vfs_slf_library.cpp + ) + source_group("Ext" FILES ${INCLUDE_Ext_slf} ${SOURCE_Ext_slf}) +endif() + +set(${mod}_files + ${INCLUDE_Ext_7zip} ${SOURCE_Ext_7zip} + ${INCLUDE_Ext_slf} ${SOURCE_Ext_slf} + CACHE INTERNAL "" +) diff --git a/ext/VFS/src/Ext/slf/vfs_slf_library.cpp b/ext/VFS/src/Ext/slf/vfs_slf_library.cpp new file mode 100644 index 000000000..be2b3e7c5 --- /dev/null +++ b/ext/VFS/src/Ext/slf/vfs_slf_library.cpp @@ -0,0 +1,179 @@ +/* + * bfVFS : vfs/Ext/slf/vfs_slf_library.cpp + * - implements Library interface, creates library object from SLF archive files + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef VFS_WITH_SLF + +#include +#include +#include +#include +#include +#include + +#include + +namespace slf +{ + typedef vfs::UInt32 DWORD; + // copy from WinDef.h + typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; + } FILETIME, *PFILETIME, *LPFILETIME; + + typedef void* HANDLE; + + const vfs::UInt32 FILENAME_SIZE = 256; + const vfs::UInt32 PATH_SIZE = 80; + + const vfs::UInt32 FILE_OK = 0; + const vfs::UInt32 FILE_DELETED = 0xff; + const vfs::UInt32 FILE_OLD = 1; + const vfs::UInt32 FILE_DOESNT_EXIST = 0xfe; + + struct LIBHEADER + { + vfs::Byte sLibName[ FILENAME_SIZE ]; + vfs::Byte sPathToLibrary[ FILENAME_SIZE ]; + vfs::Int32 iEntries; + vfs::Int32 iUsed; + vfs::UInt16 iSort; + vfs::UInt16 iVersion; + vfs::UByte fContainsSubDirectories; + vfs::Int32 iReserved; + }; + + struct DIRENTRY + { + vfs::Byte sFileName[ FILENAME_SIZE ]; + vfs::UInt32 uiOffset; + vfs::UInt32 uiLength; + vfs::UInt8 ubState; + vfs::UInt8 ubReserved; + FILETIME sFileTime; + vfs::UInt16 usReserved2; + }; +}; // end namespace slf + +/********************************************************************************************/ +/********************************************************************************************/ +/********************************************************************************************/ + +vfs::CSLFLibrary::CSLFLibrary(tReadableFile *pLibraryFile, vfs::Path const& sMountPoint, bool bOwnFile) +: vfs::CUncompressedLibraryBase(pLibraryFile,sMountPoint,bOwnFile) +{}; + +vfs::CSLFLibrary::~CSLFLibrary() +{ +} + +bool vfs::CSLFLibrary::init() +{ + if(!m_libraryFile) + { + return false; + } + try + { + vfs::COpenReadFile rfile(m_libraryFile); + + slf::LIBHEADER LibFileHeader; + vfs::size_t bytesRead = m_libraryFile->read((vfs::Byte*)&LibFileHeader, sizeof( slf::LIBHEADER )); + VFS_THROW_IFF(bytesRead == sizeof( slf::LIBHEADER ), L""); + + vfs::Path oLibPath; + //if the library has a path + if( strlen( (char*)LibFileHeader.sPathToLibrary ) != 0 ) + { + oLibPath = vfs::Path( LibFileHeader.sPathToLibrary ); + } + else + { + //else the library name does not contain a path ( most likely either an error or it is the default path ) + oLibPath = vfs::Path( vfs::Const::EMPTY() ); + } + if(m_mountPoint.empty()) + { + m_mountPoint = oLibPath; + } + else + { + m_mountPoint += oLibPath; + } + + //place the file pointer at the begining of the file headers ( they are at the end of the file ) + m_libraryFile->setReadPosition(-( LibFileHeader.iEntries * (vfs::Int32)sizeof(slf::DIRENTRY) ), vfs::IBaseFile::SD_END); + + //loop through the library and determine the number of files that are FILE_OK + //ie. so we dont load the old or deleted files + slf::DIRENTRY DirEntry; + vfs::Path oDir, oFile; + vfs::Path oDirPath; + for(vfs::UInt32 uiLoop=0; uiLoop < (vfs::UInt32)LibFileHeader.iEntries; uiLoop++ ) + { + //read in the file header + //memset(&DirEntry,0,sizeof(DirEntry)); + bytesRead = m_libraryFile->read((Byte*)&DirEntry, sizeof( slf::DIRENTRY )); + VFS_THROW_IFF(bytesRead == sizeof( slf::DIRENTRY ), L""); + + if( DirEntry.ubState == slf::FILE_OK ) + { + vfs::Path sPath(vfs::String::as_utf16(DirEntry.sFileName)); + sPath.splitLast(oDir,oFile); + oDirPath = m_mountPoint; + if(!oDir.empty()) + { + oDirPath += oDir; + } + + // get or create according directory object + vfs::TDirectory* pLD = NULL; + tDirCatalogue::iterator it = m_dirs.find(oDirPath); + if(it != m_dirs.end()) + { + pLD = it->second; + } + else + { + pLD = new vfs::CLibDirectory(oDirPath,oDirPath); + m_dirs.insert(std::make_pair(oDirPath,pLD)); + } + // create file + vfs::CLibFile *pFile = vfs::CLibFile::create(oFile,pLD,this); + // add file to directory + VFS_THROW_IFF(pLD->addFile(pFile), L""); + + // link file data struct to file object + m_fileData.insert(std::make_pair(pFile, SFileData(DirEntry.uiLength, DirEntry.uiOffset))); + } // end if + } // end for + return true; + } + catch(std::exception& ex) + { + VFS_LOG_ERROR(ex.what()); + return false; + } +} + +#endif // VFS_WITH_SLF diff --git a/ext/VFS/src/Tools/files.cmake b/ext/VFS/src/Tools/files.cmake new file mode 100644 index 000000000..536f3c6e5 --- /dev/null +++ b/ext/VFS/src/Tools/files.cmake @@ -0,0 +1,29 @@ + +## Tools + +set(INCLUDE_Tools + ${MOD_INCLUDE}/vfs_allocator.h + ${MOD_INCLUDE}/vfs_file_logger.h + ${MOD_INCLUDE}/vfs_hp_timer.h + ${MOD_INCLUDE}/vfs_log.h + ${MOD_INCLUDE}/vfs_parser_tools.h + ${MOD_INCLUDE}/vfs_profiler.h + ${MOD_INCLUDE}/vfs_property_container.h + ${MOD_INCLUDE}/vfs_tools.h +) +set(SOURCE_Tools + ${MOD_SOURCE}/vfs_allocator.cpp + ${MOD_SOURCE}/vfs_file_logger.cpp + ${MOD_SOURCE}/vfs_hp_timer.cpp + ${MOD_SOURCE}/vfs_log.cpp + ${MOD_SOURCE}/vfs_parser_tools.cpp + ${MOD_SOURCE}/vfs_profiler.cpp + ${MOD_SOURCE}/vfs_property_container.cpp + ${MOD_SOURCE}/vfs_tools.cpp +) +source_group(Tools FILES ${INCLUDE_Tools} ${SOURCE_Tools}) + +set(${mod}_files + ${INCLUDE_Tools} ${SOURCE_Tools} + CACHE INTERNAL "" +) diff --git a/ext/VFS/src/Tools/vfs_allocator.cpp b/ext/VFS/src/Tools/vfs_allocator.cpp new file mode 100644 index 000000000..310d54ce2 --- /dev/null +++ b/ext/VFS/src/Tools/vfs_allocator.cpp @@ -0,0 +1,41 @@ +/* + * bfVFS : vfs/Tools/vfs_allocator.cpp + * - allocator class to reserve memory blockwise for a larger amount of objects (that have constant size) + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +std::vector vfs::ObjectAllocator::_valloc; + +void vfs::ObjectAllocator::registerAllocator(vfs::IAllocator* allocator) +{ + _valloc.push_back(allocator); +} +void vfs::ObjectAllocator::clear() +{ + std::vector::iterator it = _valloc.begin(); + for(; it != _valloc.end(); ++it) + { + delete *it; + *it = NULL; + } + _valloc.clear(); +} diff --git a/ext/VFS/src/Tools/vfs_file_logger.cpp b/ext/VFS/src/Tools/vfs_file_logger.cpp new file mode 100644 index 000000000..ed146e12c --- /dev/null +++ b/ext/VFS/src/Tools/vfs_file_logger.cpp @@ -0,0 +1,59 @@ +/* + * bfVFS : vfs/Tools/vfs_file_logger.cpp + * - implements Logging iterface in the Aspects module by using the vfs::Log class + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +vfs::FileLogger::FileLogger(vfs::Path const& log_file, bool append, vfs::Log::EFlushMode flush_mode) +: m_log( *vfs::Log::create(log_file, append, flush_mode) ) +{ + m_log.Reserve(); + m_clock.startTimer(); +} + +vfs::FileLogger::FileLogger(vfs::tWritableFile* file, bool append, vfs::Log::EFlushMode flush_mode) +: m_log( *vfs::Log::create(file,append, flush_mode) ) +{ + m_log.Reserve(); + m_clock.startTimer(); +} + + +vfs::FileLogger::~FileLogger() +{ + m_log.destroy(); +} + +void vfs::FileLogger::Msg(const wchar_t* msg) +{ + m_log << "[" << m_clock.running() << "] : " << vfs::String::as_utf8(msg) << vfs::Log::endl; +} + +void vfs::FileLogger::Msg(const char* msg) +{ + m_log << "[" << m_clock.running() << "] : " << msg << vfs::Log::endl; +} + +void vfs::FileLogger::Msg(vfs::String const& msg) +{ + this->Msg(msg.c_str()); +} diff --git a/ext/VFS/src/Tools/vfs_hp_timer.cpp b/ext/VFS/src/Tools/vfs_hp_timer.cpp new file mode 100644 index 000000000..d0a8121c1 --- /dev/null +++ b/ext/VFS/src/Tools/vfs_hp_timer.cpp @@ -0,0 +1,93 @@ +/* + * bfVFS : vfs/Tools/vfs_hp_timer.cpp + * - high performance/precision timer, used by profiler + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +vfs::HPTimer::HPTimer() : is_running(false) +{ +#ifdef WIN32 + QueryPerformanceFrequency(&ticksPerSecond); +#endif +} + +vfs::HPTimer::~HPTimer() +{ +} + +void vfs::HPTimer::startTimer() +{ +#ifdef WIN32 + QueryPerformanceCounter(&tick); +#elif __linux__ + gettimeofday(&t1,0); +#endif + is_running = true; +} + +long long vfs::HPTimer::ticks() +{ + if(is_running) + { +#ifdef WIN32 + QueryPerformanceCounter(&tick2); + return tick2.QuadPart - tick.QuadPart; +#elif __linux__ + gettimeofday(&t2,0); + return t2.tv_usec - t1.tv_usec; +#endif + } + return 0; +} +double vfs::HPTimer::running() +{ + if(is_running) + { +#ifdef WIN32 + QueryPerformanceCounter(&tick2); + return (double)(tick2.QuadPart - tick.QuadPart)/(double)ticksPerSecond.QuadPart; +#elif __linux__ + gettimeofday(&t2,0); + return (double)(t2.tv_usec - t1.tv_usec)/1000000.0; +#endif + } + return 0; +} + +void vfs::HPTimer::stopTimer() +{ +#ifdef WIN32 + QueryPerformanceCounter(&tick2); +#elif __linux__ + gettimeofday(&t2,0); +#endif + is_running = false; +} + +double vfs::HPTimer::getElapsedTimeInSeconds() +{ +#ifdef WIN32 + return (double)(tick2.QuadPart - tick.QuadPart)/(double)ticksPerSecond.QuadPart; +#elif __linux__ + return (double)(t2.tv_usec - t1.tv_usec)/1000000.0; +#endif +} diff --git a/ext/VFS/src/Tools/vfs_log.cpp b/ext/VFS/src/Tools/vfs_log.cpp new file mode 100644 index 000000000..2c55a9ddc --- /dev/null +++ b/ext/VFS/src/Tools/vfs_log.cpp @@ -0,0 +1,412 @@ +/* + * bfVFS : vfs/Tools/vfs_log.cpp + * - simple file logger + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#ifdef WIN32 +static const char ENDL[] = "\r\n"; +#else +static const char ENDL[] = "\n"; +#endif + +typedef std::list LogList_t; +static LogList_t* __logs; +std::list& vfs::Log::_logs() +{ + if(!__logs) + { + __logs = new LogList_t; + } + return *__logs; +} + +vfs::Log* vfs::Log::create(vfs::Path const& fileName, bool append, EFlushMode flushMode) +{ + _logs().push_back(new vfs::Log(fileName, true, append, flushMode)); + return _logs().back(); +} +vfs::Log* vfs::Log::create(vfs::tWritableFile* file, bool append, EFlushMode flushMode) +{ + _logs().push_back(new vfs::Log(file, append, flushMode)); + return _logs().back(); +} + +void vfs::Log::flushDeleteAll() +{ + LogList_t::iterator it = _logs().begin(); + for(; it != _logs().end(); ++it) + { + (*it)->flush(); + (*it)->Release(); + } + _logs().clear(); +} + +void vfs::Log::flushReleaseAll() +{ + LogList_t::iterator it = _logs().begin(); + for(; it != _logs().end(); ++it) + { + (*it)->releaseFile(); + } +} + +vfs::String vfs::Log::_shared_id_str; + +vfs::String const& vfs::Log::getSharedString() +{ + return _shared_id_str; +} + +void vfs::Log::setSharedString(vfs::String const& str) +{ + _shared_id_str = str; +} + + +vfs::Log::Log(vfs::Path const& fileName, bool use_vfs_file, bool append, EFlushMode flushMode) +: IRefCountable(), + _filename(fileName), _file(NULL), _own_file(false), + _first_write(true), _flush_mode(flushMode), _append(append), + _buffer_size(0), _buffer_test_size(512) +{}; + +vfs::Log::Log(vfs::tWritableFile* file, bool append, EFlushMode flushMode) +: IRefCountable(), + _file(file), _own_file(false), + _first_write(true), _flush_mode(flushMode), _append(append), + _buffer_size(0), _buffer_test_size(512) +{ +} + + +vfs::Log::~Log() +{ + // the final flush + flush(); + + // also delete file pointer if we created it + if(_file && _own_file) + { + delete _file; + _file = NULL; + } + + // one extra unlock wouldn't hurt + _mutex.unlock(); +} + +int vfs::Log::Reserve() +{ + VFS_LOCK(_mutex); + return this->Register(); +} +int vfs::Log::Release() +{ + _mutex.lock(); + int tmp_count = this->UnRegister(); + if(tmp_count > 0) + { + _mutex.unlock(); + } + // otherwise the mutex object is destroyed at that time + return tmp_count; +} +int vfs::Log::RefCount() +{ + VFS_LOCK(_mutex); + return this->GetRefCount(); +} + + +void vfs::Log::destroy() +{ + // no need to lock here as 'flush' and 'Release' do it themselves + this->flush(); + if(this->Release() <= 0) + { + // object is deleted, so remove it now from the static list + _logs().remove(this); + } +} + +void vfs::Log::releaseFile() +{ + VFS_LOCK(_mutex); + this->flush(); + this->_file = NULL; +} + +vfs::Log& vfs::Log::operator<<(vfs::UInt64 const& t) +{ + VFS_LOCK(_mutex); + return pushNumber(t); +} +vfs::Log& vfs::Log::operator<<(vfs::UInt32 const& t) +{ + VFS_LOCK(_mutex); + return pushNumber(t); +} +vfs::Log& vfs::Log::operator<<(vfs::UInt16 const& t) +{ + VFS_LOCK(_mutex); + return pushNumber(t); +} +vfs::Log& vfs::Log::operator<<(vfs::UInt8 const& t) +{ + VFS_LOCK(_mutex); + return pushNumber(t); +} + +vfs::Log& vfs::Log::operator<<(vfs::Int64 const& t) +{ + VFS_LOCK(_mutex); + return pushNumber(t); +} +vfs::Log& vfs::Log::operator<<(vfs::Int32 const& t) +{ + VFS_LOCK(_mutex); + return pushNumber(t); +} +vfs::Log& vfs::Log::operator<<(vfs::Int16 const& t) +{ + VFS_LOCK(_mutex); + return pushNumber(t); +} +vfs::Log& vfs::Log::operator<<(vfs::Int8 const& t) +{ + VFS_LOCK(_mutex); + return pushNumber(t); +} +#ifdef _MSC_VER + vfs::Log& vfs::Log::operator<<(DWORD const& t) + { + VFS_LOCK(_mutex); + return pushNumber(t); + } +#endif +vfs::Log& vfs::Log::operator<<(float const& t) +{ + VFS_LOCK(_mutex); + return pushNumber(t); +} +vfs::Log& vfs::Log::operator<<(double const& t) +{ + VFS_LOCK(_mutex); + return pushNumber(t); +} + +vfs::Log& vfs::Log::operator<<(const char* t) +{ + VFS_LOCK(_mutex); + _buffer << t; + _buffer_size += strlen(t); + _test_flush(); + return *this; +} +vfs::Log& vfs::Log::operator<<(const wchar_t* t) +{ + VFS_LOCK(_mutex); + std::string s = vfs::String::as_utf8(t); + _buffer << s; + _buffer_size += s.length(); + _test_flush(); + return *this; +} +vfs::Log& vfs::Log::operator<<(std::string const& t) +{ + VFS_LOCK(_mutex); + _buffer << t; + _buffer_size += t.length(); + _test_flush(); + return *this; +} +vfs::Log& vfs::Log::operator<<(std::wstring const& t) +{ + VFS_LOCK(_mutex); + std::string s = vfs::String::as_utf8(t); + _buffer << s; + _buffer_size += s.length(); + _test_flush(); + return *this; +} +vfs::Log& vfs::Log::operator<<(vfs::String const& t) +{ + VFS_LOCK(_mutex); + std::string s = t.utf8(); + _buffer << s; + _buffer_size += s.length(); + _test_flush(); + return *this; +} + +vfs::Log& vfs::Log::operator<<(void* const& t) +{ + VFS_LOCK(_mutex); + _buffer << t; + return *this; +} + +vfs::Log& vfs::Log::operator<<(vfs::Log::_endl const& endl) +{ + VFS_LOCK(_mutex); + _buffer << ENDL; + _buffer_size += sizeof(ENDL)-1; + if(_flush_mode == vfs::Log::FLUSH_ON_ENDL) flush(); + return *this; +} + +/* +vfs::Log& vfs::Log::endl() +{ + _buffer << ENDL; + _buffer_size += sizeof(ENDL)-1; + _test_flush(); + return *this; +} +*/ +void vfs::Log::setAppend(bool append) +{ + VFS_LOCK(_mutex); + _append = append; +} + +void vfs::Log::setBufferSize(vfs::UInt32 bufferSize) +{ + VFS_LOCK(_mutex); + _buffer_test_size = bufferSize; +} + +void vfs::Log::_test_flush(bool force) +{ + if( (_flush_mode == FLUSH_IMMEDIATELY) || + (_flush_mode == FLUSH_BUFFER && _buffer_size > _buffer_test_size) || + (/*_flush_mode == FLUSH_ON_DELETE &&*/ force == true) ) + { + flush(); + } +} + + +vfs::Log::EFlushMode vfs::Log::flushMode() +{ + return _flush_mode; +} +void vfs::Log::flushMode(vfs::Log::EFlushMode fmode) +{ + _flush_mode = fmode; +} + +#include +#include + +void vfs::Log::flush() +{ + VFS_LOCK(_mutex); + ::size_t buflen = _buffer.str().length(); + if(buflen == 0) + { + return; + } + + if(!_file) + { + VFS_THROW_IFF(!_filename.empty(), L"_file is NULL and _filename is empty"); + //vfs::CVirtualProfile *prof = getVFS()->getProfileStack()->topProfile(); + //if( prof && prof->cWritable ) + if(vfs::canWrite()) + { + try + { + vfs::COpenWriteFile file_raii(_filename,true,!_append); + _file = &file_raii.file(); + file_raii.release(); + _own_file = false; + } + catch(...) + { + } + } + else + { + try + { + _file = vfs::tWritableFile::cast(new vfs::CFile(_filename)); + _file->openWrite(true,!_append); + _own_file = true; + } + catch(...) + { + } + } + } + + vfs::COpenWriteFile wfile(_file); + if(_append) + { + wfile->setWritePosition(0,vfs::IBaseFile::SD_END); + } + + if(_first_write) + { + time_t rawtime; + time ( &rawtime ); + std::string datetime(ctime(&rawtime)); + std::string s_out; + + vfs::size_t wloc = wfile->getWritePosition(); + if(wloc > 0) + { + s_out = ENDL; + } + s_out += " *** "; + s_out += datetime.substr(0,datetime.length()-1); + s_out += " *** "; + s_out += ENDL; + s_out += "[ "; + s_out += _shared_id_str.utf8(); + s_out += " ]"; + s_out += ENDL; + s_out += ENDL; + + wfile->write(s_out.c_str(), s_out.length()); + _first_write = false; + } + + wfile->write(_buffer.str().c_str(), buflen); + _buffer.str(""); + _buffer.clear(); + _buffer_size = 0; + + _append = true; +} + +void vfs::Log::lock() +{ + _mutex.lock(); +} +void vfs::Log::unlock() +{ + _mutex.unlock(); +} diff --git a/ext/VFS/src/Tools/vfs_parser_tools.cpp b/ext/VFS/src/Tools/vfs_parser_tools.cpp new file mode 100644 index 000000000..dbd7c74bc --- /dev/null +++ b/ext/VFS/src/Tools/vfs_parser_tools.cpp @@ -0,0 +1,249 @@ +/* + * bfVFS : vfs/Tools/vfs_parser_tools.cpp + * - read file line-wise, + * - split string into tokens, + * - simple pattern matching + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include + +/*************************************************************************************/ +/*************************************************************************************/ + +vfs::CReadLine::CReadLine(vfs::tReadableFile& rFile) +: _file(rFile), _buffer_pos(0), _eof(false) +{ + memset(_buffer,0,sizeof(_buffer)); + + vfs::COpenReadFile rfile(&_file); + _bytes_left = rfile->getSize(); + fillBuffer(); + vfs::UByte utf8bom[3] = {0xef,0xbb,0xbf}; + if(memcmp(utf8bom, &_buffer[0],3) == 0) + { + _buffer_pos += 3; + } + rfile.release(); +}; + +vfs::CReadLine::~CReadLine() +{ + if(_file.isOpenRead()) + { + _file.close(); + } +} + +bool vfs::CReadLine::fillBuffer() +{ + if(_eof) + { + return false; + } + vfs::size_t bytesRead = BUFFER_SIZE < _bytes_left ? BUFFER_SIZE : _bytes_left; + try + { + vfs::COpenReadFile rfile(&_file); + + // fill the buffer from the start, BUFFER_SIZE charactes at max (_buffer has BUFFER_SIZE+1 elements) + VFS_THROW_IFF(bytesRead == _file.read(&_buffer[0], bytesRead), L""); + rfile.release(); + } + catch(std::exception& ex) + { + VFS_RETHROW(L"", ex); + } + + _bytes_left -= bytesRead; + _eof = (_bytes_left == 0); + + + // bite-wise read files usually terminate a line with \n (or \r\n on WIN32) + // line-wise read files just returns 0-terminated string + + // always terminate the string with 0 + _buffer[bytesRead] = 0; + + _buffer_pos = 0; + _buffer_last = bytesRead; + + return true; +} + +bool vfs::CReadLine::fromBuffer(std::string& line) +{ + bool done = false; + while(!done) + { + if(_buffer_pos < _buffer_last) + { + // start where we left last time + vfs::Byte *temp = &_buffer[_buffer_pos]; + vfs::size_t start_pos = _buffer_pos; + // go until we hit 0. since our buffer is always 0 terminated, the second test should be redundant. + while(*temp && (_buffer_pos < _buffer_last)) + { + // stop when we find a line terminator + if(*temp == '\n' || *temp == '\r' /* || *temp == '\0' */) + { + break; + } + temp++; + _buffer_pos++; + } + // need to append substring, as we might have refilles the buffer (because there was no \n or \r\n terminator) + line.append( (char*)&_buffer[start_pos], _buffer_pos - start_pos ); + + // if we reach the (real) end of the buffer (that always terminate with 0), this means + // that there was no line terminator and that we have to refill the buffer. + if( _buffer_pos < BUFFER_SIZE && (*temp == '\n' || *temp == '\r' || *temp == 0) ) + { + // found the line terminator + if(*temp == '\r') + { + // the \r is most probably followed by \n. 'swallow' both characters + *temp++; + _buffer_pos++; + if( (_buffer_pos < BUFFER_SIZE) && (*temp == '\n' || *temp == 0) ) + { + // increase buffer position, so that we can start with a valid character in the next run + _buffer_pos++; + return true; + } + else + { + done = !fillBuffer(); + } + } + else if(*temp == '\n' || *temp == 0) + { + // increase buffer position, so that we can start with a valid character in the next run + _buffer_pos++; + return true; + } + } + else + { + done = !fillBuffer(); + } + } + else + { + done = !fillBuffer(); + } + } + return false; +} + +bool vfs::CReadLine::getLine(std::string& line) +{ + line.clear(); + return fromBuffer(line); +} + +/*************************************************************************************/ +/*************************************************************************************/ + +vfs::CTokenizer::CTokenizer(vfs::String const& str) +: m_list(str), m_current(0), m_next(0) +{}; + +vfs::CTokenizer::~CTokenizer() +{}; + +bool vfs::CTokenizer::next(vfs::String& token, vfs::String::char_t delimeter) +{ + if(m_next != vfs::String::str_t::npos) + { + m_next = m_list.c_wcs().find_first_of(delimeter, m_current); + if(m_next != vfs::String::str_t::npos) + { + token.r_wcs().assign(vfs::trimString(m_list,m_current,m_next > m_current ? m_next-1 : m_current).c_wcs()); + m_current = m_next+1; + } + else + { + // last or only entry + token.r_wcs().assign(vfs::trimString(m_list,m_current,m_list.length()).c_wcs()); + } + return true; + } + return false; +} + +/*************************************************************************************/ +/*************************************************************************************/ + +/** + * try to recursively match the pattern + */ +bool vfs::matchPattern(vfs::String const& sPattern, vfs::String const& sStr) +{ + return matchPattern(sPattern,sStr.c_wcs()); +} + +bool vfs::matchPattern(vfs::String const& sPattern, vfs::String::str_t const& sStr) +{ + vfs::String::str_t const& pat = sPattern.c_wcs(); + + vfs::String::size_t star = pat.find_first_of(vfs::Const::STAR()); + if(star == vfs::String::str_t::npos) + { + return vfs::StrCmp::Equal( pat, sStr ); + } + else if(star == 0) + { + if(pat.length() == 1) + { + // there is only the '*' -> matches all strings + return true; + } + vfs::String::char_t atpos1 = pat.at(1); + vfs::String::size_t match = vfs::String::size_t(-1); + do + { + match = sStr.find_first_of(atpos1,match+1); + if(match == vfs::String::str_t::npos) + { + return false; + } + } while(!matchPattern( pat.substr(1,pat.length()-1), sStr.substr(match,sStr.length()-match) )); + return true; + } + else // if(star > 0) + { + // check if characters before * match + if(!vfs::StrCmp::Equal(pat.substr(0,star), sStr.substr(0,star)) ) + { + return false; + } + return matchPattern( pat.substr(star,pat.length()-star), sStr.substr(star,sStr.length()-star) ); + } +} + +/*************************************************************************************/ +/*************************************************************************************/ diff --git a/ext/VFS/src/Tools/vfs_profiler.cpp b/ext/VFS/src/Tools/vfs_profiler.cpp new file mode 100644 index 000000000..e6e4c64d2 --- /dev/null +++ b/ext/VFS/src/Tools/vfs_profiler.cpp @@ -0,0 +1,173 @@ +/* + * bfVFS : vfs/Tools/vfs_profiler.cpp + * - basic profiler class and macros to measure execution time of code blocks + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define NOMINMAX +#include + +#include +#include +#include + +namespace vfs +{ + class CProfileStarter + { + public: + CProfileStarter() + { + Profiler::getProfiler(); + } + }; + static CProfileStarter starter; +} + +vfs::Profiler& vfs::Profiler::getProfiler() +{ + static Profiler* _prof = new Profiler; + return *_prof; +} + +vfs::Profiler::Profiler() +{ + m_vMarker.resize(1024); + _nextMarker = 0; +} + +void vfs::Profiler::clear() +{ + for(unsigned int i = 0; i < _nextMarker; ++i) + { + m_vMarker[i].markername = ""; + m_vMarker[i].time = 0; + m_vMarker[i].call_count = 0; + m_vMarker[i].success_count = 0; + m_vMarker[i].fail_count = 0; + } + _nextMarker = 0; +} + + +vfs::Profiler::tMarkerID vfs::Profiler::registerMarker(const char *marker) +{ + m_vMarker[_nextMarker].markername = marker; + return _nextMarker++; +} + +void vfs::Profiler::startMarker(tMarkerID id) +{ + m_vMarker[id].timer.startTimer(); +} + +void vfs::Profiler::stopMarker(tMarkerID id, bool success) +{ + m_vMarker[id].timer.stopTimer(); + m_vMarker[id].time += m_vMarker[id].timer.getElapsedTimeInSeconds(); + m_vMarker[id].call_count++; + if(success) m_vMarker[id].success_count++; + else m_vMarker[id].fail_count++; +} + +inline std::string multChar(std::string::value_type c, unsigned int multiplicity) +{ + std::string s; + s.resize(multiplicity); + for(unsigned int i=0; i max_time) + { + max_time = m_vMarker[i].time; + } + std::string::size_type prefix_length = m_vMarker[i].markername.length(); + if(prefix_length > max_prefix) + { + max_prefix = prefix_length; + } + } + const unsigned int WIDTH = 40; + std::stringstream line; + long double ld_success, ld_failure; + for(unsigned int i=0; i key-value map with capability to convert values to other types + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +/*************************************************************************************/ +/*************************************************************************************/ + +bool vfs::PropertyContainer::Section::has(vfs::String const& key) +{ + return mapProps.find(key) != mapProps.end(); +} + +bool vfs::PropertyContainer::Section::add(vfs::String const& key, vfs::String const& value) +{ + if(!mapProps[key].empty()) + { + mapProps[key] += L", "; + } + mapProps[key] += value; + return true; +} + +vfs::String& vfs::PropertyContainer::Section::value(vfs::String const& key) +{ + return mapProps[key]; +} +bool vfs::PropertyContainer::Section::value(vfs::String const& key, vfs::String& value) +{ + tProps::iterator sit = mapProps.find(key); + if(sit != mapProps.end()) + { + value.r_wcs().assign(sit->second.c_wcs()); + return true; + } + return false; +} +void vfs::PropertyContainer::Section::print(std::ostream& out, vfs::String::str_t sPrefix) +{ + tProps::iterator sit = mapProps.begin(); + for(; sit != mapProps.end(); ++sit) + { + out << vfs::String::as_utf8(sPrefix) << sit->first.utf8() << " = " << sit->second.utf8() << "\r\n"; + } +} + +void vfs::PropertyContainer::Section::clear() +{ + mapProps.clear(); +} + +/*************************************************************************************/ +/*************************************************************************************/ +void vfs::PropertyContainer::clearContainer() +{ + tSections::iterator it = m_mapProps.begin(); + for(;it != m_mapProps.end(); ++it) + { + it->second.clear(); + } + m_mapProps.clear(); +} + +bool vfs::PropertyContainer::extractSection(vfs::String::str_t const& readStr, vfs::size_t startPos, vfs::String::str_t& sSection) +{ + // extract section name + vfs::size_t close = readStr.find_first_of(L"]", startPos); + if( close != vfs::npos && close > startPos) + { + startPos += 1; + sSection = vfs::trimString(readStr,startPos,(vfs::size_t)(close-1)); + return true; + } + return false; +} + +vfs::PropertyContainer::EOperation vfs::PropertyContainer::extractKeyValue(vfs::String::str_t const &readStr, vfs::size_t startPos, vfs::String::str_t& sKey, vfs::String::str_t& sValue) +{ + vfs::size_t iEqual = readStr.find_first_of(L"+=", startPos); + if(iEqual == vfs::npos) + { + VFS_LOG_WARNING(_BS("WARNING : could not extract key-value pair : ") << readStr << _BS::wget); + return vfs::PropertyContainer::Error; + } + // extract key + sKey = vfs::trimString(readStr,0,iEqual-1); + // extract value + EOperation op = vfs::PropertyContainer::Set; + if( readStr.at(iEqual) == L'+' ) + { + if( (iEqual+1) < readStr.size() && (readStr.at(iEqual+1) == L'=') ) + { + iEqual += 1; + op = vfs::PropertyContainer::Add; + } + } + sValue = vfs::trimString(readStr,iEqual+1,readStr.size()); + return op; +} + + +bool vfs::PropertyContainer::initFromIniFile(vfs::Path const& sFileName) +{ + // try to open via VirtualFileSystem + if(getVFS()->fileExists(sFileName)) + { + return initFromIniFile(getVFS()->getReadFile(sFileName)); + } + else + { + vfs::CFile file(sFileName); + if(file.openRead()) + { + return initFromIniFile(vfs::tReadableFile::cast(&file)); + } + return false; + } +} + +bool vfs::PropertyContainer::initFromIniFile(vfs::tReadableFile *pFile) +{ + if(!pFile) + { + return false; + } + + std::string sBuffer; + vfs::String::str_t sCurrentSection; + int line_counter = 0; + CReadLine rl(*pFile); + while(rl.getLine(sBuffer)) + { + line_counter++; + // very simple parsing : key = value + if(!sBuffer.empty()) + { + // remove leading white spaces + ::size_t iStart = sBuffer.find_first_not_of(" \t",0); + if(iStart == std::string::npos) + { + // only white space characters + continue; + } + char first = sBuffer.at(iStart); + switch(first) + { + case '!': + case ';': + case '#': + // comment -> do nothing + break; + case '[': + { + vfs::String u8s; + try + { + vfs::String::as_utf16(sBuffer.substr(iStart, sBuffer.length()-iStart), u8s.r_wcs()); + } + catch(std::exception& ex) + { + VFS_RETHROW( _BS(L"Conversion error in file \"") << pFile->getPath() + << L"\", line " << line_counter << _BS::wget, ex); + } + if(this->extractSection(u8s.c_wcs(), 0, sCurrentSection)) + { + m_mapProps[sCurrentSection]; + } + else + { + VFS_LOG_WARNING(_BS("WARNING : could not extract section name : ") << sBuffer << _BS::wget); + } + } + break; + default: + { + // probably key-value pair + vfs::String::str_t u8s; + try + { + vfs::String::as_utf16(sBuffer.substr(iStart, sBuffer.length()-iStart), u8s); + } + catch(std::exception& ex) + { + VFS_RETHROW( _BS(L"Conversion error in file \"") << pFile->getPath() + << L"\", line " << line_counter << _BS::wget, ex); + } + vfs::String::str_t sKey, sValue; + EOperation op = this->extractKeyValue(u8s, 0, sKey, sValue); + if(op != Error) + { + // add key-value pair to map + if(m_mapProps.find(sCurrentSection) != m_mapProps.end()) + { + if(op == Set) + { + this->section(sCurrentSection).value(sKey) = sValue; + } + else if(op == Add) + { + this->section(sCurrentSection).add(sKey, sValue); + } + } + else + { + VFS_LOG_WARNING(_BS(L"ERROR : could not find section [") << sCurrentSection + << L"] in container" << _BS::wget); + } + } + } + break; + }; // end switch + } // end if (empty) + } // end while(!eof) + return true; +} + +static vfs::UByte utf8bom[4] = {0xef,0xbb,0xbf,0x0}; + +bool vfs::PropertyContainer::writeToIniFile(vfs::Path const& sFilename, bool bCreateNew) +{ +#ifdef WIN32 + const char ENDL[] = "\r\n"; +#else + const char ENDL[] = "\n"; +#endif + if(bCreateNew) + { + vfs::tWritableFile* file; + bool delete_file = false; + try + { + vfs::COpenWriteFile wfile(sFilename,true,true); + file = &wfile.file(); + wfile.release(); + } + catch(std::exception& ex) + { + VFS_LOG_WARNING(ex.what()); + // vfs not initialized? + vfs::CFile* cfile = new vfs::CFile(sFilename); + cfile->openWrite(true,true); + file = vfs::tWritableFile::cast(cfile); + delete_file = true; + } + tSections::iterator sit = m_mapProps.begin(); + std::stringstream ss; + std::string str; + ss << (char*)utf8bom; + for(; sit != m_mapProps.end(); ++sit) + { + ss.str(""); + ss << "[" << sit->first.utf8() << "]" << ENDL; + str = ss.str(); + file->write(str.c_str(), str.length()); + + ss.clear(); + ss.str(""); + Section& section = sit->second; + section.print(ss); + ss << ENDL; + str = ss.str(); + file->write(str.c_str(),str.length()); + } + file->close(); + if(delete_file) + { + delete file; + } + return true; + } + else + { + // try to open via VirtualFileSystem + vfs::CBufferFile rfile; + if(getVFS()->fileExists(sFilename)) + { + vfs::COpenReadFile rf(sFilename); + rfile.copyToBuffer(rf.file()); + } + else if(getVFS()->createNewFile(sFilename)) + { + vfs::tReadableFile* pFile = getVFS()->getReadFile(sFilename); + if(pFile && pFile->openRead()) + { + rfile.copyToBuffer(*pFile); + pFile->close(); + } + } + else + { + // file doesn't exist or VFS not initialized yet + vfs::CFile file(sFilename); + rfile.copyToBuffer(*vfs::tReadableFile::cast(&file)); + } + std::stringstream outbuffer; + + std::string sBuffer; + vfs::String::str_t sCurrentSection; + + std::set setKeys; + std::set setSections; + tSections::iterator sit = m_mapProps.begin(); + for(; sit != m_mapProps.end(); ++sit) + { + setSections.insert(sit->first); + } + + CReadLine rl(*vfs::tReadableFile::cast(&rfile)); + outbuffer << (char*)(utf8bom); + vfs::UInt32 line_counter = 0; + while(rl.getLine(sBuffer)) + { + line_counter++; + if(!sBuffer.empty()) + { + // remove leading white spaces + ::size_t iStart = sBuffer.find_first_not_of(" \t",0); + char first = sBuffer.at(iStart); + switch(first) + { + case '!': + case ';': + case '#': + outbuffer << sBuffer << ENDL; + break; + case '[': + { + vfs::String u8s; + try + { + vfs::String::as_utf16(sBuffer.substr(iStart, sBuffer.length()-iStart), u8s.r_wcs()); + } + catch(std::exception& ex) + { + VFS_RETHROW(_BS(L"Conversion error in file \"") << sFilename + << L"\", line " << line_counter << _BS::wget, ex); + } + vfs::String::str_t oldSection = sCurrentSection; + if(this->extractSection(u8s.c_wcs(), 0, sCurrentSection)) + { + if(setSections.find(sCurrentSection) == setSections.end()) + { + // section already handled ?!?!?! + // just print duplicate version + outbuffer << vfs::String::as_utf8(sBuffer) << ENDL; + break; + } + if(!setKeys.empty()) + { + // there are new keys in the previous section + Section& oldsec = m_mapProps[oldSection]; + + std::set::iterator kit = setKeys.begin(); + for(; kit != setKeys.end(); ++kit) + { + outbuffer << vfs::String::as_utf8(*kit) << " = " << vfs::String::as_utf8(oldsec.value(*kit)) << ENDL; + } + // all remaining keys were written, clear set + setKeys.clear(); + outbuffer << ENDL; + } + Section& sec = m_mapProps[sCurrentSection]; + Section::tProps::iterator it = sec.mapProps.begin(); + for(; it != sec.mapProps.end(); ++it) + { + setKeys.insert(it->first); + } + } + outbuffer << vfs::String::as_utf8(sBuffer) << ENDL; + } + break; + default: + { + // probably key-value pair + vfs::String u8s; + try + { + vfs::String::as_utf16(sBuffer.substr(iStart, sBuffer.length()-iStart), u8s.r_wcs()); + } + catch(std::exception& ex) + { + VFS_RETHROW(_BS(L"Conversion error in file \"") << sFilename + << L"\", line " << line_counter << _BS::wget, ex); + } + vfs::String::str_t sKey, sValue; + if(this->extractKeyValue(u8s.c_wcs(), 0, sKey, sValue)) + { + if(setKeys.find(sKey) != setKeys.end()) + { + outbuffer << vfs::String::as_utf8(sKey) << " = " << vfs::String::as_utf8(m_mapProps[sCurrentSection].value(sKey)) << "\r\n"; + setKeys.erase(sKey); + } + else + { + outbuffer << vfs::String::as_utf8(sBuffer) << ENDL; + } + if(setKeys.empty()) + { + setSections.erase(sCurrentSection); + } + } + } + break; + }; // end switch + } + else + { + outbuffer << ENDL; + } + } + if(!setKeys.empty()) + { + Section& sec = m_mapProps[sCurrentSection]; + std::set::iterator kit = setKeys.begin(); + for(; kit != setKeys.end(); ++kit) + { + outbuffer << vfs::String::as_utf8(*kit) << " = " << vfs::String::as_utf8(sec.value(*kit)) << ENDL; + } + setKeys.clear(); + if(setKeys.empty()) + { + setSections.erase(sCurrentSection); + } + } + std::set::iterator it = setSections.begin(); + for(; it != setSections.end(); ++it) + { + outbuffer << ENDL << "[" << vfs::String::as_utf8(*it) << "]" << ENDL; + std::stringstream ss; + m_mapProps[*it].print(outbuffer); + } + + try + { + vfs::COpenWriteFile wfile(sFilename,true,true); + wfile->write(outbuffer.str().c_str(),(vfs::size_t)outbuffer.str().length()); + } + catch(std::exception& ex) + { + VFS_LOG_WARNING(ex.what()); + vfs::CFile file(sFilename); + if(file.openWrite(true,true)) + { + file.write(outbuffer.str().c_str(),(vfs::size_t)outbuffer.str().length()); + file.close(); + } + } + return true; + } +} + + +void vfs::PropertyContainer::printProperties(std::ostream &out) +{ + tSections::iterator pit = m_mapProps.begin(); + for(;pit != m_mapProps.end(); ++pit) + { + out << "[" << pit->first.utf8() << "]\n"; + pit->second.print(out, L" "); + out << std::endl; + } +} + + +vfs::PropertyContainer::Section& vfs::PropertyContainer::section(vfs::String const& sSection) +{ + return m_mapProps[sSection]; +} + +bool vfs::PropertyContainer::getValueForKey(vfs::String const& sSection, vfs::String const& sKey, vfs::String &sValue) +{ + tSections::iterator pit = m_mapProps.find(vfs::trimString(sSection,0,(vfs::size_t)sSection.length())); + if( pit != m_mapProps.end() ) + { + return pit->second.value( vfs::trimString(sKey,0,(vfs::size_t)sKey.length()), sValue ); + } + return false; +} + +bool vfs::PropertyContainer::hasProperty(vfs::String const& sSection, vfs::String const& sKey) +{ + tSections::iterator pit = m_mapProps.find(vfs::trimString(sSection,0,(vfs::size_t)sSection.length())); + if( pit != m_mapProps.end() ) + { + return pit->second.has(vfs::trimString(sKey,0,sKey.length())); + } + return false; +} + +vfs::String const& vfs::PropertyContainer::getStringProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::String const& sDefaultValue) +{ + vfs::PropertyContainer::tSections::iterator sit = m_mapProps.find(sSection); + if(sit != m_mapProps.end()) + { + vfs::PropertyContainer::Section::tProps::iterator pit = sit->second.mapProps.find(sKey); + if(pit != sit->second.mapProps.end()) + { + return pit->second; + } + } + return sDefaultValue; +} + +bool vfs::PropertyContainer::getStringProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::String& sValue, vfs::String const& sDefaultValue) +{ + if(getValueForKey(sSection,sKey,sValue)) + { + return true; + } + sValue = sDefaultValue; + return false; +} + +bool vfs::PropertyContainer::getStringProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::String::char_t* sValue, vfs::size_t len, vfs::String const& sDefaultValue) +{ + vfs::String s; + if(getValueForKey(sSection,sKey,s)) + { + vfs::size_t l = std::min(s.length(), len-1); + wcsncpy(sValue,s.c_str(), l); + sValue[l] = 0; + return true; + } + vfs::size_t l = std::min(sDefaultValue.length(), len-1); + wcsncpy(sValue,sDefaultValue.c_str(), l); + sValue[l] = 0; + return false; +} + +vfs::Int64 vfs::PropertyContainer::getIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::Int64 iDefaultValue, vfs::Int64 iMinValue, vfs::Int64 iMaxValue) +{ + return std::min(iMaxValue, std::max(iMinValue, this->getIntProperty(sSection, sKey, iDefaultValue))); +} + +vfs::Int64 vfs::PropertyContainer::getIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::Int64 iDefaultValue) +{ + vfs::String sValue; + if(getValueForKey(sSection,sKey,sValue)) + { + vfs::Int64 iRetVal; + if(convertTo(sValue,iRetVal)) + { + return iRetVal; + } + } + return iDefaultValue; +} + +vfs::UInt64 vfs::PropertyContainer::getUIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::UInt64 iDefaultValue, vfs::UInt64 iMinValue, vfs::UInt64 iMaxValue) +{ + return std::min(iMaxValue, std::max(iMinValue, this->getIntProperty(sSection, sKey, iDefaultValue))); +} + +vfs::UInt64 vfs::PropertyContainer::getUIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::UInt64 iDefaultValue) +{ + vfs::String sValue; + if(getValueForKey(sSection,sKey,sValue)) + { + vfs::UInt64 iRetVal; + if(convertTo(sValue,iRetVal)) + { + return iRetVal; + } + } + return iDefaultValue; +} + +double vfs::PropertyContainer::getFloatProperty(vfs::String const& sSection, vfs::String const& sKey, double fDefaultValue, double fMinValue, double fMaxValue) +{ + return std::min(fMaxValue, std::max(fMinValue, this->getFloatProperty(sSection, sKey, fDefaultValue))); +} + +double vfs::PropertyContainer::getFloatProperty(vfs::String const& sSection, vfs::String const& sKey, double fDefaultValue) +{ + vfs::String sValue; + if(getValueForKey(sSection,sKey,sValue)) + { + double fRetVal; + if(convertTo(sValue,fRetVal)) + { + return fRetVal; + } + } + return fDefaultValue; +} + +bool vfs::PropertyContainer::getBoolProperty(vfs::String const& sSection, vfs::String const& sKey, bool bDefaultValue) +{ + vfs::String sValue; + if(getValueForKey(sSection,sKey,sValue)) + { + vfs::Int32 iRetVal; + if( StrCmp::Equal(sValue,L"true") || ( convertTo<>(sValue,iRetVal) && (iRetVal != 0) ) ) + { + return true; + } + else if( StrCmp::Equal(sValue,"false") || ( convertTo<>(sValue,iRetVal) && (iRetVal == 0) ) ) + { + return false; + } + // else return bDefaultValue + } + return bDefaultValue; +} + +bool vfs::PropertyContainer::getStringListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list &lValueList, vfs::String sDefaultValue) +{ + vfs::String sValue; + if(getValueForKey(sSection,sKey,sValue)) + { + CTokenizer splitter(sValue); + vfs::String entry; + while( splitter.next(entry, L',') ) + { + lValueList.push_back(vfs::trimString(entry,0,entry.length())); + } + return true; + } + return false; +} + +bool vfs::PropertyContainer::getIntListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list &lValueList, vfs::Int64 iDefaultValue) +{ + vfs::String sValue; + if(getValueForKey(sSection,sKey,sValue)) + { + vfs::String entry; + CTokenizer splitter(sValue); + while( splitter.next(entry, L',') ) + { + vfs::Int64 iRetVal; + if(convertTo(entry,iRetVal)) + { + lValueList.push_back(iRetVal); + } + else + { + lValueList.push_back(iDefaultValue); + } + } + return true; + } + return false; +} + +bool vfs::PropertyContainer::getUIntListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list &lValueList, vfs::UInt64 iDefaultValue) +{ + vfs::String sValue; + if(getValueForKey(sSection,sKey,sValue)) + { + vfs::String entry; + CTokenizer splitter(sValue); + while( splitter.next(entry, L',') ) + { + vfs::UInt64 iRetVal; + if(convertTo(entry,iRetVal)) + { + lValueList.push_back(iRetVal); + } + else + { + lValueList.push_back(iDefaultValue); + } + } + return true; + } + return false; +} +bool vfs::PropertyContainer::getFloatListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list &lValueList, double fDefaultValue) +{ + vfs::String sValue; + if(getValueForKey(sSection,sKey,sValue)) + { + vfs::String entry; + CTokenizer splitter(sValue); + while( splitter.next(entry, L',') ) + { + double fRetVal; + if(convertTo(entry,fRetVal)) + { + lValueList.push_back(fRetVal); + } + else + { + lValueList.push_back(fDefaultValue); + } + } + return true; + } + return false; +} + +bool vfs::PropertyContainer::getBoolListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list &lValueList, bool bDefaultValue) +{ + vfs::String sValue; + if(getValueForKey(sSection,sKey,sValue)) + { + vfs::String entry; + CTokenizer splitter(sValue); + while( splitter.next(entry, L',') ) + { + vfs::Int32 iRetVal; + if( StrCmp::Equal(entry,L"true") || ( convertTo<>(entry,iRetVal) && (iRetVal != 0) ) ) + { + lValueList.push_back(true); + } + else if( StrCmp::Equal(entry,L"false") || ( convertTo<>(entry,iRetVal) && (iRetVal == 0) ) ) + { + lValueList.push_back(false); + } + else + { + lValueList.push_back(bDefaultValue); + } + } + return true; + } + return false; +} + +void vfs::PropertyContainer::setStringProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::String const& sValue) +{ + this->section(sSection).value(sKey) = sValue; +} + +void vfs::PropertyContainer::setIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::Int64 const& iValue) +{ + this->section(sSection).value(sKey) = toString(iValue); +} +void vfs::PropertyContainer::setUIntProperty(vfs::String const& sSection, vfs::String const& sKey, vfs::UInt64 const& iValue) +{ + this->section(sSection).value(sKey) = toString(iValue); +} +void vfs::PropertyContainer::setFloatProperty(vfs::String const& sSection, vfs::String const& sKey, double const& fValue) +{ + this->section(sSection).value(sKey) = toString(fValue); +} +void vfs::PropertyContainer::setBoolProperty(vfs::String const& sSection, vfs::String const& sKey, bool const& bValue) +{ + this->section(sSection).value(sKey) = toString(bValue); +} + +void vfs::PropertyContainer::setStringListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list const& slValue) +{ + this->section(sSection).value(sKey) = toStringList(slValue); +} + +void vfs::PropertyContainer::setIntListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list const& ilValue) +{ + this->section(sSection).value(sKey) = toStringList(ilValue); +} + +void vfs::PropertyContainer::setFloatListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list const& flValue) +{ + this->section(sSection).value(sKey) = toStringList(flValue); +} + +void vfs::PropertyContainer::setBoolListProperty(vfs::String const& sSection, vfs::String const& sKey, std::list const& blValue) +{ + this->section(sSection).value(sKey) = toStringList(blValue); +} + +/**************************************************************************************************/ +/**************************************************************************************************/ + diff --git a/ext/VFS/src/Tools/vfs_tools.cpp b/ext/VFS/src/Tools/vfs_tools.cpp new file mode 100644 index 000000000..c92ba7d0e --- /dev/null +++ b/ext/VFS/src/Tools/vfs_tools.cpp @@ -0,0 +1,87 @@ +/* + * bfVFS : vfs/Tools/vfs_tools.cpp + * - simple from/to string (list) conversion functions, + * - remove leading/trailing whitspace characters in a string + * + * Copyright (C) 2008 - 2010 (BF) john.bf.smith@googlemail.com + * + * This file is part of the bfVFS library + * + * This library 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.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +template<> +vfs::String vfs::toStringList(std::list const& rValList) +{ + std::wstringstream ss; + std::list::const_iterator cit = rValList.begin(); + if(cit != rValList.end()) + { + ss << (*cit); + cit++; + for(;cit != rValList.end(); ++cit) + { + ss << L" , " << (*cit); + } + } + if(!ss) + { + return L""; + } + return ss.str(); +} + +/*************************************************************************************/ +/*************************************************************************************/ + +template<> +std::string vfs::trimString(std::string const& sStr, vfs::size_t iMinPos, vfs::size_t iMaxPos) +{ + if(iMinPos > iMaxPos || iMaxPos == vfs::npos) + { + return ""; + } + ::size_t iStart,iEnd; + iStart = sStr.find_first_not_of(" \t\r\n",(::size_t)iMinPos); + iEnd = sStr.find_last_not_of(" \t\r\n",(::size_t)iMaxPos); + if( (iStart != std::string::npos) && (iEnd != std::string::npos) ) + { + return sStr.substr(iStart,iEnd-iStart+1); + } + return ""; +} +template<> +std::wstring vfs::trimString(std::wstring const& sStr, vfs::size_t iMinPos, vfs::size_t iMaxPos) +{ + if(iMinPos > iMaxPos || iMaxPos == vfs::npos) + { + return L""; + } + ::size_t iStart,iEnd; + iStart = sStr.find_first_not_of(L" \t\r\n",(::size_t)iMinPos); + iEnd = sStr.find_last_not_of(L" \t\r\n",(::size_t)iMaxPos); + if( (iStart != std::wstring::npos) && (iEnd != std::wstring::npos) ) + { + return sStr.substr(iStart,iEnd-iStart+1); + } + return L""; +} +template<> +vfs::String vfs::trimString(vfs::String const& sStr, vfs::size_t iMinPos, vfs::size_t iMaxPos) +{ + return vfs::trimString(sStr.c_wcs(), iMinPos, iMaxPos); +} diff --git a/ext/export/ja2export_VS2005.vcproj b/ext/export/ja2export_VS2005.vcproj new file mode 100644 index 000000000..9d1b55e6f --- /dev/null +++ b/ext/export/ja2export_VS2005.vcproj @@ -0,0 +1,311 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/export/ja2export_VS2008.vcproj b/ext/export/ja2export_VS2008.vcproj new file mode 100644 index 000000000..047d99dc5 --- /dev/null +++ b/ext/export/ja2export_VS2008.vcproj @@ -0,0 +1,311 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/export/ja2export_VS2010.vcxproj b/ext/export/ja2export_VS2010.vcxproj new file mode 100644 index 000000000..4ccac5c8d --- /dev/null +++ b/ext/export/ja2export_VS2010.vcxproj @@ -0,0 +1,131 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {802552D2-B514-42E5-A169-F1E108527678} + Win32Proj + ja2export + ja2export + + + + Application + true + NotSet + + + Application + false + true + NotSet + + + + + + + + + + + + + true + ..\..\bin\VS2010\$(Configuration)\ + ..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + false + ..\..\bin\VS2010\$(Configuration)\ + ..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;VFS_STATIC;VFS_WITH_SLF;VFS_WITH_7ZIP;%(PreprocessorDefinitions) + ../VFS/include;../libpng;../zlib;src;src/ja2 + MultiThreadedDebug + + + + + + + Console + true + $(OutDir)$(TargetName)$(TargetExt) + ..\..\lib\VS2010\$(Configuration) + VFS.lib;libpng.lib;zlib.lib;7z.lib;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;VFS_STATIC;VFS_WITH_SLF;VFS_WITH_7ZIP;%(PreprocessorDefinitions) + ../VFS/include;../libpng;../zlib; src; src/ja2 + MultiThreaded + + + + + + + Console + false + true + true + ..\..\lib\VS2010\$(Configuration) + VFS.lib;libpng.lib;zlib.lib;7z.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/export/ja2export_VS2010.vcxproj.filters b/ext/export/ja2export_VS2010.vcxproj.filters new file mode 100644 index 000000000..ccc6fbf9d --- /dev/null +++ b/ext/export/ja2export_VS2010.vcxproj.filters @@ -0,0 +1,96 @@ + + + + + {c97349a4-a55e-4206-ae81-5705c2f84ea5} + + + {6c1d591a-a1ba-48d9-a218-050f76b94603} + + + {f8947e60-d69b-4862-94fc-2d8750d2f206} + + + {0c1248dc-45f0-4ce5-91ea-f3ac46c3b380} + + + {5a926fd2-7e29-44ff-8025-475e78e86fe7} + + + + + + + + ja2 + + + ja2 + + + ja2 + + + ja2 + + + ja2 + + + ja2 + + + export\jsd + + + export\jsd + + + export\slf + + + export\sti + + + export\sti + + + export\sti + + + export\sti + + + + + + + + ja2 + + + ja2 + + + export\jsd + + + export\jsd + + + export\slf + + + export\sti + + + export\sti + + + export\sti + + + export\sti + + + \ No newline at end of file diff --git a/ext/export/src/export/jsd/export_jsd.cpp b/ext/export/src/export/jsd/export_jsd.cpp new file mode 100644 index 000000000..e7bb66301 --- /dev/null +++ b/ext/export/src/export/jsd/export_jsd.cpp @@ -0,0 +1,96 @@ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +bool ja2xp::convertJSDtoXML(vfs::Path const& sSrc, vfs::Path const& sDst) +{ + vfs::CVirtualFileSystem::Iterator it = getVFS()->begin(sSrc); + int file_counter = 0; + for(; !it.end(); it.next()) + { + file_counter++; + vfs::String::str_t fname = it.value()->getPath().c_wcs(); + if( !vfs::StrCmp::Equal( fname.substr(fname.length()-4,4), L".jsd") ) + { + std::wcout << L"\"" << fname << L"\" " << L"is not an .jsd file" << std::endl; + continue; + } + if(!it.value()->openRead()) + { + std::wcout << L"Could not open file \"" << sSrc() << L"\"" << std::endl; + continue; + } + vfs::String::str_t new_fname = fname.substr(0,fname.length()-4) + L".jsd.xml"; + vfs::Path out_name; + if(vfs::StrCmp::Equal(sDst(), L".")) + { + out_name = vfs::Path(new_fname); + } + else + { + out_name = sDst; + } + + std::wcout << L"Converting file \"" << it.value()->getPath().c_wcs() << L"\"" << std::endl; + + vfs::COpenWriteFile wfile(out_name,true,true); + if(!ConvertStructure(it.value(), &wfile.file())) + { + printf("Error converting file : %s", vfs::String::as_utf8(it.value()->getPath()())); + continue; + } + } + if(file_counter == 0) + { + std::wcout << L"Nothing to convert!" << std::endl; + } + return true; +} + +/**********************************************************************************************/ + +const wchar_t* ja2xp::CExportJSD::commandString = L"jsd"; + +void ja2xp::CExportJSD::handleCommand(param_list_t const& params) +{ + //param_list_t::const_iterator cit = params.begin(); + //for(; cit != params.end(); ++cit) + //{ + //} + + ja2xp::InitVFS& vfs = ja2xp::InitVFS::instance(); + vfs.checkParameters(params); + if(!vfs.init()) + { + return; + } + try + { + convertJSDtoXML(vfs.srcPattern(), vfs.dstPattern()); + } + catch(vfs::Exception& msg) + { + std::wcout << msg.getLastEntryString().c_str() << std::endl; + } +} + +void ja2xp::CExportJSD::printHelp() +{ + std::wcout + << L" convert JSD to XML file(s)" << std::endl + << L" * if \"destination\" is a directory, then the filename's extension will be" << std::endl + << L" replaced with \".jsd.xml\"" << std::endl + << std::endl; +} diff --git a/ext/export/src/export/jsd/export_jsd.h b/ext/export/src/export/jsd/export_jsd.h new file mode 100644 index 000000000..994dd2723 --- /dev/null +++ b/ext/export/src/export/jsd/export_jsd.h @@ -0,0 +1,25 @@ +#ifndef _EXPORT_JSD_H_ +#define _EXPORT_SLF_H_ + +#include +#include + +#include + +namespace ja2xp +{ + class CExportJSD : public IExporterBase + { + public: + typedef IExporterBase::param_list_t param_list_t; + + static const wchar_t* commandString;// = L"jsd"; + + virtual void handleCommand(param_list_t const& params); + virtual void printHelp(); + }; + + bool convertJSDtoXML(vfs::Path const& sSrc, vfs::Path const& sDst); +}; + +#endif // _EXPORT_SLF_H_ diff --git a/ext/export/src/export/jsd/structure.cpp b/ext/export/src/export/jsd/structure.cpp new file mode 100644 index 000000000..7f234e4fd --- /dev/null +++ b/ext/export/src/export/jsd/structure.cpp @@ -0,0 +1,293 @@ +#include +#include +#include + +#include +#include +#include +#include + +bool ja2xp::ConvertStructure(vfs::tReadableFile* pStructureFile, vfs::tWritableFile* pOutputFile) +{ + vfs::tReadableFile *pFile = pStructureFile; + if(!pFile) + { + return false; + } + vfs::COpenReadFile rfile(pFile); + + XMLWriter xmlw; + xmlw.addAttributeToNextValue( "filename", vfs::String::as_utf8( rfile->getPath()() ) ); + xmlw.openNode("STRUCTURE_FILE"); + + // Read Header + STRUCTURE_FILE_HEADER Header; + rfile->read((vfs::Byte*)&Header, sizeof( STRUCTURE_FILE_HEADER )); + + // Write Header data + xmlw.openNode("HEADER"); + xmlw.addValue("szId", std::string(Header.szId,0,4)); + xmlw.addValue("usNumberOfStructures", Header.usNumberOfStructures); + xmlw.addValue("usNumberOfImages", Header.usNumberOfImages); + + xmlw.addValue("usNumberOfStructuresStored", Header.usNumberOfStructuresStored); + xmlw.addValue("usNumberOfImageTileLocsStored", Header.usNumberOfImageTileLocsStored); + xmlw.addValue("usStructureDataSize", Header.usStructureDataSize); + if(Header.fFlags > 0) + { + xmlw.addAttributeToNextValue("uint",(void*)((UINT32)Header.fFlags)); + xmlw.openNode("flags"); + xmlw.addFlag(Header.fFlags, STRUCTURE_FILE_CONTAINS_AUXIMAGEDATA, "STRUCTURE_FILE_CONTAINS_AUXIMAGEDATA"); + xmlw.addFlag(Header.fFlags, STRUCTURE_FILE_CONTAINS_STRUCTUREDATA, "STRUCTURE_FILE_CONTAINS_STRUCTUREDATA"); + xmlw.closeNode(); + } + else + { + xmlw.addValue("flags"); + } + xmlw.closeNode(); + + if (Header.fFlags & STRUCTURE_FILE_CONTAINS_AUXIMAGEDATA) + { + UINT32 uiDataSize = sizeof( AuxObjectData ) * Header.usNumberOfImages; + sgp::AutoArray pAuxData(uiDataSize); + VFS_THROW_IFF( pAuxData(), L"" ); + + // Read AuxImage data + VFS_THROW_IFF( uiDataSize == rfile->read( (vfs::Byte*)pAuxData(), uiDataSize ), L"" ); + + // Write AuxImage data + xmlw.addAttributeToNextValue("number_of", Header.usNumberOfImages); + xmlw.openNode("AUXIMAGE_DATA"); + for(int i = 0; i < Header.usNumberOfImages; ++i) + { + xmlw.addAttributeToNextValue("index",i); + xmlw.openNode("auximage"); + AuxObjectData& auximage = pAuxData[i]; + xmlw.addValue("tile_loc_index", (int)auximage.usTileLocIndex); + xmlw.addValue("wall_orientation", (int)auximage.ubWallOrientation); + xmlw.addValue("number_of_tiles", (int)auximage.ubNumberOfTiles); + xmlw.addValue("current_frame", (int)auximage.ubCurrentFrame); + xmlw.addValue("number_of_frames", (int)auximage.ubNumberOfFrames); + if(auximage.fFlags > 0) + { + xmlw.addAttributeToNextValue("uint", (void*)((UINT32)auximage.fFlags)); + xmlw.openNode("flags"); + xmlw.addFlag(auximage.fFlags, AUX_FULL_TILE, "AUX_FULL_TILE"); + xmlw.addFlag(auximage.fFlags, AUX_ANIMATED_TILE, "AUX_ANIMATED_TILE"); + xmlw.addFlag(auximage.fFlags, AUX_DYNAMIC_TILE, "AUX_DYNAMIC_TILE"); + xmlw.addFlag(auximage.fFlags, AUX_INTERACTIVE_TILE, "AUX_INTERACTIVE_TILE"); + xmlw.addFlag(auximage.fFlags, AUX_IGNORES_HEIGHT, "AUX_IGNORES_HEIGHT"); + xmlw.addFlag(auximage.fFlags, AUX_USES_LAND_Z, "AUX_USES_LAND_Z"); + xmlw.closeNode(); + } + else + { + xmlw.addValue("flags"); + } + xmlw.closeNode(); + } + xmlw.closeNode(); // auximage_data + + xmlw.addAttributeToNextValue("number_of", Header.usNumberOfImageTileLocsStored); + xmlw.openNode("TILE_OFFSETS"); + if (Header.usNumberOfImageTileLocsStored > 0) + { + uiDataSize = sizeof( RelTileLoc ) * Header.usNumberOfImageTileLocsStored; + sgp::AutoArray pTileLocData(Header.usNumberOfImageTileLocsStored); + VFS_THROW_IFF( pTileLocData(), L"" ); + + VFS_THROW_IFF( uiDataSize == rfile->read((vfs::Byte*)pTileLocData(), uiDataSize), L"" ); + + for(int i = 0; i < Header.usNumberOfImageTileLocsStored; ++i) + { + RelTileLoc& off = pTileLocData[i]; + xmlw.addAttributeToNextValue("index",i); + xmlw.addAttributeToNextValue("x",(int)off.bTileOffsetX); + xmlw.addAttributeToNextValue("y",(int)off.bTileOffsetY); + xmlw.addValue("offset"); + } + } + xmlw.closeNode(); + } + else + { + xmlw.addAttributeToNextValue("number_of", 0); + xmlw.addValue("AUXIMAGE_DATA"); + xmlw.addAttributeToNextValue("number_of", Header.usNumberOfImageTileLocsStored); + xmlw.addValue("TILE_OFFSETS"); + } + + if (Header.fFlags & STRUCTURE_FILE_CONTAINS_STRUCTUREDATA) + { + UINT32 usNumberOfStructuresStored = Header.usNumberOfStructuresStored; + UINT32 uiDataSize = Header.usStructureDataSize; + // Determine the size of the data, from the header just read, + // allocate enough memory and read it in + sgp::AutoArray pubStructureData( uiDataSize ); + VFS_THROW_IFF(pubStructureData(), L""); + + VFS_THROW_IFF( uiDataSize == rfile->read((vfs::Byte*)pubStructureData(), uiDataSize), L"" ); + + xmlw.addAttributeToNextValue("number_of", Header.usNumberOfStructures); + if(Header.usNumberOfStructures != Header.usNumberOfStructuresStored) + { + xmlw.addAttributeToNextValue("stored", Header.usNumberOfStructuresStored); + } + xmlw.openNode("STRUCTURE_DATA"); + + UINT8* p_current = pubStructureData(); + UINT8* p_end = pubStructureData() + uiDataSize; + for(unsigned int i = 0; i < usNumberOfStructuresStored; ++i) + { + if (p_current + sizeof( DB_STRUCTURE ) > p_end) + { + // gone past end of file block?! + // freeing of memory will occur outside of the function + break; + } + + DB_STRUCTURE* structure = ((DB_STRUCTURE*)p_current); + p_current += sizeof( DB_STRUCTURE ); + + //xmlw.addAttributeToNextValue("index", i); + xmlw.addAttributeToNextValue("index", (int)structure->usStructureNumber); + xmlw.openNode("STRUCTURE"); + + //xmlw.addValue("usStructureNumber", (int)structure->usStructureNumber); + xmlw.addValue("ubArmour", (int)structure->ubArmour); + xmlw.addValue("ubHitPoints", (int)structure->ubHitPoints); + xmlw.addValue("ubDensity", (int)structure->ubDensity); + xmlw.addValue("ubWallOrientation", (int)structure->ubWallOrientation); + xmlw.addValue("bDestructionPartner",(int)structure->bDestructionPartner); + xmlw.addValue("bPartnerDelta", (int)structure->bPartnerDelta); + xmlw.addValue("bZTileOffsetX", (int)structure->bZTileOffsetX); + xmlw.addValue("bZTileOffsetY", (int)structure->bZTileOffsetY); + if(structure->fFlags > 0) + { + xmlw.addAttributeToNextValue("uint",(void*)((UINT32)structure->fFlags)); + xmlw.openNode("flags"); + + xmlw.addFlag(structure->fFlags, STRUCTURE_BASE_TILE, "STRUCTURE_BASE_TILE"); + xmlw.addFlag(structure->fFlags, STRUCTURE_OPEN, "STRUCTURE_OPEN"); + xmlw.addFlag(structure->fFlags, STRUCTURE_OPENABLE, "STRUCTURE_OPENABLE"); + // synonyms for STRUCTURE_OPENABLE + xmlw.addFlag(structure->fFlags, STRUCTURE_CLOSEABLE, "STRUCTURE_CLOSEABLE"); + xmlw.addFlag(structure->fFlags, STRUCTURE_SEARCHABLE, "STRUCTURE_SEARCHABLE"); + xmlw.addFlag(structure->fFlags, STRUCTURE_HIDDEN, "STRUCTURE_HIDDEN"); + + xmlw.addFlag(structure->fFlags, STRUCTURE_MOBILE, "STRUCTURE_MOBILE"); + // STRUCTURE_PASSABLE is set for each structure instance where + // the tile flag TILE_PASSABLE is set + xmlw.addFlag(structure->fFlags, STRUCTURE_PASSABLE, "STRUCTURE_PASSABLE"); + xmlw.addFlag(structure->fFlags, STRUCTURE_EXPLOSIVE, "STRUCTURE_EXPLOSIVE"); + xmlw.addFlag(structure->fFlags, STRUCTURE_TRANSPARENT, "STRUCTURE_TRANSPARENT"); + + xmlw.addFlag(structure->fFlags, STRUCTURE_GENERIC, "STRUCTURE_GENERIC"); + xmlw.addFlag(structure->fFlags, STRUCTURE_TREE, "STRUCTURE_TREE"); + xmlw.addFlag(structure->fFlags, STRUCTURE_FENCE, "STRUCTURE_FENCE"); + xmlw.addFlag(structure->fFlags, STRUCTURE_WIREFENCE, "STRUCTURE_WIREFENCE"); + + xmlw.addFlag(structure->fFlags, STRUCTURE_HASITEMONTOP, "STRUCTURE_HASITEMONTOP"); + xmlw.addFlag(structure->fFlags, STRUCTURE_SPECIAL, "STRUCTURE_SPECIAL"); + xmlw.addFlag(structure->fFlags, STRUCTURE_LIGHTSOURCE, "STRUCTURE_LIGHTSOURCE"); + xmlw.addFlag(structure->fFlags, STRUCTURE_VEHICLE, "STRUCTURE_VEHICLE"); + + xmlw.addFlag(structure->fFlags, STRUCTURE_WALL, "STRUCTURE_WALL"); + xmlw.addFlag(structure->fFlags, STRUCTURE_WALLNWINDOW, "STRUCTURE_WALLNWINDOW"); + xmlw.addFlag(structure->fFlags, STRUCTURE_SLIDINGDOOR, "STRUCTURE_SLIDINGDOOR"); + xmlw.addFlag(structure->fFlags, STRUCTURE_DOOR, "STRUCTURE_DOOR"); + + // a "multi" structure (as opposed to multitiled) is composed of multiple graphics & structures + xmlw.addFlag(structure->fFlags, STRUCTURE_MULTI, "STRUCTURE_MULTI"); + xmlw.addFlag(structure->fFlags, STRUCTURE_CAVEWALL, "STRUCTURE_CAVEWALL"); + xmlw.addFlag(structure->fFlags, STRUCTURE_DDOOR_LEFT, "STRUCTURE_DDOOR_LEFT"); + xmlw.addFlag(structure->fFlags, STRUCTURE_DDOOR_RIGHT, "STRUCTURE_DDOOR_RIGHT"); + + xmlw.addFlag(structure->fFlags, STRUCTURE_NORMAL_ROOF, "STRUCTURE_NORMAL_ROOF"); + xmlw.addFlag(structure->fFlags, STRUCTURE_SLANTED_ROOF, "STRUCTURE_SLANTED_ROOF"); + xmlw.addFlag(structure->fFlags, STRUCTURE_TALL_ROOF, "STRUCTURE_TALL_ROOF"); + xmlw.addFlag(structure->fFlags, STRUCTURE_SWITCH, "STRUCTURE_SWITCH"); + + xmlw.addFlag(structure->fFlags, STRUCTURE_ON_LEFT_WALL, "STRUCTURE_ON_LEFT_WALL"); + xmlw.addFlag(structure->fFlags, STRUCTURE_ON_RIGHT_WALL, "STRUCTURE_ON_RIGHT_WALL"); + xmlw.addFlag(structure->fFlags, STRUCTURE_CORPSE, "STRUCTURE_CORPSE"); + xmlw.addFlag(structure->fFlags, STRUCTURE_PERSON, "STRUCTURE_PERSON"); + + // COMBINATION FLAGS + xmlw.addFlag(structure->fFlags, STRUCTURE_ANYFENCE, "STRUCTURE_ANYFENCE"); + xmlw.addFlag(structure->fFlags, STRUCTURE_ANYDOOR, "STRUCTURE_ANYDOOR"); + xmlw.addFlag(structure->fFlags, STRUCTURE_OBSTACLE, "STRUCTURE_OBSTACLE"); + xmlw.addFlag(structure->fFlags, STRUCTURE_WALLSTUFF, "STRUCTURE_WALLSTUFF"); + xmlw.addFlag(structure->fFlags, STRUCTURE_BLOCKSMOVES, "STRUCTURE_BLOCKSMOVES"); + xmlw.addFlag(structure->fFlags, STRUCTURE_TYPE_DEFINED, "STRUCTURE_TYPE_DEFINED"); + xmlw.addFlag(structure->fFlags, STRUCTURE_ROOF, "STRUCTURE_ROOF"); + + xmlw.closeNode(); + } + else + { + xmlw.addValue("flags"); + } + xmlw.addValue("ubNumberOfTiles", (int)structure->ubNumberOfTiles); + xmlw.addAttributeToNextValue("number_of", (int)structure->ubNumberOfTiles); + xmlw.openNode("TILES"); + for(int i = 0; i < structure->ubNumberOfTiles; ++i) + { + if (p_current + sizeof( DB_STRUCTURE_TILE ) > p_end) + { + // gone past end of file block?! + // freeing of memory will occur outside of the function + break; + } + DB_STRUCTURE_TILE* structTile = ((DB_STRUCTURE_TILE*)p_current); + p_current += sizeof( DB_STRUCTURE_TILE ); + + xmlw.addAttributeToNextValue("index", i); + xmlw.openNode("STRUCTURE_TILE"); + xmlw.addValue("bXPosRelToBase", (int)structTile->bXPosRelToBase); + xmlw.addValue("bYPosRelToBase", (int)structTile->bYPosRelToBase); + xmlw.addValue("sPosRelToBase", (int)structTile->sPosRelToBase); + xmlw.addValue("ubVehicleHitLocation", (int)structTile->ubVehicleHitLocation); + if(structTile->fFlags > 0) + { + xmlw.addAttributeToNextValue("uint", (void*)((UINT32)structTile->fFlags)); + xmlw.openNode("flags"); + xmlw.addFlag(structTile->fFlags, TILE_ON_ROOF, "TILE_ON_ROOF"); + xmlw.addFlag(structTile->fFlags, TILE_PASSABLE, "TILE_PASSABLE"); + xmlw.closeNode(); + } + else + { + xmlw.addValue("flags"); + } + xmlw.openNode("profile"); + for(int y=PROFILE_Y_SIZE-1; y >= 0; y--) + { + std::stringstream ss; + for(int x = 0; x < PROFILE_X_SIZE - 1; ++x) + { + ss << (int)structTile->Shape[y][x] << ","; + } + ss << (int)structTile->Shape[y][PROFILE_X_SIZE-1]; + xmlw.addValue("y"+vfs::toString(y), ss.str()); + } + xmlw.closeNode(); + xmlw.closeNode(); + } + xmlw.closeNode(); + + xmlw.closeNode(); + } + xmlw.closeNode(); + } + else + { + xmlw.addAttributeToNextValue("number_of", Header.usNumberOfStructuresStored); + xmlw.addValue("STRUCTURE_DATA"); + } + xmlw.closeNode(); // root + xmlw.writeToFile(pOutputFile); + + return true; +} diff --git a/ext/export/src/export/jsd/structure.h b/ext/export/src/export/jsd/structure.h new file mode 100644 index 000000000..114b65996 --- /dev/null +++ b/ext/export/src/export/jsd/structure.h @@ -0,0 +1,11 @@ +#ifndef _STRUCTURE_H_ +#define _STRUCTURE_H_ + +#include + +namespace ja2xp +{ + bool ConvertStructure(vfs::tReadableFile* pStructureFile, vfs::tWritableFile* pOutputFile); +}; + +#endif // _STRUCTURE_H_ diff --git a/ext/export/src/export/slf/export_slf.cpp b/ext/export/src/export/slf/export_slf.cpp new file mode 100644 index 000000000..f133f8087 --- /dev/null +++ b/ext/export/src/export/slf/export_slf.cpp @@ -0,0 +1,182 @@ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +bool ja2xp::convertSLFto7z(vfs::tReadableFile* pInFile, vfs::tWritableFile *pOutFile, bool bConvertSTIs, bool bPngOffsets) +{ + vfs::CSLFLibrary src_lib(pInFile,""); + if(!src_lib.init()) + { + std::wcout << L"Could not init SLF Library \"" << pInFile->getPath().c_wcs() << L"\"" << std::endl; + return false; + } + + vfs::CCreateUncompressed7zLibrary create7zLib; + + vfs::CSLFLibrary::Iterator it = src_lib.begin(); + int count = 0; + while(!it.end()) + { + count++; + it.next(); + } + ProgressBar pbar(54,count); + it = src_lib.begin(); + for(; !it.end(); it.next()) + { + count++; + vfs::CBufferFile* temp_file = NULL; + vfs::tReadableFile *file = vfs::tReadableFile::cast(it.value()); + if(bConvertSTIs) + { + vfs::Path filename = it.value()->getPath(); + if(vfs::StrCmp::Equal(filename().substr(filename().length()-4,4), L".sti")) + { + vfs::Path path = filename().substr(0,filename.length()-4) + L".jpc.7z"; + temp_file = new vfs::CBufferFile(path); + if(convertSTItoJPC(vfs::tReadableFile::cast(it.value()), vfs::tWritableFile::cast(temp_file), bPngOffsets, false)) + { + file = vfs::tReadableFile::cast( temp_file ); + } + } + } + if(create7zLib.addFile(file)) + { + pbar.Next(it.value()->getPath()()); + } + else + { + std::wcout << L"Adding file '" << it.value()->getPath().c_wcs() << L"' failed!" << std::endl; + } + if(temp_file) + { + delete temp_file; + } + } + std::wstringstream wss; + wss << L"Writing file \"" << pOutFile->getPath().c_wcs() << L"\""; + pbar.Next(wss.str()); + if(!create7zLib.writeLibrary(pOutFile)) + { + wss.str(L""); + wss << L"Could not write file \"" << pOutFile->getPath().c_wcs() << L"\""; + pbar.Next(wss.str()); + return false; + } + return true; +} + +bool ja2xp::convertSLFto7z(vfs::Path const& sSrc, vfs::Path const& sDst, bool bConvertSTIs, bool bPngOffsets) +{ + vfs::CVirtualFileSystem::Iterator it = getVFS()->begin(sSrc); + int file_counter = 0; + for(; !it.end(); it.next()) + { + file_counter++; + vfs::String::str_t fname = it.value()->getPath().c_wcs(); + if( !vfs::StrCmp::Equal( fname.substr(fname.length()-4,4), L".slf") ) + { + std::wcout << L"\"" << fname << L"\" " << L"is not an .slf file" << std::endl; + continue; + } + if(!it.value()->openRead()) + { + std::wcout << L"Could not open file \"" << sSrc() << L"\"" << std::endl; + continue; + } + vfs::String::str_t new_fname = fname.substr(0,fname.length()-4) + L".jdc.7z"; + vfs::Path out_name; + if(vfs::StrCmp::Equal(sDst(), L".")) + { + out_name = vfs::Path(new_fname); + } + else + { + out_name = sDst; + } + + std::wcout << L"Converting file \"" << it.value()->getPath().c_wcs() << L"\"" << std::endl; + + vfs::COpenWriteFile wfile(out_name,true,true); + if(!convertSLFto7z(it.value(), &wfile.file(), bConvertSTIs, bPngOffsets)) + { + printf("\n"); + continue; + } + printf("\n"); + } + if(file_counter == 0) + { + std::wcout << L"Nothing to convert!" << std::endl; + } + return true; +} + +/**********************************************************************************************/ + +const wchar_t* ja2xp::CExportSLF::commandString = L"slf"; + +void ja2xp::CExportSLF::handleCommand(param_list_t const& params) +{ + bool opt_Sti2Png = false, opt_PngOffsets = false; + + param_list_t vfs_params; + param_list_t::const_iterator cit = params.begin(); + for(; cit != params.end(); ++cit) + { + if( vfs::StrCmp::Equal(*cit, L"-sti2png") ) + { + opt_Sti2Png = true; + continue; + } + else if( vfs::StrCmp::Equal(*cit, L"-png_offsets") ) + { + opt_PngOffsets = true; + continue; + } + else + { + vfs_params.push_back(*cit); + } + } + + ja2xp::InitVFS& vfs = ja2xp::InitVFS::instance(); + vfs.checkParameters(vfs_params); + if(!vfs.init()) + { + return; + } + try + { + convertSLFto7z(vfs.srcPattern(), vfs.dstPattern(), opt_Sti2Png, opt_PngOffsets); + } + catch(vfs::Exception& msg) + { + std::wcout << msg.getLastEntryString().c_str() << std::endl; + } +} + +void ja2xp::CExportSLF::printHelp() +{ + std::wcout + << L" convert SLF archive(s) to uncompressed 7z archive(s)" << std::endl + << L" * if \"destination\" is a directory, then the filename's extension will be" << std::endl + << L" replaced with \".jdc.7z\"" << std::endl + << std::endl + << L" options :" << std::endl + << L" -sti2png : all sti files in the archive will be converted to" << std::endl + << L" \".jpc.7z\" files" << std::endl + << L" -png_offsets : if option \"sti2png\" is enabled, offsets of the png" << std::endl + << L" subimages will be written int the \"appdata.xml\" file" << std::endl; +} diff --git a/ext/export/src/export/slf/export_slf.h b/ext/export/src/export/slf/export_slf.h new file mode 100644 index 000000000..8628a930f --- /dev/null +++ b/ext/export/src/export/slf/export_slf.h @@ -0,0 +1,26 @@ +#ifndef _EXPORT_SLF_H_ +#define _EXPORT_SLF_H_ + +#include +#include + +#include + +namespace ja2xp +{ + class CExportSLF : public IExporterBase + { + public: + typedef IExporterBase::param_list_t param_list_t; + + static const wchar_t* commandString;// = L"slf"; + + virtual void handleCommand(param_list_t const& params); + virtual void printHelp(); + }; + + bool convertSLFto7z(vfs::tReadableFile* pInFile, vfs::tWritableFile *pOutFile, bool bConvertSTIs=false, bool bPngOffsets=false); + bool convertSLFto7z(vfs::Path const& sSrc, vfs::Path const& sDst, bool bConvertSTIs=false, bool bPngOffsets=false); +}; + +#endif // _EXPORT_SLF_H_ diff --git a/ext/export/src/export/sti/Image.cpp b/ext/export/src/export/sti/Image.cpp new file mode 100644 index 000000000..cc719d699 --- /dev/null +++ b/ext/export/src/export/sti/Image.cpp @@ -0,0 +1,1176 @@ + +#include "Image.h" +#include + +#include "STCI_lib.h" +#include "stci_image_utils.h" +#include "XMLWriter.h" + +#include +#include +#include +#include +#include +#include + +#include + +namespace png +{ +#include +} +#include +#include + +//#include "load_png.h" + +#include + + +template +inline bool _FLAG(FlagType &flags, FlagType const& flag) +{ + if(flags & flag) + { + flags -= flag; + return true; + } + return false; +} + +//template +//inline void WriteFlags(XMLWriter &xmlw, std::string const& sNodeName, FlagType flags) +template +inline void WriteFlags(XMLWriter &xmlw, std::string const& sNodeName, FlagType flags) +{ + xmlw.addAttributeToNextValue("value",(int)flags); + xmlw.openNode(sNodeName); + + /*0x01*/ if(_FLAG(flags, (FlagType)AUX_FULL_TILE)) xmlw.addValue("AUX_FULL_TILE"); + /*0x02*/ if(_FLAG(flags, (FlagType)AUX_ANIMATED_TILE)) xmlw.addValue("AUX_ANIMATED_TILE"); + /*0x04*/ if(_FLAG(flags, (FlagType)AUX_DYNAMIC_TILE)) xmlw.addValue("AUX_DYNAMIC_TILE"); + /*0x08*/ if(_FLAG(flags, (FlagType)AUX_INTERACTIVE_TILE)) xmlw.addValue("AUX_INTERACTIVE_TILE"); + /*0x10*/ if(_FLAG(flags, (FlagType)AUX_IGNORES_HEIGHT)) xmlw.addValue("AUX_IGNORES_HEIGHT"); + /*0x20*/ if(_FLAG(flags, (FlagType)AUX_USES_LAND_Z)) xmlw.addValue("AUX_USES_LAND_Z"); + + if(flags != 0) + { + xmlw.addValue("UNKNOWN_FLAG","UNKNOWN_FLAG"); + } + xmlw.closeNode(); +} + + +/*********************** + * from : http://www.gamedev.net/reference/articles/article1966.asp + * +//File information header +//provides general information about the file +typedef struct tagBITMAPFILEHEADER { + unsigned short bfType; + unsigned int bfSize; + unsigned short bfReserved1; + unsigned short bfReserved2; + unsigned int bfOffBits; +} BITMAPFILEHEADER, *PBITMAPFILEHEADER; +/*typedef struct tagBITMAPFILEHEADER { + WORD bfType; + DWORD bfSize; + WORD bfReserved1; + WORD bfReserved2; + DWORD bfOffBits; +} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;* +//Bitmap information header +//provides information specific to the image data +typedef struct tagBITMAPINFOHEADER{ + unsigned int biSize; + long biWidth; + long biHeight; + unsigned short biPlanes; + unsigned short biBitCount; + unsigned int biCompression; + unsigned int biSizeImage; + long biXPelsPerMeter; + long biYPelsPerMeter; + unsigned int biClrUsed; + unsigned int biClrImportant; +} BITMAPINFOHEADER, *PBITMAPINFOHEADER; +/*typedef struct tagBITMAPINFOHEADER{ + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;* + +//Colour palette +typedef struct tagRGBQUAD { + unsigned char rgbBlue; + unsigned char rgbGreen; + unsigned char rgbRed; + unsigned char rgbReserved; +} RGBQUAD; */ + +/******************************************************************************************/ + + + +ja2xp::CImage::CImage(vfs::Path const& sFileName) +: m_eImageType(IT_NONE), m_pRawImage(NULL), m_bImageLoaded(false) +{ + m_pImageFile = getVFS()->getReadFile(sFileName); + if(!m_pImageFile ) + { + int throw_exception = 0; + } +}; + +ja2xp::CImage::CImage(vfs::tReadableFile *pFile) +: m_pImageFile(pFile), m_eImageType(IT_NONE), m_pRawImage(NULL), m_bImageLoaded(false) +{ +}; + + +ja2xp::CImage::~CImage() +{ + if(m_pRawImage) + { + if(m_pRawImage->pPalette) + { + delete[] m_pRawImage->pPalette; + } + m_pRawImage->pPalette = NULL; + if(m_pRawImage->pETRLEObject) + { + delete[] m_pRawImage->pETRLEObject; + } + m_pRawImage->pETRLEObject = NULL; + if(m_pRawImage->pImageData) + { + delete[] m_pRawImage->pImageData; + } + m_pRawImage->pImageData = NULL; + if(m_pRawImage->pAppData) + { + delete[] m_pRawImage->pAppData; + } + m_pRawImage->pAppData = NULL; + + delete m_pRawImage; + } + m_pRawImage = NULL; +} + +UINT32 ja2xp::CImage::GetNumberOfSubImages() +{ + if(m_pRawImage) + { + if(m_pRawImage->pETRLEObject) + { + return m_pRawImage->usNumberOfObjects; + } + return 1; + } + return 0; +} + +bool ja2xp::CImage::LoadData() +{ + if(m_bImageLoaded && m_pRawImage == NULL) + { + return false; + } + if(m_pRawImage == NULL) // m_bImageLoaded == false + { + if(m_pImageFile == NULL) + { + return false; + } + m_pRawImage = new image_type; + memset(m_pRawImage,0,sizeof(image_type)); + UINT32 uiImageContent = IMAGE_ALLIMAGEDATA; // use it when loading images from disc + + vfs::Path const& sFileName = m_pImageFile->getName(); + + vfs::String::str_t const& filename = sFileName(); + vfs::String::str_t sExt = filename.substr(filename.length()-4,4); + if(vfs::StrCmp::Equal(sExt,L".sti")) + { + if(LoadSTCIFileToImage(m_pImageFile, m_pRawImage, uiImageContent)) + { + if(m_pRawImage->pPalette) + { + m_eImageType = IT_COMPRESSED; +// std::cout << "compressed ETRLE image" << std::endl; + } + else + { + m_eImageType = IT_BITMAP; +// std::cout << "bitmap image [" << m_pRawImage->usWidth << "," << m_pRawImage->usHeight << "]" << std::endl; + } + } + else + { + std::cout << "error : could not load image \"" << vfs::String::as_utf8(sFileName()) << "\"" << std::endl; + } + } + else if (vfs::StrCmp::Equal(sExt, L".bmp")) + { + LoadBMP(); + } + m_bImageLoaded = true; + } + return true; +} + +bool ja2xp::CImage::DeleteData() +{ + if( m_bImageLoaded && !m_pRawImage ) + { + return false; + } + if(m_pRawImage) + { + delete m_pRawImage; + m_eImageType = IT_NONE; + } + return true; +} + +/******************************************************************************************/ +/******************************************************************************************/ +/******************************************************************************************/ + +bool ja2xp::CImage::GetSize(UINT32 uiSubImage, UINT32 &uiWidth, UINT32 &uiHeight) +{ + if(m_eImageType == IT_BITMAP) + { + uiWidth = m_pRawImage->usWidth; + uiHeight = m_pRawImage->usHeight; + } + else if(m_eImageType == IT_COMPRESSED) + { + if(uiSubImage >= m_pRawImage->usNumberOfObjects) + { + return false; + } + uiWidth = m_pRawImage->pETRLEObject[uiSubImage].usWidth; + uiHeight = m_pRawImage->pETRLEObject[uiSubImage].usHeight; + } + else + { + return false; + } + return true; +} + +bool ja2xp::CImage::GetPosition(UINT32 uiSubImage, INT32 &iX, INT32 &iY) +{ + if(m_eImageType == IT_BITMAP) + { + iX = 0; + iY = 0; + } + else if(m_eImageType == IT_COMPRESSED) + { + if(uiSubImage >= m_pRawImage->usNumberOfObjects) + { + return false; + } + iX = m_pRawImage->pETRLEObject[uiSubImage].sOffsetX; + iY = m_pRawImage->pETRLEObject[uiSubImage].sOffsetY; + } + else + { + return false; + } + return true; +} + +void* ja2xp::CImage::GetDataPointer(UINT32 &uiSize) +{ + if(m_eImageType == IT_BITMAP) + { + uiSize = m_pRawImage->uiSizePixData; + return m_pRawImage->p8BPPData; + } + uiSize = 0; + return NULL; +} + +bool ja2xp::CImage::GetRawDataOfSubImage(UINT32 uiSubImage, void* pData, UINT32 uiMaxSize, UINT32 &uiFilledSize) +{ + int size = min(uiMaxSize,m_pRawImage->pETRLEObject[uiSubImage].uiDataLength); + memcpy(pData, &(m_pRawImage->p8BPPData[m_pRawImage->pETRLEObject[uiSubImage].uiDataOffset]),size); + return true; +} + +UINT32 ja2xp::CImage::FillData(UINT32 uiSubImage, UINT8* pData, UINT32 uiMaxSize, bool rgba) +{ + if(m_eImageType == IT_BITMAP) + { + if( (uiSubImage == 0) && (m_pRawImage->uiSizePixData < uiMaxSize) ) + { + memcpy(pData,m_pRawImage->p8BPPData,m_pRawImage->uiSizePixData); + return m_pRawImage->uiSizePixData; + } + } + else if(m_eImageType == IT_COMPRESSED) + { + if( (uiSubImage < m_pRawImage->usNumberOfObjects) )//&& + //(uiMaxSize > m_pRawImage->pETRLEObject[uiSubImage].uiDataLength) ) + { + UINT32 written = 0; + if(rgba) + { + written = UnpackETRLEImageToRGBABuffer(pData, m_pRawImage, uiSubImage); + } + else + { + written = UnpackETRLEImageToBuffer((UINT8*)pData,m_pRawImage,uiSubImage); + } + // TODO : + return written; + } + } + return 0; +} +bool ja2xp::CImage::Unpack16BppImageToRGBBuffer(UINT16* pSrc, UINT8* pDst, UINT32 uiWidth, UINT32 uiHeight) +{ + if(!pSrc || !pDst ) + { + return false; + } + UINT32 uiSize = uiWidth * uiHeight; + for(UINT32 i=0; i < uiSize; ++i) + { + UINT16 value = *pSrc; + UINT8 red = (value & gusRedMask) >> gusRedShift; + UINT8 green = (value & gusGreenMask) >> gusGreenShift; + UINT8 blue = (value & gusBlueMask) << (-gusBlueShift); + *pDst++ = red; + *pDst++ = green; + *pDst++ = blue; + pSrc++; + } + return true; +} + + +ja2xp::CImage::EImageType ja2xp::CImage::GetImageType() +{ + return m_eImageType; +} + +SGPPaletteEntry* ja2xp::CImage::GetPalette() +{ + if(m_pRawImage) + { + return m_pRawImage->pPalette; + } + return NULL; +} + + +/***************************************************************************************/ + +vfs::Path CreateFileName(vfs::Path const& sOutPathName, vfs::Path const& sFileName, int current_image, int num_images, vfs::String::str_t sExt) +{ + // create_file + vfs::Path outPath = sOutPathName; + std::wstringstream fullpath; + int test = num_images; + int left=0,right=0; + while(test > 0){ + left++; + test /= 10; + } + test = current_image==0 ? 1 : current_image; + while(test > 0){ + right++; + test /= 10; + } + test = left-right; + while(test > 0 ) + { + fullpath << L"0"; + test--; + } + fullpath << current_image << L"." << sExt; + outPath += vfs::Path(fullpath.str()); + return outPath; +} +#if 0 +bool CImage::WriteAsBMPs(vfs_string sOutPathName) +{ + if(!this->LoadData()) + { + return false; + } + + vfs_string sFileName,path; + + //SplitPath(m_pImageFile->GetFileName(),path,sFileName); + SplitPath(m_pImageFile->GetFileName()(),path,sFileName); + + for(int i=0; iusNumberOfObjects; ++i) + { + ETRLEObject &image = m_pRawImage->pETRLEObject[i]; + + BITMAPINFOHEADER bmp_infoheader; + bmp_infoheader.biSize = 40;//sizeof(BITMAPFILEHEADER); + bmp_infoheader.biWidth = image.usWidth; + bmp_infoheader.biHeight = image.usHeight; + bmp_infoheader.biPlanes = 1; + bmp_infoheader.biBitCount = 8; + bmp_infoheader.biCompression = 0; + bmp_infoheader.biSizeImage = image.usWidth * image.usHeight * sizeof(UINT8); + bmp_infoheader.biXPelsPerMeter = 0; + bmp_infoheader.biYPelsPerMeter = 0; + bmp_infoheader.biClrUsed = 256; + bmp_infoheader.biClrImportant = 256; + + UINT32 scanline_size = image.usWidth + (4 - image.usWidth%4)%4; + + // create headers for our bmp file + BITMAPFILEHEADER bmp_header; + bmp_header.bfType = 19778; + bmp_header.bfReserved1 = 0; + bmp_header.bfReserved2 = 0; + bmp_header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD); // headers + pallette + //bmp_header.bfSize = bmp_header.bfOffBits + (bmp_infoheader.biWidth * bmp_infoheader.biHeight); + bmp_header.bfSize = bmp_header.bfOffBits + (scanline_size * bmp_infoheader.biHeight); + + UINT8 *data = new UINT8[bmp_infoheader.biWidth * bmp_infoheader.biHeight]; + UINT32 imagesize; + if(!this->FillData(i,data,bmp_infoheader.biSizeImage*sizeof(UINT8),imagesize)) + { + return false; + } + if(imagesize != bmp_infoheader.biSizeImage) + { + return false; + } + + ChompSlash(sOutPathName); + vfs_string filename = CreateFileName(sOutPathName, sFileName, i, m_pRawImage->usNumberOfObjects, L"bmp"); + + VFS::tReadableFile *pTempFile = GetVFS()->GetFile(filename); + int x; + if(!pTempFile) + { + if(!GetVFS()->CreateNewFile(filename)) + { + return false; + } + pTempFile = GetVFS()->GetFile(filename); + } + if(pTempFile && pTempFile->IsWriteable()) + { + VFS::tWriteableFile *pWriteFile = VFS::tWriteableFile::Cast(pTempFile->GetWriteable()); + if(!pWriteFile || !pWriteFile->OpenWrite(true)) + { + return false; + } + UINT32 written_bytes; + // file header + if(!pWriteFile->Write(&bmp_header,sizeof(BITMAPFILEHEADER),&written_bytes) || + written_bytes != sizeof(BITMAPFILEHEADER) ) + { + pWriteFile->Close(); + return false; + } + // info header + if(!pWriteFile->Write(&bmp_infoheader,sizeof(BITMAPINFOHEADER),&written_bytes) || + written_bytes != sizeof(BITMAPINFOHEADER) ) + { + pWriteFile->Close(); + return false; + } + // palette + SGPPaletteEntry *pal = GetPalette(); + RGBQUAD palette[256]; + for(int i=0;i<256;++i) + { + palette[i].rgbBlue = pal[i].peBlue; + palette[i].rgbGreen= pal[i].peGreen; + palette[i].rgbRed = pal[i].peRed; + palette[i].rgbReserved = pal[i].peFlags; + } + if(!pWriteFile->Write(palette,sizeof(RGBQUAD)*256,&written_bytes) || + written_bytes != sizeof(RGBQUAD)*256 ) + { + pWriteFile->Close(); + return false; + } + // write data scanlines + UINT8 *scanline = new UINT8[scanline_size]; + memset(scanline,0,scanline_size); + for(int j=bmp_infoheader.biHeight-1; j>=0; --j) + { + memcpy(scanline,&data[j*bmp_infoheader.biWidth],bmp_infoheader.biWidth); + if(!pWriteFile->Write(scanline,scanline_size,&written_bytes) || + written_bytes != scanline_size ) + { + pWriteFile->Close(); + return false; + } + } + delete[] scanline; + pWriteFile->Close(); + } + delete[] data; + } + + return true; +} +#endif +vfs::tWritableFile* GetWriteFile(vfs::Path const& sFileName) +{ + vfs::tReadableFile *pRFile = getVFS()->getReadFile(sFileName); + if(!pRFile) + { + if(!getVFS()->createNewFile(sFileName)) + { + return NULL; + } + pRFile = getVFS()->getReadFile(sFileName); + } + if(pRFile->implementsWritable()) + { + //return vfs::tWritableFile::cast(pRFile->getWritable()); + return vfs::tWritableFile::cast(pRFile); + } + return NULL; +} + +/***************************************************************************/ +void user_write_data(png::png_structp png_ptr, png::png_bytep data, png::png_size_t length) +{ + vfs::tWritableFile* pFile = (vfs::tWritableFile*)(png_ptr->io_ptr); + if(pFile) + { + pFile->write((vfs::Byte*)data,length); + } +} +void user_flush_data(png::png_structp png_ptr) +{ + return; +} +/***************************************************************************/ + +bool ja2xp::CImage::writeSubImageToPNGFile(int i, vfs::tWritableFile* file, bool rgba) +{ + VFS_THROW_IFF(i >= 0 && i < m_pRawImage->usNumberOfObjects, L"invalid index"); + ETRLEObject &image = m_pRawImage->pETRLEObject[i]; + + png::png_error_ptr user_error_ptr = NULL; + png::png_error_ptr user_error_fn = NULL; + png::png_error_ptr user_warning_fn = NULL; + + png::png_structp png_ptr = png_create_write_struct( + PNG_LIBPNG_VER_STRING, + (png::png_voidp)user_error_ptr, + user_error_fn, + user_warning_fn ); + if (!png_ptr) + { + return (false); + } + + png::png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png::png_destroy_write_struct(&png_ptr, (png::png_infopp)NULL); + return (false); + } + + /* set the zlib compression level */ + png::png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); + + /* set other zlib parameters */ + png::png_set_compression_mem_level(png_ptr, 8); + png::png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); + png::png_set_compression_window_bits(png_ptr, 15); + png::png_set_compression_method(png_ptr, 8); + png::png_set_compression_buffer_size(png_ptr, 8192); + +// std::cout << "width : " << image.usWidth << ", height : " << image.usHeight << std::endl; + int bit_depth = rgba ? 8 : m_pRawImage->ubBitDepth; + int color_type = rgba ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_PALETTE; + png_set_IHDR( + png_ptr, + info_ptr, + image.usWidth, // - holds the width of the image in pixels (up to 2^31). + image.usHeight, // holds the height of the image in pixels (up to 2^31). + bit_depth, // - holds the bit depth of one of the image channels. + // (valid values are 1, 2, 4, 8, 16 and depend also on the color_type. + // See also significant bits (sBIT) below). + color_type, // - describes which color/alpha channels are present. + // PNG_COLOR_TYPE_GRAY (bit depths 1, 2, 4, 8, 16) + // PNG_COLOR_TYPE_GRAY_ALPHA (bit depths 8, 16) + // PNG_COLOR_TYPE_PALETTE (bit depths 1, 2, 4, 8) + // PNG_COLOR_TYPE_RGB (bit_depths 8, 16) + // PNG_COLOR_TYPE_RGB_ALPHA (bit_depths 8, 16) + // PNG_COLOR_MASK_PALETTE + // PNG_COLOR_MASK_COLOR + // PNG_COLOR_MASK_ALPHA + PNG_INTERLACE_NONE, // - PNG_INTERLACE_NONE or PNG_INTERLACE_ADAM7 + PNG_COMPRESSION_TYPE_DEFAULT,//- (must be PNG_COMPRESSION_TYPE_DEFAULT) + PNG_FILTER_TYPE_DEFAULT // - (must be PNG_FILTER_TYPE_DEFAULT or, if you are writing a PNG to + // be embedded in a MNG datastream, can also be PNG_INTRAPIXEL_DIFFERENCING) + ); + + if(!rgba) + { + const UINT32 PALETTE_SIZE = 256; + png::png_color pngpal[PALETTE_SIZE]; + SGPPaletteEntry *stipal = m_pRawImage->pPalette; + for(int p=0; p < PALETTE_SIZE; ++p) + { + pngpal[p].red = stipal[p].peRed; + pngpal[p].green = stipal[p].peGreen; + pngpal[p].blue = stipal[p].peBlue; + } + png_set_PLTE(png_ptr, info_ptr, + pngpal, // the palette for the file (array of png_color) + PALETTE_SIZE // number of entries in the palette + ); + } + + //png_set_gAMA(png_ptr, info_ptr, + // gamma // - the gamma the image was created at (PNG_INFO_gAMA) + //); + + //png_set_sRGB(png_ptr, info_ptr, + // srgb_intent // - the rendering intent (PNG_INFO_sRGB) The presence of + // // the sRGB chunk means that the pixel data is in the sRGB + // // color space. This chunk also implies specific values + // // of gAMA and cHRM. Rendering intent is the CSS-1 property + // // that has been defined by the International Color Consortium + // // (http://www.color.org/). + // // It can be one of PNG_sRGB_INTENT_SATURATION, + // // PNG_sRGB_INTENT_PERCEPTUAL, PNG_sRGB_INTENT_ABSOLUTE, or + // // PNG_sRGB_INTENT_RELATIVE. + + //); + + //png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, + // srgb_intent // - the rendering intent (PNG_INFO_sRGB) The presence of the + // // sRGB chunk means that the pixel data is in the sRGB color + // // space. This function also causes gAMA and cHRM chunks with + // // the specific values that are consistent with sRGB to be written. + //); + + //png_set_iCCP(png_ptr, info_ptr, + // name, // - The profile name. + // compression_type, // - The compression type; always PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + // // You may give NULL to this argument to gnore it. + // profile, // - International Color Consortium color profile data. May contain NULs. + // proflen // - length of profile data in bytes. + //); + + //png_set_sBIT(png_ptr, info_ptr, + // sig_bit // - the number of significant bits for (PNG_INFO_sBIT) each of the + // // gray, red, green, and blue channels, whichever are appropriate + // // for the given color type (png_color_16) + //); + + //png_set_tRNS(png_ptr, info_ptr, + // trans, // - array of transparent entries for palette (PNG_INFO_tRNS) + // num_trans, // - graylevel or color sample values of the single transparent + // // color for non-paletted images (PNG_INFO_tRNS) + // trans_values // - number of transparent entries (PNG_INFO_tRNS) + //); + + //png_set_hIST(png_ptr, info_ptr, + // hist // - histogram of palette (array of png_uint_16) + //); + + //png_set_tIME(png_ptr, info_ptr, + // mod_time // - time image was last modified (PNG_VALID_tIME) + //); + + //png_set_bKGD(png_ptr, info_ptr, + // background // - background color (PNG_VALID_bKGD) + //); + + //png_set_text(png_ptr, info_ptr, + // text_ptr, // - array of png_text holding image comments + // num_text // - number of comments + //); + /***** + text_ptr[i].compression // - type of compression used on "text" PNG_TEXT_COMPRESSION_NONE + // PNG_TEXT_COMPRESSION_zTXt + // PNG_ITXT_COMPRESSION_NONE + // PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key // - keyword for comment. Must contain 1-79 characters. + text_ptr[i].text // - text comments for current keyword. Can be NULL or empty. + text_ptr[i].text_length // - length of text string, after decompression, 0 for iTXt + text_ptr[i].itxt_length // - length of itxt string, after decompression, 0 for tEXt/zTXt + text_ptr[i].lang // - language of comment (NULL or empty for unknown). + text_ptr[i].translated_keyword + // - keyword in UTF-8 (NULL or empty for unknown). + *****/ + + //png_set_sPLT(png_ptr, info_ptr, + // &palette_ptr, // - array of png_sPLT_struct structures to be added to the list + // // of palettes in the info structure. + // num_spalettes // - number of palette structures to be added. + //); + + png_set_oFFs(png_ptr, info_ptr, + image.sOffsetX, // - positive offset from the left edge of the screen + image.sOffsetY, // - positive offset from the top edge of the screen + PNG_OFFSET_PIXEL // - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + ); + + //png_set_pHYs(png_ptr, info_ptr, + // res_x, // - pixels/unit physical resolution in x direction + // res_y, // - pixels/unit physical resolution in y direction + // unit_type // - PNG_RESOLUTION_UNKNOWN, PNG_RESOLUTION_METER + //); + + //png_set_sCAL(png_ptr, info_ptr, + // unit, // - physical scale units (an integer) + // width, // - width of a pixel in physical scale units + // height // - height of a pixel in physical scale units (width and height are doubles) + //); + + //png_set_sCAL_s(png_ptr, info_ptr, + // unit, // - physical scale units (an integer) + // width, // - width of a pixel in physical scale units + // height // - height of a pixel in physical scale units (width and height are strings like "2.54") + //); + + //png_set_unknown_chunks(png_ptr, info_ptr, + // &unknowns, // - array of png_unknown_chunk structures holding unknown chunks + // num_unknowns + //); + /***** + unknowns[i].name // - name of unknown chunk + unknowns[i].data // - data of unknown chunk + unknowns[i].size // - size of unknown chunk's data + unknowns[i].location // - position to write chunk in file + // 0: do not write chunk + // PNG_HAVE_IHDR: before PLTE + // PNG_HAVE_PLTE: before IDAT + // PNG_AFTER_IDAT: after IDAT + *****/ + + /***** + PNG_TRANSFORM_IDENTITY - No transformation + PNG_TRANSFORM_PACKING - Pack 1, 2 and 4-bit samples + PNG_TRANSFORM_PACKSWAP - Change order of packed pixels to LSB first + PNG_TRANSFORM_INVERT_MONO - Invert monochrome images + PNG_TRANSFORM_SHIFT - Normalize pixels to the sBIT depth + PNG_TRANSFORM_BGR - Flip RGB to BGR, RGBA to BGRA + PNG_TRANSFORM_SWAP_ALPHA - Flip RGBA to ARGB or GA to AG + PNG_TRANSFORM_INVERT_ALPHA - Change alpha from opacity to transparency + PNG_TRANSFORM_SWAP_ENDIAN - Byte-swap 16-bit samples PNG_TRANSFORM_STRIP_FILLER Strip out filler bytes. + *****/ + UINT32 png_transforms = PNG_TRANSFORM_IDENTITY; + + UINT32 num_values = image.usWidth * image.usHeight * (rgba ? 4 : 1); + sgp::AutoArray image_data(num_values); + UINT32 fill_size = num_values * sizeof(UINT8); + memset(image_data(), 0, fill_size); + if( fill_size != this->FillData(i,image_data(),fill_size, rgba) ) + { + return false; + } + + sgp::AutoArray rows(image.usHeight); + int line_skip = image.usWidth * (rgba ? 4 : 1); + for(int j=0; jusWidth << ", height : " << m_pRawImage->usHeight << std::endl; + + png::png_set_IHDR( + png_ptr, + info_ptr, + m_pRawImage->usWidth, // - holds the width of the image in pixels (up to 2^31). + m_pRawImage->usHeight, // holds the height of the image in pixels (up to 2^31). + 8, // - holds the bit depth of one of the image channels. + // (valid values are 1, 2, 4, 8, 16 and depend also on the color_type. + // See also significant bits (sBIT) below). + PNG_COLOR_TYPE_RGB, // - describes which color/alpha channels are present. + // PNG_COLOR_TYPE_GRAY (bit depths 1, 2, 4, 8, 16) + // PNG_COLOR_TYPE_GRAY_ALPHA (bit depths 8, 16) + // PNG_COLOR_TYPE_PALETTE (bit depths 1, 2, 4, 8) + // PNG_COLOR_TYPE_RGB (bit_depths 8, 16) + // PNG_COLOR_TYPE_RGB_ALPHA (bit_depths 8, 16) + // PNG_COLOR_MASK_PALETTE + // PNG_COLOR_MASK_COLOR + // PNG_COLOR_MASK_ALPHA + PNG_INTERLACE_NONE, // - PNG_INTERLACE_NONE or PNG_INTERLACE_ADAM7 + PNG_COMPRESSION_TYPE_DEFAULT, // - (must be PNG_COMPRESSION_TYPE_DEFAULT) + PNG_FILTER_TYPE_DEFAULT // - (must be PNG_FILTER_TYPE_DEFAULT or, if you are writing a PNG to + // be embedded in a MNG datastream, can also be PNG_INTRAPIXEL_DIFFERENCING) + ); + + png_set_oFFs(png_ptr, info_ptr, + 0, // - positive offset from the left edge of the screen + 0, // - positive offset from the top edge of the screen + PNG_OFFSET_PIXEL // - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + ); + + UINT32 png_transforms = PNG_TRANSFORM_IDENTITY; + + std::vector image_data; + image_data.resize(3*m_pRawImage->usHeight*m_pRawImage->usWidth); + sgp::AutoArray rows(m_pRawImage->usHeight); + if(m_pRawImage->ubBitDepth == 16) + { + this->Unpack16BppImageToRGBBuffer((UINT16*)m_pRawImage->pImageData,&image_data[0],m_pRawImage->usWidth, m_pRawImage->usHeight); + for(int j=0; jusHeight; ++j) + { + rows[j] = (UINT8*)&image_data[3*j*m_pRawImage->usWidth]; + } + png_set_rows(png_ptr,info_ptr, rows()); + } + else if(m_pRawImage->ubBitDepth == 8) + { + UINT8 *image_data = (UINT8*)m_pRawImage->pImageData; + for(int j=0; jusHeight; ++j) + { + rows[j] = &image_data[j*m_pRawImage->usWidth]; + } + png_set_rows(png_ptr,info_ptr, rows()); + } + + if(file) + { + vfs::COpenWriteFile wfile(file); + png::png_set_write_fn(png_ptr,file,user_write_data, user_flush_data); + png::png_write_png(png_ptr, info_ptr, png_transforms, NULL); + png_write_end(png_ptr,info_ptr); + } + + png::png_destroy_info_struct(png_ptr, &info_ptr); + png::png_destroy_write_struct(&png_ptr, (png::png_infopp)NULL); + + return true; +} + +bool ja2xp::CImage::writeSTIAppData(std::vector const& write_image, bool bWriteOffsets, vfs::tWritableFile* file) +{ + XMLWriter xmlw; + xmlw.openNode("ImageData"); + for(int i=0; iusNumberOfObjects; ++i) + { + if(write_image[i] || bWriteOffsets) + { + xmlw.addAttributeToNextValue("index",i); + xmlw.openNode("SubImage"); + if(bWriteOffsets) + { + if(m_pRawImage->pETRLEObject[i].sOffsetX != 0) + { + xmlw.addAttributeToNextValue("x", m_pRawImage->pETRLEObject[i].sOffsetX); + } + if(m_pRawImage->pETRLEObject[i].sOffsetY != 0) + { + xmlw.addAttributeToNextValue("y", m_pRawImage->pETRLEObject[i].sOffsetY); + } + xmlw.addValue("offset"); + } + AuxObjectData *pAOD = (AuxObjectData*)(&(m_pRawImage->pAppData[i*16])); + if(write_image[i]) + { + xmlw.openNode("AuxObjectData"); + if(pAOD->fFlags) WriteFlags( xmlw, "flags", pAOD->fFlags ); + + if(pAOD->ubCurrentFrame) xmlw.addValue("ubCurrentFrame", (int)pAOD->ubCurrentFrame); + if(pAOD->ubNumberOfFrames) xmlw.addValue("ubNumberOfFrames", (int)pAOD->ubNumberOfFrames); + if(pAOD->ubNumberOfTiles) xmlw.addValue("ubNumberOfTiles", (int)pAOD->ubNumberOfTiles); + if(pAOD->ubWallOrientation) xmlw.addValue("ubWallOrientation", (int)pAOD->ubWallOrientation); + if(pAOD->usTileLocIndex) xmlw.addValue("usTileLocIndex", (int)pAOD->usTileLocIndex); + + xmlw.closeNode(); + } + xmlw.closeNode(); + } + } + xmlw.closeNode(); + + return xmlw.writeToFile(file); +} + + +bool ja2xp::CImage::WriteAsPNGs(vfs::tWritableFile* outFile, bool bWriteOffsets, bool rgba) +{ + if(!this->LoadData()) + { + return false; + } + + vfs::CCreateUncompressed7zLibrary outLib; + vfs::Path sFileName,path; + + m_pImageFile->getName().splitLast(path,sFileName); + + if(m_pRawImage->usNumberOfObjects) + { + for(int i=0; iusNumberOfObjects; ++i) + { + vfs::Path filename = CreateFileName("", sFileName, i, m_pRawImage->usNumberOfObjects, L"png"); + vfs::CBufferFile memFile(filename); + vfs::tWritableFile *pFile = vfs::tWritableFile::cast(&memFile); + + this->writeSubImageToPNGFile(i, pFile, rgba); + outLib.addFile(vfs::tReadableFile::cast(pFile)); + } + } + else + { + vfs::Path filename = CreateFileName("", sFileName, 0, m_pRawImage->usNumberOfObjects, L"png"); + vfs::CBufferFile memFile(filename); + vfs::tWritableFile *pFile = vfs::tWritableFile::cast(&memFile); + + this->writeImageToPNGFile(pFile, rgba); + outLib.addFile(vfs::tReadableFile::cast(pFile)); + } + if(m_pRawImage->usNumberOfObjects > 0) + { + std::vector write_image(m_pRawImage->usNumberOfObjects, false); + bool write_appdata = false; + if(m_pRawImage->pAppData) + { + for(int i=0; iusNumberOfObjects; ++i) + { + AuxObjectData *pAOD = (AuxObjectData*)(&(m_pRawImage->pAppData[i*16])); + if(pAOD && (pAOD->fFlags || + pAOD->ubCurrentFrame || + pAOD->ubNumberOfFrames || + pAOD->ubNumberOfTiles || + pAOD->ubWallOrientation || + pAOD->usTileLocIndex) ) + { + write_image[i] = true; + write_appdata = true; + } + } + } + if(write_appdata || bWriteOffsets) + { + vfs::CBufferFile appDataFile("appdata.xml"); + this->writeSTIAppData(write_image, bWriteOffsets, vfs::tWritableFile::cast(&appDataFile)); + + outLib.addFile(vfs::tReadableFile::cast(&appDataFile)); + } + } + + return outLib.writeLibrary(outFile); +}; + +bool ja2xp::CImage::WriteAsPNGs(vfs::Path outpath, bool bWriteOffsets, bool rgba) +{ + if(!this->LoadData()) + { + return false; + } + + vfs::Path sFileName,path; + + m_pImageFile->getName().splitLast(path,sFileName); + + if(m_pRawImage->usNumberOfObjects) + { + for(int i=0; iusNumberOfObjects; ++i) + { + vfs::Path filename = CreateFileName(outpath, sFileName, i, m_pRawImage->usNumberOfObjects, L"png"); + + vfs::COpenWriteFile file(filename, true, true); + this->writeSubImageToPNGFile(i, &file.file(), rgba); + } + } + else + { + vfs::Path filename = CreateFileName("", sFileName, 0, m_pRawImage->usNumberOfObjects, L"png"); + + vfs::COpenWriteFile file(filename, true, true); + this->writeImageToPNGFile(&file.file(), rgba); + } + if(m_pRawImage->usNumberOfObjects > 0) + { + std::vector write_image(m_pRawImage->usNumberOfObjects, false); + bool write_appdata = false; + if(m_pRawImage->pAppData) + { + for(int i=0; iusNumberOfObjects; ++i) + { + AuxObjectData *pAOD = (AuxObjectData*)(&(m_pRawImage->pAppData[i*16])); + if(pAOD && (pAOD->fFlags || + pAOD->ubCurrentFrame || + pAOD->ubNumberOfFrames || + pAOD->ubNumberOfTiles || + pAOD->ubWallOrientation || + pAOD->usTileLocIndex) ) + { + write_image[i] = true; + write_appdata = true; + } + } + } + if(write_appdata || bWriteOffsets) + { + vfs::COpenWriteFile file(outpath+vfs::Path(L"appdata.xml"), true, true); + this->writeSTIAppData(write_image, bWriteOffsets, &file.file()); + } + } + + return true; +} + +bool ja2xp::CImage::WriteFirstPNG(vfs::tWritableFile* outFile, bool rgba) +{ + if(!outFile) + { + return false; + } + if(!this->LoadData()) + { + return false; + } + + if(m_pRawImage->usNumberOfObjects) + { + if(m_pRawImage->usNumberOfObjects > 1) + { + std::wcout << L"file has multiple subimages - converting only the first one" << std::endl; + } + this->writeSubImageToPNGFile(0, outFile, rgba); + } + else + { + this->writeImageToPNGFile(outFile); + } + if(m_pRawImage->pAppData) + { + std::wcout << "File has addional information stored - disable the '-onepng' option to convert it too" << std::endl; + } + + return true; +} + + +void ja2xp::CImage::LoadBMP() +{ + if(!m_pImageFile->openRead()) + { + return; + } + BITMAPFILEHEADER bmp_header; + if(!m_pImageFile->read((vfs::Byte*)&bmp_header,sizeof(BITMAPFILEHEADER))) + { + return; + } + BITMAPINFOHEADER bmp_infoheader; + if(!m_pImageFile->read((vfs::Byte*)&bmp_infoheader,sizeof(BITMAPINFOHEADER))) + { + return; + } + UINT8 palette[4*256]; + memset(palette,0,4*256); + if(!m_pImageFile->read((vfs::Byte*)&palette,256*sizeof(RGBQUAD))) + { + return; + } +} +#if 0 +bool CImage::WriteAsSTIs(vfs_string sOutPathName) +{ + if(!this->LoadData()) + { + return false; + } + + vfs_string sFileName,path; + + //SplitPath(m_pImageFile->GetFileName(),path,sFileName); + SplitPath(m_pImageFile->GetFileName()(),path,sFileName); + + for(int i=0; iusNumberOfObjects; ++i) + { + ETRLEObject &image = m_pRawImage->pETRLEObject[i]; + + IndexedSTIImage stiimg; + stiimg.AddCompressedImage(&m_pRawImage->p8BPPData[image.uiDataOffset], image.uiDataLength, image.usWidth, image.usHeight, image.sOffsetX, image.sOffsetY); + + stiimg.SetPalette(this->GetPalette(), 256); + + ChompSlash(sOutPathName); + vfs_string filename = CreateFileName(sOutPathName, sFileName, i, m_pRawImage->usNumberOfObjects, L"sti"); + vfs::tWriteableFile *pFile = GetWriteFile(filename); + if(pFile && pFile->OpenWrite()) + { + stiimg.WriteImage(pFile); + pFile->Close(); + } + + } + + + return true; +}; +#endif + diff --git a/ext/export/src/export/sti/Image.h b/ext/export/src/export/sti/Image.h new file mode 100644 index 000000000..9a2072958 --- /dev/null +++ b/ext/export/src/export/sti/Image.h @@ -0,0 +1,68 @@ +#ifndef _IMAGE_H_ +#define _IMAGE_H_ + +#include "Types.h" +#include "himage.h" + +#include +#include + +#include + +namespace ja2xp +{ + class CImage + { + public: + enum EImageType + { + IT_NONE, + IT_BITMAP, + IT_COMPRESSED, + }; + public: + + CImage(vfs::Path const& sFileName); + CImage(vfs::tReadableFile *pFile); + ~CImage(); + + EImageType GetImageType(); + + bool GetSize(UINT32 uiSubImage, UINT32 &uiWidth, UINT32 &uiHeight); + bool GetPosition(UINT32 uiSubImage, INT32 &uiX, INT32 &uiY); + + SGPPaletteEntry* GetPalette(); + + // use when image type is 'BITMAP' + void* GetDataPointer(UINT32 &uiSize); + + bool GetRawDataOfSubImage(UINT32 uiSubImage, void* pData, UINT32 uiMaxSize, UINT32 &uiFilledSize); + // use when image type is 'COMPRESSED' unless you know how to 'decompress' + UINT32 FillData(UINT32 uiSubImage, UINT8* pData, UINT32 uiMaxSize, bool rgba = false); + bool Unpack16BppImageToRGBBuffer(UINT16* pSrc, UINT8* pDst, UINT32 uiWidth, UINT32 uiHeight); + + UINT32 GetNumberOfSubImages(); + + bool LoadData(); + bool DeleteData(); + + void LoadBMP(); + //bool WriteAsBMPs(vfs_string sOutPathName); + bool WriteAsPNGs(vfs::tWritableFile* outFile, bool bWriteOffsets=false, bool rgba=false ); + bool WriteAsPNGs(vfs::Path outpath, bool bWriteOffsets=false, bool rgba=false); + bool WriteFirstPNG(vfs::tWritableFile* outFile, bool rgba=false); + //bool WriteAsSTIs(vfs_string sOutPathName); + + protected: + bool writeSubImageToPNGFile(int i, vfs::tWritableFile* file, bool rgba = false); + bool writeImageToPNGFile(vfs::tWritableFile* file, bool rgba = false); + bool writeSTIAppData(std::vector const& write_image, bool bWriteOffsets, vfs::tWritableFile* file); + private: + vfs::tReadableFile* m_pImageFile; + EImageType m_eImageType; + image_type* m_pRawImage; + bool m_bImageLoaded; + }; +}; + +#endif // _IMAGE_H_ diff --git a/ext/export/src/export/sti/STCI_lib.cpp b/ext/export/src/export/sti/STCI_lib.cpp new file mode 100644 index 000000000..0b82d716c --- /dev/null +++ b/ext/export/src/export/sti/STCI_lib.cpp @@ -0,0 +1,426 @@ +#include + +#include "STCI_lib.h" + +#include "imgfmt.h" +#include "himage.h" +#include "Types.h" +#include +#include +#include + +#include +#include + +namespace ja2xp +{ + BOOLEAN STCILoadRGB(vfs::tReadableFile *pFile, HIMAGE hImage, UINT16 fContents, STCIHeader * pHeader ); + BOOLEAN STCILoadIndexed(vfs::tReadableFile *pFile, HIMAGE hImage, UINT16 fContents, STCIHeader * pHeader ); + BOOLEAN STCISetPalette(vfs::tReadableFile *pFile, PTR pSTCIPalette, HIMAGE hImage ); +}; + +BOOLEAN ja2xp::LoadSTCIFileToImage(vfs::tReadableFile *pFile, HIMAGE hImage, UINT16 fContents ) +{ + STCIHeader Header; + image_type TempImage; + + // Check that hImage is valid, and that the file in question exists + assert( hImage != NULL ); + + TempImage = *hImage; + + if(pFile == NULL) + { + return FALSE; + } + + // Open the file and read the header + + vfs::COpenReadFile file(pFile); + VFS_THROW_IFF( STCI_HEADER_SIZE == pFile->read((vfs::Byte*)&Header,STCI_HEADER_SIZE), L"" ); + VFS_THROW_IFF( memcmp( Header.cID, STCI_ID_STRING, STCI_ID_LEN ) == 0, L"" ); + + // Determine from the header the data stored in the file. and run the appropriate loader + if (Header.fFlags & STCI_RGB) + { + if( !STCILoadRGB(pFile, &TempImage, fContents, &Header ) ) + { + pFile->close(); + std::cout << ".. loading bitmap image failed .." << std::endl; + return( FALSE ); + } + } + else if (Header.fFlags & STCI_INDEXED) + { + if( !STCILoadIndexed(pFile, &TempImage, fContents, &Header ) ) + { + pFile->close(); + std::cout << ".. loading compressed image failed .." << std::endl; + return( FALSE ); + } + } + else + { // unsupported type of data, or the right flags weren't set! + pFile->close(); + return( FALSE ); + } + + // Requested data loaded successfully. + pFile->close(); + + // Set some more flags in the temporary image structure, copy it so that hImage points + // to it, and return. + if (Header.fFlags & STCI_ZLIB_COMPRESSED) + { + TempImage.fFlags |= IMAGE_COMPRESSED; + } + TempImage.usWidth = Header.usWidth; + TempImage.usHeight = Header.usHeight; + TempImage.ubBitDepth = Header.ubDepth; + *hImage = TempImage; + + return( TRUE ); +} + +BOOLEAN ja2xp::STCILoadRGB(vfs::tReadableFile *pFile, HIMAGE hImage, UINT16 fContents, STCIHeader * pHeader ) +{ + if (fContents & IMAGE_PALETTE && !(fContents & IMAGE_ALLIMAGEDATA)) + { + // RGB doesn't have a palette! + std::cout << "RGB doesn't have a palette!" << std::endl; + return( FALSE ); + } + + if (fContents & IMAGE_BITMAPDATA) + { + // Allocate memory for the image data and read it in + hImage->pImageData = new char[ pHeader->uiStoredSize ]; + if (hImage->pImageData == NULL) + { + return( FALSE ); + } + try + { + vfs::size_t size = pHeader->uiStoredSize; + VFS_THROW_IFF( size == pFile->read( (vfs::Byte*)hImage->pImageData, size ), L"" ); + } + catch(vfs::Exception& ex) + { + delete[] hImage->pImageData; + return( FALSE ); + } + + hImage->fFlags |= IMAGE_BITMAPDATA; + + if( pHeader->ubDepth == 16) + { + // ASSUMPTION: file data is 565 R,G,B + + if (gusRedMask != (UINT16) pHeader->RGB.uiRedMask || gusGreenMask != (UINT16) pHeader->RGB.uiGreenMask || gusBlueMask != (UINT16) pHeader->RGB.uiBlueMask ) + { + // colour distribution of the file is different from hardware! We have to change it! + // Convert the image to the current hardware's specifications + if (gusRedMask > gusGreenMask && gusGreenMask > gusBlueMask) + { + // hardware wants RGB! + if (gusRedMask == 0x7C00 && gusGreenMask == 0x03E0 && gusBlueMask == 0x001F) + { // hardware is 555 + ConvertRGBDistribution565To555( hImage->p16BPPData, pHeader->usWidth * pHeader->usHeight ); + return( TRUE ); + } + else if (gusRedMask == 0xFC00 && gusGreenMask == 0x03E0 && gusBlueMask == 0x001F) + { + ConvertRGBDistribution565To655( hImage->p16BPPData, pHeader->usWidth * pHeader->usHeight ); + return( TRUE ); + } + else if (gusRedMask == 0xF800 && gusGreenMask == 0x07C0 && gusBlueMask == 0x003F) + { + ConvertRGBDistribution565To556( hImage->p16BPPData, pHeader->usWidth * pHeader->usHeight ); + return( TRUE ); + } + else + { + // take the long route + ConvertRGBDistribution565ToAny( hImage->p16BPPData, pHeader->usWidth * pHeader->usHeight ); + return( TRUE ); + } + } + else + { + // hardware distribution is not R-G-B so we have to take the long route! + ConvertRGBDistribution565ToAny( hImage->p16BPPData, pHeader->usWidth * pHeader->usHeight ); + return( TRUE ); + } + } + } + } + return( TRUE ); +} + + +BOOLEAN ja2xp::STCILoadIndexed(vfs::tReadableFile *pFile, HIMAGE hImage, UINT16 fContents, STCIHeader * pHeader ) +{ + UINT32 uiFileSectionSize; + PTR pSTCIPalette; + + if (fContents & IMAGE_PALETTE) + { + // Allocate memory for reading in the palette + if (pHeader->Indexed.uiNumberOfColours != 256) + { + return( FALSE ); + } + uiFileSectionSize = pHeader->Indexed.uiNumberOfColours * STCI_PALETTE_ELEMENT_SIZE; + pSTCIPalette = new char[uiFileSectionSize]; + if (pSTCIPalette == NULL) + { + pFile->close(); + return( FALSE ); + } + + memset( pSTCIPalette, 0, uiFileSectionSize ); + + // Read in the palette + try + { + VFS_THROW_IFF( uiFileSectionSize == pFile->read( (vfs::Byte*)pSTCIPalette, uiFileSectionSize ), L"" ); + } + catch(vfs::Exception& ex) + { + pFile->close(); + delete[] pSTCIPalette; + return( FALSE ); + } + if (!STCISetPalette(pFile, pSTCIPalette, hImage )) + { + pFile->close(); + delete[] pSTCIPalette; + return( FALSE ); + } + hImage->fFlags |= IMAGE_PALETTE; + // Free the temporary buffer + delete[] pSTCIPalette; + } + else if (fContents & (IMAGE_BITMAPDATA | IMAGE_APPDATA)) + { // seek past the palette + uiFileSectionSize = pHeader->Indexed.uiNumberOfColours * STCI_PALETTE_ELEMENT_SIZE; + try + { + pFile->setReadPosition( uiFileSectionSize, vfs::IBaseFile::SD_CURRENT); + } + catch(vfs::Exception& ex) + { + pFile->close(); + return( FALSE ); + } + } + if (fContents & IMAGE_BITMAPDATA) + { + if (pHeader->fFlags & STCI_ETRLE_COMPRESSED) + { + // load data for the subimage (object) structures + assert( sizeof( ETRLEObject ) == STCI_SUBIMAGE_SIZE ); + hImage->usNumberOfObjects = pHeader->Indexed.usNumberOfSubImages; + uiFileSectionSize = hImage->usNumberOfObjects * STCI_SUBIMAGE_SIZE; + hImage->pETRLEObject = (ETRLEObject *) new char[uiFileSectionSize]; + if (hImage->pETRLEObject == NULL) + { + pFile->close(); + if (fContents & IMAGE_PALETTE) + { + delete[] hImage->pPalette; + } + return( FALSE ); + } + try + { + VFS_THROW_IFF(uiFileSectionSize == pFile->read((vfs::Byte*)hImage->pETRLEObject, uiFileSectionSize), L"") + } + catch(vfs::Exception& ex) + { + //FileClose( hFile ); + pFile->close(); + if (fContents & IMAGE_PALETTE) + { + delete[] hImage->pPalette; + } + delete[] hImage->pETRLEObject; + return( FALSE ); + } + hImage->uiSizePixData = pHeader->uiStoredSize; + hImage->fFlags |= IMAGE_TRLECOMPRESSED; + } + // allocate memory for and read in the image data + hImage->pImageData = new char[pHeader->uiStoredSize]; + if (hImage->pImageData == NULL) + { + pFile->close(); + if (fContents & IMAGE_PALETTE) + { + delete[] hImage->pPalette; + } + if (hImage->usNumberOfObjects > 0) + { + delete[] hImage->pETRLEObject; + } + return( FALSE ); + } + try + { + VFS_THROW_IFF(pHeader->uiStoredSize == pFile->read( (vfs::Byte*)hImage->pImageData, pHeader->uiStoredSize), L""); + } + catch(vfs::Exception& ex) + { // Problem reading in the image data! + pFile->close(); + delete[] hImage->pImageData; + if (fContents & IMAGE_PALETTE) + { + delete[] hImage->pPalette; + } + if (hImage->usNumberOfObjects > 0) + { + delete[] hImage->pETRLEObject; + } + return( FALSE ); + } + hImage->fFlags |= IMAGE_BITMAPDATA; + } + else if (fContents & IMAGE_APPDATA) // then there's a point in seeking ahead + { + try + { + pFile->setReadPosition( pHeader->uiStoredSize, vfs::IBaseFile::SD_CURRENT); + } + catch(vfs::Exception& ex) + { + //FileClose( hFile ); + pFile->close(); + return( FALSE ); + } + } + + if (/*fContents & IMAGE_APPDATA &&*/ pHeader->uiAppDataSize > 0) + { + // load application-specific data + hImage->pAppData = new UINT8[pHeader->uiAppDataSize]; + if (hImage->pAppData == NULL) + { + pFile->close(); + delete[] hImage->pAppData; + if (fContents & IMAGE_PALETTE) + { + delete[] hImage->pPalette; + } + if (fContents & IMAGE_BITMAPDATA) + { + delete[] hImage->pImageData; + } + if (hImage->usNumberOfObjects > 0) + { + delete[] hImage->pETRLEObject; + } + return( FALSE ); + } + try + { + VFS_THROW_IFF(pHeader->uiAppDataSize == pFile->read( (vfs::Byte*)hImage->pAppData, pHeader->uiAppDataSize), L""); + } + catch(vfs::Exception& ex) + { + pFile->close(); + delete[] hImage->pAppData; + if (fContents & IMAGE_PALETTE) + { + delete[] hImage->pPalette; + } + if (fContents & IMAGE_BITMAPDATA) + { + delete[] hImage->pImageData; + } + if (hImage->usNumberOfObjects > 0) + { + delete[] hImage->pETRLEObject; + } + return( FALSE ); + } + hImage->uiAppDataSize = pHeader->uiAppDataSize; + for(int i=0; iIndexed.usNumberOfSubImages; ++i) + { + AuxObjectData *pAOD = (AuxObjectData*)(&(hImage->pAppData[i*16])); + pAOD->ubUnused[0] = pAOD->ubUnused[0]; + } + hImage->fFlags |= IMAGE_APPDATA; + } + else + { + hImage->pAppData = NULL; + hImage->uiAppDataSize = 0; + } + return( TRUE ); +} + + +BOOLEAN ja2xp::STCISetPalette(vfs::tReadableFile *pFile, PTR pSTCIPalette, HIMAGE hImage ) +{ + UINT16 usIndex; + STCIPaletteElement * pubPalette; + + pubPalette = (STCIPaletteElement *) pSTCIPalette; + + // Allocate memory for palette + hImage->pPalette = (SGPPaletteEntry *) new char[ sizeof( SGPPaletteEntry ) * 256]; + memset( hImage->pPalette, 0, ( sizeof( SGPPaletteEntry ) * 256 ) ); + + if ( hImage->pPalette == NULL ) + { + return( FALSE ); + } + + // Initialize the proper palette entries + for (usIndex = 0; usIndex < 256; usIndex++) + { + hImage->pPalette[ usIndex ].peRed = pubPalette->ubRed; + hImage->pPalette[ usIndex ].peGreen = pubPalette->ubGreen; + hImage->pPalette[ usIndex ].peBlue = pubPalette->ubBlue; + hImage->pPalette[ usIndex ].peFlags = 0; + pubPalette ++; + } + return TRUE; +} + + +BOOLEAN ja2xp::IsSTCIETRLEFile(vfs::tReadableFile *pFile, CHAR8 * ImageFile ) +{ +// HWFILE hFile; + STCIHeader Header; + + if(pFile == NULL) + { + return FALSE; + } + //CHECKF( FileExists( ImageFile ) ); + vfs::Path filename(ImageFile); + + try + { + VFS_THROW_IFF(STCI_HEADER_SIZE == pFile->read( (vfs::Byte*)&Header, STCI_HEADER_SIZE), L""); + VFS_THROW_IFF( memcmp( Header.cID, STCI_ID_STRING, STCI_ID_LEN ) == 0, L"" ); + } + catch(vfs::Exception& ex) + { + pFile->close(); + return( FALSE ); + } + pFile->close(); + if (Header.fFlags & STCI_ETRLE_COMPRESSED) + { + return( TRUE ); + } + else + { + return( FALSE ); + } +} + + + diff --git a/ext/export/src/export/sti/STCI_lib.h b/ext/export/src/export/sti/STCI_lib.h new file mode 100644 index 000000000..df6ac1adf --- /dev/null +++ b/ext/export/src/export/sti/STCI_lib.h @@ -0,0 +1,11 @@ +#include "Types.h" +#include "himage.h" + +#include + +namespace ja2xp +{ + BOOLEAN LoadSTCIFileToImage(vfs::tReadableFile *pFile, HIMAGE hImage, UINT16 fContents ); + + BOOLEAN IsSTCIETRLEFile(vfs::tReadableFile *pFile, CHAR8 * ImageFile ); +}; diff --git a/ext/export/src/export/sti/export_sti.cpp b/ext/export/src/export/sti/export_sti.cpp new file mode 100644 index 000000000..feee91548 --- /dev/null +++ b/ext/export/src/export/sti/export_sti.cpp @@ -0,0 +1,207 @@ + +#include "export_sti.h" + +#include "Image.h" +#include + +#include +#include + +#include + +bool ja2xp::convertSTItoJPC(vfs::tReadableFile *pFile, vfs::tWritableFile *pOutFile, bool bOffsets, bool rgba) +{ + if(!pFile) + { + std::wcout << L"file to read from is NULL" << std::endl; + } + if(!pOutFile) + { + std::wcout << L"file to write to is NULL" << std::endl; + } + CImage image(pFile); + if(image.LoadData()) + { + return image.WriteAsPNGs(pOutFile, bOffsets, rgba); + } + std::wcout << L"could not load data from STI file" << std::endl; + return false; +} + +bool ja2xp::convertSTItoJPC(vfs::tReadableFile *pFile, vfs::Path const base_out_path, bool bOffsets, bool rgba) +{ + if(!pFile) + { + std::wcout << L"file to read from is NULL" << std::endl; + } + CImage image(pFile); + if(image.LoadData()) + { + return image.WriteAsPNGs(base_out_path, bOffsets, rgba); + } + std::wcout << L"could not load data from STI file" << std::endl; + return false; +} + +bool ja2xp::convertSTItoPNG(vfs::tReadableFile *pFile, vfs::tWritableFile *pOutFile, bool rgba) +{ + if(!pFile) + { + std::wcout << L"file to read from is NULL" << std::endl; + } + CImage image(pFile); + if(image.LoadData()) + { + return image.WriteFirstPNG(pOutFile, rgba); + } + std::wcout << L"could not load data from STI file" << std::endl; + return false; +} + +bool ja2xp::convertSTItoJPC(vfs::Path const& sSrc, vfs::Path const& sDst, bool bPacked, bool bOffsets, bool bOnePng, bool rgba) +{ + vfs::CVirtualFileSystem::Iterator it = getVFS()->begin(sSrc); + int file_counter = 0; + for(; !it.end(); it.next()) + { + file_counter++; + vfs::String::str_t fname = it.value()->getPath().c_wcs(); + if( !vfs::StrCmp::Equal( fname.substr(fname.length()-4,4), L".sti") ) + { + std::wcout << L"\"" << fname << L"\" is not an .sti file" << std::endl; + continue; + } + if(!it.value()->openRead()) + { + std::wcout << L"Could not open file \"" << sSrc() << L"\"" << std::endl; + continue; + } + vfs::String::str_t fname_base = fname.substr(0,fname.length()-4); + + std::wcout << L"Converting file \"" << fname << L"\"" << std::endl; + + if(bOnePng) + { + vfs::Path out_name; + if(vfs::StrCmp::Equal(sDst(), L".")) + { + out_name = vfs::Path(fname_base + L".png"); + } + else + { + out_name = sDst; + } + vfs::COpenWriteFile wfile(out_name,true,true); + + if( !convertSTItoPNG( it.value(), &(wfile.file()), rgba ) ) + { + std::wcout << L"error : could not convert sti image" << std::endl; + continue; + } + } + else if(bPacked) + { + vfs::Path out_name; + if(vfs::StrCmp::Equal(sDst(), L".")) + { + out_name = vfs::Path(fname_base + L".jpc.7z"); + } + else + { + out_name = sDst; + } + vfs::COpenWriteFile wfile(out_name,true,true); + + if( !convertSTItoJPC( it.value(), &(wfile.file()), bOffsets, rgba ) ) + { + std::wcout << L"error : could not convert sti image" << std::endl; + continue; + } + } + else + { + if( !convertSTItoJPC( it.value(), vfs::Path(fname_base), bOffsets, rgba ) ) + { + std::wcout << L"error : could not convert sti image" << std::endl; + continue; + } + } + } + if(file_counter == 0) + { + std::wcout << L"Nothing to convert!" << std::endl; + } + return true; +} + +/**********************************************************************************************/ + +const wchar_t* ja2xp::CExportSTI::commandString = L"sti"; + +void ja2xp::CExportSTI::handleCommand(CExportSTI::param_list_t const& params) +{ + bool opt_Packed = true, + opt_ExportOffsets = false, + opt_OnePng = false, + opt_Rgba = false; + + param_list_t vfs_params; + param_list_t::const_iterator cit = params.begin(); + for(; cit != params.end(); ++cit) + { + if( vfs::StrCmp::Equal(*cit, L"-unpack") ) + { + opt_Packed = false; + } + else if( vfs::StrCmp::Equal(*cit, L"-offsets") ) + { + opt_ExportOffsets = true; + } + else if( vfs::StrCmp::Equal(*cit, L"-onepng") ) + { + opt_OnePng = true; + } + else if( vfs::StrCmp::Equal(*cit, L"-rgba") ) + { + opt_Rgba = true; + } + else + { + vfs_params.push_back(*cit); + } + } + + ja2xp::InitVFS& vfs = ja2xp::InitVFS::instance(); + vfs.checkParameters(vfs_params); + if(!vfs.init()) + { + return; + } + try + { + convertSTItoJPC(vfs.srcPattern(), vfs.dstPattern(), opt_Packed, opt_ExportOffsets, opt_OnePng, opt_Rgba); + } + catch(vfs::Exception& msg) + { + std::wcout << msg.getLastEntryString().c_wcs() << std::endl; + } +} + +void ja2xp::CExportSTI::printHelp() +{ + std::wcout + << L" convert STI image file(s) to a series of png images (as 7z archive)" << std::endl + << L" * if \"destination\" is a directory, then the filename's extension will be" << std::endl + << L" replaced with \".jpc.7z\"" << std::endl + << std::endl + << L" options :" << std::endl + << L" -unpack : if set, no 7z archive will be created. Instead," << std::endl + << L" for an image 'path/image.sti',subimages will be" << std::endl + << L" written into the directory \"path/image/.\"" << std::endl + << L" -offsets : offsets of all subimages will we written in the" << std::endl + << L" \"appdata.xml\" file" << std::endl + << L" -onepng : creates one png image instead of a jpc.7z archive." << std::endl + << L" If there are multiple subimages, only the first one" << std::endl + << L" will be converted." << std::endl; +} + diff --git a/ext/export/src/export/sti/export_sti.h b/ext/export/src/export/sti/export_sti.h new file mode 100644 index 000000000..84d478fa4 --- /dev/null +++ b/ext/export/src/export/sti/export_sti.h @@ -0,0 +1,30 @@ +#ifndef _EXPORT_STI_H_ +#define _EXPORT_STI_H_ + +#include +#include + +#include + +namespace ja2xp +{ + class CExportSTI : public IExporterBase + { + public: + typedef IExporterBase::param_list_t param_list_t; + + static const wchar_t* commandString;// = L"sti"; + + virtual void handleCommand(param_list_t const& params); + virtual void printHelp(); + }; + + bool convertSTItoJPC(vfs::tReadableFile *pFile, vfs::tWritableFile *pOutFile, bool bOffsets, bool rgba); + bool convertSTItoJPC(vfs::tReadableFile *pFile, vfs::Path const base_out_path, bool bOffsets, bool rgba); + bool convertSTItoPNG(vfs::tReadableFile *pFile, vfs::tWritableFile *pOutFile, bool rgba); + + bool convertSTItoJPC(vfs::Path const& sSrc, vfs::Path const& sDst, + bool bPacked=true, bool bOffsets=false, bool bOnePng=false, bool rgba=false); +}; + +#endif // _EXPORT_STI_H_ diff --git a/ext/export/src/export/sti/stci_image_utils.cpp b/ext/export/src/export/sti/stci_image_utils.cpp new file mode 100644 index 000000000..5dbe1d621 --- /dev/null +++ b/ext/export/src/export/sti/stci_image_utils.cpp @@ -0,0 +1,554 @@ +#include "stci_image_utils.h" +#include "himage.h" + +#include + +const int iCOMPRESS_TRANSPARENT = 0x80; +const int iCOMPRESS_RUN_MASK = 0x7F; + + +UINT32 ja2xp::UnpackETRLEImageToBuffer(UINT8 *pBuffer, image_type *pImage, UINT16 usETRLEIndex) +{ + if(!pImage || !pBuffer) + { + return 0; + } + + ETRLEObject *pETRLEObject = &(pImage->pETRLEObject[usETRLEIndex]); + if(!pETRLEObject) + { + return 0; + } + + UINT8 *pCurrent; + pCurrent = &((UINT8 *)pImage->pPixData8)[pETRLEObject->uiDataOffset]; + unsigned int uiImageSize = pETRLEObject->usHeight * pETRLEObject->usWidth; + + unsigned int uiBufferPos = 0; + unsigned char ubCount; + while(uiBufferPos < uiImageSize) + { + ubCount = *pCurrent & iCOMPRESS_RUN_MASK; + if(*pCurrent & iCOMPRESS_TRANSPARENT) + { + pCurrent++; + uiBufferPos += ubCount; + } + else + { + pCurrent++; + memcpy(&pBuffer[uiBufferPos], pCurrent, ubCount); + pCurrent += ubCount; + uiBufferPos += ubCount; + } + } + return uiBufferPos; +} + +UINT32 ja2xp::UnpackETRLEImageToRGBABuffer(UINT8 *pBuffer, image_type *pImage, UINT16 usETRLEIndex) +{ + if(!pImage || !pBuffer) + { + return 0; + } + + ETRLEObject *pETRLEObject = &(pImage->pETRLEObject[usETRLEIndex]); + if(!pETRLEObject) + { + return 0; + } + + SGPPaletteEntry* palette = pImage->pPalette; + if(!palette) + { + return 0; + } + + UINT8 *pCurrent; + pCurrent = &((UINT8 *)pImage->pPixData8)[pETRLEObject->uiDataOffset]; + unsigned int uiImageSize = pETRLEObject->usHeight * pETRLEObject->usWidth; + + unsigned int uiBufferPos = 0; + unsigned char ubCount; + while(uiBufferPos < (4*uiImageSize)) + { + ubCount = *pCurrent & iCOMPRESS_RUN_MASK; + if(*pCurrent & iCOMPRESS_TRANSPARENT) + { + pCurrent++; + uiBufferPos += 4 * (int)ubCount; + pBuffer += 4 * (int)ubCount; + } + else + { + pCurrent++; + int count = ubCount; + while(count--) + { + UINT8 cur = *pCurrent++; + *pBuffer++ = palette[cur].peRed; + *pBuffer++ = palette[cur].peGreen; + *pBuffer++ = palette[cur].peBlue; + *pBuffer++ = 255; // alpha + } + uiBufferPos += 4 * (int)ubCount; + } + } + return uiBufferPos; +} + + +ja2xp::CIndexedSTIImage::CIndexedSTIImage() +{ + memset(&_header, 0, sizeof(STCIHeader)); +} + +ja2xp::CIndexedSTIImage::~CIndexedSTIImage() +{ + if(_palette) + { + delete[] _palette; + } + for(unsigned int i=0; i < _compressed_images.size(); ++i) + { + delete[] _compressed_images[i]; + } +} + + + + +bool ja2xp::CIndexedSTIImage::SetPalette(SGPPaletteEntry *pPal, int iSize) +{ + if(iSize < 0 ||iSize > 1024) + { + return false; + } + _pal_size = iSize; + _palette = new STCIPaletteElement[iSize]; + for(int i=0; i= data_size) + { + done = true; + } + } + + subimage.uiDataLength = compressed_size; + _header.uiStoredSize += compressed_size; + _images.push_back(subimage); + _compressed_images.push_back(compressed_start); + _header.uiOriginalSize += data_size; + _header.Indexed.usNumberOfSubImages += 1; + + return true; +} + +bool ja2xp::CIndexedSTIImage::WriteImage(vfs::tWritableFile* pFile) +{ + if(!pFile || !pFile->openWrite()) + { + return false; + } + + strncpy((char*)&(_header.cID[0]),"STCI",4); + + _header.uiOriginalSize = _compressed_images.size() * 640 * 480; + //_header.uiStoredSize += 64 + 768 + _header.Indexed.usNumberOfSubImages*16; // equal to uiOriginalSize if data uncompressed + _header.uiTransparentValue = 0; + _header.fFlags = STCI_ETRLE_COMPRESSED | STCI_INDEXED | STCI_TRANSPARENT; + _header.usHeight = 480; + _header.usWidth = 640; + + _header.ubDepth = 8; + _header.uiAppDataSize = _compressed_images.size() * 16; + + _header.Indexed.ubRedDepth = 8; + _header.Indexed.ubGreenDepth = 8; + _header.Indexed.ubBlueDepth = 8; + _header.Indexed.uiNumberOfColours = 256; + _header.Indexed.usNumberOfSubImages = _compressed_images.size(); + + pFile->write((vfs::Byte*)&_header,STCI_HEADER_SIZE); + + pFile->write((vfs::Byte*)_palette,_pal_size*sizeof(STCIPaletteElement)); + + UINT32 offset=0; + // write sub-image headers + for(unsigned int i=0; i<_images.size(); ++i) + { + _images[i].uiDataOffset = offset; + pFile->write((vfs::Byte*)&_images[i],STCI_SUBIMAGE_SIZE); + offset += _images[i].uiDataLength; + } + // write sub-images + for(unsigned int i=0; i<_compressed_images.size(); ++i) + { + pFile->write((vfs::Byte*)_compressed_images[i],_images[i].uiDataLength); + } + // write application data + int frames = _compressed_images.size()/8; // 8 = number of directions + for(unsigned int i=0; i<_compressed_images.size(); ++i) + { + AuxObjectData aod; + memset(&aod,0,sizeof(AuxObjectData)); + if((frames+1) % (i+1) == 0) + { + aod.ubNumberOfFrames = frames; + aod.fFlags = AUX_ANIMATED_TILE; + } + pFile->write((vfs::Byte*)&aod,sizeof(AuxObjectData)); + } + pFile->close(); + return true; +} + +bool ja2xp::CIndexedSTIImage::WriteToHIMAGE(HIMAGE pImage) +{ + if(!pImage) + { + return false; + } + pImage->usNumberOfObjects = _compressed_images.size(); + pImage->usWidth = 640; + pImage->usHeight = 480; + pImage->ubBitDepth = 8; + pImage->fFlags = STCI_ETRLE_COMPRESSED | STCI_INDEXED | STCI_TRANSPARENT;; + strncat(pImage->ImageFile,"test",4); + pImage->iFileLoader = -1; + pImage->pui16BPPPalette = NULL; + + + pImage->pPalette = new SGPPaletteEntry[256]; + for(int j=0; j<256; ++j) + { + pImage->pPalette[j].peRed = _palette[j].ubRed; + pImage->pPalette[j].peGreen = _palette[j].ubGreen; + pImage->pPalette[j].peBlue = _palette[j].ubBlue; + pImage->pPalette[j].peFlags = 0; + } + + pImage->pETRLEObject = new ETRLEObject[pImage->usNumberOfObjects]; + UINT32 offset=0; // == size + for(unsigned int i=0; i<_images.size(); ++i) + { + pImage->pETRLEObject[i].sOffsetX = _images[i].sOffsetX; + pImage->pETRLEObject[i].sOffsetY = _images[i].sOffsetY; + pImage->pETRLEObject[i].usHeight = _images[i].usHeight; + pImage->pETRLEObject[i].usWidth = _images[i].usWidth; + pImage->pETRLEObject[i].uiDataOffset = offset; + pImage->pETRLEObject[i].uiDataLength = _images[i].uiDataLength; + offset += _images[i].uiDataLength; + } + + pImage->uiSizePixData = offset; + pImage->pPixData8 = new UINT8[offset]; + // write sub-images + for(unsigned int i=0; i<_compressed_images.size(); ++i) + { + memcpy( + &pImage->pPixData8[pImage->pETRLEObject[i].uiDataOffset], + _compressed_images[i], + pImage->pETRLEObject[i].uiDataLength); + } + + pImage->uiAppDataSize = pImage->usNumberOfObjects * sizeof(AuxObjectData); + pImage->pAppData = (UINT8*)(new AuxObjectData[pImage->usNumberOfObjects]); + memset(pImage->pAppData,0,pImage->uiAppDataSize); + + // write application data + int frames = _compressed_images.size()/8; // 8 = number of directions + for(unsigned int i=0; iusNumberOfObjects; ++i) + { + if(i % frames == 0) + { + AuxObjectData &aod = *((AuxObjectData*)(&pImage->pAppData[i*sizeof(AuxObjectData)])); + aod.ubNumberOfFrames = frames; + aod.fFlags = AUX_ANIMATED_TILE; + } + } + return true; +} + + + +//BOOLEAN GetETRLEPixelValue( UINT8 * pDest, HVOBJECT hVObject, UINT16 usETRLEIndex, UINT16 usX, UINT16 usY ) +BOOLEAN ja2xp::GetETRLEPixelValue( UINT8 * pDest, image_type *hImage, UINT16 usETRLEIndex, UINT16 usX, UINT16 usY ) +{ + UINT8 * pCurrent; + UINT16 usLoopX = 0; + UINT16 usLoopY = 0; + UINT16 ubRunLength; + ETRLEObject * pETRLEObject; + + // Do a bunch of checks + assert( hImage != NULL ); + assert( usETRLEIndex < hImage->usNumberOfObjects ); + + pETRLEObject = &(hImage->pETRLEObject[usETRLEIndex]); + + assert( usX < pETRLEObject->usWidth ); + assert( usY < pETRLEObject->usHeight ); + + // Assuming everything's okay, go ahead and look... + pCurrent = &((UINT8 *)hImage->pPixData8)[pETRLEObject->uiDataOffset]; + + // Skip past all uninteresting scanlines + while( usLoopY < usY ) + { + while( *pCurrent != 0 ) + { + if (*pCurrent & iCOMPRESS_TRANSPARENT) + { + pCurrent++; + } + else + { + pCurrent += *pCurrent & iCOMPRESS_RUN_MASK; + } + } + usLoopY++; + } + + // Now look in this scanline for the appropriate byte + do + { + ubRunLength = *pCurrent & iCOMPRESS_RUN_MASK; + + if (*pCurrent & iCOMPRESS_TRANSPARENT) + { + if (usLoopX + ubRunLength >= usX) + { + *pDest = 0; + return( TRUE ); + } + else + { + pCurrent++; + } + } + else + { + if (usLoopX + ubRunLength >= usX) + { + // skip to the correct byte; skip at least 1 to get past the byte defining the run + pCurrent += (usX - usLoopX) + 1; + *pDest = *pCurrent; + return( TRUE ); + } + else + { + pCurrent += ubRunLength + 1; + } + } + usLoopX += ubRunLength; + } + while( usLoopX < usX ); + // huh??? + return( FALSE ); +} + +/* +BOOLEAN Blt8BPPDataTo8BPPBuffer( UINT8 *pBuffer, UINT32 uiDestPitchBYTES, image_type *hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex ) +{ + static UINT32 uiOffset; + static UINT32 usHeight, usWidth; + static UINT8 *SrcPtr, *DestPtr; + static UINT32 LineSkip; + static ETRLEObject *pTrav; + static INT32 iTempX, iTempY; + + + // Assertions + Assert( hSrcVObject != NULL ); + Assert( pBuffer != NULL ); + + // Get Offsets from Index into structure + pTrav = &(hSrcVObject->pETRLEObject[ usIndex ] ); + usHeight = (UINT32)pTrav->usHeight; + usWidth = (UINT32)pTrav->usWidth; + uiOffset = pTrav->uiDataOffset; + + // Add to start position of dest buffer + iTempX = iX + pTrav->sOffsetX; + iTempY = iY + pTrav->sOffsetY; + + // Validations + CHECKF( iTempX >= 0 ); + CHECKF( iTempY >= 0 ); + + + SrcPtr= (UINT8 *)hSrcVObject->pPixData8 + uiOffset; + DestPtr = (UINT8 *)pBuffer + (uiDestPitchBYTES*iTempY) + (iTempX); + LineSkip=(uiDestPitchBYTES-(usWidth)); + + __asm { + + mov esi, SrcPtr + mov edi, DestPtr + xor eax, eax + xor ebx, ebx + xor ecx, ecx + +BlitDispatch: + + mov cl, [esi] + inc esi + or cl, cl + js BlitTransparent + jz BlitDoneLine + +//BlitNonTransLoop: + + clc + rcr cl, 1 + jnc BlitNTL2 + + movsb + +BlitNTL2: + clc + rcr cl, 1 + jnc BlitNTL3 + + movsw + +BlitNTL3: + + or cl, cl + jz BlitDispatch + + xor ebx, ebx + +//BlitNTL4: + + rep movsd + + jmp BlitDispatch + +BlitTransparent: + + and ecx, 07fH + xor al, al + rep stosb + + jmp BlitDispatch + + +BlitDoneLine: + + dec usHeight + jz BlitDone + add edi, LineSkip + jmp BlitDispatch + + +BlitDone: + } + + return(TRUE); + +} +*/ + + diff --git a/ext/export/src/export/sti/stci_image_utils.h b/ext/export/src/export/sti/stci_image_utils.h new file mode 100644 index 000000000..38c6e7a1a --- /dev/null +++ b/ext/export/src/export/sti/stci_image_utils.h @@ -0,0 +1,51 @@ +#ifndef _STCI_IMAGE_UTILS_H_ +#define _STCI_IMAGE_UTILS_H_ + +#include "Types.h" +#include "himage.h" +#include +#include + +#include + +namespace ja2xp +{ + class CIndexedSTIImage + { + public: + CIndexedSTIImage(); + ~CIndexedSTIImage(); + + bool SetPalette(SGPPaletteEntry *pPal, int iSize); + bool AddImage(UINT8 *data, UINT32 data_size, UINT32 image_width, UINT32 image_height, INT32 image_offset_x, INT32 image_offset_y, UINT8 *original_compressed=NULL, UINT32 iriginal_compressed_size=0); + + bool AddCompressedImage(UINT8 *data, UINT32 data_size, UINT32 image_width, UINT32 image_height, INT32 image_offset_x, INT32 image_offset_y); + + bool WriteImage(vfs::tWritableFile* pFile); + bool WriteToHIMAGE(HIMAGE pImage); + private: + STCIHeader _header; + STCIPaletteElement *_palette; + int _pal_size; + std::vector _images; + std::vector _compressed_images; + }; + + + void SplitSTIImage(vfs::String const&, vfs::String &file, vfs::String &ext); + + /** + * BUG: this function gives wrong results + */ + BOOLEAN GetETRLEPixelValue( UINT8 * pDest, image_type *hImage, UINT16 usETRLEIndex, UINT16 usX, UINT16 usY ); + + UINT32 UnpackETRLEImageToBuffer(UINT8 *pBuffer, image_type *pImage, UINT16 ueETRLEIndex); + UINT32 UnpackETRLEImageToRGBABuffer(UINT8 *pBuffer, image_type *pImage, UINT16 ueETRLEIndex); + + /** + * NOTE: implemented in msvc inline assembler + * does not work with gcc -> use 'UnpackETRLEImageToBuffer' + */ + BOOLEAN Blt8BPPDataTo8BPPBuffer( UINT8 *pBuffer, UINT32 uiDestPitchBYTES, image_type *hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex ); +}; +#endif // _STCI_IMAGE_UTILS_H_ diff --git a/ext/export/src/exporter_base.h b/ext/export/src/exporter_base.h new file mode 100644 index 000000000..dd7deff5f --- /dev/null +++ b/ext/export/src/exporter_base.h @@ -0,0 +1,19 @@ +#ifndef _EXPORTER_BASE_H_ +#define _EXPORTER_BASE_H_ + +#include +#include + +namespace ja2xp +{ + class IExporterBase + { + public: + typedef std::list param_list_t; + + virtual void handleCommand(std::list const& params) = 0; + virtual void printHelp() = 0; + }; +}; + +#endif // _EXPORTER_BASE_H_ diff --git a/ext/export/src/init_vfs.cpp b/ext/export/src/init_vfs.cpp new file mode 100644 index 000000000..5816b20c1 --- /dev/null +++ b/ext/export/src/init_vfs.cpp @@ -0,0 +1,211 @@ +#include + +#include +#include +#include + +#include +#include + +ja2xp::InitVFS::InitVFS() +{ +} + +ja2xp::InitVFS& ja2xp::InitVFS::instance() +{ + static ja2xp::InitVFS singleton; + return singleton; +} + +void ja2xp::InitVFS::checkParameters(ja2xp::IExporterBase::param_list_t const& params) +{ + ja2xp::IExporterBase::param_list_t::const_iterator cit = params.begin(); + for(; cit != params.end(); ++cit) + { + if( vfs::StrCmp::Equal(*cit, L"-lib") ) + { + this->src_lib = true; + cit++; + if(cit != params.end()) + { + // get library path + this->src_path = vfs::Path(*cit); + this->has_src = true; + + cit++; + if(cit != params.end()) + { + this->src_pattern = vfs::Path(*cit); + continue; + } + } + std::wcout << L"error " << std::endl; + } + else if( vfs::StrCmp::Equal(*cit, L"-create_dst") ) + { + this->dst_create = true; + continue; + } + else if(!cit->empty() && cit->at(0) == L'-') + { + //ignore unknown options + continue; + } + + if(!this->has_src) + { + this->src_path = vfs::Path(*cit); + this->has_src = true; + } + else if(this->has_src && !this->has_dst) + { + this->dst_path = vfs::Path(*cit); + this->has_dst = true; + } + } +} + +static void SplitPath(vfs::Path const& path, vfs::Path& root, vfs::Path& pattern) +{ + vfs::String::str_t sSrc = path(); + if(sSrc.empty()) + { + return; + } + // remove enclosing "" + if(sSrc.at(0) == L'\"' && sSrc.at(sSrc.length()-1) == L'\"') + { + sSrc = sSrc.substr(1,sSrc.length()-2); + } + // has * in path + size_t pos = sSrc.find_first_of(L"*"); + if(pos != std::wstring::npos) + { + vfs::Path temp_root, temp_pattern; + // get directory + vfs::Path temp(sSrc.substr(0,pos+1)); + temp.splitLast(temp_root, temp_pattern); + // correct pattern + temp_pattern = vfs::Path(temp_pattern.c_wcs() + sSrc.substr(pos+1,sSrc.length()-pos-1)); + + root = vfs::Path(temp_root); + pattern = vfs::Path(temp_pattern); + } + else + { + path.splitLast(root,pattern); + } +} + + +//bool InitVFS(vfs::Path const& sSrcPath, vfs::Path const& sDstPath, +// vfs::Path& src_pattern, vfs::Path& dst_pattern, +// bool bSourceAsLib, bool bCreateDstDirectory) +bool ja2xp::InitVFS::init() +{ + if( !this->has_src || !this->has_dst ) + { + return false; + } + vfs::Path src_root, dst_root; + + if( this->src_pattern.empty() && !this->src_lib ) + { + SplitPath(this->src_path, src_root, this->src_pattern); + if(src_root.empty()) src_root = L"."; + } + else + { + src_root = this->src_path; + } + + SplitPath(this->dst_path, dst_root, this->dst_pattern); + if(dst_root.empty()) dst_root = L"."; + + vfs::String ext_test; + if(!this->dst_pattern.extension(ext_test)) + { + // output pattern has no extension and is probably not a directory name + dst_root += this->dst_pattern; + this->dst_pattern = L"."; + } + + if(!this->src_lib && !vfs::OS::checkRealDirectory(src_root)) + { + std::wcout << L"Source directory \"" << src_root() << L"\" does not exist" << std::endl; + return false; + } + if(!vfs::OS::checkRealDirectory(dst_root)) + { + if(!this->dst_create) + { + std::wcout << L"Destination directory \"" << dst_root() << L"\" does not exist" << std::endl; + return false; + } + std::stack dirs; + vfs::Path left = dst_root, right, temp; + while(!left.empty() && !vfs::OS::checkRealDirectory(left)) + { + dirs.push(left); + left.splitLast(temp,right); + left = temp; + } + while(!dirs.empty()) + { + if(!vfs::OS::createRealDirectory(dirs.top())) + { + std::wcout << L"Could not create directory \"" << dirs.top().c_wcs() << std::endl; + return false; + } + dirs.pop(); + } + } + + vfs_init::Location src_loc; + if(this->src_lib) + { + src_loc.m_type = L"library"; + } + else + { + src_loc.m_type = L"directory"; + } + src_loc.m_path = src_root; + + vfs_init::Profile src_prof; + src_prof.m_name = L"Source"; + src_prof.addLocation(&src_loc); + + vfs_init::Location dst_loc; + dst_loc.m_type = L"directory"; + dst_loc.m_path = dst_root; + + vfs_init::Profile dst_prof; + dst_prof.m_name = L"Destination"; + dst_prof.addLocation(&dst_loc); + dst_prof.m_writable = true; + + vfs_init::VfsConfig conf; + conf.addProfile(&src_prof); + conf.addProfile(&dst_prof); + + try + { + vfs_init::initVirtualFileSystem(conf); + } + catch(vfs::Exception& ex) + { + std::wcout << ex.m_CallStack.front().message.c_wcs() << std::endl; + return false; + } + return true; +} + +vfs::Path const& ja2xp::InitVFS::srcPattern() +{ + return this->src_pattern; +} +vfs::Path const& ja2xp::InitVFS::dstPattern() +{ + return this->dst_pattern; +} diff --git a/ext/export/src/init_vfs.h b/ext/export/src/init_vfs.h new file mode 100644 index 000000000..9620d2613 --- /dev/null +++ b/ext/export/src/init_vfs.h @@ -0,0 +1,33 @@ +#ifndef _INIT_VFS_H_ +#define _INIT_VFS_H_ + +#include +#include + +namespace ja2xp +{ + class InitVFS + { + public: + static InitVFS& instance(); + + void checkParameters(IExporterBase::param_list_t const& params); + bool init(); + + vfs::Path const& srcPattern(); + vfs::Path const& dstPattern(); + private: + InitVFS(); + + bool has_src, has_dst; + bool src_lib, dst_create; + vfs::Path src_path, dst_path; + vfs::Path src_pattern, dst_pattern; + }; +} + +//bool InitVFS(vfs::Path const& sSrcPath, vfs::Path const& sDstPath, +// vfs::Path& src_pattern, vfs::Path& dst_pattern, +// bool bSourceAsLib, bool bCreateDstDirectory); + +#endif // _INIT_VFS_H_ diff --git a/ext/export/src/ja2/Structure Internals.h b/ext/export/src/ja2/Structure Internals.h new file mode 100644 index 000000000..3d86fe57f --- /dev/null +++ b/ext/export/src/ja2/Structure Internals.h @@ -0,0 +1,243 @@ +#ifndef __STRUCTURE_INTERNAL_H +#define __STRUCTURE_INTERNAL_H + +// +// If you wish to use the structure database functions, include +// structure_extern.h, not structure.h! +// + +#include "types.h" +#include "himage.h" + +// A few words about the overall structure scheme: +// +// Large structures are split into multiple sections, +// one for each tile. +// +// Each section is treated as a separate object, +// except that it does NOT record information about +// hit points, but instead stores a pointer to the +// base object (section). +// +// Each section has a line of sight profile. These +// profiles are split into 5 in each horizontal direction +// and 4 vertically, forming 100 "cubes". In real +// world terms, each section represents a volume +// with a height of 8 feet (and width and length +// of what?) +// +// It is important to note that the vertical +// position of each section is measured in individual +// cubes (rather than, as it were, groups of 4 vertical +// cubes) + +#define PROFILE_X_SIZE 5 +#define PROFILE_Y_SIZE 5 +#define PROFILE_Z_SIZE 4 + +// these values should be compared for less than rather than less +// than or equal to +#define STRUCTURE_ON_GROUND 0 +#define STRUCTURE_ON_ROOF PROFILE_Z_SIZE +#define STRUCTURE_ON_GROUND_MAX PROFILE_Z_SIZE +#define STRUCTURE_ON_ROOF_MAX PROFILE_Z_SIZE * 2 + +typedef UINT8 PROFILE[PROFILE_X_SIZE][PROFILE_Y_SIZE]; + +extern UINT8 AtHeight[PROFILE_Z_SIZE]; + +// MAP_ELEMENT may get later: +// PROFILE * CombinedLOSProfile; +// PROFILE * CombinedProtectionProfile; +// +// LEVELNODE gets a pointer to a STRUCTURE or +// a union between its soldier pointer and a +// STRUCTURE pointer + +// if (fFlags & STRUCTURE_BASE_TILE) +// then the structure is the "base" of the object +// and its hitpoint value is the one for the object +// +// vv generic flags for all structures +// vvv type flags +// + +// how to handle explodable structures + +// NOT used in DB structures! +#define STRUCTURE_BASE_TILE 0x00000001 +#define STRUCTURE_OPEN 0x00000002 +#define STRUCTURE_OPENABLE 0x00000004 +// synonyms for STRUCTURE_OPENABLE +#define STRUCTURE_CLOSEABLE 0x00000004 +#define STRUCTURE_SEARCHABLE 0x00000004 +#define STRUCTURE_HIDDEN 0x00000008 + +#define STRUCTURE_MOBILE 0x00000010 +// STRUCTURE_PASSABLE is set for each structure instance where +// the tile flag TILE_PASSABLE is set +#define STRUCTURE_PASSABLE 0x00000020 +#define STRUCTURE_EXPLOSIVE 0x00000040 +#define STRUCTURE_TRANSPARENT 0x00000080 + +#define STRUCTURE_GENERIC 0x00000100 +#define STRUCTURE_TREE 0x00000200 +#define STRUCTURE_FENCE 0x00000400 +#define STRUCTURE_WIREFENCE 0x00000800 + +#define STRUCTURE_HASITEMONTOP 0x00001000 // ATE: HASITEM: struct has item on top of it +#define STRUCTURE_SPECIAL 0x00002000 +#define STRUCTURE_LIGHTSOURCE 0x00004000 +#define STRUCTURE_VEHICLE 0x00008000 + +#define STRUCTURE_WALL 0x00010000 +#define STRUCTURE_WALLNWINDOW 0x00020000 +#define STRUCTURE_SLIDINGDOOR 0x00040000 +#define STRUCTURE_DOOR 0x00080000 + +// a "multi" structure (as opposed to multitiled) is composed of multiple graphics & structures +#define STRUCTURE_MULTI 0x00100000 +#define STRUCTURE_CAVEWALL 0x00200000 +#define STRUCTURE_DDOOR_LEFT 0x00400000 +#define STRUCTURE_DDOOR_RIGHT 0x00800000 + +#define STRUCTURE_NORMAL_ROOF 0x01000000 +#define STRUCTURE_SLANTED_ROOF 0x02000000 +#define STRUCTURE_TALL_ROOF 0x04000000 +#define STRUCTURE_SWITCH 0x08000000 + +#define STRUCTURE_ON_LEFT_WALL 0x10000000 +#define STRUCTURE_ON_RIGHT_WALL 0x20000000 +#define STRUCTURE_CORPSE 0x40000000 +#define STRUCTURE_PERSON 0x80000000 + +// COMBINATION FLAGS +#define STRUCTURE_ANYFENCE 0x00000C00 +#define STRUCTURE_ANYDOOR 0x00CC0000 +#define STRUCTURE_OBSTACLE 0x00008F00 +#define STRUCTURE_WALLSTUFF 0x00CF0000 +#define STRUCTURE_BLOCKSMOVES 0x00208F00 +#define STRUCTURE_TYPE_DEFINED 0x8FEF8F00 +#define STRUCTURE_ROOF 0x07000000 + +#define TILE_ON_ROOF 0x01 +#define TILE_PASSABLE 0x02 + +typedef struct TAG_STRUCTURE_TILE +{ + INT16 sPosRelToBase; // "single-axis" + INT8 bXPosRelToBase; + INT8 bYPosRelToBase; + PROFILE Shape; // 25 bytes + UINT8 fFlags; + UINT8 ubVehicleHitLocation; + BYTE bUnused[1]; +} DB_STRUCTURE_TILE; // 32 bytes + +#define BASE_TILE 0 + +#define NO_PARTNER_STRUCTURE 0 + +typedef struct TAG_DB_STRUCTURE +{ + UINT8 ubArmour; + UINT8 ubHitPoints; + UINT8 ubDensity; + UINT8 ubNumberOfTiles; + UINT32 fFlags; + UINT16 usStructureNumber; + UINT8 ubWallOrientation; + INT8 bDestructionPartner; // >0 = debris number (bDP - 1), <0 = partner graphic + INT8 bPartnerDelta; // opened/closed version, etc... 0 for unused + INT8 bZTileOffsetX; + INT8 bZTileOffsetY; + BYTE bUnused[1]; +} DB_STRUCTURE; // 16 bytes + +typedef struct TAG_DB_STRUCTURE_REF +{ + DB_STRUCTURE * pDBStructure; + DB_STRUCTURE_TILE ** ppTile; // dynamic array +} DB_STRUCTURE_REF; // 8 bytes + +//dnl ch46 031009 +typedef struct TAG_STRUCTURE +{ + struct TAG_STRUCTURE* pPrev; + struct TAG_STRUCTURE* pNext; + DB_STRUCTURE_REF* pDBStructureRef; + PROFILE* pShape; + UINT32 fFlags;// need to have something to indicate base tile/not + INT32 sGridNo; + union + { + struct + { + UINT8 ubHitPoints; + UINT8 ubLockStrength; + }; + INT32 sBaseGridNo; + }; + UINT16 usStructureID; + INT16 sCubeOffset;// height of bottom of object in profile "cubes" + UINT8 ubWallOrientation; + UINT8 ubVehicleHitLocation; + UINT8 ubStructureHeight;// if 0, then unset; otherwise stores height of structure when last calculated + UINT8 ubUnused; +}STRUCTURE;// 36 bytes + +typedef struct TAG_STRUCTURE_FILE_REF +{ + struct TAG_STRUCTURE_FILE_REF * pPrev; + struct TAG_STRUCTURE_FILE_REF * pNext; + AuxObjectData * pAuxData; + RelTileLoc * pTileLocData; + UINT8 * pubStructureData; + DB_STRUCTURE_REF * pDBStructureRef; // dynamic array + UINT16 usNumberOfStructures; + UINT16 usNumberOfStructuresStored; +} STRUCTURE_FILE_REF; // 24 bytes + +// IMPORTANT THING TO REMEMBER +// +// Although the number of structures and images about which information +// may be stored in a file, the two are stored very differently. +// +// The structure data stored amounts to a sparse array, with no data +// saved for any structures that are not defined. +// +// For image information, however, an array is stored with every entry +// filled regardless of whether there is non-zero data defined for +// that graphic! +typedef struct TAG_STRUCTURE_FILE_HEADER +{ + CHAR8 szId[4]; + union + { + //struct + //{ + UINT16 usNumberOfStructures; + //}; + //struct + //{ + UINT16 usNumberOfImages; + //}; + }; + UINT16 usNumberOfStructuresStored; + UINT16 usStructureDataSize; + UINT8 fFlags; + UINT8 bUnused[3]; + UINT16 usNumberOfImageTileLocsStored; +} STRUCTURE_FILE_HEADER; // 16 bytes + +// "J2SD" = Jagged 2 Structure Data +#define STRUCTURE_FILE_ID "J2SD" +#define STRUCTURE_FILE_ID_LEN 4 + +#define STRUCTURE_SCRIPT_FILE_EXTENSION "JSS" +#define STRUCTURE_FILE_EXTENSION "JSD" + +#define STRUCTURE_FILE_CONTAINS_AUXIMAGEDATA 0x01 +#define STRUCTURE_FILE_CONTAINS_STRUCTUREDATA 0x02 + +#endif \ No newline at end of file diff --git a/ext/export/src/ja2/Types.h b/ext/export/src/ja2/Types.h new file mode 100644 index 000000000..b6e9ba281 --- /dev/null +++ b/ext/export/src/ja2/Types.h @@ -0,0 +1,103 @@ +#ifndef __TYPES_ +#define __TYPES_ + +#include // for wide-character strings + +// *** SIR-TECH TYPE DEFINITIONS *** + +// These two types are defined by VC6 and were causing redefinition +// problems, but JA2 is compiled with VC5 + +// HEY WIZARDRY DUDES, JA2 ISN'T THE ONLY PROGRAM WE COMPILE! :-) + +typedef unsigned int UINT32; +typedef signed int INT32; + +// integers +typedef unsigned char UINT8; +typedef signed char INT8; +typedef unsigned short UINT16; +typedef signed short INT16; +// floats +typedef float FLOAT; +typedef double DOUBLE; +// strings +typedef char CHAR8; +typedef wchar_t CHAR16; +typedef CHAR8 * STR; +typedef CHAR8 * STR8; +typedef CHAR16 * STR16; +// flags (individual bits used) +typedef unsigned char FLAGS8; +typedef unsigned short FLAGS16; +typedef unsigned long FLAGS32; +// other +typedef unsigned char BOOLEAN; +typedef void * PTR; +typedef unsigned short HNDL; +typedef UINT8 BYTE; +typedef CHAR8 STRING512[512]; +typedef UINT32 HWFILE; + +#define SGPFILENAME_LEN 100 +typedef CHAR8 SGPFILENAME[SGPFILENAME_LEN]; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define BAD_INDEX -1 + +#define NULL_HANDLE 65535 + +#define PI 3.1415926 + + +#ifndef NULL +#define NULL 0 +#endif + +typedef struct +{ + INT32 iLeft; + INT32 iTop; + INT32 iRight; + INT32 iBottom; + +} SGPRect; + +typedef struct +{ + INT32 iX; + INT32 iY; + +} SGPPoint; + +typedef struct +{ + INT32 Min; + INT32 Max; + +} SGPRange; + + +typedef FLOAT VECTOR2[2]; // 2d vector (2x1 matrix) +typedef FLOAT VECTOR3[3]; // 3d vector (3x1 matrix) +typedef FLOAT VECTOR4[4]; // 4d vector (4x1 matrix) + +typedef INT32 IVECTOR2[2]; // 2d vector (2x1 matrix) +typedef INT32 IVECTOR3[3]; // 3d vector (3x1 matrix) +typedef INT32 IVECTOR4[4]; // 4d vector (4x1 matrix) + +typedef VECTOR3 MATRIX3[3]; // 3x3 matrix +typedef VECTOR4 MATRIX4[4]; // 4x4 matrix + +//typedef VECTOR3 ANGLE; // angle return array //lal removed +typedef VECTOR4 COLOR; // rgba color array + + +#endif \ No newline at end of file diff --git a/ext/export/src/ja2/XMLWriter.cpp b/ext/export/src/ja2/XMLWriter.cpp new file mode 100644 index 000000000..01ff6f0c3 --- /dev/null +++ b/ext/export/src/ja2/XMLWriter.cpp @@ -0,0 +1,175 @@ +#include "XMLWriter.h" + +#include +#include + +#include + +void XMLWriter::addValue(vfs::String const& key) +{ + m_ssBuffer << indent() << "<" << key.utf8(); + insertAttributesIntoBuffer(); + m_ssBuffer << " />\n"; +} + +void XMLWriter::addComment(vfs::String const& comment) +{ + m_ssBuffer << indent() << "\n"; +} + +void XMLWriter::addFlag(UINT32 const& flags, UINT32 const& flag, vfs::String strFlag) +{ + if( ( flags & flag) == flag ) + { + this->addValue(strFlag); + } +} + +void XMLWriter::openNode(vfs::String const& key) +{ + std::string utf8key = key.utf8(); + m_ssBuffer << indent() << "<" << utf8key; + insertAttributesIntoBuffer(); + m_ssBuffer << ">\n"; + m_iIndentLevel += 1; + m_stOpenNodes.push(utf8key); +} + +bool XMLWriter::closeNode() +{ + if(m_iIndentLevel < 1) + { + // there is nothing to close + return false; + } + if(m_stOpenNodes.empty()) + { + return false; + } + m_iIndentLevel -= 1; + m_ssBuffer << indent() << "\n"; + m_stOpenNodes.pop(); + return true; +} + +bool XMLWriter::writeToFile(vfs::Path const& sFileName) +{ + try + { + vfs::COpenWriteFile file(sFileName,true,true); + return writeToFile( &file.file() ); + } + catch(vfs::Exception& ex) + { + std::wcout << ex.getExceptionString() << std::endl; + vfs::CFile file(sFileName); + if(file.openWrite(true,true)) + { + return writeToFile(vfs::tWritableFile::cast(&file)); + } + } + return false; +} + +bool XMLWriter::writeToFile(vfs::tWritableFile* pFile) +{ + try + { + vfs::COpenWriteFile file(pFile); + std::string &str = m_ssBuffer.str(); + pFile->write(str.c_str(), str.length() * sizeof(std::string::value_type)); + return true; + } + catch(vfs::Exception& ex) + { + std::wcout << ex.getLastEntryString() << std::endl; + return false; + } +} + +std::string XMLWriter::indent() +{ + std::string indent_string; + for(int i=0; i < m_iIndentLevel; ++i) + { + indent_string += "\t"; + } + return indent_string; +} + +void XMLWriter::insertAttributesIntoBuffer() +{ + if(!m_stNextValAttributes.empty()) + { + std::vector::iterator it = m_stNextValAttributes.begin(); + for(; it != m_stNextValAttributes.end(); ++it) + { + m_ssBuffer << " " << it->first << "=\"" << it->second << "\""; + } + } + m_stNextValAttributes.clear(); +} + +std::string XMLWriter::handleSpecialCharacters(std::string const& str) +{ + std::stringstream ss; + unsigned int current = 0, old = 0; + while( current < str.length() ) + { + char const& c = str.at(current); + if( c == '&' ) + { + ss << str.substr(old, current-old) << "&"; + old = current + 1; + } + else if( c == '<' ) + { + ss << str.substr(old, current-old) << "<"; + old = current + 1; + } + else if( c == '>' ) + { + ss << str.substr(old, current-old) << ">"; + old = current + 1; + } + else if( c == '\"' ) + { + ss << str.substr(old, current-old) << """; + old = current + 1; + } + else if( c == '\'' ) + { + ss << str.substr(old, current-old) << "'"; + old = current + 1; + } + current++; + } + if(old) + { + ss << str.substr(old, current-old); + return ss.str(); + } + return str; +} + +void testMXLWriter() +{ + //XMLWriter xmlw; + XMLWriter xmlw; + //xmlw.openNode(L"root"); + xmlw.openNode("root"); + xmlw.addAttributeToNextValue("attr1",10); + xmlw.addAttributeToNextValue("attr2","string"); + //xmlw.AddValue(L"val1",10); + xmlw.addValue("val1",10); + + xmlw.addAttributeToNextValue("node_attr",17); + xmlw.addComment("bbb -->\n comment