AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Base64 coder/decoder
Goto page 1, 2  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Tue Oct 18, 2005 5:18 pm    Post subject: Base64 coder/decoder Reply with quote

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
View user's profile Send private message
Titan



Joined: 11 Aug 2004
Posts: 5068
Location: imaginationland

PostPosted: Thu Mar 23, 2006 8:09 pm    Post subject: Reply with quote

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 Smile
_________________

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
View user's profile Send private message Visit poster's website
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Thu Mar 23, 2006 8:31 pm    Post subject: Reply with quote

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
View user's profile Send private message
PhiLho



Joined: 27 Dec 2005
Posts: 6721
Location: France (near Paris)

PostPosted: Fri Mar 24, 2006 12:15 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Fri Mar 24, 2006 4:40 pm    Post subject: Reply with quote

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
View user's profile Send private message
Titan



Joined: 11 Aug 2004
Posts: 5068
Location: imaginationland

PostPosted: Fri Mar 24, 2006 10:12 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Fri Mar 24, 2006 10:28 pm    Post subject: Reply with quote

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
View user's profile Send private message
PhiLho



Joined: 27 Dec 2005
Posts: 6721
Location: France (near Paris)

PostPosted: Fri Mar 24, 2006 11:10 pm    Post subject: Reply with quote

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... Razz 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
View user's profile Send private message Visit poster's website
Titan



Joined: 11 Aug 2004
Posts: 5068
Location: imaginationland

PostPosted: Fri Mar 24, 2006 11:40 pm    Post subject: Reply with quote

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 Razz

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
View user's profile Send private message Visit poster's website
Titan



Joined: 11 Aug 2004
Posts: 5068
Location: imaginationland

PostPosted: Sun Mar 26, 2006 2:43 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
Titan



Joined: 11 Aug 2004
Posts: 5068
Location: imaginationland

PostPosted: Sat Apr 01, 2006 10:51 am    Post subject: Reply with quote

I got Ascii85() fully working now. *just an update Smile
_________________

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
View user's profile Send private message Visit poster's website
rg33



Joined: 04 Apr 2006
Posts: 7

PostPosted: Tue Apr 04, 2006 7:44 pm    Post subject: Reply with quote

Titan, Laszlo,

Why don't the results from your two different base64 functions match?
Back to top
View user's profile Send private message
Titan



Joined: 11 Aug 2004
Posts: 5068
Location: imaginationland

PostPosted: Tue Apr 04, 2006 8:22 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
rg33



Joined: 04 Apr 2006
Posts: 7

PostPosted: Tue Apr 04, 2006 8:46 pm    Post subject: Reply with quote

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
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Tue Apr 04, 2006 10:11 pm    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group