+static void
+sparse_map_decoder (struct tar_stat_info *st,
+ char const *keyword,
+ char const *arg,
+ size_t size __attribute__((unused)))
+{
+ int offset = 1;
+
+ st->sparse_map_avail = 0;
+ while (1)
+ {
+ uintmax_t u;
+ char *delim;
+ struct sp_array e;
+
+ if (!ISDIGIT (*arg))
+ {
+ ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
+ keyword, arg));
+ return;
+ }
+
+ errno = 0;
+ u = strtoumax (arg, &delim, 10);
+ if (offset)
+ {
+ e.offset = u;
+ if (!(u == e.offset && errno != ERANGE))
+ {
+ out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t));
+ return;
+ }
+ }
+ else
+ {
+ e.numbytes = u;
+ if (!(u == e.numbytes && errno != ERANGE))
+ {
+ out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t));
+ return;
+ }
+ if (st->sparse_map_avail < st->sparse_map_size)
+ st->sparse_map[st->sparse_map_avail++] = e;
+ else
+ {
+ ERROR ((0, 0, _("Malformed extended header: excess %s=%s"),
+ keyword, arg));
+ return;
+ }
+ }
+
+ offset = !offset;
+
+ if (*delim == 0)
+ break;
+ else if (*delim != ',')
+ {
+ ERROR ((0, 0,
+ _("Malformed extended header: invalid %s: unexpected delimiter %c"),
+ keyword, *delim));
+ return;
+ }
+
+ arg = delim + 1;
+ }
+
+ if (!offset)
+ ERROR ((0, 0,
+ _("Malformed extended header: invalid %s: odd number of values"),
+ keyword));
+}
+
+static void
+dumpdir_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ xheader_print_n (xhdr, keyword, data, dumpdir_size (data));
+}
+
+static void
+dumpdir_decoder (struct tar_stat_info *st,
+ char const *keyword __attribute__((unused)),
+ char const *arg,
+ size_t size)
+{
+ st->dumpdir = xmalloc (size);
+ memcpy (st->dumpdir, arg, size);
+}
+
+static void
+volume_label_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ code_string (data, keyword, xhdr);
+}
+
+static void
+volume_label_decoder (struct tar_stat_info *st,
+ char const *keyword __attribute__((unused)),
+ char const *arg,
+ size_t size __attribute__((unused)))
+{
+ decode_string (&volume_label, arg);
+}
+
+static void
+volume_size_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ off_t const *v = data;
+ code_num (*v, keyword, xhdr);
+}
+
+static void
+volume_size_decoder (struct tar_stat_info *st,
+ char const *keyword,
+ char const *arg, size_t size)
+{
+ uintmax_t u;
+ if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword))
+ continued_file_size = u;
+}
+
+/* FIXME: Merge with volume_size_coder */
+static void
+volume_offset_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ off_t const *v = data;
+ code_num (*v, keyword, xhdr);
+}
+
+static void
+volume_offset_decoder (struct tar_stat_info *st,
+ char const *keyword,
+ char const *arg, size_t size)
+{
+ uintmax_t u;
+ if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword))
+ continued_file_offset = u;
+}
+
+static void
+volume_filename_decoder (struct tar_stat_info *st,
+ char const *keyword __attribute__((unused)),
+ char const *arg,
+ size_t size __attribute__((unused)))
+{
+ decode_string (&continued_file_name, arg);
+}
+
+static void
+sparse_major_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ code_num (st->sparse_major, keyword, xhdr);
+}
+
+static void
+sparse_major_decoder (struct tar_stat_info *st,
+ char const *keyword,
+ char const *arg,
+ size_t size)
+{
+ uintmax_t u;
+ if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword))
+ st->sparse_major = u;
+}
+
+static void
+sparse_minor_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ code_num (st->sparse_minor, keyword, xhdr);
+}
+
+static void
+sparse_minor_decoder (struct tar_stat_info *st,
+ char const *keyword,
+ char const *arg,
+ size_t size)
+{
+ uintmax_t u;
+ if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword))
+ st->sparse_minor = u;
+}
+