start to abstract the decoding/encoding part. create modules for compression algorithms

This commit is contained in:
niamtokik
2021-03-30 19:16:24 +00:00
parent fded5d2e4f
commit 6044e2827b
15 changed files with 198 additions and 9 deletions

3
.gitignore vendored
View File

@@ -22,6 +22,7 @@ erl_crash.dump
# Ignore package tarball (built via "mix hex.build").
dotzip-*.tar
# Temporary files for e.g. tests
/tmp
**~

View File

@@ -16,14 +16,28 @@ defmodule Dotzip do
decode(data)
end
def encode(_data) do
def encode(data) do
{:error, :not_supported}
end
def encode_file(_file) do
{:error, :not_supported}
end
def end_central_directory?(<<signature::binary-size(4), _::bitstring>>) do
end_central_directory = Dotzip.EndCentralDirectory.signature()
signature == end_central_directory
end
def central_directory_header?(<<signature::binary-size(4), _::bitstring>>) do
central_directory_header = Dotzip.CentralDirectoryHeader.signature()
signature == central_directory_header
end
def local_file_header?(<<signature::binary-size(4), _::bitstring>>) do
local_file_header = Dotzip.LocalFileHeader.signature()
signature == local_file_header
end
end

View File

@@ -1,6 +1,6 @@
defmodule Dotzip.CentralDirectoryHeader do
defp signature() do
def signature() do
<< 0x50, 0x4b, 0x01, 0x02 >>
end

View File

@@ -0,0 +1,9 @@
defmodule Dotzip.Compression.Bzip2 do
def compress(_data) do
{:error, :not_supported}
end
def decompression(_data) do
{:error, :not_supported}
end
end

View File

@@ -0,0 +1,9 @@
defmodule Dotzip.Compression.Deflating do
def compress(_data) do
{:error, :not_supported}
end
def decompression(_data) do
{:error, :not_supported}
end
end

View File

@@ -0,0 +1,9 @@
defmodule Dotzip.Compression.EnhancedDeflating do
def compress(_data) do
{:error, :not_supported}
end
def decompression(_data) do
{:error, :not_supported}
end
end

View File

@@ -0,0 +1,9 @@
defmodule Dotzip.Compression.Expanding do
def compress(_data) do
{:error, :not_supported}
end
def decompression(_data) do
{:error, :not_supported}
end
end

View File

@@ -0,0 +1,9 @@
defmodule Dotzip.Compression.Imploding do
def compress(_data) do
{:error, :not_supported}
end
def decompression(_data) do
{:error, :not_supported}
end
end

View File

@@ -0,0 +1,9 @@
defmodule Dotzip.Compression.Lzma do
def compress(_data) do
{:error, :not_supported}
end
def decompression(_data) do
{:error, :not_supported}
end
end

View File

@@ -0,0 +1,9 @@
defmodule Dotzip.Compression.Ppmd do
def compress(_data) do
{:error, :not_supported}
end
def decompression(_data) do
{:error, :not_supported}
end
end

View File

@@ -0,0 +1,9 @@
defmodule Dotzip.Compression.Unshrinking do
def compress(_data) do
{:error, :not_supported}
end
def decompression(_data) do
{:error, :not_supported}
end
end

View File

@@ -0,0 +1,9 @@
defmodule Dotzip.Compression.Wavpack do
def compress(_data) do
{:error, :not_supported}
end
def decompression(_data) do
{:error, :not_supported}
end
end

View File

