defmodule DataUrl do @moduledoc """ Struct and functions for representing and parsing data: URLs """ @default_mime_type "text/plain;charset=US-ASCII" defstruct mime_type: @default_mime_type, data: "" @type t() :: %DataUrl{ mime_type: String.t(), data: binary() } @doc """ Parse a data: URL into a %DataUrl{} struct """ @spec parse(String.t()) :: {:ok, DataUrl.t()} | {:error, any()} def parse("data:" <> rest) do String.split(rest, ",", parts: 2) |> parse_parts end def parse(_), do: {:error, "missing \"data:\" scheme"} defp parse_parts([_]), do: {:error, "missing comma"} defp parse_parts([prefix, data]) do with {:ok, data} <- parse_data(String.ends_with?(prefix, ";base64"), data), prefix <- String.replace_suffix(prefix, ";base64", "") do {:ok, %DataUrl{mime_type: get_mime_type(prefix), data: data}} else :error -> {:error, "invalid base64"} x -> {:error, {"unknown error", x}} end end defp get_mime_type(""), do: @default_mime_type defp get_mime_type(mime_type) when is_binary(mime_type), do: mime_type defp parse_data(true, data), do: Base.decode64(data) defp parse_data(false, data), do: {:ok, URI.decode(data)} end