1- @ (echo off% <#% ) & color 07 & title Compressed2TXT v6.0 - Files/Folders " Send to" menu .bat ascii encoder by AveYo
1+ @ (echo off% <#% ) & color 07 & title Compressed2TXT v6.1 - Files/Folders " Send to" menu .bat ascii encoder by AveYo
22chcp 65001 > nul & set " 0=%~f0 " & set 1=%* & powershell -nop -c iex ([io.file]::ReadAllText($env:0)) & pause & exit/b || #> )[1]
33
4- $env:1; if (!$env:1) {write-host "`n No input files or folders to encode ! use 'Send to' context menu ...`n" -fore Yellow
5- $s=" $env:APPDATA\Microsoft\Windows\SendTo" ; if ($(Split-Path $env:0) -ne $s){copy $env:0 " $s\Compressed 2 TXT.bat" -force} exit}
4+ $env:1; if (!$env:1) {write-host "`n No input files or folders to encode ! use 'Send to' context menu ...`n" -fore Yellow}
5+ $SendTo = Join-Path $([Environment]::GetFolderPath(" ApplicationData" )) -Child 'Microsoft\Windows\SendTo'
6+ if (!$env:1) {if ($(Split-Path $env:0) -ne $SendTo){copy $env:0 " $SendTo\Compressed 2 TXT.bat" -force} exit}
67
78$Main = {
89# Choice text - & x is optional hotkey toggle # Choice value # Default:1
910 $c = @ () ; $v = @ () ; $d = @ ()
1011 $c += '& 1 Input decoding key as password '; $v += 'password' ; $d += 0
1112 $c += '& 2 Randomize decoding key (use with 1) '; $v += 'random' ; $d += 0
1213 $c += '& 3 BAT91 encoder instead of BAT85 -1.7%'; $v += 'bat91' ; $d += 0
13- $c += '& 4 No long lines (adds more overhead) '; $v += 'nolonglines'; $d += 1
14- $c += '& 5 No LZX compression (full size) '; $v += 'nocompress' ; $d += 0
14+ $c += '& 4 No long lines (adds more overhead) '; $v += 'nolonglines'; $d += 0
15+ $c += '& 5 No LZX compression (for dense files) '; $v += 'nocompress' ; $d += 0
1516 $c += '& 6 No txt encoding (cab archive only) '; $v += 'cabonly' ; $d += 0
1617
17- # Show choices dialog - outputs $result with indexes like '1,2,4' - query via ($selected[number]) or ($choices -eq 'value')
18+ # Show Choices dialog snippet - outputs $result with indexes like '1,2,4'
1819 $all=$c -join ',';$def=(($d -split " `n" )| Select-String 1).LineNumber -join ',';$choices=@ ();$selected=@ ($false)*($c.length+1)
19- $result = Choices $all $def 'Compressed2TXT' 14; $result -split ',' | % {$selected[[int]$_] = $true;$choices += $v[[int]$_-1]}
20- # Quit if canceled (allows no selection)
21- if ($result -eq $null) {write-host " `n Canceled `n" -fore Yellow; exit} else {write-host $($choices -join ',')}
20+ $result = Choices $all $def 'Compressed2TXT' 14
21+ # Test individual choices presence via ($choices -eq 'value') or ($selected[number])
22+ if ($result) {$result -split ',' | % {$selected[$_-0] = $true; $choices += $v[$_-1]}}
23+ # Quit if canceled
24+ if ($result -eq $null) {write-host " `n Canceled `n" -fore Yellow; exit} else {write-host " $($choices -join ',')`n" }
2225
2326# Choice 3: BAT91 encoder instead of BAT85 for ~1.7% less size, but will use some web-problematic chars <*`% \>
2427 $key = '.,;{-}[+](/)_| ^ =?O123456A789BCDEFGHYIeJKLMoN0PQRSTyUWXVZabcdfghijklmnpqrvstuwxz!@ #$& ~'; $chars = 85
@@ -44,23 +47,29 @@ $Main = {
4447 }
4548 }
4649
50+ # Start measuring total processing time
51+ $timer=new-object Diagnostics.StopWatch; $timer.Start()
4752# Process command line arguments - supports multiple files and folders
4853 $arg = ([regex]'" [^" ]+" |[^ ]+').Matches($env:1)
49- $val = gi -force -lit $arg[0].Value.Trim('" ')
50- $fn1 = $val.Name
51- # Setup work and output dirs
52- $top = Split-Path $val; $dir = $top; $rng = [Guid]::NewGuid().Guid; $work = Join-Path $dir -Child $rng
53- mkdir $work -force -ea 0| out-null
54- if (!(Test-Path -lit $work)) {
55- $dir = " $env:USERPROFILE\Desktop" ; $work = Join-Path $dir -Child $rng; mkdir $work -force -ea 0| out-null
54+ $val = Get-Item -force -lit $arg[0].Value.Trim('" ')
55+ $fn1 = $val.Name.replace('.','_')
56+ # Setup work and output dirs - if source not writable fallback to user Desktop
57+ $top = Split-Path $val; $dir = $top; $rng = [Guid]::NewGuid().Guid; $work = Join-Path $dir -Child $rng; $write = $work+'~'
58+ mkdir $work -force -ea 0| out-null; New-Item $write -item File -force -ea 0| out-null
59+ if (!(Test-Path -lit $work) -or ! (Test-Path -lit $write)) {
60+ rmdir -lit $work -force -ea 0| out-null
61+ $dir = [Environment]::GetFolderPath(" Desktop" )
62+ $work = Join-Path $dir -Child $rng; mkdir $work -force -ea 0| out-null
5663 }
57- sl -lit $work
64+ del -lit $write -force -ea 0 | out-null
5865# Grab target files names
5966 $files = @ ()
6067 foreach ($a in $arg) {
6168 $f = gi -force -lit $a.Value.Trim('" ')
6269 if ($f.PSTypeNames -match 'FileInfo') {$files += $f} else {dir -lit $f -rec -force | ? {!$_.PSIsContainer} | % {$files += $_}}
6370 }
71+ # Jump to work dir
72+ sl -lit $work
6473
6574# Improved MakeCab ddf generator to handle localized and special characters file names better
6675 $ddf1 = @ "
@@ -71,53 +80,43 @@ $Main = {
7180.Set ReservePerCabinetSize=0`r`n.Set ReservePerDataBlockSize=0`r`n.Set ReservePerFolderSize=0`r`n.Set RptFileName=nul
7281.Set UniqueFiles=ON`r`n.Set SourceDir=.`r`n
7382" @
74- $ddf2 = $ddf1+" 1.cab`r`n" ; $cabinet = " $work\1.cab" ; [int]$renamed = 100; $rel = $top.Length + 1; if ($rel -eq 4) {$rel--}
75-
76- # Makecab tool has issues with source filenames so just rename them, while keeping destination filenames the same
83+ # MakeCab tool has issues with source filenames so just rename them while keeping destination full; skip inaccesible files
84+ [int]$renamed = 100; $rel = $top.Length + 1; if ($rel -eq 4) {$rel--}
7785 foreach ($f in $files){
78- copy -lit $f.FullName -dest " $work\$renamed" -force -ea 0| out-null
79- $ddf1 += $(" $renamed `" " +$f.FullName.substring($rel)+" `" `r`n" ); $renamed++
86+ try{ copy -lit $f.FullName -dest " $work\$renamed" -force -ea 0| out-null }catch{}
87+ if (Test-Path -lit " $work\$renamed" ) {$ddf1 += $(" $renamed `" " +$f.FullName.substring($rel)+" `" `r`n" )}
88+ $renamed++
8089 }
81-
82- # Choice 6: No text encoding (cab archive only) - single pass
83- if ($choices -eq 'cabonly') {$comp = 'ON'} else {$comp = 'OFF'}
84- # Choice 5: No LZX compression (full size)
85- if ($choices -eq 'nocompress') {$comp = 'OFF'}
86- # With default choices MakeCab is done in two passes, first just stores the files without compression
8790 [IO.File]::WriteAllText(" $work\1.ddf" , $ddf1, [Text.Encoding]::UTF8)
88- write-host
91+ # Choice 5: No LZX compression (full size)
92+ if ($choices -eq 'nocompress') {$comp = 'OFF'} else {$comp = 'ON'}
93+ # Run MakeCab to either just store the files without compression or use LZX
8994 makecab.exe /F 1.ddf /D Compress=$comp /D CabinetNameTemplate=1.cab
90- # Choice 6: No text encoding (cab archive only) - if selected script ends right after this
95+
96+ # Choice 6: No text encoding (cab archive only) - if selected, script ends right after this
9197 if ($choices -eq 'cabonly') {
92- copy -lit $cabinet -dest $(Join-Path $dir -Child " $fn1~.cab" ) -force -ea 0
93- sl -lit $top; rmdir -lit $work -rec -force -ea 0| out-null
98+ $output = Join-Path $dir -Child " $fn1~.cab"
99+ write-host " `nCAB archive only $output ..."
100+ move -lit " $work\1.cab" -dest $output -force -ea 0
101+ sl -lit $top; rmdir -lit $work -rec -force -ea 0| out-null; if (Test-Path -lit $work) {$null=cmd /c rmdir /s/q " `" $work`" " }
102+ $timer.Stop()
103+ write-host " `nDone in $([math]::Round($timer.Elapsed.TotalSeconds,4)) sec" -fore Cyan
94104 exit
95105 }
96- # With default choices MakeCab second pass LZX compresses the potentially large tree of filenames as well
97- if ($choices -notcontains 'nocompress') {
98- $cabinet = " $work\1.ca_"
99- [IO.File]::WriteAllText(" $work\2.ddf" , $ddf2, [Text.Encoding]::UTF8)
100- write-host
101- makecab.exe /F 2.ddf /D Compress=ON /D CabinetNameTemplate=1.ca_
102- }
103-
104- # Text encoding - compact self-expanding batch file bundling ascii encoded with BAT91 cab archive of target files
105- $HEADER = " @echo off& color 07& chcp 65001 >nul`r`n"
106- $HEADER += 'set " 0=%~f0 " & powershell -nop -c cd -li(Split-Path $env:0);'
107- $HEADER += '$f=[IO.File]::ReadAllText($env:0)-split'':bat2file\:.*'';iex($f[1]); X 1'
108- $HEADER += " `r`n@pause& exit/b`r`n`r`n:bat2file: Compressed2TXT v6.0`r`n"
109106
107+ # Generate text decoding header - compact self-expanding batch file for bundled ascii encoded cab archive of target files
108+ $HEADER = " @echo off & color 07 & chcp 65001 >nul`r`n"
109+ $HEADER += 'set " 0=%~f0 " & powershell -nop -c $f=[IO.File]::ReadAllText($env:0)-split'':bat2file\:.*'';iex($f[1]); X 1'
110+ $HEADER += " `r`n@pause & exit/b`r`n`r`n:bat2file: Compressed2TXT v6.1`r`n"
110111# Choice 4: No long lines (adds more overhead) - each line has 4 extra chars (cr lf ::) and short lines are ~8 times as many
111112 if ($choices -eq 'nolonglines') {$line = 124} else {$line = 1014}
112-
113113# Choice 1: Input decoding key as password - or bundle it with the file for automatic extraction
114114 if ($choices -eq 'password') {
115115 $HEADER += '$b=''Microsoft.VisualBasic'';Add-Type -As $b;$k=iex " [$b.Interaction]::InputBox(''Key'','+$chars+')" ;'
116- $HEADER += 'if($k.Length-ne'+$chars+'){exit} Add-Type -Ty @ ' + " '`r`n"
116+ $HEADER += 'if($k.Length-ne'+$chars+'){exit}Add-Type -Ty @ ' + " '`r`n"
117117 } else {
118118 $HEADER += '$k='''+$key+" '; Add-Type -Ty @'`r`n"
119119 }
120-
121120# Generate text decoding C# snippet depending on Choice 3: BAT91 encoder instead of BAT85
122121 if ($choices -eq 'bat91') {
123122 $HEADER += @ '
@@ -126,47 +125,44 @@ byte[] b91=new byte[256]; int n=0,c=255,v=91,q=0,z=f[x].Length; while (c>0) b91[
126125using (FileStream o=new FileStream(fo,FileMode.Create)) { for (int i=0; i != z; i++) { c=b91[ f[x][i] ]; if (c == 91) continue;
127126if (v == 91) {v = c;} else {v += c * 91; q | = v << n; if ((v & 8191) > 88) {n += 13;} else {n += 14;} v = 91;
128127do {o.WriteByte((byte)q); q >> = 8; n -= 8;} while (n> 7);} } if (v != 91) o.WriteByte((byte)(q | v << n)); } }}}
129- '@ + " `r`n'@; " + 'function X([int]$x=1) {[BAT91]::Dec([ref]$f,$x+1,'
128+ '@ + " `r`n'@; "
130129 } else {
131130 $HEADER += @ '
132131using System.IO; public class BAT85 {public static void Dec (ref string[] f, int x, string fo, string key) { unchecked {
133132byte[] b85=new byte[256];long n=0;int p=0,q=0,c=255,z=f[x].Length; while (c> 0) b85[c--]=85; while (c< 85) b85[key[c]]=(byte)c++;
134133int[] p85={52200625,614125,7225,85,1}; using (FileStream o=new FileStream(fo,FileMode.Create)) { for (int i=0;i != z;i++) {
135134c=b85[f[x][i]]; if (c== 85) continue; n += c * p85[p++]; if (p== 5) {p=0; q=4; while (q > 0) {q--; o.WriteByte((byte)(n>> 8*q));}
136135n=0;}} if (p> 0) {for (int i=0;i< 5-p;i++) {n += 84 * p85[p+i];} q=4; while (q > p-1) {q--;o.WriteByte((byte)(n>> 8*q));} } } }}}
137- '@ + " `r`n'@; " + 'function X([int]$x=1) {[BAT85]::Dec([ref]$f,$x+1,'
138- }
139-
140- # Generate expand function (must run twice if compressed in two passes)
141- if ($choices -eq 'nocompress') {
142- $HEADER += '" 1.cab" ,$k); expand -R " 1.cab" -F:* .; del " 1.cab" -force}'
143- } else {
144- $HEADER += '" 1.ca_" ,$k); @ (" 1.ca_" ," 1.cab" ) | % {expand -R $_ -F:* .; del $_ -force}}'
136+ '@ + " `r`n'@; "
145137 }
138+ # Generate expand function
139+ $HEADER += 'cd -lit (Split-Path $env:0); '
140+ $HEADER += 'function X([int]$x=1) {[BAT' + $chars + ']::Dec([ref]$f,$x+1,$x,$k); expand -R $x -F:* .; del $x -force}'
146141 $HEADER += " `r`n`r`n:bat2file:[ $fn1`r`n"
147142
148- # BAT91 or BAT85 ascii encoding of cab file containing target files
143+ # BAT91 or BAT85 ascii encoding the cab archive of target files
149144 $output = Join-Path $dir -Child " $fn1~.bat" ; $outputkey = Join-Path $dir -Child " $fn1~key.ini"
150145 [IO.File]::WriteAllText($output, $HEADER)
151- write-host " `nBAT$chars encoding $output ..." -fore Green
152- $timer =new-object Diagnostics.StopWatch; $timer .Start()
146+ write-host " `nBAT$chars encoding $output ... " -nonew
147+ $enctimer =new-object Diagnostics.StopWatch; $enctimer .Start()
153148 if ($choices -eq 'bat91') {
154- [BAT91]::Enc($cabinet , $output, $key, $line)
149+ [BAT91]::Enc(" $work\1.cab " , $output, $key, $line)
155150 } else {
156- [BAT85]::Enc($cabinet , $output, $key, $line)
151+ [BAT85]::Enc(" $work\1.cab " , $output, $key, $line)
157152 }
158- $timer .Stop()
159- write-host " $($timer .Elapsed.TotalSeconds) seconds `n "
153+ $enctimer .Stop()
154+ write-host " $([math]::Round($enctimer .Elapsed.TotalSeconds,4)) sec "
160155 [IO.File]::AppendAllText($output, " `r`n:bat2file:]`r`n" )
161-
162156# Choice 1: Input decoding key as password - saving decoding key externally
163157 if ($choices -eq 'password') {
164158 [IO.File]::WriteAllText($outputkey, $key)
165- write-host " decoding key saved separately to $fn1~key.ini" -fore Yellow; write-host " $key`n"
159+ write-host " `ndecoding key saved separately to $fn1~key.ini" -fore Yellow; write-host " $key`n"
166160 } else {del $outputkey -force -ea 0| out-null}
167161
168- # Done - cleanup $work dir
169- sl -lit $top; rmdir -lit $work -rec -force -ea 0| out-null
162+ # Done - cleanup $work dir and write timer
163+ sl -lit $top; rmdir -lit $work -rec -force -ea 0| out-null; if (Test-Path -lit $work) {$null=cmd /c rmdir /s/q " `" $work`" " }
164+ $timer.Stop()
165+ write-host " `nDone in $([math]::Round($timer.Elapsed.TotalSeconds,4)) sec" -fore Cyan
170166}
171167
172168############
@@ -208,7 +204,7 @@ public class BAT91 {
208204 using (FileStream o = new FileStream(fo, FileMode.Append)) {
209205 o.WriteByte(58); o.WriteByte(58);
210206 for (int i = 0; i != z; i++) {
211- q | = (a[i] & 255) << n; n += 8;
207+ q | = (byte) a[i] << n; n += 8;
212208 if (n > 13) {
213209 v = q & 8191; if (v > 88) {q >> = 13; n -= 13;} else {v = q & 16383; q >> = 14; n -= 14;}
214210 o.WriteByte(b91[v % 91]); o.WriteByte(b91[v / 91]);
@@ -222,9 +218,9 @@ public class BAT91 {
222218'@
223219
224220# Choices dialog snippet - parameters: 1=allchoices, 2=default; [optional] 3=title, 4=textsize, 5=backcolor, 6=textcolor
225- function Choices($all, $def, $n='Choices', [byte]$sz=12, $bc='MidnightBlue', $fc='Snow', $saved='HKCU:\Environment'){
221+ function Choices($all, $def, $n='Choices', [byte]$sz=12, $bc='MidnightBlue', $fc='Snow', $saved='HKCU:\Environment') {
226222 [void][Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); $f=new-object Windows.Forms.Form
227- $a=$all.split(','); $s=$def.split(','); $reg=(gp $saved -ea 0).$n; if($reg.length) {$s=$reg.split(',')}
223+ $a=$all.split(','); $s=$def.split(','); $reg=(gp $saved -ea 0).$n; if($reg.length) {$s=$reg.Trim(). split(',')}
228224 function rst(){ $cb | %{ $_.Checked=0; if($s -contains $_.Name){ $_.Checked=1 } } }; $f.Add_Shown({rst; $f.Activate()})
229225 $cb=@ (); $i=1; $a | %{ $c=new-object Windows.Forms.CheckBox; $cb+=$c; $c.Text=$_; $c.AutoSize=1;
230226 $c.Margin='8,4,8,4'; $c.Location='64,'+($sz*3*$i-$sz); $c.Font='Tahoma,'+$sz; $c.Name=$i; $f.Controls.Add($c); $i++}
0 commit comments