@@ -1,42 +1,82 @@
defmodule Dotzip.EndCentralDirectory do
def signature() do
<< 0x50, 0x4b, 0x05, 0x06 >>
end
defp signature(<< 0x50, 0x4b, 0x05, 0x06, rest::bitstring >>) do
{:ok, %{}, rest}
end
defp encode_signature(data) when is_map(data) do
{:ok, data, signature()}
end
defp number_disk({:ok, data, << number_disk::little-size(16), rest::bitstring >>}) do
{:ok, Map.put(data, :number_disk, number_disk), rest}
end
defp encode_number_disk({:ok, %{ :number_disk => number_disk } = data, buffer}) do
{:ok, data, <<buffer::bitstring, number_disk::little-size(16)>>}
end
defp number_disk_start({:ok, data, << number_disk::little-size(16), rest::bitstring >>}) do
{:ok, Map.put(data, :number_disk_start, number_disk), rest}
end
defp encode_number_disk_start({:ok, %{ :number_disk_start => number_disk_start } = data, buffer}) do
{:ok, data, <<buffer::bitstring, number_disk_start::little-size(16)>> }
end
defp total_entries_disk({:ok, data, << total_entries_disk::little-size(16), rest::bitstring >>}) do
{:ok, Map.put(data, :total_entries_disk, total_entries_disk), rest}
end
defp encode_total_entries_disk({:ok, %{ :total_entries_disk => total_entries_disk } = data, buffer}) do
{:ok, data, <<buffer::bitstring, total_entries_disk::little-size(16)>> }
end
defp total_entries({:ok, data, << total_entries::little-size(16), rest::bitstring >>}) do
{:ok, Map.put(data, :total_entries, total_entries), rest}
end
defp encode_total_entries({:ok, %{ :total_entries => total_entries } = data, buffer }) do
{:ok, data, <<buffer::bitstring, total_entries::little-size(16)>> }
end
defp size({:ok, data, << size::little-size(32), rest::bitstring >>}) do
{:ok, Map.put(data, :size, size), rest}
end
defp encode_size({:ok, %{ :size => size } = data, buffer}) do
{:ok, data, <<buffer::bitstring, size::little-size(32)>>}
end
defp offset({:ok, data, << offset::little-size(32), rest::bitstring >>}) do
{:ok, Map.put(data, :offset, offset), rest}
end
defp encode_offset({:ok, %{ :offset => offset } = data, buffer}) do
{:ok, data, <<buffer::bitstring, offset::little-size(32)>> }
end
defp comment_length({:ok, data, << comment_length::little-size(16), rest::bitstring >>}) do
{:ok, Map.put(data, :comment_length, comment_length), rest}
end
defp encode_comment_length({:ok, %{ :comment_length => comment_length } = data, buffer}) do
{:ok, data, <<buffer::bitstring, comment_length::little-size(16)>> }
end
defp comment({:ok, data, rest}) do
%{ :comment_length => comment_length } = data
<< comment::binary-size(comment_length), r::bitstring >> = rest
{:ok, Map.put(data, :comment, comment), r}
end
defp encode_comment({:ok, %{ :comment => comment, :comment_length => comment_length} = data, buffer}) do
{:ok, data, <<buffer::bitstring, comment::binary-size(comment_length)>>}
end
def decode(file) do
{:ok, end_central_directory, rest} = signature(file)
@@ -49,5 +89,17 @@ defmodule Dotzip.EndCentralDirectory do
|> comment_length()
|> comment()
end
def encode(data) do
encode_signature(data)
|> encode_number_disk()
|> encode_number_disk_start()
|> encode_total_entries_disk()
|> encode_total_entries()
|> encode_size()
|> encode_offset()
|> encode_comment_length()
|> encode_comment()
end
end

13
lib/dotzip/format.ex Normal file
View File

@@ -0,0 +1,13 @@
# https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-dosdatetimetofiletime?redirectedfrom=MSDN
defmodule Dotzip.Format.Msdos do
def decode_date(<<day::size(5), month::size(4), offset::size(7)>>) do
Date.new(1980+offset, month, day)
end
def decode_time(<<second::size(5), minute::size(6), hour::size(5)>>) do
Time.new(hour, minute, second*2, 0)
end
end

View File

@@ -1,6 +1,6 @@
defmodule Dotzip.LocalFileHeader do
defp signature() do
def signature() do
<< 0x50, 0x4b, 0x03, 0x04 >>
end
@@ -23,13 +23,41 @@ defmodule Dotzip.LocalFileHeader do
defp purpose_flag({:ok, data, << purpose_flag::binary-size(2), rest::bitstring >>}) do
{:ok, Map.put(data, :purpose_flag, purpose_flag), rest}
end
defp encode_purpose_flag({:ok, %{ :purpose_flag => purpose_flag } = data, buffer }) do
{:ok, data, <<buffer::bitstring, purpose_flag::binary-size(2)>> }
end
defp compression_method({:ok, data, << compression_method::binary-size(2), rest::bitstring >>}) do
{:ok, Map.put(data, :compression_method, compression_method), rest}
defp compression_method_type(data) do
case data do
0 -> :stored
1 -> :shrunk
2 -> :reduced_factor1
3 -> :reduced_factor2
4 -> :reduced_factor3
5 -> :reduced_factor4
6 -> :imploded
7 -> :tokenizing
8 -> :deflated
9 -> :deflate64
10 -> :pkware
11 -> :reserved
12 -> :bzip2
13 -> :reserved
14 -> :lzma
15 -> :reserved
16 -> :reserved
17 -> :reserved
18 -> :terse
19 -> :lz77
97 -> :wavpack
98 -> :ppmd
end
end
defp compression_method({:ok, data, << compression_method::little-size(16), rest::bitstring >>}) do
method = compression_method_type(compression_method)
{:ok, Map.put(data, :compression_method, method), rest}
end
defp encode_compression_method({:ok, %{ :compression_method => compression_method } = data, buffer}) do
@@ -44,7 +72,7 @@ defmodule Dotzip.LocalFileHeader do
{:ok, data, <<buffer::bitstring, last_modification_time::little-size(16)>>}
end
defp last_modification_date({:ok, data, << last_modification_date::little-size(16), rest::bitstring >>}) do
defp last_modification_date({:ok, data, << last_modification_date::little-binary-size(2), rest::bitstring >>}) do
{:ok, Map.put(data, :last_modification_date, last_modification_date), rest}
end