AutoHotkey Community

It is currently May 27th, 2012, 11:44 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 37 posts ]  Go to page Previous  1, 2, 3
Author Message
 Post subject:
PostPosted: May 22nd, 2010, 4:01 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
You are right. The original command order might allocate 1 too many bytes for the result. While I don't think it matters, we should use the correct order.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 22nd, 2010, 6:28 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
...there was a more serious bug in the binary decoder: at m=0 in the end we have to return immediately, as in the string version. I fixed the command order (thanks to Jamie), and added the missing conditional return in the first post.

If you like compact AHK code, I added shorter code to the end of the first post.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 19th, 2011, 4:40 pm 
Offline

Joined: June 7th, 2010, 3:40 pm
Posts: 553
I've recently had a need to use base64 and I compacted and sped up the functions if anyone's interested.

Code:
Base64Encode(ByRef Bin, n=0)
{
   Static Chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
   m := VarSetCapacity(Bin)
   VarSetCapacity(out,Round(m*1.3))
   Loop % n<1 || n>m ? m : n
      A := *(&Bin+A_Index-1)
      ,m := Mod(A_Index,3)
      ,b := m=1 ? A << 16 : m=2 ? b+(A<<8) : b+A
      ,out .= m ? "" : SubStr(Chars,((b>>18)&63)+1,1) SubStr(Chars,((b>>12)&63)+1,1) SubStr(Chars,((b>>6)&63)+1,1) SubStr(Chars,(b&63)+1,1)
      Return out (m ? SubStr(Chars,((b>>18)&63)+1,1) SubStr(Chars,((b>>12)&63)+1,1) (m=1 ? "==" : SubStr(Chars,((b>>6)&63)+1,1) "=") : "")
}

