diff --git a/.gitignore b/.gitignore index 1f2781f..24fc553 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ erl_crash.dump # Ignore package tarball (built via "mix hex.build"). dotzip-*.tar - # Temporary files for e.g. tests /tmp + +**~ diff --git a/lib/dotzip.ex b/lib/dotzip.ex index 412c6ce..316f07c 100644 --- a/lib/dotzip.ex +++ b/lib/dotzip.ex @@ -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?(<>) do + end_central_directory = Dotzip.EndCentralDirectory.signature() + signature == end_central_directory + end + + def central_directory_header?(<>) do + central_directory_header = Dotzip.CentralDirectoryHeader.signature() + signature == central_directory_header + end + + def local_file_header?(<>) do + local_file_header = Dotzip.LocalFileHeader.signature() + signature == local_file_header + end end diff --git a/lib/dotzip/central_directory_header.ex b/lib/dotzip/central_directory_header.ex index 143fc71..430a906 100644 --- a/lib/dotzip/central_directory_header.ex +++ b/lib/dotzip/central_directory_header.ex @@ -1,6 +1,6 @@ defmodule Dotzip.CentralDirectoryHeader do - defp signature() do + def signature() do << 0x50, 0x4b, 0x01, 0x02 >> end diff --git a/lib/dotzip/compression/bzip2.ex b/lib/dotzip/compression/bzip2.ex new file mode 100644 index 0000000..868d329 --- /dev/null +++ b/lib/dotzip/compression/bzip2.ex @@ -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 diff --git a/lib/dotzip/compression/deflating.ex b/lib/dotzip/compression/deflating.ex new file mode 100644 index 0000000..5146027 --- /dev/null +++ b/lib/dotzip/compression/deflating.ex @@ -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 diff --git a/lib/dotzip/compression/enhanced_deflating.ex b/lib/dotzip/compression/enhanced_deflating.ex new file mode 100644 index 0000000..6321e78 --- /dev/null +++ b/lib/dotzip/compression/enhanced_deflating.ex @@ -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 diff --git a/lib/dotzip/compression/expanding.ex b/lib/dotzip/compression/expanding.ex new file mode 100644 index 0000000..0e3715b --- /dev/null +++ b/lib/dotzip/compression/expanding.ex @@ -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 diff --git a/lib/dotzip/compression/imploding.ex b/lib/dotzip/compression/imploding.ex new file mode 100644 index 0000000..67ba33a --- /dev/null +++ b/lib/dotzip/compression/imploding.ex @@ -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 diff --git a/lib/dotzip/compression/lzma.ex b/lib/dotzip/compression/lzma.ex new file mode 100644 index 0000000..4cfff2b --- /dev/null +++ b/lib/dotzip/compression/lzma.ex @@ -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 diff --git a/lib/dotzip/compression/ppmd.ex b/lib/dotzip/compression/ppmd.ex new file mode 100644 index 0000000..8649975 --- /dev/null +++ b/lib/dotzip/compression/ppmd.ex @@ -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 diff --git a/lib/dotzip/compression/unshrinking.ex b/lib/dotzip/compression/unshrinking.ex new file mode 100644 index 0000000..84a5087 --- /dev/null +++ b/lib/dotzip/compression/unshrinking.ex @@ -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 diff --git a/lib/dotzip/compression/wavpack.ex b/lib/dotzip/compression/wavpack.ex new file mode 100644 index 0000000..cc873ae --- /dev/null +++ b/lib/dotzip/compression/wavpack.ex @@ -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 diff --git a/lib/dotzip/end_central_directory.ex b/lib/dotzip/end_central_directory.ex index e5c69c5..00d2525 100644 --- a/lib/dotzip/end_central_directory.ex +++ b/lib/dotzip/end_central_directory.ex @@ -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, <>} + 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, <> } + 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, <> } + 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, <> } + 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, <>} + 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, <> } + 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, <> } + 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, <>} + 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 diff --git a/lib/dotzip/format.ex b/lib/dotzip/format.ex new file mode 100644 index 0000000..a298997 --- /dev/null +++ b/lib/dotzip/format.ex @@ -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(<>) do + Date.new(1980+offset, month, day) + end + + def decode_time(<>) do + Time.new(hour, minute, second*2, 0) + end + +end diff --git a/lib/dotzip/local_file_header.ex b/lib/dotzip/local_file_header.ex index a084487..4d25fa8 100644 --- a/lib/dotzip/local_file_header.ex +++ b/lib/dotzip/local_file_header.ex @@ -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, <> } 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, <>} 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