+ while (where != lim && ISODIGIT (*where));
+
+ /* Parse the output of older tars, which output negative values
+ in two's complement octal. This method works only if the
+ type has the same number of bits as it did on the host that
+ created the tar file, but that's the best we can do. */
+ if (maxval < value && value - maxval <= minus_minval)
+ {
+ value = minus_minval - (value - maxval);
+ negative = 1;
+ }
+ }
+ else if (*where == '-' || *where == '+')
+ {
+ int dig;
+ negative = *where++ == '-';
+ while (where != lim
+ && (dig = base64_map[(unsigned char) *where]) < 64)
+ {
+ if (value << LG_64 >> LG_64 != value)
+ {
+ ERROR ((0, 0,
+ _("Archive signed base 64 string `%.*s' is out of %s range"),
+ (int) digs, where0, type));
+ return -1;
+ }
+ value = (value << LG_64) | dig;
+ where++;
+ }
+ }
+
+ if (where != lim && *where && !ISSPACE ((unsigned char) *where))
+ {
+ if (type)
+ {
+ char buf[1000]; /* Big enough to represent any header. */
+ static struct quoting_options *o;
+
+ if (!o)
+ {
+ o = clone_quoting_options (0);
+ set_quoting_style (o, c_quoting_style);
+ }
+
+ while (where0 != lim && ! lim[-1])
+ lim--;
+ quotearg_buffer (buf, sizeof buf, where0, lim - where, o);
+ ERROR ((0, 0,
+ _("Archive contains `%.*s' where numeric %s value expected"),
+ (int) sizeof buf, buf, type));
+ }
+
+ return -1;
+ }
+
+ if (value <= (negative ? minus_minval : maxval))
+ return negative ? -value : value;
+
+ if (type)
+ {
+ char minval_buf[UINTMAX_STRSIZE_BOUND + 1];
+ char maxval_buf[UINTMAX_STRSIZE_BOUND];
+ char value_buf[UINTMAX_STRSIZE_BOUND + 1];
+ char *minval_string = STRINGIFY_BIGINT (minus_minval, minval_buf + 1);
+ char *value_string = STRINGIFY_BIGINT (value, value_buf + 1);
+ if (negative)
+ *--value_string = '-';
+ if (minus_minval)
+ *--minval_string = '-';
+ ERROR ((0, 0, _("Archive value %s is out of %s range %s..%s"),
+ value_string, type,
+ minval_string, STRINGIFY_BIGINT (maxval, maxval_buf)));
+ }
+
+ return -1;