Path85

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

 

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注