open System.Text open System module Path85 = let ToString x = x.ToString() let Bind2nd f y x = f x y let Table = "!#$%&'()+,-.0123456789;=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{}~" let Encode (data:byte[]) = let block = Array.chunkBySize 4 data let lastLen = block |> Array.rev |> Array.head |> Array.length block |> Array.map (fun x -> (match x.Length with 4 -> x | _ -> Array.append x (Array.create (4 - x.Length) 0uy)) |> Array.mapi (fun i x -> (uint32)x <<< (3 - i) * 8) |> Array.reduce (|||)) |> Array.map (fun (x:uint32) -> List.init 5 (fun i -> x / (pown 85u (4 - i)) % 85u |> int32)) |> Array.reduce (@) |> Seq.map (Bind2nd Seq.item Table >> ToString) |> String.concat "" |> fun x -> x.Substring(0, x.Length - (4 - lastLen)) let Decode (data:string) = let lastLen = match data.Length % 5 with 0 -> 5 | x -> x let padLen = data.Length / 5 * 5 + match lastLen with 5 -> 0 | _ -> 5 data.PadRight(padLen, '~').ToCharArray() |> Array.chunkBySize 5 |> Array.map (Array.map Table.IndexOf) |> Array.map (Array.mapi (fun i x -> (uint32)x * pown 85u (4 - i)) >> Array.sum) |> Array.map (fun x -> Array.init 4 (fun i -> x >>> ((3 - i) * 8) &&& 0xffu |> byte)) |> Array.reduce Array.append |> Array.take ((padLen / 5) * 4 - (5 - lastLen)) module Debug = let (|>|>) x f = f x; x let Encode (data:byte[]) = let block = Array.chunkBySize 4 data printfn "=>\n%A" block let lastLen = block |> Array.rev |> Array.head |> Array.length printfn "=>\n%A" lastLen block |> Array.map (fun x -> (match x.Length with 4 -> x | _ -> Array.append x (Array.create (4 - x.Length) 0uy)) |> Array.mapi (fun i x -> (uint32)x <<< (3 - i) * 8) |> Array.reduce (|||)) |>|> printfn "=>\n%A" |> Array.map (fun (x:uint32) -> List.init 5 (fun i -> x / (pown 85u (4 - i)) % 85u |> int32)) |>|> printfn "=>\n%A" |> Array.reduce (@) |>|> printfn "=>\n%A" |> Seq.map (Bind2nd Seq.item Table >> ToString) |>|> printfn "=>\n%A" |> String.concat "" |>|> printfn "=>\n%A" |> fun x -> x.Substring(0, x.Length - (4 - lastLen)) |>|> printfn "=>\n%A" let Decode (data:string) = let lastLen = match data.Length % 5 with 0 -> 5 | x -> x printfn "=>\n%A" lastLen let padLen = data.Length / 5 * 5 + match lastLen with 5 -> 0 | _ -> 5 printfn "=>\n%A" padLen data.PadRight(padLen, '~').ToCharArray() |>|> printfn "=>\n%A" |> Array.chunkBySize 5 |>|> printfn "=>\n%A" |> Array.map (Array.map Table.IndexOf) |>|> printfn "=>\n%A" |> Array.map (Array.mapi (fun i x -> (uint32)x * pown 85u (4 - i)) >> Array.sum) |>|> printfn "=>\n%A" |> Array.map (fun x -> Array.init 4 (fun i -> x >>> ((3 - i) * 8) &&& 0xffu |> byte)) |>|> printfn "=>\n%A" |> Array.reduce Array.append |>|> printfn "=>\n%A" |> Array.take ((padLen / 5) * 4 - (5 - lastLen)) |>|> printfn "=>\n%A" [<EntryPoint>] let main _ = let (EncodeString:string -> string) = Encoding.UTF8.GetBytes >> Path85.Encode let (DecodeString:string -> string) = Encoding.UTF8.GetString << Path85.Decode let str = "阿姆斯特朗回旋加速喷气式超电磁炮!" let encoded = EncodeString str let decoded = DecodeString encoded printfn "%A => %A" str encoded printfn "%A => %A" encoded decoded printfn "----------DEBUG----------" let (EncodeStringDebug:string -> string) = Encoding.UTF8.GetBytes >> Path85.Debug.Encode let (DecodeStringDebug:string -> string) = Encoding.UTF8.GetString << Path85.Debug.Decode let encodedDebug = EncodeStringDebug str printfn "%A => %A" str encoded let decodedDebug = DecodeStringDebug encoded printfn "%A => %A" encoded decoded Console.ReadLine() |> ignore 0