 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Laszlo
Joined: 14 Feb 2005 Posts: 4016 Location: Pittsburgh
|
Posted: Tue Oct 18, 2005 5:18 pm Post subject: Base64 coder/decoder |
|
|
Wikipedia: The first byte is placed in the most significant eight bits of a 24-bit buffer,
the next in the middle eight, and the third in the least significant eight bits.
If there are fewer than three bytes to encode, the corresponding buffer bits will be zero.
The buffer is then used, six bits at a time, most significant first, as indices into the string
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" and the indicated character output.
If there were only one or two input bytes, only the first two or three characters of the output
are used and are padded with two or one "=" characters respectively.
The process then repeats on the remaining input data. | Code: | In =
( Join
Man is distinguished, not only by his reason, but by this singular passion from other animals,
which is a lust of the mind, that by a perseverance of delight in the continued and
indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.
)
Out =
( Join
TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0
aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1
c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0
aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdl
LCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=
)
StringCaseSense On
Chars = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
If Base64(In) = Out
MsgBox OK
If InvBase64(Out) = In
MsgBox OK
Base64(string)
{
Loop Parse, string
{
If Mod(A_Index,3) = 1
buffer := Asc(A_LoopField) << 16
Else If Mod(A_Index,3) = 2
buffer += Asc(A_LoopField) << 8
Else {
buffer += Asc(A_LoopField)
out := out . Code(buffer>>18) . Code(buffer>>12) . Code(buffer>>6) . Code(buffer)
}
}
If Mod(StrLen(string),3) = 0
Return out
If Mod(StrLen(string),3) = 1
Return out . Code(buffer>>18) . Code(buffer>>12) "=="
Return out . Code(buffer>>18) . Code(buffer>>12) . Code(buffer>>6) "="
}
InvBase64(code)
{
StringReplace code, code, =,,All
Loop Parse, code
{
If Mod(A_Index,4) = 1
buffer := DeCode(A_LoopField) << 18
Else If Mod(A_Index,4) = 2
buffer += DeCode(A_LoopField) << 12
Else If Mod(A_Index,4) = 3
buffer += DeCode(A_LoopField) << 6
Else {
buffer += DeCode(A_LoopField)
out := out . Chr(buffer>>16) . Chr(255 & buffer>>8) . Chr(255 & buffer)
}
}
If Mod(StrLen(code),4) = 0
Return out
If Mod(StrLen(code),4) = 2
Return out . Chr(buffer>>16)
Return out . Chr(buffer>>16) . Chr(255 & buffer>>8)
}
Code(i) ; <== Chars[i & 63], 0-base index
{
Global Chars
StringMid i, Chars, (i&63)+1, 1
Return i
}
DeCode(c) ; c = a char in Chars ==> position [0,63]
{
Global Chars
Return InStr(Chars,c,1) - 1
} |
And here is a version, which handles binary buffers, not just AHK strings: | Code: | Base64Encode(ByRef bin, n=0) {
m := VarSetCapacity(bin)
If n not between 1 and %m%
n = %m%
Loop %n% {
A := *(&bin+A_Index-1)
m := Mod(A_Index,3)
IfEqual m,1, SetEnv buffer,% A << 16
Else IfEqual m,2, EnvAdd buffer,% A << 8
Else {
buffer += A
out := out Code(buffer>>18) Code(buffer>>12) Code(buffer>>6) Code(buffer)
}
}
IfEqual m,0, Return out
IfEqual m,1, Return out Code(buffer>>18) Code(buffer>>12) "=="
Return out Code(buffer>>18) Code(buffer>>12) Code(buffer>>6) "="
}
Base64Decode(ByRef bin, code) {
VarSetCapacity(bin, 3*StrLen(code)//4, 0)
StringReplace code, code, =,,All
Loop Parse, code
{
m := A_Index & 3 ; mod 4
IfEqual m,0, {
buffer += DeCode(A_LoopField)
Append(bin, pos, buffer>>16, 255 & buffer>>8, 255 & buffer)
}
Else IfEqual m,1, SetEnv buffer, % DeCode(A_LoopField) << 18
Else buffer += DeCode(A_LoopField) << 24-6*m
}
IfEqual m,2
Append(bin, pos, buffer>>16)
Else Append(bin, pos, buffer>>16, 255 & buffer>>8)
}
Append(ByRef bin, ByRef pos, c1, c2="", c3="", c4="") {
pos += 0
Loop 4 {
IfEqual c%A_Index%,, Break
DllCall("RtlFillMemory",UInt,&bin+pos, UInt,1, UChar,c%A_Index%)
pos++
}
}
Code(i) { ; <== Chars[i & 63], 0-base index
Global Chars
StringMid i, Chars, (i&63)+1, 1
Return i
}
DeCode(c) { ; c = a char in Chars ==> position [0,63]
Global Chars
Return InStr(Chars,c,1) - 1
} |
Edit 2006.07.09: added version to handle binary buffers.
Last edited by Laszlo on Sun Jul 09, 2006 8:09 pm; edited 1 time in total |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Thu Mar 23, 2006 8:09 pm Post subject: |
|
|
I needed a Base64 decoder and I was just about to write one myself when I found this with Search.
I use a modified version which is basically the two combined with the extra 'inv=0' parameter. It works great anyway, thanks  _________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4016 Location: Pittsburgh
|
Posted: Thu Mar 23, 2006 8:31 pm Post subject: |
|
|
| In the Ask for help section of the Forum somebody requested it half a year ago. He did not even bother to tell if it worked for him. You seem to be the only one, who used it. I am glad it saved some time for you. |
|
| Back to top |
|
 |
PhiLho
Joined: 27 Dec 2005 Posts: 6721 Location: France (near Paris)
|
Posted: Fri Mar 24, 2006 12:15 pm Post subject: |
|
|
It was one of the first script I saved, as an advanced (for me, at the time) example of scripting with AutoHotkey.
I have not yet used it, but I recommanded to Goyyah to check it out because he wanted to create a binary file encoded in a script.
I provided a solution using hexadecimal encoding, but it is a waste of space for large files (> 10KB), so I wrote to use this code to encode the file in a compacter format.
Taking another look, it may need a slight rewrite to handle binary data, but the base is here. (no pun intended...)
Or, for an even smaller result, we could use Base96 (created by Adobe for PDF, IIRC), since we don't have to maintain Mime compatibility or such. _________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2") |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4016 Location: Pittsburgh
|
Posted: Fri Mar 24, 2006 4:40 pm Post subject: |
|
|
| AHK can handle all of the printable ANSI characters, about 200, so we could probably get an even compacter (but nonstandard) encoding. For speed, character codes 0..31, 127..144, 147..160 and 255 could be remapped to "`c" c denoting a printable character, "``" for "`". This has the advantage, that plain text portions of the data remain unchanged, so looking at program binaries, you could find text messages. |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Fri Mar 24, 2006 10:12 pm Post subject: |
|
|
| PhiLho wrote: | | we could use Base96 (created by Adobe for PDF, IIRC), since we don't have to maintain Mime compatibility or such. | I never heard of this? I couldn't find anything on it either. Talking of MIME, does this insert a linefeed after every 76 characters Laszlo (RFC 2045)?
Here's my version of the script. It's roughly 30% smaller in size but is 9% slower on average (measuring flops is hard so this could be unreliable): *Edit: Removed _________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2")
Last edited by Titan on Tue Apr 04, 2006 8:23 pm; edited 1 time in total |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4016 Location: Pittsburgh
|
Posted: Fri Mar 24, 2006 10:28 pm Post subject: |
|
|
| Wow! Titan is going to beat me in my own game (to save a few lines of code by all means). Who can make it even shorter? (I have to finish a paper in the next two weeks, so I cannot compete...) |
|
| Back to top |
|
 |
PhiLho
Joined: 27 Dec 2005 Posts: 6721 Location: France (near Paris)
|
Posted: Fri Mar 24, 2006 11:10 pm Post subject: |
|
|
| Titan wrote: | | PhiLho wrote: | | we could use Base96 (created by Adobe for PDF, IIRC), since we don't have to maintain Mime compatibility or such. | I never heard of this? |
Oops, I had a vague doubt, but did checked before, I should have...
That's ASCII85, not Base96... Mix up with Base64 and an unreliable memory. _________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2") |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Fri Mar 24, 2006 11:40 pm Post subject: |
|
|
| Laszlo wrote: | | Wow! Titan is going to beat me in my own game | lol, it was just my 30 sec mod for other fans of short code
btw. Ascii85 looks interesting but is it patented? Base64 is quite common so I prefer to stick with that for now. _________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Sun Mar 26, 2006 2:43 pm Post subject: |
|
|
Here is a fully working Ascii85() (or Base85) function with an example: | Code: | In =
( Join
Man is distinguished, not only by his reason, but by this singular passion from other animals
, which is a lust of the mind, that by a perseverance of delight in the continued
, and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.
)
example := "Ascii85: -----`n" . Ascii85(In)
. "`n`nInverse: -----`n" . Ascii85(Ascii85(In), 1)
MsgBox, 64, Ascii85, %example%
ExitApp
Ascii85(str, inv=0) { ; by Titan
xFI := A_FormatInteger
If inv {
StringReplace, str, str, <~
StringReplace, str, str, ~>
Loop, Parse, str
If !Mod(A_Index, 5) or StrLen(str) / A_Index = 1 {
If StrLen(str) / A_Index = 1
tr := 5 - Mod(A_Index, 5)
Loop, %tr%
x += (Asc("0x00") - 33) * (85 ** 5 - (5 - (5 - Mod(A_Index, 5))))
x += Asc(A_LoopField) - 33
SetFormat, Integer, Hex
x += 0
Loop, 4 {
StringMid, a, x, (A_Index * 2) + 1, 2
i := i . Chr("0x" . a)
} SetFormat, Integer, D
x = 0
} Else x += (Asc(A_LoopField) - 33) * (85 ** (5 - Mod(A_Index, 5)))
StringTrimRight, i, i, %tr%
Return, i
} SetFormat, Integer, Hex
Loop, Parse, str
If !Mod(A_Index, 4) or (StrLen(str) / A_Index = 1) {
x := x . Asc(A_LoopField)
If StrLen(str) / A_Index = 1 and Mod(A_Index, 4)
tr := 4 - Mod(A_Index, 4)
Loop, %tr%
x := x . 0x00
StringReplace, x, x, 0x, , 1
x =0x%x%
SetFormat, Integer, D
x += 0
Loop, 5
i := i . Chr((Floor(Mod(x / (85 ** (5 - A_Index)), 85))) + 33)
SetFormat, Integer, Hex
StringTrimLeft, x, x, 4
x := ""
} Else x := x . Asc(A_LoopField)
StringReplace, i, i, !!!!!, z, 1
StringTrimRight, i, i, %tr%
SetFormat, Integer, %xFI%
Return, "<~" . i . "~>"
} |
_________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Sat Apr 01, 2006 10:51 am Post subject: |
|
|
I got Ascii85() fully working now. *just an update  _________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
rg33
Joined: 04 Apr 2006 Posts: 7
|
Posted: Tue Apr 04, 2006 7:44 pm Post subject: |
|
|
Titan, Laszlo,
Why don't the results from your two different base64 functions match? |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Tue Apr 04, 2006 8:22 pm Post subject: |
|
|
I think I made a mistake somewhere so I'll scrap that post. I use Laszlo's version because it's faster anyway so I didn't quite notice the error, sorry. _________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
rg33
Joined: 04 Apr 2006 Posts: 7
|
Posted: Tue Apr 04, 2006 8:46 pm Post subject: |
|
|
No problem. Thank you both for all your contributions!
| Titan wrote: | | I think I made a mistake somewhere so I'll scrap that post. I use Laszlo's version because it's faster anyway so I didn't quite notice the error, sorry. |
|
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4016 Location: Pittsburgh
|
Posted: Tue Apr 04, 2006 10:11 pm Post subject: |
|
|
This version is a little more compact and should be slightly faster, because the mod function is called less often. | Code: | In =
( Join
Man is distinguished, not only by his reason, but by this singular passion from other animals,
which is a lust of the mind, that by a perseverance of delight in the continued and
indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.
)
Out =
( Join
TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0
aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1
c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0
aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdl
LCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=
)
StringCaseSense On
Chars = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
MsgBox % "Encode = " (Base64Encode(In) == Out)
MsgBox % "Decode = " (Base64Decode(Out) == In)
Base64Encode(string) {
Loop Parse, string
{
m := Mod(A_Index,3)
IfEqual m,1, SetEnv buffer, % Asc(A_LoopField) << 16
Else IfEqual m,2, EnvAdd buffer, % Asc(A_LoopField) << 8
Else {
buffer += Asc(A_LoopField)
out := out Code(buffer>>18) Code(buffer>>12) Code(buffer>>6) Code(buffer)
}
}
IfEqual m,0, Return out
IfEqual m,1, Return out Code(buffer>>18) Code(buffer>>12) "=="
Return out Code(buffer>>18) Code(buffer>>12) Code(buffer>>6) "="
}
Base64Decode(code) {
StringReplace code, code, =,,All
Loop Parse, code
{
m := A_Index & 3 ; mod 4
IfEqual m,0, {
buffer += DeCode(A_LoopField)
out := out Chr(buffer>>16) Chr(255 & buffer>>8) Chr(255 & buffer)
}
Else IfEqual m,1, SetEnv buffer, % DeCode(A_LoopField) << 18
Else buffer += DeCode(A_LoopField) << 24-6*m
}
IfEqual m,0, Return out
IfEqual m,2, Return out Chr(buffer>>16)
Return out Chr(buffer>>16) Chr(255 & buffer>>8)
}
Code(i) { ; <== Chars[i & 63], 0-base index
Global Chars
StringMid i, Chars, (i&63)+1, 1
Return i
}
DeCode(c) { ; c = a char in Chars ==> position [0,63]
Global Chars
Return InStr(Chars,c,1) - 1
} |
|
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|