zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

types.ex (2563B)


      1 defmodule HPAX.Types do
      2   @moduledoc false
      3 
      4   import Bitwise, only: [<<<: 2]
      5 
      6   alias HPAX.Huffman
      7 
      8   # This is used as a macro and not an inlined function because we want to be able to use it in
      9   # guards.
     10   defmacrop power_of_two(n) do
     11     quote do: 1 <<< unquote(n)
     12   end
     13 
     14   ## Encoding
     15 
     16   @spec encode_integer(non_neg_integer(), 1..8) :: bitstring()
     17   def encode_integer(integer, prefix)
     18 
     19   def encode_integer(integer, prefix) when integer < power_of_two(prefix) - 1 do
     20     <<integer::size(prefix)>>
     21   end
     22 
     23   def encode_integer(integer, prefix) do
     24     initial = power_of_two(prefix) - 1
     25     remaining = integer - initial
     26     <<initial::size(prefix), encode_remaining_integer(remaining)::binary>>
     27   end
     28 
     29   defp encode_remaining_integer(remaining) when remaining >= 128 do
     30     first = rem(remaining, 128) + 128
     31     <<first::8, encode_remaining_integer(div(remaining, 128))::binary>>
     32   end
     33 
     34   defp encode_remaining_integer(remaining) do
     35     <<remaining::8>>
     36   end
     37 
     38   @spec encode_binary(binary(), boolean()) :: iodata()
     39   def encode_binary(binary, huffman?) do
     40     binary = if huffman?, do: Huffman.encode(binary), else: binary
     41     huffman_bit = if huffman?, do: 1, else: 0
     42     binary_size = encode_integer(byte_size(binary), 7)
     43     [<<huffman_bit::1, binary_size::bitstring>>, binary]
     44   end
     45 
     46   ## Decoding
     47 
     48   @spec decode_integer(bitstring, 1..8) :: {:ok, non_neg_integer(), binary()} | :error
     49   def decode_integer(bitstring, prefix) when is_bitstring(bitstring) and prefix in 1..8 do
     50     with <<value::size(prefix), rest::binary>> <- bitstring do
     51       if value < power_of_two(prefix) - 1 do
     52         {:ok, value, rest}
     53       else
     54         decode_remaining_integer(rest, value, 0)
     55       end
     56     else
     57       _ -> :error
     58     end
     59   end
     60 
     61   defp decode_remaining_integer(<<0::1, value::7, rest::binary>>, int, m) do
     62     {:ok, int + (value <<< m), rest}
     63   end
     64 
     65   defp decode_remaining_integer(<<1::1, value::7, rest::binary>>, int, m) do
     66     decode_remaining_integer(rest, int + (value <<< m), m + 7)
     67   end
     68 
     69   defp decode_remaining_integer(_, _, _) do
     70     :error
     71   end
     72 
     73   @spec decode_binary(binary) :: {:ok, binary(), binary()} | :error
     74   def decode_binary(binary) when is_binary(binary) do
     75     with <<huffman_bit::1, rest::bitstring>> <- binary,
     76          {:ok, length, rest} <- decode_integer(rest, 7),
     77          <<contents::binary-size(length), rest::binary>> <- rest do
     78       contents =
     79         case huffman_bit do
     80           0 -> contents
     81           1 -> Huffman.decode(contents)
     82         end
     83 
     84       {:ok, contents, rest}
     85     else
     86       _ -> :error
     87     end
     88   end
     89 end