summarylogtreecommitdiffstats
path: root/bitrock-unpacker.tcl
blob: f035f61d6eda907c5888b660a7f2bd25c828323b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env tclkit
#
# Bitrock unpacking script
#
# This script must be executed using 32-bit tclkit
#
# Author : mickael9 <mickael9 at gmail dot com>
#
# Latest version can be found at:
# https://gist.github.com/mickael9/0b902da7c13207d1b86e

source /usr/bin/sdx.kit

if {$argc < 2} {
    puts "Usage: $argv0 installerFile outputDirectory"
    exit 1
}

set installerFile [lindex $argv 0]
set destDir  [lindex $argv 1]

set installerMount /installer
set dataMount /installerData

vfs::mk4::Mount $installerFile $installerMount -readonly

lappend auto_path $installerMount/libraries/
package require vfs::cookfs
catch {package require Tcllzmadec}

# progress from http://wiki.tcl.tk/16939 (sligtly modified)
# thanks to the author
proc progress {cur tot} {
    # set to total width of progress bar
    set total 76
    
    if {$cur == $tot} {
        # cleanup
        set str "\r[string repeat " " [expr $total + 4]]\r"
    } else {
        set half [expr {$total/2}]
        set percent [expr {100.*$cur/$tot}]
        set val (\ [format "%6.2f%%" $percent]\ )
        set str "\r|[string repeat = [
                    expr {round($percent*$total/100)}]][
                            string repeat { } [expr {$total-round($percent*$total/100)}]]|"
        set str "[string range $str 0 $half]$val[string range $str [expr {$half+[string length $val]-1}] end]"
    }
    puts -nonewline stderr $str
}

# Read cookfs options
set optionsFile [open $installerMount/cookfsinfo.txt]
set options [read $optionsFile]
close $optionsFile

# Read the manifest
set manifestFile [open $installerMount/manifest.txt]
set manifest [read $manifestFile]
close $manifestFile

# Mount the files to $dataMount
vfs::cookfs::Mount {*}$options $installerFile $dataMount

puts "Creating directories..."
foreach {fileName props} $manifest {
    set type [lindex $props 0]

    if {$type == "directory"} {
        set mode [lindex $props 1]
        file mkdir $destDir/$fileName
        file attributes $destDir/$fileName -permissions $mode
    }
}

puts "Unpacking files, please wait..."

set entryCount [expr [llength $manifest] / 2]
set entryIndex 0

foreach {fileName props} $manifest {
    set type [lindex $props 0]

    if {$type == "file"} {
        set mode [lindex $props 1]
        set sizes [lindex $props 4]
        set nparts [llength $sizes]
        set index 1

        file mkdir [file dirname $destDir/$fileName]
        file copy -force $dataMount/$fileName $destDir/$fileName

        if {$nparts > 0} {
            set fp [open $destDir/$fileName a]
            fconfigure $fp -translation binary

            while {$index < $nparts} {
                set chunkName $dataMount/${fileName}___bitrockBigFile$index
                set fp2 [open $chunkName r]
                fconfigure $fp2 -translation binary
                puts -nonewline $fp [read $fp2]
                close $fp2
                incr index
            }
            close $fp
        }

        file attributes $destDir/$fileName -permissions $mode
    }

    incr entryIndex
    progress $entryIndex $entryCount
}

puts "Creating links..."

foreach {fileName props} $manifest {
    set type [lindex $props 0]

    if {$type == "link"} {
        set linkTarget [lindex $props 1]
        file delete $destDir/$fileName
        file link -symbolic $destDir/$fileName $linkTarget
    }
}
puts "Done"