From 124f869faae3a0f75a3825e6a8e195c17f3c626a Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Thu, 16 Oct 2014 23:34:20 +0400 Subject: initial for idea --- .gitignore | 11 + .idea/.name | 1 + .idea/compiler.xml | 23 + .idea/copyright/profiles_settings.xml | 3 + .idea/encodings.xml | 5 + .idea/gradle.xml | 18 + .idea/misc.xml | 23 + .idea/modules.xml | 10 + .idea/scopes/scope_settings.xml | 5 + .idea/vcs.xml | 7 + Tiny-Comics-Reader.iml | 19 + build.gradle | 15 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 +++ gradlew.bat | 90 ++ org.fox.ttcomics/build.gradle | 25 + org.fox.ttcomics/org.fox.ttcomics.iml | 88 ++ org.fox.ttcomics/src/main/AndroidManifest.xml | 54 + .../src/main/java/com/github/junrar/Archive.java | 583 ++++++++++ .../src/main/java/com/github/junrar/MVTest.java | 56 + .../main/java/com/github/junrar/UnrarCallback.java | 21 + .../src/main/java/com/github/junrar/Volume.java | 44 + .../main/java/com/github/junrar/VolumeManager.java | 28 + .../main/java/com/github/junrar/crc/RarCRC.java | 145 +++ .../java/com/github/junrar/crypt/Rijndael.java | 27 + .../com/github/junrar/exception/RarException.java | 73 ++ .../java/com/github/junrar/impl/FileVolume.java | 65 ++ .../com/github/junrar/impl/FileVolumeManager.java | 54 + .../java/com/github/junrar/io/IReadOnlyAccess.java | 61 + .../junrar/io/InputStreamReadOnlyAccessFile.java | 59 + .../com/github/junrar/io/RandomAccessStream.java | 203 ++++ .../src/main/java/com/github/junrar/io/Raw.java | 305 +++++ .../github/junrar/io/ReadOnlyAccessByteArray.java | 90 ++ .../com/github/junrar/io/ReadOnlyAccessFile.java | 55 + .../junrar/io/ReadOnlyAccessInputStream.java | 81 ++ .../java/com/github/junrar/rarfile/AVHeader.java | 66 ++ .../java/com/github/junrar/rarfile/BaseBlock.java | 179 +++ .../com/github/junrar/rarfile/BlockHeader.java | 70 ++ .../com/github/junrar/rarfile/CommentHeader.java | 70 ++ .../java/com/github/junrar/rarfile/EAHeader.java | 90 ++ .../com/github/junrar/rarfile/EndArcHeader.java | 63 + .../java/com/github/junrar/rarfile/FileHeader.java | 421 +++++++ .../com/github/junrar/rarfile/FileNameDecoder.java | 76 ++ .../java/com/github/junrar/rarfile/HostSystem.java | 72 ++ .../com/github/junrar/rarfile/MacInfoHeader.java | 81 ++ .../java/com/github/junrar/rarfile/MainHeader.java | 141 +++ .../java/com/github/junrar/rarfile/MarkHeader.java | 84 ++ .../github/junrar/rarfile/NewSubHeaderType.java | 89 ++ .../com/github/junrar/rarfile/ProtectHeader.java | 71 ++ .../java/com/github/junrar/rarfile/SignHeader.java | 60 + .../com/github/junrar/rarfile/SubBlockHeader.java | 70 ++ .../github/junrar/rarfile/SubBlockHeaderType.java | 77 ++ .../github/junrar/rarfile/UnixOwnersHeader.java | 93 ++ .../com/github/junrar/rarfile/UnrarHeadertype.java | 164 +++ .../java/com/github/junrar/unpack/ComprDataIO.java | 362 ++++++ .../main/java/com/github/junrar/unpack/Unpack.java | 1051 +++++++++++++++++ .../java/com/github/junrar/unpack/Unpack15.java | 620 ++++++++++ .../java/com/github/junrar/unpack/Unpack20.java | 597 ++++++++++ .../com/github/junrar/unpack/UnpackFilter.java | 94 ++ .../junrar/unpack/decode/AudioVariables.java | 144 +++ .../com/github/junrar/unpack/decode/BitDecode.java | 35 + .../com/github/junrar/unpack/decode/CodeType.java | 29 + .../com/github/junrar/unpack/decode/Compress.java | 45 + .../com/github/junrar/unpack/decode/Decode.java | 81 ++ .../github/junrar/unpack/decode/DistDecode.java | 37 + .../github/junrar/unpack/decode/FilterType.java | 30 + .../com/github/junrar/unpack/decode/LitDecode.java | 36 + .../github/junrar/unpack/decode/LowDistDecode.java | 37 + .../github/junrar/unpack/decode/MultDecode.java | 37 + .../com/github/junrar/unpack/decode/RepDecode.java | 36 + .../github/junrar/unpack/ppm/AnalyzeHeapDump.java | 94 ++ .../com/github/junrar/unpack/ppm/BlockTypes.java | 58 + .../com/github/junrar/unpack/ppm/FreqData.java | 87 ++ .../com/github/junrar/unpack/ppm/ModelPPM.java | 696 +++++++++++ .../com/github/junrar/unpack/ppm/PPMContext.java | 477 ++++++++ .../java/com/github/junrar/unpack/ppm/Pointer.java | 59 + .../com/github/junrar/unpack/ppm/RangeCoder.java | 177 +++ .../com/github/junrar/unpack/ppm/RarMemBlock.java | 139 +++ .../java/com/github/junrar/unpack/ppm/RarNode.java | 69 ++ .../com/github/junrar/unpack/ppm/SEE2Context.java | 102 ++ .../java/com/github/junrar/unpack/ppm/State.java | 119 ++ .../com/github/junrar/unpack/ppm/StateRef.java | 92 ++ .../com/github/junrar/unpack/ppm/SubAllocator.java | 427 +++++++ .../java/com/github/junrar/unpack/vm/BitInput.java | 108 ++ .../java/com/github/junrar/unpack/vm/RarVM.java | 1221 ++++++++++++++++++++ .../com/github/junrar/unpack/vm/VMCmdFlags.java | 81 ++ .../com/github/junrar/unpack/vm/VMCommands.java | 226 ++++ .../java/com/github/junrar/unpack/vm/VMFlags.java | 79 ++ .../java/com/github/junrar/unpack/vm/VMOpType.java | 66 ++ .../github/junrar/unpack/vm/VMPreparedCommand.java | 57 + .../github/junrar/unpack/vm/VMPreparedOperand.java | 58 + .../github/junrar/unpack/vm/VMPreparedProgram.java | 127 ++ .../unpack/vm/VMStandardFilterSignature.java | 64 + .../github/junrar/unpack/vm/VMStandardFilters.java | 79 ++ .../com/github/junrar/unsigned/UnsignedByte.java | 68 ++ .../github/junrar/unsigned/UnsignedInteger.java | 29 + .../com/github/junrar/unsigned/UnsignedLong.java | 29 + .../com/github/junrar/unsigned/UnsignedShort.java | 29 + .../java/com/github/junrar/util/VolumeHelper.java | 101 ++ .../android/library/imagezoom/ImageViewTouch.java | 268 +++++ .../library/imagezoom/ImageViewTouchBase.java | 509 ++++++++ .../android/library/imagezoom/easing/Cubic.java | 20 + .../android/library/imagezoom/easing/Easing.java | 10 + .../imagezoom/graphics/FastBitmapDrawable.java | 84 ++ .../imagezoom/graphics/IBitmapDrawable.java | 14 + .../library/imagezoom/utils/IDisposable.java | 6 + .../java/org/fox/ttcomics/CbrComicArchive.java | 69 ++ .../java/org/fox/ttcomics/CbzComicArchive.java | 50 + .../main/java/org/fox/ttcomics/ComicArchive.java | 12 + .../main/java/org/fox/ttcomics/ComicFragment.java | 329 ++++++ .../java/org/fox/ttcomics/ComicListFragment.java | 529 +++++++++ .../src/main/java/org/fox/ttcomics/ComicPager.java | 166 +++ .../main/java/org/fox/ttcomics/CommonActivity.java | 653 +++++++++++ .../main/java/org/fox/ttcomics/DatabaseHelper.java | 68 ++ .../java/org/fox/ttcomics/DirectoryPicker.java | 169 +++ .../main/java/org/fox/ttcomics/MainActivity.java | 253 ++++ .../java/org/fox/ttcomics/PreferencesActivity.java | 124 ++ .../src/main/java/org/fox/ttcomics/SyncClient.java | 159 +++ .../java/org/fox/ttcomics/ViewComicActivity.java | 391 +++++++ .../src/main/java/org/fox/ttcomics/ViewPager.java | 38 + org.fox.ttcomics/src/main/res/anim/appear.xml | 9 + .../src/main/res/anim/layout_comics.xml | 5 + .../src/main/res/drawable-hdpi/badimage.png | Bin 0 -> 14350 bytes .../src/main/res/drawable-hdpi/ic_action_good.png | Bin 0 -> 457 bytes .../main/res/drawable-hdpi/ic_action_overflow.png | Bin 0 -> 225 bytes .../src/main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 7867 bytes .../main/res/drawable-hdpi/ic_refresh_light.png | Bin 0 -> 3138 bytes .../src/main/res/drawable-hdpi/ic_search_light.png | Bin 0 -> 1764 bytes .../src/main/res/drawable-hdpi/ic_settings.png | Bin 0 -> 1540 bytes .../src/main/res/drawable-hdpi/ic_share_light.png | Bin 0 -> 1606 bytes .../src/main/res/drawable-xhdpi/ic_action_good.png | Bin 0 -> 585 bytes .../main/res/drawable-xhdpi/ic_action_overflow.png | Bin 0 -> 280 bytes .../src/main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 11597 bytes .../main/res/drawable-xhdpi/ic_refresh_light.png | Bin 0 -> 3219 bytes .../main/res/drawable-xhdpi/ic_search_light.png | Bin 0 -> 2127 bytes .../src/main/res/drawable-xhdpi/ic_settings.png | Bin 0 -> 1641 bytes .../src/main/res/drawable-xhdpi/ic_share_light.png | Bin 0 -> 1780 bytes .../src/main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 13687 bytes .../src/main/res/drawable/comic_tile.xml | 26 + .../src/main/res/drawable/comic_tile_folder.xml | 26 + .../src/main/res/drawable/s_badimage.svg | 88 ++ .../src/main/res/drawable/s_launcher.svg | 204 ++++ .../main/res/layout-land/fragment_comics_list.xml | 29 + .../src/main/res/layout-sw600dp/activity_main.xml | 22 + .../res/layout-sw600dp/activity_view_comic.xml | 23 + .../main/res/layout-sw600dp/comics_grid_row.xml | 73 ++ .../res/layout-sw600dp/fragment_comics_list.xml | 35 + .../src/main/res/layout/activity_main.xml | 15 + .../src/main/res/layout/activity_view_comic.xml | 16 + .../src/main/res/layout/chooser_list.xml | 33 + .../src/main/res/layout/comics_grid_row.xml | 73 ++ .../src/main/res/layout/comics_list_row.xml | 73 ++ .../src/main/res/layout/dialog_location.xml | 14 + .../src/main/res/layout/dialog_location_compat.xml | 23 + .../src/main/res/layout/fragment_comic.xml | 21 + .../src/main/res/layout/fragment_comics_list.xml | 36 + .../src/main/res/layout/fragment_comics_pager.xml | 9 + org.fox.ttcomics/src/main/res/layout/list_item.xml | 7 + .../src/main/res/menu/activity_main.xml | 19 + .../src/main/res/menu/activity_view_comic.xml | 26 + .../src/main/res/menu/comic_archive_context.xml | 8 + .../src/main/res/values-large/dimens.xml | 7 + org.fox.ttcomics/src/main/res/values-v19/style.xml | 31 + org.fox.ttcomics/src/main/res/values/attrs.xml | 5 + org.fox.ttcomics/src/main/res/values/dimens.xml | 7 + org.fox.ttcomics/src/main/res/values/strings.xml | 67 ++ org.fox.ttcomics/src/main/res/values/style.xml | 15 + org.fox.ttcomics/src/main/res/xml/preferences.xml | 63 + settings.gradle | 1 + 170 files changed, 17873 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.name create mode 100644 .idea/compiler.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/scopes/scope_settings.xml create mode 100644 .idea/vcs.xml create mode 100644 Tiny-Comics-Reader.iml create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 org.fox.ttcomics/build.gradle create mode 100644 org.fox.ttcomics/org.fox.ttcomics.iml create mode 100644 org.fox.ttcomics/src/main/AndroidManifest.xml create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/Archive.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/MVTest.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/UnrarCallback.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/Volume.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/VolumeManager.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/crc/RarCRC.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/crypt/Rijndael.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/exception/RarException.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/impl/FileVolume.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/impl/FileVolumeManager.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/io/IReadOnlyAccess.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/io/InputStreamReadOnlyAccessFile.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/io/RandomAccessStream.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/io/Raw.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessByteArray.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessFile.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessInputStream.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/AVHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/BaseBlock.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/BlockHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/CommentHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/EAHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/EndArcHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/FileHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/FileNameDecoder.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/HostSystem.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MacInfoHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MainHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MarkHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/NewSubHeaderType.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/ProtectHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SignHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SubBlockHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SubBlockHeaderType.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/UnixOwnersHeader.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/UnrarHeadertype.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ComprDataIO.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack15.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack20.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/UnpackFilter.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/AudioVariables.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/BitDecode.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/CodeType.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/Compress.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/Decode.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/DistDecode.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/FilterType.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/LitDecode.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/LowDistDecode.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/MultDecode.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/RepDecode.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/AnalyzeHeapDump.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/BlockTypes.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/FreqData.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/ModelPPM.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/PPMContext.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/Pointer.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RangeCoder.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarMemBlock.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarNode.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SEE2Context.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/State.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/StateRef.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SubAllocator.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/BitInput.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/RarVM.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMCmdFlags.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMCommands.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMFlags.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMOpType.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedCommand.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedOperand.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedProgram.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMStandardFilterSignature.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMStandardFilters.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedByte.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedInteger.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedLong.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedShort.java create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/util/VolumeHelper.java create mode 100644 org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/ImageViewTouch.java create mode 100644 org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/ImageViewTouchBase.java create mode 100644 org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/easing/Cubic.java create mode 100644 org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/easing/Easing.java create mode 100644 org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/graphics/FastBitmapDrawable.java create mode 100644 org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/graphics/IBitmapDrawable.java create mode 100644 org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/utils/IDisposable.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/CbrComicArchive.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/CbzComicArchive.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicArchive.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicFragment.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicListFragment.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicPager.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/CommonActivity.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/DatabaseHelper.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/DirectoryPicker.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/MainActivity.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/PreferencesActivity.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/SyncClient.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/ViewComicActivity.java create mode 100644 org.fox.ttcomics/src/main/java/org/fox/ttcomics/ViewPager.java create mode 100644 org.fox.ttcomics/src/main/res/anim/appear.xml create mode 100644 org.fox.ttcomics/src/main/res/anim/layout_comics.xml create mode 100644 org.fox.ttcomics/src/main/res/drawable-hdpi/badimage.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-hdpi/ic_action_good.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-hdpi/ic_action_overflow.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-hdpi/ic_refresh_light.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-hdpi/ic_search_light.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-hdpi/ic_settings.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-hdpi/ic_share_light.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_action_good.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_action_overflow.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_refresh_light.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_search_light.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_settings.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_share_light.png create mode 100644 org.fox.ttcomics/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 org.fox.ttcomics/src/main/res/drawable/comic_tile.xml create mode 100644 org.fox.ttcomics/src/main/res/drawable/comic_tile_folder.xml create mode 100644 org.fox.ttcomics/src/main/res/drawable/s_badimage.svg create mode 100644 org.fox.ttcomics/src/main/res/drawable/s_launcher.svg create mode 100644 org.fox.ttcomics/src/main/res/layout-land/fragment_comics_list.xml create mode 100644 org.fox.ttcomics/src/main/res/layout-sw600dp/activity_main.xml create mode 100644 org.fox.ttcomics/src/main/res/layout-sw600dp/activity_view_comic.xml create mode 100644 org.fox.ttcomics/src/main/res/layout-sw600dp/comics_grid_row.xml create mode 100644 org.fox.ttcomics/src/main/res/layout-sw600dp/fragment_comics_list.xml create mode 100644 org.fox.ttcomics/src/main/res/layout/activity_main.xml create mode 100644 org.fox.ttcomics/src/main/res/layout/activity_view_comic.xml create mode 100644 org.fox.ttcomics/src/main/res/layout/chooser_list.xml create mode 100644 org.fox.ttcomics/src/main/res/layout/comics_grid_row.xml create mode 100644 org.fox.ttcomics/src/main/res/layout/comics_list_row.xml create mode 100644 org.fox.ttcomics/src/main/res/layout/dialog_location.xml create mode 100644 org.fox.ttcomics/src/main/res/layout/dialog_location_compat.xml create mode 100644 org.fox.ttcomics/src/main/res/layout/fragment_comic.xml create mode 100644 org.fox.ttcomics/src/main/res/layout/fragment_comics_list.xml create mode 100644 org.fox.ttcomics/src/main/res/layout/fragment_comics_pager.xml create mode 100644 org.fox.ttcomics/src/main/res/layout/list_item.xml create mode 100644 org.fox.ttcomics/src/main/res/menu/activity_main.xml create mode 100644 org.fox.ttcomics/src/main/res/menu/activity_view_comic.xml create mode 100644 org.fox.ttcomics/src/main/res/menu/comic_archive_context.xml create mode 100644 org.fox.ttcomics/src/main/res/values-large/dimens.xml create mode 100644 org.fox.ttcomics/src/main/res/values-v19/style.xml create mode 100644 org.fox.ttcomics/src/main/res/values/attrs.xml create mode 100644 org.fox.ttcomics/src/main/res/values/dimens.xml create mode 100644 org.fox.ttcomics/src/main/res/values/strings.xml create mode 100644 org.fox.ttcomics/src/main/res/values/style.xml create mode 100644 org.fox.ttcomics/src/main/res/xml/preferences.xml create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..906aa82 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +bin/ +gen/ +.gradle/ +build/ +local.properties +import-summary.txt +Thumbs.db +.idea/workspace.xml +.idea/tasks.xml +.idea/datasources.xml +.idea/dataSources.ids diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..0e0a20e --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Tiny-Comics-Reader \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..28bb10a --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..c7d1c5a --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..7c62b52 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..8842032 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..38cc86c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,23 @@ + + + + + + + + + + Android API 19 Platform + + + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..93796ff --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..0d5175c --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..ab55cf1 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Tiny-Comics-Reader.iml b/Tiny-Comics-Reader.iml new file mode 100644 index 0000000..8d49284 --- /dev/null +++ b/Tiny-Comics-Reader.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..3ef601d --- /dev/null +++ b/build.gradle @@ -0,0 +1,15 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:0.12.2' + } +} + +allprojects { + repositories { + jcenter() + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..8c0fb64 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..1e61d1f --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Apr 10 15:27:10 PDT 2013 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..91a7e26 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/org.fox.ttcomics/build.gradle b/org.fox.ttcomics/build.gradle new file mode 100644 index 0000000..ad3ab44 --- /dev/null +++ b/org.fox.ttcomics/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 19 + buildToolsVersion "20.0.0" + + defaultConfig { + applicationId "org.fox.ttcomics" + minSdkVersion 8 + targetSdkVersion 19 + } + + buildTypes { + release { + runProguard false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +dependencies { + compile 'com.readystatesoftware.systembartint:systembartint:1.0.3' + compile 'com.android.support:support-v4:19.1.0' + compile 'com.android.support:appcompat-v7:18.0.0' +} diff --git a/org.fox.ttcomics/org.fox.ttcomics.iml b/org.fox.ttcomics/org.fox.ttcomics.iml new file mode 100644 index 0000000..333a3cd --- /dev/null +++ b/org.fox.ttcomics/org.fox.ttcomics.iml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.fox.ttcomics/src/main/AndroidManifest.xml b/org.fox.ttcomics/src/main/AndroidManifest.xml new file mode 100644 index 0000000..bb68e84 --- /dev/null +++ b/org.fox.ttcomics/src/main/AndroidManifest.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/Archive.java b/org.fox.ttcomics/src/main/java/com/github/junrar/Archive.java new file mode 100644 index 0000000..23ca39b --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/Archive.java @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 22.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression + * algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.github.junrar.exception.RarException; +import com.github.junrar.exception.RarException.RarExceptionType; +import com.github.junrar.impl.FileVolumeManager; +import com.github.junrar.io.IReadOnlyAccess; +import com.github.junrar.rarfile.AVHeader; +import com.github.junrar.rarfile.BaseBlock; +import com.github.junrar.rarfile.BlockHeader; +import com.github.junrar.rarfile.CommentHeader; +import com.github.junrar.rarfile.EAHeader; +import com.github.junrar.rarfile.EndArcHeader; +import com.github.junrar.rarfile.FileHeader; +import com.github.junrar.rarfile.MacInfoHeader; +import com.github.junrar.rarfile.MainHeader; +import com.github.junrar.rarfile.MarkHeader; +import com.github.junrar.rarfile.ProtectHeader; +import com.github.junrar.rarfile.SignHeader; +import com.github.junrar.rarfile.SubBlockHeader; +import com.github.junrar.rarfile.UnixOwnersHeader; +import com.github.junrar.rarfile.UnrarHeadertype; +import com.github.junrar.unpack.ComprDataIO; +import com.github.junrar.unpack.Unpack; + + +/** + * The Main Rar Class; represents a rar Archive + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class Archive implements Closeable { + private static Logger logger = Logger.getLogger(Archive.class.getName()); + + private IReadOnlyAccess rof; + + private final UnrarCallback unrarCallback; + + private final ComprDataIO dataIO; + + private final List headers = new ArrayList(); + + private MarkHeader markHead = null; + + private MainHeader newMhd = null; + + private Unpack unpack; + + private int currentHeaderIndex; + + /** Size of packed data in current file. */ + private long totalPackedSize = 0L; + + /** Number of bytes of compressed data read from current file. */ + private long totalPackedRead = 0L; + + private VolumeManager volumeManager; + private Volume volume; + + public Archive(VolumeManager volumeManager) throws RarException, + IOException { + this(volumeManager, null); + } + + /** + * create a new archive object using the given {@link VolumeManager} + * + * @param volumeManager + * the the {@link VolumeManager} that will provide volume stream + * data + * @throws RarException + */ + public Archive(VolumeManager volumeManager, UnrarCallback unrarCallback) + throws RarException, IOException { + this.volumeManager = volumeManager; + this.unrarCallback = unrarCallback; + + setVolume(this.volumeManager.nextArchive(this, null)); + dataIO = new ComprDataIO(this); + } + + public Archive(File firstVolume) throws RarException, IOException { + this(new FileVolumeManager(firstVolume), null); + } + + public Archive(File firstVolume, UnrarCallback unrarCallback) + throws RarException, IOException { + this(new FileVolumeManager(firstVolume), unrarCallback); + } + + // public File getFile() { + // return file; + // } + // + // void setFile(File file) throws IOException { + // this.file = file; + // setFile(new ReadOnlyAccessFile(file), file.length()); + // } + + private void setFile(IReadOnlyAccess file, long length) throws IOException { + totalPackedSize = 0L; + totalPackedRead = 0L; + close(); + rof = file; + try { + readHeaders(length); + } catch (Exception e) { + logger.log(Level.WARNING, + "exception in archive constructor maybe file is encrypted " + + "or currupt", e); + // ignore exceptions to allow exraction of working files in + // corrupt archive + } + // Calculate size of packed data + for (BaseBlock block : headers) { + if (block.getHeaderType() == UnrarHeadertype.FileHeader) { + totalPackedSize += ((FileHeader) block).getFullPackSize(); + } + } + if (unrarCallback != null) { + unrarCallback.volumeProgressChanged(totalPackedRead, + totalPackedSize); + } + } + + public void bytesReadRead(int count) { + if (count > 0) { + totalPackedRead += count; + if (unrarCallback != null) { + unrarCallback.volumeProgressChanged(totalPackedRead, + totalPackedSize); + } + } + } + + public IReadOnlyAccess getRof() { + return rof; + } + + /** + * @return returns all file headers of the archive + */ + public List getFileHeaders() { + List list = new ArrayList(); + for (BaseBlock block : headers) { + if (block.getHeaderType().equals(UnrarHeadertype.FileHeader)) { + list.add((FileHeader) block); + } + } + return list; + } + + public FileHeader nextFileHeader() { + int n = headers.size(); + while (currentHeaderIndex < n) { + BaseBlock block = headers.get(currentHeaderIndex++); + if (block.getHeaderType() == UnrarHeadertype.FileHeader) { + return (FileHeader) block; + } + } + return null; + } + + public UnrarCallback getUnrarCallback() { + return unrarCallback; + } + + /** + * + * @return whether the archive is encrypted + */ + public boolean isEncrypted() { + if (newMhd != null) { + return newMhd.isEncrypted(); + } else { + throw new NullPointerException("mainheader is null"); + } + } + + /** + * Read the headers of the archive + * + * @param fileLength + * Length of file. + * @throws RarException + */ + private void readHeaders(long fileLength) throws IOException, RarException { + markHead = null; + newMhd = null; + headers.clear(); + currentHeaderIndex = 0; + int toRead = 0; + + while (true) { + int size = 0; + long newpos = 0; + byte[] baseBlockBuffer = new byte[BaseBlock.BaseBlockSize]; + + long position = rof.getPosition(); + + // Weird, but is trying to read beyond the end of the file + if (position >= fileLength) { + break; + } + + // logger.info("\n--------reading header--------"); + size = rof.readFully(baseBlockBuffer, BaseBlock.BaseBlockSize); + if (size == 0) { + break; + } + BaseBlock block = new BaseBlock(baseBlockBuffer); + + block.setPositionInFile(position); + + switch (block.getHeaderType()) { + + case MarkHeader: + markHead = new MarkHeader(block); + if (!markHead.isSignature()) { + throw new RarException( + RarException.RarExceptionType.badRarArchive); + } + headers.add(markHead); + // markHead.print(); + break; + + case MainHeader: + toRead = block.hasEncryptVersion() ? MainHeader.mainHeaderSizeWithEnc + : MainHeader.mainHeaderSize; + byte[] mainbuff = new byte[toRead]; + rof.readFully(mainbuff, toRead); + MainHeader mainhead = new MainHeader(block, mainbuff); + headers.add(mainhead); + this.newMhd = mainhead; + if (newMhd.isEncrypted()) { + throw new RarException( + RarExceptionType.rarEncryptedException); + } + // mainhead.print(); + break; + + case SignHeader: + toRead = SignHeader.signHeaderSize; + byte[] signBuff = new byte[toRead]; + rof.readFully(signBuff, toRead); + SignHeader signHead = new SignHeader(block, signBuff); + headers.add(signHead); + // logger.info("HeaderType: SignHeader"); + + break; + + case AvHeader: + toRead = AVHeader.avHeaderSize; + byte[] avBuff = new byte[toRead]; + rof.readFully(avBuff, toRead); + AVHeader avHead = new AVHeader(block, avBuff); + headers.add(avHead); + // logger.info("headertype: AVHeader"); + break; + + case CommHeader: + toRead = CommentHeader.commentHeaderSize; + byte[] commBuff = new byte[toRead]; + rof.readFully(commBuff, toRead); + CommentHeader commHead = new CommentHeader(block, commBuff); + headers.add(commHead); + // logger.info("method: "+commHead.getUnpMethod()+"; 0x"+ + // Integer.toHexString(commHead.getUnpMethod())); + newpos = commHead.getPositionInFile() + + commHead.getHeaderSize(); + rof.setPosition(newpos); + + break; + case EndArcHeader: + + toRead = 0; + if (block.hasArchiveDataCRC()) { + toRead += EndArcHeader.endArcArchiveDataCrcSize; + } + if (block.hasVolumeNumber()) { + toRead += EndArcHeader.endArcVolumeNumberSize; + } + EndArcHeader endArcHead; + if (toRead > 0) { + byte[] endArchBuff = new byte[toRead]; + rof.readFully(endArchBuff, toRead); + endArcHead = new EndArcHeader(block, endArchBuff); + // logger.info("HeaderType: endarch\ndatacrc:"+ + // endArcHead.getArchiveDataCRC()); + } else { + // logger.info("HeaderType: endarch - no Data"); + endArcHead = new EndArcHeader(block, null); + } + headers.add(endArcHead); + // logger.info("\n--------end header--------"); + return; + + default: + byte[] blockHeaderBuffer = new byte[BlockHeader.blockHeaderSize]; + rof.readFully(blockHeaderBuffer, BlockHeader.blockHeaderSize); + BlockHeader blockHead = new BlockHeader(block, + blockHeaderBuffer); + + switch (blockHead.getHeaderType()) { + case NewSubHeader: + case FileHeader: + toRead = blockHead.getHeaderSize() + - BlockHeader.BaseBlockSize + - BlockHeader.blockHeaderSize; + byte[] fileHeaderBuffer = new byte[toRead]; + rof.readFully(fileHeaderBuffer, toRead); + + FileHeader fh = new FileHeader(blockHead, fileHeaderBuffer); + headers.add(fh); + newpos = fh.getPositionInFile() + fh.getHeaderSize() + + fh.getFullPackSize(); + rof.setPosition(newpos); + break; + + case ProtectHeader: + toRead = blockHead.getHeaderSize() + - BlockHeader.BaseBlockSize + - BlockHeader.blockHeaderSize; + byte[] protectHeaderBuffer = new byte[toRead]; + rof.readFully(protectHeaderBuffer, toRead); + ProtectHeader ph = new ProtectHeader(blockHead, + protectHeaderBuffer); + + newpos = ph.getPositionInFile() + ph.getHeaderSize() + + ph.getDataSize(); + rof.setPosition(newpos); + break; + + case SubHeader: { + byte[] subHeadbuffer = new byte[SubBlockHeader.SubBlockHeaderSize]; + rof.readFully(subHeadbuffer, + SubBlockHeader.SubBlockHeaderSize); + SubBlockHeader subHead = new SubBlockHeader(blockHead, + subHeadbuffer); + subHead.print(); + switch (subHead.getSubType()) { + case MAC_HEAD: { + byte[] macHeaderbuffer = new byte[MacInfoHeader.MacInfoHeaderSize]; + rof.readFully(macHeaderbuffer, + MacInfoHeader.MacInfoHeaderSize); + MacInfoHeader macHeader = new MacInfoHeader(subHead, + macHeaderbuffer); + macHeader.print(); + headers.add(macHeader); + + break; + } + // TODO implement other subheaders + case BEEA_HEAD: + break; + case EA_HEAD: { + byte[] eaHeaderBuffer = new byte[EAHeader.EAHeaderSize]; + rof.readFully(eaHeaderBuffer, EAHeader.EAHeaderSize); + EAHeader eaHeader = new EAHeader(subHead, + eaHeaderBuffer); + eaHeader.print(); + headers.add(eaHeader); + + break; + } + case NTACL_HEAD: + break; + case STREAM_HEAD: + break; + case UO_HEAD: + toRead = subHead.getHeaderSize(); + toRead -= BaseBlock.BaseBlockSize; + toRead -= BlockHeader.blockHeaderSize; + toRead -= SubBlockHeader.SubBlockHeaderSize; + byte[] uoHeaderBuffer = new byte[toRead]; + rof.readFully(uoHeaderBuffer, toRead); + UnixOwnersHeader uoHeader = new UnixOwnersHeader( + subHead, uoHeaderBuffer); + uoHeader.print(); + headers.add(uoHeader); + break; + default: + break; + } + + break; + } + default: + logger.warning("Unknown Header"); + throw new RarException(RarExceptionType.notRarArchive); + + } + } + // logger.info("\n--------end header--------"); + } + } + + /** + * Extract the file specified by the given header and write it to the + * supplied output stream + * + * @param header + * the header to be extracted + * @param os + * the outputstream + * @throws RarException + */ + public void extractFile(FileHeader hd, OutputStream os) throws RarException { + if (!headers.contains(hd)) { + throw new RarException(RarExceptionType.headerNotInArchive); + } + try { + doExtractFile(hd, os); + } catch (Exception e) { + if (e instanceof RarException) { + throw (RarException) e; + } else { + throw new RarException(e); + } + } + } + + /** + * Returns an {@link InputStream} that will allow to read the file and + * stream it. Please note that this method will create a new Thread and an a + * pair of Pipe streams. + * + * @param header + * the header to be extracted + * @throws RarException + * @throws IOException + * if any IO error occur + */ + public InputStream getInputStream(final FileHeader hd) throws RarException, + IOException { + final PipedInputStream in = new PipedInputStream(32 * 1024); + final PipedOutputStream out = new PipedOutputStream(in); + + // creates a new thread that will write data to the pipe. Data will be + // available in another InputStream, connected to the OutputStream. + new Thread(new Runnable() { + public void run() { + try { + extractFile(hd, out); + } catch (RarException e) { + } finally { + try { + out.close(); + } catch (IOException e) { + } + } + } + }).start(); + + return in; + } + + private void doExtractFile(FileHeader hd, OutputStream os) + throws RarException, IOException { + dataIO.init(os); + dataIO.init(hd); + dataIO.setUnpFileCRC(this.isOldFormat() ? 0 : 0xffFFffFF); + if (unpack == null) { + unpack = new Unpack(dataIO); + } + if (!hd.isSolid()) { + unpack.init(null); + } + unpack.setDestSize(hd.getFullUnpackSize()); + try { + unpack.doUnpack(hd.getUnpVersion(), hd.isSolid()); + // Verify file CRC + hd = dataIO.getSubHeader(); + long actualCRC = hd.isSplitAfter() ? ~dataIO.getPackedCRC() + : ~dataIO.getUnpFileCRC(); + int expectedCRC = hd.getFileCRC(); + if (actualCRC != expectedCRC) { + throw new RarException(RarExceptionType.crcError); + } + // if (!hd.isSplitAfter()) { + // // Verify file CRC + // if(~dataIO.getUnpFileCRC() != hd.getFileCRC()){ + // throw new RarException(RarExceptionType.crcError); + // } + // } + } catch (Exception e) { + unpack.cleanUp(); + if (e instanceof RarException) { + // throw new RarException((RarException)e); + throw (RarException) e; + } else { + throw new RarException(e); + } + } + } + + /** + * @return returns the main header of this archive + */ + public MainHeader getMainHeader() { + return newMhd; + } + + /** + * @return whether the archive is old format + */ + public boolean isOldFormat() { + return markHead.isOldFormat(); + } + + /** Close the underlying compressed file. */ + public void close() throws IOException { + if (rof != null) { + rof.close(); + rof = null; + } + if (unpack != null) { + unpack.cleanUp(); + } + } + + /** + * @return the volumeManager + */ + public VolumeManager getVolumeManager() { + return volumeManager; + } + + /** + * @param volumeManager + * the volumeManager to set + */ + public void setVolumeManager(VolumeManager volumeManager) { + this.volumeManager = volumeManager; + } + + /** + * @return the volume + */ + public Volume getVolume() { + return volume; + } + + /** + * @param volume + * the volume to set + * @throws IOException + */ + public void setVolume(Volume volume) throws IOException { + this.volume = volume; + setFile(volume.getReadOnlyAccess(), volume.getLength()); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/MVTest.java b/org.fox.ttcomics/src/main/java/com/github/junrar/MVTest.java new file mode 100644 index 0000000..36c33c8 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/MVTest.java @@ -0,0 +1,56 @@ +package com.github.junrar; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import com.github.junrar.exception.RarException; +import com.github.junrar.impl.FileVolumeManager; +import com.github.junrar.rarfile.FileHeader; + + +public class MVTest { + + /** + * @param args + */ + public static void main(String[] args) { + String filename = "/home/rogiel/fs/home/ae721273-eade-45e7-8112-d14115ebae56/Village People - Y.M.C.A.mp3.part1.rar"; + File f = new File(filename); + Archive a = null; + try { + a = new Archive(new FileVolumeManager(f)); + } catch (RarException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if (a != null) { + a.getMainHeader().print(); + FileHeader fh = a.nextFileHeader(); + while (fh != null) { + try { + File out = new File("/home/rogiel/fs/test/" + + fh.getFileNameString().trim()); + System.out.println(out.getAbsolutePath()); + FileOutputStream os = new FileOutputStream(out); + a.extractFile(fh, os); + os.close(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (RarException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + fh = a.nextFileHeader(); + } + } + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/UnrarCallback.java b/org.fox.ttcomics/src/main/java/com/github/junrar/UnrarCallback.java new file mode 100644 index 0000000..06bc088 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/UnrarCallback.java @@ -0,0 +1,21 @@ +package com.github.junrar; + + +/** + * + * @author alban + */ +public interface UnrarCallback { + + /** + * Return true if the next volume is ready to be processed, + * false otherwise. + */ + boolean isNextVolumeReady(Volume nextVolume); + + /** + * This method is invoked each time the progress of the current + * volume changes. + */ + void volumeProgressChanged(long current, long total); +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/Volume.java b/org.fox.ttcomics/src/main/java/com/github/junrar/Volume.java new file mode 100644 index 0000000..edc17ae --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/Volume.java @@ -0,0 +1,44 @@ +/* + * This file is part of seedbox . + * + * seedbox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * seedbox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with seedbox. If not, see . + */ +package com.github.junrar; + +import java.io.IOException; + +import com.github.junrar.io.IReadOnlyAccess; + + +/** + * @author Rogiel + * + */ +public interface Volume { + /** + * @return the access + * @throws IOException + */ + IReadOnlyAccess getReadOnlyAccess() throws IOException; + + /** + * @return the data length + */ + long getLength(); + + /** + * @return the archive this volume belongs to + */ + Archive getArchive(); +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/VolumeManager.java b/org.fox.ttcomics/src/main/java/com/github/junrar/VolumeManager.java new file mode 100644 index 0000000..3e96530 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/VolumeManager.java @@ -0,0 +1,28 @@ +/* + * This file is part of seedbox . + * + * seedbox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * seedbox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with seedbox. If not, see . + */ +package com.github.junrar; + +import java.io.IOException; + +/** + * @author Rogiel + * + */ +public interface VolumeManager { + public Volume nextArchive(Archive archive, Volume lastVolume) + throws IOException; +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/crc/RarCRC.java b/org.fox.ttcomics/src/main/java/com/github/junrar/crc/RarCRC.java new file mode 100644 index 0000000..8a778ed --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/crc/RarCRC.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 29.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.crc; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RarCRC { + + private final static int crcTab[]; + static { + crcTab = new int[256]; + for (int i = 0; i < 256; i++) { + int c = i; + for (int j = 0; j < 8; j++){ + if ((c & 1) !=0) { + c >>>= 1; + c ^= 0xEDB88320; + } + else{ + c >>>= 1; + } + } + crcTab[i] = c; + } + } + + private RarCRC() { + } + + public static int checkCrc(int startCrc, byte[] data, int offset, + int count) { + int size = Math.min(data.length-offset,count); + // #if defined(LITTLE_ENDIAN) && defined(PRESENT_INT32) && + // defined(ALLOW_NOT_ALIGNED_INT) + /* + for (int i = 0; (0 < size) && i < data.length - 8 + && ((data[i + 8] & 7) != 0); i++) { + startCrc = crcTab[(short) (startCrc ^ data[i]) & 0x00FF] ^ (startCrc >>> 8); + size--; + } + + for (int i = 0; size >= 8; i += 8) { + startCrc ^= data[i + 0] << 24; + startCrc ^= data[i + 1] << 16; + startCrc ^= data[i + 2] << 8; + startCrc ^= data[i + 3]; + + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + + startCrc ^= data[i + 4] << 24; + startCrc ^= data[i + 5] << 16; + startCrc ^= data[i + 6] << 8; + startCrc ^= data[i + 7]; + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + startCrc = crcTab[(short) startCrc & 0x00FF] ^ (startCrc >>> 8); + size -= 8; + }*/ + + for (int i = 0; i < size; i++) + { +/* + // (byte)(StartCRC^Data[I]) + int pos = 0; // pos=0x00000000 + pos |= startCrc; // pos=ffffffff + + pos ^= data[i]; // data[0]=0x73=115dec --> pos=140 + System.out.println(Integer.toHexString(pos)); + + // Only last 8 bit because CRCtab has length 256 + pos = pos & 0x000000FF; + System.out.println("pos:"+pos); + //startCrc >>>= 8; + + + //StartCRC>>8 + int temp =0; + temp|=startCrc; + temp >>>= 8; + System.out.println("temp:"+Integer.toHexString(temp)); + + + startCrc = (crcTab[pos]^temp); + System.out.println("--"+Integer.toHexString(startCrc));*/ + + startCrc=(crcTab[((int)((int)startCrc ^ + (int)data[offset+i]))&0xff]^(startCrc>>>8)); + + //System.out.println(Integer.toHexString(startCrc)); + + // Original code: + //StartCRC=CRCTab[(byte)(StartCRC^Data[I])]^(StartCRC>>8); + } + return (startCrc); + } + + public static short checkOldCrc(short startCrc, byte[] data, int count) { + int n = Math.min(data.length, count); + for (int i = 0; i < n; i++) { + startCrc = (short) ((short) (startCrc + (short) (data[i]&0x00ff)) & -1); + startCrc = (short) (((startCrc << 1) | (startCrc >>> 15)) & -1); + } + return (startCrc); + } + +// public static void main(String[] args) +// { +// RarCRC rc = new RarCRC(); +// //byte[] data = { 0x72, 0x21, 0x1A, 0x07, 0x00}; +// +// byte[] data = {0x73 ,0x00 ,0x00 ,0x0D ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00}; +// +// int crc = 0x90CF; +// +// +// int result = rc.checkCrc(0xFFFFffff, data,0,data.length); +// System.out.println("3: "+Integer.toHexString(~result&0xffff)); +// +// } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/crypt/Rijndael.java b/org.fox.ttcomics/src/main/java/com/github/junrar/crypt/Rijndael.java new file mode 100644 index 0000000..a1cf7c7 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/crypt/Rijndael.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.crypt; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class Rijndael { + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/exception/RarException.java b/org.fox.ttcomics/src/main/java/com/github/junrar/exception/RarException.java new file mode 100644 index 0000000..a0b969f --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/exception/RarException.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 30.07.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.exception; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RarException extends Exception +{ + private static final long serialVersionUID = 1L; + private RarExceptionType type; + + public RarException(Exception e){ + super(RarExceptionType.unkownError.name(),e); + this.type = RarExceptionType.unkownError; + } + + public RarException(RarException e) + { + + super(e.getMessage(),e); + this.type = e.getType(); + } + + public RarException(RarExceptionType type){ + super(type.name()); + this.type = type; + } + + + + public enum RarExceptionType{ + notImplementedYet, + crcError, + notRarArchive, + badRarArchive, + unkownError, + headerNotInArchive, + wrongHeaderType, + ioError, + rarEncryptedException ; + } + + + + public RarExceptionType getType() + { + return type; + } + + public void setType(RarExceptionType type) + { + this.type = type; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/impl/FileVolume.java b/org.fox.ttcomics/src/main/java/com/github/junrar/impl/FileVolume.java new file mode 100644 index 0000000..eba4da9 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/impl/FileVolume.java @@ -0,0 +1,65 @@ +/* + * This file is part of seedbox . + * + * seedbox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * seedbox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with seedbox. If not, see . + */ +package com.github.junrar.impl; + +import java.io.File; +import java.io.IOException; + +import com.github.junrar.Archive; +import com.github.junrar.Volume; +import com.github.junrar.io.IReadOnlyAccess; +import com.github.junrar.io.ReadOnlyAccessFile; + + +/** + * @author Rogiel + * + */ +public class FileVolume implements Volume { + private final Archive archive; + private final File file; + + /** + * @param file + */ + public FileVolume(Archive archive, File file) { + this.archive = archive; + this.file = file; + } + + @Override + public IReadOnlyAccess getReadOnlyAccess() throws IOException { + return new ReadOnlyAccessFile(file); + } + + @Override + public long getLength() { + return file.length(); + } + + @Override + public Archive getArchive() { + return archive; + } + + /** + * @return the file + */ + public File getFile() { + return file; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/impl/FileVolumeManager.java b/org.fox.ttcomics/src/main/java/com/github/junrar/impl/FileVolumeManager.java new file mode 100644 index 0000000..3552248 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/impl/FileVolumeManager.java @@ -0,0 +1,54 @@ +/* + * This file is part of seedbox . + * + * seedbox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * seedbox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with seedbox. If not, see . + */ +package com.github.junrar.impl; + +import java.io.File; +import java.io.IOException; + +import com.github.junrar.Archive; +import com.github.junrar.Volume; +import com.github.junrar.VolumeManager; +import com.github.junrar.util.VolumeHelper; + + +/** + * @author Rogiel + * + */ +public class FileVolumeManager implements VolumeManager { + private final File firstVolume; + + public FileVolumeManager(File firstVolume) { + this.firstVolume = firstVolume; + } + + @Override + public Volume nextArchive(Archive archive, Volume last) + throws IOException { + if (last == null) + return new FileVolume(archive, firstVolume); + + FileVolume lastFileVolume = (FileVolume) last; + boolean oldNumbering = !archive.getMainHeader().isNewNumbering() + || archive.isOldFormat(); + String nextName = VolumeHelper.nextVolumeName(lastFileVolume.getFile() + .getAbsolutePath(), oldNumbering); + File nextVolume = new File(nextName); + + return new FileVolume(archive, nextVolume); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/io/IReadOnlyAccess.java b/org.fox.ttcomics/src/main/java/com/github/junrar/io/IReadOnlyAccess.java new file mode 100644 index 0000000..e0cde6e --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/io/IReadOnlyAccess.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 23.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.io; + +import java.io.IOException; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public interface IReadOnlyAccess { + + /** + * @return the current position in the file + */ + public long getPosition() throws IOException; + + /** + * @param pos the position in the file + * @return success ? true : false + */ + public void setPosition(long pos) throws IOException; + + /** Read a single byte of data. */ + public int read() throws IOException; + + /** + * Read up to count bytes to the specified buffer. + */ + public int read(byte[] buffer, int off, int count) throws IOException; + + /** + * Read exactly count bytes to the specified buffer. + * + * @param buffer where to store the read data + * @param count how many bytes to read + * @return bytes read || -1 if IO problem + */ + public int readFully(byte[] buffer, int count) throws IOException; + + /** Close this file. */ + public void close() throws IOException; +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/io/InputStreamReadOnlyAccessFile.java b/org.fox.ttcomics/src/main/java/com/github/junrar/io/InputStreamReadOnlyAccessFile.java new file mode 100644 index 0000000..3c7eedd --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/io/InputStreamReadOnlyAccessFile.java @@ -0,0 +1,59 @@ +package com.github.junrar.io; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + + + + +/** + * InputStream based implementation of the IReadOnlyAccess interface. + * + * @see http://rsbweb.nih.gov/ij/ + * @author martinr + */ +public class InputStreamReadOnlyAccessFile implements IReadOnlyAccess { + private RandomAccessStream is; + + /** + * Create new instance. + * + * @param is The input stream to wrap. + */ + public InputStreamReadOnlyAccessFile(final InputStream is) { + this.is = new RandomAccessStream(new BufferedInputStream(is)); + } + + @Override + public long getPosition() throws IOException { + return is.getLongFilePointer(); + } + + @Override + public void setPosition(long pos) throws IOException { + is.seek(pos); + } + + @Override + public int read() throws IOException { + return is.read(); + } + + @Override + public int read(byte[] buffer, int off, int count) throws IOException { + return is.read(buffer, off, count); + } + + @Override + public int readFully(byte[] buffer, int count) throws IOException { + is.readFully(buffer, count); + return count; + } + + @Override + public void close() throws IOException { + is.close(); + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/io/RandomAccessStream.java b/org.fox.ttcomics/src/main/java/com/github/junrar/io/RandomAccessStream.java new file mode 100644 index 0000000..49442bf --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/io/RandomAccessStream.java @@ -0,0 +1,203 @@ +/* + * public domain as of http://rsbweb.nih.gov/ij/disclaimer.html + */ +package com.github.junrar.io; + +import java.io.*; +import java.util.Vector; + +/** + * This is a class that uses a memory cache to allow seeking within an + * InputStream. Based on the JAI MemoryCacheSeekableStream class. Can also be + * constructed from a RandomAccessFile, which uses less memory since the memory + * cache is not required. + */ +@SuppressWarnings("rawtypes") +public final class RandomAccessStream extends InputStream { + + private static final int BLOCK_SIZE = 512; + private static final int BLOCK_MASK = 511; + private static final int BLOCK_SHIFT = 9; + + private InputStream src; + private RandomAccessFile ras; + private long pointer; + private Vector data; + private int length; + private boolean foundEOS; + + /** + * Constructs a RandomAccessStream from an InputStream. Seeking backwards is + * supported using a memory cache. + */ + public RandomAccessStream(InputStream inputstream) { + pointer = 0L; + data = new Vector(); + length = 0; + foundEOS = false; + src = inputstream; + } + + /** Constructs a RandomAccessStream from an RandomAccessFile. */ + public RandomAccessStream(RandomAccessFile ras) { + this.ras = ras; + } + + public int getFilePointer() throws IOException { + if (ras != null) + return (int) ras.getFilePointer(); + else + return (int) pointer; + } + + public long getLongFilePointer() throws IOException { + if (ras != null) + return ras.getFilePointer(); + else + return pointer; + } + + public int read() throws IOException { + if (ras != null) + return ras.read(); + long l = pointer + 1L; + long l1 = readUntil(l); + if (l1 >= l) { + byte abyte0[] = (byte[]) data + .elementAt((int) (pointer >> BLOCK_SHIFT)); + return abyte0[(int) (pointer++ & BLOCK_MASK)] & 0xff; + } else + return -1; + } + + public int read(byte[] bytes, int off, int len) throws IOException { + if (bytes == null) + throw new NullPointerException(); + if (ras != null) + return ras.read(bytes, off, len); + if (off < 0 || len < 0 || off + len > bytes.length) + throw new IndexOutOfBoundsException(); + if (len == 0) + return 0; + long l = readUntil(pointer + len); + if (l <= pointer) + return -1; + else { + byte abyte1[] = (byte[]) data + .elementAt((int) (pointer >> BLOCK_SHIFT)); + int k = Math.min(len, BLOCK_SIZE - (int) (pointer & BLOCK_MASK)); + System.arraycopy(abyte1, (int) (pointer & BLOCK_MASK), bytes, off, + k); + pointer += k; + return k; + } + } + + public final void readFully(byte[] bytes) throws IOException { + readFully(bytes, bytes.length); + } + + public final void readFully(byte[] bytes, int len) throws IOException { + int read = 0; + do { + int l = read(bytes, read, len - read); + if (l < 0) + break; + read += l; + } while (read < len); + } + + @SuppressWarnings("unchecked") + private long readUntil(long l) throws IOException { + if (l < length) + return l; + if (foundEOS) + return length; + int i = (int) (l >> BLOCK_SHIFT); + int j = length >> BLOCK_SHIFT; + for (int k = j; k <= i; k++) { + byte abyte0[] = new byte[BLOCK_SIZE]; + data.addElement(abyte0); + int i1 = BLOCK_SIZE; + int j1 = 0; + while (i1 > 0) { + int k1 = src.read(abyte0, j1, i1); + if (k1 == -1) { + foundEOS = true; + return length; + } + j1 += k1; + i1 -= k1; + length += k1; + } + + } + + return length; + } + + public void seek(long loc) throws IOException { + if (ras != null) { + ras.seek(loc); + return; + } + if (loc < 0L) + pointer = 0L; + else + pointer = loc; + } + + public void seek(int loc) throws IOException { + long lloc = ((long) loc) & 0xffffffffL; + if (ras != null) { + ras.seek(lloc); + return; + } + if (lloc < 0L) + pointer = 0L; + else + pointer = lloc; + } + + public final int readInt() throws IOException { + int i = read(); + int j = read(); + int k = read(); + int l = read(); + if ((i | j | k | l) < 0) + throw new EOFException(); + else + return (i << 24) + (j << 16) + (k << 8) + l; + } + + public final long readLong() throws IOException { + return ((long) readInt() << 32) + ((long) readInt() & 0xffffffffL); + } + + public final double readDouble() throws IOException { + return Double.longBitsToDouble(readLong()); + } + + public final short readShort() throws IOException { + int i = read(); + int j = read(); + if ((i | j) < 0) + throw new EOFException(); + else + return (short) ((i << 8) + j); + } + + public final float readFloat() throws IOException { + return Float.intBitsToFloat(readInt()); + } + + public void close() throws IOException { + if (ras != null) + ras.close(); + else { + data.removeAllElements(); + src.close(); + } + } + +} \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/io/Raw.java b/org.fox.ttcomics/src/main/java/com/github/junrar/io/Raw.java new file mode 100644 index 0000000..87affda --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/io/Raw.java @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 18.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.io; + +/** + * Read / write numbers to a byte[] regarding the endianness of the array + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class Raw { + /** + * Read a short value from the byte array at the given position (Big Endian) + * + * @param array + * the array to read from + * @param pos + * the position + * @return the value + */ + public static final short readShortBigEndian(byte[] array, int pos) { + short temp = 0; + temp |= array[pos] & 0xff; + temp <<= 8; + temp |= array[pos + 1] & 0xff; + return temp; + } + + /** + * Read a int value from the byte array at the given position (Big Endian) + * + * @param array + * the array to read from + * @param pos + * the offset + * @return the value + */ + public static final int readIntBigEndian(byte[] array, int pos) { + int temp = 0; + temp |= array[pos] & 0xff; + temp <<= 8; + temp |= array[pos + 1] & 0xff; + temp <<= 8; + temp |= array[pos + 2] & 0xff; + temp <<= 8; + temp |= array[pos + 3] & 0xff; + return temp; + } + + /** + * Read a long value from the byte array at the given position (Big Endian) + * + * @param array + * the array to read from + * @param pos + * the offset + * @return the value + */ + public static final long readLongBigEndian(byte[] array, int pos) { + int temp = 0; + temp |= array[pos] & 0xff; + temp <<= 8; + temp |= array[pos + 1] & 0xff; + temp <<= 8; + temp |= array[pos + 2] & 0xff; + temp <<= 8; + temp |= array[pos + 3] & 0xff; + temp <<= 8; + temp |= array[pos + 4] & 0xff; + temp <<= 8; + temp |= array[pos + 5] & 0xff; + temp <<= 8; + temp |= array[pos + 6] & 0xff; + temp <<= 8; + temp |= array[pos + 7] & 0xff; + return temp; + } + + /** + * Read a short value from the byte array at the given position (little + * Endian) + * + * @param array + * the array to read from + * @param pos + * the offset + * @return the value + */ + public static final short readShortLittleEndian(byte[] array, int pos) { + short result = 0; + result += array[pos + 1] & 0xff; + result <<= 8; + result += array[pos] & 0xff; + return result; + } + + /** + * Read an int value from the byte array at the given position (little + * Endian) + * + * @param array + * the array to read from + * @param pos + * the offset + * @return the value + */ + public static final int readIntLittleEndian(byte[] array, int pos) { + return ((array[pos + 3] & 0xff) << 24) + | ((array[pos + 2] & 0xff) << 16) + | ((array[pos + 1] & 0xff) << 8) | ((array[pos] & 0xff)); + } + + /** + * Read an long value(unsigned int) from the byte array at the given + * position (little Endian) + * + * @param array + * @param pos + * @return + */ + public static final long readIntLittleEndianAsLong(byte[] array, int pos) { + return (((long) array[pos + 3] & 0xff) << 24) + | (((long) array[pos + 2] & 0xff) << 16) + | (((long) array[pos + 1] & 0xff) << 8) + | (((long) array[pos] & 0xff)); + } + + /** + * Read a long value from the byte array at the given position (little + * Endian) + * + * @param array + * the array to read from + * @param pos + * the offset + * @return the value + */ + public static final long readLongLittleEndian(byte[] array, int pos) { + int temp = 0; + temp |= array[pos + 7] & 0xff; + temp <<= 8; + temp |= array[pos + 6] & 0xff; + temp <<= 8; + temp |= array[pos + 5] & 0xff; + temp <<= 8; + temp |= array[pos + 4] & 0xff; + temp <<= 8; + temp |= array[pos + 3] & 0xff; + temp <<= 8; + temp |= array[pos + 2] & 0xff; + temp <<= 8; + temp |= array[pos + 1] & 0xff; + temp <<= 8; + temp |= array[pos]; + return temp; + } + + /** + * Write a short value into the byte array at the given position (Big + * endian) + * + * @param array + * the array + * @param pos + * the offset + * @param value + * the value to write + */ + public static final void writeShortBigEndian(byte[] array, int pos, + short value) { + array[pos] = (byte) (value >>> 8); + array[pos + 1] = (byte) (value & 0xFF); + + } + + /** + * Write an int value into the byte array at the given position (Big endian) + * + * @param array + * the array + * @param pos + * the offset + * @param value + * the value to write + */ + public static final void writeIntBigEndian(byte[] array, int pos, int value) { + array[pos] = (byte) ((value >>> 24) & 0xff); + array[pos + 1] = (byte) ((value >>> 16) & 0xff); + array[pos + 2] = (byte) ((value >>> 8) & 0xff); + array[pos + 3] = (byte) ((value) & 0xff); + + } + + /** + * Write a long value into the byte array at the given position (Big endian) + * + * @param array + * the array + * @param pos + * the offset + * @param value + * the value to write + */ + public static final void writeLongBigEndian(byte[] array, int pos, + long value) { + array[pos] = (byte) (value >>> 56); + array[pos + 1] = (byte) (value >>> 48); + array[pos + 2] = (byte) (value >>> 40); + array[pos + 3] = (byte) (value >>> 32); + array[pos + 4] = (byte) (value >>> 24); + array[pos + 5] = (byte) (value >>> 16); + array[pos + 6] = (byte) (value >>> 8); + array[pos + 7] = (byte) (value & 0xFF); + + } + + /** + * Write a short value into the byte array at the given position (little + * endian) + * + * @param array + * the array + * @param pos + * the offset + * @param value + * the value to write + */ + public static final void writeShortLittleEndian(byte[] array, int pos, + short value) { + array[pos + 1] = (byte) (value >>> 8); + array[pos] = (byte) (value & 0xFF); + + } + + /** + * Increment a short value at the specified position by the specified amount + * (little endian). + */ + public static final void incShortLittleEndian(byte[] array, int pos, int dv) { + int c = ((array[pos] & 0xff) + (dv & 0xff)) >>> 8; + array[pos] += dv & 0xff; + if ((c > 0) || ((dv & 0xff00) != 0)) { + array[pos + 1] += ((dv >>> 8) & 0xff) + c; + } + } + + /** + * Write an int value into the byte array at the given position (little + * endian) + * + * @param array + * the array + * @param pos + * the offset + * @param value + * the value to write + */ + public static final void writeIntLittleEndian(byte[] array, int pos, + int value) { + array[pos + 3] = (byte) (value >>> 24); + array[pos + 2] = (byte) (value >>> 16); + array[pos + 1] = (byte) (value >>> 8); + array[pos] = (byte) (value & 0xFF); + + } + + /** + * Write a long value into the byte array at the given position (little + * endian) + * + * @param array + * the array + * @param pos + * the offset + * @param value + * the value to write + */ + public static final void writeLongLittleEndian(byte[] array, int pos, + long value) { + array[pos + 7] = (byte) (value >>> 56); + array[pos + 6] = (byte) (value >>> 48); + array[pos + 5] = (byte) (value >>> 40); + array[pos + 4] = (byte) (value >>> 32); + array[pos + 3] = (byte) (value >>> 24); + array[pos + 2] = (byte) (value >>> 16); + array[pos + 1] = (byte) (value >>> 8); + array[pos] = (byte) (value & 0xFF); + + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessByteArray.java b/org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessByteArray.java new file mode 100644 index 0000000..bbdb687 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessByteArray.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 30.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.io; + +import java.io.EOFException; +import java.io.IOException; + +/** + * A File like access to a byte array. + * (seek and read certain number of bytes) + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class ReadOnlyAccessByteArray implements IReadOnlyAccess{ + + private int positionInFile; + private byte[] file; + + /** + * Initialize with byte[ ] + * @param file the file given as byte array + */ + public ReadOnlyAccessByteArray(byte[] file){ + if(file == null){ + throw new NullPointerException("file must not be null!!"); + } + this.file = file; + this.positionInFile = 0; + } + + public long getPosition() throws IOException { + return positionInFile; + } + + public void setPosition(long pos) throws IOException { + if (pos < file.length && pos >= 0){ + this.positionInFile = (int)pos; + } + else{ + throw new EOFException(); + } + } + + /** Read a single byte of data. */ + public int read() throws IOException { + return file[positionInFile++]; + } + + /** + * Read up to count bytes to the specified buffer. + */ + public int read(byte[] buffer, int off, int count) throws IOException { + int read = Math.min(count, file.length-positionInFile); + System.arraycopy(file, positionInFile, buffer, off, read); + positionInFile += read; + return read; + } + + public int readFully(byte[] buffer, int count) throws IOException { + if(buffer == null ){ + throw new NullPointerException("buffer must not be null"); + } + if(count == 0){ + throw new IllegalArgumentException("cannot read 0 bytes ;-)"); + } + int read = Math.min(count, file.length-(int)positionInFile-1); + System.arraycopy(file, (int)positionInFile, buffer, 0, read ); + positionInFile+=read; + return read; + } + + public void close() throws IOException { + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessFile.java b/org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessFile.java new file mode 100644 index 0000000..77ad35a --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessFile.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 23.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.io; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class ReadOnlyAccessFile extends RandomAccessFile + implements IReadOnlyAccess{ + + /** + * @param file the file + * @throws FileNotFoundException + */ + public ReadOnlyAccessFile(File file) throws FileNotFoundException { + super(file, "r"); + } + + public int readFully(byte[] buffer, int count) throws IOException { + assert (count > 0) : count; + this.readFully(buffer, 0, count); + return count; + } + + public long getPosition() throws IOException { + return this.getFilePointer(); + } + + public void setPosition(long pos) throws IOException { + this.seek(pos); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessInputStream.java b/org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessInputStream.java new file mode 100644 index 0000000..80c022e --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/io/ReadOnlyAccessInputStream.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 26.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression + * algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.io; + +import java.io.IOException; +import java.io.InputStream; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class ReadOnlyAccessInputStream extends InputStream { + private IReadOnlyAccess file; + + private long curPos; + private final long startPos; + private final long endPos; + + public ReadOnlyAccessInputStream(IReadOnlyAccess file, long startPos, + long endPos) throws IOException { + super(); + this.file = file; + this.startPos = startPos; + curPos = startPos; + this.endPos = endPos; + file.setPosition(curPos); + } + + @Override + public int read() throws IOException { + if (curPos == endPos) { + return -1; + } + else { + int b = file.read(); + curPos++; + return b; + } + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (len == 0) { + return 0; + } + if (curPos == endPos) { + return -1; + } + int bytesRead = file.read(b, off, + (int)Math.min(len, endPos - curPos)); + curPos += bytesRead; + return bytesRead; + } + + @Override + public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } +// +// public void close() throws IOException { +// file.close(); +// } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/AVHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/AVHeader.java new file mode 100644 index 0000000..66e9dbb --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/AVHeader.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + +/** + * extended version info header + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class AVHeader extends BaseBlock { + + public static final int avHeaderSize = 7; + + private byte unpackVersion; + private byte method; + private byte avVersion; + private int avInfoCRC; + + public AVHeader(BaseBlock bb, byte[] avHeader){ + super(bb); + + int pos =0; + unpackVersion |= avHeader[pos]&0xff; + pos++; + method |= avHeader[pos]&0xff; + pos++; + avVersion |= avHeader[pos]&0xff; + pos++; + avInfoCRC = Raw.readIntLittleEndian(avHeader, pos); + } + + public int getAvInfoCRC() { + return avInfoCRC; + } + + public byte getAvVersion() { + return avVersion; + } + + public byte getMethod() { + return method; + } + + public byte getUnpackVersion() { + return unpackVersion; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/BaseBlock.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/BaseBlock.java new file mode 100644 index 0000000..68c2d94 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/BaseBlock.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 22.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + + + +/** + * Base class of all rar headers + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class BaseBlock{ + + //Log //logger = LogFactory.getLog(BaseBlock.class.getName()); + + public static final short BaseBlockSize = 7; + + //TODO move somewhere else + + public static final short MHD_VOLUME = 0x0001; + public static final short MHD_COMMENT = 0x0002; + public static final short MHD_LOCK = 0x0004; + public static final short MHD_SOLID = 0x0008; + public static final short MHD_PACK_COMMENT = 0x0010; + public static final short MHD_NEWNUMBERING = 0x0010; + public static final short MHD_AV = 0x0020; + public static final short MHD_PROTECT = 0x0040; + public static final short MHD_PASSWORD = 0x0080; + public static final short MHD_FIRSTVOLUME = 0x0100; + public static final short MHD_ENCRYPTVER = 0x0200; + + + public static final short LHD_SPLIT_BEFORE = 0x0001; + public static final short LHD_SPLIT_AFTER = 0x0002; + public static final short LHD_PASSWORD = 0x0004; + public static final short LHD_COMMENT = 0x0008; + public static final short LHD_SOLID = 0x0010; + + public static final short LHD_WINDOWMASK = 0x00e0; + public static final short LHD_WINDOW64 = 0x0000; + public static final short LHD_WINDOW128 = 0x0020; + public static final short LHD_WINDOW256 = 0x0040; + public static final short LHD_WINDOW512 = 0x0060; + public static final short LHD_WINDOW1024 = 0x0080; + public static final short LHD_WINDOW2048 = 0x00a0; + public static final short LHD_WINDOW4096 = 0x00c0; + public static final short LHD_DIRECTORY = 0x00e0; + + public static final short LHD_LARGE = 0x0100; + public static final short LHD_UNICODE = 0x0200; + public static final short LHD_SALT = 0x0400; + public static final short LHD_VERSION = 0x0800; + public static final short LHD_EXTTIME = 0x1000; + public static final short LHD_EXTFLAGS = 0x2000; + + public static final short SKIP_IF_UNKNOWN = 0x4000; + public static final short LONG_BLOCK = -0x8000; + + public static final short EARC_NEXT_VOLUME = 0x0001; + public static final short EARC_DATACRC = 0x0002; + public static final short EARC_REVSPACE = 0x0004; + public static final short EARC_VOLNUMBER = 0x0008; + + + protected long positionInFile; + + protected short headCRC = 0; + protected byte headerType = 0; + protected short flags = 0; + protected short headerSize = 0 ; + + /** + * + */ + public BaseBlock(){ + + } + + public BaseBlock(BaseBlock bb){ + this.flags = bb.getFlags(); + this.headCRC = bb.getHeadCRC(); + this.headerType = bb.getHeaderType().getHeaderByte(); + this.headerSize = bb.getHeaderSize(); + this.positionInFile = bb.getPositionInFile(); + } + public BaseBlock(byte[] baseBlockHeader){ + + int pos = 0; + this.headCRC = Raw.readShortLittleEndian(baseBlockHeader, pos); + pos+=2; + this.headerType |= baseBlockHeader[pos]&0xff; + pos++; + this.flags = Raw.readShortLittleEndian(baseBlockHeader, pos); + pos+=2; + this.headerSize = Raw.readShortLittleEndian(baseBlockHeader, pos); + } + + + public boolean hasArchiveDataCRC(){ + return (this.flags & EARC_DATACRC)!=0; + } + + public boolean hasVolumeNumber(){ + return (this.flags & EARC_VOLNUMBER)!=0; + } + + public boolean hasEncryptVersion(){ + return (flags & MHD_ENCRYPTVER)!=0; + } + + /** + * @return is it a sub block + */ + public boolean isSubBlock() + { + if (UnrarHeadertype.SubHeader.equals(headerType)){ + return(true); + } + if (UnrarHeadertype.NewSubHeader.equals(headerType) && (flags & LHD_SOLID)!=0) + { + return(true); + } + return(false); + + } + + public long getPositionInFile() { + return positionInFile; + } + + public short getFlags() { + return flags; + } + + public short getHeadCRC() { + return headCRC; + } + + public short getHeaderSize() { + return headerSize; + } + + public UnrarHeadertype getHeaderType() { + return UnrarHeadertype.findType(headerType); + } + + public void setPositionInFile(long positionInFile) { + this.positionInFile = positionInFile; + } + + public void print(){ + StringBuilder str =new StringBuilder(); + str.append("HeaderType: " + getHeaderType()); + str.append("\nHeadCRC: "+Integer.toHexString(getHeadCRC())); + str.append("\nFlags: "+Integer.toHexString(getFlags())); + str.append("\nHeaderSize: "+getHeaderSize()); + str.append("\nPosition in file: "+getPositionInFile()); + //logger.info(str.toString()); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/BlockHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/BlockHeader.java new file mode 100644 index 0000000..78fe955 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/BlockHeader.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 22.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + + +/** + * Base class of headers that contain data + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class BlockHeader extends BaseBlock{ + public static final short blockHeaderSize = 4; + + //private Log //logger = LogFactory.getLog(BlockHeader.class.getName()); + + private int dataSize; + private int packSize; + + public BlockHeader(){ + + } + + public BlockHeader(BlockHeader bh){ + super(bh); + this.packSize = bh.getDataSize(); + this.dataSize = packSize; + this.positionInFile = bh.getPositionInFile(); + } + + public BlockHeader(BaseBlock bb, byte[] blockHeader) + { + super(bb); + + this.packSize = Raw.readIntLittleEndian(blockHeader, 0); + this.dataSize = this.packSize; + } + + public int getDataSize() { + return dataSize; + } + + public int getPackSize() { + return packSize; + } + + public void print(){ + super.print(); + String s = "DataSize: "+getDataSize()+" packSize: "+getPackSize(); + //logger.info(s); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/CommentHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/CommentHeader.java new file mode 100644 index 0000000..2664330 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/CommentHeader.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 23.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ + +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + +/** + * Comment header + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class CommentHeader extends BaseBlock { + + public static final short commentHeaderSize = 6; + + private short unpSize; + private byte unpVersion; + private byte unpMethod; + private short commCRC; + + + public CommentHeader(BaseBlock bb, byte[] commentHeader){ + super(bb); + + int pos =0; + unpSize = Raw.readShortLittleEndian(commentHeader, pos); + pos += 2; + unpVersion |= commentHeader[pos]&0xff; + pos++; + + unpMethod |= commentHeader[pos]&0xff; + pos++; + commCRC =Raw.readShortLittleEndian(commentHeader, pos); + + } + + public short getCommCRC() { + return commCRC; + } + + public byte getUnpMethod() { + return unpMethod; + } + + public short getUnpSize() { + return unpSize; + } + + public byte getUnpVersion() { + return unpVersion; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/EAHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/EAHeader.java new file mode 100644 index 0000000..762e644 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/EAHeader.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 27.11.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + + +/** + * extended archive CRC header + * + */ +public class EAHeader +extends SubBlockHeader +{ + //private Log //logger = LogFactory.getLog(getClass()); + + public static final short EAHeaderSize = 10; + + private int unpSize; + private byte unpVer; + private byte method; + private int EACRC; + + public EAHeader(SubBlockHeader sb, byte[] eahead) + { + super(sb); + int pos = 0; + unpSize = Raw.readIntLittleEndian(eahead, pos); + pos+=4; + unpVer |= eahead[pos]&0xff; + pos++; + method |= eahead[pos]&0xff; + pos++; + EACRC = Raw.readIntLittleEndian(eahead, pos); + } + + /** + * @return the eACRC + */ + public int getEACRC() { + return EACRC; + } + + /** + * @return the method + */ + public byte getMethod() { + return method; + } + + /** + * @return the unpSize + */ + public int getUnpSize() { + return unpSize; + } + + /** + * @return the unpVer + */ + public byte getUnpVer() { + return unpVer; + } + + public void print() + { + super.print(); + //logger.info("unpSize: "+unpSize); + //logger.info("unpVersion: " + unpVer); + //logger.info("method: "+method); + //logger.info("EACRC:" + EACRC); + } +} + diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/EndArcHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/EndArcHeader.java new file mode 100644 index 0000000..5a9be5e --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/EndArcHeader.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + +/** + * + * the optional End header + * + */ +public class EndArcHeader extends BaseBlock{ + + private static final short EARC_NEXT_VOLUME = 0x0001; + private static final short EARC_DATACRC = 0x0002; + private static final short EARC_REVSPACE = 0x0004; + private static final short EARC_VOLNUMBER = 0x0008; + + private static final short endArcHeaderSize = 6; + public static final short endArcArchiveDataCrcSize = 4; + public static final short endArcVolumeNumberSize = 2; + + private int archiveDataCRC; + private short volumeNumber; + + + public EndArcHeader(BaseBlock bb, byte[] endArcHeader){ + super(bb); + + int pos = 0; + if(hasArchiveDataCRC()){ + archiveDataCRC =Raw.readIntLittleEndian(endArcHeader, pos); + pos+=4; + } + if(hasVolumeNumber()){ + volumeNumber = Raw.readShortLittleEndian(endArcHeader, pos); + } + } + + public int getArchiveDataCRC() { + return archiveDataCRC; + } + + public short getVolumeNumber() { + return volumeNumber; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/FileHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/FileHeader.java new file mode 100644 index 0000000..84dce5e --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/FileHeader.java @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 22.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import java.util.Calendar; +import java.util.Date; + +import org.apache.commons.logging.Log; + +import com.github.junrar.io.Raw; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class FileHeader extends BlockHeader { + + //private final Log //logger = LogFactory.getLog(FileHeader.class.getName()); + + private static final byte SALT_SIZE = 8; + + private static final byte NEWLHD_SIZE = 32; + + private long unpSize; + + private final HostSystem hostOS; + + private final int fileCRC; + + private final int fileTime; + + private byte unpVersion; + + private byte unpMethod; + + private short nameSize; + + private int highPackSize; + + private int highUnpackSize; + + private final byte[] fileNameBytes; + + private String fileName; + private String fileNameW; + + private byte[] subData; + + private final byte[] salt = new byte[SALT_SIZE]; + + private Date mTime; + + private Date cTime; + + private Date aTime; + + private Date arcTime; + + private long fullPackSize; + + private long fullUnpackSize; + + private int fileAttr; + + private int subFlags; // same as fileAttr (in header) + + private int recoverySectors = -1; + + public FileHeader(BlockHeader bh, byte[] fileHeader) { + super(bh); + + int position = 0; + unpSize = Raw.readIntLittleEndianAsLong(fileHeader, position); + position += 4; + hostOS = HostSystem.findHostSystem(fileHeader[4]); + position++; + + fileCRC = Raw.readIntLittleEndian(fileHeader, position); + position += 4; + + fileTime = Raw.readIntLittleEndian(fileHeader, position); + position += 4; + + unpVersion |= fileHeader[13] & 0xff; + position++; + unpMethod |= fileHeader[14] & 0xff; + position++; + nameSize = Raw.readShortLittleEndian(fileHeader, position); + position += 2; + + fileAttr = Raw.readIntLittleEndian(fileHeader, position); + position += 4; + if (isLargeBlock()) { + highPackSize = Raw.readIntLittleEndian(fileHeader, position); + position += 4; + + highUnpackSize = Raw.readIntLittleEndian(fileHeader, position); + position += 4; + } else { + highPackSize = 0; + highUnpackSize = 0; + if (unpSize == 0xffffffff) { + + unpSize = 0xffffffff; + highUnpackSize = Integer.MAX_VALUE; + } + + } + fullPackSize |= highPackSize; + fullPackSize <<= 32; + fullPackSize |= getPackSize(); + + fullUnpackSize |= highUnpackSize; + fullUnpackSize <<= 32; + fullUnpackSize += unpSize; + + nameSize = nameSize > 4 * 1024 ? 4 * 1024 : nameSize; + + fileNameBytes = new byte[nameSize]; + for (int i = 0; i < nameSize; i++) { + fileNameBytes[i] = fileHeader[position]; + position++; + } + + if (isFileHeader()) { + if (isUnicode()) { + int length = 0; + fileName = ""; + fileNameW = ""; + while (length < fileNameBytes.length + && fileNameBytes[length] != 0) { + length++; + } + byte[] name = new byte[length]; + System.arraycopy(fileNameBytes, 0, name, 0, name.length); + fileName = new String(name); + if (length != nameSize) { + length++; + fileNameW = FileNameDecoder.decode(fileNameBytes, length); + } + } else { + fileName = new String(fileNameBytes); + fileNameW = ""; + } + } + + if (UnrarHeadertype.NewSubHeader.equals(headerType)) { + int datasize = headerSize - NEWLHD_SIZE - nameSize; + if (hasSalt()) { + datasize -= SALT_SIZE; + } + if (datasize > 0) { + subData = new byte[datasize]; + for (int i = 0; i < datasize; i++) { + subData[i] = (fileHeader[position]); + position++; + } + } + + if (NewSubHeaderType.SUBHEAD_TYPE_RR.byteEquals(fileNameBytes)) { + recoverySectors = subData[8] + (subData[9] << 8) + + (subData[10] << 16) + (subData[11] << 24); + } + } + + if (hasSalt()) { + for (int i = 0; i < SALT_SIZE; i++) { + salt[i] = fileHeader[position]; + position++; + } + } + mTime = getDateDos(fileTime); + // TODO rartime -> extended + + } + + @Override + public void print() { + super.print(); + StringBuilder str = new StringBuilder(); + str.append("unpSize: " + getUnpSize()); + str.append("\nHostOS: " + hostOS.name()); + str.append("\nMDate: " + mTime); + str.append("\nFileName: " + getFileNameString()); + str.append("\nunpMethod: " + Integer.toHexString(getUnpMethod())); + str.append("\nunpVersion: " + Integer.toHexString(getUnpVersion())); + str.append("\nfullpackedsize: " + getFullPackSize()); + str.append("\nfullunpackedsize: " + getFullUnpackSize()); + str.append("\nisEncrypted: " + isEncrypted()); + str.append("\nisfileHeader: " + isFileHeader()); + str.append("\nisSolid: " + isSolid()); + str.append("\nisSplitafter: " + isSplitAfter()); + str.append("\nisSplitBefore:" + isSplitBefore()); + str.append("\nunpSize: " + getUnpSize()); + str.append("\ndataSize: " + getDataSize()); + str.append("\nisUnicode: " + isUnicode()); + str.append("\nhasVolumeNumber: " + hasVolumeNumber()); + str.append("\nhasArchiveDataCRC: " + hasArchiveDataCRC()); + str.append("\nhasSalt: " + hasSalt()); + str.append("\nhasEncryptVersions: " + hasEncryptVersion()); + str.append("\nisSubBlock: " + isSubBlock()); + //logger.info(str.toString()); + } + + private Date getDateDos(int time) { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, (time >>> 25) + 1980); + cal.set(Calendar.MONTH, ((time >>> 21) & 0x0f) - 1); + cal.set(Calendar.DAY_OF_MONTH, (time >>> 16) & 0x1f); + cal.set(Calendar.HOUR_OF_DAY, (time >>> 11) & 0x1f); + cal.set(Calendar.MINUTE, (time >>> 5) & 0x3f); + cal.set(Calendar.SECOND, (time & 0x1f) * 2); + return cal.getTime(); + } + + public Date getArcTime() { + return arcTime; + } + + public void setArcTime(Date arcTime) { + this.arcTime = arcTime; + } + + public Date getATime() { + return aTime; + } + + public void setATime(Date time) { + aTime = time; + } + + public Date getCTime() { + return cTime; + } + + public void setCTime(Date time) { + cTime = time; + } + + public int getFileAttr() { + return fileAttr; + } + + public void setFileAttr(int fileAttr) { + this.fileAttr = fileAttr; + } + + public int getFileCRC() { + return fileCRC; + } + + public byte[] getFileNameByteArray() { + return fileNameBytes; + } + + public String getFileNameString() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getFileNameW() { + return fileNameW; + } + + public void setFileNameW(String fileNameW) { + this.fileNameW = fileNameW; + } + + public int getHighPackSize() { + return highPackSize; + } + + public int getHighUnpackSize() { + return highUnpackSize; + } + + public HostSystem getHostOS() { + return hostOS; + } + + public Date getMTime() { + return mTime; + } + + public void setMTime(Date time) { + mTime = time; + } + + public short getNameSize() { + return nameSize; + } + + public int getRecoverySectors() { + return recoverySectors; + } + + public byte[] getSalt() { + return salt; + } + + public byte[] getSubData() { + return subData; + } + + public int getSubFlags() { + return subFlags; + } + + public byte getUnpMethod() { + return unpMethod; + } + + public long getUnpSize() { + return unpSize; + } + + public byte getUnpVersion() { + return unpVersion; + } + + public long getFullPackSize() { + return fullPackSize; + } + + public long getFullUnpackSize() { + return fullUnpackSize; + } + + @Override + public String toString() { + return super.toString(); + } + + /** + * the file will be continued in the next archive part + * + * @return + */ + public boolean isSplitAfter() { + return (this.flags & BlockHeader.LHD_SPLIT_AFTER) != 0; + } + + /** + * the file is continued in this archive + * + * @return + */ + public boolean isSplitBefore() { + return (this.flags & LHD_SPLIT_BEFORE) != 0; + } + + /** + * this file is compressed as solid (all files handeled as one) + * + * @return + */ + public boolean isSolid() { + return (this.flags & LHD_SOLID) != 0; + } + + /** + * the file is encrypted + * + * @return + */ + public boolean isEncrypted() { + return (this.flags & BlockHeader.LHD_PASSWORD) != 0; + } + + /** + * the filename is also present in unicode + * + * @return + */ + public boolean isUnicode() { + return (flags & LHD_UNICODE) != 0; + } + + public boolean isFileHeader() { + return UnrarHeadertype.FileHeader.equals(headerType); + } + + public boolean hasSalt() { + return (flags & LHD_SALT) != 0; + } + + public boolean isLargeBlock() { + return (flags & LHD_LARGE) != 0; + } + + /** + * whether this fileheader represents a directory + * + * @return + */ + public boolean isDirectory() { + return (flags & LHD_WINDOWMASK) == LHD_DIRECTORY; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/FileNameDecoder.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/FileNameDecoder.java new file mode 100644 index 0000000..aee1179 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/FileNameDecoder.java @@ -0,0 +1,76 @@ +/* + * + * Original author: alpha_lam + * Creation date: ? + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +public class FileNameDecoder { + public static int getChar(byte [] name,int pos){ + return name[pos]&0xff; + } + + public static String decode(byte [] name,int encPos){ + int decPos = 0; + int flags = 0; + int flagBits = 0; + + int low = 0; + int high = 0; + int highByte = getChar(name,encPos++); + StringBuffer buf = new StringBuffer(); + while(encPos < name.length){ + if(flagBits == 0){ + flags = getChar(name,encPos++); + flagBits = 8; + } + switch(flags >> 6){ + case 0: + buf.append((char)(getChar(name,encPos++))); + ++decPos; + break; + case 1: + buf.append((char)(getChar(name,encPos++)+(highByte<<8))); + ++decPos; + break; + case 2: + low = getChar(name,encPos); + high = getChar(name,encPos+1); + buf.append((char)((high << 8) + low)); + ++decPos; + encPos += 2; + break; + case 3: + int length = getChar(name,encPos++); + if((length&0x80)!=0){ + int correction = getChar(name,encPos++); + for(length=(length&0x7f)+2;length>0&&decPos0&&decPos": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public enum HostSystem { + msdos ((byte)0), + os2 ((byte)1), + win32 ((byte)2), + unix ((byte)3), + macos ((byte)4), + beos ((byte)5); + + private byte hostByte; + + public static HostSystem findHostSystem(byte hostByte){ + if(HostSystem.msdos.equals(hostByte)){ + return HostSystem.msdos; + } + if(HostSystem.os2.equals(hostByte)){ + return HostSystem.os2; + } + if(HostSystem.win32.equals(hostByte)){ + return HostSystem.win32; + } + if(HostSystem.unix.equals(hostByte)){ + return HostSystem.unix; + } + if(HostSystem.macos.equals(hostByte)){ + return HostSystem.macos; + } + if(HostSystem.beos.equals(hostByte)){ + return HostSystem.beos; + } + return null; + } + + + private HostSystem(byte hostByte){ + this.hostByte = hostByte; + } + + public boolean equals(byte hostByte){ + return this.hostByte == hostByte; + } + + public byte getHostByte(){ + return hostByte; + } + //???? public static final byte max = 6; +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MacInfoHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MacInfoHeader.java new file mode 100644 index 0000000..e94521d --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MacInfoHeader.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 26.11.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + + +/** + * Mac File attribute header + * + */ +public class MacInfoHeader +extends SubBlockHeader +{ + //private Log //logger = LogFactory.getLog(getClass()); + + public static final short MacInfoHeaderSize = 8; + + private int fileType; + private int fileCreator; + + public MacInfoHeader(SubBlockHeader sb, byte[] macHeader) + { + super(sb); + int pos = 0; + fileType = Raw.readIntLittleEndian(macHeader, pos); + pos+=4; + fileCreator = Raw.readIntLittleEndian(macHeader, pos); + } + + /** + * @return the fileCreator + */ + public int getFileCreator() { + return fileCreator; + } + + /** + * @param fileCreator the fileCreator to set + */ + public void setFileCreator(int fileCreator) { + this.fileCreator = fileCreator; + } + + /** + * @return the fileType + */ + public int getFileType() { + return fileType; + } + + /** + * @param fileType the fileType to set + */ + public void setFileType(int fileType) { + this.fileType = fileType; + } + + public void print(){ + super.print(); + //logger.info("filetype: "+fileType); + //logger.info("creator :"+fileCreator); + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MainHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MainHeader.java new file mode 100644 index 0000000..8c3e89f --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MainHeader.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 22.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + + +/** + * The main header of an rar archive. holds information concerning the whole archive (solid, encrypted etc). + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class MainHeader extends BaseBlock { + //private Log //logger = LogFactory.getLog(MainHeader.class.getName()); + public static final short mainHeaderSizeWithEnc = 7; + public static final short mainHeaderSize = 6; + private short highPosAv; + private int posAv; + private byte encryptVersion; + + public MainHeader(BaseBlock bb, byte[] mainHeader) { + super(bb); + int pos = 0; + highPosAv = Raw.readShortLittleEndian(mainHeader, pos); + pos += 2; + posAv = Raw.readIntLittleEndian(mainHeader, pos); + pos+=4; + + if(hasEncryptVersion()){ + encryptVersion |= mainHeader[pos]&0xff; + } + } + + /** + * old cmt block is present + * @return true if has cmt block + */ + public boolean hasArchCmt(){ + return (this.flags & BaseBlock.MHD_COMMENT)!=0; + } + /** + * the version the the encryption + * @return + */ + public byte getEncryptVersion() { + return encryptVersion; + } + + public short getHighPosAv() { + return highPosAv; + } + + public int getPosAv() { + return posAv; + } + + /** + * returns whether the archive is encrypted + * @return + */ + public boolean isEncrypted(){ + return (this.flags & BaseBlock.MHD_PASSWORD)!=0; + } + + /** + * return whether the archive is a multivolume archive + * @return + */ + public boolean isMultiVolume(){ + return (this.flags & BaseBlock.MHD_VOLUME)!=0; + } + + /** + * if the archive is a multivolume archive this method returns whether this instance is the first part of the multivolume archive + * @return + */ + public boolean isFirstVolume(){ + return (this.flags & BaseBlock.MHD_FIRSTVOLUME)!=0; + } + + public void print(){ + super.print(); + StringBuilder str=new StringBuilder(); + str.append("posav: "+getPosAv()); + str.append("\nhighposav: "+getHighPosAv()); + str.append("\nhasencversion: "+hasEncryptVersion()+(hasEncryptVersion()?getEncryptVersion():"")); + str.append("\nhasarchcmt: "+hasArchCmt()); + str.append("\nisEncrypted: "+isEncrypted()); + str.append("\nisMultivolume: "+isMultiVolume()); + str.append("\nisFirstvolume: "+isFirstVolume()); + str.append("\nisSolid: "+isSolid()); + str.append("\nisLocked: "+isLocked()); + str.append("\nisProtected: "+isProtected()); + str.append("\nisAV: "+isAV()); + //logger.info(str.toString()); + } + + /** + * returns whether this archive is solid. in this case you can only extract all file at once + * @return + */ + public boolean isSolid(){ + return (this.flags&MHD_SOLID)!=0; + } + + public boolean isLocked(){ + return (this.flags&MHD_LOCK)!=0; + } + + public boolean isProtected(){ + return (this.flags&MHD_PROTECT)!=0; + } + + public boolean isAV(){ + return (this.flags&MHD_AV)!=0; + } + /** + * the numbering format a multivolume archive + * @return + */ + public boolean isNewNumbering(){ + return (this.flags&MHD_NEWNUMBERING)!=0; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MarkHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MarkHeader.java new file mode 100644 index 0000000..1673306 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/MarkHeader.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + + +/** + * the header to recognize a file to be a rar archive + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class MarkHeader extends BaseBlock { + + //private Log //logger = LogFactory.getLog(MarkHeader.class.getName()); + private boolean oldFormat = false; + + public MarkHeader(BaseBlock bb){ + super(bb); + } + public boolean isValid(){ + if(!(getHeadCRC() == 0x6152)){ + return false; + } + if(!(getHeaderType() == UnrarHeadertype.MarkHeader)){ + return false; + } + if(!(getFlags() == 0x1a21)){ + return false; + } + if(!(getHeaderSize() == BaseBlockSize)){ + return false; + } + return true; + } + + public boolean isSignature() { + boolean valid=false; + byte[] d = new byte[BaseBlock.BaseBlockSize]; + Raw.writeShortLittleEndian(d, 0, headCRC); + d[2] = headerType; + Raw.writeShortLittleEndian(d, 3, flags); + Raw.writeShortLittleEndian(d, 5, headerSize); + + if (d[0] == 0x52) { + if (d[1]==0x45 && d[2]==0x7e && d[3]==0x5e) { + oldFormat=true; + valid=true; + } + else if (d[1]==0x61 && d[2]==0x72 && d[3]==0x21 && d[4]==0x1a && + d[5]==0x07 && d[6]==0x00) { + oldFormat=false; + valid=true; + } + } + return valid; + } + + public boolean isOldFormat() { + return oldFormat; + } + + public void print(){ + super.print(); + //logger.info("valid: "+isValid()); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/NewSubHeaderType.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/NewSubHeaderType.java new file mode 100644 index 0000000..e0096f7 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/NewSubHeaderType.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import java.util.Arrays; + +/** + * subheaders new version of the info headers + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class NewSubHeaderType { + + /** + * comment subheader + */ + public static final NewSubHeaderType SUBHEAD_TYPE_CMT = new NewSubHeaderType(new byte[]{'C','M','T'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_ACL = new NewSubHeaderType(new byte[]{'A','C','L'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_STREAM = new NewSubHeaderType(new byte[]{'S','T','M'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_UOWNER = new NewSubHeaderType(new byte[]{'U','O','W'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_AV = new NewSubHeaderType(new byte[]{'A','V'}); + /** + * recovery record subheader + */ + public static final NewSubHeaderType SUBHEAD_TYPE_RR = new NewSubHeaderType(new byte[]{'R','R'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_OS2EA = new NewSubHeaderType(new byte[]{'E','A','2'}); + /** + * + */ + public static final NewSubHeaderType SUBHEAD_TYPE_BEOSEA = new NewSubHeaderType(new byte[]{'E','A','B','E'}); + + private byte[] headerTypes; + + /** + * Private constructor + * @param headerTypes + */ + private NewSubHeaderType(byte[] headerTypes) + { + this.headerTypes = headerTypes; + } + + /** + * @param toCompare + * @return Returns true if the given byte array matches to the internal byte array of this header. + */ + public boolean byteEquals(byte[] toCompare) + { + return Arrays.equals(this.headerTypes, toCompare); + } + + @Override + public String toString() + { + return new String(this.headerTypes); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/ProtectHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/ProtectHeader.java new file mode 100644 index 0000000..348b25b --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/ProtectHeader.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + +/** + * recovery header + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class ProtectHeader extends BlockHeader { + + /** + * the header size + */ + public static final int protectHeaderSize = 8; + + private byte version; + private short recSectors; + private int totalBlocks; + private byte mark; + + + public ProtectHeader(BlockHeader bh, byte[] protectHeader){ + super(bh); + + int pos = 0; + version |= protectHeader[pos]&0xff; + + recSectors = Raw.readShortLittleEndian(protectHeader, pos); + pos += 2; + totalBlocks = Raw.readIntLittleEndian(protectHeader, pos); + pos += 4; + mark |= protectHeader[pos]&0xff; + } + + + public byte getMark() { + return mark; + } + + public short getRecSectors() { + return recSectors; + } + + public int getTotalBlocks() { + return totalBlocks; + } + + public byte getVersion() { + return version; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SignHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SignHeader.java new file mode 100644 index 0000000..e78d4a3 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SignHeader.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 24.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + +/** + * sign header + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class SignHeader extends BaseBlock { + + public static final short signHeaderSize = 8; + + private int creationTime=0; + private short arcNameSize=0; + private short userNameSize=0; + + + public SignHeader(BaseBlock bb, byte[] signHeader){ + super(bb); + + int pos = 0; + creationTime = Raw.readIntLittleEndian(signHeader, pos); + pos +=4; + arcNameSize = Raw.readShortLittleEndian(signHeader, pos); + pos+=2; + userNameSize = Raw.readShortLittleEndian(signHeader, pos); + } + + public short getArcNameSize() { + return arcNameSize; + } + + public int getCreationTime() { + return creationTime; + } + + public short getUserNameSize() { + return userNameSize; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SubBlockHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SubBlockHeader.java new file mode 100644 index 0000000..d0e0eed --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SubBlockHeader.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 21.11.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + + +public class SubBlockHeader +extends BlockHeader +{ + //private Log //logger = LogFactory.getLog(getClass()); + + public static final short SubBlockHeaderSize = 3; + + private short subType; + private byte level; + + public SubBlockHeader(SubBlockHeader sb) + { + super(sb); + subType = sb.getSubType().getSubblocktype(); + level = sb.getLevel(); + } + + public SubBlockHeader(BlockHeader bh, byte[] subblock) + { + super(bh); + int position = 0; + subType = Raw.readShortLittleEndian(subblock, position); + position +=2; + level |= subblock[position]&0xff; + } + + /** + * @return + */ + public byte getLevel() { + return level; + } + + /** + * @return + */ + public SubBlockHeaderType getSubType() { + return SubBlockHeaderType.findSubblockHeaderType(subType); + } + + public void print() + { + super.print(); + //logger.info("subtype: "+getSubType()); + //logger.info("level: "+level); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SubBlockHeaderType.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SubBlockHeaderType.java new file mode 100644 index 0000000..000f24d --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/SubBlockHeaderType.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 20.11.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ + +package com.github.junrar.rarfile; + +public enum SubBlockHeaderType +{ + EA_HEAD ((short)0x100), + UO_HEAD ((short)0x101), + MAC_HEAD ((short)0x102), + BEEA_HEAD ((short)0x103), + NTACL_HEAD ((short)0x104), + STREAM_HEAD ((short)0x105); + + private short subblocktype; + + private SubBlockHeaderType(short subblocktype) + { + this.subblocktype = subblocktype; + } + + /** + * Return true if the given value is equal to the enum's value + * @param subblocktype + * @return true if the given value is equal to the enum's value + */ + public boolean equals(short subblocktype) + { + return this.subblocktype == subblocktype; + } + + /** + * find the header type for the given short value + * @param SubType the short value + * @return the correspo nding enum or null + */ + public static SubBlockHeaderType findSubblockHeaderType(short subType) + { + if(EA_HEAD.equals(subType)){ + return EA_HEAD; + }else if(UO_HEAD.equals(subType)){ + return UO_HEAD; + }else if(MAC_HEAD.equals(subType)){ + return MAC_HEAD; + }else if(BEEA_HEAD.equals(subType)){ + return BEEA_HEAD; + }else if(NTACL_HEAD.equals(subType)){ + return NTACL_HEAD; + }else if(STREAM_HEAD.equals(subType)){ + return STREAM_HEAD; + } + return null; + } + + /** + * @return the short representation of this enum + */ + public short getSubblocktype() { + return subblocktype; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/UnixOwnersHeader.java b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/UnixOwnersHeader.java new file mode 100644 index 0000000..192ba7a --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/rarfile/UnixOwnersHeader.java @@ -0,0 +1,93 @@ +package com.github.junrar.rarfile; + +import com.github.junrar.io.Raw; + + +public class UnixOwnersHeader +extends SubBlockHeader +{ + //private Log //logger = LogFactory.getLog(UnixOwnersHeader.class); + private int ownerNameSize; + private int groupNameSize; + private String owner; + private String group; + + public UnixOwnersHeader(SubBlockHeader sb, byte[] uoHeader) { + super(sb); + int pos = 0; + ownerNameSize = Raw.readShortLittleEndian(uoHeader, pos)&0xFFFF; + pos+=2; + groupNameSize = Raw.readShortLittleEndian(uoHeader, pos)&0xFFFF; + pos+=2; + if(pos+ownerNameSize": ">" or ">" + * "@": "@" + */ +package com.github.junrar.rarfile; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public enum UnrarHeadertype { + + + /** + * + */ + MainHeader ((byte)0x73), + + /** + * + */ + MarkHeader ((byte)0x72), + + /** + * + */ + FileHeader ((byte) 0x74), + + /** + * + */ + CommHeader ((byte) 0x75), + + /** + * + */ + AvHeader ((byte) 0x76), + + /** + * + */ + SubHeader ((byte) 0x77), + + /** + * + */ + ProtectHeader ((byte) 0x78), + + /** + * + */ + SignHeader ((byte) 0x79), + + /** + * + */ + NewSubHeader ((byte) 0x7a), + + /** + * + */ + EndArcHeader ((byte) 0x7b); + + /** + * Returns the enum according to the given byte or null + * @param headerType the headerbyte + * @return the enum or null + */ + public static UnrarHeadertype findType(byte headerType) + { + if(UnrarHeadertype.MarkHeader.equals(headerType)){ + return UnrarHeadertype.MarkHeader; + } + if(UnrarHeadertype.MainHeader.equals(headerType)){ + return UnrarHeadertype.MainHeader; + } + if(UnrarHeadertype.FileHeader.equals(headerType)){ + return UnrarHeadertype.FileHeader; + } + if(UnrarHeadertype.EndArcHeader.equals(headerType)){ + return UnrarHeadertype.EndArcHeader; + } + if(UnrarHeadertype.NewSubHeader.equals(headerType)){ + return UnrarHeadertype.NewSubHeader; + } + if(UnrarHeadertype.SubHeader.equals(headerType)){ + return UnrarHeadertype.SubHeader; + } + if(UnrarHeadertype.SignHeader.equals(headerType)){ + return UnrarHeadertype.SignHeader; + } + if(UnrarHeadertype.ProtectHeader.equals(headerType)){ + return UnrarHeadertype.ProtectHeader; + } + if(UnrarHeadertype.MarkHeader.equals(headerType)){ + return UnrarHeadertype.MarkHeader; + } + if(UnrarHeadertype.MainHeader.equals(headerType)){ + return UnrarHeadertype.MainHeader; + } + if(UnrarHeadertype.FileHeader.equals(headerType)){ + return UnrarHeadertype.FileHeader; + } + if(UnrarHeadertype.EndArcHeader.equals(headerType)){ + return UnrarHeadertype.EndArcHeader; + } + if(UnrarHeadertype.CommHeader.equals(headerType)){ + return UnrarHeadertype.CommHeader; + } + if(UnrarHeadertype.AvHeader.equals(headerType)){ + return UnrarHeadertype.AvHeader; + } + return null; + } + + + + private byte headerByte; + + private UnrarHeadertype(byte headerByte) + { + this.headerByte = headerByte; + } + + + /** + * Return true if the given byte is equal to the enum's byte + * @param header + * @return true if the given byte is equal to the enum's byte + */ + public boolean equals(byte header) + { + return headerByte == header; + } + + + /** + * the header byte of this enum + * @return the header byte of this enum + */ + public byte getHeaderByte() { + return headerByte; + } + + + + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ComprDataIO.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ComprDataIO.java new file mode 100644 index 0000000..8791b09 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ComprDataIO.java @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.github.junrar.Archive; +import com.github.junrar.UnrarCallback; +import com.github.junrar.Volume; +import com.github.junrar.crc.RarCRC; +import com.github.junrar.exception.RarException; +import com.github.junrar.exception.RarException.RarExceptionType; +import com.github.junrar.io.ReadOnlyAccessInputStream; +import com.github.junrar.rarfile.FileHeader; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class ComprDataIO { + + private final Archive archive; + + private long unpPackedSize; + + private boolean testMode; + + private boolean skipUnpCRC; + + private InputStream inputStream; + + private OutputStream outputStream; + + private FileHeader subHead; + + // cryptData Crypt; + // cryptData Decrypt; + private boolean packVolume; + + private boolean unpVolume; + + private boolean nextVolumeMissing; + + private long totalPackRead; + + private long unpArcSize; + + private long curPackRead, curPackWrite, curUnpRead, curUnpWrite; + + private long processedArcSize, totalArcSize; + + private long packFileCRC, unpFileCRC, packedCRC; + + private int encryption; + + private int decryption; + + private int lastPercent; + + private char currentCommand; + + public ComprDataIO(Archive arc) { + this.archive = arc; + } + + public void init(OutputStream outputStream) { + this.outputStream = outputStream; + unpPackedSize = 0; + testMode = false; + skipUnpCRC = false; + packVolume = false; + unpVolume = false; + nextVolumeMissing = false; + // command = null; + encryption = 0; + decryption = 0; + totalPackRead = 0; + curPackRead = curPackWrite = curUnpRead = curUnpWrite = 0; + packFileCRC = unpFileCRC = packedCRC = 0xffffffff; + lastPercent = -1; + subHead = null; + + currentCommand = 0; + processedArcSize = totalArcSize = 0; + } + + public void init(FileHeader hd) throws IOException { + long startPos = hd.getPositionInFile() + hd.getHeaderSize(); + unpPackedSize = hd.getFullPackSize(); + inputStream = new ReadOnlyAccessInputStream(archive.getRof(), startPos, + startPos + unpPackedSize); + subHead = hd; + curUnpRead = 0; + curPackWrite = 0; + packedCRC = 0xFFffFFff; + } + + public int unpRead(byte[] addr, int offset, int count) throws IOException, + RarException { + int retCode = 0, totalRead = 0; + while (count > 0) { + int readSize = (count > unpPackedSize) ? (int) unpPackedSize + : count; + retCode = inputStream.read(addr, offset, readSize); + if (retCode < 0) { + throw new EOFException(); + } + if (subHead.isSplitAfter()) { + packedCRC = RarCRC.checkCrc((int) packedCRC, addr, offset, + retCode); + } + + curUnpRead += retCode; + totalRead += retCode; + offset += retCode; + count -= retCode; + unpPackedSize -= retCode; + archive.bytesReadRead(retCode); + if (unpPackedSize == 0 && subHead.isSplitAfter()) { + Volume nextVolume = archive.getVolumeManager().nextArchive( + archive, archive.getVolume()); + if (nextVolume == null) { + nextVolumeMissing = true; + return -1; + } + + FileHeader hd = this.getSubHeader(); + if (hd.getUnpVersion() >= 20 && hd.getFileCRC() != 0xffffffff + && this.getPackedCRC() != ~hd.getFileCRC()) { + throw new RarException(RarExceptionType.crcError); + } + UnrarCallback callback = archive.getUnrarCallback(); + if ((callback != null) + && !callback.isNextVolumeReady(nextVolume)) { + return -1; + } + archive.setVolume(nextVolume); + hd = archive.nextFileHeader(); + if (hd == null) { + return -1; + } + this.init(hd); + } else { + break; + } + } + + if (retCode != -1) { + retCode = totalRead; + } + return retCode; + + } + + public void unpWrite(byte[] addr, int offset, int count) throws IOException { + if (!testMode) { + // DestFile->Write(Addr,Count); + outputStream.write(addr, offset, count); + } + + curUnpWrite += count; + + if (!skipUnpCRC) { + if (archive.isOldFormat()) { + unpFileCRC = RarCRC + .checkOldCrc((short) unpFileCRC, addr, count); + } else { + unpFileCRC = RarCRC.checkCrc((int) unpFileCRC, addr, offset, + count); + } + } + // if (!skipArcCRC) { + // archive.updateDataCRC(Addr, offset, ReadSize); + // } + } + + public void setPackedSizeToRead(long size) { + unpPackedSize = size; + } + + public void setTestMode(boolean mode) { + testMode = mode; + } + + public void setSkipUnpCRC(boolean skip) { + skipUnpCRC = skip; + } + + public void setSubHeader(FileHeader hd) { + subHead = hd; + + } + + public long getCurPackRead() { + return curPackRead; + } + + public void setCurPackRead(long curPackRead) { + this.curPackRead = curPackRead; + } + + public long getCurPackWrite() { + return curPackWrite; + } + + public void setCurPackWrite(long curPackWrite) { + this.curPackWrite = curPackWrite; + } + + public long getCurUnpRead() { + return curUnpRead; + } + + public void setCurUnpRead(long curUnpRead) { + this.curUnpRead = curUnpRead; + } + + public long getCurUnpWrite() { + return curUnpWrite; + } + + public void setCurUnpWrite(long curUnpWrite) { + this.curUnpWrite = curUnpWrite; + } + + public int getDecryption() { + return decryption; + } + + public void setDecryption(int decryption) { + this.decryption = decryption; + } + + public int getEncryption() { + return encryption; + } + + public void setEncryption(int encryption) { + this.encryption = encryption; + } + + public boolean isNextVolumeMissing() { + return nextVolumeMissing; + } + + public void setNextVolumeMissing(boolean nextVolumeMissing) { + this.nextVolumeMissing = nextVolumeMissing; + } + + public long getPackedCRC() { + return packedCRC; + } + + public void setPackedCRC(long packedCRC) { + this.packedCRC = packedCRC; + } + + public long getPackFileCRC() { + return packFileCRC; + } + + public void setPackFileCRC(long packFileCRC) { + this.packFileCRC = packFileCRC; + } + + public boolean isPackVolume() { + return packVolume; + } + + public void setPackVolume(boolean packVolume) { + this.packVolume = packVolume; + } + + public long getProcessedArcSize() { + return processedArcSize; + } + + public void setProcessedArcSize(long processedArcSize) { + this.processedArcSize = processedArcSize; + } + + public long getTotalArcSize() { + return totalArcSize; + } + + public void setTotalArcSize(long totalArcSize) { + this.totalArcSize = totalArcSize; + } + + public long getTotalPackRead() { + return totalPackRead; + } + + public void setTotalPackRead(long totalPackRead) { + this.totalPackRead = totalPackRead; + } + + public long getUnpArcSize() { + return unpArcSize; + } + + public void setUnpArcSize(long unpArcSize) { + this.unpArcSize = unpArcSize; + } + + public long getUnpFileCRC() { + return unpFileCRC; + } + + public void setUnpFileCRC(long unpFileCRC) { + this.unpFileCRC = unpFileCRC; + } + + public boolean isUnpVolume() { + return unpVolume; + } + + public void setUnpVolume(boolean unpVolume) { + this.unpVolume = unpVolume; + } + + public FileHeader getSubHeader() { + return subHead; + } + + // public void setEncryption(int method, char[] Password, byte[] Salt, + // boolean encrypt, boolean handsOffHash) + // { + // + // } + // + // public void setAV15Encryption() + // { + // + // } + // + // public void setCmt13Encryption() + // { + // + // } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack.java new file mode 100644 index 0000000..fdf5eb4 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack.java @@ -0,0 +1,1051 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Vector; + +import com.github.junrar.exception.RarException; +import com.github.junrar.unpack.decode.Compress; +import com.github.junrar.unpack.ppm.BlockTypes; +import com.github.junrar.unpack.ppm.ModelPPM; +import com.github.junrar.unpack.ppm.SubAllocator; +import com.github.junrar.unpack.vm.BitInput; +import com.github.junrar.unpack.vm.RarVM; +import com.github.junrar.unpack.vm.VMPreparedProgram; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public final class Unpack extends Unpack20 { + + private final ModelPPM ppm = new ModelPPM(); + + private int ppmEscChar; + + private RarVM rarVM = new RarVM(); + + /* Filters code, one entry per filter */ + private List filters = new ArrayList(); + + /* Filters stack, several entrances of same filter are possible */ + private List prgStack = new ArrayList(); + + /* + * lengths of preceding blocks, one length per filter. Used to reduce size + * required to write block length if lengths are repeating + */ + private List oldFilterLengths = new ArrayList(); + + private int lastFilter; + + private boolean tablesRead; + + private byte[] unpOldTable = new byte[Compress.HUFF_TABLE_SIZE]; + + private BlockTypes unpBlockType; + + private boolean externalWindow; + + private long writtenFileSize; + + private boolean fileExtracted; + + private boolean ppmError; + + private int prevLowDist; + + private int lowDistRepCount; + + public static int[] DBitLengthCounts = { 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 14, 0, 12 }; + + public Unpack(ComprDataIO DataIO) { + unpIO = DataIO; + window = null; + externalWindow = false; + suspended = false; + unpAllBuf = false; + unpSomeRead = false; + } + + public void init(byte[] window) { + if (window == null) { + this.window = new byte[Compress.MAXWINSIZE]; + } else { + this.window = window; + externalWindow = true; + } + inAddr = 0; + unpInitData(false); + } + + public void doUnpack(int method, boolean solid) throws IOException, + RarException { + if (unpIO.getSubHeader().getUnpMethod() == 0x30) { + unstoreFile(); + } + switch (method) { + case 15: // rar 1.5 compression + unpack15(solid); + break; + case 20: // rar 2.x compression + case 26: // files larger than 2GB + unpack20(solid); + break; + case 29: // rar 3.x compression + case 36: // alternative hash + unpack29(solid); + break; + } + } + + private void unstoreFile() throws IOException, RarException { + byte[] buffer = new byte[0x10000]; + while (true) { + int code = unpIO.unpRead(buffer, 0, (int) Math.min(buffer.length, + destUnpSize)); + if (code == 0 || code == -1) + break; + code = code < destUnpSize ? code : (int) destUnpSize; + unpIO.unpWrite(buffer, 0, code); + if (destUnpSize >= 0) + destUnpSize -= code; + } + + } + + private void unpack29(boolean solid) throws IOException, RarException { + + int[] DDecode = new int[Compress.DC]; + byte[] DBits = new byte[Compress.DC]; + + int Bits; + + if (DDecode[1] == 0) { + int Dist = 0, BitLength = 0, Slot = 0; + for (int I = 0; I < DBitLengthCounts.length; I++, BitLength++) { + int count = DBitLengthCounts[I]; + for (int J = 0; J < count; J++, Slot++, Dist += (1 << BitLength)) { + DDecode[Slot] = Dist; + DBits[Slot] = (byte) BitLength; + } + } + } + + fileExtracted = true; + + if (!suspended) { + unpInitData(solid); + if (!unpReadBuf()) { + return; + } + if ((!solid || !tablesRead) && !readTables()) { + return; + } + } + + if (ppmError) { + return; + } + + while (true) { + unpPtr &= Compress.MAXWINMASK; + + if (inAddr > readBorder) { + if (!unpReadBuf()) { + break; + } + } + // System.out.println(((wrPtr - unpPtr) & + // Compress.MAXWINMASK)+":"+wrPtr+":"+unpPtr); + if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 260 + && wrPtr != unpPtr) { + + UnpWriteBuf(); + if (writtenFileSize > destUnpSize) { + return; + } + if (suspended) { + fileExtracted = false; + return; + } + } + if (unpBlockType == BlockTypes.BLOCK_PPM) { + int Ch = ppm.decodeChar(); + if (Ch == -1) { + ppmError = true; + break; + } + if (Ch == ppmEscChar) { + int NextCh = ppm.decodeChar(); + if (NextCh == 0) { + if (!readTables()) { + break; + } + continue; + } + if (NextCh == 2 || NextCh == -1) { + break; + } + if (NextCh == 3) { + if (!readVMCodePPM()) { + break; + } + continue; + } + if (NextCh == 4) { + int Distance = 0, Length = 0; + boolean failed = false; + for (int I = 0; I < 4 && !failed; I++) { + int ch = ppm.decodeChar(); + if (ch == -1) { + failed = true; + } else { + if (I == 3) { + // Bug fixed + Length = ch & 0xff; + } else { + // Bug fixed + Distance = (Distance << 8) + (ch & 0xff); + } + } + } + if (failed) { + break; + } + copyString(Length + 32, Distance + 2); + continue; + } + if (NextCh == 5) { + int Length = ppm.decodeChar(); + if (Length == -1) { + break; + } + copyString(Length + 4, 1); + continue; + } + } + window[unpPtr++] = (byte) Ch; + continue; + } + + int Number = decodeNumber(LD); + if (Number < 256) { + window[unpPtr++] = (byte) Number; + continue; + } + if (Number >= 271) { + int Length = LDecode[Number -= 271] + 3; + if ((Bits = LBits[Number]) > 0) { + Length += getbits() >>> (16 - Bits); + addbits(Bits); + } + + int DistNumber = decodeNumber(DD); + int Distance = DDecode[DistNumber] + 1; + if ((Bits = DBits[DistNumber]) > 0) { + if (DistNumber > 9) { + if (Bits > 4) { + Distance += ((getbits() >>> (20 - Bits)) << 4); + addbits(Bits - 4); + } + if (lowDistRepCount > 0) { + lowDistRepCount--; + Distance += prevLowDist; + } else { + int LowDist = decodeNumber(LDD); + if (LowDist == 16) { + lowDistRepCount = Compress.LOW_DIST_REP_COUNT - 1; + Distance += prevLowDist; + } else { + Distance += LowDist; + prevLowDist = LowDist; + } + } + } else { + Distance += getbits() >>> (16 - Bits); + addbits(Bits); + } + } + + if (Distance >= 0x2000) { + Length++; + if (Distance >= 0x40000L) { + Length++; + } + } + + insertOldDist(Distance); + insertLastMatch(Length, Distance); + + copyString(Length, Distance); + continue; + } + if (Number == 256) { + if (!readEndOfBlock()) { + break; + } + continue; + } + if (Number == 257) { + if (!readVMCode()) { + break; + } + continue; + } + if (Number == 258) { + if (lastLength != 0) { + copyString(lastLength, lastDist); + } + continue; + } + if (Number < 263) { + int DistNum = Number - 259; + int Distance = oldDist[DistNum]; + for (int I = DistNum; I > 0; I--) { + oldDist[I] = oldDist[I - 1]; + } + oldDist[0] = Distance; + + int LengthNumber = decodeNumber(RD); + int Length = LDecode[LengthNumber] + 2; + if ((Bits = LBits[LengthNumber]) > 0) { + Length += getbits() >>> (16 - Bits); + addbits(Bits); + } + insertLastMatch(Length, Distance); + copyString(Length, Distance); + continue; + } + if (Number < 272) { + int Distance = SDDecode[Number -= 263] + 1; + if ((Bits = SDBits[Number]) > 0) { + Distance += getbits() >>> (16 - Bits); + addbits(Bits); + } + insertOldDist(Distance); + insertLastMatch(2, Distance); + copyString(2, Distance); + continue; + } + } + UnpWriteBuf(); + + } + + private void UnpWriteBuf() throws IOException { + int WrittenBorder = wrPtr; + int WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; + for (int I = 0; I < prgStack.size(); I++) { + UnpackFilter flt = prgStack.get(I); + if (flt == null) { + continue; + } + if (flt.isNextWindow()) { + flt.setNextWindow(false);// ->NextWindow=false; + continue; + } + int BlockStart = flt.getBlockStart();// ->BlockStart; + int BlockLength = flt.getBlockLength();// ->BlockLength; + if (((BlockStart - WrittenBorder) & Compress.MAXWINMASK) < WriteSize) { + if (WrittenBorder != BlockStart) { + UnpWriteArea(WrittenBorder, BlockStart); + WrittenBorder = BlockStart; + WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; + } + if (BlockLength <= WriteSize) { + int BlockEnd = (BlockStart + BlockLength) + & Compress.MAXWINMASK; + if (BlockStart < BlockEnd || BlockEnd == 0) { + // VM.SetMemory(0,Window+BlockStart,BlockLength); + rarVM.setMemory(0, window, BlockStart, BlockLength); + } else { + int FirstPartLength = Compress.MAXWINSIZE - BlockStart; + // VM.SetMemory(0,Window+BlockStart,FirstPartLength); + rarVM.setMemory(0, window, BlockStart, FirstPartLength); + // VM.SetMemory(FirstPartLength,Window,BlockEnd); + rarVM.setMemory(FirstPartLength, window, 0, BlockEnd); + + } + + VMPreparedProgram ParentPrg = filters.get( + flt.getParentFilter()).getPrg(); + VMPreparedProgram Prg = flt.getPrg(); + + if (ParentPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) { + // copy global data from previous script execution if + // any + // Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + // memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + Prg.getGlobalData().setSize( + ParentPrg.getGlobalData().size()); + for (int i = 0; i < ParentPrg.getGlobalData().size() + - RarVM.VM_FIXEDGLOBALSIZE; i++) { + Prg.getGlobalData().set( + RarVM.VM_FIXEDGLOBALSIZE + i, + ParentPrg.getGlobalData().get( + RarVM.VM_FIXEDGLOBALSIZE + i)); + } + } + + ExecuteCode(Prg); + + if (Prg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) { + // save global data for next script execution + if (ParentPrg.getGlobalData().size() < Prg + .getGlobalData().size()) { + ParentPrg.getGlobalData().setSize( + Prg.getGlobalData().size());// ->GlobalData.Alloc(Prg->GlobalData.Size()); + } + // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for (int i = 0; i < Prg.getGlobalData().size() + - RarVM.VM_FIXEDGLOBALSIZE; i++) { + ParentPrg.getGlobalData().set( + RarVM.VM_FIXEDGLOBALSIZE + i, + Prg.getGlobalData().get( + RarVM.VM_FIXEDGLOBALSIZE + i)); + } + } else { + ParentPrg.getGlobalData().clear(); + } + + int FilteredDataOffset = Prg.getFilteredDataOffset(); + int FilteredDataSize = Prg.getFilteredDataSize(); + byte[] FilteredData = new byte[FilteredDataSize]; + + for (int i = 0; i < FilteredDataSize; i++) { + FilteredData[i] = rarVM.getMem()[FilteredDataOffset + i];// Prg.getGlobalData().get(FilteredDataOffset + // + + // i); + } + + prgStack.set(I, null); + while (I + 1 < prgStack.size()) { + UnpackFilter NextFilter = prgStack.get(I + 1); + if (NextFilter == null + || NextFilter.getBlockStart() != BlockStart + || NextFilter.getBlockLength() != FilteredDataSize + || NextFilter.isNextWindow()) { + break; + } + // apply several filters to same data block + + rarVM.setMemory(0, FilteredData, 0, FilteredDataSize);// .SetMemory(0,FilteredData,FilteredDataSize); + + VMPreparedProgram pPrg = filters.get( + NextFilter.getParentFilter()).getPrg(); + VMPreparedProgram NextPrg = NextFilter.getPrg(); + + if (pPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) { + // copy global data from previous script execution + // if any + // NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + NextPrg.getGlobalData().setSize( + pPrg.getGlobalData().size()); + // memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for (int i = 0; i < pPrg.getGlobalData().size() + - RarVM.VM_FIXEDGLOBALSIZE; i++) { + NextPrg.getGlobalData().set( + RarVM.VM_FIXEDGLOBALSIZE + i, + pPrg.getGlobalData().get( + RarVM.VM_FIXEDGLOBALSIZE + i)); + } + } + + ExecuteCode(NextPrg); + + if (NextPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) { + // save global data for next script execution + if (pPrg.getGlobalData().size() < NextPrg + .getGlobalData().size()) { + pPrg.getGlobalData().setSize( + NextPrg.getGlobalData().size()); + } + // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for (int i = 0; i < NextPrg.getGlobalData().size() + - RarVM.VM_FIXEDGLOBALSIZE; i++) { + pPrg.getGlobalData().set( + RarVM.VM_FIXEDGLOBALSIZE + i, + NextPrg.getGlobalData().get( + RarVM.VM_FIXEDGLOBALSIZE + i)); + } + } else { + pPrg.getGlobalData().clear(); + } + FilteredDataOffset = NextPrg.getFilteredDataOffset(); + FilteredDataSize = NextPrg.getFilteredDataSize(); + + FilteredData = new byte[FilteredDataSize]; + for (int i = 0; i < FilteredDataSize; i++) { + FilteredData[i] = NextPrg.getGlobalData().get( + FilteredDataOffset + i); + } + + I++; + prgStack.set(I, null); + } + unpIO.unpWrite(FilteredData, 0, FilteredDataSize); + unpSomeRead = true; + writtenFileSize += FilteredDataSize; + WrittenBorder = BlockEnd; + WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; + } else { + for (int J = I; J < prgStack.size(); J++) { + UnpackFilter filt = prgStack.get(J); + if (filt != null && filt.isNextWindow()) { + filt.setNextWindow(false); + } + } + wrPtr = WrittenBorder; + return; + } + } + } + + UnpWriteArea(WrittenBorder, unpPtr); + wrPtr = unpPtr; + + } + + private void UnpWriteArea(int startPtr, int endPtr) throws IOException { + if (endPtr != startPtr) { + unpSomeRead = true; + } + if (endPtr < startPtr) { + UnpWriteData(window, startPtr, -startPtr & Compress.MAXWINMASK); + UnpWriteData(window, 0, endPtr); + unpAllBuf = true; + } else { + UnpWriteData(window, startPtr, endPtr - startPtr); + } + } + + private void UnpWriteData(byte[] data, int offset, int size) + throws IOException { + if (writtenFileSize >= destUnpSize) { + return; + } + int writeSize = size; + long leftToWrite = destUnpSize - writtenFileSize; + if (writeSize > leftToWrite) { + writeSize = (int) leftToWrite; + } + unpIO.unpWrite(data, offset, writeSize); + + writtenFileSize += size; + + } + + private void insertOldDist(int distance) { + oldDist[3] = oldDist[2]; + oldDist[2] = oldDist[1]; + oldDist[1] = oldDist[0]; + oldDist[0] = distance; + } + + private void insertLastMatch(int length, int distance) { + lastDist = distance; + lastLength = length; + } + + private void copyString(int length, int distance) { + // System.out.println("copyString(" + length + ", " + distance + ")"); + + int destPtr = unpPtr - distance; + // System.out.println(unpPtr+":"+distance); + if (destPtr >= 0 && destPtr < Compress.MAXWINSIZE - 260 + && unpPtr < Compress.MAXWINSIZE - 260) { + + window[unpPtr++] = window[destPtr++]; + + while (--length > 0) + + window[unpPtr++] = window[destPtr++]; + } else + while (length-- != 0) { + window[unpPtr] = window[destPtr++ & Compress.MAXWINMASK]; + unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; + } + } + + protected void unpInitData(boolean solid) { + if (!solid) { + tablesRead = false; + Arrays.fill(oldDist, 0); // memset(oldDist,0,sizeof(OldDist)); + + oldDistPtr = 0; + lastDist = 0; + lastLength = 0; + + Arrays.fill(unpOldTable, (byte) 0);// memset(UnpOldTable,0,sizeof(UnpOldTable)); + + unpPtr = 0; + wrPtr = 0; + ppmEscChar = 2; + + initFilters(); + } + InitBitInput(); + ppmError = false; + writtenFileSize = 0; + readTop = 0; + readBorder = 0; + unpInitData20(solid); + } + + private void initFilters() { + oldFilterLengths.clear(); + lastFilter = 0; + + filters.clear(); + + prgStack.clear(); + } + + private boolean readEndOfBlock() throws IOException, RarException { + int BitField = getbits(); + boolean NewTable, NewFile = false; + if ((BitField & 0x8000) != 0) { + NewTable = true; + addbits(1); + } else { + NewFile = true; + NewTable = (BitField & 0x4000) != 0 ? true : false; + addbits(2); + } + tablesRead = !NewTable; + return !(NewFile || NewTable && !readTables()); + } + + private boolean readTables() throws IOException, RarException { + byte[] bitLength = new byte[Compress.BC]; + + byte[] table = new byte[Compress.HUFF_TABLE_SIZE]; + if (inAddr > readTop - 25) { + if (!unpReadBuf()) { + return (false); + } + } + faddbits((8 - inBit) & 7); + long bitField = fgetbits() & 0xffFFffFF; + if ((bitField & 0x8000) != 0) { + unpBlockType = BlockTypes.BLOCK_PPM; + return (ppm.decodeInit(this, ppmEscChar)); + } + unpBlockType = BlockTypes.BLOCK_LZ; + + prevLowDist = 0; + lowDistRepCount = 0; + + if ((bitField & 0x4000) == 0) { + Arrays.fill(unpOldTable, (byte) 0);// memset(UnpOldTable,0,sizeof(UnpOldTable)); + } + faddbits(2); + + for (int i = 0; i < Compress.BC; i++) { + int length = (fgetbits() >>> 12) & 0xFF; + faddbits(4); + if (length == 15) { + int zeroCount = (fgetbits() >>> 12) & 0xFF; + faddbits(4); + if (zeroCount == 0) { + bitLength[i] = 15; + } else { + zeroCount += 2; + while (zeroCount-- > 0 && i < bitLength.length) { + bitLength[i++] = 0; + } + i--; + } + } else { + bitLength[i] = (byte) length; + } + } + + makeDecodeTables(bitLength, 0, BD, Compress.BC); + + int TableSize = Compress.HUFF_TABLE_SIZE; + + for (int i = 0; i < TableSize;) { + if (inAddr > readTop - 5) { + if (!unpReadBuf()) { + return (false); + } + } + int Number = decodeNumber(BD); + if (Number < 16) { + table[i] = (byte) ((Number + unpOldTable[i]) & 0xf); + i++; + } else if (Number < 18) { + int N; + if (Number == 16) { + N = (fgetbits() >>> 13) + 3; + faddbits(3); + } else { + N = (fgetbits() >>> 9) + 11; + faddbits(7); + } + while (N-- > 0 && i < TableSize) { + table[i] = table[i - 1]; + i++; + } + } else { + int N; + if (Number == 18) { + N = (fgetbits() >>> 13) + 3; + faddbits(3); + } else { + N = (fgetbits() >>> 9) + 11; + faddbits(7); + } + while (N-- > 0 && i < TableSize) { + table[i++] = 0; + } + } + } + tablesRead = true; + if (inAddr > readTop) { + return (false); + } + makeDecodeTables(table, 0, LD, Compress.NC); + makeDecodeTables(table, Compress.NC, DD, Compress.DC); + makeDecodeTables(table, Compress.NC + Compress.DC, LDD, Compress.LDC); + makeDecodeTables(table, Compress.NC + Compress.DC + Compress.LDC, RD, + Compress.RC); + + // memcpy(unpOldTable,table,sizeof(unpOldTable)); + for (int i = 0; i < unpOldTable.length; i++) { + unpOldTable[i] = table[i]; + } + return (true); + + } + + private boolean readVMCode() throws IOException, RarException { + int FirstByte = getbits() >> 8; + addbits(8); + int Length = (FirstByte & 7) + 1; + if (Length == 7) { + Length = (getbits() >> 8) + 7; + addbits(8); + } else if (Length == 8) { + Length = getbits(); + addbits(16); + } + List vmCode = new ArrayList(); + for (int I = 0; I < Length; I++) { + if (inAddr >= readTop - 1 && !unpReadBuf() && I < Length - 1) { + return (false); + } + vmCode.add(Byte.valueOf((byte) (getbits() >> 8))); + addbits(8); + } + return (addVMCode(FirstByte, vmCode, Length)); + } + + private boolean readVMCodePPM() throws IOException, RarException { + int FirstByte = ppm.decodeChar(); + if ((int) FirstByte == -1) { + return (false); + } + int Length = (FirstByte & 7) + 1; + if (Length == 7) { + int B1 = ppm.decodeChar(); + if (B1 == -1) { + return (false); + } + Length = B1 + 7; + } else if (Length == 8) { + int B1 = ppm.decodeChar(); + if (B1 == -1) { + return (false); + } + int B2 = ppm.decodeChar(); + if (B2 == -1) { + return (false); + } + Length = B1 * 256 + B2; + } + List vmCode = new ArrayList(); + for (int I = 0; I < Length; I++) { + int Ch = ppm.decodeChar(); + if (Ch == -1) { + return (false); + } + vmCode.add(Byte.valueOf((byte) Ch));// VMCode[I]=Ch; + } + return (addVMCode(FirstByte, vmCode, Length)); + } + + private boolean addVMCode(int firstByte, List vmCode, int length) { + BitInput Inp = new BitInput(); + Inp.InitBitInput(); + // memcpy(Inp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize)); + for (int i = 0; i < Math.min(BitInput.MAX_SIZE, vmCode.size()); i++) { + Inp.getInBuf()[i] = vmCode.get(i); + } + rarVM.init(); + + int FiltPos; + if ((firstByte & 0x80) != 0) { + FiltPos = RarVM.ReadData(Inp); + if (FiltPos == 0) { + initFilters(); + } else { + FiltPos--; + } + } else + FiltPos = lastFilter; // use the same filter as last time + + if (FiltPos > filters.size() || FiltPos > oldFilterLengths.size()) { + return (false); + } + lastFilter = FiltPos; + boolean NewFilter = (FiltPos == filters.size()); + + UnpackFilter StackFilter = new UnpackFilter(); // new filter for + // PrgStack + + UnpackFilter Filter; + if (NewFilter) // new filter code, never used before since VM reset + { + // too many different filters, corrupt archive + if (FiltPos > 1024) { + return (false); + } + + // Filters[Filters.Size()-1]=Filter=new UnpackFilter; + Filter = new UnpackFilter(); + filters.add(Filter); + StackFilter.setParentFilter(filters.size() - 1); + oldFilterLengths.add(0); + Filter.setExecCount(0); + } else // filter was used in the past + { + Filter = filters.get(FiltPos); + StackFilter.setParentFilter(FiltPos); + Filter.setExecCount(Filter.getExecCount() + 1);// ->ExecCount++; + } + + prgStack.add(StackFilter); + StackFilter.setExecCount(Filter.getExecCount());// ->ExecCount; + + int BlockStart = RarVM.ReadData(Inp); + if ((firstByte & 0x40) != 0) { + BlockStart += 258; + } + StackFilter.setBlockStart((BlockStart + unpPtr) & Compress.MAXWINMASK); + if ((firstByte & 0x20) != 0) { + StackFilter.setBlockLength(RarVM.ReadData(Inp)); + } else { + StackFilter + .setBlockLength(FiltPos < oldFilterLengths.size() ? oldFilterLengths + .get(FiltPos) + : 0); + } + StackFilter.setNextWindow((wrPtr != unpPtr) + && ((wrPtr - unpPtr) & Compress.MAXWINMASK) <= BlockStart); + + // DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x + // BlockStart=%08x",UnpPtr,WrPtr,BlockStart); + + oldFilterLengths.set(FiltPos, StackFilter.getBlockLength()); + + // memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR)); + Arrays.fill(StackFilter.getPrg().getInitR(), 0); + StackFilter.getPrg().getInitR()[3] = RarVM.VM_GLOBALMEMADDR;// StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR; + StackFilter.getPrg().getInitR()[4] = StackFilter.getBlockLength();// StackFilter->Prg.InitR[4]=StackFilter->BlockLength; + StackFilter.getPrg().getInitR()[5] = StackFilter.getExecCount();// StackFilter->Prg.InitR[5]=StackFilter->ExecCount; + + if ((firstByte & 0x10) != 0) // set registers to optional parameters + // if any + { + int InitMask = Inp.fgetbits() >>> 9; + Inp.faddbits(7); + for (int I = 0; I < 7; I++) { + if ((InitMask & (1 << I)) != 0) { + // StackFilter->Prg.InitR[I]=RarVM::ReadData(Inp); + StackFilter.getPrg().getInitR()[I] = RarVM.ReadData(Inp); + } + } + } + + if (NewFilter) { + int VMCodeSize = RarVM.ReadData(Inp); + if (VMCodeSize >= 0x10000 || VMCodeSize == 0) { + return (false); + } + byte[] VMCode = new byte[VMCodeSize]; + for (int I = 0; I < VMCodeSize; I++) { + if (Inp.Overflow(3)) { + return (false); + } + VMCode[I] = (byte) (Inp.fgetbits() >> 8); + Inp.faddbits(8); + } + // VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); + rarVM.prepare(VMCode, VMCodeSize, Filter.getPrg()); + } + StackFilter.getPrg().setAltCmd(Filter.getPrg().getCmd());// StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0]; + StackFilter.getPrg().setCmdCount(Filter.getPrg().getCmdCount());// StackFilter->Prg.CmdCount=Filter->Prg.CmdCount; + + int StaticDataSize = Filter.getPrg().getStaticData().size(); + if (StaticDataSize > 0 && StaticDataSize < RarVM.VM_GLOBALMEMSIZE) { + // read statically defined data contained in DB commands + // StackFilter->Prg.StaticData.Add(StaticDataSize); + StackFilter.getPrg().setStaticData(Filter.getPrg().getStaticData()); + // memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize); + } + + if (StackFilter.getPrg().getGlobalData().size() < RarVM.VM_FIXEDGLOBALSIZE) { + // StackFilter->Prg.GlobalData.Reset(); + // StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE); + StackFilter.getPrg().getGlobalData().clear(); + StackFilter.getPrg().getGlobalData().setSize( + RarVM.VM_FIXEDGLOBALSIZE); + } + + // byte *GlobalData=&StackFilter->Prg.GlobalData[0]; + Vector globalData = StackFilter.getPrg().getGlobalData(); + for (int I = 0; I < 7; I++) { + rarVM.setLowEndianValue(globalData, I * 4, StackFilter.getPrg() + .getInitR()[I]); + } + + // VM.SetLowEndianValue((uint + // *)&GlobalData[0x1c],StackFilter->BlockLength); + rarVM.setLowEndianValue(globalData, 0x1c, StackFilter.getBlockLength()); + // VM.SetLowEndianValue((uint *)&GlobalData[0x20],0); + rarVM.setLowEndianValue(globalData, 0x20, 0); + rarVM.setLowEndianValue(globalData, 0x24, 0); + rarVM.setLowEndianValue(globalData, 0x28, 0); + + // VM.SetLowEndianValue((uint + // *)&GlobalData[0x2c],StackFilter->ExecCount); + rarVM.setLowEndianValue(globalData, 0x2c, StackFilter.getExecCount()); + // memset(&GlobalData[0x30],0,16); + for (int i = 0; i < 16; i++) { + globalData.set(0x30 + i, Byte.valueOf((byte) (0))); + } + if ((firstByte & 8) != 0) // put data block passed as parameter if any + { + if (Inp.Overflow(3)) { + return (false); + } + int DataSize = RarVM.ReadData(Inp); + if (DataSize > RarVM.VM_GLOBALMEMSIZE - RarVM.VM_FIXEDGLOBALSIZE) { + return (false); + } + int CurSize = StackFilter.getPrg().getGlobalData().size(); + if (CurSize < DataSize + RarVM.VM_FIXEDGLOBALSIZE) { + // StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); + StackFilter.getPrg().getGlobalData().setSize( + DataSize + RarVM.VM_FIXEDGLOBALSIZE - CurSize); + } + int offset = RarVM.VM_FIXEDGLOBALSIZE; + globalData = StackFilter.getPrg().getGlobalData(); + for (int I = 0; I < DataSize; I++) { + if (Inp.Overflow(3)) { + return (false); + } + globalData.set(offset + I, Byte + .valueOf((byte) (Inp.fgetbits() >>> 8))); + Inp.faddbits(8); + } + } + return (true); + } + + private void ExecuteCode(VMPreparedProgram Prg) { + if (Prg.getGlobalData().size() > 0) { + // Prg->InitR[6]=int64to32(WrittenFileSize); + Prg.getInitR()[6] = (int) (writtenFileSize); + // rarVM.SetLowEndianValue((uint + // *)&Prg->GlobalData[0x24],int64to32(WrittenFileSize)); + rarVM.setLowEndianValue(Prg.getGlobalData(), 0x24, + (int) writtenFileSize); + // rarVM.SetLowEndianValue((uint + // *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>32)); + rarVM.setLowEndianValue(Prg.getGlobalData(), 0x28, + (int) (writtenFileSize >>> 32)); + rarVM.execute(Prg); + } + } + + // Duplicate method + // private boolean ReadEndOfBlock() throws IOException, RarException + // { + // int BitField = getbits(); + // boolean NewTable, NewFile = false; + // if ((BitField & 0x8000) != 0) { + // NewTable = true; + // addbits(1); + // } else { + // NewFile = true; + // NewTable = (BitField & 0x4000) != 0; + // addbits(2); + // } + // tablesRead = !NewTable; + // return !(NewFile || NewTable && !readTables()); + // } + + public boolean isFileExtracted() { + return fileExtracted; + } + + public void setDestSize(long destSize) { + this.destUnpSize = destSize; + this.fileExtracted = false; + } + + public void setSuspended(boolean suspended) { + this.suspended = suspended; + } + + public int getChar() throws IOException, RarException { + if (inAddr > BitInput.MAX_SIZE - 30) { + unpReadBuf(); + } + return (inBuf[inAddr++] & 0xff); + } + + public int getPpmEscChar() { + return ppmEscChar; + } + + public void setPpmEscChar(int ppmEscChar) { + this.ppmEscChar = ppmEscChar; + } + + public void cleanUp() { + if (ppm != null) { + SubAllocator allocator = ppm.getSubAlloc(); + if (allocator != null) { + allocator.stopSubAllocator(); + } + } + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack15.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack15.java new file mode 100644 index 0000000..d365cc6 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack15.java @@ -0,0 +1,620 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 21.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack; + +import java.io.IOException; +import java.util.Arrays; + +import com.github.junrar.exception.RarException; +import com.github.junrar.unpack.decode.Compress; +import com.github.junrar.unpack.vm.BitInput; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public abstract class Unpack15 extends BitInput +{ + + protected int readBorder; + + protected boolean suspended; + + protected boolean unpAllBuf; + + protected ComprDataIO unpIO; + + protected boolean unpSomeRead; + + protected int readTop; + + protected long destUnpSize; + + protected byte[] window; + + protected int[] oldDist = new int[4]; + + protected int unpPtr, wrPtr; + + protected int oldDistPtr; + + protected int[] ChSet = new int[256], ChSetA = new int[256], + ChSetB = new int[256], ChSetC = new int[256]; + + protected int[] Place = new int[256], PlaceA = new int[256], + PlaceB = new int[256], PlaceC = new int[256]; + + protected int[] NToPl = new int[256], NToPlB = new int[256], + NToPlC = new int[256]; + + protected int FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3; + + protected int Buf60, NumHuf, StMode, LCount, FlagsCnt; + + protected int Nhfb, Nlzb, MaxDist3; + + protected int lastDist, lastLength; + + private static final int STARTL1 = 2; + + private static int DecL1[] = { 0x8000, 0xa000, 0xc000, 0xd000, 0xe000, + 0xea00, 0xee00, 0xf000, 0xf200, 0xf200, 0xffff }; + + private static int PosL1[] = { 0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32 }; + + private static final int STARTL2 = 3; + + private static int DecL2[] = { 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, + 0xee00, 0xf000, 0xf200, 0xf240, 0xffff }; + + private static int PosL2[] = { 0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36 }; + + private static final int STARTHF0 = 4; + + private static int DecHf0[] = { 0x8000, 0xc000, 0xe000, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xffff }; + + private static int PosHf0[] = { 0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, + 33 }; + + private static final int STARTHF1 = 5; + + private static int DecHf1[] = { 0x2000, 0xc000, 0xe000, 0xf000, 0xf200, + 0xf200, 0xf7e0, 0xffff }; + + private static int PosHf1[] = { 0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, + 127 }; + + private static final int STARTHF2 = 5; + + private static int DecHf2[] = { 0x1000, 0x2400, 0x8000, 0xc000, 0xfa00, + 0xffff, 0xffff, 0xffff }; + + private static int PosHf2[] = { 0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0 }; + + private static final int STARTHF3 = 6; + + private static int DecHf3[] = { 0x800, 0x2400, 0xee00, 0xfe80, 0xffff, + 0xffff, 0xffff }; + + private static int PosHf3[] = { 0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0 }; + + private static final int STARTHF4 = 8; + + private static int DecHf4[] = { 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff }; + + private static int PosHf4[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0 }; + + static int ShortLen1[] = { 1, 3, 4, 4, 5, 6, 7, 8, 8, 4, 4, 5, 6, 6, 4, 0 }; + + static int ShortXor1[] = { 0, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, + 0xff, 0xc0, 0x80, 0x90, 0x98, 0x9c, 0xb0 }; + + static int ShortLen2[] = { 2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 4, 5, 6, 6, 4, 0 }; + + static int ShortXor2[] = { 0, 0x40, 0x60, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, + 0xfc, 0xc0, 0x80, 0x90, 0x98, 0x9c, 0xb0 }; + + protected abstract void unpInitData(boolean solid); + + protected void unpack15(boolean solid) throws IOException, RarException + { + if (suspended) { + unpPtr = wrPtr; + } else { + unpInitData(solid); + oldUnpInitData(solid); + unpReadBuf(); + if (!solid) { + initHuff(); + unpPtr = 0; + } else { + unpPtr = wrPtr; + } + --destUnpSize; + } + if (destUnpSize >= 0) { + getFlagsBuf(); + FlagsCnt = 8; + } + + while (destUnpSize >= 0) { + unpPtr &= Compress.MAXWINMASK; + + if (inAddr > readTop - 30 && !unpReadBuf()) { + break; + } + if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 270 + && wrPtr != unpPtr) { + oldUnpWriteBuf(); + if (suspended) { + return; + } + } + if (StMode != 0) { + huffDecode(); + continue; + } + + if (--FlagsCnt < 0) { + getFlagsBuf(); + FlagsCnt = 7; + } + + if ((FlagBuf & 0x80) != 0) { + FlagBuf <<= 1; + if (Nlzb > Nhfb) { + longLZ(); + } else { + huffDecode(); + } + } else { + FlagBuf <<= 1; + if (--FlagsCnt < 0) { + getFlagsBuf(); + FlagsCnt = 7; + } + if ((FlagBuf & 0x80) != 0) { + FlagBuf <<= 1; + if (Nlzb > Nhfb) { + huffDecode(); + } else { + longLZ(); + } + } else { + FlagBuf <<= 1; + shortLZ(); + } + } + } + oldUnpWriteBuf(); + } + + + + protected boolean unpReadBuf() throws IOException, RarException + { + int dataSize=readTop-inAddr; + if (dataSize<0){ + return(false); + } + if (inAddr>BitInput.MAX_SIZE/2) { + if (dataSize>0){ + //memmove(InBuf,InBuf+InAddr,DataSize); +// for (int i = 0; i < dataSize; i++) { +// inBuf[i] = inBuf[inAddr + i]; +// } + System.arraycopy(inBuf, inAddr, inBuf, 0, dataSize); + } + inAddr=0; + readTop=dataSize; + } + else{ + dataSize=readTop; + } + //int readCode=UnpIO->UnpRead(InBuf+DataSize,(BitInput::MAX_SIZE-DataSize)&~0xf); + int readCode=unpIO.unpRead(inBuf, dataSize, (BitInput.MAX_SIZE-dataSize)&~0xf); + if (readCode>0){ + readTop+=readCode; + } + readBorder=readTop-30; + return(readCode!=-1); + } + + private int getShortLen1(int pos) + { + return pos == 1 ? Buf60 + 3 : ShortLen1[pos]; + } + + private int getShortLen2(int pos) + { + return pos == 3 ? Buf60 + 3 : ShortLen2[pos]; + } + + protected void shortLZ() + { + int Length, SaveLength; + int LastDistance; + int Distance; + int DistancePlace; + NumHuf = 0; + + int BitField = fgetbits(); + if (LCount == 2) { + faddbits(1); + if (BitField >= 0x8000) { + oldCopyString(lastDist, lastLength); + return; + } + BitField <<= 1; + LCount = 0; + } + BitField >>>= 8; + if (AvrLn1 < 37) { + for (Length = 0;; Length++) { + if (((BitField ^ ShortXor1[Length]) & (~(0xff >>> getShortLen1(Length)))) == 0) { + break; + } + } + faddbits(getShortLen1(Length)); + } else { + for (Length = 0;; Length++) { + if (((BitField ^ ShortXor2[Length]) & (~(0xff >> getShortLen2(Length)))) == 0) { + break; + } + } + faddbits(getShortLen2(Length)); + } + + if (Length >= 9) { + if (Length == 9) { + LCount++; + oldCopyString(lastDist, lastLength); + return; + } + if (Length == 14) { + LCount = 0; + Length = decodeNum(fgetbits(), STARTL2, DecL2, PosL2) + 5; + Distance = (fgetbits() >> 1) | 0x8000; + faddbits(15); + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + return; + } + + LCount = 0; + SaveLength = Length; + Distance = oldDist[(oldDistPtr - (Length - 9)) & 3]; + Length = decodeNum(fgetbits(), STARTL1, DecL1, PosL1) + 2; + if (Length == 0x101 && SaveLength == 10) { + Buf60 ^= 1; + return; + } + if (Distance > 256) + Length++; + if (Distance >= MaxDist3) + Length++; + + oldDist[oldDistPtr++] = Distance; + oldDistPtr = oldDistPtr & 3; + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + return; + } + + LCount = 0; + AvrLn1 += Length; + AvrLn1 -= AvrLn1 >> 4; + + DistancePlace = decodeNum(fgetbits(), STARTHF2, DecHf2, PosHf2) & 0xff; + Distance = ChSetA[DistancePlace]; + if (--DistancePlace != -1) { + PlaceA[Distance]--; + LastDistance = ChSetA[DistancePlace]; + PlaceA[LastDistance]++; + ChSetA[DistancePlace + 1] = LastDistance; + ChSetA[DistancePlace] = Distance; + } + Length += 2; + oldDist[oldDistPtr++] = ++Distance; + oldDistPtr = oldDistPtr & 3; + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + } + + protected void longLZ() + { + int Length; + int Distance; + int DistancePlace, NewDistancePlace; + int OldAvr2, OldAvr3; + + NumHuf = 0; + Nlzb += 16; + if (Nlzb > 0xff) { + Nlzb = 0x90; + Nhfb >>>= 1; + } + OldAvr2 = AvrLn2; + + int BitField = fgetbits(); + if (AvrLn2 >= 122) { + Length = decodeNum(BitField, STARTL2, DecL2, PosL2); + } else { + if (AvrLn2 >= 64) { + Length = decodeNum(BitField, STARTL1, DecL1, PosL1); + } else { + if (BitField < 0x100) { + Length = BitField; + faddbits(16); + } else { + for (Length = 0; ((BitField << Length) & 0x8000) == 0; Length++) { + ; + } + faddbits(Length + 1); + } + } + } + AvrLn2 += Length; + AvrLn2 -= AvrLn2 >>> 5; + + BitField = fgetbits(); + if (AvrPlcB > 0x28ff) { + DistancePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); + } else { + if (AvrPlcB > 0x6ff) { + DistancePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); + } else { + DistancePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); + } + } + AvrPlcB += DistancePlace; + AvrPlcB -= AvrPlcB >> 8; + while (true) { + Distance = ChSetB[DistancePlace & 0xff]; + NewDistancePlace = NToPlB[Distance++ & 0xff]++; + if ((Distance & 0xff) == 0) { + corrHuff(ChSetB, NToPlB); + } else { + break; + } + } + + ChSetB[DistancePlace] = ChSetB[NewDistancePlace]; + ChSetB[NewDistancePlace] = Distance; + + Distance = ((Distance & 0xff00) | (fgetbits() >>> 8)) >>> 1; + faddbits(7); + + OldAvr3 = AvrLn3; + if (Length != 1 && Length != 4) { + if (Length == 0 && Distance <= MaxDist3) { + AvrLn3++; + AvrLn3 -= AvrLn3 >> 8; + } else { + if (AvrLn3 > 0) { + AvrLn3--; + } + } + } + Length += 3; + if (Distance >= MaxDist3) { + Length++; + } + if (Distance <= 256) { + Length += 8; + } + if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40) { + MaxDist3 = 0x7f00; + } else { + MaxDist3 = 0x2001; + } + oldDist[oldDistPtr++] = Distance; + oldDistPtr = oldDistPtr & 3; + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + } + + protected void huffDecode() + { + int CurByte, NewBytePlace; + int Length; + int Distance; + int BytePlace; + + int BitField = fgetbits(); + + if (AvrPlc > 0x75ff) { + BytePlace = decodeNum(BitField, STARTHF4, DecHf4, PosHf4); + } else { + if (AvrPlc > 0x5dff) { + BytePlace = decodeNum(BitField, STARTHF3, DecHf3, PosHf3); + } else { + if (AvrPlc > 0x35ff) { + BytePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); + } else { + if (AvrPlc > 0x0dff) { + BytePlace = decodeNum(BitField, STARTHF1, DecHf1, + PosHf1); + } else { + BytePlace = decodeNum(BitField, STARTHF0, DecHf0, + PosHf0); + } + } + } + } + BytePlace &= 0xff; + if (StMode != 0) { + if (BytePlace == 0 && BitField > 0xfff) { + BytePlace = 0x100; + } + if (--BytePlace == -1) { + BitField = fgetbits(); + faddbits(1); + if ((BitField & 0x8000) != 0) { + NumHuf = StMode = 0; + return; + } else { + Length = (BitField & 0x4000) != 0 ? 4 : 3; + faddbits(1); + Distance = decodeNum(fgetbits(), STARTHF2, DecHf2, PosHf2); + Distance = (Distance << 5) | (fgetbits() >>> 11); + faddbits(5); + oldCopyString(Distance, Length); + return; + } + } + } else { + if (NumHuf++ >= 16 && FlagsCnt == 0) { + StMode = 1; + } + } + AvrPlc += BytePlace; + AvrPlc -= AvrPlc >>> 8; + Nhfb += 16; + if (Nhfb > 0xff) { + Nhfb = 0x90; + Nlzb >>>= 1; + } + + window[unpPtr++] = (byte) (ChSet[BytePlace] >>> 8); + --destUnpSize; + + while (true) { + CurByte = ChSet[BytePlace]; + NewBytePlace = NToPl[CurByte++ & 0xff]++; + if ((CurByte & 0xff) > 0xa1) { + corrHuff(ChSet, NToPl); + } else { + break; + } + } + + ChSet[BytePlace] = ChSet[NewBytePlace]; + ChSet[NewBytePlace] = CurByte; + } + + protected void getFlagsBuf() + { + int Flags, NewFlagsPlace; + int FlagsPlace = decodeNum(fgetbits(), STARTHF2, DecHf2, PosHf2); + + while (true) { + Flags = ChSetC[FlagsPlace]; + FlagBuf = Flags >>> 8; + NewFlagsPlace = NToPlC[Flags++ & 0xff]++; + if ((Flags & 0xff) != 0) { + break; + } + corrHuff(ChSetC, NToPlC); + } + + ChSetC[FlagsPlace] = ChSetC[NewFlagsPlace]; + ChSetC[NewFlagsPlace] = Flags; + } + + protected void oldUnpInitData(boolean Solid) + { + if (!Solid ) { + AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; + AvrPlc = 0x3500; + MaxDist3 = 0x2001; + Nhfb = Nlzb = 0x80; + } + FlagsCnt = 0; + FlagBuf = 0; + StMode = 0; + LCount = 0; + readTop = 0; + } + + protected void initHuff() + { + for (int I = 0; I < 256; I++) { + Place[I] = PlaceA[I] = PlaceB[I] = I; + PlaceC[I] = (~I + 1) & 0xff; + ChSet[I] = ChSetB[I] = I << 8; + ChSetA[I] = I; + ChSetC[I] = ((~I + 1) & 0xff) << 8; + } + + Arrays.fill(NToPl, 0);// memset(NToPl,0,sizeof(NToPl)); + Arrays.fill(NToPlB, 0); // memset(NToPlB,0,sizeof(NToPlB)); + Arrays.fill(NToPlC, 0); // memset(NToPlC,0,sizeof(NToPlC)); + corrHuff(ChSetB, NToPlB); + } + + protected void corrHuff(int[] CharSet, int[] NumToPlace) + { + int I, J, pos = 0; + for (I = 7; I >= 0; I--) { + for (J = 0; J < 32; J++, pos++) { + CharSet[pos] = ((CharSet[pos] & ~0xff) | I);// *CharSet=(*CharSet + // & ~0xff) | I; + } + } + Arrays.fill(NumToPlace, 0);// memset(NumToPlace,0,sizeof(NToPl)); + for (I = 6; I >= 0; I--) { + NumToPlace[I] = (7 - I) * 32; + } + } + + protected void oldCopyString(int Distance, int Length) + { + destUnpSize -= Length; + while ((Length--) != 0) { + window[unpPtr] = window[(unpPtr - Distance) & Compress.MAXWINMASK]; + unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; + } + } + + protected int decodeNum(int Num, int StartPos, int[] DecTab, int[] PosTab) + { + int I; + for (Num &= 0xfff0, I = 0; DecTab[I] <= Num; I++) { + StartPos++; + } + faddbits(StartPos); + return (((Num - (I != 0 ? DecTab[I - 1] : 0)) >>> (16 - StartPos)) + PosTab[StartPos]); + } + + protected void oldUnpWriteBuf() throws IOException + { + if (unpPtr != wrPtr) { + unpSomeRead = true; + } + if (unpPtr < wrPtr) { + unpIO.unpWrite(window, wrPtr, -wrPtr & Compress.MAXWINMASK); + unpIO.unpWrite(window, 0, unpPtr); + unpAllBuf = true; + } else { + unpIO.unpWrite(window, wrPtr, unpPtr - wrPtr); + } + wrPtr = unpPtr; + } + + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack20.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack20.java new file mode 100644 index 0000000..a9138cc --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack20.java @@ -0,0 +1,597 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 21.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack; + +import java.io.IOException; +import java.util.Arrays; + +import com.github.junrar.exception.RarException; +import com.github.junrar.unpack.decode.AudioVariables; +import com.github.junrar.unpack.decode.BitDecode; +import com.github.junrar.unpack.decode.Compress; +import com.github.junrar.unpack.decode.Decode; +import com.github.junrar.unpack.decode.DistDecode; +import com.github.junrar.unpack.decode.LitDecode; +import com.github.junrar.unpack.decode.LowDistDecode; +import com.github.junrar.unpack.decode.MultDecode; +import com.github.junrar.unpack.decode.RepDecode; + + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public abstract class Unpack20 extends Unpack15 +{ + + protected MultDecode[] MD = new MultDecode[4]; + + protected byte[] UnpOldTable20 = new byte[Compress.MC20 * 4]; + + protected int UnpAudioBlock, UnpChannels, UnpCurChannel, UnpChannelDelta; + + protected AudioVariables[] AudV = new AudioVariables[4]; + + protected LitDecode LD = new LitDecode(); + + protected DistDecode DD = new DistDecode(); + + protected LowDistDecode LDD = new LowDistDecode(); + + protected RepDecode RD = new RepDecode(); + + protected BitDecode BD = new BitDecode(); + + public static final int[] LDecode = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, + 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, + 224 }; + + public static final byte[] LBits = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, + 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; + + public static final int[] DDecode = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, + 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, + 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, 65536, 98304, + 131072, 196608, 262144, 327680, 393216, 458752, 524288, 589824, + 655360, 720896, 786432, 851968, 917504, 983040 }; + + public static final int[] DBits = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, + 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, + 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; + + public static final int[] SDDecode = { 0, 4, 8, 16, 32, 64, 128, 192 }; + + public static final int[] SDBits = { 2, 2, 3, 4, 5, 6, 6, 6 }; + + protected void unpack20(boolean solid) throws IOException, RarException + { + + int Bits; + + if (suspended) { + unpPtr = wrPtr; + } else { + unpInitData(solid); + if (!unpReadBuf()) { + return; + } + if (!solid) { + if (!ReadTables20()) { + return; + } + } + --destUnpSize; + } + + while (destUnpSize >= 0) { + unpPtr &= Compress.MAXWINMASK; + + if (inAddr > readTop - 30) + if (!unpReadBuf()) + break; + if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 270 + && wrPtr != unpPtr) { + oldUnpWriteBuf(); + if (suspended) + return; + } + if (UnpAudioBlock != 0) { + int AudioNumber = decodeNumber(MD[UnpCurChannel]); + + if (AudioNumber == 256) { + if (!ReadTables20()) + break; + continue; + } + window[unpPtr++] = DecodeAudio(AudioNumber); + if (++UnpCurChannel == UnpChannels) + UnpCurChannel = 0; + --destUnpSize; + continue; + } + + int Number = decodeNumber(LD); + if (Number < 256) { + window[unpPtr++] = (byte) Number; + --destUnpSize; + continue; + } + if (Number > 269) { + int Length = LDecode[Number -= 270] + 3; + if ((Bits = LBits[Number]) > 0) { + Length += getbits() >>> (16 - Bits); + addbits(Bits); + } + + int DistNumber = decodeNumber(DD); + int Distance = DDecode[DistNumber] + 1; + if ((Bits = DBits[DistNumber]) > 0) { + Distance += getbits() >>> (16 - Bits); + addbits(Bits); + } + + if (Distance >= 0x2000) { + Length++; + if (Distance >= 0x40000L) + Length++; + } + + CopyString20(Length, Distance); + continue; + } + if (Number == 269) { + if (!ReadTables20()) + break; + continue; + } + if (Number == 256) { + CopyString20(lastLength, lastDist); + continue; + } + if (Number < 261) { + int Distance = oldDist[(oldDistPtr - (Number - 256)) & 3]; + int LengthNumber = decodeNumber(RD); + int Length = LDecode[LengthNumber] + 2; + if ((Bits = LBits[LengthNumber]) > 0) { + Length += getbits() >>> (16 - Bits); + addbits(Bits); + } + if (Distance >= 0x101) { + Length++; + if (Distance >= 0x2000) { + Length++; + if (Distance >= 0x40000) + Length++; + } + } + CopyString20(Length, Distance); + continue; + } + if (Number < 270) { + int Distance = SDDecode[Number -= 261] + 1; + if ((Bits = SDBits[Number]) > 0) { + Distance += getbits() >>> (16 - Bits); + addbits(Bits); + } + CopyString20(2, Distance); + continue; + } + } + ReadLastTables(); + oldUnpWriteBuf(); + + } + + protected void CopyString20(int Length, int Distance) + { + lastDist = oldDist[oldDistPtr++ & 3] = Distance; + lastLength = Length; + destUnpSize -= Length; + + int DestPtr = unpPtr - Distance; + if (DestPtr < Compress.MAXWINSIZE - 300 + && unpPtr < Compress.MAXWINSIZE - 300) { + window[unpPtr++] = window[DestPtr++]; + window[unpPtr++] = window[DestPtr++]; + while (Length > 2) { + Length--; + window[unpPtr++] = window[DestPtr++]; + } + } else { + while ((Length--) != 0) { + window[unpPtr] = window[DestPtr++ & Compress.MAXWINMASK]; + unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; + } + } + } + + protected void makeDecodeTables(byte[] lenTab, int offset, Decode dec, + int size) + { + int[] lenCount = new int[16]; + int[] tmpPos = new int[16]; + int i; + long M, N; + + Arrays.fill(lenCount, 0);// memset(LenCount,0,sizeof(LenCount)); + + Arrays.fill(dec.getDecodeNum(), 0);// memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum)); + + for (i = 0; i < size; i++) { + lenCount[(int) (lenTab[offset + i] & 0xF)]++; + } + lenCount[0] = 0; + for (tmpPos[0] = 0, dec.getDecodePos()[0] = 0, dec.getDecodeLen()[0] = 0, N = 0, i = 1; i < 16; i++) { + N = 2 * (N + lenCount[i]); + M = N << (15 - i); + if (M > 0xFFFF) { + M = 0xFFFF; + } + dec.getDecodeLen()[i] = (int) M; + tmpPos[i] = dec.getDecodePos()[i] = dec.getDecodePos()[i - 1] + + lenCount[i - 1]; + } + + for (i = 0; i < size; i++) { + if (lenTab[offset + i] != 0) { + dec.getDecodeNum()[tmpPos[lenTab[offset + i] & 0xF]++] = i; + } + } + dec.setMaxNum(size); + } + + protected int decodeNumber(Decode dec) + { + int bits; + long bitField = getbits() & 0xfffe; +// if (bitField < dec.getDecodeLen()[8]) { +// if (bitField < dec.getDecodeLen()[4]) { +// if (bitField < dec.getDecodeLen()[2]) { +// if (bitField < dec.getDecodeLen()[1]) { +// bits = 1; +// } else { +// bits = 2; +// } +// } else { +// if (bitField < dec.getDecodeLen()[3]) { +// bits = 3; +// } else { +// bits = 4; +// } +// } +// } else { +// if (bitField < dec.getDecodeLen()[6]) { +// if (bitField < dec.getDecodeLen()[5]) +// bits = 5; +// else +// bits = 6; +// } else { +// if (bitField < dec.getDecodeLen()[7]) { +// bits = 7; +// } else { +// bits = 8; +// } +// } +// } +// } else { +// if (bitField < dec.getDecodeLen()[12]) { +// if (bitField < dec.getDecodeLen()[10]) +// if (bitField < dec.getDecodeLen()[9]) +// bits = 9; +// else +// bits = 10; +// else if (bitField < dec.getDecodeLen()[11]) +// bits = 11; +// else +// bits = 12; +// } else { +// if (bitField < dec.getDecodeLen()[14]) { +// if (bitField < dec.getDecodeLen()[13]) { +// bits = 13; +// } else { +// bits = 14; +// } +// } else { +// bits = 15; +// } +// } +// } +// addbits(bits); +// int N = dec.getDecodePos()[bits] +// + (((int) bitField - dec.getDecodeLen()[bits - 1]) >>> (16 - bits)); +// if (N >= dec.getMaxNum()) { +// N = 0; +// } +// return (dec.getDecodeNum()[N]); + int[] decodeLen = dec.getDecodeLen(); + if (bitField < decodeLen[8]) { + if (bitField < decodeLen[4]) { + if (bitField < decodeLen[2]) { + if (bitField < decodeLen[1]) { + bits = 1; + } else { + bits = 2; + } + } else { + if (bitField < decodeLen[3]) { + bits = 3; + } else { + bits = 4; + } + } + } else { + if (bitField < decodeLen[6]) { + if (bitField < decodeLen[5]) + bits = 5; + else + bits = 6; + } else { + if (bitField < decodeLen[7]) { + bits = 7; + } else { + bits = 8; + } + } + } + } else { + if (bitField < decodeLen[12]) { + if (bitField < decodeLen[10]) + if (bitField < decodeLen[9]) + bits = 9; + else + bits = 10; + else if (bitField < decodeLen[11]) + bits = 11; + else + bits = 12; + } else { + if (bitField < decodeLen[14]) { + if (bitField < decodeLen[13]) { + bits = 13; + } else { + bits = 14; + } + } else { + bits = 15; + } + } + } + addbits(bits); + int N = dec.getDecodePos()[bits] + + (((int) bitField - decodeLen[bits - 1]) >>> (16 - bits)); + if (N >= dec.getMaxNum()) { + N = 0; + } + return (dec.getDecodeNum()[N]); + } + + protected boolean ReadTables20() throws IOException, RarException + { + byte[] BitLength = new byte[Compress.BC20]; + byte[] Table = new byte[Compress.MC20 * 4]; + int TableSize, N, I; + if (inAddr > readTop - 25) { + if (!unpReadBuf()) { + return (false); + } + } + int BitField = getbits(); + UnpAudioBlock = (BitField & 0x8000); + + if (0 == (BitField & 0x4000)) { + // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + Arrays.fill(UnpOldTable20, (byte) 0); + } + addbits(2); + + if (UnpAudioBlock != 0) { + UnpChannels = ((BitField >>> 12) & 3) + 1; + if (UnpCurChannel >= UnpChannels) { + UnpCurChannel = 0; + } + addbits(2); + TableSize = Compress.MC20 * UnpChannels; + } else { + TableSize = Compress.NC20 + Compress.DC20 + Compress.RC20; + } + for (I = 0; I < Compress.BC20; I++) { + BitLength[I] = (byte) (getbits() >>> 12); + addbits(4); + } + makeDecodeTables(BitLength, 0, BD, Compress.BC20); + I = 0; + while (I < TableSize) { + if (inAddr > readTop - 5) { + if (!unpReadBuf()) { + return (false); + } + } + int Number = decodeNumber(BD); + if (Number < 16) { + Table[I] = (byte) ((Number + UnpOldTable20[I]) & 0xf); + I++; + } else if (Number == 16) { + N = (getbits() >>> 14) + 3; + addbits(2); + while (N-- > 0 && I < TableSize) { + Table[I] = Table[I - 1]; + I++; + } + } else { + if (Number == 17) { + N = (getbits() >>> 13) + 3; + addbits(3); + } else { + N = (getbits() >>> 9) + 11; + addbits(7); + } + while (N-- > 0 && I < TableSize) + Table[I++] = 0; + } + } + if (inAddr > readTop) { + return (true); + } + if (UnpAudioBlock != 0) + for (I = 0; I < UnpChannels; I++) + makeDecodeTables(Table, I * Compress.MC20, MD[I], Compress.MC20); + else { + makeDecodeTables(Table, 0, LD, Compress.NC20); + makeDecodeTables(Table, Compress.NC20, DD, Compress.DC20); + makeDecodeTables(Table, Compress.NC20 + Compress.DC20, RD, + Compress.RC20); + } + // memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); + for (int i = 0; i < UnpOldTable20.length; i++) { + UnpOldTable20[i] = Table[i]; + } + return (true); + } + + protected void unpInitData20(boolean Solid) + { + if (!Solid) { + UnpChannelDelta = UnpCurChannel = 0; + UnpChannels = 1; + // memset(AudV,0,sizeof(AudV)); + Arrays.fill(AudV, new AudioVariables()); + // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + Arrays.fill(UnpOldTable20, (byte) 0); + } + } + + protected void ReadLastTables() throws IOException, RarException + { + if (readTop >= inAddr + 5) { + if (UnpAudioBlock != 0) { + if (decodeNumber(MD[UnpCurChannel]) == 256) { + ReadTables20(); + } + } else { + if (decodeNumber(LD) == 269) { + ReadTables20(); + } + } + } + } + + protected byte DecodeAudio(int Delta) + { + AudioVariables v = AudV[UnpCurChannel]; + v.setByteCount(v.getByteCount() + 1); + v.setD4(v.getD3()); + v.setD3(v.getD2());// ->D3=V->D2; + v.setD2(v.getLastDelta() - v.getD1());// ->D2=V->LastDelta-V->D1; + v.setD1(v.getLastDelta());// V->D1=V->LastDelta; + // int PCh=8*V->LastChar+V->K1*V->D1 +V->K2*V->D2 +V->K3*V->D3 + // +V->K4*V->D4+ V->K5*UnpChannelDelta; + int PCh = 8 * v.getLastChar() + v.getK1() * v.getD1(); + PCh += v.getK2() * v.getD2() + v.getK3() * v.getD3(); + PCh += v.getK4() * v.getD4() + v.getK5() * UnpChannelDelta; + PCh = (PCh >>> 3) & 0xFF; + + int Ch = PCh - Delta; + + int D = ((byte) Delta) << 3; + + v.getDif()[0] += Math.abs(D);// V->Dif[0]+=abs(D); + v.getDif()[1] += Math.abs(D - v.getD1());// V->Dif[1]+=abs(D-V->D1); + v.getDif()[2] += Math.abs(D + v.getD1());// V->Dif[2]+=abs(D+V->D1); + v.getDif()[3] += Math.abs(D - v.getD2());// V->Dif[3]+=abs(D-V->D2); + v.getDif()[4] += Math.abs(D + v.getD2());// V->Dif[4]+=abs(D+V->D2); + v.getDif()[5] += Math.abs(D - v.getD3());// V->Dif[5]+=abs(D-V->D3); + v.getDif()[6] += Math.abs(D + v.getD3());// V->Dif[6]+=abs(D+V->D3); + v.getDif()[7] += Math.abs(D - v.getD4());// V->Dif[7]+=abs(D-V->D4); + v.getDif()[8] += Math.abs(D + v.getD4());// V->Dif[8]+=abs(D+V->D4); + v.getDif()[9] += Math.abs(D - UnpChannelDelta);// V->Dif[9]+=abs(D-UnpChannelDelta); + v.getDif()[10] += Math.abs(D + UnpChannelDelta);// V->Dif[10]+=abs(D+UnpChannelDelta); + + v.setLastDelta((byte) (Ch - v.getLastChar())); + UnpChannelDelta = v.getLastDelta(); + v.setLastChar(Ch);// V->LastChar=Ch; + + if ((v.getByteCount() & 0x1F) == 0) { + int MinDif = v.getDif()[0], NumMinDif = 0; + v.getDif()[0] = 0;// ->Dif[0]=0; + for (int I = 1; I < v.getDif().length; I++) { + if (v.getDif()[I] < MinDif) { + MinDif = v.getDif()[I]; + NumMinDif = I; + } + v.getDif()[I] = 0; + } + switch (NumMinDif) { + case 1: + if (v.getK1() >= -16) { + v.setK1(v.getK1() - 1);// V->K1--; + } + break; + case 2: + if (v.getK1() < 16) { + v.setK1(v.getK1() + 1);// V->K1++; + } + break; + case 3: + if (v.getK2() >= -16) { + v.setK2(v.getK2() - 1);// V->K2--; + } + break; + case 4: + if (v.getK2() < 16) { + v.setK2(v.getK2() + 1);// V->K2++; + } + break; + case 5: + if (v.getK3() >= -16) { + v.setK3(v.getK3() - 1); + } + break; + case 6: + if (v.getK3() < 16) { + v.setK3(v.getK3() + 1); + } + break; + case 7: + if (v.getK4() >= -16) { + v.setK4(v.getK4() - 1); + } + break; + case 8: + if (v.getK4() < 16) { + v.setK4(v.getK4() + 1); + } + break; + case 9: + if (v.getK5() >= -16) { + v.setK5(v.getK5() - 1); + } + break; + case 10: + if (v.getK5() < 16) { + v.setK5(v.getK5() + 1); + } + break; + } + } + return ((byte) Ch); + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/UnpackFilter.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/UnpackFilter.java new file mode 100644 index 0000000..29ed99a --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/UnpackFilter.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack; + +import com.github.junrar.unpack.vm.VMPreparedProgram; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class UnpackFilter { + + private int BlockStart; + + private int BlockLength; + + private int ExecCount; + + private boolean NextWindow; + + // position of parent filter in Filters array used as prototype for filter + // in PrgStack array. Not defined for filters in Filters array. + private int ParentFilter; + + private VMPreparedProgram Prg = new VMPreparedProgram(); + + public int getBlockLength() { + return BlockLength; + } + + public void setBlockLength(int blockLength) { + BlockLength = blockLength; + } + + public int getBlockStart() { + return BlockStart; + } + + public void setBlockStart(int blockStart) { + BlockStart = blockStart; + } + + public int getExecCount() { + return ExecCount; + } + + public void setExecCount(int execCount) { + ExecCount = execCount; + } + + public boolean isNextWindow() { + return NextWindow; + } + + public void setNextWindow(boolean nextWindow) { + NextWindow = nextWindow; + } + + public int getParentFilter() { + return ParentFilter; + } + + public void setParentFilter(int parentFilter) { + ParentFilter = parentFilter; + } + + public VMPreparedProgram getPrg() { + return Prg; + } + + public void setPrg(VMPreparedProgram prg) { + Prg = prg; + } + + + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/AudioVariables.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/AudioVariables.java new file mode 100644 index 0000000..7310663 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/AudioVariables.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class AudioVariables { + int k1, k2, k3, k4, k5; + + int d1, d2, d3, d4; + + int lastDelta; + + int dif[] = new int[11]; + + int byteCount; + + int lastChar; + + public int getByteCount() { + return byteCount; + } + + public void setByteCount(int byteCount) { + this.byteCount = byteCount; + } + + public int getD1() { + return d1; + } + + public void setD1(int d1) { + this.d1 = d1; + } + + public int getD2() { + return d2; + } + + public void setD2(int d2) { + this.d2 = d2; + } + + public int getD3() { + return d3; + } + + public void setD3(int d3) { + this.d3 = d3; + } + + public int getD4() { + return d4; + } + + public void setD4(int d4) { + this.d4 = d4; + } + + public int[] getDif() { + return dif; + } + + public void setDif(int[] dif) { + this.dif = dif; + } + + public int getK1() { + return k1; + } + + public void setK1(int k1) { + this.k1 = k1; + } + + public int getK2() { + return k2; + } + + public void setK2(int k2) { + this.k2 = k2; + } + + public int getK3() { + return k3; + } + + public void setK3(int k3) { + this.k3 = k3; + } + + public int getK4() { + return k4; + } + + public void setK4(int k4) { + this.k4 = k4; + } + + public int getK5() { + return k5; + } + + public void setK5(int k5) { + this.k5 = k5; + } + + public int getLastChar() { + return lastChar; + } + + public void setLastChar(int lastChar) { + this.lastChar = lastChar; + } + + public int getLastDelta() { + return lastDelta; + } + + public void setLastDelta(int lastDelta) { + this.lastDelta = lastDelta; + } + + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/BitDecode.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/BitDecode.java new file mode 100644 index 0000000..453d90a --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/BitDecode.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class BitDecode extends Decode +{ + /** + * + */ + public BitDecode() + { + decodeNum = new int[Compress.BC]; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/CodeType.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/CodeType.java new file mode 100644 index 0000000..047dc0c --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/CodeType.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.decode; + +/** + * DOCUMENT ME + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public enum CodeType { + CODE_HUFFMAN,CODE_LZ,CODE_LZ2,CODE_REPEATLZ,CODE_CACHELZ, + CODE_STARTFILE,CODE_ENDFILE,CODE_VM,CODE_VMDATA; +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/Compress.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/Compress.java new file mode 100644 index 0000000..12bf342 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/Compress.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class Compress { + public static final int CODEBUFSIZE = 0x4000; + public static final int MAXWINSIZE = 0x400000; + public static final int MAXWINMASK = (MAXWINSIZE-1); + + public static final int LOW_DIST_REP_COUNT = 16; + + public static final int NC = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public static final int DC = 60; + public static final int LDC = 17; + public static final int RC = 28; + public static final int HUFF_TABLE_SIZE = (NC+DC+RC+LDC); + public static final int BC = 20; + + public static final int NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public static final int DC20 = 48; + public static final int RC20 = 28; + public static final int BC20 = 19; + public static final int MC20 = 257; +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/Decode.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/Decode.java new file mode 100644 index 0000000..2d1b9b6 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/Decode.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.decode; + +/** + * Used to store information for lz decoding + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class Decode +{ + private int maxNum; + + private final int[] decodeLen = new int[16]; + + private final int[] decodePos = new int[16]; + + protected int[] decodeNum = new int[2]; + + /** + * returns the decode Length array + * @return decodeLength + */ + public int[] getDecodeLen() + { + return decodeLen; + } + + /** + * returns the decode num array + * @return decodeNum + */ + public int[] getDecodeNum() + { + return decodeNum; + } + + /** + * returns the decodePos array + * @return decodePos + */ + public int[] getDecodePos() + { + return decodePos; + } + + /** + * returns the max num + * @return maxNum + */ + public int getMaxNum() + { + return maxNum; + } + + /** + * sets the max num + * @param maxNum to be set to maxNum + */ + public void setMaxNum(int maxNum) + { + this.maxNum = maxNum; + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/DistDecode.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/DistDecode.java new file mode 100644 index 0000000..d52d767 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/DistDecode.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class DistDecode extends Decode +{ + + /** + * + */ + public DistDecode() + { + decodeNum = new int[Compress.DC]; + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/FilterType.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/FilterType.java new file mode 100644 index 0000000..d0cbfcc --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/FilterType.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public enum FilterType { + FILTER_NONE, FILTER_PPM /*dummy*/, FILTER_E8, FILTER_E8E9, + FILTER_UPCASETOLOW, FILTER_AUDIO, FILTER_RGB, FILTER_DELTA, + FILTER_ITANIUM, FILTER_E8E9V2; +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/LitDecode.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/LitDecode.java new file mode 100644 index 0000000..563566f --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/LitDecode.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class LitDecode extends Decode +{ + /** + * + */ + public LitDecode() + { + decodeNum = new int[Compress.NC]; + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/LowDistDecode.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/LowDistDecode.java new file mode 100644 index 0000000..837eb77 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/LowDistDecode.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class LowDistDecode extends Decode +{ + + /** + * + */ + public LowDistDecode() + { + decodeNum = new int[Compress.LDC]; + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/MultDecode.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/MultDecode.java new file mode 100644 index 0000000..95db9cf --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/MultDecode.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class MultDecode extends Decode +{ + + /** + * + */ + public MultDecode() + { + decodeNum = new int[Compress.MC20]; + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/RepDecode.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/RepDecode.java new file mode 100644 index 0000000..02f7ef4 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/decode/RepDecode.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.decode; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RepDecode extends Decode +{ + /** + * + */ + public RepDecode() + { + decodeNum = new int[Compress.RC]; + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/AnalyzeHeapDump.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/AnalyzeHeapDump.java new file mode 100644 index 0000000..634fc92 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/AnalyzeHeapDump.java @@ -0,0 +1,94 @@ +package com.github.junrar.unpack.ppm; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * For debugging purposes only. + * + * @author alban + */ +public class AnalyzeHeapDump { + + /** Creates a new instance of AnalyzeHeapDump */ + public AnalyzeHeapDump() { + } + + public static void main(String[] argv) { + File cfile = new File("P:\\test\\heapdumpc"); + File jfile = new File("P:\\test\\heapdumpj"); + if (!cfile.exists()) { + System.err.println("File not found: " + cfile.getAbsolutePath()); + return; + } + if (!jfile.exists()) { + System.err.println("File not found: " + jfile.getAbsolutePath()); + return; + } + long clen = cfile.length(); + long jlen = jfile.length(); + if (clen != jlen) { + System.out.println("File size mismatch"); + System.out.println("clen = " + clen); + System.out.println("jlen = " + jlen); + } + // Do byte comparison + long len = Math.min(clen, jlen); + InputStream cin = null; + InputStream jin = null; + int bufferLen = 256*1024; + try { + cin = new BufferedInputStream( + new FileInputStream(cfile), bufferLen); + jin = new BufferedInputStream( + new FileInputStream(jfile), bufferLen); + boolean matching = true; + boolean mismatchFound = false; + long startOff = 0L; + long off = 0L; + while (off < len) { + if (cin.read() != jin.read()) { + if (matching) { + startOff = off; + matching = false; + mismatchFound = true; + } + } + else { // match + if (!matching) { + printMismatch(startOff, off); + matching = true; + } + } + off++; + } + if (!matching) { + printMismatch(startOff, off); + } + if (!mismatchFound) { + System.out.println("Files are identical"); + } + System.out.println("Done"); + } + catch (IOException e) { + e.printStackTrace(); + } + finally { + try { + cin.close(); + jin.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private static void printMismatch(long startOff, long bytesRead) { + System.out.println("Mismatch: off=" + startOff + + "(0x" + Long.toHexString(startOff) + + "), len=" + (bytesRead - startOff)); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/BlockTypes.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/BlockTypes.java new file mode 100644 index 0000000..ffe7c61 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/BlockTypes.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public enum BlockTypes +{ + BLOCK_LZ(0), BLOCK_PPM(1); + + private int blockType; + + private BlockTypes(int blockType) + { + this.blockType = blockType; + } + + public int getBlockType() + { + return blockType; + } + + public boolean equals(int blockType) + { + return this.blockType == blockType; + } + + public static BlockTypes findBlockType(int blockType) + { + if (BLOCK_LZ.equals(blockType)) { + return BLOCK_LZ; + } + if (BLOCK_PPM.equals(blockType)) { + return BLOCK_PPM; + } + return null; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/FreqData.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/FreqData.java new file mode 100644 index 0000000..4308a85 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/FreqData.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + +import com.github.junrar.io.Raw; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class FreqData extends Pointer{ + + public static final int size = 6; + +// struct FreqData +// { +// ushort SummFreq; +// STATE _PACK_ATTR * Stats; +// }; + + public FreqData(byte[]mem){ + super(mem); + } + + public FreqData init(byte[] mem) { + this.mem = mem; + pos = 0; + return this; + } + + public int getSummFreq() { + return Raw.readShortLittleEndian(mem, pos)&0xffff; + } + + public void setSummFreq(int summFreq) { + Raw.writeShortLittleEndian(mem, pos, (short)summFreq); + } + + public void incSummFreq(int dSummFreq) { + Raw.incShortLittleEndian(mem, pos, dSummFreq); + } + + public int getStats() { + return Raw.readIntLittleEndian(mem, pos+2); + } + + public void setStats(State state) { + setStats(state.getAddress()); + } + + public void setStats(int state) { + Raw.writeIntLittleEndian(mem, pos+2, state); + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("FreqData["); + buffer.append("\n pos="); + buffer.append(pos); + buffer.append("\n size="); + buffer.append(size); + buffer.append("\n summFreq="); + buffer.append(getSummFreq()); + buffer.append("\n stats="); + buffer.append(getStats()); + buffer.append("\n]"); + return buffer.toString(); + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/ModelPPM.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/ModelPPM.java new file mode 100644 index 0000000..25e20bb --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/ModelPPM.java @@ -0,0 +1,696 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + +import java.io.IOException; +import java.util.Arrays; + +import com.github.junrar.exception.RarException; +import com.github.junrar.unpack.Unpack; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class ModelPPM +{ + public static final int MAX_O = 64; /* maximum allowed model order */ + + public static final int INT_BITS = 7; + + public static final int PERIOD_BITS = 7; + + public static final int TOT_BITS = INT_BITS + PERIOD_BITS; + + public static final int INTERVAL = 1 << INT_BITS; + + public static final int BIN_SCALE = 1 << TOT_BITS; + + public static final int MAX_FREQ = 124; + + private SEE2Context[][] SEE2Cont = new SEE2Context[25][16]; + + private SEE2Context dummySEE2Cont; + + private PPMContext minContext, medContext, maxContext; + + private State foundState; // found next state transition + + private int numMasked, initEsc, orderFall, maxOrder, runLength, initRL; + + private int[] charMask = new int[256]; + + private int[] NS2Indx = new int[256]; + + private int[] NS2BSIndx = new int[256]; + + private int[] HB2Flag = new int[256]; + + // byte EscCount, PrevSuccess, HiBitsFlag; + private int escCount, prevSuccess, hiBitsFlag; + + private int[][] binSumm = new int[128][64]; // binary SEE-contexts + + private RangeCoder coder = new RangeCoder(); + + private SubAllocator subAlloc = new SubAllocator(); + + private static int InitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, + 0x64A1, 0x5ABC, 0x6632, 0x6051 }; + + // Temp fields + private final State tempState1 = new State(null); + private final State tempState2 = new State(null); + private final State tempState3 = new State(null); + private final State tempState4 = new State(null); + private final StateRef tempStateRef1 = new StateRef(); + private final StateRef tempStateRef2 = new StateRef(); + private final PPMContext tempPPMContext1 = new PPMContext(null); + private final PPMContext tempPPMContext2 = new PPMContext(null); + private final PPMContext tempPPMContext3 = new PPMContext(null); + private final PPMContext tempPPMContext4 = new PPMContext(null); + private final int[] ps = new int[MAX_O]; + + public ModelPPM() + { + minContext = null; + maxContext = null; + medContext = null; + } + + public SubAllocator getSubAlloc() + { + return subAlloc; + } + + private void restartModelRare() + { + Arrays.fill(charMask, 0); + subAlloc.initSubAllocator(); + initRL = -(maxOrder < 12 ? maxOrder : 12) - 1; + int addr = subAlloc.allocContext(); + minContext.setAddress(addr); + maxContext.setAddress(addr); + minContext.setSuffix(0); + orderFall = maxOrder; + minContext.setNumStats(256); + minContext.getFreqData().setSummFreq(minContext.getNumStats()+1); + + addr = subAlloc.allocUnits(256 / 2); + foundState.setAddress(addr); + minContext.getFreqData().setStats(addr); + + State state = new State(subAlloc.getHeap()); + addr = minContext.getFreqData().getStats(); + runLength = initRL; + prevSuccess = 0; + for (int i = 0; i < 256; i++) { + state.setAddress(addr + i * State.size); + state.setSymbol(i); + state.setFreq(1); + state.setSuccessor(0); + } + + for (int i = 0; i < 128; i++) { + for (int k = 0; k < 8; k++) { + for (int m = 0; m < 64; m += 8) { + binSumm[i][k + m] = BIN_SCALE - InitBinEsc[k] / (i + 2); + } + } + } + for (int i = 0; i < 25; i++) { + for (int k = 0; k < 16; k++) { + SEE2Cont[i][k].init(5 * i + 10); + } + } + } + + private void startModelRare(int MaxOrder) + { + int i, k, m, Step; + escCount = 1; + this.maxOrder = MaxOrder; + restartModelRare(); + // Bug Fixed + NS2BSIndx[0] = 0; + NS2BSIndx[1] = 2; + for (int j = 0; j < 9; j++) { + NS2BSIndx[2 + j] = 4; + } + for (int j = 0; j < 256 - 11; j++) { + NS2BSIndx[11 + j] = 6; + } + for (i = 0; i < 3; i++) { + NS2Indx[i] = i; + } + for (m = i, k = 1, Step = 1; i < 256; i++) { + NS2Indx[i] = m; + if ((--k) == 0) { + k = ++Step; + m++; + } + } + for (int j = 0; j < 0x40; j++) { + HB2Flag[j] = 0; + } + for (int j = 0; j < 0x100 - 0x40; j++) { + HB2Flag[0x40 + j] = 0x08; + } + dummySEE2Cont.setShift(PERIOD_BITS); + + } + + private void clearMask() + { + escCount = 1; + Arrays.fill(charMask, 0); + } + + public boolean decodeInit(Unpack unpackRead, int escChar/* ref */) + throws IOException, RarException + { + + int MaxOrder = unpackRead.getChar() & 0xff; + boolean reset = ((MaxOrder & 0x20) != 0); + + int MaxMB = 0; + if (reset) { + MaxMB = unpackRead.getChar(); + } else { + if (subAlloc.GetAllocatedMemory() == 0) { + return (false); + } + } + if ((MaxOrder & 0x40) != 0) { + escChar = unpackRead.getChar(); + unpackRead.setPpmEscChar(escChar); + } + coder.initDecoder(unpackRead); + if (reset) { + MaxOrder = (MaxOrder & 0x1f) + 1; + if (MaxOrder > 16) { + MaxOrder = 16 + (MaxOrder - 16) * 3; + } + if (MaxOrder == 1) { + subAlloc.stopSubAllocator(); + return (false); + } + subAlloc.startSubAllocator(MaxMB + 1); + minContext = new PPMContext(getHeap()); + medContext = new PPMContext(getHeap()); + maxContext = new PPMContext(getHeap()); + foundState = new State(getHeap()); + dummySEE2Cont = new SEE2Context(); + for (int i = 0; i < 25; i++) { + for (int j = 0; j < 16; j++) { + SEE2Cont[i][j] = new SEE2Context(); + } + } + startModelRare(MaxOrder); + } + return (minContext.getAddress() != 0); + } + + public int decodeChar() throws IOException, RarException + { + // Debug + //subAlloc.dumpHeap(); + + if (minContext.getAddress() <= subAlloc.getPText() + || minContext.getAddress() > subAlloc.getHeapEnd()) { + return (-1); + } + + if (minContext.getNumStats() != 1) { + if (minContext.getFreqData().getStats() <= subAlloc.getPText() + || minContext.getFreqData().getStats() > subAlloc.getHeapEnd()) { + return (-1); + } + if (!minContext.decodeSymbol1(this)) { + return (-1); + } + } else { + minContext.decodeBinSymbol(this); + } + coder.decode(); + while (foundState.getAddress() == 0) { + coder.ariDecNormalize(); + do { + orderFall++; + minContext.setAddress(minContext.getSuffix());// =MinContext->Suffix; + if (minContext.getAddress() <= subAlloc.getPText() + || minContext.getAddress() > subAlloc.getHeapEnd()) { + return (-1); + } + } while (minContext.getNumStats() == numMasked); + if (!minContext.decodeSymbol2(this)) { + return (-1); + } + coder.decode(); + } + int Symbol = foundState.getSymbol(); + if ((orderFall == 0) && foundState.getSuccessor() > subAlloc.getPText()) { + // MinContext=MaxContext=FoundState->Successor; + int addr = foundState.getSuccessor(); + minContext.setAddress(addr); + maxContext.setAddress(addr); + } else { + updateModel(); + //this.foundState.setAddress(foundState.getAddress());//TODO just 4 debugging + if (escCount == 0) { + clearMask(); + } + } + coder.ariDecNormalize();// ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); + return (Symbol); + } + + public SEE2Context[][] getSEE2Cont() + { + return SEE2Cont; + } + + public SEE2Context getDummySEE2Cont() + { + return dummySEE2Cont; + } + + public int getInitRL() + { + return initRL; + } + + public void setEscCount(int escCount) + { + this.escCount = escCount&0xff; + } + + public int getEscCount() + { + return escCount; + } + + public void incEscCount(int dEscCount) { + setEscCount(getEscCount() + dEscCount); + } + + public int[] getCharMask() + { + return charMask; + } + + public int getNumMasked() + { + return numMasked; + } + + public void setNumMasked(int numMasked) + { + this.numMasked = numMasked; + } + + public void setPrevSuccess(int prevSuccess) + { + this.prevSuccess = prevSuccess&0xff; + } + + public int getInitEsc() + { + return initEsc; + } + + public void setInitEsc(int initEsc) + { + this.initEsc = initEsc; + } + + public void setRunLength(int runLength) + { + this.runLength = runLength; + } + + public int getRunLength() + { + return runLength; + } + + public void incRunLength(int dRunLength) { + setRunLength(getRunLength() + dRunLength); + } + + public int getPrevSuccess() + { + return prevSuccess; + } + + public int getHiBitsFlag() + { + return hiBitsFlag; + } + + public void setHiBitsFlag(int hiBitsFlag) + { + this.hiBitsFlag = hiBitsFlag&0xff; + } + + public int[][] getBinSumm() + { + return binSumm; + } + + public RangeCoder getCoder() + { + return coder; + } + + public int[] getHB2Flag() + { + return HB2Flag; + } + + public int[] getNS2BSIndx() + { + return NS2BSIndx; + } + + public int[] getNS2Indx() + { + return NS2Indx; + } + + public State getFoundState() + { + return foundState; + } + + public byte[] getHeap() + { + return subAlloc.getHeap(); + } + + public int getOrderFall() + { + return orderFall; + } + + private int /* ppmcontext ptr */createSuccessors(boolean Skip, + State p1 /* state ptr */) { + //State upState = tempState1.init(null); + StateRef upState = tempStateRef2; + State tempState = tempState1.init(getHeap()); + + // PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor; + PPMContext pc = tempPPMContext1.init(getHeap()); + pc.setAddress(minContext.getAddress()); + PPMContext upBranch = tempPPMContext2.init(getHeap()); + upBranch.setAddress(foundState.getSuccessor()); + + // STATE * p, * ps[MAX_O], ** pps=ps; + State p = tempState2.init(getHeap()); + int pps = 0; + + boolean noLoop = false; + + if (!Skip) { + ps[pps++] = foundState.getAddress();// *pps++ = FoundState; + if (pc.getSuffix() == 0) { + noLoop = true; + } + } + if (!noLoop) { + boolean loopEntry = false; + if (p1.getAddress() != 0) { + p.setAddress(p1.getAddress()); + pc.setAddress(pc.getSuffix());// =pc->Suffix; + loopEntry = true; + } + do { + if (!loopEntry) { + pc.setAddress(pc.getSuffix());// pc=pc->Suffix; + if (pc.getNumStats() != 1) { + p.setAddress(pc.getFreqData().getStats());// p=pc->U.Stats + if (p.getSymbol() != foundState.getSymbol()) { + do { + p.incAddress(); + } while (p.getSymbol() != foundState.getSymbol()); + } + } else { + p.setAddress(pc.getOneState().getAddress());// p=&(pc->OneState); + } + }// LOOP_ENTRY: + loopEntry = false; + if (p.getSuccessor() != upBranch.getAddress()) { + pc.setAddress(p.getSuccessor());// =p->Successor; + break; + } + ps[pps++] = p.getAddress(); + } while (pc.getSuffix() != 0); + + } // NO_LOOP: + if (pps == 0) { + return pc.getAddress(); + } + upState.setSymbol(getHeap()[upBranch.getAddress()]);// UpState.Symbol=*(byte*) + // UpBranch; + // UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1); + upState.setSuccessor(upBranch.getAddress() + 1); //TODO check if +1 necessary + if (pc.getNumStats() != 1) { + if (pc.getAddress() <= subAlloc.getPText()) { + return (0); + } + p.setAddress(pc.getFreqData().getStats()); + if (p.getSymbol() != upState.getSymbol()) { + do { + p.incAddress(); + } while (p.getSymbol() != upState.getSymbol()); + } + int cf = p.getFreq() - 1; + int s0 = pc.getFreqData().getSummFreq() - pc.getNumStats() - cf; + // UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0))); + upState.setFreq(1 + ((2 * cf <= s0) ? (5 * cf > s0 ? 1 : 0) : + ((2 * cf + 3 * s0 - 1) / (2 * s0)))); + } else { + upState.setFreq(pc.getOneState().getFreq());// UpState.Freq=pc->OneState.Freq; + } + do { + // pc = pc->createChild(this,*--pps,UpState); + tempState.setAddress(ps[--pps]); + pc.setAddress(pc.createChild(this, tempState, upState)); + if (pc.getAddress() == 0) { + return 0; + } + } while (pps != 0); + return pc.getAddress(); + } + + private void updateModelRestart() + { + restartModelRare(); + escCount = 0; + } + + private void updateModel() + { + //System.out.println("ModelPPM.updateModel()"); + // STATE fs = *FoundState, *p = NULL; + StateRef fs = tempStateRef1; + fs.setValues(foundState); + State p = tempState3.init(getHeap()); + State tempState = tempState4.init(getHeap()); + + PPMContext pc = tempPPMContext3.init(getHeap()); + PPMContext successor = tempPPMContext4.init(getHeap()); + + int ns1, ns, cf, sf, s0; + pc.setAddress(minContext.getSuffix()); + if (fs.getFreq() < MAX_FREQ / 4 && pc.getAddress() != 0) { + if (pc.getNumStats() != 1) { + p.setAddress(pc.getFreqData().getStats()); + if (p.getSymbol() != fs.getSymbol()) { + do { + p.incAddress(); + } while (p.getSymbol() != fs.getSymbol()); + tempState.setAddress(p.getAddress() - State.size); + if (p.getFreq() >= tempState.getFreq()) { + State.ppmdSwap(p, tempState); + p.decAddress(); + } + } + if (p.getFreq() < MAX_FREQ - 9) { + p.incFreq(2); + pc.getFreqData().incSummFreq(2); + } + } else { + p.setAddress(pc.getOneState().getAddress()); + if (p.getFreq() < 32) { + p.incFreq(1); + } + } + } + if (orderFall == 0) { + foundState.setSuccessor(createSuccessors(true, p)); + minContext.setAddress(foundState.getSuccessor()); + maxContext.setAddress(foundState.getSuccessor()); + if (minContext.getAddress() == 0) { + updateModelRestart(); + return; + } + return; + } + subAlloc.getHeap()[subAlloc.getPText()] = (byte)fs.getSymbol(); + subAlloc.incPText(); + successor.setAddress(subAlloc.getPText()); + if (subAlloc.getPText() >= subAlloc.getFakeUnitsStart()) { + updateModelRestart(); + return; + } +// // Debug +// subAlloc.dumpHeap(); + if (fs.getSuccessor() != 0) { + if (fs.getSuccessor() <= subAlloc.getPText()) { + fs.setSuccessor(createSuccessors(false, p)); + if (fs.getSuccessor() == 0) { + updateModelRestart(); + return; + } + } + if (--orderFall == 0) { + successor.setAddress(fs.getSuccessor()); + if (maxContext.getAddress() != minContext.getAddress()) { + subAlloc.decPText(1); + } + } + } + else { + foundState.setSuccessor(successor.getAddress()); + fs.setSuccessor(minContext); + } +// // Debug +// subAlloc.dumpHeap(); + ns = minContext.getNumStats(); + s0 = minContext.getFreqData().getSummFreq() - (ns) - (fs.getFreq() - 1); + for (pc.setAddress(maxContext.getAddress()); + pc.getAddress() != minContext.getAddress(); + pc.setAddress(pc.getSuffix())) { + if ((ns1 = pc.getNumStats()) != 1) { + if ((ns1 & 1) == 0) { + //System.out.println(ns1); + pc.getFreqData().setStats( + subAlloc.expandUnits(pc.getFreqData().getStats(), + ns1 >>> 1)); + if (pc.getFreqData().getStats() == 0) { + updateModelRestart(); + return; + } + } + // bug fixed +// int sum = ((2 * ns1 < ns) ? 1 : 0) + +// 2 * ((4 * ((ns1 <= ns) ? 1 : 0)) & ((pc.getFreqData() +// .getSummFreq() <= 8 * ns1) ? 1 : 0)); + int sum = ((2 * ns1 < ns) ? 1 : 0) + 2 * ( + ((4 * ns1 <= ns) ? 1 : 0) & + ((pc.getFreqData().getSummFreq() <= 8 * ns1) ? 1 : 0) + ); + pc.getFreqData().incSummFreq(sum); + } + else { + p.setAddress(subAlloc.allocUnits(1)); + if (p.getAddress() == 0) { + updateModelRestart(); + return; + } + p.setValues(pc.getOneState()); + pc.getFreqData().setStats(p); + if (p.getFreq() < MAX_FREQ / 4 - 1) { + p.incFreq(p.getFreq()); + } + else { + p.setFreq(MAX_FREQ - 4); + } + pc.getFreqData().setSummFreq( + (p.getFreq() + initEsc + (ns > 3 ? 1 : 0))); + } + cf = 2 * fs.getFreq() * (pc.getFreqData().getSummFreq() + 6); + sf = s0 + pc.getFreqData().getSummFreq(); + if (cf < 6 * sf) { + cf = 1 + (cf > sf ? 1 : 0) + (cf >= 4 * sf ? 1 : 0); + pc.getFreqData().incSummFreq(3); + } + else { + cf = 4 + (cf >= 9 * sf ? 1 : 0) + (cf >= 12 * sf ? 1 : 0) + + (cf >= 15 * sf ? 1 : 0); + pc.getFreqData().incSummFreq(cf); + } + p.setAddress(pc.getFreqData().getStats() + ns1*State.size); + p.setSuccessor(successor); + p.setSymbol(fs.getSymbol()); + p.setFreq(cf); + pc.setNumStats(++ns1); + } + + int address = fs.getSuccessor(); + maxContext.setAddress(address); + minContext.setAddress(address); + //TODO-----debug +// int pos = minContext.getFreqData().getStats(); +// State a = new State(getHeap()); +// a.setAddress(pos); +// pos+=State.size; +// a.setAddress(pos); + //--dbg end + return; + } + + // Debug + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("ModelPPM["); + buffer.append("\n numMasked="); + buffer.append(numMasked); + buffer.append("\n initEsc="); + buffer.append(initEsc); + buffer.append("\n orderFall="); + buffer.append(orderFall); + buffer.append("\n maxOrder="); + buffer.append(maxOrder); + buffer.append("\n runLength="); + buffer.append(runLength); + buffer.append("\n initRL="); + buffer.append(initRL); + buffer.append("\n escCount="); + buffer.append(escCount); + buffer.append("\n prevSuccess="); + buffer.append(prevSuccess); + buffer.append("\n foundState="); + buffer.append(foundState); + buffer.append("\n coder="); + buffer.append(coder); + buffer.append("\n subAlloc="); + buffer.append(subAlloc); + buffer.append("\n]"); + return buffer.toString(); + } + + // Debug +// public void dumpHeap() { +// subAlloc.dumpHeap(); +// } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/PPMContext.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/PPMContext.java new file mode 100644 index 0000000..f6e5d67 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/PPMContext.java @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + +import com.github.junrar.io.Raw; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class PPMContext extends Pointer +{ + + private static final int unionSize = Math.max(FreqData.size, State.size); + + public static final int size = 2 + unionSize + 4; // 12 + + // ushort NumStats; + private int numStats; // determines if feqData or onstate is used + + // (1==onestate) + + private final FreqData freqData; // -\ + + // |-> union + private final State oneState; // -/ + + private int suffix; // pointer ppmcontext + + public final static int[] ExpEscape = + { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; + + // Temp fields + private final State tempState1 = new State(null); + private final State tempState2 = new State(null); + private final State tempState3 = new State(null); + private final State tempState4 = new State(null); + private final State tempState5 = new State(null); + private PPMContext tempPPMContext = null; + private final int[] ps = new int[256]; + + public PPMContext(byte[] mem) + { + super(mem); + oneState = new State(mem); + freqData = new FreqData(mem); + } + + public PPMContext init(byte[] mem) { + this.mem = mem; + pos = 0; + oneState.init(mem); + freqData.init(mem); + return this; + } + + public FreqData getFreqData() + { + return freqData; + } + + public void setFreqData(FreqData freqData) + { + this.freqData.setSummFreq(freqData.getSummFreq()); + this.freqData.setStats(freqData.getStats()); + } + + public final int getNumStats() + { + if (mem!=null){ + numStats = Raw.readShortLittleEndian(mem, pos)&0xffff; + } + return numStats; + } + + public final void setNumStats(int numStats) + { + this.numStats = numStats&0xffff; + if (mem != null) { + Raw.writeShortLittleEndian(mem, pos, (short)numStats); + } + } + + public State getOneState() + { + return oneState; + } + + public void setOneState(StateRef oneState) + { + this.oneState.setValues(oneState); + } + + public int getSuffix() + { + if(mem!=null){ + suffix = Raw.readIntLittleEndian(mem, pos+8); + } + return suffix; + } + + public void setSuffix(PPMContext suffix) + { + setSuffix(suffix.getAddress()); + } + + public void setSuffix(int suffix) + { + this.suffix = suffix; + if (mem != null) { + Raw.writeIntLittleEndian(mem, pos + 8, suffix); + } + } + + @Override + public void setAddress(int pos) + { + super.setAddress(pos); + oneState.setAddress(pos+2); + freqData.setAddress(pos+2); + } + + private PPMContext getTempPPMContext(byte[] mem) { + if (tempPPMContext == null) { + tempPPMContext = new PPMContext(null); + } + return tempPPMContext.init(mem); + } + + public int createChild(ModelPPM model, State pStats/* ptr */, + StateRef firstState /* ref */) + { + PPMContext pc = getTempPPMContext(model.getSubAlloc().getHeap()); + pc.setAddress(model.getSubAlloc().allocContext()); + if (pc != null) { + pc.setNumStats(1); + pc.setOneState(firstState); + pc.setSuffix(this); + pStats.setSuccessor(pc); + } + return pc.getAddress(); + } + + public void rescale(ModelPPM model) + { + int OldNS = getNumStats(), i = getNumStats() - 1, Adder, EscFreq; + // STATE* p1, * p; + State p1 = new State(model.getHeap()); + State p = new State(model.getHeap()); + State temp = new State(model.getHeap()); + + for (p.setAddress(model.getFoundState().getAddress()); + p.getAddress() != freqData.getStats(); + p.decAddress()) { + temp.setAddress(p.getAddress() - State.size); + State.ppmdSwap(p, temp); + } + temp.setAddress(freqData.getStats()); + temp.incFreq(4); + freqData.incSummFreq(4); + EscFreq = freqData.getSummFreq() - p.getFreq(); + Adder = (model.getOrderFall() != 0) ? 1 : 0; + p.setFreq((p.getFreq() + Adder) >>> 1); + freqData.setSummFreq(p.getFreq()); + do { + p.incAddress(); + EscFreq -= p.getFreq(); + p.setFreq((p.getFreq() + Adder) >>> 1); + freqData.incSummFreq(p.getFreq()); + temp.setAddress(p.getAddress() - State.size); + if (p.getFreq() > temp.getFreq()) { + p1.setAddress(p.getAddress()); + StateRef tmp = new StateRef(); + tmp.setValues(p1); + State temp2 = new State(model.getHeap()); + State temp3 = new State(model.getHeap()); + do { + // p1[0]=p1[-1]; + temp2.setAddress(p1.getAddress() - State.size); + p1.setValues(temp2); + p1.decAddress(); + temp3.setAddress(p1.getAddress() - State.size); + } while (p1.getAddress() != freqData.getStats() && tmp.getFreq() > temp3.getFreq()); + p1.setValues(tmp); + } + } while (--i != 0); + if (p.getFreq() == 0) { + do { + i++; + p.decAddress(); + } while (p.getFreq() == 0); + EscFreq += i; + setNumStats(getNumStats() - i); + if (getNumStats() == 1) { + StateRef tmp = new StateRef(); + temp.setAddress(freqData.getStats()); + tmp.setValues(temp); + // STATE tmp=*U.Stats; + do { + // tmp.Freq-=(tmp.Freq >> 1) + tmp.decFreq(tmp.getFreq() >>> 1); + EscFreq >>>= 1; + } while (EscFreq > 1); + model.getSubAlloc().freeUnits(freqData.getStats(),(OldNS + 1) >>> 1); + oneState.setValues(tmp); + model.getFoundState().setAddress(oneState.getAddress()); + return; + } + } + EscFreq -= EscFreq >>> 1; + freqData.incSummFreq(EscFreq); + int n0 = (OldNS + 1) >>> 1, n1 = (getNumStats() + 1) >>> 1; + if (n0 != n1) { + freqData.setStats(model.getSubAlloc().shrinkUnits(freqData.getStats(), n0, n1)); + } + model.getFoundState().setAddress(freqData.getStats()); + } + + private int getArrayIndex(ModelPPM Model, State rs) + { + PPMContext tempSuffix = getTempPPMContext(Model.getSubAlloc().getHeap()); + tempSuffix.setAddress(getSuffix()); + int ret = 0; + ret += Model.getPrevSuccess(); + ret += Model.getNS2BSIndx()[tempSuffix.getNumStats() - 1]; + ret += Model.getHiBitsFlag() + 2* Model.getHB2Flag()[rs.getSymbol()]; + ret += ((Model.getRunLength() >>> 26) & 0x20); + return ret; + } + + public int getMean(int summ, int shift, int round) + { + return ( (summ + (1 << (shift - round) ) ) >>> (shift) ); + } + + public void decodeBinSymbol(ModelPPM model) + { + State rs = tempState1.init(model.getHeap()); + rs.setAddress(oneState.getAddress());// State& + model.setHiBitsFlag(model.getHB2Flag()[model.getFoundState().getSymbol()]); + int off1 = rs.getFreq() - 1; + int off2 = getArrayIndex(model, rs); + int bs = model.getBinSumm()[off1][off2]; + if (model.getCoder().getCurrentShiftCount(ModelPPM.TOT_BITS) < bs) { + model.getFoundState().setAddress(rs.getAddress()); + rs.incFreq((rs.getFreq() < 128) ? 1 : 0); + model.getCoder().getSubRange().setLowCount(0); + model.getCoder().getSubRange().setHighCount(bs); + bs = ((bs + ModelPPM.INTERVAL - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xffff); + model.getBinSumm()[off1][off2] = bs; + model.setPrevSuccess(1); + model.incRunLength(1); + } else { + model.getCoder().getSubRange().setLowCount(bs); + bs = (bs - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xFFFF; + model.getBinSumm()[off1][off2] = bs; + model.getCoder().getSubRange().setHighCount(ModelPPM.BIN_SCALE); + model.setInitEsc(ExpEscape[bs >>> 10]); + model.setNumMasked(1); + model.getCharMask()[rs.getSymbol()] = model.getEscCount(); + model.setPrevSuccess(0); + model.getFoundState().setAddress(0); + } + //int a = 0;//TODO just 4 debugging + } + +// public static void ppmdSwap(ModelPPM model, StatePtr state1, StatePtr state2) +// { +// byte[] bytes = model.getSubAlloc().getHeap(); +// int p1 = state1.getAddress(); +// int p2 = state2.getAddress(); +// +// for (int i = 0; i < StatePtr.size; i++) { +// byte temp = bytes[p1+i]; +// bytes[p1+i] = bytes[p2+i]; +// bytes[p2+i] = temp; +// } +// state1.setAddress(p1); +// state2.setAddress(p2); +// } + + public void update1(ModelPPM model, int p/* ptr */) + { + model.getFoundState().setAddress(p); + model.getFoundState().incFreq(4); + freqData.incSummFreq(4); + State p0 = tempState3.init(model.getHeap()); + State p1 = tempState4.init(model.getHeap()); + p0.setAddress(p); + p1.setAddress(p - State.size); + if (p0.getFreq() > p1.getFreq()) { + State.ppmdSwap(p0, p1); + model.getFoundState().setAddress(p1.getAddress()); + if (p1.getFreq() > ModelPPM.MAX_FREQ) + rescale(model); + } + } + + public boolean decodeSymbol2(ModelPPM model) + { + long count; + int hiCnt, i = getNumStats() - model.getNumMasked(); + SEE2Context psee2c = makeEscFreq2(model, i); + RangeCoder coder = model.getCoder(); + // STATE* ps[256], ** pps=ps, * p=U.Stats-1; + State p = tempState1.init(model.getHeap()); + State temp = tempState2.init(model.getHeap()); + p.setAddress(freqData.getStats() - State.size); + int pps = 0; + hiCnt = 0; + + do { + do { + p.incAddress();// p++; + } while (model.getCharMask()[p.getSymbol()] == model.getEscCount()); + hiCnt += p.getFreq(); + ps[pps++] = p.getAddress(); + } while (--i != 0); + coder.getSubRange().incScale(hiCnt); + count = coder.getCurrentCount(); + if (count >= coder.getSubRange().getScale()) { + return false; + } + pps = 0; + p.setAddress(ps[pps]); + if (count < hiCnt) { + hiCnt = 0; + while ((hiCnt += p.getFreq()) <= count) { + p.setAddress(ps[++pps]);// p=*++pps; + } + coder.getSubRange().setHighCount(hiCnt); + coder.getSubRange().setLowCount(hiCnt - p.getFreq()); + psee2c.update(); + update2(model, p.getAddress()); + } else { + coder.getSubRange().setLowCount(hiCnt); + coder.getSubRange().setHighCount(coder.getSubRange().getScale()); + i = getNumStats() - model.getNumMasked();// ->NumMasked; + pps--; + do { + temp.setAddress(ps[++pps]);// (*++pps) + model.getCharMask()[temp.getSymbol()] = model.getEscCount(); + } while (--i != 0); + psee2c.incSumm((int)coder.getSubRange().getScale()); + model.setNumMasked(getNumStats()); + } + return (true); + } + + public void update2(ModelPPM model, int p/* state ptr */) + { + State temp = tempState5.init(model.getHeap()); + temp.setAddress(p); + model.getFoundState().setAddress(p); + model.getFoundState().incFreq(4); + freqData.incSummFreq(4); + if (temp.getFreq() > ModelPPM.MAX_FREQ) { + rescale(model); + } + model.incEscCount(1); + model.setRunLength(model.getInitRL()); + } + + private SEE2Context makeEscFreq2(ModelPPM model, int Diff) + { + SEE2Context psee2c; + int numStats = getNumStats(); + if (numStats != 256) { + PPMContext suff = getTempPPMContext(model.getHeap()); + suff.setAddress(getSuffix()); + int idx1 = model.getNS2Indx()[Diff - 1]; + int idx2 = 0; + idx2 += (Diff < suff.getNumStats() - numStats) ? 1 : 0; + idx2 += 2 * ((freqData.getSummFreq() < 11 * numStats) ? 1 : 0); + idx2 += 4 * ((model.getNumMasked() > Diff) ? 1 : 0); + idx2 += model.getHiBitsFlag(); + psee2c = model.getSEE2Cont()[idx1][idx2]; + model.getCoder().getSubRange().setScale(psee2c.getMean()); + } else { + psee2c = model.getDummySEE2Cont(); + model.getCoder().getSubRange().setScale(1); + } + return psee2c; + } + + public boolean decodeSymbol1(ModelPPM model) + { + + RangeCoder coder = model.getCoder(); + coder.getSubRange().setScale(freqData.getSummFreq()); + State p = new State(model.getHeap()); + p.setAddress(freqData.getStats()); + int i, HiCnt; + long count = coder.getCurrentCount(); + if (count >= coder.getSubRange().getScale()) { + return false; + } + if (count < (HiCnt = p.getFreq())) { + coder.getSubRange().setHighCount(HiCnt); + model.setPrevSuccess((2 * HiCnt > coder.getSubRange().getScale()) ? 1 : 0); + model.incRunLength(model.getPrevSuccess()); + HiCnt += 4; + model.getFoundState().setAddress(p.getAddress()); + model.getFoundState().setFreq(HiCnt); + freqData.incSummFreq(4); + if (HiCnt > ModelPPM.MAX_FREQ) { + rescale(model); + } + coder.getSubRange().setLowCount(0); + return true; + } else { + if (model.getFoundState().getAddress() == 0) { + return (false); + } + } + model.setPrevSuccess(0); + int numStats = getNumStats(); + i = numStats - 1; + while ((HiCnt += p.incAddress().getFreq()) <= count) + { + if (--i == 0) { + model.setHiBitsFlag(model.getHB2Flag()[model.getFoundState().getSymbol()]); + coder.getSubRange().setLowCount(HiCnt); + model.getCharMask()[p.getSymbol()] = model.getEscCount(); + model.setNumMasked(numStats); + i = numStats - 1; + model.getFoundState().setAddress(0); + do { + model.getCharMask()[p.decAddress().getSymbol()] = model.getEscCount(); + } while (--i != 0); + coder.getSubRange().setHighCount(coder.getSubRange().getScale()); + return (true); + } + } + coder.getSubRange().setLowCount(HiCnt-p.getFreq()); + coder.getSubRange().setHighCount(HiCnt); + update1(model, p.getAddress()); + return (true); + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("PPMContext["); + buffer.append("\n pos="); + buffer.append(pos); + buffer.append("\n size="); + buffer.append(size); + buffer.append("\n numStats="); + buffer.append(getNumStats()); + buffer.append("\n Suffix="); + buffer.append(getSuffix()); + buffer.append("\n freqData="); + buffer.append(freqData); + buffer.append("\n oneState="); + buffer.append(oneState); + buffer.append("\n]"); + return buffer.toString(); + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/Pointer.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/Pointer.java new file mode 100644 index 0000000..c206b9d --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/Pointer.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 14.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + +/** + * Simulates Pointers on a single mem block as a byte[] + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public abstract class Pointer +{ + protected byte[] mem; + protected int pos; + + /** + * Initialize the object with the array (may be null) + * @param mem the byte array + */ + public Pointer(byte[] mem){ + this.mem = mem; + } + /** + * returns the position of this object in the byte[] + * @return the address of this object + */ + public int getAddress(){ + assert (mem != null); + return pos; + } + + /** + * needs to set the fields of this object to the values in the byte[] + * at the given position. + * be aware of the byte order + * @param pos the position this object should point to + * @return true if the address could be set + */ + public void setAddress(int pos) { + assert (mem != null); + assert (pos >= 0) && (pos < mem.length) : pos; + this.pos = pos; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RangeCoder.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RangeCoder.java new file mode 100644 index 0000000..734813f --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RangeCoder.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + +import java.io.IOException; + +import com.github.junrar.exception.RarException; +import com.github.junrar.unpack.Unpack; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RangeCoder +{ + public static final int TOP = 1 << 24; + + public static final int BOT = 1 << 15; + + private static final long uintMask = 0xFFFFffffL; + + // uint low, code, range; + private long low, code, range; + + private final SubRange subRange = new SubRange(); + + private Unpack unpackRead; + + public SubRange getSubRange() + { + return subRange; + } + + public void initDecoder(Unpack unpackRead) throws IOException, RarException + { + this.unpackRead = unpackRead; + + low = code = 0L; + range = 0xFFFFffffL; + for (int i = 0; i < 4; i++) { + code = ((code << 8) | getChar())&uintMask; + } + } + + public int getCurrentCount() + { + range = (range / subRange.getScale())&uintMask; + return (int)((code - low) / (range)); + } + + public long getCurrentShiftCount(int SHIFT) + { + range = range >>>SHIFT; + return ((code - low) / (range))&uintMask; + } + + public void decode() + { + low = (low + (range * subRange.getLowCount()))&uintMask; + range = (range * (subRange.getHighCount() - subRange.getLowCount()))&uintMask; + } + + private int getChar() throws IOException, RarException + { + return (unpackRead.getChar()); + } + + public void ariDecNormalize() throws IOException, RarException + { +// while ((low ^ (low + range)) < TOP || range < BOT && ((range = -low & (BOT - 1)) != 0 ? true : true)) +// { +// code = ((code << 8) | unpackRead.getChar()&0xff)&uintMask; +// range = (range << 8)&uintMask; +// low = (low << 8)&uintMask; +// } + + // Rewrote for clarity + boolean c2 = false; + while ((low ^ (low + range)) < TOP || (c2 = range < BOT)) { + if (c2) { + range = (-low & (BOT - 1))&uintMask; + c2 = false; + } + code = ((code << 8) | getChar())&uintMask; + range = (range << 8)&uintMask; + low = (low << 8)&uintMask; + } + } + + // Debug + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("RangeCoder["); + buffer.append("\n low="); + buffer.append(low); + buffer.append("\n code="); + buffer.append(code); + buffer.append("\n range="); + buffer.append(range); + buffer.append("\n subrange="); + buffer.append(subRange); + buffer.append("]"); + return buffer.toString(); + } + + public static class SubRange + { + // uint LowCount, HighCount, scale; + private long lowCount, highCount, scale; + + public long getHighCount() + { + return highCount; + } + + public void setHighCount(long highCount) + { + this.highCount = highCount&uintMask; + } + + public long getLowCount() + { + return lowCount&uintMask; + } + + public void setLowCount(long lowCount) + { + this.lowCount = lowCount&uintMask; + } + + public long getScale() + { + return scale; + } + + public void setScale(long scale) + { + this.scale = scale&uintMask; + } + + public void incScale(int dScale) { + setScale(getScale() + dScale); + } + + // Debug + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("SubRange["); + buffer.append("\n lowCount="); + buffer.append(lowCount); + buffer.append("\n highCount="); + buffer.append(highCount); + buffer.append("\n scale="); + buffer.append(scale); + buffer.append("]"); + return buffer.toString(); + } + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarMemBlock.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarMemBlock.java new file mode 100644 index 0000000..1b5e7cc --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarMemBlock.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 05.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + +import com.github.junrar.io.Raw; + + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RarMemBlock extends Pointer +{ + + public static final int size = 12; + + private int stamp, NU; + + private int next, prev; // Pointer RarMemBlock + + public RarMemBlock(byte[] mem) + { + super(mem); + } + + public void insertAt(RarMemBlock p) + { + RarMemBlock temp = new RarMemBlock(mem); + setPrev(p.getAddress()); + temp.setAddress(getPrev()); + setNext(temp.getNext());// prev.getNext(); + temp.setNext(this);// prev.setNext(this); + temp.setAddress(getNext()); + temp.setPrev(this);// next.setPrev(this); + } + + public void remove() + { + RarMemBlock temp = new RarMemBlock(mem); + temp.setAddress(getPrev()); + temp.setNext(getNext());// prev.setNext(next); + temp.setAddress(getNext()); + temp.setPrev(getPrev());// next.setPrev(prev); +// next = -1; +// prev = -1; + } + + public int getNext() + { + if(mem!=null){ + next = Raw.readIntLittleEndian(mem, pos+4); + } + return next; + } + + public void setNext(RarMemBlock next) + { + setNext(next.getAddress()); + } + + public void setNext(int next) + { + this.next = next; + if (mem != null) { + Raw.writeIntLittleEndian(mem, pos + 4, next); + } + } + + public int getNU() + { + if(mem!=null){ + NU = Raw.readShortLittleEndian(mem, pos+2)&0xffff; + } + return NU; + } + + public void setNU(int nu) + { + NU = nu&0xffff; + if (mem != null) { + Raw.writeShortLittleEndian(mem, pos + 2, (short)nu); + } + } + + public int getPrev() + { + if(mem!=null){ + prev = Raw.readIntLittleEndian(mem, pos+8); + } + return prev; + } + + public void setPrev(RarMemBlock prev) + { + setPrev(prev.getAddress()); + } + + public void setPrev(int prev) + { + this.prev = prev; + if (mem != null) { + Raw.writeIntLittleEndian(mem, pos + 8, prev); + } + } + + public int getStamp() + { + if(mem!=null){ + stamp = Raw.readShortLittleEndian(mem, pos)&0xffff; + } + return stamp; + } + + public void setStamp(int stamp) + { + this.stamp = stamp; + if (mem != null) { + Raw.writeShortLittleEndian(mem, pos, (short)stamp); + } + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarNode.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarNode.java new file mode 100644 index 0000000..a9353cb --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarNode.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 05.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + +import com.github.junrar.io.Raw; + + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RarNode extends Pointer{ + private int next; //rarnode pointer + + public static final int size = 4; + + public RarNode(byte[] mem){ + super(mem); + } + + public int getNext() { + if(mem!=null){ + next = Raw.readIntLittleEndian(mem, pos); + } + return next; + } + + public void setNext(RarNode next) { + setNext(next.getAddress()); + } + + public void setNext(int next) { + this.next = next; + if(mem!=null){ + Raw.writeIntLittleEndian(mem, pos, next); + } + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("State["); + buffer.append("\n pos="); + buffer.append(pos); + buffer.append("\n size="); + buffer.append(size); + buffer.append("\n next="); + buffer.append(getNext()); + buffer.append("\n]"); + return buffer.toString(); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SEE2Context.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SEE2Context.java new file mode 100644 index 0000000..1f42419 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SEE2Context.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class SEE2Context { + public static final int size = 4; + + // ushort Summ; + private int summ; + + // byte Shift; + private int shift; + + // byte Count; + private int count; + + public void init(int initVal) { + shift = (ModelPPM.PERIOD_BITS - 4)&0xff; + summ = (initVal << shift)&0xffff; + count = 4; + } + + public int getMean() { + int retVal = summ >>> shift; + summ -= retVal; + return retVal + ((retVal == 0) ? 1 : 0); + } + + public void update() { + if (shift < ModelPPM.PERIOD_BITS && --count == 0) { + summ += summ; + count = (3 << shift++); + } + summ &= 0xffff; + count &= 0xff; + shift &= 0xff; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count&0xff; + } + + public int getShift() { + return shift; + } + + public void setShift(int shift) { + this.shift = shift&0xff; + } + + public int getSumm() { + return summ; + } + + public void setSumm(int summ) { + this.summ = summ&0xffff; + } + + public void incSumm(int dSumm) { + setSumm(getSumm() + dSumm); + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("SEE2Context["); + buffer.append("\n size="); + buffer.append(size); + buffer.append("\n summ="); + buffer.append(summ); + buffer.append("\n shift="); + buffer.append(shift); + buffer.append("\n count="); + buffer.append(count); + buffer.append("\n]"); + return buffer.toString(); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/State.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/State.java new file mode 100644 index 0000000..812fb40 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/State.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + +import com.github.junrar.io.Raw; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class State extends Pointer { + + public static final int size = 6; + + public State(byte[] mem) { + super(mem); + } + + public State init(byte[] mem) { + this.mem = mem; + pos = 0; + return this; + } + + public int getSymbol() { + return mem[pos]&0xff; + } + + public void setSymbol(int symbol) { + mem[pos] = (byte)symbol; + } + + public int getFreq() { + return mem[pos+1]&0xff; + } + + public void setFreq(int freq) { + mem[pos + 1] = (byte)freq; + } + + public void incFreq(int dFreq) { + mem[pos + 1] += dFreq; + } + + public int getSuccessor() { + return Raw.readIntLittleEndian(mem, pos+2); + } + + public void setSuccessor(PPMContext successor) { + setSuccessor(successor.getAddress()); + } + + public void setSuccessor(int successor) { + Raw.writeIntLittleEndian(mem, pos + 2, successor); + } + + public void setValues(StateRef state){ + setSymbol(state.getSymbol()); + setFreq(state.getFreq()); + setSuccessor(state.getSuccessor()); + } + + public void setValues(State ptr){ + System.arraycopy(ptr.mem, ptr.pos, mem, pos, size); + } + + public State decAddress(){ + setAddress(pos-size); + return this; + } + + public State incAddress(){ + setAddress(pos+size); + return this; + } + + public static void ppmdSwap(State ptr1, State ptr2) { + byte[] mem1=ptr1.mem, mem2=ptr2.mem; + for (int i=0, pos1=ptr1.pos, pos2=ptr2.pos; i < size; i++, pos1++, pos2++) { + byte temp = mem1[pos1]; + mem1[pos1] = mem2[pos2]; + mem2[pos2] = temp; + } + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("State["); + buffer.append("\n pos="); + buffer.append(pos); + buffer.append("\n size="); + buffer.append(size); + buffer.append("\n symbol="); + buffer.append(getSymbol()); + buffer.append("\n freq="); + buffer.append(getFreq()); + buffer.append("\n successor="); + buffer.append(getSuccessor()); + buffer.append("\n]"); + return buffer.toString(); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/StateRef.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/StateRef.java new file mode 100644 index 0000000..39195e0 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/StateRef.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 01.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class StateRef { + + private int symbol; + + private int freq; + + private int successor; // pointer ppmcontext + + public StateRef() { + } + + public int getSymbol() { + return symbol; + } + + public void setSymbol(int symbol) { + this.symbol = symbol&0xff; + } + + public int getFreq() { + return freq; + } + + public void setFreq(int freq) { + this.freq = freq&0xff; + } + + public void incFreq(int dFreq) { + freq = (freq + dFreq)&0xff; + } + + public void decFreq(int dFreq) { + freq = (freq - dFreq)&0xff; + } + + public void setValues(State statePtr){ + setFreq(statePtr.getFreq()); + setSuccessor(statePtr.getSuccessor()); + setSymbol(statePtr.getSymbol()); + } + + public int getSuccessor() { + return successor; + } + + public void setSuccessor(PPMContext successor) { + setSuccessor(successor.getAddress()); + } + + public void setSuccessor(int successor) { + this.successor = successor; + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("State["); + buffer.append("\n symbol="); + buffer.append(getSymbol()); + buffer.append("\n freq="); + buffer.append(getFreq()); + buffer.append("\n successor="); + buffer.append(getSuccessor()); + buffer.append("\n]"); + return buffer.toString(); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SubAllocator.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SubAllocator.java new file mode 100644 index 0000000..8844736 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SubAllocator.java @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.ppm; + +import java.util.Arrays; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class SubAllocator { + public static final int N1 = 4, N2 = 4, N3 = 4, N4 = (128 + 3 - 1 * N1 - 2 + * N2 - 3 * N3) / 4; + + public static final int N_INDEXES = N1 + N2 + N3 + N4; + + public static final int UNIT_SIZE = Math.max(PPMContext.size, + RarMemBlock.size); + + public static final int FIXED_UNIT_SIZE = 12; + + private int subAllocatorSize; + + // byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount; + private int[] indx2Units = new int[N_INDEXES]; + private int[] units2Indx = new int[128]; + private int glueCount; + + // byte *HeapStart,*LoUnit, *HiUnit; + private int heapStart, loUnit, hiUnit; + + private final RarNode[] freeList = new RarNode[N_INDEXES]; + + // byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart; + private int pText, unitsStart, heapEnd, fakeUnitsStart; + + private byte[] heap; + + private int freeListPos; + + private int tempMemBlockPos; + + // Temp fields + private RarNode tempRarNode = null; + private RarMemBlock tempRarMemBlock1 = null; + private RarMemBlock tempRarMemBlock2 = null; + private RarMemBlock tempRarMemBlock3 = null; + + public SubAllocator() { + clean(); + } + + public void clean() { + subAllocatorSize = 0; + } + + private void insertNode(int p/* rarnode ptr */, int indx) { + RarNode temp = tempRarNode; + temp.setAddress(p); + temp.setNext(freeList[indx].getNext()); + freeList[indx].setNext(temp); + } + + public void incPText() { + pText++; + } + + private int removeNode(int indx) { + int retVal = freeList[indx].getNext(); + RarNode temp = tempRarNode; + temp.setAddress(retVal); + freeList[indx].setNext(temp.getNext()); + return retVal; + } + + private int U2B(int NU) { + return /* 8*NU+4*NU */UNIT_SIZE * NU; + } + + /* memblockptr */ + private int MBPtr(int BasePtr, int Items) { + return (BasePtr + U2B(Items)); + } + + private void splitBlock(int pv/* ptr */, int oldIndx, int newIndx) { + int i, uDiff = indx2Units[oldIndx] - indx2Units[newIndx]; + int p = pv + U2B(indx2Units[newIndx]); + if (indx2Units[i = units2Indx[uDiff - 1]] != uDiff) { + insertNode(p, --i); + p += U2B(i = indx2Units[i]); + uDiff -= i; + } + insertNode(p, units2Indx[uDiff - 1]); + } + + public void stopSubAllocator() { + if (subAllocatorSize != 0) { + subAllocatorSize = 0; + heap = null; + heapStart = 1; + // rarfree(HeapStart); + // Free temp fields + tempRarNode = null; + tempRarMemBlock1 = null; + tempRarMemBlock2 = null; + tempRarMemBlock3 = null; + } + } + + public int GetAllocatedMemory() { + return subAllocatorSize; + }; + + public boolean startSubAllocator(int SASize) { + int t = SASize << 20; + if (subAllocatorSize == t) { + return true; + } + stopSubAllocator(); + int allocSize = t / FIXED_UNIT_SIZE * UNIT_SIZE + UNIT_SIZE; + + // adding space for freelist (needed for poiters) + // 1+ for null pointer + int realAllocSize = 1 + allocSize + 4 * N_INDEXES; + // adding space for an additional memblock + tempMemBlockPos = realAllocSize; + realAllocSize += RarMemBlock.size; + + heap = new byte[realAllocSize]; + heapStart = 1; + heapEnd = heapStart + allocSize - UNIT_SIZE; + subAllocatorSize = t; + // Bug fixed + freeListPos = heapStart + allocSize; + assert (realAllocSize - tempMemBlockPos == RarMemBlock.size) : realAllocSize + + " " + tempMemBlockPos + " " + RarMemBlock.size; + + // Init freeList + for (int i = 0, pos = freeListPos; i < freeList.length; i++, pos += RarNode.size) { + freeList[i] = new RarNode(heap); + freeList[i].setAddress(pos); + } + + // Init temp fields + tempRarNode = new RarNode(heap); + tempRarMemBlock1 = new RarMemBlock(heap); + tempRarMemBlock2 = new RarMemBlock(heap); + tempRarMemBlock3 = new RarMemBlock(heap); + + return true; + } + + private void glueFreeBlocks() { + RarMemBlock s0 = tempRarMemBlock1; + s0.setAddress(tempMemBlockPos); + RarMemBlock p = tempRarMemBlock2; + RarMemBlock p1 = tempRarMemBlock3; + int i, k, sz; + if (loUnit != hiUnit) { + heap[loUnit] = 0; + } + for (i = 0, s0.setPrev(s0), s0.setNext(s0); i < N_INDEXES; i++) { + while (freeList[i].getNext() != 0) { + p.setAddress(removeNode(i));// =(RAR_MEM_BLK*)RemoveNode(i); + p.insertAt(s0);// p->insertAt(&s0); + p.setStamp(0xFFFF);// p->Stamp=0xFFFF; + p.setNU(indx2Units[i]);// p->NU=Indx2Units[i]; + } + } + for (p.setAddress(s0.getNext()); p.getAddress() != s0.getAddress(); p + .setAddress(p.getNext())) { + // while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU + // < 0x10000) + // Bug fixed + p1.setAddress(MBPtr(p.getAddress(), p.getNU())); + while (p1.getStamp() == 0xFFFF && p.getNU() + p1.getNU() < 0x10000) { + p1.remove(); + p.setNU(p.getNU() + p1.getNU());// ->NU += p1->NU; + p1.setAddress(MBPtr(p.getAddress(), p.getNU())); + } + } + // while ((p=s0.next) != &s0) + // Bug fixed + p.setAddress(s0.getNext()); + while (p.getAddress() != s0.getAddress()) { + for (p.remove(), sz = p.getNU(); sz > 128; sz -= 128, p + .setAddress(MBPtr(p.getAddress(), 128))) { + insertNode(p.getAddress(), N_INDEXES - 1); + } + if (indx2Units[i = units2Indx[sz - 1]] != sz) { + k = sz - indx2Units[--i]; + insertNode(MBPtr(p.getAddress(), sz - k), k - 1); + } + insertNode(p.getAddress(), i); + p.setAddress(s0.getNext()); + } + } + + private int allocUnitsRare(int indx) { + if (glueCount == 0) { + glueCount = 255; + glueFreeBlocks(); + if (freeList[indx].getNext() != 0) { + return removeNode(indx); + } + } + int i = indx; + do { + if (++i == N_INDEXES) { + glueCount--; + i = U2B(indx2Units[indx]); + int j = FIXED_UNIT_SIZE * indx2Units[indx]; + if (fakeUnitsStart - pText > j) { + fakeUnitsStart -= j; + unitsStart -= i; + return unitsStart; + } + return (0); + } + } while (freeList[i].getNext() == 0); + int retVal = removeNode(i); + splitBlock(retVal, i, indx); + return retVal; + } + + public int allocUnits(int NU) { + int indx = units2Indx[NU - 1]; + if (freeList[indx].getNext() != 0) { + return removeNode(indx); + } + int retVal = loUnit; + loUnit += U2B(indx2Units[indx]); + if (loUnit <= hiUnit) { + return retVal; + } + loUnit -= U2B(indx2Units[indx]); + return allocUnitsRare(indx); + } + + public int allocContext() { + if (hiUnit != loUnit) + return (hiUnit -= UNIT_SIZE); + if (freeList[0].getNext() != 0) { + return removeNode(0); + } + return allocUnitsRare(0); + } + + public int expandUnits(int oldPtr, int OldNU) { + int i0 = units2Indx[OldNU - 1]; + int i1 = units2Indx[OldNU - 1 + 1]; + if (i0 == i1) { + return oldPtr; + } + int ptr = allocUnits(OldNU + 1); + if (ptr != 0) { + // memcpy(ptr,OldPtr,U2B(OldNU)); + System.arraycopy(heap, oldPtr, heap, ptr, U2B(OldNU)); + insertNode(oldPtr, i0); + } + return ptr; + } + + public int shrinkUnits(int oldPtr, int oldNU, int newNU) { + // System.out.println("SubAllocator.shrinkUnits(" + OldPtr + ", " + + // OldNU + ", " + NewNU + ")"); + int i0 = units2Indx[oldNU - 1]; + int i1 = units2Indx[newNU - 1]; + if (i0 == i1) { + return oldPtr; + } + if (freeList[i1].getNext() != 0) { + int ptr = removeNode(i1); + // memcpy(ptr,OldPtr,U2B(NewNU)); + // for (int i = 0; i < U2B(NewNU); i++) { + // heap[ptr + i] = heap[OldPtr + i]; + // } + System.arraycopy(heap, oldPtr, heap, ptr, U2B(newNU)); + insertNode(oldPtr, i0); + return ptr; + } else { + splitBlock(oldPtr, i0, i1); + return oldPtr; + } + } + + public void freeUnits(int ptr, int OldNU) { + insertNode(ptr, units2Indx[OldNU - 1]); + } + + public int getFakeUnitsStart() { + return fakeUnitsStart; + } + + public void setFakeUnitsStart(int fakeUnitsStart) { + this.fakeUnitsStart = fakeUnitsStart; + } + + public int getHeapEnd() { + return heapEnd; + } + + public int getPText() { + return pText; + } + + public void setPText(int text) { + pText = text; + } + + public void decPText(int dPText) { + setPText(getPText() - dPText); + } + + public int getUnitsStart() { + return unitsStart; + } + + public void setUnitsStart(int unitsStart) { + this.unitsStart = unitsStart; + } + + public void initSubAllocator() { + int i, k; + Arrays + .fill(heap, freeListPos, freeListPos + sizeOfFreeList(), + (byte) 0); + + pText = heapStart; + + int size2 = FIXED_UNIT_SIZE + * (subAllocatorSize / 8 / FIXED_UNIT_SIZE * 7); + int realSize2 = size2 / FIXED_UNIT_SIZE * UNIT_SIZE; + int size1 = subAllocatorSize - size2; + int realSize1 = size1 / FIXED_UNIT_SIZE * UNIT_SIZE + size1 + % FIXED_UNIT_SIZE; + hiUnit = heapStart + subAllocatorSize; + loUnit = unitsStart = heapStart + realSize1; + fakeUnitsStart = heapStart + size1; + hiUnit = loUnit + realSize2; + + for (i = 0, k = 1; i < N1; i++, k += 1) { + indx2Units[i] = k & 0xff; + } + for (k++; i < N1 + N2; i++, k += 2) { + indx2Units[i] = k & 0xff; + } + for (k++; i < N1 + N2 + N3; i++, k += 3) { + indx2Units[i] = k & 0xff; + } + for (k++; i < (N1 + N2 + N3 + N4); i++, k += 4) { + indx2Units[i] = k & 0xff; + } + + for (glueCount = 0, k = 0, i = 0; k < 128; k++) { + i += ((indx2Units[i] < (k + 1)) ? 1 : 0); + units2Indx[k] = i & 0xff; + } + + } + + private int sizeOfFreeList() { + return freeList.length * RarNode.size; + } + + public byte[] getHeap() { + return heap; + } + + // Debug + // public void dumpHeap() { + // File file = new File("P:\\test\\heapdumpj"); + // OutputStream out = null; + // try { + // out = new FileOutputStream(file); + // out.write(heap, heapStart, heapEnd - heapStart); + // out.flush(); + // System.out.println("Heap dumped to " + file.getAbsolutePath()); + // } + // catch (IOException e) { + // e.printStackTrace(); + // } + // finally { + // FileUtil.close(out); + // } + // } + + // Debug + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("SubAllocator["); + buffer.append("\n subAllocatorSize="); + buffer.append(subAllocatorSize); + buffer.append("\n glueCount="); + buffer.append(glueCount); + buffer.append("\n heapStart="); + buffer.append(heapStart); + buffer.append("\n loUnit="); + buffer.append(loUnit); + buffer.append("\n hiUnit="); + buffer.append(hiUnit); + buffer.append("\n pText="); + buffer.append(pText); + buffer.append("\n unitsStart="); + buffer.append(unitsStart); + buffer.append("\n]"); + return buffer.toString(); + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/BitInput.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/BitInput.java new file mode 100644 index 0000000..603cb77 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/BitInput.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class BitInput { + /** + * the max size of the input + */ + public static final int MAX_SIZE = 0x8000; + protected int inAddr; + protected int inBit; + protected byte[] inBuf; + + /** + * + */ + public void InitBitInput() + { + inAddr=0; + inBit=0; + } + /** + * @param Bits + */ + public void addbits(int Bits) + { + Bits+=inBit; + inAddr+=Bits>>3; + inBit=Bits&7; + } + + /** + * @return the bits (unsigned short) + */ + public int getbits() + { +// int BitField=0; +// BitField|=(int)(inBuf[inAddr] << 16)&0xFF0000; +// BitField|=(int)(inBuf[inAddr+1] << 8)&0xff00; +// BitField|=(int)(inBuf[inAddr+2])&0xFF; +// BitField >>>= (8-inBit); +// return (BitField & 0xffff); + return (((((inBuf[inAddr] & 0xff) << 16) + + ((inBuf[inAddr+1] & 0xff) << 8) + + ((inBuf[inAddr+2] & 0xff))) >>> (8-inBit)) & 0xffff); + } + + /** + * + */ + public BitInput() + { + inBuf=new byte[MAX_SIZE]; + } + + /** + * @param Bits add the bits + */ + public void faddbits(int Bits) + { + addbits(Bits); + } + + + /** + * @return get the bits + */ + public int fgetbits() + { + return(getbits()); + } + + /** + * Indicates an Overfow + * @param IncPtr how many bytes to inc + * @return true if an Oververflow would occur + */ + public boolean Overflow(int IncPtr) { + return(inAddr+IncPtr>=MAX_SIZE); + } + public byte[] getInBuf() + { + return inBuf; + } + + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/RarVM.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/RarVM.java new file mode 100644 index 0000000..e6e6a01 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/RarVM.java @@ -0,0 +1,1221 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.vm; + +import java.util.List; +import java.util.Vector; + +import com.github.junrar.crc.RarCRC; +import com.github.junrar.io.Raw; + + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class RarVM extends BitInput { + + public static final int VM_MEMSIZE = 0x40000; + + public static final int VM_MEMMASK = (VM_MEMSIZE - 1); + + public static final int VM_GLOBALMEMADDR = 0x3C000; + + public static final int VM_GLOBALMEMSIZE = 0x2000; + + public static final int VM_FIXEDGLOBALSIZE = 64; + + private static final int regCount = 8; + + private static final long UINT_MASK = 0xffffFFFF;//((long)2*(long)Integer.MAX_VALUE); + + private byte[] mem; + + private int[] R = new int[regCount]; + + private int flags; + + private int maxOpCount = 25000000; + + private int codeSize; + + private int IP; + + public RarVM() { + mem = null; + } + + public void init() { + if (mem == null) { + mem = new byte[VM_MEMSIZE + 4]; + } + } + + private boolean isVMMem(byte[] mem) { + return this.mem == mem; + } + + private int getValue(boolean byteMode, byte[] mem, int offset) { + if (byteMode) { + if (isVMMem(mem)) { + return (mem[offset]); + } else { + return (mem[offset] & 0xff); + } + } else { + if (isVMMem(mem)) { + //little + return Raw.readIntLittleEndian(mem, offset); + } else + //big endian + return Raw.readIntBigEndian(mem, offset); + } + } + + private void setValue(boolean byteMode, byte[] mem, int offset, int value) { + if (byteMode) { + if (isVMMem(mem)) { + mem[offset] = (byte) value; + } else { + mem[offset] = (byte) ((mem[offset] & 0x00) | (byte) (value & 0xff)); + } + } else { + if (isVMMem(mem)) { + Raw.writeIntLittleEndian(mem, offset, value); +// mem[offset + 0] = (byte) value; +// mem[offset + 1] = (byte) (value >>> 8); +// mem[offset + 2] = (byte) (value >>> 16); +// mem[offset + 3] = (byte) (value >>> 24); + } else { + Raw.writeIntBigEndian(mem, offset, value); +// mem[offset + 3] = (byte) value; +// mem[offset + 2] = (byte) (value >>> 8); +// mem[offset + 1] = (byte) (value >>> 16); +// mem[offset + 0] = (byte) (value >>> 24); + } + + } + // #define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint + // *)Addr,Value) + } + + public void setLowEndianValue(byte[] mem, int offset, int value) { + Raw.writeIntLittleEndian(mem, offset, value); +// mem[offset + 0] = (byte) (value&0xff); +// mem[offset + 1] = (byte) ((value >>> 8)&0xff); +// mem[offset + 2] = (byte) ((value >>> 16)&0xff); +// mem[offset + 3] = (byte) ((value >>> 24)&0xff); + } + public void setLowEndianValue(Vector mem, int offset, int value) { + mem.set(offset + 0, Byte.valueOf((byte) (value&0xff))) ; + mem.set(offset + 1, Byte.valueOf((byte) ((value >>> 8)&0xff))); + mem.set(offset + 2, Byte.valueOf((byte) ((value >>> 16)&0xff) )); + mem.set(offset + 3, Byte.valueOf((byte) ((value >>> 24)&0xff))) ; + } + private int getOperand(VMPreparedOperand cmdOp) { + int ret = 0; + if (cmdOp.getType() == VMOpType.VM_OPREGMEM) { + int pos = (cmdOp.getOffset() + cmdOp.getBase()) & VM_MEMMASK; + ret = Raw.readIntLittleEndian(mem, pos); + } else { + int pos = cmdOp.getOffset(); + ret = Raw.readIntLittleEndian(mem, pos); + } + return ret; + } + + public void execute(VMPreparedProgram prg) { + for (int i = 0; i < prg.getInitR().length; i++) // memcpy(R,Prg->InitR,sizeof(Prg->InitR)); + { + R[i] = prg.getInitR()[i]; + } + + long globalSize = Math + .min(prg.getGlobalData().size(), VM_GLOBALMEMSIZE) & 0xffFFffFF; + if (globalSize != 0) { + for (int i = 0; i < globalSize; i++) // memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); + { + mem[VM_GLOBALMEMADDR + i] = prg.getGlobalData().get(i); + } + + } + long staticSize = Math.min(prg.getStaticData().size(), VM_GLOBALMEMSIZE + - globalSize) & 0xffFFffFF; + if (staticSize != 0) { + for (int i = 0; i < staticSize; i++) // memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); + { + mem[VM_GLOBALMEMADDR + (int) globalSize + i] = prg + .getStaticData().get(i); + } + + } + R[7] = VM_MEMSIZE; + flags = 0; + + List preparedCode = prg.getAltCmd().size() != 0 ? prg + .getAltCmd() + : prg.getCmd(); + + if (!ExecuteCode(preparedCode, prg.getCmdCount())) { + preparedCode.get(0).setOpCode(VMCommands.VM_RET); + } + int newBlockPos = getValue(false, mem, VM_GLOBALMEMADDR + 0x20) + & VM_MEMMASK; + int newBlockSize = getValue(false, mem, VM_GLOBALMEMADDR + 0x1c) + & VM_MEMMASK; + if ((newBlockPos + newBlockSize) >= VM_MEMSIZE) { + newBlockPos = 0; + newBlockSize = 0; + } + + prg.setFilteredDataOffset(newBlockPos); + prg.setFilteredDataSize(newBlockSize); + + prg.getGlobalData().clear(); + + int dataSize = Math.min(getValue(false, mem, VM_GLOBALMEMADDR + 0x30), + VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE); + if (dataSize != 0) { + prg.getGlobalData().setSize(dataSize + VM_FIXEDGLOBALSIZE); + // ->GlobalData.Add(dataSize+VM_FIXEDGLOBALSIZE); + + for (int i = 0; i < dataSize + VM_FIXEDGLOBALSIZE; i++) // memcpy(&Prg->GlobalData[0],&Mem[VM_GLOBALMEMADDR],DataSize+VM_FIXEDGLOBALSIZE); + { + prg.getGlobalData().set(i, mem[VM_GLOBALMEMADDR + i]); + } + } + } + + public byte[] getMem() + { + return mem; + } + + private boolean setIP(int ip) { + if ((ip) >= codeSize) { + return (true); + } + + if (--maxOpCount <= 0) { + return (false); + } + + IP = ip; + return true; + } + + private boolean ExecuteCode(List preparedCode, + int cmdCount) { + + maxOpCount = 25000000; + this.codeSize = cmdCount; + this.IP = 0; + + while (true) { + VMPreparedCommand cmd = preparedCode.get(IP); + int op1 = getOperand(cmd.getOp1()); + int op2 = getOperand(cmd.getOp2()); + switch (cmd.getOpCode()) { + case VM_MOV: + setValue(cmd.isByteMode(), mem, op1, getValue(cmd.isByteMode(), + mem, op2)); // SET_VALUE(Cmd->ByteMode,Op1,GET_VALUE(Cmd->ByteMode,Op2)); + break; + case VM_MOVB: + setValue(true, mem, op1, getValue(true, mem, op2)); + break; + case VM_MOVD: + setValue(false, mem, op1, getValue(false, mem, op2)); + break; + + case VM_CMP: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int result = value1 - getValue(cmd.isByteMode(), mem, op2); + + if (result == 0) { + flags = VMFlags.VM_FZ.getFlag(); + } else { + flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS + .getFlag()); + } + } + break; + + case VM_CMPB: { + int value1 = getValue(true, mem, op1); + int result = value1 - getValue(true, mem, op2); + if (result == 0) { + flags = VMFlags.VM_FZ.getFlag(); + } else { + flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS + .getFlag()); + } + } + break; + case VM_CMPD: { + int value1 = getValue(false, mem, op1); + int result = value1 - getValue(false, mem, op2); + if (result == 0) { + flags = VMFlags.VM_FZ.getFlag(); + } else { + flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS + .getFlag()); + } + } + break; + + case VM_ADD: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int result = (int) ((((long) value1 + (long) getValue(cmd + .isByteMode(), mem, op2))) & 0xffffffff); + if (cmd.isByteMode()) { + result &= 0xff; + flags = (result < value1) ? 1 + : 0 | (result == 0 ? VMFlags.VM_FZ.getFlag() + : ((result & 0x80) != 0) ? VMFlags.VM_FS + .getFlag() : 0); + // Flags=(Result value1) ? 1 : 0 | (result & VMFlags.VM_FS + .getFlag()); + setValue(cmd.isByteMode(), mem, op1, result);// (Cmd->ByteMode,Op1,Result); + } + break; + + case VM_SUBB: + setValue(true, mem, op1, + (int) ((long) getValue(true, mem, op1) & 0xFFffFFff + - (long) getValue(true, mem, op2) & 0xFFffFFff)); + break; + case VM_SUBD: + setValue( + false, + mem, + op1, + (int) ((long) getValue(false, mem, op1) & 0xFFffFFff + - (long) getValue(false, mem, op2) & 0xFFffFFff)); + break; + + case VM_JZ: + if ((flags & VMFlags.VM_FZ.getFlag()) != 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JNZ: + if ((flags & VMFlags.VM_FZ.getFlag()) == 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_INC: { + int result = (int) ((long) getValue(cmd.isByteMode(), mem, op1) & 0xFFffFFff + 1); + if (cmd.isByteMode()) { + result &= 0xff; + } + + setValue(cmd.isByteMode(), mem, op1, result); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + } + break; + + case VM_INCB: + setValue( + true, + mem, + op1, + (int) ((long) getValue(true, mem, op1) & 0xFFffFFff + 1)); + break; + case VM_INCD: + setValue(false, mem, op1, (int) ((long) getValue(false, mem, + op1) & 0xFFffFFff + 1)); + break; + + case VM_DEC: { + int result = (int) ((long) getValue(cmd.isByteMode(), mem, op1) & 0xFFffFFff - 1); + setValue(cmd.isByteMode(), mem, op1, result); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + } + break; + + case VM_DECB: + setValue( + true, + mem, + op1, + (int) ((long) getValue(true, mem, op1) & 0xFFffFFff - 1)); + break; + case VM_DECD: + setValue(false, mem, op1, (int) ((long) getValue(false, mem, + op1) & 0xFFffFFff - 1)); + break; + + case VM_JMP: + setIP(getValue(false, mem, op1)); + continue; + case VM_XOR: { + int result = getValue(cmd.isByteMode(), mem, op1) + ^ getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_AND: { + int result = getValue(cmd.isByteMode(), mem, op1) + & getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_OR: { + int result = getValue(cmd.isByteMode(), mem, op1) + | getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_TEST: { + int result = getValue(cmd.isByteMode(), mem, op1) + & getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + } + break; + case VM_JS: + if ((flags & VMFlags.VM_FS.getFlag()) != 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JNS: + if ((flags & VMFlags.VM_FS.getFlag()) == 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JB: + if ((flags & VMFlags.VM_FC.getFlag()) != 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JBE: + if ((flags & (VMFlags.VM_FC.getFlag() | VMFlags.VM_FZ.getFlag())) != 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JA: + if ((flags & (VMFlags.VM_FC.getFlag() | VMFlags.VM_FZ.getFlag())) == 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JAE: + if ((flags & VMFlags.VM_FC.getFlag()) == 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_PUSH: + R[7] -= 4; + setValue(false, mem, R[7] & VM_MEMMASK, getValue(false, mem, + op1)); + break; + case VM_POP: + setValue(false, mem, op1, getValue(false, mem, R[7] + & VM_MEMMASK)); + R[7] += 4; + break; + case VM_CALL: + R[7] -= 4; + setValue(false, mem, R[7] & VM_MEMMASK, IP + 1); + setIP(getValue(false, mem, op1)); + continue; + case VM_NOT: + setValue(cmd.isByteMode(), mem, op1, ~getValue( + cmd.isByteMode(), mem, op1)); + break; + case VM_SHL: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int value2 = getValue(cmd.isByteMode(), mem, op2); + int result = value1 << value2; + flags = (result == 0 ? VMFlags.VM_FZ.getFlag() + : (result & VMFlags.VM_FS.getFlag())) + | (((value1 << (value2 - 1)) & 0x80000000) != 0 ? VMFlags.VM_FC + .getFlag() + : 0); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_SHR: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int value2 = getValue(cmd.isByteMode(), mem, op2); + int result = value1 >>> value2; + flags = (result == 0 ? VMFlags.VM_FZ.getFlag() + : (result & VMFlags.VM_FS.getFlag())) + | ((value1 >>> (value2 - 1)) & VMFlags.VM_FC.getFlag()); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_SAR: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int value2 = getValue(cmd.isByteMode(), mem, op2); + int result = ((int) value1) >> value2; + flags = (result == 0 ? VMFlags.VM_FZ.getFlag() + : (result & VMFlags.VM_FS.getFlag())) + | ((value1 >> (value2 - 1)) & VMFlags.VM_FC.getFlag()); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_NEG: { + int result = -getValue(cmd.isByteMode(), mem, op1); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : VMFlags.VM_FC + .getFlag() + | (result & VMFlags.VM_FS.getFlag()); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + + case VM_NEGB: + setValue(true, mem, op1, -getValue(true, mem, op1)); + break; + case VM_NEGD: + setValue(false, mem, op1, -getValue(false, mem, op1)); + break; + case VM_PUSHA: { + for (int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) { + setValue(false, mem, SP & VM_MEMMASK, R[i]); + } + R[7] -= regCount * 4; + } + break; + case VM_POPA: { + for (int i = 0, SP = R[7]; i < regCount; i++, SP += 4) + R[7 - i] = getValue(false, mem, SP & VM_MEMMASK); + } + break; + case VM_PUSHF: + R[7] -= 4; + setValue(false, mem, R[7] & VM_MEMMASK, flags); + break; + case VM_POPF: + flags = getValue(false, mem, R[7] & VM_MEMMASK); + R[7] += 4; + break; + case VM_MOVZX: + setValue(false, mem, op1, getValue(true, mem, op2)); + break; + case VM_MOVSX: + setValue(false, mem, op1, (byte) getValue(true, mem, op2)); + break; + case VM_XCHG: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + setValue(cmd.isByteMode(), mem, op1, getValue(cmd.isByteMode(), + mem, op2)); + setValue(cmd.isByteMode(), mem, op2, value1); + } + break; + case VM_MUL: { + int result = (int) (((long) getValue(cmd.isByteMode(), mem, op1) + & 0xFFffFFff + * (long) getValue(cmd.isByteMode(), mem, op2) & 0xFFffFFff) & 0xFFffFFff); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_DIV: { + int divider = getValue(cmd.isByteMode(), mem, op2); + if (divider != 0) { + int result = getValue(cmd.isByteMode(), mem, op1) / divider; + setValue(cmd.isByteMode(), mem, op1, result); + } + } + break; + case VM_ADC: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int FC = (flags & VMFlags.VM_FC.getFlag()); + int result = (int) ((long) value1 & 0xFFffFFff + + (long) getValue(cmd.isByteMode(), mem, op2) + & 0xFFffFFff + (long) FC & 0xFFffFFff); + if (cmd.isByteMode()) { + result &= 0xff; + } + + flags = (result < value1 || result == value1 && FC != 0) ? 1 + : 0 | (result == 0 ? VMFlags.VM_FZ.getFlag() + : (result & VMFlags.VM_FS.getFlag())); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_SBB: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int FC = (flags & VMFlags.VM_FC.getFlag()); + int result = (int) ((long) value1 & 0xFFffFFff + - (long) getValue(cmd.isByteMode(), mem, op2) + & 0xFFffFFff - (long) FC & 0xFFffFFff); + if (cmd.isByteMode()) { + result &= 0xff; + } + flags = (result > value1 || result == value1 && FC != 0) ? 1 + : 0 | (result == 0 ? VMFlags.VM_FZ.getFlag() + : (result & VMFlags.VM_FS.getFlag())); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + + case VM_RET: + if (R[7] >= VM_MEMSIZE) { + return (true); + } + setIP(getValue(false, mem, R[7] & VM_MEMMASK)); + R[7] += 4; + continue; + + case VM_STANDARD: + ExecuteStandardFilter(VMStandardFilters.findFilter(cmd.getOp1() + .getData())); + break; + case VM_PRINT: + break; + } + IP++; + --maxOpCount; + } + } + + public void prepare(byte[] code, int codeSize, VMPreparedProgram prg) { + InitBitInput(); + int cpLength = Math.min(MAX_SIZE, codeSize); + for (int i = 0; i < cpLength; i++) // memcpy(inBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); + { + inBuf[i] |= code[i]; + } + + byte xorSum = 0; + for (int i = 1; i < codeSize; i++) { + xorSum ^= code[i]; + } + + faddbits(8); + + prg.setCmdCount(0); + if (xorSum == code[0]) { + VMStandardFilters filterType = IsStandardFilter(code, codeSize); + if (filterType != VMStandardFilters.VMSF_NONE) { + + VMPreparedCommand curCmd = new VMPreparedCommand(); + curCmd.setOpCode(VMCommands.VM_STANDARD); + curCmd.getOp1().setData(filterType.getFilter()); + curCmd.getOp1().setType(VMOpType.VM_OPNONE); + curCmd.getOp2().setType(VMOpType.VM_OPNONE); + codeSize = 0; + prg.getCmd().add(curCmd); + prg.setCmdCount(prg.getCmdCount()+1); + // TODO + // curCmd->Op1.Data=FilterType; + // >>>>>> CurCmd->Op1.Addr=&CurCmd->Op1.Data; <<<<<<<<<< not set + // do i need to ? + // >>>>>> CurCmd->Op2.Addr=&CurCmd->Op2.Data; <<<<<<<<<< " + // CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; + // CodeSize=0; + } + int dataFlag = fgetbits(); + faddbits(1); + + // Read static data contained in DB operators. This data cannot be + // changed, + // it is a part of VM code, not a filter parameter. + + if ((dataFlag & 0x8000) != 0) { + long dataSize = (long) ((long) ReadData(this) & 0xffFFffFF + 1); + for (int i = 0; inAddr < codeSize && i < dataSize; i++) { + prg.getStaticData().add( + Byte.valueOf((byte) (fgetbits() >> 8))); + faddbits(8); + } + } + + while (inAddr < codeSize) { + VMPreparedCommand curCmd = new VMPreparedCommand(); + int data = fgetbits(); + if ((data & 0x8000) == 0) { + curCmd.setOpCode(VMCommands.findVMCommand((data >> 12))); + faddbits(4); + } else { + curCmd.setOpCode(VMCommands + .findVMCommand((data >> 10) - 24)); + faddbits(6); + } + if ((VMCmdFlags.VM_CmdFlags[curCmd.getOpCode().getVMCommand()] & VMCmdFlags.VMCF_BYTEMODE) != 0) { + curCmd.setByteMode((fgetbits() >> 15) == 1 ? true : false); + faddbits(1); + } else { + curCmd.setByteMode(false); + } + curCmd.getOp1().setType(VMOpType.VM_OPNONE); + curCmd.getOp2().setType(VMOpType.VM_OPNONE); + + int opNum = (VMCmdFlags.VM_CmdFlags[curCmd.getOpCode() + .getVMCommand()] & VMCmdFlags.VMCF_OPMASK); + // TODO >>> CurCmd->Op1.Addr=CurCmd->Op2.Addr=NULL; << 0) { + decodeArg(curCmd.getOp1(), curCmd.isByteMode()); + if (opNum == 2) + decodeArg(curCmd.getOp2(), curCmd.isByteMode()); + else { + if (curCmd.getOp1().getType() == VMOpType.VM_OPINT + && (VMCmdFlags.VM_CmdFlags[curCmd.getOpCode() + .getVMCommand()] & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC)) != 0) { + int distance = curCmd.getOp1().getData(); + if (distance >= 256) + distance -= 256; + else { + if (distance >= 136) { + distance -= 264; + } else { + if (distance >= 16) { + distance -= 8; + } else { + if (distance >= 8) { + distance -= 16; + } + } + } + distance += prg.getCmdCount(); + } + curCmd.getOp1().setData(distance); + } + } + } + prg.setCmdCount(prg.getCmdCount() + 1); + prg.getCmd().add(curCmd); + } + } + VMPreparedCommand curCmd = new VMPreparedCommand(); + curCmd.setOpCode(VMCommands.VM_RET); + // TODO CurCmd->Op1.Addr=&CurCmd->Op1.Data; + // CurCmd->Op2.Addr=&CurCmd->Op2.Data; + curCmd.getOp1().setType(VMOpType.VM_OPNONE); + curCmd.getOp2().setType(VMOpType.VM_OPNONE); + + // for (int i=0;iCmd[I]; + // if (Cmd->Op1.Addr==NULL) + // Cmd->Op1.Addr=&Cmd->Op1.Data; + // if (Cmd->Op2.Addr==NULL) + // Cmd->Op2.Addr=&Cmd->Op2.Data; + // } + + prg.getCmd().add(curCmd); + prg.setCmdCount(prg.getCmdCount()+1); + // #ifdef VM_OPTIMIZE + if (codeSize != 0) { + optimize(prg); + } + } + + private void decodeArg(VMPreparedOperand op, boolean byteMode) { + int data = fgetbits(); + if ((data & 0x8000) != 0) { + op.setType(VMOpType.VM_OPREG); + op.setData((data >> 12) & 7); + op.setOffset(op.getData()); + faddbits(4); + } else { + if ((data & 0xc000) == 0) { + op.setType(VMOpType.VM_OPINT); + if (byteMode) { + op.setData((data >> 6) & 0xff); + faddbits(10); + } else { + faddbits(2); + op.setData(ReadData(this)); + } + } else { + op.setType(VMOpType.VM_OPREGMEM); + if ((data & 0x2000) == 0) { + op.setData((data >> 10) & 7); + op.setOffset(op.getData()); + op.setBase(0); + faddbits(6); + } else { + if ((data & 0x1000) == 0) { + op.setData((data >> 9) & 7); + op.setOffset(op.getData()); + faddbits(7); + } else { + op.setData(0); + faddbits(4); + } + op.setBase(ReadData(this)); + } + } + } + + } + + private void optimize(VMPreparedProgram prg) { + List commands = prg.getCmd(); + + for (VMPreparedCommand cmd : commands) { + switch (cmd.getOpCode()) { + case VM_MOV: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_MOVB + : VMCommands.VM_MOVD); + continue; + case VM_CMP: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_CMPB + : VMCommands.VM_CMPD); + continue; + } + if ((VMCmdFlags.VM_CmdFlags[cmd.getOpCode().getVMCommand()] & VMCmdFlags.VMCF_CHFLAGS) == 0) { + continue; + } + boolean flagsRequired = false; + + for (int i = commands.indexOf(cmd) + 1; i < commands.size(); i++) { + int flags = VMCmdFlags.VM_CmdFlags[commands.get(i).getOpCode() + .getVMCommand()]; + if ((flags & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC | VMCmdFlags.VMCF_USEFLAGS)) != 0) { + flagsRequired = true; + break; + } + if ((flags & VMCmdFlags.VMCF_CHFLAGS) != 0) { + break; + } + } + if (flagsRequired) { + continue; + } + switch (cmd.getOpCode()) { + case VM_ADD: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_ADDB + : VMCommands.VM_ADDD); + continue; + case VM_SUB: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_SUBB + : VMCommands.VM_SUBD); + continue; + case VM_INC: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_INCB + : VMCommands.VM_INCD); + continue; + case VM_DEC: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_DECB + : VMCommands.VM_DECD); + continue; + case VM_NEG: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_NEGB + : VMCommands.VM_NEGD); + continue; + } + } + + } + + public static int ReadData(BitInput rarVM) { + int data = rarVM.fgetbits(); + switch (data & 0xc000) { + case 0: + rarVM.faddbits(6); + return ((data >> 10) & 0xf); + case 0x4000: + if ((data & 0x3c00) == 0) { + data = 0xffffff00 | ((data >> 2) & 0xff); + rarVM.faddbits(14); + } else { + data = (data >> 6) & 0xff; + rarVM.faddbits(10); + } + return (data); + case 0x8000: + rarVM.faddbits(2); + data = rarVM.fgetbits(); + rarVM.faddbits(16); + return (data); + default: + rarVM.faddbits(2); + data = (rarVM.fgetbits() << 16); + rarVM.faddbits(16); + data |= rarVM.fgetbits(); + rarVM.faddbits(16); + return (data); + } + } + + private VMStandardFilters IsStandardFilter(byte[] code, int codeSize) { + VMStandardFilterSignature stdList[]={ + new VMStandardFilterSignature(53, 0xad576887, VMStandardFilters.VMSF_E8), + new VMStandardFilterSignature(57, 0x3cd7e57e, VMStandardFilters.VMSF_E8E9), + new VMStandardFilterSignature(120, 0x3769893f, VMStandardFilters.VMSF_ITANIUM), + new VMStandardFilterSignature(29, 0x0e06077d, VMStandardFilters.VMSF_DELTA), + new VMStandardFilterSignature(149, 0x1c2c5dc8, VMStandardFilters.VMSF_RGB), + new VMStandardFilterSignature(216, 0xbc85e701, VMStandardFilters.VMSF_AUDIO), + new VMStandardFilterSignature(40, 0x46b9c560, VMStandardFilters.VMSF_UPCASE) + }; + int CodeCRC = RarCRC.checkCrc(0xffffffff,code,0,code.length)^0xffffffff; + for (int i=0;i=VM_GLOBALMEMADDR){ + break; + } + int fileSize=0x1000000; + byte cmpByte2=(byte) ((filterType==VMStandardFilters.VMSF_E8E9) ? 0xe9:0xe8); + for (int curPos=0;curPos=0) +// SET_VALUE(false,Data,Addr+FileSize); +// } +// else +// if (Addr=VM_GLOBALMEMADDR){ + break; + } + int curPos=0; + final byte Masks[]={4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0}; + fileOffset>>>=4; + + while (curPos=0) + { + + byte cmdMask=Masks[Byte]; + if (cmdMask!=0) + for (int i=0;i<=2;i++) + if ((cmdMask & (1<=VM_GLOBALMEMADDR/2){ + break; + } +// bytes from same channels are grouped to continual data blocks, +// so we need to place them back to their interleaving positions + + for (int curChannel=0;curChannel=VM_GLOBALMEMADDR/2 || posR<0){ + break; + } + for (int curChannel=0;curChannel=3) + { + int upperDataPos=destDataPos+upperPos; + int upperByte=mem[(int)upperDataPos]&0xff; + int upperLeftByte=mem[upperDataPos-3]&0xff; + predicted=prevByte+upperByte-upperLeftByte; + int pa=Math.abs((int)(predicted-prevByte)); + int pb=Math.abs((int)(predicted-upperByte)); + int pc=Math.abs((int)(predicted-upperLeftByte)); + if (pa<=pb && pa<=pc){ + predicted=prevByte; + } + else{ + if (pb<=pc){ + predicted=upperByte; + } + else{ + predicted=upperLeftByte; + } + } + } + else{ + predicted=prevByte; + } + + prevByte=(predicted-mem[srcPos++]&0xff)&0xff; + mem[destDataPos+i]=(byte)(prevByte&0xff); + + } + } + for (int i=posR,border=dataSize-2;i=VM_GLOBALMEMADDR/2){ + break; + } + for (int curChannel=0;curChannel>>3) & 0xff; + + long curByte=mem[srcPos++]&0xff; + + predicted = (predicted - curByte)&UINT_MASK; + mem[destDataPos+i]=(byte)predicted; + prevDelta=(byte)(predicted-prevByte); + prevByte=predicted; + + int D=((byte)curByte)<<3; + + Dif[0]+=Math.abs(D); + Dif[1]+=Math.abs(D-D1); + Dif[2]+=Math.abs(D+D1); + Dif[3]+=Math.abs(D-D2); + Dif[4]+=Math.abs(D+D2); + Dif[5]+=Math.abs(D-D3); + Dif[6]+=Math.abs(D+D3); + + if ((byteCount & 0x1f)==0) + { + long minDif=Dif[0], numMinDif=0; + Dif[0]=0; + for (int j=1;j=-16) K1--; break; + case 2: if (K1 < 16) K1++; break; + case 3: if (K2>=-16) K2--; break; + case 4: if (K2 < 16) K2++; break; + case 5: if (K3>=-16) K3--; break; + case 6: if (K3 < 16) K3++; break; + } + } + } + } + } + break; + case VMSF_UPCASE: + { + int dataSize=R[4],srcPos=0,destPos=dataSize; + if (dataSize>=VM_GLOBALMEMADDR/2){ + break; + } + while (srcPos>>(32-bitCount); + andMask=~(andMask<>>8)|0xff000000; + bitField>>>=8; + } + + } + + private int filterItanium_GetBits(int curPos, int bitPos, int bitCount) { + int inAddr=bitPos/8; + int inBit=bitPos&7; + int bitField=(int)(mem[curPos+inAddr++]&0xff); + bitField|=(int) ((mem[curPos+inAddr++]&0xff) << 8); + bitField|=(int) ((mem[curPos+inAddr++]&0xff) << 16); + bitField|=(int) ((mem[curPos+inAddr]&0xff) << 24); + bitField >>>= inBit; + return(bitField & (0xffffffff>>>(32-bitCount))); + } + + + public void setMemory(int pos,byte[] data,int offset,int dataSize) + { + if (pos": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMCmdFlags { + public static final byte VMCF_OP0 = 0; + public static final byte VMCF_OP1 = 1; + public static final byte VMCF_OP2 = 2; + public static final byte VMCF_OPMASK = 3; + public static final byte VMCF_BYTEMODE = 4; + public static final byte VMCF_JUMP = 8; + public static final byte VMCF_PROC = 16; + public static final byte VMCF_USEFLAGS = 32; + public static final byte VMCF_CHFLAGS = 64; + + public static byte VM_CmdFlags[]= + { + /* VM_MOV */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_CMP */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_ADD */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_SUB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_JZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JNZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_INC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_DEC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_JMP */ VMCF_OP1 | VMCF_JUMP , + /* VM_XOR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_AND */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_OR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_TEST */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_JS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JNS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JB */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JBE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JA */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JAE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_PUSH */ VMCF_OP1 , + /* VM_POP */ VMCF_OP1 , + /* VM_CALL */ VMCF_OP1 | VMCF_PROC , + /* VM_RET */ VMCF_OP0 | VMCF_PROC , + /* VM_NOT */ VMCF_OP1 | VMCF_BYTEMODE , + /* VM_SHL */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_SHR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_SAR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_NEG */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_PUSHA */ VMCF_OP0 , + /* VM_POPA */ VMCF_OP0 , + /* VM_PUSHF */ VMCF_OP0 | VMCF_USEFLAGS , + /* VM_POPF */ VMCF_OP0 | VMCF_CHFLAGS , + /* VM_MOVZX */ VMCF_OP2 , + /* VM_MOVSX */ VMCF_OP2 , + /* VM_XCHG */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_MUL */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_DIV */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_ADC */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS , + /* VM_SBB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS , + /* VM_PRINT */ VMCF_OP0 + }; + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMCommands.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMCommands.java new file mode 100644 index 0000000..e52911a --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMCommands.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public enum VMCommands { + VM_MOV(0), VM_CMP(1), VM_ADD(2), VM_SUB(3), VM_JZ(4), VM_JNZ(5), VM_INC(6), VM_DEC( + 7), VM_JMP(8), VM_XOR(9), VM_AND(10), VM_OR(11), VM_TEST(12), VM_JS( + 13), VM_JNS(14), VM_JB(15), VM_JBE(16), VM_JA(17), VM_JAE(18), VM_PUSH( + 19), VM_POP(20), VM_CALL(21), VM_RET(22), VM_NOT(23), VM_SHL(24), VM_SHR( + 25), VM_SAR(26), VM_NEG(27), VM_PUSHA(28), VM_POPA(29), VM_PUSHF(30), VM_POPF( + 31), VM_MOVZX(32), VM_MOVSX(33), VM_XCHG(34), VM_MUL(35), VM_DIV(36), VM_ADC( + 37), VM_SBB(38), VM_PRINT(39), + + // #ifdef VM_OPTIMIZE + VM_MOVB(40), VM_MOVD(41), VM_CMPB(42), VM_CMPD(43), + + VM_ADDB(44), VM_ADDD(45), VM_SUBB(46), VM_SUBD(47), VM_INCB(48), VM_INCD(49), VM_DECB( + 50), VM_DECD(51), VM_NEGB(52), VM_NEGD(53), + // #endif*/ + + VM_STANDARD(54); + + private int vmCommand; + + private VMCommands(int vmCommand) { + this.vmCommand = vmCommand; + } + + public int getVMCommand() { + return vmCommand; + } + + public boolean equals(int vmCommand) { + return this.vmCommand == vmCommand; + } + + public static VMCommands findVMCommand(int vmCommand) { + if (VM_MOV.equals(vmCommand)) { + return VM_MOV; + } + if (VM_CMP.equals(vmCommand)) { + return VM_CMP; + } + if (VM_ADD.equals(vmCommand)) { + return VM_ADD; + } + if (VM_SUB.equals(vmCommand)) { + return VM_SUB; + } + if (VM_JZ.equals(vmCommand)) { + return VM_JZ; + } + if (VM_JNZ.equals(vmCommand)) { + return VM_JNZ; + } + if (VM_INC.equals(vmCommand)) { + return VM_INC; + } + if (VM_DEC.equals(vmCommand)) { + return VM_DEC; + } + if (VM_JMP.equals(vmCommand)) { + return VM_JMP; + } + if (VM_XOR.equals(vmCommand)) { + return VM_XOR; + } + if (VM_AND.equals(vmCommand)) { + return VM_AND; + } + if (VM_OR.equals(vmCommand)) { + return VM_OR; + } + if (VM_TEST.equals(vmCommand)) { + return VM_TEST; + } + if (VM_JS.equals(vmCommand)) { + return VM_JS; + } + if (VM_JNS.equals(vmCommand)) { + return VM_JNS; + } + if (VM_JB.equals(vmCommand)) { + return VM_JB; + } + if (VM_JBE.equals(vmCommand)) { + return VM_JBE; + } + if (VM_JA.equals(vmCommand)) { + return VM_JA; + } + if (VM_JAE.equals(vmCommand)) { + return VM_JAE; + } + if (VM_PUSH.equals(vmCommand)) { + return VM_PUSH; + } + if (VM_POP.equals(vmCommand)) { + return VM_POP; + } + if (VM_CALL.equals(vmCommand)) { + return VM_CALL; + } + if (VM_RET.equals(vmCommand)) { + return VM_RET; + } + if (VM_NOT.equals(vmCommand)) { + return VM_NOT; + } + if (VM_SHL.equals(vmCommand)) { + return VM_SHL; + } + if (VM_SHR.equals(vmCommand)) { + return VM_SHR; + } + if (VM_SAR.equals(vmCommand)) { + return VM_SAR; + } + if (VM_NEG.equals(vmCommand)) { + return VM_NEG; + } + if (VM_PUSHA.equals(vmCommand)) { + return VM_PUSHA; + } + if (VM_POPA.equals(vmCommand)) { + return VM_POPA; + } + if (VM_PUSHF.equals(vmCommand)) { + return VM_PUSHF; + } + if (VM_POPF.equals(vmCommand)) { + return VM_POPF; + } + if (VM_MOVZX.equals(vmCommand)) { + return VM_MOVZX; + } + if (VM_MOVSX.equals(vmCommand)) { + return VM_MOVSX; + } + if (VM_XCHG.equals(vmCommand)) { + return VM_XCHG; + } + if (VM_MUL.equals(vmCommand)) { + return VM_MUL; + } + if (VM_DIV.equals(vmCommand)) { + return VM_DIV; + } + if (VM_ADC.equals(vmCommand)) { + return VM_ADC; + } + if (VM_SBB.equals(vmCommand)) { + return VM_SBB; + } + if (VM_PRINT.equals(vmCommand)) { + return VM_PRINT; + } + if (VM_MOVB.equals(vmCommand)) { + return VM_MOVB; + } + if (VM_MOVD.equals(vmCommand)) { + return VM_MOVD; + } + if (VM_CMPB.equals(vmCommand)) { + return VM_CMPB; + } + if (VM_CMPD.equals(vmCommand)) { + return VM_CMPD; + } + if (VM_ADDB.equals(vmCommand)) { + return VM_ADDB; + } + if (VM_ADDD.equals(vmCommand)) { + return VM_ADDD; + } + if (VM_SUBB.equals(vmCommand)) { + return VM_SUBB; + } + if (VM_SUBD.equals(vmCommand)) { + return VM_SUBD; + } + if (VM_INCB.equals(vmCommand)) { + return VM_INCB; + } + if (VM_INCD.equals(vmCommand)) { + return VM_INCD; + } + if (VM_DECB.equals(vmCommand)) { + return VM_DECB; + } + if (VM_DECD.equals(vmCommand)) { + return VM_DECD; + } + if (VM_NEGB.equals(vmCommand)) { + return VM_NEGB; + } + if (VM_NEGD.equals(vmCommand)) { + return VM_NEGD; + } + if (VM_STANDARD.equals(vmCommand)) { + return VM_STANDARD; + } + return null; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMFlags.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMFlags.java new file mode 100644 index 0000000..d2b997b --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMFlags.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public enum VMFlags { + /** + * + */ + VM_FC (1), + /** + * + */ + VM_FZ (2), + /** + * + */ + VM_FS (0x80000000); + + private int flag; + + private VMFlags(int flag){ + this.flag = flag; + } + + /** + * Returns the VMFlags Type of the given int or null + * @param flag as int + * @return VMFlag of the int value + */ + public static VMFlags findFlag(int flag){ + if(VM_FC.equals(flag)){ + return VM_FC; + } + if(VM_FS.equals(flag)){ + return VM_FS; + } + if(VM_FZ.equals(flag)){ + return VM_FZ; + } + return null; + } + + /** + * Returns true if the flag provided as int is equal to the enum + * @param flag + * @return returns true if the flag is equal to the enum + */ + public boolean equals(int flag){ + return this.flag == flag; + } + /** + * @return the flag as int + */ + public int getFlag() { + return flag; + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMOpType.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMOpType.java new file mode 100644 index 0000000..1b8bc97 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMOpType.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public enum VMOpType { + VM_OPREG (0), + VM_OPINT (1), + VM_OPREGMEM (2), + VM_OPNONE (3); + + private int opType; + + private VMOpType(int opType){ + this.opType=opType; + } + + public int getOpType() { + return opType; + } + + + public boolean equals(int opType){ + return this.opType == opType; + } + public static VMOpType findOpType(int opType){ + + if (VM_OPREG.equals(opType)) { + return VM_OPREG; + } + + + if (VM_OPINT.equals(opType)) { + return VM_OPINT; + } + + if (VM_OPREGMEM.equals(opType)) { + return VM_OPREGMEM; + } + + if (VM_OPNONE.equals(opType)) { + return VM_OPNONE; + } + return null; + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedCommand.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedCommand.java new file mode 100644 index 0000000..74cc86d --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedCommand.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMPreparedCommand { + private VMCommands OpCode; + private boolean ByteMode; + private VMPreparedOperand Op1 = new VMPreparedOperand(); + private VMPreparedOperand Op2 = new VMPreparedOperand(); + + public boolean isByteMode() { + return ByteMode; + } + public void setByteMode(boolean byteMode) { + ByteMode = byteMode; + } + public VMPreparedOperand getOp1() { + return Op1; + } + public void setOp1(VMPreparedOperand op1) { + Op1 = op1; + } + public VMPreparedOperand getOp2() { + return Op2; + } + public void setOp2(VMPreparedOperand op2) { + Op2 = op2; + } + public VMCommands getOpCode() { + return OpCode; + } + public void setOpCode(VMCommands opCode) { + OpCode = opCode; + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedOperand.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedOperand.java new file mode 100644 index 0000000..f6aeff4 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedOperand.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMPreparedOperand { + private VMOpType Type; + private int Data; + private int Base; + private int offset; + + + public int getBase() { + return Base; + } + public void setBase(int base) { + Base = base; + } + public int getData() { + return Data; + } + public void setData(int data) { + Data = data; + } + public VMOpType getType() { + return Type; + } + public void setType(VMOpType type) { + Type = type; + } + public int getOffset() { + return offset; + } + public void setOffset(int offset) { + this.offset = offset; + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedProgram.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedProgram.java new file mode 100644 index 0000000..497b4a9 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMPreparedProgram.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.vm; + +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMPreparedProgram +{ + private List Cmd = new ArrayList(); + private List AltCmd =new ArrayList(); + private int CmdCount; + + + + private Vector GlobalData = new Vector(); + private Vector StaticData = new Vector(); // static data contained in DB operators + private int InitR[] = new int[7]; + + private int FilteredDataOffset; + private int FilteredDataSize; + + public VMPreparedProgram() + { + AltCmd=null; + } + + + + public List getAltCmd() { + return AltCmd; + } + + + + public void setAltCmd(List altCmd) { + AltCmd = altCmd; + } + + + + public List getCmd() { + return Cmd; + } + + public void setCmd(List cmd) { + Cmd = cmd; + } + + public int getCmdCount() { + return CmdCount; + } + + public void setCmdCount(int cmdCount) { + CmdCount = cmdCount; + } + + + + public int getFilteredDataOffset() { + return FilteredDataOffset; + } + + + + public void setFilteredDataOffset(int filteredDataOffset) { + FilteredDataOffset = filteredDataOffset; + } + + + + public int getFilteredDataSize() { + return FilteredDataSize; + } + + public void setFilteredDataSize(int filteredDataSize) { + FilteredDataSize = filteredDataSize; + } + + public Vector getGlobalData() { + return GlobalData; + } + + public void setGlobalData(Vector globalData) { + GlobalData = globalData; + } + + public int[] getInitR() { + return InitR; + } + + public void setInitR(int[] initR) { + InitR = initR; + } + + public Vector getStaticData() { + return StaticData; + } + + public void setStaticData(Vector staticData) { + StaticData = staticData; + } + + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMStandardFilterSignature.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMStandardFilterSignature.java new file mode 100644 index 0000000..ca7ab73 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMStandardFilterSignature.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class VMStandardFilterSignature { + private int length; + + private int CRC; + + private VMStandardFilters type; + + public VMStandardFilterSignature(int length, int crc, VMStandardFilters type) { + super(); + this.length = length; + CRC = crc; + this.type = type; + } + + public int getCRC() { + return CRC; + } + + public void setCRC(int crc) { + CRC = crc; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public VMStandardFilters getType() { + return type; + } + + public void setType(VMStandardFilters type) { + this.type = type; + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMStandardFilters.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMStandardFilters.java new file mode 100644 index 0000000..ceff170 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/vm/VMStandardFilters.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 31.05.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unpack.vm; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public enum VMStandardFilters { + VMSF_NONE ((int)0), + VMSF_E8 ((int)1), + VMSF_E8E9 ((int)2), + VMSF_ITANIUM( (int)3), + VMSF_RGB ((int)4), + VMSF_AUDIO ((int)5), + VMSF_DELTA ((int)6), + VMSF_UPCASE ((int)7); + + private int filter; + + private VMStandardFilters(int filter){ + this.filter=filter; + } + + public int getFilter() { + return filter; + } + + public boolean equals(int filter){ + return this.filter == filter; + } + + public static VMStandardFilters findFilter(int filter){ + if (VMSF_NONE.equals(filter)) { + return VMSF_NONE; + } + + if (VMSF_E8.equals(filter)) { + return VMSF_E8; + } + + if (VMSF_E8E9.equals(filter)) { + return VMSF_E8E9; + } + if (VMSF_ITANIUM.equals(filter)) { + return VMSF_ITANIUM; + } + + if (VMSF_RGB.equals(filter)) { + return VMSF_RGB; + } + + if (VMSF_AUDIO.equals(filter)) { + return VMSF_AUDIO; + } + if (VMSF_DELTA.equals(filter)) { + return VMSF_DELTA; + } + return null; + } + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedByte.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedByte.java new file mode 100644 index 0000000..f59ce96 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedByte.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unsigned; + +import com.github.junrar.crc.RarCRC; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class UnsignedByte { + + public static byte longToByte(long unsignedByte1){ + return (byte) (unsignedByte1&0xff); + } + public static byte intToByte(int unsignedByte1){ + return (byte) (unsignedByte1&0xff); + } + public static byte shortToByte(short unsignedByte1){ + return (byte) (unsignedByte1&0xff); + } + + + public static short add(byte unsignedByte1, byte unsignedByte2){ + return (short) (unsignedByte1 + unsignedByte2); + } + + public static short sub(byte unsignedByte1, byte unsignedByte2){ + + return (short) (unsignedByte1 - unsignedByte2); + } + + + public static void main(String[] args) + { + //tests unsigned (signed) + //add + System.out.println(add((byte)0xfe,(byte)0x01)); //255 (-1) + System.out.println(add((byte)0xff,(byte)0x01)); //0 (0) + System.out.println(add((byte)0x7f,(byte)0x01)); //128 (-128) + System.out.println(add((byte)0xff,(byte)0xff)); //254 (-2) + + //sub + System.out.println(sub((byte)0xfe,(byte)0x01)); //253 (-3) + System.out.println(sub((byte)0x00,(byte)0x01)); //255 (-1) + System.out.println(sub((byte)0x80,(byte)0x01)); //127 (127) + //mul + System.out.println((byte)-1*(byte)-1); + } +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedInteger.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedInteger.java new file mode 100644 index 0000000..0f12c5c --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedInteger.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unsigned; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class UnsignedInteger { + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedLong.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedLong.java new file mode 100644 index 0000000..a859929 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedLong.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unsigned; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class UnsignedLong { + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedShort.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedShort.java new file mode 100644 index 0000000..e9131e9 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unsigned/UnsignedShort.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. + * Original author: Edmund Wagner + * Creation date: 04.06.2007 + * + * Source: $HeadURL$ + * Last changed: $LastChangedDate$ + * + * + * the unrar licence applies to all junrar source and binary distributions + * you are not allowed to use this source to re-create the RAR compression algorithm + * + * Here some html entities which can be used for escaping javadoc tags: + * "&": "&" or "&" + * "<": "<" or "<" + * ">": ">" or ">" + * "@": "@" + */ +package com.github.junrar.unsigned; + +/** + * DOCUMENT ME + * + * @author $LastChangedBy$ + * @version $LastChangedRevision$ + */ +public class UnsignedShort { + +} diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/util/VolumeHelper.java b/org.fox.ttcomics/src/main/java/com/github/junrar/util/VolumeHelper.java new file mode 100644 index 0000000..4238051 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/util/VolumeHelper.java @@ -0,0 +1,101 @@ +package com.github.junrar.util; + +/** + * + * @author alban + */ +public class VolumeHelper { + private VolumeHelper() { + } + + // public static boolean mergeArchive(Archive archive, ComprDataIO dataIO) + // throws IOException { + // FileHeader hd = dataIO.getSubHeader(); + // if (hd.getUnpVersion() >= 20 && hd.getFileCRC() != 0xffffffff + // && dataIO.getPackedCRC() != ~hd.getFileCRC()) { + // System.err.println("Data Bad CRC"); + // } + // + // boolean oldNumbering = !archive.getMainHeader().isNewNumbering() + // || archive.isOldFormat(); + // String nextName = nextVolumeName(archive.getFile().getAbsolutePath(), + // oldNumbering); + // File nextVolume = new File(nextName); + // UnrarCallback callback = archive.getUnrarCallback(); + // if ((callback != null) && !callback.isNextVolumeReady(nextVolume)) { + // return false; + // } + // if (!nextVolume.exists()) { + // return false; + // } + // archive.setFile(nextVolume); + // hd = archive.nextFileHeader(); + // if (hd == null) { + // return false; + // } + // dataIO.init(hd); + // return true; + // } + + public static String nextVolumeName(String arcName, boolean oldNumbering) { + if (!oldNumbering) { + // part1.rar, part2.rar, ... + int len = arcName.length(); + int indexR = len - 1; + while ((indexR >= 0) && !isDigit(arcName.charAt(indexR))) { + indexR--; + } + int index = indexR + 1; + int indexL = indexR - 1; + while ((indexL >= 0) && isDigit(arcName.charAt(indexL))) { + indexL--; + } + if (indexL < 0) { + return null; + } + indexL++; + StringBuilder buffer = new StringBuilder(len); + buffer.append(arcName, 0, indexL); + char[] digits = new char[indexR - indexL + 1]; + arcName.getChars(indexL, indexR + 1, digits, 0); + indexR = digits.length - 1; + while ((indexR >= 0) && (++digits[indexR]) == '9' + 1) { + digits[indexR] = '0'; + indexR--; + } + if (indexR < 0) { + buffer.append('1'); + } + buffer.append(digits); + buffer.append(arcName, index, len); + return buffer.toString(); + } else { + // .rar, .r00, .r01, ... + int len = arcName.length(); + if ((len <= 4) || (arcName.charAt(len - 4) != '.')) { + return null; + } + StringBuilder buffer = new StringBuilder(); + int off = len - 3; + buffer.append(arcName, 0, off); + if (!isDigit(arcName.charAt(off + 1)) + || !isDigit(arcName.charAt(off + 2))) { + buffer.append("r00"); + } else { + char[] ext = new char[3]; + arcName.getChars(off, len, ext, 0); + int i = ext.length - 1; + while ((++ext[i]) == '9' + 1) { + ext[i] = '0'; + i--; + } + buffer.append(ext); + } + return buffer.toString(); + } + } + + private static boolean isDigit(char c) { + return (c >= '0') && (c <= '9'); + } +} diff --git a/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/ImageViewTouch.java b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/ImageViewTouch.java new file mode 100644 index 0000000..73392b1 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/ImageViewTouch.java @@ -0,0 +1,268 @@ +package it.sephiroth.android.library.imagezoom; + +import android.content.Context; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.Log; +import android.view.GestureDetector; +import android.view.GestureDetector.OnGestureListener; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.ScaleGestureDetector.OnScaleGestureListener; +import android.view.ViewConfiguration; + +public class ImageViewTouch extends ImageViewTouchBase { + + private static final float SCROLL_DELTA_THRESHOLD = 1.0f; + static final float MIN_ZOOM = 0.9f; + protected ScaleGestureDetector mScaleDetector; + protected GestureDetector mGestureDetector; + protected int mTouchSlop; + protected float mCurrentScaleFactor; + protected float mScaleFactor; + protected int mDoubleTapDirection; + protected OnGestureListener mGestureListener; + protected OnScaleGestureListener mScaleListener; + protected boolean mDoubleTapToZoomEnabled = true; + protected boolean mScaleEnabled = true; + protected boolean mScrollEnabled = true; + + private OnImageViewTouchDoubleTapListener doubleTapListener; + + public interface OnScaleChangedListener { + public void onScaleChanged(float scale); + } + + protected OnScaleChangedListener mScaleChangedListener; + + public ImageViewTouch( Context context, AttributeSet attrs ) { + super( context, attrs ); + } + + @Override + protected void init() { + super.init(); + mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); + mGestureListener = getGestureListener(); + mScaleListener = getScaleListener(); + + mScaleDetector = new ScaleGestureDetector( getContext(), mScaleListener ); + mGestureDetector = new GestureDetector( getContext(), mGestureListener, null, true ); + + mCurrentScaleFactor = 1f; + mDoubleTapDirection = 1; + } + + public void setDoubleTapListener( OnImageViewTouchDoubleTapListener doubleTapListener ){ + this.doubleTapListener = doubleTapListener; + } + + public void setDoubleTapToZoomEnabled( boolean value ) { + mDoubleTapToZoomEnabled = value; + } + + public void setScaleEnabled( boolean value ) { + mScaleEnabled = value; + } + + public void setScrollEnabled( boolean value ) { + mScrollEnabled = value; + } + + public boolean getDoubleTapEnabled() { + return mDoubleTapToZoomEnabled; + } + + protected OnGestureListener getGestureListener() { + return new GestureListener(); + } + + protected OnScaleGestureListener getScaleListener() { + return new ScaleListener(); + } + + @Override + protected void onBitmapChanged( Drawable drawable ) { + super.onBitmapChanged( drawable ); + + float v[] = new float[9]; + mSuppMatrix.getValues( v ); + mCurrentScaleFactor = v[Matrix.MSCALE_X]; + } + + @Override + protected void _setImageDrawable( final Drawable drawable, final boolean reset, final Matrix initial_matrix, final float maxZoom ) { + super._setImageDrawable( drawable, reset, initial_matrix, maxZoom ); + mScaleFactor = getMaxZoom() / 3; + } + + @Override + public boolean onTouchEvent( MotionEvent event ) { + mScaleDetector.onTouchEvent( event ); + if ( !mScaleDetector.isInProgress() ) mGestureDetector.onTouchEvent( event ); + int action = event.getAction(); + switch ( action & MotionEvent.ACTION_MASK ) { + case MotionEvent.ACTION_UP: + if ( getScale() < 1f ) { + zoomTo( 1f, 50 ); + } + break; + } + return true; + } + + @Override + protected void onZoom( float scale ) { + super.onZoom( scale ); + if ( !mScaleDetector.isInProgress() ) mCurrentScaleFactor = scale; + + if (mScaleChangedListener != null) { + mScaleChangedListener.onScaleChanged(mCurrentScaleFactor); + } + } + + protected float onDoubleTapPost( float scale, float maxZoom ) { + if ( mDoubleTapDirection == 1 ) { + if (mCurrentScaleFactor - 1.0f < 0.01) { //( scale + ( mScaleFactor * 2 ) ) <= maxZoom + + float scaleFactor = mScaleFactor; + + RectF bitmapRect = getBitmapRect(); + + float w = bitmapRect.right - bitmapRect.left; + float h = bitmapRect.bottom - bitmapRect.top; + + if (w < getWidth()) { + scaleFactor = (float)getWidth() / w - scale; + } else if (h < getHeight()) { + scaleFactor = (float)getHeight() / h - scale; + } + + return scale + scaleFactor; + } else { + mDoubleTapDirection = -1; + return maxZoom; + } + } else { + mDoubleTapDirection = 1; + return 1f; + } + } + + /** + * Determines whether this ImageViewTouch can be scrolled. + * @param direction + * - positive direction value means scroll from right to left, + * negative value means scroll from left to right + * + * @return true if there is some more place to scroll, false - otherwise. + */ + public boolean canScroll(int direction) { + RectF bitmapRect = getBitmapRect(); + updateRect(bitmapRect, mScrollRect); + Rect imageViewRect = new Rect(); + getGlobalVisibleRect(imageViewRect); + + if (bitmapRect.right >= imageViewRect.right) { + if (direction < 0) { + return Math.abs(bitmapRect.right - imageViewRect.right) > SCROLL_DELTA_THRESHOLD; + } + } + + double bitmapScrollRectDelta = Math.abs(bitmapRect.left - mScrollRect.left); + return bitmapScrollRectDelta > SCROLL_DELTA_THRESHOLD; + } + + public class GestureListener extends GestureDetector.SimpleOnGestureListener { + + @Override + public boolean onDoubleTap( MotionEvent e ) { + Log.i( LOG_TAG, "onDoubleTap. double tap enabled? " + mDoubleTapToZoomEnabled); + if (mDoubleTapToZoomEnabled) { + float scale = getScale(); + float targetScale = scale; + targetScale = onDoubleTapPost( scale, getMaxZoom() ); + targetScale = Math.min( getMaxZoom(), Math.max( targetScale, MIN_ZOOM ) ); + mCurrentScaleFactor = targetScale; + zoomTo( targetScale, e.getX(), e.getY(), 200 ); + invalidate(); + } + + if( null != doubleTapListener ){ + doubleTapListener.onDoubleTap(); + } + + return super.onDoubleTap( e ); + } + + @Override + public void onLongPress( MotionEvent e ) { + if ( isLongClickable() ) { + if ( !mScaleDetector.isInProgress() ) { + setPressed( true ); + performLongClick(); + } + } + } + + @Override + public boolean onScroll( MotionEvent e1, MotionEvent e2, float distanceX, float distanceY ) { + if ( !mScrollEnabled ) return false; + + if ( e1 == null || e2 == null ) return false; + if ( e1.getPointerCount() > 1 || e2.getPointerCount() > 1 ) return false; + if ( mScaleDetector.isInProgress() ) return false; + if ( getScale() == 1f ) return false; + scrollBy( -distanceX, -distanceY ); + invalidate(); + return super.onScroll( e1, e2, distanceX, distanceY ); + } + + @Override + public boolean onFling( MotionEvent e1, MotionEvent e2, float velocityX, float velocityY ) { + if ( !mScrollEnabled ) return false; + + if ( e1.getPointerCount() > 1 || e2.getPointerCount() > 1 ) return false; + if ( mScaleDetector.isInProgress() ) return false; + + float diffX = e2.getX() - e1.getX(); + float diffY = e2.getY() - e1.getY(); + + if ( Math.abs( velocityX ) > 800 || Math.abs( velocityY ) > 800 ) { + scrollBy( diffX / 2, diffY / 2, 300 ); + invalidate(); + } + return super.onFling( e1, e2, velocityX, velocityY ); + } + } + + public class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + + @SuppressWarnings("unused") + @Override + public boolean onScale( ScaleGestureDetector detector ) { + float span = detector.getCurrentSpan() - detector.getPreviousSpan(); + float targetScale = mCurrentScaleFactor * detector.getScaleFactor(); + if ( mScaleEnabled ) { + targetScale = Math.min( getMaxZoom(), Math.max( targetScale, MIN_ZOOM ) ); + zoomTo( targetScale, detector.getFocusX(), detector.getFocusY() ); + mCurrentScaleFactor = Math.min( getMaxZoom(), Math.max( targetScale, MIN_ZOOM ) ); + mDoubleTapDirection = 1; + invalidate(); + return true; + } + return false; + } + } + + public interface OnImageViewTouchDoubleTapListener { + void onDoubleTap(); + } + + public void setOnScaleChangedListener(OnScaleChangedListener listener) { + mScaleChangedListener = listener; + } +} diff --git a/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/ImageViewTouchBase.java b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/ImageViewTouchBase.java new file mode 100644 index 0000000..8452a21 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/ImageViewTouchBase.java @@ -0,0 +1,509 @@ +package it.sephiroth.android.library.imagezoom; + +import it.sephiroth.android.library.imagezoom.easing.Cubic; +import it.sephiroth.android.library.imagezoom.easing.Easing; +import it.sephiroth.android.library.imagezoom.graphics.FastBitmapDrawable; +import it.sephiroth.android.library.imagezoom.utils.IDisposable; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.util.AttributeSet; +import android.util.Log; +import android.widget.ImageView; + +/** + * Base View to manage image zoom/scrool/pinch operations + * + * @author alessandro + * + */ +public class ImageViewTouchBase extends ImageView implements IDisposable { + + public interface OnBitmapChangedListener { + + void onBitmapChanged( Drawable drawable ); + }; + + public static final String LOG_TAG = "image"; + + protected Easing mEasing = new Cubic(); + protected Matrix mBaseMatrix = new Matrix(); + protected Matrix mSuppMatrix = new Matrix(); + protected Handler mHandler = new Handler(); + protected Runnable mOnLayoutRunnable = null; + protected float mMaxZoom; + protected final Matrix mDisplayMatrix = new Matrix(); + protected final float[] mMatrixValues = new float[9]; + protected int mThisWidth = -1, mThisHeight = -1; + protected boolean mFitToScreen = false; + protected boolean mFitToWidth = false; + final protected float MAX_ZOOM = 3.0f; + + protected RectF mBitmapRect = new RectF(); + protected RectF mCenterRect = new RectF(); + protected RectF mScrollRect = new RectF(); + + private OnBitmapChangedListener mListener; + + public ImageViewTouchBase( Context context ) { + super( context ); + init(); + } + + public ImageViewTouchBase( Context context, AttributeSet attrs ) { + super( context, attrs ); + init(); + } + + public void setOnBitmapChangedListener( OnBitmapChangedListener listener ) { + mListener = listener; + } + + protected void init() { + setScaleType( ImageView.ScaleType.MATRIX ); + } + + public void clear() { + setImageBitmap( null, true ); + } + + public void setFitToScreen( boolean value ) { + if ( value != mFitToScreen ) { + mFitToScreen = value; + requestLayout(); + } + } + + public void setFitToWidth( boolean value ) { + if ( value != mFitToWidth ) { + mFitToWidth = value; + requestLayout(); + } + } + + @Override + protected void onLayout( boolean changed, int left, int top, int right, int bottom ) { + super.onLayout( changed, left, top, right, bottom ); + mThisWidth = right - left; + mThisHeight = bottom - top; + Runnable r = mOnLayoutRunnable; + if ( r != null ) { + mOnLayoutRunnable = null; + r.run(); + } + if ( getDrawable() != null ) { + if ( mFitToScreen ) + getProperBaseMatrix2( getDrawable(), mBaseMatrix ); + else + getProperBaseMatrix( getDrawable(), mBaseMatrix ); + setImageMatrix( getImageViewMatrix() ); + + if (mFitToWidth) zoomToWidth(); + } + } + + @Override + public void setImageBitmap( Bitmap bm ) { + setImageBitmap( bm, true ); + } + + @Override + public void setImageResource( int resId ) { + setImageDrawable( getContext().getResources().getDrawable( resId ) ); + } + + /** + * Set the new image to display and reset the internal matrix. + * + * @param bitmap + * - the {@link Bitmap} to display + * @param reset + * - if true the image bounds will be recreated, otherwise the old {@link Matrix} is used to display the new bitmap + * @see #setImageBitmap(Bitmap) + */ + public void setImageBitmap( final Bitmap bitmap, final boolean reset ) { + setImageBitmap( bitmap, reset, null ); + } + + /** + * Similar to {@link #setImageBitmap(Bitmap, boolean)} but an optional view {@link Matrix} can be passed to determine the new + * bitmap view matrix.
+ * This method is useful if you need to restore a Bitmap with the same zoom/pan values from a previous state + * + * @param bitmap + * - the {@link Bitmap} to display + * @param reset + * @param matrix + * - the {@link Matrix} to be used to display the new bitmap + * + * @see #setImageBitmap(Bitmap, boolean) + * @see #setImageBitmap(Bitmap) + * @see #getImageViewMatrix() + * @see #getDisplayMatrix() + */ + public void setImageBitmap( final Bitmap bitmap, final boolean reset, Matrix matrix ) { + setImageBitmap( bitmap, reset, matrix, -1 ); + } + + /** + * + * @param bitmap + * @param reset + * @param matrix + * @param maxZoom + * - maximum zoom allowd during zoom gestures + * + * @see #setImageBitmap(Bitmap, boolean, Matrix) + */ + public void setImageBitmap( final Bitmap bitmap, final boolean reset, Matrix matrix, float maxZoom ) { + + Log.i( LOG_TAG, "setImageBitmap: " + bitmap ); + + if ( bitmap != null ) + setImageDrawable( new FastBitmapDrawable( bitmap ), reset, matrix, maxZoom ); + else + setImageDrawable( null, reset, matrix, maxZoom ); + } + + @Override + public void setImageDrawable( Drawable drawable ) { + setImageDrawable( drawable, true, null, -1 ); + } + + public void setImageDrawable( final Drawable drawable, final boolean reset, final Matrix initial_matrix, final float maxZoom ) { + + final int viewWidth = getWidth(); + + if ( viewWidth <= 0 ) { + mOnLayoutRunnable = new Runnable() { + + @Override + public void run() { + setImageDrawable( drawable, reset, initial_matrix, maxZoom ); + } + }; + return; + } + + _setImageDrawable( drawable, reset, initial_matrix, maxZoom ); + } + + protected void _setImageDrawable( final Drawable drawable, final boolean reset, final Matrix initial_matrix, final float maxZoom ) { + + if ( drawable != null ) { + if ( mFitToScreen ) + getProperBaseMatrix2( drawable, mBaseMatrix ); + else + getProperBaseMatrix( drawable, mBaseMatrix ); + super.setImageDrawable( drawable ); + + if (mFitToWidth) zoomToWidth(); + + } else { + mBaseMatrix.reset(); + super.setImageDrawable( null ); + } + + if ( reset ) { + mSuppMatrix.reset(); + if ( initial_matrix != null ) { + mSuppMatrix = new Matrix( initial_matrix ); + } + } + + setImageMatrix( getImageViewMatrix() ); + + if ( maxZoom < 1 ) + mMaxZoom = maxZoom(); + else + mMaxZoom = maxZoom; + + onBitmapChanged( drawable ); + } + + protected void onBitmapChanged( final Drawable bitmap ) { + if ( mListener != null ) { + mListener.onBitmapChanged( bitmap ); + } + } + + protected float maxZoom() { + final Drawable drawable = getDrawable(); + + if ( drawable == null ) { + return 1F; + } + + float fw = (float) drawable.getIntrinsicWidth() / (float) mThisWidth; + float fh = (float) drawable.getIntrinsicHeight() / (float) mThisHeight; + float max = Math.max( fw, fh ) * 4; + return max; + } + + public float getMaxZoom() { + return mMaxZoom; + } + + public Matrix getImageViewMatrix() { + mDisplayMatrix.set( mBaseMatrix ); + mDisplayMatrix.postConcat( mSuppMatrix ); + return mDisplayMatrix; + } + + /** + * Returns the current image display matrix. This matrix can be used in the next call to the + * {@link #setImageBitmap(Bitmap, boolean, Matrix)} to restore the same view state of the previous {@link Bitmap} + * + * @return + */ + public Matrix getDisplayMatrix() { + return new Matrix( mSuppMatrix ); + } + + /** + * Setup the base matrix so that the image is centered and scaled properly. + * + * @param bitmap + * @param matrix + */ + protected void getProperBaseMatrix( Drawable drawable, Matrix matrix ) { + float viewWidth = getWidth(); + float viewHeight = getHeight(); + float w = drawable.getIntrinsicWidth(); + float h = drawable.getIntrinsicHeight(); + matrix.reset(); + + if ( w > viewWidth || h > viewHeight ) { + float widthScale = Math.min( viewWidth / w, 2.0f ); + float heightScale = Math.min( viewHeight / h, 2.0f ); + float scale = Math.min( widthScale, heightScale ); + matrix.postScale( scale, scale ); + float tw = ( viewWidth - w * scale ) / 2.0f; + float th = ( viewHeight - h * scale ) / 2.0f; + matrix.postTranslate( tw, th ); + } else { + float tw = ( viewWidth - w ) / 2.0f; + float th = ( viewHeight - h ) / 2.0f; + matrix.postTranslate( tw, th ); + } + } + + /** + * Setup the base matrix so that the image is centered and scaled properly. + * + * @param bitmap + * @param matrix + */ + protected void getProperBaseMatrix2( Drawable bitmap, Matrix matrix ) { + float viewWidth = getWidth(); + float viewHeight = getHeight(); + float w = bitmap.getIntrinsicWidth(); + float h = bitmap.getIntrinsicHeight(); + matrix.reset(); + float widthScale = Math.min( viewWidth / w, MAX_ZOOM ); + float heightScale = Math.min( viewHeight / h, MAX_ZOOM ); + float scale = Math.min( widthScale, heightScale ); + matrix.postScale( scale, scale ); + matrix.postTranslate( ( viewWidth - w * scale ) / 2.0f, ( viewHeight - h * scale ) / 2.0f ); + } + + protected float getValue( Matrix matrix, int whichValue ) { + matrix.getValues( mMatrixValues ); + return mMatrixValues[whichValue]; + } + + protected RectF getBitmapRect() { + final Drawable drawable = getDrawable(); + + if ( drawable == null ) return null; + Matrix m = getImageViewMatrix(); + mBitmapRect.set( 0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight() ); + m.mapRect( mBitmapRect ); + return mBitmapRect; + } + + protected float getScale( Matrix matrix ) { + return getValue( matrix, Matrix.MSCALE_X ); + } + + public float getRotation() { + return 0; + } + + public float getScale() { + return getScale( mSuppMatrix ); + } + + protected void center( boolean horizontal, boolean vertical ) { + // Log.i(LOG_TAG, "center"); + final Drawable drawable = getDrawable(); + + if ( drawable == null ) return; + RectF rect = getCenter( horizontal, vertical ); + if ( rect.left != 0 || rect.top != 0 ) { + postTranslate( rect.left, rect.top ); + } + } + + protected RectF getCenter( boolean horizontal, boolean vertical ) { + final Drawable drawable = getDrawable(); + + if ( drawable == null ) return new RectF( 0, 0, 0, 0 ); + + RectF rect = getBitmapRect(); + float height = rect.height(); + float width = rect.width(); + float deltaX = 0, deltaY = 0; + if ( vertical ) { + int viewHeight = getHeight(); + if ( height < viewHeight ) { + deltaY = ( viewHeight - height ) / 2 - rect.top; + } else if ( rect.top > 0 ) { + deltaY = -rect.top; + } else if ( rect.bottom < viewHeight ) { + deltaY = getHeight() - rect.bottom; + } + } + if ( horizontal ) { + int viewWidth = getWidth(); + if ( width < viewWidth ) { + deltaX = ( viewWidth - width ) / 2 - rect.left; + } else if ( rect.left > 0 ) { + deltaX = -rect.left; + } else if ( rect.right < viewWidth ) { + deltaX = viewWidth - rect.right; + } + } + mCenterRect.set( deltaX, deltaY, 0, 0 ); + return mCenterRect; + } + + protected void postTranslate( float deltaX, float deltaY ) { + mSuppMatrix.postTranslate( deltaX, deltaY ); + setImageMatrix( getImageViewMatrix() ); + } + + protected void postScale( float scale, float centerX, float centerY ) { + mSuppMatrix.postScale( scale, scale, centerX, centerY ); + setImageMatrix( getImageViewMatrix() ); + } + + protected void zoomTo( float scale ) { + float cx = getWidth() / 2F; + float cy = getHeight() / 2F; + zoomTo( scale, cx, cy ); + } + + public void zoomTo( float scale, float durationMs ) { + float cx = getWidth() / 2F; + float cy = getHeight() / 2F; + zoomTo( scale, cx, cy, durationMs ); + } + + protected void zoomTo( float scale, float centerX, float centerY ) { + if ( scale > mMaxZoom ) scale = mMaxZoom; + float oldScale = getScale(); + float deltaScale = scale / oldScale; + postScale( deltaScale, centerX, centerY ); + onZoom( getScale() ); + center( true, true ); + } + + protected void onZoom( float scale ) {} + + public void scrollBy( float x, float y ) { + panBy( x, y ); + } + + protected void panBy( double dx, double dy ) { + RectF rect = getBitmapRect(); + mScrollRect.set( (float) dx, (float) dy, 0, 0 ); + updateRect( rect, mScrollRect ); + postTranslate( mScrollRect.left, mScrollRect.top ); + center( true, true ); + } + + protected void updateRect( RectF bitmapRect, RectF scrollRect ) { + float width = getWidth(); + float height = getHeight(); + + if ( bitmapRect.top >= 0 && bitmapRect.bottom <= height ) scrollRect.top = 0; + if ( bitmapRect.left >= 0 && bitmapRect.right <= width ) scrollRect.left = 0; + if ( bitmapRect.top + scrollRect.top >= 0 && bitmapRect.bottom > height ) scrollRect.top = (int) ( 0 - bitmapRect.top ); + if ( bitmapRect.bottom + scrollRect.top <= ( height - 0 ) && bitmapRect.top < 0 ) + scrollRect.top = (int) ( ( height - 0 ) - bitmapRect.bottom ); + if ( bitmapRect.left + scrollRect.left >= 0 ) scrollRect.left = (int) ( 0 - bitmapRect.left ); + if ( bitmapRect.right + scrollRect.left <= ( width - 0 ) ) scrollRect.left = (int) ( ( width - 0 ) - bitmapRect.right ); + // Log.d( LOG_TAG, "scrollRect(2): " + scrollRect.toString() ); + } + + protected void scrollBy( float distanceX, float distanceY, final double durationMs ) { + final double dx = distanceX; + final double dy = distanceY; + final long startTime = System.currentTimeMillis(); + mHandler.post( new Runnable() { + + double old_x = 0; + double old_y = 0; + + @Override + public void run() { + long now = System.currentTimeMillis(); + double currentMs = Math.min( durationMs, now - startTime ); + double x = mEasing.easeOut( currentMs, 0, dx, durationMs ); + double y = mEasing.easeOut( currentMs, 0, dy, durationMs ); + panBy( ( x - old_x ), ( y - old_y ) ); + old_x = x; + old_y = y; + if ( currentMs < durationMs ) { + mHandler.post( this ); + } else { + RectF centerRect = getCenter( true, true ); + if ( centerRect.left != 0 || centerRect.top != 0 ) scrollBy( centerRect.left, centerRect.top ); + } + } + } ); + } + + protected void zoomTo( float scale, final float centerX, final float centerY, final float durationMs ) { + // Log.i( LOG_TAG, "zoomTo: " + scale + ", " + centerX + ": " + centerY ); + final long startTime = System.currentTimeMillis(); + final float incrementPerMs = ( scale - getScale() ) / durationMs; + final float oldScale = getScale(); + mHandler.post( new Runnable() { + + @Override + public void run() { + long now = System.currentTimeMillis(); + float currentMs = Math.min( durationMs, now - startTime ); + float target = oldScale + ( incrementPerMs * currentMs ); + zoomTo( target, centerX, centerY ); + if ( currentMs < durationMs ) { + mHandler.post( this ); + } else { + // if ( getScale() < 1f ) {} + } + } + } ); + } + + @Override + public void dispose() { + clear(); + } + + protected void zoomToWidth() { + RectF bitmapRect = getBitmapRect(); + + float w = bitmapRect.right - bitmapRect.left; + + if (w < getWidth()) { + float scale = (float)getWidth() / w; + + zoomTo(scale, 0f, 0f); + } + } +} diff --git a/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/easing/Cubic.java b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/easing/Cubic.java new file mode 100644 index 0000000..6f7e87d --- /dev/null +++ b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/easing/Cubic.java @@ -0,0 +1,20 @@ +package it.sephiroth.android.library.imagezoom.easing; + +public class Cubic implements Easing { + + @Override + public double easeOut( double time, double start, double end, double duration ) { + return end * ( ( time = time / duration - 1.0 ) * time * time + 1.0 ) + start; + } + + @Override + public double easeIn( double time, double start, double end, double duration ) { + return end * ( time /= duration ) * time * time + start; + } + + @Override + public double easeInOut( double time, double start, double end, double duration ) { + if ( ( time /= duration / 2.0 ) < 1.0 ) return end / 2.0 * time * time * time + start; + return end / 2.0 * ( ( time -= 2.0 ) * time * time + 2.0 ) + start; + } +} diff --git a/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/easing/Easing.java b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/easing/Easing.java new file mode 100644 index 0000000..202e9d9 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/easing/Easing.java @@ -0,0 +1,10 @@ +package it.sephiroth.android.library.imagezoom.easing; + +public interface Easing { + + double easeOut( double time, double start, double end, double duration ); + + double easeIn( double time, double start, double end, double duration ); + + double easeInOut( double time, double start, double end, double duration ); +} diff --git a/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/graphics/FastBitmapDrawable.java b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/graphics/FastBitmapDrawable.java new file mode 100644 index 0000000..8afc38e --- /dev/null +++ b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/graphics/FastBitmapDrawable.java @@ -0,0 +1,84 @@ +package it.sephiroth.android.library.imagezoom.graphics; + +import java.io.InputStream; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; + +/** + * Fast bitmap drawable. Does not support states. it only + * support alpha and colormatrix + * @author alessandro + * + */ +public class FastBitmapDrawable extends Drawable implements IBitmapDrawable { + + protected Bitmap mBitmap; + protected Paint mPaint; + + public FastBitmapDrawable( Bitmap b ) { + mBitmap = b; + mPaint = new Paint(); + mPaint.setDither( true ); + mPaint.setFilterBitmap( true ); + } + + public FastBitmapDrawable( Resources res, InputStream is ){ + this(BitmapFactory.decodeStream(is)); + } + + @Override + public void draw( Canvas canvas ) { + canvas.drawBitmap( mBitmap, 0.0f, 0.0f, mPaint ); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public void setAlpha( int alpha ) { + mPaint.setAlpha( alpha ); + } + + @Override + public void setColorFilter( ColorFilter cf ) { + mPaint.setColorFilter( cf ); + } + + @Override + public int getIntrinsicWidth() { + return mBitmap.getWidth(); + } + + @Override + public int getIntrinsicHeight() { + return mBitmap.getHeight(); + } + + @Override + public int getMinimumWidth() { + return mBitmap.getWidth(); + } + + @Override + public int getMinimumHeight() { + return mBitmap.getHeight(); + } + + public void setAntiAlias( boolean value ){ + mPaint.setAntiAlias( value ); + invalidateSelf(); + } + + @Override + public Bitmap getBitmap() { + return mBitmap; + } +} \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/graphics/IBitmapDrawable.java b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/graphics/IBitmapDrawable.java new file mode 100644 index 0000000..5a2892a --- /dev/null +++ b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/graphics/IBitmapDrawable.java @@ -0,0 +1,14 @@ +package it.sephiroth.android.library.imagezoom.graphics; + +import it.sephiroth.android.library.imagezoom.ImageViewTouchBase; +import android.graphics.Bitmap; + +/** + * Base interface used in the {@link ImageViewTouchBase} view + * @author alessandro + * + */ +public interface IBitmapDrawable { + + Bitmap getBitmap(); +} diff --git a/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/utils/IDisposable.java b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/utils/IDisposable.java new file mode 100644 index 0000000..da991a7 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/it/sephiroth/android/library/imagezoom/utils/IDisposable.java @@ -0,0 +1,6 @@ +package it.sephiroth.android.library.imagezoom.utils; + +public interface IDisposable { + + void dispose(); +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/CbrComicArchive.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/CbrComicArchive.java new file mode 100644 index 0000000..b1fb65d --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/CbrComicArchive.java @@ -0,0 +1,69 @@ +package org.fox.ttcomics; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.zip.ZipFile; + +import com.github.junrar.Archive; +import com.github.junrar.exception.RarException; +import com.github.junrar.rarfile.FileHeader; + +import android.util.Log; + +public class CbrComicArchive extends ComicArchive { + private final String TAG = this.getClass().getSimpleName(); + + private Archive m_archive; + private ArrayList m_entries = new ArrayList(); + + @Override + public int getCount() { + return m_entries.size(); + } + + @Override + public InputStream getItem(int index) throws IOException { + try { + return m_archive.getInputStream(m_entries.get(index)); + } catch (RarException e) { + e.printStackTrace(); + return null; + } catch (OutOfMemoryError e) { + e.printStackTrace(); + return null; + } + } + + public CbrComicArchive(String fileName) throws IOException, RarException { + m_archive = new Archive(new File(fileName)); + + FileHeader header = m_archive.nextFileHeader(); + + while (header != null) { + if (!header.isDirectory()) { + String name = header.isUnicode() ? header.getFileNameW() : header.getFileNameString(); + + if (isValidComic(name)) { + m_entries.add(header); + } + } + + header = m_archive.nextFileHeader(); + } + + Collections.sort(m_entries, new Comparator() { + public int compare(FileHeader a, FileHeader b) { + String nameA = a.isUnicode() ? a.getFileNameW() : a.getFileNameString(); + String nameB = b.isUnicode() ? b.getFileNameW() : b.getFileNameString(); + + return nameA.compareTo(nameB); + } + }); + + } + +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/CbzComicArchive.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/CbzComicArchive.java new file mode 100644 index 0000000..5e5b54f --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/CbzComicArchive.java @@ -0,0 +1,50 @@ +package org.fox.ttcomics; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class CbzComicArchive extends ComicArchive { + private final String TAG = this.getClass().getSimpleName(); + + private ZipFile m_zipFile; + private int m_count; + private ArrayList m_entries = new ArrayList(); + + @Override + public int getCount() { + return m_count; + } + + @Override + public InputStream getItem(int index) throws IOException { + return m_zipFile.getInputStream(m_entries.get(index)); + } + + public CbzComicArchive(String fileName) throws IOException { + m_zipFile = new ZipFile(fileName); + + Enumeration e = m_zipFile.entries(); + + while (e.hasMoreElements()) { + ZipEntry ze = e.nextElement(); + if (!ze.isDirectory() && isValidComic(ze.getName())) { + m_entries.add(ze); + m_count++; + } + } + + Collections.sort(m_entries, new Comparator() { + public int compare(ZipEntry a, ZipEntry b) { + return a.getName().compareTo(b.getName()); + } + }); + + } + +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicArchive.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicArchive.java new file mode 100644 index 0000000..3070323 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicArchive.java @@ -0,0 +1,12 @@ +package org.fox.ttcomics; + +import java.io.IOException; +import java.io.InputStream; + +public abstract class ComicArchive { + public abstract int getCount(); + public abstract InputStream getItem(int index) throws IOException; + public boolean isValidComic(String fileName) { + return fileName.toLowerCase().matches(".*\\.(jpg|bmp|gif|png)$"); + } +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicFragment.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicFragment.java new file mode 100644 index 0000000..75d750f --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicFragment.java @@ -0,0 +1,329 @@ +package org.fox.ttcomics; + + +import it.sephiroth.android.library.imagezoom.ImageViewTouch; + +import java.io.IOException; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.app.Fragment; +import android.support.v7.app.ActionBar; +import android.util.Log; +import android.view.GestureDetector; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +public class ComicFragment extends Fragment implements GestureDetector.OnDoubleTapListener { + private final String TAG = this.getClass().getSimpleName(); + + private SharedPreferences m_prefs; + private int m_page; + private CommonActivity m_activity; + private GestureDetector m_detector; + private boolean m_thumbnail = false; + + public ComicFragment() { + super(); + } + + private void setThumbnail(boolean thumbnail) { + if (m_thumbnail != thumbnail) { + m_thumbnail = thumbnail; + + if (isAdded()) { + AsyncTask loadTask = new AsyncTask() { + @Override + protected Bitmap doInBackground(ComicArchive... params) { + return loadImage(params[0], m_page); + } + + @Override + protected void onPostExecute(Bitmap result) { + CommonActivity activity = (CommonActivity) getActivity(); + + ImageViewTouch image = (ImageViewTouch) getView().findViewById(R.id.comic_image); + + if (activity != null && isAdded() && image != null) { + if (result != null) { + image.setImageBitmap(result); + } else { + activity.toast(R.string.error_loading_image); + image.setImageResource(R.drawable.badimage); + } + } + } + }; + + ComicPager pager = (ComicPager) getActivity().getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_COMICS_PAGER); + loadTask.execute(pager.getArchive()); + } + } + } + + public void setPage(int page) { + m_page = page; + } + + public Bitmap loadImage(ComicArchive archive, int page) { + CommonActivity activity = (CommonActivity) getActivity(); + + try { + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(archive.getItem(page), null, options); + options.inJustDecodeBounds = false; + + Bitmap bitmap = null; + + int sampleSizes[]; + + if (m_thumbnail) { + sampleSizes = new int[] { 512, 256 }; + } else { + sampleSizes = new int[] { 1024, 768, 512, 256 }; + } + + for (int sampleSize : sampleSizes) { + try { + options.inSampleSize = CommonActivity.calculateInSampleSize(options, sampleSize, sampleSize); + bitmap = BitmapFactory.decodeStream(archive.getItem(page), null, options); + + return bitmap; + } catch (OutOfMemoryError e) { + if (sampleSize == sampleSizes[sampleSizes.length-1]) { + e.printStackTrace(); + + if (activity != null && isAdded()) { + activity.toast(R.string.error_out_of_memory); + } + } + } + } + + } catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + View view = inflater.inflate(R.layout.fragment_comic, container, false); + + final ImageViewTouch image = (ImageViewTouch) view.findViewById(R.id.comic_image); + + if (savedInstanceState != null) { + m_page = savedInstanceState.getInt("page"); + m_thumbnail = savedInstanceState.getBoolean("thumbnail"); + } + + ComicPager pager = (ComicPager) getActivity().getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_COMICS_PAGER); + + if (pager != null) { + if (CommonActivity.isCompatMode() && m_prefs.getBoolean("use_dark_theme", false)) { + image.setBackgroundColor(0xff000000); + } + + image.setFitToScreen(true); + + if (m_prefs.getBoolean("fit_to_width", false)) { + image.setFitToWidth(true); + } + + AsyncTask loadTask = new AsyncTask() { + @Override + protected Bitmap doInBackground(ComicArchive... params) { + return loadImage(params[0], m_page); + } + + @Override + protected void onPostExecute(Bitmap result) { + CommonActivity activity = (CommonActivity) getActivity(); + + if (activity != null && isAdded()) { + if (result != null) { + image.setImageBitmap(result); + } else { + activity.toast(R.string.error_loading_image); + image.setImageResource(R.drawable.badimage); + } + } + } + }; + + loadTask.execute(pager.getArchive()); + + image.setOnScaleChangedListener(new ImageViewTouch.OnScaleChangedListener() { + @Override + public void onScaleChanged(float scale) { + // TODO: shared scale change? + } + }); + + image.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent event) { + return m_detector.onTouchEvent(event); + } + }); + + } + + TextView page = (TextView) view.findViewById(R.id.comic_page); + + if (page != null) { + page.setText(String.valueOf(m_page+1)); + } + + return view; + + } + + private void onLeftSideTapped() { + ImageViewTouch image = (ImageViewTouch) getView().findViewById(R.id.comic_image); + + if (image != null) { + boolean atLeftEdge = !image.canScroll(1); + + if (atLeftEdge) { + m_activity.selectPreviousComic(); + } + } + } + + public boolean canScroll(int direction) { + ImageViewTouch image = (ImageViewTouch) getView().findViewById(R.id.comic_image); + + if (image != null) { + return image.canScroll(direction); + } else { + return false; + } + } + + private void onRightSideTapped() { + ImageViewTouch image = (ImageViewTouch) getView().findViewById(R.id.comic_image); + + if (image != null) { + boolean atRightEdge = !image.canScroll(-1); + + if (atRightEdge) { + m_activity.selectNextComic(); + } + } + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + + //setThumbnail(!isVisibleToUser); disabled + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_prefs = PreferenceManager.getDefaultSharedPreferences(activity.getApplicationContext()); + m_activity = (CommonActivity) activity; + + m_detector = new GestureDetector(m_activity, new GestureDetector.OnGestureListener() { + + @Override + public boolean onSingleTapUp(MotionEvent e) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void onShowPress(MotionEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, + float distanceY) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void onLongPress(MotionEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, + float velocityY) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean onDown(MotionEvent e) { + // TODO Auto-generated method stub + return false; + } + }); + + m_detector.setOnDoubleTapListener(this); + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + out.putInt("page", m_page); + out.putBoolean("thumbnail", m_thumbnail); + } + + @Override + public boolean onDoubleTap(MotionEvent e) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent e) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + + int width = getView().getWidth(); + + int x = Math.round(e.getX()); + + if (x <= width/10) { + onLeftSideTapped(); + } else if (x >= width-(width/10)) { + onRightSideTapped(); + } else { + ActionBar bar = m_activity.getSupportActionBar(); + + if (bar.isShowing()) { + bar.hide(); + m_activity.hideSystemUiIfNecessary(); + } else { + m_activity.showSystemUiIfNecessary(); + bar.show(); + } + } + + return false; + } +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicListFragment.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicListFragment.java new file mode 100644 index 0000000..26166fc --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicListFragment.java @@ -0,0 +1,529 @@ +package org.fox.ttcomics; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.SQLException; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SimpleCursorAdapter; +import android.support.v4.widget.SwipeRefreshLayout; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.github.junrar.exception.RarException; + +public class ComicListFragment extends Fragment implements OnItemClickListener { + private final String TAG = this.getClass().getSimpleName(); + + private final static int SIZE_DIR = -100; + + // corresponds to tab indexes + private final static int MODE_ALL = 0; + private final static int MODE_UNREAD = 1; + private final static int MODE_UNFINISHED = 2; + private final static int MODE_READ = 3; + + private CommonActivity m_activity; + private SharedPreferences m_prefs; + private ComicsListAdapter m_adapter; + private int m_mode = 0; + private String m_baseDirectory = ""; + private SwipeRefreshLayout m_swipeLayout; + + public ComicListFragment() { + super(); + } + + public void setBaseDirectory(String baseDirectory) { + m_baseDirectory = baseDirectory; + } + + public void setMode(int mode) { + m_mode = mode; + } + + private class ComicsListAdapter extends SimpleCursorAdapter { + public ComicsListAdapter(Context context, int layout, Cursor c, + String[] from, int[] to, int flags) { + super(context, layout, c, from, to, flags); + // TODO Auto-generated constructor stub + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = convertView; + + Cursor c = (Cursor) getItem(position); + + String filePath = c.getString(c.getColumnIndex("path")); + String fileBaseName = c.getString(c.getColumnIndex("filename")); + String firstChild = c.getString(c.getColumnIndex("firstchild")); + + int lastPos = m_activity.getLastPosition(filePath + "/" + fileBaseName); + int size = m_activity.getSize(filePath + "/" + fileBaseName); + + boolean isList = ComicListFragment.this.getView().findViewById(R.id.comics_list) != null; + + if (v == null) { + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + + v = vi.inflate(isList ? R.layout.comics_list_row : R.layout.comics_grid_row, null); + + } + + TextView name = (TextView) v.findViewById(R.id.file_name); + + if (name != null) { + name.setText(fileBaseName); + } + + TextView info = (TextView) v.findViewById(R.id.file_progress_info); + + if (info != null) { + if (size != -1 && size != SIZE_DIR) { + if (lastPos == size - 1) { + info.setText(getString(R.string.file_finished)); + } else if (lastPos > 0) { + info.setText(getString(R.string.file_progress_info, lastPos+1, size, (int)(lastPos/ (float)size * 100f))); + } else { + info.setText(getString(R.string.file_unread, size)); + } + info.setVisibility(View.VISIBLE); + } else { + info.setVisibility(View.GONE); + } + } + + ProgressBar progressBar = (ProgressBar) v.findViewById(R.id.file_progress_bar); + + if (progressBar != null) { + if (size != -1 && size != SIZE_DIR) { + progressBar.setMax(size-1); + progressBar.setProgress(lastPos); + progressBar.setVisibility(View.VISIBLE); + } else { + progressBar.setVisibility(View.GONE); + } + } + + ImageView overflow = (ImageView) v.findViewById(R.id.comic_overflow); + + if (overflow != null) { + if (size == SIZE_DIR) { + overflow.setVisibility(View.GONE); + } else { + overflow.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + getActivity().openContextMenu(v); + } + }); + } + } + + File thumbnailFile = new File(m_activity.getCacheFileName(firstChild != null ? firstChild : filePath + "/" + fileBaseName)); + + ImageView thumbnail = (ImageView) v.findViewById(R.id.thumbnail); + + if (thumbnail != null) { + View imageholder = v.findViewById(R.id.imageholder); + + int padding = dpToPx(2); + + if (imageholder != null) { + if (size == SIZE_DIR) { + imageholder.setBackgroundResource(R.drawable.comic_tile_folder); + imageholder.setPadding(padding, padding, padding, padding); + } else { + imageholder.setBackgroundResource(R.drawable.comic_tile); + imageholder.setPadding(padding, padding, padding, padding); + } + } + + thumbnail.setTag(""); + thumbnail.setImageResource(R.drawable.ic_launcher); + + if (m_activity.isStorageAvailable() && thumbnailFile.exists()) { + thumbnail.setTag(thumbnailFile.getAbsolutePath()); + + CoverImageLoader imageLoader = new CoverImageLoader(); + imageLoader.execute(thumbnail); + } + } + + return v; + } + } + + public int dpToPx(int dp) { + DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); + int px = Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)); + return px; + } + + class CoverImageLoader extends AsyncTask { + private ImageView m_thumbnail; + private String m_tag; + + @Override + protected Bitmap doInBackground(ImageView... params) { + m_thumbnail = params[0]; + + if (m_thumbnail != null) { + m_tag = m_thumbnail.getTag().toString(); + + File thumbnailFile = new File(m_tag); + + if (thumbnailFile.exists() && thumbnailFile.canRead()) { + + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(thumbnailFile.getAbsolutePath(), options); + + options.inSampleSize = CommonActivity.calculateInSampleSize(options, 256, 256); + options.inJustDecodeBounds = false; + + Bitmap bmp = BitmapFactory.decodeFile(thumbnailFile.getAbsolutePath(), options); + + return bmp; + } + } + + return null; + } + + @Override + protected void onPostExecute(Bitmap bmp) { + if (isAdded() && bmp != null && m_tag != null && m_tag.equals(m_thumbnail.getTag().toString())) { + m_thumbnail.setImageBitmap(bmp); + } + } + + }; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + View view = inflater.inflate(R.layout.fragment_comics_list, container, false); + + if (savedInstanceState != null) { + m_mode = savedInstanceState.getInt("mode"); + m_baseDirectory = savedInstanceState.getString("baseDir"); + //m_files = savedInstanceState.getStringArrayList("files"); + } + + m_swipeLayout = (SwipeRefreshLayout) view.findViewById(R.id.comics_swipe_container); + + m_swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + rescan(true); + } + }); + + if (!CommonActivity.isCompatMode()) { + m_swipeLayout.setColorScheme(android.R.color.holo_green_dark, + android.R.color.holo_red_dark, + android.R.color.holo_blue_dark, + android.R.color.holo_orange_dark); + } + + m_adapter = new ComicsListAdapter(getActivity(), R.layout.comics_list_row, createCursor(), + new String[] { "filename" }, new int[] { R.id.file_name }, 0); + + if (view.findViewById(R.id.comics_list) != null) { + ListView list = (ListView) view.findViewById(R.id.comics_list); + list.setAdapter(m_adapter); + list.setEmptyView(view.findViewById(R.id.no_comics)); + list.setOnItemClickListener(this); + + registerForContextMenu(list); + + } else { + GridView grid = (GridView) view.findViewById(R.id.comics_grid); + grid.setAdapter(m_adapter); + grid.setEmptyView(view.findViewById(R.id.no_comics)); + grid.setOnItemClickListener(this); + + registerForContextMenu(grid); + + } + + return view; + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.comic_archive_context, menu); + + AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo; + + Cursor c = (Cursor) m_adapter.getItem(info.position); + + if (c != null) { + menu.setHeaderTitle(c.getString(c.getColumnIndex("filename"))); + } + + super.onCreateContextMenu(menu, v, menuInfo); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + + Cursor c = (Cursor) m_adapter.getItem(info.position); + String fileName = c.getString(c.getColumnIndex("path")) + "/" + c.getString(c.getColumnIndex("filename")); + + switch (item.getItemId()) { + case R.id.menu_reset_progress: + if (fileName != null) { + m_activity.resetProgress(fileName); + m_adapter.notifyDataSetChanged(); + } + return true; + case R.id.menu_mark_as_read: + + if (fileName != null) { + m_activity.setLastPosition(fileName, m_activity.getSize(fileName)-1); + m_adapter.notifyDataSetChanged(); + } + + return true; + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + private Cursor createCursor() { + String baseDir = m_baseDirectory.length() == 0 ? m_prefs.getString("comics_directory", "") : m_baseDirectory; + + String selection; + String selectionArgs[]; + + switch (m_mode) { + case MODE_READ: + selection = "path = ? AND position = size - 1"; + selectionArgs = new String[] { baseDir }; + break; + case MODE_UNFINISHED: + selection = "path = ? AND position < size AND position > 0 AND position != size - 1"; + selectionArgs = new String[] { baseDir }; + break; + case MODE_UNREAD: + selection = "path = ? AND position = 0 AND size != ?"; + selectionArgs = new String[] { baseDir, String.valueOf(SIZE_DIR) }; + break; + default: + selection = "path = ?"; + selectionArgs = new String[] { baseDir }; + } + + if (!m_prefs.getBoolean("enable_rar", false)) { + selection += " AND (UPPER(filename) NOT LIKE '%.CBR' AND UPPER(filename) NOT LIKE '%.RAR')"; + } + + return m_activity.getReadableDb().query("comics_cache", new String[] { BaseColumns._ID, "filename", "path", + "(SELECT path || '/' || filename FROM comics_cache AS t2 WHERE t2.path = comics_cache.path || '/' || comics_cache.filename AND filename != '' ORDER BY filename LIMIT 1) AS firstchild" }, + selection, selectionArgs, null, null, "size != " + SIZE_DIR + ", filename, size = " + SIZE_DIR + ", filename"); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_activity = (CommonActivity)activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(activity.getApplicationContext()); + } + + protected void rescan(final boolean fullRescan) { + m_swipeLayout.setRefreshing(true); + + AsyncTask rescanTask = new AsyncTask() { + + @Override + protected void onProgressUpdate(Integer... progress) { + if (isAdded()) { + m_activity.setProgress(Math.round(((float)progress[0] / (float)progress[1]) * 10000)); + } + } + + @Override + protected Integer doInBackground(String... params) { + String comicsDir = params[0]; + + File dir = new File(comicsDir); + + int fileIndex = 0; + + if (dir.isDirectory()) { + File archives[] = dir.listFiles(); + + java.util.Arrays.sort(archives); + + for (File archive : archives) { + String filePath = archive.getAbsolutePath(); + + if (archive.isDirectory()) { + m_activity.setSize(filePath, SIZE_DIR); + + } else if (archive.getName().toLowerCase().matches(".*\\.(cbz|zip|cbr|rar)") && isAdded() && m_activity != null && + m_activity.getWritableDb() != null && m_activity.getWritableDb().isOpen()) { + try { + int size = m_activity.getSize(filePath); + + if (size == -1 || fullRescan) { + + ComicArchive cba = null; + + if (archive.getName().toLowerCase().matches(".*\\.(cbz|zip)")) { + cba = new CbzComicArchive(filePath); + } else { + try { + cba = new CbrComicArchive(filePath); + } catch (RarException e) { + e.printStackTrace(); + } + } + + if (cba != null && cba.getCount() > 0) { + // Get cover + + try { + File thumbnailFile = new File(m_activity.getCacheFileName(filePath)); + + if (m_activity.isStorageWritable() && (!thumbnailFile.exists() || fullRescan)) { + InputStream is = cba.getItem(0); + + if (is != null) { + FileOutputStream fos = new FileOutputStream(thumbnailFile); + + byte[] buffer = new byte[1024]; + int len = 0; + while ((len = is.read(buffer)) != -1) { + fos.write(buffer, 0, len); + } + + fos.close(); + is.close(); + } + } + + } catch (IOException e) { + e.printStackTrace(); + } + + size = cba.getCount(); + + m_activity.setSize(filePath, size); + } + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + ++fileIndex; + + publishProgress(Integer.valueOf(fileIndex), Integer.valueOf(archives.length)); + } + } + + if (isAdded() && m_activity != null) { + m_activity.cleanupCache(false); + m_activity.cleanupSqliteCache(comicsDir); + + m_swipeLayout.setRefreshing(false); + } + + return fileIndex; //m_files.size(); + } + + @Override + protected void onPostExecute(Integer result) { + if (isAdded() && m_adapter != null) { + m_adapter.changeCursor(createCursor()); + m_adapter.notifyDataSetChanged(); + } + } + }; + + String comicsDir = m_prefs.getString("comics_directory", null); + + if (comicsDir != null && m_activity.isStorageAvailable()) { + rescanTask.execute(m_baseDirectory.length() > 0 ? m_baseDirectory : comicsDir); + } + } + + @Override + public void onResume() { + super.onResume(); + + m_adapter.notifyDataSetChanged(); + + String comicsDir = m_prefs.getString("comics_directory", ""); + + if (m_activity.getCachedItemCount(m_baseDirectory.length() > 0 ? m_baseDirectory : comicsDir) == 0) { + rescan(false); + } else { + m_adapter.notifyDataSetChanged(); + } + } + + public void onItemClick(AdapterView av, View view, int position, long id) { + //Log.d(TAG, "onItemClick position=" + position); + + Cursor c = (Cursor) m_adapter.getItem(position); + String fileName = c.getString(c.getColumnIndex("path")) + "/" + c.getString(c.getColumnIndex("filename")); + + if (fileName != null) { + m_activity.onComicArchiveSelected(fileName); + } + } + + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("mode", m_mode); + out.putString("baseDir", m_baseDirectory); + //out.putStringArrayList("files", m_files); + } + +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicPager.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicPager.java new file mode 100644 index 0000000..4371df4 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ComicPager.java @@ -0,0 +1,166 @@ +package org.fox.ttcomics; + +import java.io.IOException; +import java.util.HashMap; + +import com.github.junrar.exception.RarException; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class ComicPager extends Fragment { + private String m_fileName; + private SharedPreferences m_prefs; + private final String TAG = this.getClass().getSimpleName(); + private ComicArchive m_archive; + private CommonActivity m_activity; + + private class PagerAdapter extends FragmentStatePagerAdapter { + public PagerAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int position) { + ComicFragment cf = new ComicFragment(); + cf.setPage(position); + + return cf; + } + + @Override + public int getCount() { + return m_archive.getCount(); + } + } + + private PagerAdapter m_adapter; + + public ComicPager() { + super(); + } + + public ComicArchive getArchive() { + return m_archive; + } + + public int getCount() { + return m_adapter.getCount(); + } + + public int getPosition() { + ViewPager pager = (ViewPager) getView().findViewById(R.id.comics_pager); + + if (pager != null) { + return pager.getCurrentItem(); + } + + return 0; + } + + public String getFileName() { + return m_fileName; + } + + public void setCurrentItem(int item) { + ViewPager pager = (ViewPager) getView().findViewById(R.id.comics_pager); + + if (pager != null) { + try { + pager.setCurrentItem(item); + } catch (IndexOutOfBoundsException e) { + e.printStackTrace(); + } + } + } + + public void setFileName(String fileName) { + m_fileName = fileName; + } + + @SuppressLint("NewApi") + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + final View view = inflater.inflate(R.layout.fragment_comics_pager, container, false); + + m_adapter = new PagerAdapter(getActivity().getSupportFragmentManager()); + + final ViewPager pager = (ViewPager) view.findViewById(R.id.comics_pager); + + if (savedInstanceState != null) { + m_fileName = savedInstanceState.getString("fileName"); + } + + try { + if (m_fileName.toLowerCase().matches(".*\\.(cbz|zip)")) { + m_archive = new CbzComicArchive(m_fileName); + } else { + m_archive = new CbrComicArchive(m_fileName); + } + + int position = m_activity.getLastPosition(m_fileName); + + pager.setAdapter(m_adapter); + pager.setCurrentItem(position); + + m_activity.onComicSelected(m_fileName, position); + m_activity.setProgress(Math.round(((float)position / (float)(m_archive.getCount()-1)) * 10000)); + m_activity.hideSystemUiIfNecessary(); + + } catch (IOException e) { + m_activity.toast(R.string.error_could_not_open_comic_archive); + e.printStackTrace(); + } catch (RarException e) { + m_activity.toast(R.string.error_could_not_open_comic_archive); + e.printStackTrace(); + } + + pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + public void onPageSelected(int position) { + + m_activity.onComicSelected(m_fileName, position); + m_activity.setProgress(Math.round(((float)position / (float)(m_archive.getCount()-1)) * 10000)); + + m_activity.hideSystemUiIfNecessary(); + } + + public void onPageScrolled(int arg0, float arg1, int arg2) { + // TODO Auto-generated method stub + } + + public void onPageScrollStateChanged(int arg0) { + // TODO Auto-generated method stub + } + }); + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_activity = (CommonActivity) activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(activity.getApplicationContext()); + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putString("fileName", m_fileName); + } + +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/CommonActivity.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/CommonActivity.java new file mode 100644 index 0000000..6d392d2 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/CommonActivity.java @@ -0,0 +1,653 @@ +package org.fox.ttcomics; + + +import java.io.File; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Date; + +import com.readystatesoftware.systembartint.SystemBarTintManager; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.AlertDialog; +import android.content.ActivityNotFoundException; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v7.app.ActionBarActivity; +import android.util.Log; +import android.util.TypedValue; +import android.view.Display; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.widget.Toast; + +public class CommonActivity extends ActionBarActivity { + private final String TAG = this.getClass().getSimpleName(); + + protected static final String FRAG_COMICS_PAGER = "comic_pager"; + protected static final String FRAG_COMICS_LIST = "comics_list"; + + protected final static int REQUEST_SHARE = 1; + protected static final int REQUEST_VIEWCOMIC = 2; + + protected SharedPreferences m_prefs; + protected SyncClient m_syncClient = new SyncClient(); + + private boolean m_smallScreenMode = true; + + private boolean m_storageAvailable; + private boolean m_storageWritable; + + private SQLiteDatabase m_readableDb; + private SQLiteDatabase m_writableDb; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + + initDatabase(); + initSync(); + } + + @Override + public void onResume() { + super.onResume(); + + String state = Environment.getExternalStorageState(); + + if (Environment.MEDIA_MOUNTED.equals(state)) { + m_storageAvailable = true; + m_storageWritable = true; + } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { + m_storageAvailable = true; + m_storageWritable = false; + } else { + m_storageAvailable = false; + m_storageWritable = false; + } + + initSync(); + } + + private void initSync() { + if (m_prefs.getBoolean("use_position_sync", false)) { + String googleAccount = getGoogleAccount(); + + if (googleAccount != null) { + m_syncClient.setOwner(googleAccount); + } else { + if (Build.HARDWARE.contains("goldfish")) { + m_syncClient.setOwner("TEST-ACCOUNT"); + + //toast(R.string.sync_running_in_test_mode); + } else { + m_syncClient.setOwner(null); + toast(R.string.error_sync_no_account); + + SharedPreferences.Editor editor = m_prefs.edit(); + editor.putBoolean("use_position_sync", false); + editor.commit(); + } + } + } else { + m_syncClient.setOwner(null); + } + } + + public static boolean isCompatMode() { + return android.os.Build.VERSION.SDK_INT <= 10; + } + + protected void setSmallScreen(boolean smallScreen) { + Log.d(TAG, "m_smallScreenMode=" + smallScreen); + m_smallScreenMode = smallScreen; + } + + public boolean isSmallScreen() { + return m_smallScreenMode; + } + + + public void onComicArchiveSelected(String fileName) { + // + } + + public Cursor findComicByFileName(String fileName) { + File file = new File(fileName); + + Cursor c = getReadableDb().query("comics_cache", null, + "filename = ? AND path = ?", + new String[] { file.getName(), file.getParentFile().getAbsolutePath() }, null, null, null); + + if (c.moveToFirst()) { + return c; + } else { + c.close(); + + SQLiteStatement stmt = getWritableDb().compileStatement("INSERT INTO comics_cache " + + "(filename, path, position, max_position, size, checksum) VALUES (?, ?, 0, 0, -1, '')"); + stmt.bindString(1, file.getName()); + stmt.bindString(2, file.getParentFile().getAbsolutePath()); + stmt.execute(); + + c = getReadableDb().query("comics_cache", null, + "filename = ? AND path = ?", + new String[] { file.getName(), file.getParentFile().getAbsolutePath() }, null, null, null); + + if (c.moveToFirst()) { + return c; + } else { + c.close(); + } + } + + return null; + } + + public void setSize(String fileName, int size) { + Cursor c = findComicByFileName(fileName); + + if (c != null) { + c.close(); + + File file = new File(fileName); + + SQLiteStatement stmt = getWritableDb().compileStatement("UPDATE comics_cache SET size = ? WHERE filename = ? AND path = ?"); + stmt.bindLong(1, size); + stmt.bindString(2, file.getName()); + stmt.bindString(3, file.getParentFile().getAbsolutePath()); + stmt.execute(); + stmt.close(); + } + } + + public void setChecksum(String fileName, String checksum) { + Cursor c = findComicByFileName(fileName); + + if (c != null) { + c.close(); + + File file = new File(fileName); + + SQLiteStatement stmt = getWritableDb().compileStatement("UPDATE comics_cache SET checksum = ? WHERE filename = ? AND path = ?"); + stmt.bindString(1, checksum); + stmt.bindString(2, file.getName()); + stmt.bindString(3, file.getParentFile().getAbsolutePath()); + stmt.execute(); + stmt.close(); + } + } + + public void resetProgress(final String fileName) { + + if (m_prefs.getBoolean("use_position_sync", false) && m_syncClient.hasOwner()) { + setLastPosition(fileName, 0); + setLastMaxPosition(fileName, 0); + + AlertDialog.Builder builder = new AlertDialog.Builder(CommonActivity.this); + builder.setMessage(R.string.reset_remove_synced_progress) + .setCancelable(true) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + m_syncClient.clearData(sha1(new File(fileName).getName())); + } + }) + .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + + } + + } + + public void setLastPosition(String fileName, int position) { + int lastPosition = getLastPosition(fileName); + + Cursor c = findComicByFileName(fileName); + + if (c != null) { + c.close(); + + File file = new File(fileName); + + SQLiteStatement stmt = getWritableDb().compileStatement("UPDATE comics_cache SET position = ?, max_position = ? WHERE filename = ? AND path = ?"); + stmt.bindLong(1, position); + stmt.bindLong(2, Math.max(position, lastPosition)); + stmt.bindString(3, file.getName()); + stmt.bindString(4, file.getParentFile().getAbsolutePath()); + stmt.execute(); + stmt.close(); + } + + } + + public void setLastMaxPosition(String fileName, int position) { + + Cursor c = findComicByFileName(fileName); + + if (c != null) { + c.close(); + + File file = new File(fileName); + + SQLiteStatement stmt = getWritableDb().compileStatement("UPDATE comics_cache SET max_position = ? WHERE filename = ? AND path = ?"); + stmt.bindLong(1, position); + stmt.bindString(2, file.getName()); + stmt.bindString(3, file.getParentFile().getAbsolutePath()); + stmt.execute(); + stmt.close(); + } + } + + public String getChecksum(String fileName) { + String checksum = null; + + File file = new File(fileName); + + Cursor c = getReadableDb().query("comics_cache", new String[] { "checksum" }, + "filename = ? AND path = ?", + new String[] { file.getName(), file.getParentFile().getAbsolutePath() }, null, null, null); + + if (c.moveToFirst()) { + checksum = c.getString(c.getColumnIndex("checksum")); + } + + c.close(); + + return checksum; + + } + + + public int getLastPosition(String fileName) { + int position = 0; + + File file = new File(fileName); + + Cursor c = getReadableDb().query("comics_cache", new String[] { "position" }, + "filename = ? AND path = ?", + new String[] { file.getName(), file.getParentFile().getAbsolutePath() }, null, null, null); + + if (c.moveToFirst()) { + position = c.getInt(c.getColumnIndex("position")); + } + + c.close(); + + return position; + + } + + public int getCachedItemCount(String baseDir) { + Cursor c = getReadableDb().query("comics_cache", new String[] { "COUNT(*)" }, + "path = ?", + new String[] { baseDir }, null, null, null); + + c.moveToFirst(); + int count = c.getInt(0); + c.close(); + + //Log.d(TAG, "getCachedItemCount:" + baseDir + "=" + count); + + return count; + } + + public int getMaxPosition(String fileName) { + int position = 0; + + File file = new File(fileName); + + Cursor c = getReadableDb().query("comics_cache", new String[] { "max_position" }, + "filename = ? AND path = ?", + new String[] { file.getName(), file.getParentFile().getAbsolutePath() }, null, null, null); + + if (c.moveToFirst()) { + position = c.getInt(c.getColumnIndex("max_position")); + } + + c.close(); + + return position; + } + + public int getSize(String fileName) { + int size = -1; + + File file = new File(fileName); + + Cursor c = getReadableDb().query("comics_cache", new String[] { "size" }, + "filename = ? AND path = ?", + new String[] { file.getName(), file.getParentFile().getAbsolutePath() }, null, null, null); + + if (c.moveToFirst()) { + size = c.getInt(c.getColumnIndex("size")); + } + + c.close(); + + //Log.d(TAG, "getSize:" + fileName + "=" + size); + + return size; + } + + public void onComicSelected(String fileName, int position) { + setLastPosition(fileName, position); + } + + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_donate: + if (true) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse("market://details?id=org.fox.ttcomics.donation")); + startActivity(intent); + } catch (ActivityNotFoundException ae) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse("https://play.google.com/store/apps/details?id=org.fox.ttcomics.donation")); + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + + return true; + case R.id.menu_rescan: + ComicListFragment frag = (ComicListFragment) getSupportFragmentManager().findFragmentByTag(FRAG_COMICS_LIST); + + if (frag != null && frag.isAdded()) { + frag.rescan(true); + } + + return true; + case R.id.menu_settings: + Intent intent = new Intent(CommonActivity.this, + PreferencesActivity.class); + startActivityForResult(intent, 0); + return true; + default: + Log.d(TAG, + "onOptionsItemSelected, unhandled id=" + item.getItemId()); + return super.onOptionsItemSelected(item); + } + } + + @SuppressWarnings("deprecation") + public boolean isPortrait() { + Display display = getWindowManager().getDefaultDisplay(); + + int width = display.getWidth(); + int height = display.getHeight(); + + return width < height; + } + + protected static String md5(String s) { + try { + MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); + digest.update(s.getBytes()); + byte messageDigest[] = digest.digest(); + + StringBuffer hexString = new StringBuffer(); + for (int i=0; i reqHeight || width > reqWidth) { + if (width > height) { + inSampleSize = Math.round((float)height / (float)reqHeight); + } else { + inSampleSize = Math.round((float)width / (float)reqWidth); + } + } + return inSampleSize; + } + + + public void cleanupCache(boolean deleteAll) { + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + File cachePath = getExternalCacheDir(); + + long now = new Date().getTime(); + + if (cachePath.isDirectory()) { + for (File file : cachePath.listFiles()) { + if (deleteAll || now - file.lastModified() > 1000*60*60*24*7) { + file.delete(); + } + } + } + } + } + + public boolean isStorageAvailable() { + return m_storageAvailable; + } + + public boolean isStorageWritable() { + return m_storageWritable; + } + + private void initDatabase() { + DatabaseHelper dh = new DatabaseHelper(getApplicationContext()); + + m_writableDb = dh.getWritableDatabase(); + m_readableDb = dh.getReadableDatabase(); + } + + public synchronized SQLiteDatabase getReadableDb() { + return m_readableDb; + } + + public synchronized SQLiteDatabase getWritableDb() { + return m_writableDb; + } + + @Override + public void onDestroy() { + super.onDestroy(); + + m_readableDb.close(); + m_writableDb.close(); + } + + public void selectPreviousComic() { + ComicPager frag = (ComicPager) getSupportFragmentManager().findFragmentByTag(FRAG_COMICS_PAGER); + + if (frag != null && frag.isAdded() && frag.getPosition() > 0) { + frag.setCurrentItem(frag.getPosition() - 1); + } + } + + public void selectNextComic() { + ComicPager frag = (ComicPager) getSupportFragmentManager().findFragmentByTag(FRAG_COMICS_PAGER); + + if (frag != null && frag.isAdded() && frag.getPosition() < frag.getCount()-1) { + frag.setCurrentItem(frag.getPosition() + 1); + } + } + + public void cleanupSqliteCache(String baseDir) { + Cursor c = getReadableDb().query("comics_cache", null, + null, null, null, null, null); + + if (c.moveToFirst()) { + while (!c.isAfterLast()) { + int id = c.getInt(c.getColumnIndex(BaseColumns._ID)); + String fileName = c.getString(c.getColumnIndex("path")) + "/" + c.getString(c.getColumnIndex("filename")); + + File file = new File(fileName); + + if (!file.exists()) { + SQLiteStatement stmt = getWritableDb().compileStatement("DELETE FROM comics_cache WHERE " + BaseColumns._ID + " = ?"); + stmt.bindLong(1, id); + stmt.execute(); + } + + c.moveToNext(); + } + } + + c.close(); + } + + public void showSystemUiIfNecessary() { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { + if (m_prefs.getBoolean("use_full_screen", false)) { + getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + } else { + getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_VISIBLE); + } + } + } + + public void setStatusBarTint() { + if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.KITKAT) { + SystemBarTintManager tintManager = new SystemBarTintManager(this); + // enable status bar tint + tintManager.setStatusBarTintEnabled(true); + // enable navigation bar tint + tintManager.setNavigationBarTintEnabled(true); + + TypedValue tv = new TypedValue(); + getTheme().resolveAttribute(R.attr.statusBarHintColor, tv, true); + + tintManager.setStatusBarTintColor(tv.data); + } + } + + public void hideSystemUiIfNecessary() { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { + if (m_prefs.getBoolean("use_full_screen", false)) { + + getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE); + + } else if (m_prefs.getBoolean("dim_status_bar", false)) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); + } + + } else { + + if (!isCompatMode()) { + if (m_prefs.getBoolean("dim_status_bar", false)) { + getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_HIDDEN); + } + } + + if (m_prefs.getBoolean("use_full_screen", false)) { + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + getSupportActionBar().hide(); + } + + } + + + } +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/DatabaseHelper.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/DatabaseHelper.java new file mode 100644 index 0000000..15b7a25 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/DatabaseHelper.java @@ -0,0 +1,68 @@ +package org.fox.ttcomics; + +import java.io.File; + +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteStatement; +import android.provider.BaseColumns; + +public class DatabaseHelper extends SQLiteOpenHelper { + + public static final String DATABASE_NAME = "ComicsCache.db"; + public static final int DATABASE_VERSION = 2; + + public DatabaseHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("DROP TABLE IF EXISTS comics_cache;"); + + db.execSQL("CREATE TABLE IF NOT EXISTS comics_cache (" + + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + "filename TEXT, " + + "path TEXT, " + //v2 + "checksum TEXT, " + //v2 + "size INTEGER, " + + "position INTEGER, " + + "max_position INTEGER" + + ");"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion == 1 && newVersion == 2) { + + db.execSQL("ALTER TABLE comics_cache ADD COLUMN path TEXT;"); + db.execSQL("ALTER TABLE comics_cache ADD COLUMN checksum TEXT;"); + + Cursor c = db.query("comics_cache", null, + null, null, null, null, null); + + if (c.moveToFirst()) { + while (!c.isAfterLast()) { + int id = c.getInt(c.getColumnIndex(BaseColumns._ID)); + String fileName = c.getString(c.getColumnIndex("filename")); + + File file = new File(fileName); + + SQLiteStatement stmt = db.compileStatement("UPDATE comics_cache SET filename = ?, path = ? WHERE " + BaseColumns._ID + " = ?"); + stmt.bindString(1, file.getName()); + stmt.bindString(2, file.getParentFile().getAbsolutePath()); + stmt.bindLong(3, id); + stmt.execute(); + + c.moveToNext(); + } + } + + c.close(); + } + } + +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/DirectoryPicker.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/DirectoryPicker.java new file mode 100644 index 0000000..d607b48 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/DirectoryPicker.java @@ -0,0 +1,169 @@ +package org.fox.ttcomics; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; + +import android.app.ListActivity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Environment; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ListView; +import android.widget.Toast; + +/** +Copyright (C) 2011 by Brad Greco + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ + +public class DirectoryPicker extends ListActivity { + + public static final String START_DIR = "startDir"; + public static final String ONLY_DIRS = "onlyDirs"; + public static final String SHOW_HIDDEN = "showHidden"; + public static final String CHOSEN_DIRECTORY = "chosenDir"; + public static final int PICK_DIRECTORY = 43522432; + private File dir; + private boolean showHidden = false; + private boolean onlyDirs = true ; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle extras = getIntent().getExtras(); + dir = Environment.getExternalStorageDirectory(); + if (extras != null) { + String preferredStartDir = extras.getString(START_DIR); + showHidden = extras.getBoolean(SHOW_HIDDEN, false); + onlyDirs = extras.getBoolean(ONLY_DIRS, true); + if(preferredStartDir != null) { + File startDir = new File(preferredStartDir); + if(startDir.isDirectory()) { + dir = startDir; + } + } + } + + setContentView(R.layout.chooser_list); + setTitle(dir.getAbsolutePath()); + Button btnChoose = (Button) findViewById(R.id.btnChoose); + String name = dir.getName(); + if(name.length() == 0) + name = "/"; + btnChoose.setText(getString(R.string.picker_choose, name)); + btnChoose.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + returnDir(dir.getAbsolutePath()); + } + }); + + Button btnParent = (Button) findViewById(R.id.btnParent); + btnParent.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + Intent intent = new Intent(DirectoryPicker.this, DirectoryPicker.class); + intent.putExtra(DirectoryPicker.START_DIR, dir.getParent()); + intent.putExtra(DirectoryPicker.SHOW_HIDDEN, showHidden); + intent.putExtra(DirectoryPicker.ONLY_DIRS, onlyDirs); + startActivityForResult(intent, PICK_DIRECTORY); + } + }); + + if (dir.getParent() == null) { + btnParent.setVisibility(View.GONE); + } + + ListView lv = getListView(); + lv.setTextFilterEnabled(true); + + if(!dir.canRead()) { + Context context = getApplicationContext(); + String msg = getString(R.string.error_could_not_read_folder_contents_); + Toast toast = Toast.makeText(context, msg, Toast.LENGTH_LONG); + toast.show(); + return; + } + + final ArrayList files = filter(dir.listFiles(), onlyDirs, showHidden); + String[] names = names(files); + setListAdapter(new ArrayAdapter(this, R.layout.list_item, names)); + + + lv.setOnItemClickListener(new OnItemClickListener() { + public void onItemClick(AdapterView parent, View view, int position, long id) { + if(!files.get(position).isDirectory()) + return; + String path = files.get(position).getAbsolutePath(); + Intent intent = new Intent(DirectoryPicker.this, DirectoryPicker.class); + intent.putExtra(DirectoryPicker.START_DIR, path); + intent.putExtra(DirectoryPicker.SHOW_HIDDEN, showHidden); + intent.putExtra(DirectoryPicker.ONLY_DIRS, onlyDirs); + startActivityForResult(intent, PICK_DIRECTORY); + } + }); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if(requestCode == PICK_DIRECTORY && resultCode == RESULT_OK) { + Bundle extras = data.getExtras(); + String path = (String) extras.get(DirectoryPicker.CHOSEN_DIRECTORY); + returnDir(path); + } + } + + private void returnDir(String path) { + Intent result = new Intent(); + result.putExtra(CHOSEN_DIRECTORY, path); + setResult(RESULT_OK, result); + finish(); + } + + public ArrayList filter(File[] file_list, boolean onlyDirs, boolean showHidden) { + ArrayList files = new ArrayList(); + + for(File file: file_list) { + if(onlyDirs && !file.isDirectory()) + continue; + if(!showHidden && file.isHidden()) + continue; + files.add(file); + } + Collections.sort(files); + + return files; + } + + public String[] names(ArrayList files) { + String[] names = new String[files.size()]; + int i = 0; + for(File file: files) { + names[i] = file.getName(); + i++; + } + return names; + } +} + diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/MainActivity.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/MainActivity.java new file mode 100644 index 0000000..0e589fa --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/MainActivity.java @@ -0,0 +1,253 @@ +package org.fox.ttcomics; + + +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import android.animation.LayoutTransition; +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBar.Tab; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.ShareActionProvider; + +public class MainActivity extends CommonActivity { + private final String TAG = this.getClass().getSimpleName(); + + private TabListener m_tabListener; + private int m_selectedTab; + private String m_baseDirectory = ""; + private String m_fileName = ""; + + @SuppressLint("NewApi") + private class TabListener implements ActionBar.TabListener { + + @Override + public void onTabReselected(Tab tab, FragmentTransaction ft) { + // TODO Auto-generated method stub + } + + @Override + public void onTabSelected(Tab tab, FragmentTransaction ft) { + FragmentTransaction sft = getSupportFragmentManager().beginTransaction(); + + if (m_selectedTab != tab.getPosition() && m_selectedTab != -1) { + + ComicListFragment frag = new ComicListFragment(); + frag.setMode(tab.getPosition()); + + frag.setBaseDirectory(m_baseDirectory); + + sft.replace(R.id.comics_list, frag, FRAG_COMICS_LIST); + } + + m_selectedTab = tab.getPosition(); + + sft.commit(); + } + + @Override + public void onTabUnselected(Tab tab, FragmentTransaction ft) { + // TODO Auto-generated method stub + + } + + } + + @SuppressLint("NewApi") + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + requestWindowFeature(Window.FEATURE_PROGRESS); + + setContentView(R.layout.activity_main); + + setProgressBarVisibility(false); + + setStatusBarTint(); + setSmallScreen(findViewById(R.id.tablet_layout_hack) == null); + + if (savedInstanceState == null) { + m_selectedTab = getIntent().getIntExtra("selectedTab", 0); + + Log.d(TAG, "selTab=" + m_selectedTab); + + ComicListFragment frag = new ComicListFragment(); + frag.setMode(m_selectedTab); + + if (getIntent().getStringExtra("baseDir") != null) { + m_baseDirectory = getIntent().getStringExtra("baseDir"); + frag.setBaseDirectory(m_baseDirectory); + } + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + ft.replace(R.id.comics_list, frag, FRAG_COMICS_LIST); + ft.commit(); + + m_selectedTab = -1; + } else { + m_selectedTab = -1; + m_baseDirectory = savedInstanceState.getString("baseDir"); + m_fileName = savedInstanceState.getString("fileName"); + } + + m_tabListener = new TabListener(); + + ActionBar actionBar = getSupportActionBar(); + + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + + actionBar.addTab(getSupportActionBar().newTab() + .setText(R.string.tab_all_comics) + .setTabListener(m_tabListener)); + + actionBar.addTab(getSupportActionBar().newTab() + .setText(R.string.tab_unread) + .setTabListener(m_tabListener)); + + actionBar.addTab(getSupportActionBar().newTab() + .setText(R.string.tab_unfinished) + .setTabListener(m_tabListener)); + + actionBar.addTab(getSupportActionBar().newTab() + .setText(R.string.tab_read) + .setTabListener(m_tabListener)); + + if (savedInstanceState != null) { + m_selectedTab = savedInstanceState.getInt("selectedTab"); + } else { + m_selectedTab = getIntent().getIntExtra("selectedTab", 0); + } + + actionBar.selectTab(actionBar.getTabAt(m_selectedTab)); + + actionBar.setDisplayHomeAsUpEnabled(m_baseDirectory.length() > 0); + + if (m_prefs.getString("comics_directory", null) == null) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.dialog_need_prefs_message) + .setCancelable(false) + .setPositiveButton(R.string.dialog_need_prefs_preferences, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // launch preferences + + Intent intent = new Intent(MainActivity.this, + PreferencesActivity.class); + startActivityForResult(intent, 0); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + } + + if (!isCompatMode()) { + ((ViewGroup)findViewById(R.id.comics_list)).setLayoutTransition(new LayoutTransition()); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.activity_main, menu); + + boolean isDonationFound = getPackageManager().checkSignatures( + getPackageName(), "org.fox.ttcomics.donation") == PackageManager.SIGNATURE_MATCH; + + if (isDonationFound) + menu.findItem(R.id.menu_donate).setVisible(false); + + return true; + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("selectedTab", m_selectedTab); + out.putString("baseDir", m_baseDirectory); + out.putString("fileName", m_fileName); + } + + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + if (m_baseDirectory.length() > 0) { + finish(); + } + return true; + default: + Log.d(TAG, + "onOptionsItemSelected, unhandled id=" + item.getItemId()); + return super.onOptionsItemSelected(item); + } + } + + @Override + public void onComicArchiveSelected(String fileName) { + super.onComicArchiveSelected(fileName); + + File file = new File(fileName); + + if (file.isDirectory()) { + Intent intent = new Intent(MainActivity.this, + MainActivity.class); + + intent.putExtra("baseDir", fileName); + intent.putExtra("selectedTab", m_selectedTab); + + startActivityForResult(intent, 0); + + } else if (file.canRead()) { + Intent intent = new Intent(MainActivity.this, + ViewComicActivity.class); + + intent.putExtra("fileName", fileName); + m_fileName = fileName; + + startActivityForResult(intent, REQUEST_VIEWCOMIC); + } else { + toast(getString(R.string.error_cant_open_file, fileName)); + + ComicListFragment frag = (ComicListFragment) getSupportFragmentManager().findFragmentByTag(FRAG_COMICS_LIST); + + if (frag != null && frag.isAdded()) { + frag.rescan(true); + } + } + } + + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent intent) { + if (requestCode == REQUEST_VIEWCOMIC) { + Log.d(TAG, "finished viewing comic: " + m_fileName); + + if (m_prefs.getBoolean("use_position_sync", false) && m_syncClient.hasOwner()) { + toast(R.string.sync_uploading); + m_syncClient.setPosition(sha1(new File(m_fileName).getName()), getLastPosition(m_fileName)); + } + } + + System.gc(); + + super.onActivityResult(requestCode, resultCode, intent); + } + +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/PreferencesActivity.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/PreferencesActivity.java new file mode 100644 index 0000000..7aa24a5 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/PreferencesActivity.java @@ -0,0 +1,124 @@ +package org.fox.ttcomics; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceCategory; +import android.preference.PreferenceManager; +import android.widget.Toast; + +public class PreferencesActivity extends PreferenceActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final SharedPreferences prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + addPreferencesFromResource(R.xml.preferences); + + if (CommonActivity.isCompatMode()) { + Preference dimPref = findPreference("dim_status_bar"); + PreferenceCategory readingCat = (PreferenceCategory) findPreference("prefs_reading"); + readingCat.removePreference(dimPref); + } + + Preference dirPref = findPreference("comics_directory"); + dirPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(PreferencesActivity.this, DirectoryPicker.class); + + intent.putExtra(DirectoryPicker.START_DIR, prefs.getString("comics_directory", + Environment.getExternalStorageDirectory().getAbsolutePath())); + + startActivityForResult(intent, DirectoryPicker.PICK_DIRECTORY); + return true; + } + }); + + Preference clearPref = findPreference("clear_sync_data"); + clearPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + AlertDialog.Builder builder = new AlertDialog.Builder(PreferencesActivity.this); + builder.setMessage(R.string.dialog_clear_data_title) + .setCancelable(false) + .setPositiveButton(R.string.dialog_clear_data, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + + String googleAccount = getGoogleAccount(); + SyncClient m_syncClient = new SyncClient(); + + if (googleAccount != null) { + m_syncClient.setOwner(googleAccount); + } else { + if (Build.HARDWARE.equals("goldfish")) { + m_syncClient.setOwner("TEST-ACCOUNT"); + } else { + m_syncClient.setOwner(null); + + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean("use_position_sync", false); + editor.commit(); + + Toast toast = Toast.makeText(PreferencesActivity.this, R.string.error_sync_no_account, Toast.LENGTH_SHORT); + toast.show(); + } + } + + if (m_syncClient.hasOwner()) { + m_syncClient.clearData(); + } + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + + return false; + } + }); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if(requestCode == DirectoryPicker.PICK_DIRECTORY && resultCode == RESULT_OK) { + Bundle extras = data.getExtras(); + String path = (String) extras.get(DirectoryPicker.CHOSEN_DIRECTORY); + + SharedPreferences prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + SharedPreferences.Editor editor = prefs.edit(); + editor.putString("comics_directory", path); + editor.commit(); + + } + } + + public String getGoogleAccount() { + AccountManager manager = (AccountManager) getSystemService(ACCOUNT_SERVICE); + Account[] list = manager.getAccounts(); + + for (Account account: list) { + if (account.type.equalsIgnoreCase("com.google")) { + return account.name; + } + } + return null; + } +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/SyncClient.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/SyncClient.java new file mode 100644 index 0000000..f67d01b --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/SyncClient.java @@ -0,0 +1,159 @@ +package org.fox.ttcomics; + +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +import android.os.AsyncTask; +import android.util.Log; + +public class SyncClient { + public interface PositionReceivedListener { + void onPositionReceived(int position); + } + + private class HttpTask extends AsyncTask { + protected String m_response = null; + protected int m_responseCode = -1; + + @Override + protected Boolean doInBackground(String... params) { + + String requestStr = null; + String op = params[0]; + + if (op.equals("set")) { + requestStr = String.format("op=set&owner=%1$s&hash=%2$s&position=%3$s", m_owner, params[1], params[2]); + } else if (op.equals("get")) { + requestStr = String.format("op=get&owner=%1$s&hash=%2$s", m_owner, params[1]); + } else if (op.equals("clear")) { + if (params.length > 1) { + requestStr = String.format("op=clear&owner=%1$s&hash=%2$s", m_owner, params[1]); + } else { + requestStr = String.format("op=clear&owner=%1$s", m_owner); + } + } + + Log.d(TAG, requestStr); + + if (requestStr == null) return false; + + try { + byte[] postData = requestStr.getBytes("UTF-8"); + + URL url = new URL(SYNC_ENDPOINT); + + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setUseCaches(false); + conn.setRequestMethod("POST"); + + OutputStream out = conn.getOutputStream(); + out.write(postData); + out.close(); + + m_responseCode = conn.getResponseCode(); + + if (m_responseCode == HttpURLConnection.HTTP_OK) { + StringBuffer response = new StringBuffer(); + InputStreamReader in = new InputStreamReader(conn.getInputStream(), "UTF-8"); + + char[] buf = new char[1024]; + int read = 0; + + while ((read = in.read(buf)) >= 0) { + response.append(buf, 0, read); + } + + //Log.d(TAG, "<<< " + response); + + m_response = response.toString(); + + if (response.indexOf("ERROR") == -1) { + return true; + } else { + return false; + } + } else { + Log.d(TAG, "HTTP error, code: " + m_responseCode); + } + + conn.disconnect(); + + } catch (Exception e) { + e.printStackTrace(); + } + + return false; + } + + } + + private final String TAG = this.getClass().getSimpleName(); + private static final String SYNC_ENDPOINT = "http://tt-rss.org/tcrsync/"; + private String m_owner = null; + + public void setOwner(String owner) { + m_owner = CommonActivity.sha1(owner); + } + + public int getPosition(String hash, final PositionReceivedListener listener) { + if (m_owner != null) { + Log.d(TAG, "Requesting sync data..."); + + HttpTask task = new HttpTask() { + @Override + protected void onPostExecute(Boolean result) { + if (result) { + try { + listener.onPositionReceived(Integer.valueOf(m_response)); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + } + }; + + task.execute("get", hash); + + } + return -1; + } + + public void setPosition(String hash, int position) { + if (m_owner != null) { + Log.d(TAG, "Uploading sync data..."); + + HttpTask task = new HttpTask(); + + task.execute("set", hash, String.valueOf(position)); + } + } + + public void clearData() { + if (m_owner != null) { + Log.d(TAG, "Clearing sync data..."); + + HttpTask task = new HttpTask(); + + task.execute("clear"); + } + } + + public void clearData(String hash) { + if (m_owner != null) { + Log.d(TAG, "Clearing sync data: " + hash); + + HttpTask task = new HttpTask(); + + task.execute("clear", hash); + } + } + + public boolean hasOwner() { + return m_owner != null; + } + +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ViewComicActivity.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ViewComicActivity.java new file mode 100644 index 0000000..6ccc0a5 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ViewComicActivity.java @@ -0,0 +1,391 @@ +package org.fox.ttcomics; + + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.NumberPicker; +import android.widget.SeekBar; +import android.widget.TextView; + +public class ViewComicActivity extends CommonActivity { + private final String TAG = this.getClass().getSimpleName(); + + private String m_fileName; + private String m_tmpFileName; + + @SuppressLint("NewApi") + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (!isCompatMode()) + setTheme(m_prefs.getBoolean("use_dark_theme", false) ? R.style.ViewDarkTheme : R.style.ViewLightTheme); + + requestWindowFeature(Window.FEATURE_PROGRESS); + + if (m_prefs.getBoolean("prevent_screen_sleep", false)) + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + /* if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.KITKAT && !m_prefs.getBoolean("use_full_screen", false)) { + getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + setStatusBarTint(); + } */ + + setContentView(R.layout.activity_view_comic); + + if (savedInstanceState == null) { + m_fileName = getIntent().getStringExtra("fileName"); + + ComicPager cp = new ComicPager(); + cp.setFileName(m_fileName); + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + ft.replace(R.id.comics_pager_container, cp, FRAG_COMICS_PAGER); + ft.commit(); + } else { + m_fileName = savedInstanceState.getString("fileName"); + m_tmpFileName = savedInstanceState.getString("tmpFileName"); + } + + setOrientationLock(isOrientationLocked(), true); + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + setTitle(new File(m_fileName).getName()); + + /* if (m_prefs.getBoolean("use_full_screen", false)) { + //getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + // WindowManager.LayoutParams.FLAG_FULLSCREEN); + + //getSupportActionBar().hide(); + } */ + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && m_prefs.getBoolean("use_dark_theme", false)) { + getSupportActionBar().setBackgroundDrawable(new ColorDrawable(Color.BLACK)); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.activity_view_comic, menu); + + menu.findItem(R.id.menu_sync_location).setVisible(m_prefs.getBoolean("use_position_sync", false) && m_syncClient.hasOwner()); + + return true; + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putString("fileName", m_fileName); + out.putString("tmpFileName", m_tmpFileName); + } + + @Override + public void onComicSelected(String fileName, int position) { + super.onComicSelected(fileName, position); + } + + public void onPause() { + super.onPause(); + + // upload progress + if (m_prefs.getBoolean("use_position_sync", false) && m_syncClient.hasOwner()) { + //toast(R.string.sync_uploading); + m_syncClient.setPosition(sha1(new File(m_fileName).getName()), getLastPosition(m_fileName)); + } + } + + private void shareComic() { + + ComicPager pager = (ComicPager) getSupportFragmentManager().findFragmentByTag(FRAG_COMICS_PAGER); + + if (pager != null) { + + try { + File tmpFile = File.createTempFile("trcshare", ".jpg", getExternalCacheDir()); + + Log.d(TAG, "FILE=" + tmpFile); + + InputStream is = pager.getArchive().getItem(pager.getPosition()); + + FileOutputStream fos = new FileOutputStream(tmpFile); + + byte[] buffer = new byte[1024]; + int len = 0; + while ((len = is.read(buffer)) != -1) { + fos.write(buffer, 0, len); + } + + fos.close(); + is.close(); + + Intent shareIntent = new Intent(Intent.ACTION_SEND); + + shareIntent.setType("image/jpeg"); + shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tmpFile)); + + m_tmpFileName = tmpFile.getAbsolutePath(); + + startActivityForResult(Intent.createChooser(shareIntent, getString(R.string.share_comic)), REQUEST_SHARE); + + } catch (IOException e) { + toast(getString(R.string.error_could_not_prepare_file_for_sharing)); + e.printStackTrace(); + } + + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent intent) { + if (requestCode == REQUEST_SHARE) { + File tmpFile = new File(m_tmpFileName); + + if (tmpFile.exists()) { + tmpFile.delete(); + } + + } + super.onActivityResult(requestCode, resultCode, intent); + } + + protected boolean isOrientationLocked() { + return m_prefs.getBoolean("prefs_lock_orientation", false); + } + + private void setOrientationLock(boolean locked, boolean restoreLast) { + if (locked) { + + int currentOrientation = restoreLast ? m_prefs.getInt("last_orientation", getResources().getConfiguration().orientation) : + getResources().getConfiguration().orientation; + + if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); + } else { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); + } + } else { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); + } + + if (locked != isOrientationLocked()) { + SharedPreferences.Editor editor = m_prefs.edit(); + editor.putBoolean("prefs_lock_orientation", locked); + editor.putInt("last_orientation", getResources().getConfiguration().orientation); + editor.commit(); + } + } + + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_share: + shareComic(); + return true; + case R.id.menu_toggle_orientation_lock: + setOrientationLock(!isOrientationLocked(), false); + return true; + case R.id.menu_sync_location: + m_syncClient.getPosition(sha1(new File(m_fileName).getName()), new SyncClient.PositionReceivedListener() { + @Override + public void onPositionReceived(final int position) { + final ComicPager pager = (ComicPager) getSupportFragmentManager().findFragmentByTag(FRAG_COMICS_PAGER); + + if (pager != null && pager.isAdded()) { + int localPosition = pager.getPosition(); + + if (position > localPosition) { + AlertDialog.Builder builder = new AlertDialog.Builder(ViewComicActivity.this); + builder.setMessage(getString(R.string.sync_server_has_further_page, localPosition+1, position+1)) + .setCancelable(true) + .setPositiveButton(R.string.dialog_open_page, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + pager.setCurrentItem(position); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + + } else { + toast(R.string.error_sync_no_data); + } + + } + } + }); + return true; + case R.id.menu_go_location: + Dialog dialog = new Dialog(ViewComicActivity.this); + AlertDialog.Builder builder = new AlertDialog.Builder(ViewComicActivity.this) + .setTitle("Go to...") + .setItems( + new String[] { + getString(R.string.dialog_location_beginning), + getString(R.string.dialog_location_furthest), + getString(R.string.dialog_location_location), + getString(R.string.dialog_location_end) + }, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + + final ComicPager cp = (ComicPager) getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_COMICS_PAGER); + + switch (which) { + case 0: + cp.setCurrentItem(0); + break; + case 1: + cp.setCurrentItem(getMaxPosition(m_fileName)); + break; + case 2: + if (!isCompatMode()) { + LayoutInflater inflater = getLayoutInflater(); + View contentView = inflater.inflate(R.layout.dialog_location, null); + + final NumberPicker picker = (NumberPicker) contentView.findViewById(R.id.number_picker); + + picker.setMinValue(1); + picker.setMaxValue(getSize(m_fileName)); + picker.setValue(cp.getPosition()+1); + + Dialog seekDialog = new Dialog(ViewComicActivity.this); + AlertDialog.Builder seekBuilder = new AlertDialog.Builder(ViewComicActivity.this) + .setTitle(R.string.dialog_open_location) + .setView(contentView) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }).setPositiveButton(R.string.dialog_open_location, new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + + cp.setCurrentItem(picker.getValue()-1); + + } + }); + + seekDialog = seekBuilder.create(); + seekDialog.show(); + } else { + LayoutInflater inflater = getLayoutInflater(); + final View contentView = inflater.inflate(R.layout.dialog_location_compat, null); + + final SeekBar seeker = (SeekBar) contentView.findViewById(R.id.number_seeker); + final TextView pageNum = (TextView) contentView.findViewById(R.id.page_number); + final int size = getSize(m_fileName); + + seeker.setMax(size-1); + seeker.setProgress(cp.getPosition()); + + pageNum.setText(getString(R.string.dialog_location_page_number, cp.getPosition()+1, size)); + + seeker.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){ + + @Override + public void onProgressChanged( + SeekBar seekBar, int progress, + boolean fromUser) { + + pageNum.setText(getString(R.string.dialog_location_page_number, progress+1, size)); + + } + + @Override + public void onStartTrackingTouch( + SeekBar arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void onStopTrackingTouch( + SeekBar arg0) { + // TODO Auto-generated method stub + + } + + + }); + + Dialog seekDialog = new Dialog(ViewComicActivity.this); + AlertDialog.Builder seekBuilder = new AlertDialog.Builder(ViewComicActivity.this) + .setTitle(R.string.dialog_open_location) + .setView(contentView) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }).setPositiveButton(R.string.dialog_open_location, new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + + cp.setCurrentItem(seeker.getProgress()); + + } + }); + + seekDialog = seekBuilder.create(); + seekDialog.show(); + + } + + break; + case 3: + cp.setCurrentItem(cp.getCount()-1); + break; + } + + dialog.cancel(); + } + }); + + dialog = builder.create(); + dialog.show(); + + return true; + case android.R.id.home: + finish(); + return true; + default: + Log.d(TAG, + "onOptionsItemSelected, unhandled id=" + item.getItemId()); + return super.onOptionsItemSelected(item); + } + } + +} diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ViewPager.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ViewPager.java new file mode 100644 index 0000000..a81261d --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics/ViewPager.java @@ -0,0 +1,38 @@ +package org.fox.ttcomics; + +import it.sephiroth.android.library.imagezoom.ImageViewTouch; +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +public class ViewPager extends android.support.v4.view.ViewPager { + public ViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { + if (v instanceof ImageViewTouch) { + ImageViewTouch ivt = (ImageViewTouch) v; + try { + return ivt.canScroll(dx); + } catch (NullPointerException e) { + // bad image, etc + return false; + } + } else { + return super.canScroll(v, checkV, dx, x, y); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return super.onTouchEvent(event); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + return super.onInterceptTouchEvent(event); + } +} \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/res/anim/appear.xml b/org.fox.ttcomics/src/main/res/anim/appear.xml new file mode 100644 index 0000000..a60e055 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/anim/appear.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/org.fox.ttcomics/src/main/res/anim/layout_comics.xml b/org.fox.ttcomics/src/main/res/anim/layout_comics.xml new file mode 100644 index 0000000..93a58f1 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/anim/layout_comics.xml @@ -0,0 +1,5 @@ + + diff --git a/org.fox.ttcomics/src/main/res/drawable-hdpi/badimage.png b/org.fox.ttcomics/src/main/res/drawable-hdpi/badimage.png new file mode 100644 index 0000000..bc71802 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-hdpi/badimage.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_action_good.png b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_action_good.png new file mode 100644 index 0000000..594ee12 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_action_good.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_action_overflow.png b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_action_overflow.png new file mode 100644 index 0000000..002fc4b Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_action_overflow.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_launcher.png b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000..04b4741 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_refresh_light.png b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_refresh_light.png new file mode 100644 index 0000000..bb9d855 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_refresh_light.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_search_light.png b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_search_light.png new file mode 100644 index 0000000..f12e005 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_search_light.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_settings.png b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_settings.png new file mode 100644 index 0000000..3e4580e Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_settings.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_share_light.png b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_share_light.png new file mode 100644 index 0000000..c329f58 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-hdpi/ic_share_light.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_action_good.png b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_action_good.png new file mode 100644 index 0000000..49b85ca Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_action_good.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_action_overflow.png b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_action_overflow.png new file mode 100644 index 0000000..cfe1287 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_action_overflow.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_launcher.png b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000..3447f91 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_refresh_light.png b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_refresh_light.png new file mode 100644 index 0000000..a7fdc0d Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_refresh_light.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_search_light.png b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_search_light.png new file mode 100644 index 0000000..3549f84 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_search_light.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_settings.png b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_settings.png new file mode 100644 index 0000000..09b0148 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_settings.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_share_light.png b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_share_light.png new file mode 100644 index 0000000..15549b0 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-xhdpi/ic_share_light.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable-xxhdpi/ic_launcher.png b/org.fox.ttcomics/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..c2557e0 Binary files /dev/null and b/org.fox.ttcomics/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/org.fox.ttcomics/src/main/res/drawable/comic_tile.xml b/org.fox.ttcomics/src/main/res/drawable/comic_tile.xml new file mode 100644 index 0000000..428e246 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/drawable/comic_tile.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/res/drawable/comic_tile_folder.xml b/org.fox.ttcomics/src/main/res/drawable/comic_tile_folder.xml new file mode 100644 index 0000000..2cd13b5 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/drawable/comic_tile_folder.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/res/drawable/s_badimage.svg b/org.fox.ttcomics/src/main/res/drawable/s_badimage.svg new file mode 100644 index 0000000..8c61713 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/drawable/s_badimage.svg @@ -0,0 +1,88 @@ + + + + + + + + + + image/svg+xml + + + + + + + + ? + + diff --git a/org.fox.ttcomics/src/main/res/drawable/s_launcher.svg b/org.fox.ttcomics/src/main/res/drawable/s_launcher.svg new file mode 100644 index 0000000..9af7a1b --- /dev/null +++ b/org.fox.ttcomics/src/main/res/drawable/s_launcher.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + POW! + + diff --git a/org.fox.ttcomics/src/main/res/layout-land/fragment_comics_list.xml b/org.fox.ttcomics/src/main/res/layout-land/fragment_comics_list.xml new file mode 100644 index 0000000..9752e65 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/layout-land/fragment_comics_list.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/res/layout-sw600dp/activity_main.xml b/org.fox.ttcomics/src/main/res/layout-sw600dp/activity_main.xml new file mode 100644 index 0000000..81b302b --- /dev/null +++ b/org.fox.ttcomics/src/main/res/layout-sw600dp/activity_main.xml @@ -0,0 +1,22 @@ + + + + + + + + + + \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/res/layout-sw600dp/activity_view_comic.xml b/org.fox.ttcomics/src/main/res/layout-sw600dp/activity_view_comic.xml new file mode 100644 index 0000000..e6479f6 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/layout-sw600dp/activity_view_comic.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/res/layout-sw600dp/comics_grid_row.xml b/org.fox.ttcomics/src/main/res/layout-sw600dp/comics_grid_row.xml new file mode 100644 index 0000000..8392a17 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/layout-sw600dp/comics_grid_row.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/res/layout-sw600dp/fragment_comics_list.xml b/org.fox.ttcomics/src/main/res/layout-sw600dp/fragment_comics_list.xml new file mode 100644 index 0000000..eaf8c90 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/layout-sw600dp/fragment_comics_list.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/res/layout/activity_main.xml b/org.fox.ttcomics/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..49a8732 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/layout/activity_main.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/res/layout/activity_view_comic.xml b/org.fox.ttcomics/src/main/res/layout/activity_view_comic.xml new file mode 100644 index 0000000..2cc0dd3 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/layout/activity_view_comic.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/org.fox.ttcomics/src/main/res/layout/chooser_list.xml b/org.fox.ttcomics/src/main/res/layout/chooser_list.xml new file mode 100644 index 0000000..f4b4a12 --- /dev/null +++ b/org.fox.ttcomics/src/main/res/layout/chooser_list.xml @@ -0,0 +1,33 @@ + + + + + + + +