From 58932365dde93d2c77502e4fc84e37c7ac9a183c Mon Sep 17 00:00:00 2001 From: Lars Christensen Date: Mon, 6 Apr 2009 14:03:43 +0200 Subject: [PATCH] Changes --- .autotest | 46 +- History.txt | 12 +- Manifest.txt | 14 +- README.txt | 102 +-- Rakefile | 54 +- bin/ocra.rb | 344 ++++---- lib/ocra.rb | 6 +- src/Makefile | 28 +- src/lzma/LzmaDec.c | 2014 ++++++++++++++++++++++---------------------- src/lzma/LzmaDec.h | 446 +++++----- src/lzma/Types.h | 416 ++++----- src/stub.c | 768 ++++++++--------- test/test_ocra.rb | 238 +++--- 13 files changed, 2264 insertions(+), 2224 deletions(-) diff --git a/.autotest b/.autotest index ae8d4b71..ef753adf 100644 --- a/.autotest +++ b/.autotest @@ -1,23 +1,23 @@ -# -*- ruby -*- - -require 'autotest/restart' - -# Autotest.add_hook :initialize do |at| -# at.extra_files << "../some/external/dependency.rb" -# -# at.libs << ":../some/external" -# -# at.add_exception 'vendor' -# -# at.add_mapping(/dependency.rb/) do |f, _| -# at.files_matching(/test_.*rb$/) -# end -# -# %w(TestA TestB).each do |klass| -# at.extra_class_map[klass] = "test/test_misc.rb" -# end -# end - -# Autotest.add_hook :run_command do |at| -# system "rake build" -# end +# -*- ruby -*- + +require 'autotest/restart' + +# Autotest.add_hook :initialize do |at| +# at.extra_files << "../some/external/dependency.rb" +# +# at.libs << ":../some/external" +# +# at.add_exception 'vendor' +# +# at.add_mapping(/dependency.rb/) do |f, _| +# at.files_matching(/test_.*rb$/) +# end +# +# %w(TestA TestB).each do |klass| +# at.extra_class_map[klass] = "test/test_misc.rb" +# end +# end + +# Autotest.add_hook :run_command do |at| +# system "rake build" +# end diff --git a/History.txt b/History.txt index 4b44e7a6..fae2d232 100644 --- a/History.txt +++ b/History.txt @@ -1,6 +1,6 @@ -=== 1.0.0 / 2009-04-05 - -* 1 major enhancement - - * Birthday! - +=== 1.0.0 / 2009-04-05 + +* 1 major enhancement + + * Birthday! + diff --git a/Manifest.txt b/Manifest.txt index 55bdfe0e..d8ac95ce 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -1,7 +1,7 @@ -History.txt -Manifest.txt -README.txt -Rakefile -bin/ocra -lib/ocra.rb -test/test_ocra.rb +History.txt +Manifest.txt +README.txt +Rakefile +bin/ocra +lib/ocra.rb +test/test_ocra.rb diff --git a/README.txt b/README.txt index 0771134c..2a6311dd 100644 --- a/README.txt +++ b/README.txt @@ -1,48 +1,54 @@ -= ocra - -* FIX (url) - -== DESCRIPTION: - -FIX (describe your package) - -== FEATURES/PROBLEMS: - -* FIX (list of features or problems) - -== SYNOPSIS: - - FIX (code sample of usage) - -== REQUIREMENTS: - -* FIX (list of requirements) - -== INSTALL: - -* FIX (sudo gem install, anything else) - -== LICENSE: - -(The MIT License) - -Copyright (c) 2009 FIX - -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. += ocra + +* FIX (url) + +== DESCRIPTION: + +FIX (describe your package) + +== FEATURES/PROBLEMS: + +* FIX (list of features or problems) + +== TODO: + +* Handle environment variables (RUBYOPT, RUBYLIB) +* No-console stub +* Ensure cleanup using PendingFileRenameOperations + +== SYNOPSIS: + + FIX (code sample of usage) + +== REQUIREMENTS: + +* FIX (list of requirements) + +== INSTALL: + +* FIX (sudo gem install, anything else) + +== LICENSE: + +(The MIT License) + +Copyright (c) 2009 FIX + +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. diff --git a/Rakefile b/Rakefile index 02e54ee2..2e061822 100644 --- a/Rakefile +++ b/Rakefile @@ -1,27 +1,27 @@ -# -*- ruby -*- - -require 'rubygems' -require 'hoe' -require './lib/ocra.rb' - -Hoe.new('ocra', Ocra::VERSION) do |p| - # p.rubyforge_name = 'ocrax' # if different than lowercase project name - p.developer('Lars Christensen', 'larsch@belunktum.dk') -end - - -file 'share/ocra/stub.exe' => 'src/stub.exe' do - mv 'src/stub.exe', 'share/ocra/stub.exe' -end - -file 'src/stub.exe' do - chdir 'src' do - system("mingw32-make") - end -end - -task :stub => 'share/ocra/stub.exe' - -task :test => :stub - -# vim: syntax=Ruby +# -*- ruby -*- + +require 'rubygems' +require 'hoe' +require './lib/ocra.rb' + +Hoe.new('ocra', Ocra::VERSION) do |p| + # p.rubyforge_name = 'ocrax' # if different than lowercase project name + p.developer('Lars Christensen', 'larsch@belunktum.dk') +end + + +file 'share/ocra/stub.exe' => 'src/stub.exe' do + mv 'src/stub.exe', 'share/ocra/stub.exe' +end + +file 'src/stub.exe' do + chdir 'src' do + system("mingw32-make") + end +end + +task :stub => 'share/ocra/stub.exe' + +task :test => :stub + +# vim: syntax=Ruby diff --git a/bin/ocra.rb b/bin/ocra.rb index 5e09ae12..21bd54d0 100644 --- a/bin/ocra.rb +++ b/bin/ocra.rb @@ -1,155 +1,189 @@ -#!/usr/bin/env ruby -# -*- ruby -*- - -$lzma_mode = true -$extra_dlls = [] -$files = [] - -usage = <NUL") or fail - @c = File.open("tmpout", "rb") { |tmp| tmp.read } - f.write([OP_DECOMPRESS_LZMA, @c.size, @c].pack("VVA*")) - f.write([OP_END].pack("V")) - else - f.write(@of) if $lzma_mode - end - - f.write([OP_END].pack("V")) - f.write([$sebimage.size].pack("V")) - f.write(Signature.pack("C*")) - end - end - def mkdir(path) - @paths[path] = true - puts "m #{path}" unless $quiet - @of << [OP_CREATE_DIRECTORY, path].pack("VZ*") - end - def ensuremkdir(tgt) - return if tgt == "." - if not @paths[tgt] - ensuremkdir(File.dirname(tgt)) - mkdir(tgt) - end - end - def createfile(src, tgt) - ensuremkdir(File.dirname(tgt)) - str = File.open(src, "rb") { |s| s.read } - puts "a #{tgt}" unless $quiet - @of << [OP_CREATE_FILE, tgt, str.size, str].pack("VZ*VA*") - end - def createprocess(image, cmdline) - @of << [OP_CREATE_PROCESS, image, cmdline].pack("VZ*Z*") - end - def close - @of.close - end -end - - -executable = $files[0].sub(/(\.rb)?$/, '.exe') - -puts "=== Building #{executable}" unless $quiet -SebBuilder.new(executable) do |sb| - sb.mkdir('src') - sb.createfile($files[0], 'src\\' + $files[0]) - sb.mkdir('bin') - sb.createfile(File.join(bindir, "ruby.exe"), "bin\\ruby.exe") - sb.createfile(File.join(bindir, libruby_so), "bin\\msvcrt-ruby18.dll") - $extra_dlls.each { |dll| - sb.createfile(File.join(bindir, dll), File.join("bin", dll).tr('/','\\')) - } - - libs.each { |path, tgt| - jn = File.join(tgt, path) - if jn =~ /\/(lib\/ruby\/.*)$/ - dst = $1 - else - dst = tgt - end - dst.tr!('/', '\\') - sb.createfile(jn, dst) - } - - sb.createprocess("bin\\ruby.exe", "ruby.exe \xff\\src\\" + $files[0]) -end -puts "=== Finished (Final size was #{File.size(executable)})" unless $quiet +#!/usr/bin/env ruby +# -*- ruby -*- + +$lzma_mode = true +$extra_dlls = [] +$files = [] + +usage = <NUL") or fail + @c = File.open("tmpout", "rb") { |tmp| tmp.read } + f.write([OP_DECOMPRESS_LZMA, @c.size, @c].pack("VVA*")) + f.write([OP_END].pack("V")) + else + f.write(@of) if $lzma_mode + end + + f.write([OP_END].pack("V")) + f.write([$sebimage.size].pack("V")) + f.write(Signature.pack("C*")) + end + end + def mkdir(path) + @paths[path] = true + puts "m #{path}" unless $quiet + @of << [OP_CREATE_DIRECTORY, path].pack("VZ*") + end + def ensuremkdir(tgt) + return if tgt == "." + if not @paths[tgt] + ensuremkdir(File.dirname(tgt)) + mkdir(tgt) + end + end + def createfile(src, tgt) + ensuremkdir(File.dirname(tgt)) + str = File.open(src, "rb") { |s| s.read } + puts "a #{tgt}" unless $quiet + @of << [OP_CREATE_FILE, tgt, str.size, str].pack("VZ*VA*") + end + def createprocess(image, cmdline) + puts "l #{image} #{cmdline}" + @of << [OP_CREATE_PROCESS, image, cmdline].pack("VZ*Z*") + end + def close + @of.close + end +end + + +executable = $files[0].sub(/(\.rbw?)?$/, '.exe') + +puts "=== Building #{executable}" unless $quiet +SebBuilder.new(executable) do |sb| + sb.mkdir('src') + + $files.each do |file| + path = File.join('src', file).tr('/','\\') + sb.createfile(file, path) + end + sb.mkdir('bin') + + if ($files[0] =~ /\.rbw$/ && !$force_windows) || $force_console + rubyexe = "ruby.exe" + else + rubyexe = "ruby.exe" + end + + sb.createfile(File.join(bindir, rubyexe), "bin\\" + rubyexe) + + sb.createfile(File.join(bindir, libruby_so), "bin\\msvcrt-ruby18.dll") + $extra_dlls.each { |dll| + sb.createfile(File.join(bindir, dll), File.join("bin", dll).tr('/','\\')) + } + #sb.createfile('c:\lang\Ruby-186-27\lib\ruby\gems\1.8\specifications\wxruby-2.0.0-x86-mswin32-60.gemspec', + # 'lib\ruby\gems\1.8\specifications\wxruby-2.0.0-x86-mswin32-60.gemspec') + + exec_prefix = RbConfig::CONFIG['exec_prefix'] + gemspecs.each { |gemspec| + pref = gemspec[0,exec_prefix.size] + path = gemspec[exec_prefix.size+1..-1] + if pref != exec_prefix + raise "#{gemspec} does not exist in the Ruby installation. Don't know where to put it." + end + sb.createfile(gemspec, path.tr('/','\\')) + } + + libs.each { |path, tgt| + jn = File.join(tgt, path) + if jn =~ /\/(lib\/ruby\/.*)$/ + dst = $1 + else + dst = path.dup + end + dst.tr!('/', '\\') + sb.createfile(jn, dst) + } + + sb.createprocess("bin\\" + rubyexe, "#{rubyexe} \xff\\src\\" + $files[0]) + puts "=== Compressing" unless $quiet or not $lzma_mode +end +puts "=== Finished (Final size was #{File.size(executable)})" unless $quiet diff --git a/lib/ocra.rb b/lib/ocra.rb index a416b96b..5e93fb78 100644 --- a/lib/ocra.rb +++ b/lib/ocra.rb @@ -1,3 +1,3 @@ -class Ocra - VERSION = '1.0.0' -end +class Ocra + VERSION = '1.0.0' +end diff --git a/src/Makefile b/src/Makefile index d2411f41..b4d0b04f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,14 +1,14 @@ -SRCS = stub.c lzma/lzmadec.c -OBJS = $(SRCS:.c=.o) -CC = gcc - -CFLAGS = -Wall -O2 -DWITH_LZMA -Ilzma -# CFLAGS += -D_DEBUG - -all: stub.exe - -stub.exe: $(OBJS) - $(CC) $(CFLAGS) $(OBJS) -s -o stub - -clean: - rm $(OBJS) +SRCS = stub.c lzma/lzmadec.c +OBJS = $(SRCS:.c=.o) +CC = gcc + +CFLAGS = -Wall -O2 -DWITH_LZMA -Ilzma +# CFLAGS += -D_DEBUG + +all: stub.exe + +stub.exe: $(OBJS) + $(CC) $(CFLAGS) $(OBJS) -s -o stub + +clean: + rm $(OBJS) diff --git a/src/lzma/LzmaDec.c b/src/lzma/LzmaDec.c index eb525017..d87eb191 100644 --- a/src/lzma/LzmaDec.c +++ b/src/lzma/LzmaDec.c @@ -1,1007 +1,1007 @@ -/* LzmaDec.c -- LZMA Decoder -2008-11-06 : Igor Pavlov : Public domain */ - -#include "LzmaDec.h" - -#include - -#define kNumTopBits 24 -#define kTopValue ((UInt32)1 << kNumTopBits) - -#define kNumBitModelTotalBits 11 -#define kBitModelTotal (1 << kNumBitModelTotalBits) -#define kNumMoveBits 5 - -#define RC_INIT_SIZE 5 - -#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } - -#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) -#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); -#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); -#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ - { UPDATE_0(p); i = (i + i); A0; } else \ - { UPDATE_1(p); i = (i + i) + 1; A1; } -#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) - -#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } -#define TREE_DECODE(probs, limit, i) \ - { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } - -/* #define _LZMA_SIZE_OPT */ - -#ifdef _LZMA_SIZE_OPT -#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) -#else -#define TREE_6_DECODE(probs, i) \ - { i = 1; \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - i -= 0x40; } -#endif - -#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } - -#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) -#define UPDATE_0_CHECK range = bound; -#define UPDATE_1_CHECK range -= bound; code -= bound; -#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ - { UPDATE_0_CHECK; i = (i + i); A0; } else \ - { UPDATE_1_CHECK; i = (i + i) + 1; A1; } -#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) -#define TREE_DECODE_CHECK(probs, limit, i) \ - { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } - - -#define kNumPosBitsMax 4 -#define kNumPosStatesMax (1 << kNumPosBitsMax) - -#define kLenNumLowBits 3 -#define kLenNumLowSymbols (1 << kLenNumLowBits) -#define kLenNumMidBits 3 -#define kLenNumMidSymbols (1 << kLenNumMidBits) -#define kLenNumHighBits 8 -#define kLenNumHighSymbols (1 << kLenNumHighBits) - -#define LenChoice 0 -#define LenChoice2 (LenChoice + 1) -#define LenLow (LenChoice2 + 1) -#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) -#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) -#define kNumLenProbs (LenHigh + kLenNumHighSymbols) - - -#define kNumStates 12 -#define kNumLitStates 7 - -#define kStartPosModelIndex 4 -#define kEndPosModelIndex 14 -#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) - -#define kNumPosSlotBits 6 -#define kNumLenToPosStates 4 - -#define kNumAlignBits 4 -#define kAlignTableSize (1 << kNumAlignBits) - -#define kMatchMinLen 2 -#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) - -#define IsMatch 0 -#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) -#define IsRepG0 (IsRep + kNumStates) -#define IsRepG1 (IsRepG0 + kNumStates) -#define IsRepG2 (IsRepG1 + kNumStates) -#define IsRep0Long (IsRepG2 + kNumStates) -#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) -#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) -#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) -#define LenCoder (Align + kAlignTableSize) -#define RepLenCoder (LenCoder + kNumLenProbs) -#define Literal (RepLenCoder + kNumLenProbs) - -#define LZMA_BASE_SIZE 1846 -#define LZMA_LIT_SIZE 768 - -#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) - -#if Literal != LZMA_BASE_SIZE -StopCompilingDueBUG -#endif - -static const Byte kLiteralNextStates[kNumStates * 2] = -{ - 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5, - 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10 -}; - -#define LZMA_DIC_MIN (1 << 12) - -/* First LZMA-symbol is always decoded. -And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization -Out: - Result: - SZ_OK - OK - SZ_ERROR_DATA - Error - p->remainLen: - < kMatchSpecLenStart : normal remain - = kMatchSpecLenStart : finished - = kMatchSpecLenStart + 1 : Flush marker - = kMatchSpecLenStart + 2 : State Init Marker -*/ - -static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) -{ - CLzmaProb *probs = p->probs; - - unsigned state = p->state; - UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; - unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; - unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; - unsigned lc = p->prop.lc; - - Byte *dic = p->dic; - SizeT dicBufSize = p->dicBufSize; - SizeT dicPos = p->dicPos; - - UInt32 processedPos = p->processedPos; - UInt32 checkDicSize = p->checkDicSize; - unsigned len = 0; - - const Byte *buf = p->buf; - UInt32 range = p->range; - UInt32 code = p->code; - - do - { - CLzmaProb *prob; - UInt32 bound; - unsigned ttt; - unsigned posState = processedPos & pbMask; - - prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; - IF_BIT_0(prob) - { - unsigned symbol; - UPDATE_0(prob); - prob = probs + Literal; - if (checkDicSize != 0 || processedPos != 0) - prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + - (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); - - if (state < kNumLitStates) - { - symbol = 1; - do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); - } - else - { - unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; - unsigned offs = 0x100; - symbol = 1; - do - { - unsigned bit; - CLzmaProb *probLit; - matchByte <<= 1; - bit = (matchByte & offs); - probLit = prob + offs + bit + symbol; - GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) - } - while (symbol < 0x100); - } - dic[dicPos++] = (Byte)symbol; - processedPos++; - - state = kLiteralNextStates[state]; - /* if (state < 4) state = 0; else if (state < 10) state -= 3; else state -= 6; */ - continue; - } - else - { - UPDATE_1(prob); - prob = probs + IsRep + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - state += kNumStates; - prob = probs + LenCoder; - } - else - { - UPDATE_1(prob); - if (checkDicSize == 0 && processedPos == 0) - return SZ_ERROR_DATA; - prob = probs + IsRepG0 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; - IF_BIT_0(prob) - { - UPDATE_0(prob); - dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; - dicPos++; - processedPos++; - state = state < kNumLitStates ? 9 : 11; - continue; - } - UPDATE_1(prob); - } - else - { - UInt32 distance; - UPDATE_1(prob); - prob = probs + IsRepG1 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - distance = rep1; - } - else - { - UPDATE_1(prob); - prob = probs + IsRepG2 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - distance = rep2; - } - else - { - UPDATE_1(prob); - distance = rep3; - rep3 = rep2; - } - rep2 = rep1; - } - rep1 = rep0; - rep0 = distance; - } - state = state < kNumLitStates ? 8 : 11; - prob = probs + RepLenCoder; - } - { - unsigned limit, offset; - CLzmaProb *probLen = prob + LenChoice; - IF_BIT_0(probLen) - { - UPDATE_0(probLen); - probLen = prob + LenLow + (posState << kLenNumLowBits); - offset = 0; - limit = (1 << kLenNumLowBits); - } - else - { - UPDATE_1(probLen); - probLen = prob + LenChoice2; - IF_BIT_0(probLen) - { - UPDATE_0(probLen); - probLen = prob + LenMid + (posState << kLenNumMidBits); - offset = kLenNumLowSymbols; - limit = (1 << kLenNumMidBits); - } - else - { - UPDATE_1(probLen); - probLen = prob + LenHigh; - offset = kLenNumLowSymbols + kLenNumMidSymbols; - limit = (1 << kLenNumHighBits); - } - } - TREE_DECODE(probLen, limit, len); - len += offset; - } - - if (state >= kNumStates) - { - UInt32 distance; - prob = probs + PosSlot + - ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); - TREE_6_DECODE(prob, distance); - if (distance >= kStartPosModelIndex) - { - unsigned posSlot = (unsigned)distance; - int numDirectBits = (int)(((distance >> 1) - 1)); - distance = (2 | (distance & 1)); - if (posSlot < kEndPosModelIndex) - { - distance <<= numDirectBits; - prob = probs + SpecPos + distance - posSlot - 1; - { - UInt32 mask = 1; - unsigned i = 1; - do - { - GET_BIT2(prob + i, i, ; , distance |= mask); - mask <<= 1; - } - while (--numDirectBits != 0); - } - } - else - { - numDirectBits -= kNumAlignBits; - do - { - NORMALIZE - range >>= 1; - - { - UInt32 t; - code -= range; - t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ - distance = (distance << 1) + (t + 1); - code += range & t; - } - /* - distance <<= 1; - if (code >= range) - { - code -= range; - distance |= 1; - } - */ - } - while (--numDirectBits != 0); - prob = probs + Align; - distance <<= kNumAlignBits; - { - unsigned i = 1; - GET_BIT2(prob + i, i, ; , distance |= 1); - GET_BIT2(prob + i, i, ; , distance |= 2); - GET_BIT2(prob + i, i, ; , distance |= 4); - GET_BIT2(prob + i, i, ; , distance |= 8); - } - if (distance == (UInt32)0xFFFFFFFF) - { - len += kMatchSpecLenStart; - state -= kNumStates; - break; - } - } - } - rep3 = rep2; - rep2 = rep1; - rep1 = rep0; - rep0 = distance + 1; - if (checkDicSize == 0) - { - if (distance >= processedPos) - return SZ_ERROR_DATA; - } - else if (distance >= checkDicSize) - return SZ_ERROR_DATA; - state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; - /* state = kLiteralNextStates[state]; */ - } - - len += kMatchMinLen; - - if (limit == dicPos) - return SZ_ERROR_DATA; - { - SizeT rem = limit - dicPos; - unsigned curLen = ((rem < len) ? (unsigned)rem : len); - SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); - - processedPos += curLen; - - len -= curLen; - if (pos + curLen <= dicBufSize) - { - Byte *dest = dic + dicPos; - ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; - const Byte *lim = dest + curLen; - dicPos += curLen; - do - *(dest) = (Byte)*(dest + src); - while (++dest != lim); - } - else - { - do - { - dic[dicPos++] = dic[pos]; - if (++pos == dicBufSize) - pos = 0; - } - while (--curLen != 0); - } - } - } - } - while (dicPos < limit && buf < bufLimit); - NORMALIZE; - p->buf = buf; - p->range = range; - p->code = code; - p->remainLen = len; - p->dicPos = dicPos; - p->processedPos = processedPos; - p->reps[0] = rep0; - p->reps[1] = rep1; - p->reps[2] = rep2; - p->reps[3] = rep3; - p->state = state; - - return SZ_OK; -} - -static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) -{ - if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) - { - Byte *dic = p->dic; - SizeT dicPos = p->dicPos; - SizeT dicBufSize = p->dicBufSize; - unsigned len = p->remainLen; - UInt32 rep0 = p->reps[0]; - if (limit - dicPos < len) - len = (unsigned)(limit - dicPos); - - if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) - p->checkDicSize = p->prop.dicSize; - - p->processedPos += len; - p->remainLen -= len; - while (len-- != 0) - { - dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; - dicPos++; - } - p->dicPos = dicPos; - } -} - -static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) -{ - do - { - SizeT limit2 = limit; - if (p->checkDicSize == 0) - { - UInt32 rem = p->prop.dicSize - p->processedPos; - if (limit - p->dicPos > rem) - limit2 = p->dicPos + rem; - } - RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); - if (p->processedPos >= p->prop.dicSize) - p->checkDicSize = p->prop.dicSize; - LzmaDec_WriteRem(p, limit); - } - while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); - - if (p->remainLen > kMatchSpecLenStart) - { - p->remainLen = kMatchSpecLenStart; - } - return 0; -} - -typedef enum -{ - DUMMY_ERROR, /* unexpected end of input stream */ - DUMMY_LIT, - DUMMY_MATCH, - DUMMY_REP -} ELzmaDummy; - -static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) -{ - UInt32 range = p->range; - UInt32 code = p->code; - const Byte *bufLimit = buf + inSize; - CLzmaProb *probs = p->probs; - unsigned state = p->state; - ELzmaDummy res; - - { - CLzmaProb *prob; - UInt32 bound; - unsigned ttt; - unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); - - prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK - - /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ - - prob = probs + Literal; - if (p->checkDicSize != 0 || p->processedPos != 0) - prob += (LZMA_LIT_SIZE * - ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + - (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); - - if (state < kNumLitStates) - { - unsigned symbol = 1; - do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); - } - else - { - unsigned matchByte = p->dic[p->dicPos - p->reps[0] + - ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; - unsigned offs = 0x100; - unsigned symbol = 1; - do - { - unsigned bit; - CLzmaProb *probLit; - matchByte <<= 1; - bit = (matchByte & offs); - probLit = prob + offs + bit + symbol; - GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) - } - while (symbol < 0x100); - } - res = DUMMY_LIT; - } - else - { - unsigned len; - UPDATE_1_CHECK; - - prob = probs + IsRep + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - state = 0; - prob = probs + LenCoder; - res = DUMMY_MATCH; - } - else - { - UPDATE_1_CHECK; - res = DUMMY_REP; - prob = probs + IsRepG0 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - NORMALIZE_CHECK; - return DUMMY_REP; - } - else - { - UPDATE_1_CHECK; - } - } - else - { - UPDATE_1_CHECK; - prob = probs + IsRepG1 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - } - else - { - UPDATE_1_CHECK; - prob = probs + IsRepG2 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - } - else - { - UPDATE_1_CHECK; - } - } - } - state = kNumStates; - prob = probs + RepLenCoder; - } - { - unsigned limit, offset; - CLzmaProb *probLen = prob + LenChoice; - IF_BIT_0_CHECK(probLen) - { - UPDATE_0_CHECK; - probLen = prob + LenLow + (posState << kLenNumLowBits); - offset = 0; - limit = 1 << kLenNumLowBits; - } - else - { - UPDATE_1_CHECK; - probLen = prob + LenChoice2; - IF_BIT_0_CHECK(probLen) - { - UPDATE_0_CHECK; - probLen = prob + LenMid + (posState << kLenNumMidBits); - offset = kLenNumLowSymbols; - limit = 1 << kLenNumMidBits; - } - else - { - UPDATE_1_CHECK; - probLen = prob + LenHigh; - offset = kLenNumLowSymbols + kLenNumMidSymbols; - limit = 1 << kLenNumHighBits; - } - } - TREE_DECODE_CHECK(probLen, limit, len); - len += offset; - } - - if (state < 4) - { - unsigned posSlot; - prob = probs + PosSlot + - ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << - kNumPosSlotBits); - TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); - if (posSlot >= kStartPosModelIndex) - { - int numDirectBits = ((posSlot >> 1) - 1); - - /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ - - if (posSlot < kEndPosModelIndex) - { - prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; - } - else - { - numDirectBits -= kNumAlignBits; - do - { - NORMALIZE_CHECK - range >>= 1; - code -= range & (((code - range) >> 31) - 1); - /* if (code >= range) code -= range; */ - } - while (--numDirectBits != 0); - prob = probs + Align; - numDirectBits = kNumAlignBits; - } - { - unsigned i = 1; - do - { - GET_BIT_CHECK(prob + i, i); - } - while (--numDirectBits != 0); - } - } - } - } - } - NORMALIZE_CHECK; - return res; -} - - -static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) -{ - p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); - p->range = 0xFFFFFFFF; - p->needFlush = 0; -} - -void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) -{ - p->needFlush = 1; - p->remainLen = 0; - p->tempBufSize = 0; - - if (initDic) - { - p->processedPos = 0; - p->checkDicSize = 0; - p->needInitState = 1; - } - if (initState) - p->needInitState = 1; -} - -void LzmaDec_Init(CLzmaDec *p) -{ - p->dicPos = 0; - LzmaDec_InitDicAndState(p, True, True); -} - -static void LzmaDec_InitStateReal(CLzmaDec *p) -{ - UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); - UInt32 i; - CLzmaProb *probs = p->probs; - for (i = 0; i < numProbs; i++) - probs[i] = kBitModelTotal >> 1; - p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; - p->state = 0; - p->needInitState = 0; -} - -SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, - ELzmaFinishMode finishMode, ELzmaStatus *status) -{ - SizeT inSize = *srcLen; - (*srcLen) = 0; - LzmaDec_WriteRem(p, dicLimit); - - *status = LZMA_STATUS_NOT_SPECIFIED; - - while (p->remainLen != kMatchSpecLenStart) - { - int checkEndMarkNow; - - if (p->needFlush != 0) - { - for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) - p->tempBuf[p->tempBufSize++] = *src++; - if (p->tempBufSize < RC_INIT_SIZE) - { - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - if (p->tempBuf[0] != 0) - return SZ_ERROR_DATA; - - LzmaDec_InitRc(p, p->tempBuf); - p->tempBufSize = 0; - } - - checkEndMarkNow = 0; - if (p->dicPos >= dicLimit) - { - if (p->remainLen == 0 && p->code == 0) - { - *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; - return SZ_OK; - } - if (finishMode == LZMA_FINISH_ANY) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_OK; - } - if (p->remainLen != 0) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; - } - checkEndMarkNow = 1; - } - - if (p->needInitState) - LzmaDec_InitStateReal(p); - - if (p->tempBufSize == 0) - { - SizeT processed; - const Byte *bufLimit; - if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) - { - int dummyRes = LzmaDec_TryDummy(p, src, inSize); - if (dummyRes == DUMMY_ERROR) - { - memcpy(p->tempBuf, src, inSize); - p->tempBufSize = (unsigned)inSize; - (*srcLen) += inSize; - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - if (checkEndMarkNow && dummyRes != DUMMY_MATCH) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; - } - bufLimit = src; - } - else - bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; - p->buf = src; - if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) - return SZ_ERROR_DATA; - processed = (SizeT)(p->buf - src); - (*srcLen) += processed; - src += processed; - inSize -= processed; - } - else - { - unsigned rem = p->tempBufSize, lookAhead = 0; - while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) - p->tempBuf[rem++] = src[lookAhead++]; - p->tempBufSize = rem; - if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) - { - int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); - if (dummyRes == DUMMY_ERROR) - { - (*srcLen) += lookAhead; - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - if (checkEndMarkNow && dummyRes != DUMMY_MATCH) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; - } - } - p->buf = p->tempBuf; - if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) - return SZ_ERROR_DATA; - lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); - (*srcLen) += lookAhead; - src += lookAhead; - inSize -= lookAhead; - p->tempBufSize = 0; - } - } - if (p->code == 0) - *status = LZMA_STATUS_FINISHED_WITH_MARK; - return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; -} - -SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) -{ - SizeT outSize = *destLen; - SizeT inSize = *srcLen; - *srcLen = *destLen = 0; - for (;;) - { - SizeT inSizeCur = inSize, outSizeCur, dicPos; - ELzmaFinishMode curFinishMode; - SRes res; - if (p->dicPos == p->dicBufSize) - p->dicPos = 0; - dicPos = p->dicPos; - if (outSize > p->dicBufSize - dicPos) - { - outSizeCur = p->dicBufSize; - curFinishMode = LZMA_FINISH_ANY; - } - else - { - outSizeCur = dicPos + outSize; - curFinishMode = finishMode; - } - - res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); - src += inSizeCur; - inSize -= inSizeCur; - *srcLen += inSizeCur; - outSizeCur = p->dicPos - dicPos; - memcpy(dest, p->dic + dicPos, outSizeCur); - dest += outSizeCur; - outSize -= outSizeCur; - *destLen += outSizeCur; - if (res != 0) - return res; - if (outSizeCur == 0 || outSize == 0) - return SZ_OK; - } -} - -void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) -{ - alloc->Free(alloc, p->probs); - p->probs = 0; -} - -static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) -{ - alloc->Free(alloc, p->dic); - p->dic = 0; -} - -void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) -{ - LzmaDec_FreeProbs(p, alloc); - LzmaDec_FreeDict(p, alloc); -} - -SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) -{ - UInt32 dicSize; - Byte d; - - if (size < LZMA_PROPS_SIZE) - return SZ_ERROR_UNSUPPORTED; - else - dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); - - if (dicSize < LZMA_DIC_MIN) - dicSize = LZMA_DIC_MIN; - p->dicSize = dicSize; - - d = data[0]; - if (d >= (9 * 5 * 5)) - return SZ_ERROR_UNSUPPORTED; - - p->lc = d % 9; - d /= 9; - p->pb = d / 5; - p->lp = d % 5; - - return SZ_OK; -} - -static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) -{ - UInt32 numProbs = LzmaProps_GetNumProbs(propNew); - if (p->probs == 0 || numProbs != p->numProbs) - { - LzmaDec_FreeProbs(p, alloc); - p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); - p->numProbs = numProbs; - if (p->probs == 0) - return SZ_ERROR_MEM; - } - return SZ_OK; -} - -SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) -{ - CLzmaProps propNew; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)); - RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); - p->prop = propNew; - return SZ_OK; -} - -SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) -{ - CLzmaProps propNew; - SizeT dicBufSize; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)); - RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); - dicBufSize = propNew.dicSize; - if (p->dic == 0 || dicBufSize != p->dicBufSize) - { - LzmaDec_FreeDict(p, alloc); - p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); - if (p->dic == 0) - { - LzmaDec_FreeProbs(p, alloc); - return SZ_ERROR_MEM; - } - } - p->dicBufSize = dicBufSize; - p->prop = propNew; - return SZ_OK; -} - -SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAlloc *alloc) -{ - CLzmaDec p; - SRes res; - SizeT inSize = *srcLen; - SizeT outSize = *destLen; - *srcLen = *destLen = 0; - if (inSize < RC_INIT_SIZE) - return SZ_ERROR_INPUT_EOF; - - LzmaDec_Construct(&p); - res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); - if (res != 0) - return res; - p.dic = dest; - p.dicBufSize = outSize; - - LzmaDec_Init(&p); - - *srcLen = inSize; - res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); - - if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) - res = SZ_ERROR_INPUT_EOF; - - (*destLen) = p.dicPos; - LzmaDec_FreeProbs(&p, alloc); - return res; -} +/* LzmaDec.c -- LZMA Decoder +2008-11-06 : Igor Pavlov : Public domain */ + +#include "LzmaDec.h" + +#include + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_INIT_SIZE 5 + +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p); i = (i + i); A0; } else \ + { UPDATE_1(p); i = (i + i) + 1; A1; } +#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) + +#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define _LZMA_SIZE_OPT */ + +#ifdef _LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + i -= 0x40; } +#endif + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK; i = (i + i); A0; } else \ + { UPDATE_1_CHECK; i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +static const Byte kLiteralNextStates[kNumStates * 2] = +{ + 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5, + 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10 +}; + +#define LZMA_DIC_MIN (1 << 12) + +/* First LZMA-symbol is always decoded. +And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization +Out: + Result: + SZ_OK - OK + SZ_ERROR_DATA - Error + p->remainLen: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished + = kMatchSpecLenStart + 1 : Flush marker + = kMatchSpecLenStart + 2 : State Init Marker +*/ + +static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = p->probs; + + unsigned state = p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; + unsigned lc = p->prop.lc; + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = processedPos & pbMask; + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (checkDicSize != 0 || processedPos != 0) + prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + + if (state < kNumLitStates) + { + symbol = 1; + do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned offs = 0x100; + symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + dic[dicPos++] = (Byte)symbol; + processedPos++; + + state = kLiteralNextStates[state]; + /* if (state < 4) state = 0; else if (state < 10) state -= 3; else state -= 6; */ + continue; + } + else + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = (1 << kLenNumMidBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, limit, len); + len += offset; + } + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + int numDirectBits = (int)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos + distance - posSlot - 1; + { + UInt32 mask = 1; + unsigned i = 1; + do + { + GET_BIT2(prob + i, i, ; , distance |= mask); + mask <<= 1; + } + while (--numDirectBits != 0); + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits != 0); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + GET_BIT2(prob + i, i, ; , distance |= 1); + GET_BIT2(prob + i, i, ; , distance |= 2); + GET_BIT2(prob + i, i, ; , distance |= 4); + GET_BIT2(prob + i, i, ; , distance |= 8); + } + if (distance == (UInt32)0xFFFFFFFF) + { + len += kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + if (checkDicSize == 0) + { + if (distance >= processedPos) + return SZ_ERROR_DATA; + } + else if (distance >= checkDicSize) + return SZ_ERROR_DATA; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + /* state = kLiteralNextStates[state]; */ + } + + len += kMatchMinLen; + + if (limit == dicPos) + return SZ_ERROR_DATA; + { + SizeT rem = limit - dicPos; + unsigned curLen = ((rem < len) ? (unsigned)rem : len); + SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + + processedPos += curLen; + + len -= curLen; + if (pos + curLen <= dicBufSize) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = state; + + return SZ_OK; +} + +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte *dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = p->remainLen; + UInt32 rep0 = p->reps[0]; + if (limit - dicPos < len) + len = (unsigned)(limit - dicPos); + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += len; + p->remainLen -= len; + while (len-- != 0) + { + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } +} + +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); + if (p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + if (p->remainLen > kMatchSpecLenStart) + { + p->remainLen = kMatchSpecLenStart; + } + return 0; +} + +typedef enum +{ + DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = buf + inSize; + CLzmaProb *probs = p->probs; + unsigned state = p->state; + ELzmaDummy res; + + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += (LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumMidBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits != 0); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + do + { + GET_BIT_CHECK(prob + i, i); + } + while (--numDirectBits != 0); + } + } + } + } + } + NORMALIZE_CHECK; + return res; +} + + +static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) +{ + p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +{ + p->needFlush = 1; + p->remainLen = 0; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->needInitState = 1; + } + if (initState) + p->needInitState = 1; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + +static void LzmaDec_InitStateReal(CLzmaDec *p) +{ + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); + UInt32 i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + p->needInitState = 0; +} + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + LzmaDec_WriteRem(p, dicLimit); + + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow; + + if (p->needFlush != 0) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + + LzmaDec_InitRc(p, p->tempBuf); + p->tempBufSize = 0; + } + + checkEndMarkNow = 0; + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->needInitState) + LzmaDec_InitStateReal(p); + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte *bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + (*srcLen) += lookAhead; + src += lookAhead; + inSize -= lookAhead; + p->tempBufSize = 0; + } + } + if (p->code == 0) + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; +} + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->probs); + p->probs = 0; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->dic); + p->dic = 0; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = d % 9; + d /= 9; + p->pb = d / 5; + p->lp = d % 5; + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (p->probs == 0 || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); + p->numProbs = numProbs; + if (p->probs == 0) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + dicBufSize = propNew.dicSize; + if (p->dic == 0 || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); + if (p->dic == 0) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc) +{ + CLzmaDec p; + SRes res; + SizeT inSize = *srcLen; + SizeT outSize = *destLen; + *srcLen = *destLen = 0; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + + LzmaDec_Construct(&p); + res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); + if (res != 0) + return res; + p.dic = dest; + p.dicBufSize = outSize; + + LzmaDec_Init(&p); + + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + + (*destLen) = p.dicPos; + LzmaDec_FreeProbs(&p, alloc); + return res; +} diff --git a/src/lzma/LzmaDec.h b/src/lzma/LzmaDec.h index ad7d7057..98cdbe94 100644 --- a/src/lzma/LzmaDec.h +++ b/src/lzma/LzmaDec.h @@ -1,223 +1,223 @@ -/* LzmaDec.h -- LZMA Decoder -2008-10-04 : Igor Pavlov : Public domain */ - -#ifndef __LZMADEC_H -#define __LZMADEC_H - -#include "Types.h" - -/* #define _LZMA_PROB32 */ -/* _LZMA_PROB32 can increase the speed on some CPUs, - but memory usage for CLzmaDec::probs will be doubled in that case */ - -#ifdef _LZMA_PROB32 -#define CLzmaProb UInt32 -#else -#define CLzmaProb UInt16 -#endif - - -/* ---------- LZMA Properties ---------- */ - -#define LZMA_PROPS_SIZE 5 - -typedef struct _CLzmaProps -{ - unsigned lc, lp, pb; - UInt32 dicSize; -} CLzmaProps; - -/* LzmaProps_Decode - decodes properties -Returns: - SZ_OK - SZ_ERROR_UNSUPPORTED - Unsupported properties -*/ - -SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); - - -/* ---------- LZMA Decoder state ---------- */ - -/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. - Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ - -#define LZMA_REQUIRED_INPUT_MAX 20 - -typedef struct -{ - CLzmaProps prop; - CLzmaProb *probs; - Byte *dic; - const Byte *buf; - UInt32 range, code; - SizeT dicPos; - SizeT dicBufSize; - UInt32 processedPos; - UInt32 checkDicSize; - unsigned state; - UInt32 reps[4]; - unsigned remainLen; - int needFlush; - int needInitState; - UInt32 numProbs; - unsigned tempBufSize; - Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; -} CLzmaDec; - -#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } - -void LzmaDec_Init(CLzmaDec *p); - -/* There are two types of LZMA streams: - 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. - 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ - -typedef enum -{ - LZMA_FINISH_ANY, /* finish at any point */ - LZMA_FINISH_END /* block must be finished at the end */ -} ELzmaFinishMode; - -/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! - - You must use LZMA_FINISH_END, when you know that current output buffer - covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. - - If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, - and output value of destLen will be less than output buffer size limit. - You can check status result also. - - You can use multiple checks to test data integrity after full decompression: - 1) Check Result and "status" variable. - 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. - 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. - You must use correct finish mode in that case. */ - -typedef enum -{ - LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ - LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ - LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ - LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ -} ELzmaStatus; - -/* ELzmaStatus is used only as output value for function call */ - - -/* ---------- Interfaces ---------- */ - -/* There are 3 levels of interfaces: - 1) Dictionary Interface - 2) Buffer Interface - 3) One Call Interface - You can select any of these interfaces, but don't mix functions from different - groups for same object. */ - - -/* There are two variants to allocate state for Dictionary Interface: - 1) LzmaDec_Allocate / LzmaDec_Free - 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs - You can use variant 2, if you set dictionary buffer manually. - For Buffer Interface you must always use variant 1. - -LzmaDec_Allocate* can return: - SZ_OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties -*/ - -SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); -void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); - -SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); -void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); - -/* ---------- Dictionary Interface ---------- */ - -/* You can use it, if you want to eliminate the overhead for data copying from - dictionary to some other external buffer. - You must work with CLzmaDec variables directly in this interface. - - STEPS: - LzmaDec_Constr() - LzmaDec_Allocate() - for (each new stream) - { - LzmaDec_Init() - while (it needs more decompression) - { - LzmaDec_DecodeToDic() - use data from CLzmaDec::dic and update CLzmaDec::dicPos - } - } - LzmaDec_Free() -*/ - -/* LzmaDec_DecodeToDic - - The decoding to internal dictionary buffer (CLzmaDec::dic). - You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! - -finishMode: - It has meaning only if the decoding reaches output limit (dicLimit). - LZMA_FINISH_ANY - Decode just dicLimit bytes. - LZMA_FINISH_END - Stream must be finished after dicLimit. - -Returns: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_NEEDS_MORE_INPUT - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - SZ_ERROR_DATA - Data error -*/ - -SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); - - -/* ---------- Buffer Interface ---------- */ - -/* It's zlib-like interface. - See LzmaDec_DecodeToDic description for information about STEPS and return results, - but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need - to work with CLzmaDec variables manually. - -finishMode: - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - Decode just destLen bytes. - LZMA_FINISH_END - Stream must be finished after (*destLen). -*/ - -SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); - - -/* ---------- One Call Interface ---------- */ - -/* LzmaDecode - -finishMode: - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - Decode just destLen bytes. - LZMA_FINISH_END - Stream must be finished after (*destLen). - -Returns: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - SZ_ERROR_DATA - Data error - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties - SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). -*/ - -SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAlloc *alloc); - -#endif +/* LzmaDec.h -- LZMA Decoder +2008-10-04 : Igor Pavlov : Public domain */ + +#ifndef __LZMADEC_H +#define __LZMADEC_H + +#include "Types.h" + +/* #define _LZMA_PROB32 */ +/* _LZMA_PROB32 can increase the speed on some CPUs, + but memory usage for CLzmaDec::probs will be doubled in that case */ + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaProps +{ + unsigned lc, lp, pb; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); + + +/* ---------- LZMA Decoder state ---------- */ + +/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. + Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ + +#define LZMA_REQUIRED_INPUT_MAX 20 + +typedef struct +{ + CLzmaProps prop; + CLzmaProb *probs; + Byte *dic; + const Byte *buf; + UInt32 range, code; + SizeT dicPos; + SizeT dicBufSize; + UInt32 processedPos; + UInt32 checkDicSize; + unsigned state; + UInt32 reps[4]; + unsigned remainLen; + int needFlush; + int needInitState; + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; +} CLzmaDec; + +#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +void LzmaDec_Init(CLzmaDec *p); + +/* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ + +typedef enum +{ + LZMA_FINISH_ANY, /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ +} ELzmaFinishMode; + +/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! + + You must use LZMA_FINISH_END, when you know that current output buffer + covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. + + If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, + and output value of destLen will be less than output buffer size limit. + You can check status result also. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + +typedef enum +{ + LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ +} ELzmaStatus; + +/* ELzmaStatus is used only as output value for function call */ + + +/* ---------- Interfaces ---------- */ + +/* There are 3 levels of interfaces: + 1) Dictionary Interface + 2) Buffer Interface + 3) One Call Interface + You can select any of these interfaces, but don't mix functions from different + groups for same object. */ + + +/* There are two variants to allocate state for Dictionary Interface: + 1) LzmaDec_Allocate / LzmaDec_Free + 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs + You can use variant 2, if you set dictionary buffer manually. + For Buffer Interface you must always use variant 1. + +LzmaDec_Allocate* can return: + SZ_OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); + +SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); + +/* ---------- Dictionary Interface ---------- */ + +/* You can use it, if you want to eliminate the overhead for data copying from + dictionary to some other external buffer. + You must work with CLzmaDec variables directly in this interface. + + STEPS: + LzmaDec_Constr() + LzmaDec_Allocate() + for (each new stream) + { + LzmaDec_Init() + while (it needs more decompression) + { + LzmaDec_DecodeToDic() + use data from CLzmaDec::dic and update CLzmaDec::dicPos + } + } + LzmaDec_Free() +*/ + +/* LzmaDec_DecodeToDic + + The decoding to internal dictionary buffer (CLzmaDec::dic). + You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! + +finishMode: + It has meaning only if the decoding reaches output limit (dicLimit). + LZMA_FINISH_ANY - Decode just dicLimit bytes. + LZMA_FINISH_END - Stream must be finished after dicLimit. + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error +*/ + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- Buffer Interface ---------- */ + +/* It's zlib-like interface. + See LzmaDec_DecodeToDic description for information about STEPS and return results, + but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need + to work with CLzmaDec variables manually. + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). +*/ + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + +#endif diff --git a/src/lzma/Types.h b/src/lzma/Types.h index 2638196a..1af5cfc4 100644 --- a/src/lzma/Types.h +++ b/src/lzma/Types.h @@ -1,208 +1,208 @@ -/* Types.h -- Basic types -2008-11-23 : Igor Pavlov : Public domain */ - -#ifndef __7Z_TYPES_H -#define __7Z_TYPES_H - -#include - -#ifdef _WIN32 -#include -#endif - -#define SZ_OK 0 - -#define SZ_ERROR_DATA 1 -#define SZ_ERROR_MEM 2 -#define SZ_ERROR_CRC 3 -#define SZ_ERROR_UNSUPPORTED 4 -#define SZ_ERROR_PARAM 5 -#define SZ_ERROR_INPUT_EOF 6 -#define SZ_ERROR_OUTPUT_EOF 7 -#define SZ_ERROR_READ 8 -#define SZ_ERROR_WRITE 9 -#define SZ_ERROR_PROGRESS 10 -#define SZ_ERROR_FAIL 11 -#define SZ_ERROR_THREAD 12 - -#define SZ_ERROR_ARCHIVE 16 -#define SZ_ERROR_NO_ARCHIVE 17 - -typedef int SRes; - -#ifdef _WIN32 -typedef DWORD WRes; -#else -typedef int WRes; -#endif - -#ifndef RINOK -#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } -#endif - -typedef unsigned char Byte; -typedef short Int16; -typedef unsigned short UInt16; - -#ifdef _LZMA_UINT32_IS_ULONG -typedef long Int32; -typedef unsigned long UInt32; -#else -typedef int Int32; -typedef unsigned int UInt32; -#endif - -#ifdef _SZ_NO_INT_64 - -/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. - NOTES: Some code will work incorrectly in that case! */ - -typedef long Int64; -typedef unsigned long UInt64; - -#else - -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef __int64 Int64; -typedef unsigned __int64 UInt64; -#else -typedef long long int Int64; -typedef unsigned long long int UInt64; -#endif - -#endif - -#ifdef _LZMA_NO_SYSTEM_SIZE_T -typedef UInt32 SizeT; -#else -typedef size_t SizeT; -#endif - -typedef int Bool; -#define True 1 -#define False 0 - - -#ifdef _MSC_VER - -#if _MSC_VER >= 1300 -#define MY_NO_INLINE __declspec(noinline) -#else -#define MY_NO_INLINE -#endif - -#define MY_CDECL __cdecl -#define MY_STD_CALL __stdcall -#define MY_FAST_CALL MY_NO_INLINE __fastcall - -#else - -#define MY_CDECL -#define MY_STD_CALL -#define MY_FAST_CALL - -#endif - - -/* The following interfaces use first parameter as pointer to structure */ - -typedef struct -{ - SRes (*Read)(void *p, void *buf, size_t *size); - /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. - (output(*size) < input(*size)) is allowed */ -} ISeqInStream; - -/* it can return SZ_ERROR_INPUT_EOF */ -SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); -SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); -SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); - -typedef struct -{ - size_t (*Write)(void *p, const void *buf, size_t size); - /* Returns: result - the number of actually written bytes. - (result < size) means error */ -} ISeqOutStream; - -typedef enum -{ - SZ_SEEK_SET = 0, - SZ_SEEK_CUR = 1, - SZ_SEEK_END = 2 -} ESzSeek; - -typedef struct -{ - SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ - SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); -} ISeekInStream; - -typedef struct -{ - SRes (*Look)(void *p, void **buf, size_t *size); - /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. - (output(*size) > input(*size)) is not allowed - (output(*size) < input(*size)) is allowed */ - SRes (*Skip)(void *p, size_t offset); - /* offset must be <= output(*size) of Look */ - - SRes (*Read)(void *p, void *buf, size_t *size); - /* reads directly (without buffer). It's same as ISeqInStream::Read */ - SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); -} ILookInStream; - -SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); -SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); - -/* reads via ILookInStream::Read */ -SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); -SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); - -#define LookToRead_BUF_SIZE (1 << 14) - -typedef struct -{ - ILookInStream s; - ISeekInStream *realStream; - size_t pos; - size_t size; - Byte buf[LookToRead_BUF_SIZE]; -} CLookToRead; - -void LookToRead_CreateVTable(CLookToRead *p, int lookahead); -void LookToRead_Init(CLookToRead *p); - -typedef struct -{ - ISeqInStream s; - ILookInStream *realStream; -} CSecToLook; - -void SecToLook_CreateVTable(CSecToLook *p); - -typedef struct -{ - ISeqInStream s; - ILookInStream *realStream; -} CSecToRead; - -void SecToRead_CreateVTable(CSecToRead *p); - -typedef struct -{ - SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); - /* Returns: result. (result != SZ_OK) means break. - Value (UInt64)(Int64)-1 for size means unknown value. */ -} ICompressProgress; - -typedef struct -{ - void *(*Alloc)(void *p, size_t size); - void (*Free)(void *p, void *address); /* address can be 0 */ -} ISzAlloc; - -#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) -#define IAlloc_Free(p, a) (p)->Free((p), a) - -#endif +/* Types.h -- Basic types +2008-11-23 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#include + +#ifdef _WIN32 +#include +#endif + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + +#ifdef _WIN32 +typedef DWORD WRes; +#else +typedef int WRes; +#endif + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int Bool; +#define True 1 +#define False 0 + + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define MY_NO_INLINE __declspec(noinline) +#else +#define MY_NO_INLINE +#endif + +#define MY_CDECL __cdecl +#define MY_STD_CALL __stdcall +#define MY_FAST_CALL MY_NO_INLINE __fastcall + +#else + +#define MY_CDECL +#define MY_STD_CALL +#define MY_FAST_CALL + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +} ISeqInStream; + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); + +typedef struct +{ + size_t (*Write)(void *p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +} ISeqOutStream; + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ISeekInStream; + +typedef struct +{ + SRes (*Look)(void *p, void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(void *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(void *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ILookInStream; + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); + +#define LookToRead_BUF_SIZE (1 << 14) + +typedef struct +{ + ILookInStream s; + ISeekInStream *realStream; + size_t pos; + size_t size; + Byte buf[LookToRead_BUF_SIZE]; +} CLookToRead; + +void LookToRead_CreateVTable(CLookToRead *p, int lookahead); +void LookToRead_Init(CLookToRead *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + +typedef struct +{ + SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +} ICompressProgress; + +typedef struct +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ +} ISzAlloc; + +#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) +#define IAlloc_Free(p, a) (p)->Free((p), a) + +#endif diff --git a/src/stub.c b/src/stub.c index 5aaed77a..2c61edbc 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1,384 +1,384 @@ -/* - Single Executable Bundle Stub - - This stub reads itself for embedded instructions to create directory - and files in a temporary directory, launching a program. -*/ - -#include -#include -#include - -const BYTE Signature[] = { 0x41, 0xb6, 0xba, 0x4e }; - -#define OP_END 0 -#define OP_CREATE_DIRECTORY 1 -#define OP_CREATE_FILE 2 -#define OP_CREATE_PROCESS 3 -#define OP_DECOMPRESS_LZMA 4 -#define OP_MAX 5 - -void ProcessImage(LPVOID p, DWORD size); -void ProcessOpcodes(LPVOID* p); - -BOOL OpEnd(LPVOID *p); -BOOL OpCreateFile(LPVOID *p); -BOOL OpCreateDirectory(LPVOID *p); -BOOL OpCreateProcess(LPVOID *p); -BOOL OpDecompressLzma(LPVOID *p); -#include - -typedef BOOL (*POpcodeHandler)(LPVOID*); - -DWORD ExitStatus = 0; - -POpcodeHandler OpcodeHandlers[OP_MAX] = { - &OpEnd, - &OpCreateDirectory, - &OpCreateFile, - &OpCreateProcess, - &OpDecompressLzma -}; - -CHAR InstDir[MAX_PATH]; - -/** Decoder: Zero-terminated string */ -LPTSTR GetString(LPVOID* p) -{ - LPTSTR str = *p; - *p += strlen(str) + 1; - return str; -} - -/** Decoder: 32 bit unsigned integer */ -DWORD GetInteger(LPVOID* p) -{ - DWORD dw = *(DWORD*)*p; - *p += 4; - return dw; -} - -int main(int argc, char** argv) -{ - CHAR TempPath[MAX_PATH]; - GetTempPath(MAX_PATH, TempPath); - GetTempFileName(TempPath, "seb", 0, InstDir); -#ifdef _DEBUG - printf("Temporary directory: %s\n", InstDir); -#endif - - /* Attempt to delete the temp file created by GetTempFileName. - Ignore errors, i.e. if it doesn't exist. */ - (void)DeleteFile(InstDir); - - /* Create the temporary directory that will hold the extracted files */ - if (!CreateDirectory(InstDir, NULL)){ - printf("Failed to create temporary directory.\n"); - return -1; - } - - /* Find name of image */ - TCHAR ImageFileName[MAX_PATH]; - if (!GetModuleFileName(NULL, ImageFileName, MAX_PATH)) { - fprintf(stderr, "Failed to get executable name (error %lu).\n", GetLastError()); - return -1; - } - - /* Open the image (executable) */ - HANDLE hImage = CreateFile(ImageFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if (hImage == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed to open executable (%s)\n", ImageFileName); - return -1; - } - - /* Create a file mapping */ - DWORD FileSize = GetFileSize(hImage, NULL); - HANDLE hMem = CreateFileMapping(hImage, NULL, PAGE_READONLY, 0, FileSize, NULL); - if (hMem == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed to create file mapping (error %lu)\n", GetLastError()); - CloseHandle(hImage); - return -1; - } - - /* Map the image into memory */ - LPVOID lpv = MapViewOfFile(hMem, FILE_MAP_READ, 0, 0, 0); - if (lpv == NULL) - { - fprintf(stderr, "Failed to map view of executable into memory (error %lu).\n", GetLastError()); - } - else - { - ProcessImage(lpv, FileSize); - if (!UnmapViewOfFile(lpv)) - fprintf(stderr, "Failed to unmap view of executable.\n"); - } - - if (!CloseHandle(hMem)) - fprintf(stderr, "Failed to close file mapping.\n"); - - if (!CloseHandle(hImage)) - fprintf(stderr, "Failed to close executable.\n"); - - /* Remove the temporary directory */ - SHFILEOPSTRUCT shop; - shop.hwnd = NULL; - shop.wFunc = FO_DELETE; - InstDir[strlen(InstDir)+1] = 0; - shop.pFrom = InstDir; - shop.pTo = NULL; - shop.fFlags = FOF_NOCONFIRMATION; - SHFileOperation(&shop); - - ExitProcess(ExitStatus); - - /* Never gets here */ - return 0; -} - -/** - Process the image by checking the signature and locating the first - opcode. -*/ -void ProcessImage(LPVOID ptr, DWORD size) -{ - LPVOID pSig = ptr + size - 4; - if (memcmp(pSig, Signature, 4) == 0) - { -#ifdef _DEBUG - printf("Good signature found.\n"); -#endif - DWORD OpcodeOffset = *(DWORD*)(pSig - 4); - LPVOID pSeg = ptr + OpcodeOffset; - ProcessOpcodes(&pSeg); - } - else - { - fprintf(stderr, "Bad signature in SEB.\n"); - } -} - -/** - Process the opcodes in memory. -*/ -void ProcessOpcodes(LPVOID* p) -{ - BOOL Stop = FALSE; - while(!Stop) - { - DWORD opcode = GetInteger(p); - if (opcode >= OP_MAX || !OpcodeHandlers[opcode](p)) - break; - } -} - -/** - Expands a specially formatted string, replacing \xFF with the - temporary installation directory. -*/ -void ExpandPath(LPTSTR out, LPTSTR str) -{ - char* a; - while ((a = strchr(str, '\xFF'))) - { - int l = a - str; - if (l > 0) { - memcpy(out, str, l); - out += l; - str += l; - } - str += 1; - strcpy(out, InstDir); - out += strlen(out); - } - strcpy(out, str); -} - -/** - Finds the start of the first argument after the current one. Handles quoted arguments. -*/ -LPTSTR SkipArg(LPTSTR str) -{ - if (*str == '"') { - str++; - while (*str && *str != '"') str++; - if (*str == '"') str++; - } else { - while (*str && *str != ' ') str++; - } - while (*str && *str != ' ') str++; - return str; -} - -/** - Create a file (OP_CREATE_FILE opcode handler) -*/ -BOOL OpCreateFile(LPVOID *p) -{ - BOOL Result = TRUE; - LPTSTR FileName = GetString(p); - DWORD FileSize = GetInteger(p); - LPVOID Data = *p; - *p += FileSize; - - CHAR Fn[MAX_PATH]; - strcpy(Fn, InstDir); - strcat(Fn, "\\"); - strcat(Fn, FileName); - -#ifdef _DEBUG - printf("CreateFile(%s, %lu)\n", Fn, FileSize); -#endif - HANDLE hFile = CreateFile(Fn, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - if (hFile != INVALID_HANDLE_VALUE) - { - DWORD BytesWritten; - if (!WriteFile(hFile, Data, FileSize, &BytesWritten, NULL)) - { - printf("Write failure\n"); - Result = FALSE; - } - if (BytesWritten != FileSize) - { - fprintf(stderr, "Write size failure\n"); - Result = FALSE; - } - CloseHandle(hFile); - } - else - { - fprintf(stderr, "Failed to create file '%s'\n", Fn); - Result = FALSE; - } - - return Result; -} - -/** - Create a directory (OP_CREATE_DIRECTORY opcode handler) -*/ -BOOL OpCreateDirectory(LPVOID *p) -{ - LPTSTR DirectoryName = GetString(p); - - CHAR DirName[MAX_PATH]; - strcpy(DirName, InstDir); - strcat(DirName, "\\"); - strcat(DirName, DirectoryName); - -#ifdef _DEBUG - printf("CreateDirectory(%s)\n", DirName); -#endif - - if (!CreateDirectory(DirName, NULL)){ - printf("Failed to create directory.\n"); - return FALSE; - } - - return TRUE; -} - -/** - Create a new process and wait for it to complete (OP_CREATE_PROCESS - opcode handler) -*/ -BOOL OpCreateProcess(LPVOID *p) -{ - LPTSTR ImageName = GetString(p); - LPTSTR CmdLine = GetString(p); - - STARTUPINFO StartupInfo; - ZeroMemory(&StartupInfo, sizeof(StartupInfo)); - StartupInfo.cb = sizeof(StartupInfo); - - CHAR ApplicationName[MAX_PATH]; - strcpy(ApplicationName, InstDir); - strcat(ApplicationName, "\\"); - strcat(ApplicationName, ImageName); - - CHAR CmdLine2[MAX_PATH]; - ExpandPath(CmdLine2, CmdLine); - - LPTSTR MyCmdLine = GetCommandLine(); - LPTSTR MyArgs = SkipArg(MyCmdLine); - - LPTSTR CmdLine3 = LocalAlloc(LMEM_FIXED, strlen(CmdLine2) + 1 + strlen(MyArgs) + 1); - strcpy(CmdLine3, CmdLine2); - strcat(CmdLine3, " "); - strcat(CmdLine3, MyArgs); - -#ifdef _DEBUG - printf("CreateProcess(%s, %s)\n", ApplicationName, CmdLine2); -#endif - - PROCESS_INFORMATION ProcessInformation; - BOOL r = CreateProcess(ApplicationName, CmdLine3, NULL, NULL, - TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInformation); - - LocalFree(CmdLine3); - - if (!r) - { - printf("Failed to createprocess %lu\n", GetLastError()); - } - - WaitForSingleObject(ProcessInformation.hProcess, INFINITE); - - if (!GetExitCodeProcess(ProcessInformation.hProcess, &ExitStatus)) - fprintf(stderr, "Failed to get exit status (error %lu).\n", GetLastError()); - - CloseHandle(ProcessInformation.hProcess); - CloseHandle(ProcessInformation.hThread); - - return TRUE; -} - -void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } -void SzFree(void *p, void *address) { p = p; free(address); } -ISzAlloc alloc = { SzAlloc, SzFree }; - -#if WITH_LZMA - -#define LZMA_UNPACKSIZE_SIZE 8 -#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + LZMA_UNPACKSIZE_SIZE) - -BOOL OpDecompressLzma(LPVOID *p) -{ - DWORD CompressedSize = GetInteger(p); -#ifdef _DEBUG - printf("LzmaDecode(%ld)\n", CompressedSize); -#endif - - Byte* src = (Byte*)*p; - *p += CompressedSize; - - UInt64 unpackSize = 0; - int i; - for (i = 0; i < 8; i++) - unpackSize += (UInt64)src[LZMA_PROPS_SIZE + i] << (i * 8); - - Byte* DecompressedData = LocalAlloc(LMEM_FIXED, unpackSize); - - SizeT lzmaDecompressedSize = unpackSize; - SizeT inSizePure = CompressedSize - LZMA_HEADER_SIZE; - ELzmaStatus status; - SRes res = LzmaDecode(DecompressedData, &lzmaDecompressedSize, src + LZMA_HEADER_SIZE, &inSizePure, - src, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &alloc); - if (res != SZ_OK) - { - fprintf(stderr, "LZMA decompression failed.\n"); - } - else - { - LPVOID decPtr = DecompressedData; - ProcessOpcodes(&decPtr); - } - - LocalFree(DecompressedData); - return TRUE; -} -#endif - -BOOL OpEnd(LPVOID* p) -{ - return FALSE; -} +/* + Single Executable Bundle Stub + + This stub reads itself for embedded instructions to create directory + and files in a temporary directory, launching a program. +*/ + +#include +#include +#include + +const BYTE Signature[] = { 0x41, 0xb6, 0xba, 0x4e }; + +#define OP_END 0 +#define OP_CREATE_DIRECTORY 1 +#define OP_CREATE_FILE 2 +#define OP_CREATE_PROCESS 3 +#define OP_DECOMPRESS_LZMA 4 +#define OP_MAX 5 + +void ProcessImage(LPVOID p, DWORD size); +void ProcessOpcodes(LPVOID* p); + +BOOL OpEnd(LPVOID *p); +BOOL OpCreateFile(LPVOID *p); +BOOL OpCreateDirectory(LPVOID *p); +BOOL OpCreateProcess(LPVOID *p); +BOOL OpDecompressLzma(LPVOID *p); +#include + +typedef BOOL (*POpcodeHandler)(LPVOID*); + +DWORD ExitStatus = 0; + +POpcodeHandler OpcodeHandlers[OP_MAX] = { + &OpEnd, + &OpCreateDirectory, + &OpCreateFile, + &OpCreateProcess, + &OpDecompressLzma +}; + +CHAR InstDir[MAX_PATH]; + +/** Decoder: Zero-terminated string */ +LPTSTR GetString(LPVOID* p) +{ + LPTSTR str = *p; + *p += strlen(str) + 1; + return str; +} + +/** Decoder: 32 bit unsigned integer */ +DWORD GetInteger(LPVOID* p) +{ + DWORD dw = *(DWORD*)*p; + *p += 4; + return dw; +} + +int main(int argc, char** argv) +{ + CHAR TempPath[MAX_PATH]; + GetTempPath(MAX_PATH, TempPath); + GetTempFileName(TempPath, "seb", 0, InstDir); +#ifdef _DEBUG + printf("Temporary directory: %s\n", InstDir); +#endif + + /* Attempt to delete the temp file created by GetTempFileName. + Ignore errors, i.e. if it doesn't exist. */ + (void)DeleteFile(InstDir); + + /* Create the temporary directory that will hold the extracted files */ + if (!CreateDirectory(InstDir, NULL)){ + printf("Failed to create temporary directory.\n"); + return -1; + } + + /* Find name of image */ + TCHAR ImageFileName[MAX_PATH]; + if (!GetModuleFileName(NULL, ImageFileName, MAX_PATH)) { + fprintf(stderr, "Failed to get executable name (error %lu).\n", GetLastError()); + return -1; + } + + /* Open the image (executable) */ + HANDLE hImage = CreateFile(ImageFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (hImage == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed to open executable (%s)\n", ImageFileName); + return -1; + } + + /* Create a file mapping */ + DWORD FileSize = GetFileSize(hImage, NULL); + HANDLE hMem = CreateFileMapping(hImage, NULL, PAGE_READONLY, 0, FileSize, NULL); + if (hMem == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed to create file mapping (error %lu)\n", GetLastError()); + CloseHandle(hImage); + return -1; + } + + /* Map the image into memory */ + LPVOID lpv = MapViewOfFile(hMem, FILE_MAP_READ, 0, 0, 0); + if (lpv == NULL) + { + fprintf(stderr, "Failed to map view of executable into memory (error %lu).\n", GetLastError()); + } + else + { + ProcessImage(lpv, FileSize); + if (!UnmapViewOfFile(lpv)) + fprintf(stderr, "Failed to unmap view of executable.\n"); + } + + if (!CloseHandle(hMem)) + fprintf(stderr, "Failed to close file mapping.\n"); + + if (!CloseHandle(hImage)) + fprintf(stderr, "Failed to close executable.\n"); + + /* Remove the temporary directory */ + SHFILEOPSTRUCT shop; + shop.hwnd = NULL; + shop.wFunc = FO_DELETE; + InstDir[strlen(InstDir)+1] = 0; + shop.pFrom = InstDir; + shop.pTo = NULL; + shop.fFlags = FOF_NOCONFIRMATION; + SHFileOperation(&shop); + + ExitProcess(ExitStatus); + + /* Never gets here */ + return 0; +} + +/** + Process the image by checking the signature and locating the first + opcode. +*/ +void ProcessImage(LPVOID ptr, DWORD size) +{ + LPVOID pSig = ptr + size - 4; + if (memcmp(pSig, Signature, 4) == 0) + { +#ifdef _DEBUG + printf("Good signature found.\n"); +#endif + DWORD OpcodeOffset = *(DWORD*)(pSig - 4); + LPVOID pSeg = ptr + OpcodeOffset; + ProcessOpcodes(&pSeg); + } + else + { + fprintf(stderr, "Bad signature in SEB.\n"); + } +} + +/** + Process the opcodes in memory. +*/ +void ProcessOpcodes(LPVOID* p) +{ + BOOL Stop = FALSE; + while(!Stop) + { + DWORD opcode = GetInteger(p); + if (opcode >= OP_MAX || !OpcodeHandlers[opcode](p)) + break; + } +} + +/** + Expands a specially formatted string, replacing \xFF with the + temporary installation directory. +*/ +void ExpandPath(LPTSTR out, LPTSTR str) +{ + char* a; + while ((a = strchr(str, '\xFF'))) + { + int l = a - str; + if (l > 0) { + memcpy(out, str, l); + out += l; + str += l; + } + str += 1; + strcpy(out, InstDir); + out += strlen(out); + } + strcpy(out, str); +} + +/** + Finds the start of the first argument after the current one. Handles quoted arguments. +*/ +LPTSTR SkipArg(LPTSTR str) +{ + if (*str == '"') { + str++; + while (*str && *str != '"') str++; + if (*str == '"') str++; + } else { + while (*str && *str != ' ') str++; + } + while (*str && *str != ' ') str++; + return str; +} + +/** + Create a file (OP_CREATE_FILE opcode handler) +*/ +BOOL OpCreateFile(LPVOID *p) +{ + BOOL Result = TRUE; + LPTSTR FileName = GetString(p); + DWORD FileSize = GetInteger(p); + LPVOID Data = *p; + *p += FileSize; + + CHAR Fn[MAX_PATH]; + strcpy(Fn, InstDir); + strcat(Fn, "\\"); + strcat(Fn, FileName); + +#ifdef _DEBUG + printf("CreateFile(%s, %lu)\n", Fn, FileSize); +#endif + HANDLE hFile = CreateFile(Fn, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD BytesWritten; + if (!WriteFile(hFile, Data, FileSize, &BytesWritten, NULL)) + { + printf("Write failure\n"); + Result = FALSE; + } + if (BytesWritten != FileSize) + { + fprintf(stderr, "Write size failure\n"); + Result = FALSE; + } + CloseHandle(hFile); + } + else + { + fprintf(stderr, "Failed to create file '%s'\n", Fn); + Result = FALSE; + } + + return Result; +} + +/** + Create a directory (OP_CREATE_DIRECTORY opcode handler) +*/ +BOOL OpCreateDirectory(LPVOID *p) +{ + LPTSTR DirectoryName = GetString(p); + + CHAR DirName[MAX_PATH]; + strcpy(DirName, InstDir); + strcat(DirName, "\\"); + strcat(DirName, DirectoryName); + +#ifdef _DEBUG + printf("CreateDirectory(%s)\n", DirName); +#endif + + if (!CreateDirectory(DirName, NULL)){ + printf("Failed to create directory.\n"); + return FALSE; + } + + return TRUE; +} + +/** + Create a new process and wait for it to complete (OP_CREATE_PROCESS + opcode handler) +*/ +BOOL OpCreateProcess(LPVOID *p) +{ + LPTSTR ImageName = GetString(p); + LPTSTR CmdLine = GetString(p); + + STARTUPINFO StartupInfo; + ZeroMemory(&StartupInfo, sizeof(StartupInfo)); + StartupInfo.cb = sizeof(StartupInfo); + + CHAR ApplicationName[MAX_PATH]; + strcpy(ApplicationName, InstDir); + strcat(ApplicationName, "\\"); + strcat(ApplicationName, ImageName); + + CHAR CmdLine2[MAX_PATH]; + ExpandPath(CmdLine2, CmdLine); + + LPTSTR MyCmdLine = GetCommandLine(); + LPTSTR MyArgs = SkipArg(MyCmdLine); + + LPTSTR CmdLine3 = LocalAlloc(LMEM_FIXED, strlen(CmdLine2) + 1 + strlen(MyArgs) + 1); + strcpy(CmdLine3, CmdLine2); + strcat(CmdLine3, " "); + strcat(CmdLine3, MyArgs); + +#ifdef _DEBUG + printf("CreateProcess(%s, %s)\n", ApplicationName, CmdLine2); +#endif + + PROCESS_INFORMATION ProcessInformation; + BOOL r = CreateProcess(ApplicationName, CmdLine3, NULL, NULL, + TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInformation); + + LocalFree(CmdLine3); + + if (!r) + { + printf("Failed to createprocess %lu\n", GetLastError()); + } + + WaitForSingleObject(ProcessInformation.hProcess, INFINITE); + + if (!GetExitCodeProcess(ProcessInformation.hProcess, &ExitStatus)) + fprintf(stderr, "Failed to get exit status (error %lu).\n", GetLastError()); + + CloseHandle(ProcessInformation.hProcess); + CloseHandle(ProcessInformation.hThread); + + return TRUE; +} + +void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } +void SzFree(void *p, void *address) { p = p; free(address); } +ISzAlloc alloc = { SzAlloc, SzFree }; + +#if WITH_LZMA + +#define LZMA_UNPACKSIZE_SIZE 8 +#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + LZMA_UNPACKSIZE_SIZE) + +BOOL OpDecompressLzma(LPVOID *p) +{ + DWORD CompressedSize = GetInteger(p); +#ifdef _DEBUG + printf("LzmaDecode(%ld)\n", CompressedSize); +#endif + + Byte* src = (Byte*)*p; + *p += CompressedSize; + + UInt64 unpackSize = 0; + int i; + for (i = 0; i < 8; i++) + unpackSize += (UInt64)src[LZMA_PROPS_SIZE + i] << (i * 8); + + Byte* DecompressedData = LocalAlloc(LMEM_FIXED, unpackSize); + + SizeT lzmaDecompressedSize = unpackSize; + SizeT inSizePure = CompressedSize - LZMA_HEADER_SIZE; + ELzmaStatus status; + SRes res = LzmaDecode(DecompressedData, &lzmaDecompressedSize, src + LZMA_HEADER_SIZE, &inSizePure, + src, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &alloc); + if (res != SZ_OK) + { + fprintf(stderr, "LZMA decompression failed.\n"); + } + else + { + LPVOID decPtr = DecompressedData; + ProcessOpcodes(&decPtr); + } + + LocalFree(DecompressedData); + return TRUE; +} +#endif + +BOOL OpEnd(LPVOID* p) +{ + return FALSE; +} diff --git a/test/test_ocra.rb b/test/test_ocra.rb index 1636cc76..c28b8a98 100644 --- a/test/test_ocra.rb +++ b/test/test_ocra.rb @@ -1,119 +1,119 @@ -require "test/unit" -require "ocra" -require "tmpdir" -require "fileutils" - -class TestOcra < Test::Unit::TestCase - - def initialize(*args) - super(*args) - @testnum = 0 - @ocra = File.expand_path(File.join(File.dirname(__FILE__), '../bin/ocra.rb')) - end - - def ocra - @ocra - end - - def setup - @testnum += 1 - @tempdirname = ".ocratest-#{$$}-#{@testnum}" - Dir.mkdir @tempdirname - Dir.chdir @tempdirname - end - - def teardown - Dir.chdir '..' - FileUtils.rm_rf @tempdirname - end - - def test_helloworld - File.open("helloworld.rb", "w") do |f| - f << "hello_world = \"Hello, World!\"\n" - end - assert system("ruby", ocra, "--quiet", "helloworld.rb") - assert File.exist?("helloworld.exe") - assert system("helloworld.exe") - end - - def test_writefile - File.open("writefile.rb", "w") do |f| - f << "File.open(\"output.txt\", \"w\") do |f| f.write \"output\"; end" - end - assert system("ruby", ocra, "--quiet", "writefile.rb") - assert File.exist?("writefile.exe") - assert system("writefile.exe") - assert File.exist?("output.txt") - assert "output", File.read("output.txt") - end - - def test_exitstatus - File.open("exitstatus.rb", "w") do |f| - f << "exit 167 if __FILE__ == $0" - end - assert system("ruby", ocra, "--quiet", "exitstatus.rb") - system("exitstatus.exe") - assert_equal 167, $?.exitstatus - end - - def test_arguments - File.open("arguments.rb", "w") do |f| - f << "if $0 == __FILE__\n" - f << "exit 1 if ARGV.size != 3\n" - f << "exit 2 if ARGV[0] != \"foo\"\n" - f << "exit 3 if ARGV[1] != \"bar baz\"\n" - f << "exit 4 if ARGV[2] != \"\\\"smile\\\"\"\n" - f << "exit(5)\n" - f << "end" - end - assert system("ruby", ocra, "--quiet", "arguments.rb") - assert File.exist?("arguments.exe") - system(File.expand_path("arguments.exe"), "foo", "bar baz", "\"smile\"") - assert_equal 5, $?.exitstatus - end - - def test_stdout_redir - File.open("stdoutredir.rb", "w") do |f| - f << "if $0 == __FILE__\n" - f << "puts \"Hello, World!\"\n" - f << "end\n" - end - assert system("ruby", ocra, "--quiet", "stdoutredir.rb") - assert File.exist?("stdoutredir.exe") - system("stdoutredir.exe > output.txt") - assert File.exist?("output.txt") - assert_equal "Hello, World!\n", File.read("output.txt") - end - - def test_stdin_redir - File.open("input.txt", "w") do |f| - f << "Hello, World!\n" - end - File.open("stdinredir.rb", "w") do |f| - f << "if $0 == __FILE__\n" - f << " exit 104 if gets == \"Hello, World!\\n\"" - f << "end\n" - end - assert system("ruby", ocra, "--quiet", "stdinredir.rb") - assert File.exist?("stdinredir.exe") - system("stdinredir.exe < input.txt") - assert 104, $?.exitstatus - end - - def test_gdbmdll - File.open("gdbmdll.rb", "w") do |f| - f << "require 'gdbm'\n" - f << "exit 104 if $0 == __FILE__ and defined?(GDBM)\n" - end - assert system("ruby", ocra, "--quiet", "--dll", "gdbm.dll", "gdbmdll.rb") - path = ENV['PATH'] - ENV['PATH'] = "." - begin - system("gdbmdll.exe") - ensure - ENV['PATH'] = path - end - assert_equal 104, $?.exitstatus - end - -end +require "test/unit" +require "ocra" +require "tmpdir" +require "fileutils" + +class TestOcra < Test::Unit::TestCase + + def initialize(*args) + super(*args) + @testnum = 0 + @ocra = File.expand_path(File.join(File.dirname(__FILE__), '../bin/ocra.rb')) + end + + def ocra + @ocra + end + + def setup + @testnum += 1 + @tempdirname = ".ocratest-#{$$}-#{@testnum}" + Dir.mkdir @tempdirname + Dir.chdir @tempdirname + end + + def teardown + Dir.chdir '..' + FileUtils.rm_rf @tempdirname + end + + def test_helloworld + File.open("helloworld.rb", "w") do |f| + f << "hello_world = \"Hello, World!\"\n" + end + assert system("ruby", ocra, "--quiet", "helloworld.rb") + assert File.exist?("helloworld.exe") + assert system("helloworld.exe") + end + + def test_writefile + File.open("writefile.rb", "w") do |f| + f << "File.open(\"output.txt\", \"w\") do |f| f.write \"output\"; end" + end + assert system("ruby", ocra, "--quiet", "writefile.rb") + assert File.exist?("writefile.exe") + assert system("writefile.exe") + assert File.exist?("output.txt") + assert "output", File.read("output.txt") + end + + def test_exitstatus + File.open("exitstatus.rb", "w") do |f| + f << "exit 167 if __FILE__ == $0" + end + assert system("ruby", ocra, "--quiet", "exitstatus.rb") + system("exitstatus.exe") + assert_equal 167, $?.exitstatus + end + + def test_arguments + File.open("arguments.rb", "w") do |f| + f << "if $0 == __FILE__\n" + f << "exit 1 if ARGV.size != 3\n" + f << "exit 2 if ARGV[0] != \"foo\"\n" + f << "exit 3 if ARGV[1] != \"bar baz\"\n" + f << "exit 4 if ARGV[2] != \"\\\"smile\\\"\"\n" + f << "exit(5)\n" + f << "end" + end + assert system("ruby", ocra, "--quiet", "arguments.rb") + assert File.exist?("arguments.exe") + system(File.expand_path("arguments.exe"), "foo", "bar baz", "\"smile\"") + assert_equal 5, $?.exitstatus + end + + def test_stdout_redir + File.open("stdoutredir.rb", "w") do |f| + f << "if $0 == __FILE__\n" + f << "puts \"Hello, World!\"\n" + f << "end\n" + end + assert system("ruby", ocra, "--quiet", "stdoutredir.rb") + assert File.exist?("stdoutredir.exe") + system("stdoutredir.exe > output.txt") + assert File.exist?("output.txt") + assert_equal "Hello, World!\n", File.read("output.txt") + end + + def test_stdin_redir + File.open("input.txt", "w") do |f| + f << "Hello, World!\n" + end + File.open("stdinredir.rb", "w") do |f| + f << "if $0 == __FILE__\n" + f << " exit 104 if gets == \"Hello, World!\\n\"" + f << "end\n" + end + assert system("ruby", ocra, "--quiet", "stdinredir.rb") + assert File.exist?("stdinredir.exe") + system("stdinredir.exe < input.txt") + assert 104, $?.exitstatus + end + + def test_gdbmdll + File.open("gdbmdll.rb", "w") do |f| + f << "require 'gdbm'\n" + f << "exit 104 if $0 == __FILE__ and defined?(GDBM)\n" + end + assert system("ruby", ocra, "--quiet", "--dll", "gdbm.dll", "gdbmdll.rb") + path = ENV['PATH'] + ENV['PATH'] = "." + begin + system("gdbmdll.exe") + ensure + ENV['PATH'] = path + end + assert_equal 104, $?.exitstatus + end + +end