Base64Decode(ByRef Bin, Code, IsString=0)
{
   Static Chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
   StringReplace Code, Code, =,, All
   VarSetCapacity(Bin, 3*StrLen(Code)//4, 0)
   pos := 0, Address := &Bin
   Loop Parse, Code
   {
      m := A_Index&3
      ,d := InStr(Chars,A_LoopField,1) - 1
      ,b := m ? (m=1 ? d<<18 : b+(d<<24-6*m)) : b+d
      IfEqual,m,0
         Numput(b>>16,Address+0,Pos++,"UChar")
         ,Numput(255 & b>>8,Address+0,Pos++,"UChar")
         ,Numput(255 & b,Address+0,Pos++,"UChar")
   }
   c1 := b>>16, c2 := 255 & b>>8, c3 := 0
   Loop % !!m+(m&1)
      NumPut(c%A_Index%,Address+0,Pos++,"UChar")
   If IsString
      VarSetCapacity(Bin,-1)
}

_________________
(Statistics script) M&K Counter 2.0
My FAST ini Lib
Minecraft NBT Lib


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 22nd, 2011, 1:08 am 
Offline
User avatar

Joined: August 23rd, 2010, 6:22 pm
Posts: 781
Location: Ontario, Canada
Here are some even faster versions :lol::

Base64Encode():

Code:
Base64Encode(ByRef Bin,Length = "")
{
 static CharSet := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 If (Length = "")
  Length := StrLen(Bin) << !!A_IsUnicode
 VarSetCapacity(Output,Ceil(Length / 3) * 4), Index := 0, pBin := &Bin
 Loop, % Length // 3
  Temp1 := (*(pBin ++) << 16) | (*(pBin ++) << 8) | (*(pBin ++)), Output .= SubStr(CharSet,((Temp1 >> 18) & 63) + 1,1) . SubStr(CharSet,((Temp1 >> 12) & 63) + 1,1) . SubStr(CharSet,((Temp1 >> 6) & 63) + 1,1) . SubStr(CharSet,(Temp1 & 63) + 1,1)
 Temp2 := Mod(Length,3)
 If (Temp2 = 0)
  Return, Output
 Index := pBin - &Bin, Temp1 := NumGet(Bin,Index,"UChar") << 16
 If (Temp2 = 1)
  Return, Output . SubStr(CharSet,((Temp1 >> 18) & 63) + 1,1) . SubStr(CharSet,((Temp1 >> 12) & 63) + 1,1) . "=="
 Temp1 |= NumGet(Bin,Index + 1,"UChar") << 8
 Return, Output . SubStr(CharSet,((Temp1 >> 18) & 63) + 1,1) . SubStr(CharSet,((Temp1 >> 12) & 63) + 1,1) . SubStr(CharSet,((Temp1 >> 6) & 63) + 1,1) . "="
}


Benchmark:

Code:
Benchmark:                    Base64 encoding with 1000 character strings
Iterations:                   1000
Control Run:                  0.818053 ms.    (0.000818 ms. per run)
Original Encoder (rseding91): 4233.641312 ms. (4.233641 ms. per run)
Optimised Encoder (Uberi):    1833.870210 ms. (1.833870 ms. per run)


Base64Decode:

Code:
Base64Decode(ByRef Bin,Code,IsString = 0)
{
 static CharSet := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 StringReplace Code, Code, =,, All
 Length := StrLen(Code), VarSetCapacity(Bin,Ceil((Length / 4) * 3),0), Index := 1, BinPos := 0
 Loop, % Length // 4
  Temp1 := ((InStr(CharSet,SubStr(Code,Index,1),True) - 1) << 18) | ((InStr(CharSet,SubStr(Code,Index + 1,1),True) - 1) << 12) | ((InStr(CharSet,SubStr(Code,Index + 2,1),True) - 1) << 6) | (InStr(CharSet,SubStr(Code,Index + 3,1),True) - 1), NumPut((Temp1 >> 16) | (((Temp1 >> 8) & 255) << 8) | ((Temp1 & 255) << 16),Bin,BinPos,"UInt"), Index += 4, BinPos += 3
 If (Length & 3)
 {
  Temp1 := ((InStr(CharSet,SubStr(Code,Index,1),True) - 1) << 18) | ((InStr(CharSet,SubStr(Code,Index + 1,1),True) - 1) << 12), NumPut(Temp1 >> 16,Bin,BinPos,"UChar")
  If (Length & 1)
   Temp1 |= ((InStr(CharSet,SubStr(Code,Index + 2,1),True) - 1) << 6), NumPut((Temp1 >> 8) & 255,Bin,BinPos + 1,"UChar")
 }
 If IsString
  VarSetCapacity(Bin,-1)
}


Benchmark:

Code:
Benchmark:                    Base64 decoding with 1000 character strings
Iterations:                   1000
Control Run:                  0.615920 ms.    (0.000616 ms. per run)
Original Decoder (rseding91): 4210.171410 ms. (4.210171 ms. per run)
Optimised Decoder (Uberi):    3145.511597 ms. (3.145512 ms. per run)


Code isn't as short, though, but it is much faster at huge inputs, such as files.

Edit: Encoding function is even faster (benchmarks and code updated)

_________________
AutoHotkey.net | GitHub

My default license.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 28th, 2011, 7:09 pm 
Code:
Base64Decode(ByRef Bin,Code,IsString = 0)
{
 static CharSet := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 StringReplace Code, Code, =,, All
 Length := StrLen(Code), VarSetCapacity(Bin,Ceil((Length / 4) * 3),0), Index := 1, BinPos := 0
 Loop, % Length // 4
  Temp1 := ((InStr(CharSet,SubStr(Code,Index,1),True) - 1) << 18) | ((InStr(CharSet,SubStr(Code,Index + 1,1),True) - 1) << 12) | ((InStr(CharSet,SubStr(Code,Index + 2,1),True) - 1) << 6) | (InStr(CharSet,SubStr(Code,Index + 3,1),True) - 1), NumPut((Temp1 >> 16) | (((Temp1 >> 8) & 255) << 8) | ((Temp1 & 255) << 16),Bin,BinPos,"UInt"), Index += 4, BinPos += 3
 If (Length & 3)
 {
  Temp1 := ((InStr(CharSet,SubStr(Code,Index,1),True) - 1) << 18) | ((InStr(CharSet,SubStr(Code,Index + 1,1),True) - 1) << 12), NumPut(Temp1 >> 16,Bin,BinPos,"UChar")
  If (Length & 1)
   Temp1 |= ((InStr(CharSet,SubStr(Code,Index + 2,1),True) - 1) << 6), NumPut((Temp1 >> 8) & 255,Bin,BinPos + 1,"UChar")
 }


Sorry to be such a noob but if i want to use this function to decode some base64 string, where do i put it, and more to the point, can you explain how I use this?


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: June 29th, 2011, 4:28 am 
Offline
User avatar

Joined: August 23rd, 2010, 6:22 pm
Posts: 781
Location: Ontario, Canada
uname: try this:

Code:
Base64String := "" ;your string in Base64 goes here, in between the quotation marks
Base64Decode(NormalString,Base64String,1)
MsgBox, The decoded string is "%NormalString%". The Base64 string was "%Base64String%"

;this is the function I posted above
Base64Decode(ByRef Bin,Code,IsString = 0)
{
 static CharSet := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 StringReplace Code, Code, =,, All
 Length := StrLen(Code), VarSetCapacity(Bin,Ceil((Length / 4) * 3),0), Index := 1, BinPos := 0
 Loop, % Length // 4
  Temp1 := ((InStr(CharSet,SubStr(Code,Index,1),True) - 1) << 18) | ((InStr(CharSet,SubStr(Code,Index + 1,1),True) - 1) << 12) | ((InStr(CharSet,SubStr(Code,Index + 2,1),True) - 1) << 6) | (InStr(CharSet,SubStr(Code,Index + 3,1),True) - 1), NumPut((Temp1 >> 16) | (((Temp1 >> 8) & 255) << 8) | ((Temp1 & 255) << 16),Bin,BinPos,"UInt"), Index += 4, BinPos += 3
 If (Length & 3)
 {
  Temp1 := ((InStr(CharSet,SubStr(Code,Index,1),True) - 1) << 18) | ((InStr(CharSet,SubStr(Code,Index + 1,1),True) - 1) << 12), NumPut(Temp1 >> 16,Bin,BinPos,"UChar")
  If (Length & 1)
   Temp1 |= ((InStr(CharSet,SubStr(Code,Index + 2,1),True) - 1) << 6), NumPut((Temp1 >> 8) & 255,Bin,BinPos + 1,"UChar")
 }
 If IsString
  VarSetCapacity(Bin,-1)
}

_________________
AutoHotkey.net | GitHub

My default license.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 5th, 2011, 6:13 am 
Offline
User avatar

Joined: October 31st, 2008, 9:39 am
Posts: 641
Location: France
I had some problem to find my answer that's why I post the solve... I tried like a noob with FileAppend...
However why ahk_l add 1 byte ? thx Laszo :)

BinWrite (from Laszo):
http://www.autohotkey.com/forum/topic4604.html
or from PhiLho:
http://www.autohotkey.com/forum/topic7549.html

an example:
Code:
StringCaseSense, On
Chars := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

code:="iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="



Base64Decode(data, code)
BinWrite("reddot.png", data) ; result is a valid png file



Base64Decode(ByRef bin, code) {
   StringReplace code, code, =,,All
msgbox %   VarSetCapacity(bin, 3*StrLen(code)//4, 0)
   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,0, Return
   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++
   }
}

DeCode(c) { ; c = a char in Chars ==> position [0,63]
   Global Chars
   Return InStr(Chars,c,1) - 1
}

BinWrite(file, ByRef data, n=0, offset=0)
{
   ; Open file for WRITE (0x40..), OPEN_ALWAYS (4): creates only if it does not exists
   h := DllCall("CreateFile","str",file,"Uint",0x40000000,"Uint",0,"UInt",0,"UInt",4,"Uint",0,"UInt",0)
   IfEqual h,-1, SetEnv, ErrorLevel, -1
   IfNotEqual ErrorLevel,0,Return,0 ; couldn't create the file

   m = 0                            ; seek to offset
   IfLess offset,0, SetEnv,m,2
   r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m)
   IfEqual r,0, SetEnv, ErrorLevel, -3
   IfNotEqual ErrorLevel,0, {
      t = %ErrorLevel%              ; save ErrorLevel to be returned
      DllCall("CloseHandle", "Uint", h)
      ErrorLevel = %t%              ; return seek error
      Return 0
   }

   m := VarSetCapacity(data)        ; get the capacity ( >= used length )
   If (n < 1 or n > m)
       n := m
   result := DllCall("WriteFile","UInt",h,"Str",data,"UInt",n,"UInt *",Written,"UInt",0)
   if (!result or Written < n)
       ErrorLevel = -3
   IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel%

   h := DllCall("CloseHandle", "Uint", h)
   IfEqual h,-1, SetEnv, ErrorLevel, -2
   IfNotEqual t,,SetEnv, ErrorLevel, %t%-%ErrorLevel%

   Return Written
}

_________________
"You annoy me, therefore I exist."


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 37 posts ]  Go to page Previous  1, 2, 3

All times are UTC [ DST ]


Who is online

Users browsing this forum: rrhuffy and 60 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group