my $ref_str = shift;
# Check for special objects before attempting general parsing.
- if ($ref_str =~ m/^zero\[(\d+)\+(\d+)\]$/) {
- return "\0" x ($2 + 0);
+ if ($ref_str =~ m/^zero\[((\d+)\+)?(\d+)\]$/) {
+ return "\0" x ($3 + 0);
}
# Try to parse the object reference string into constituent pieces. The
# If a range was specified, then only a subset of the bytes of the object
# are desired. Extract just the desired bytes.
if ($range) {
- if ($range !~ m/^\[(\d+)\+(\d+)\]$/) {
+ if ($range !~ m/^\[((\d+)\+)?(\d+)\]$/) {
die "Malformed object range: $range";
}
my $object_size = length $contents;
- my ($start, $length) = ($1 + 0, $2 + 0);
+ my ($start, $length);
+ if ($1 ne "") {
+ ($start, $length) = ($2 + 0, $3 + 0);
+ } else {
+ ($start, $length) = (0, $3 + 0);
+ }
if ($start >= $object_size || $start + $length > $object_size) {
die "Object range $range falls outside object bounds "
. "(actual size $object_size)";
not fall within the original object. The slice specification should be
appended to an object name, for example:
a704eeae-97f2-4f30-91a4-d4473956366b/000001ad[264+1000]
-selects only bytes 264..1263 from the original object.
+selects only bytes 264..1263 from the original object. As an
+abbreviation, the slice syntax
+ [<length>]
+is shorthand for
+ [0+<length>]
Both a checksum and a slice can be used. In this case, the checksum is
given first, followed by the slice. The checksum is computed over the
This represents an object consisting entirely of zeroes. The zero
object must have a slice specification appended to indicate the size of
the object. For example
- zero[0+1024]
+ zero[1024]
represents a block consisting of 1024 null bytes. A checksum should not
-be given.
+be given. The slice syntax should use the abbreviated length-only form.
FILE METADATA LISTING
@staticmethod
def parse_ref(refstr):
- m = re.match(r"^zero\[(\d+)\+(\d+)\]$", refstr)
+ m = re.match(r"^zero\[(\d+)\]$", refstr)
if m:
- return ("zero", None, None, (int(m.group(1)), int(m.group(2))))
+ return ("zero", None, None, (0, int(m.group(1))))
- m = re.match(r"^([-0-9a-f]+)\/([0-9a-f]+)(\(\S+\))?(\[(\d+)\+(\d+)\])?$", refstr)
+ m = re.match(r"^([-0-9a-f]+)\/([0-9a-f]+)(\(\S+\))?(\[((\d+)\+)?(\d+)\])?$", refstr)
if not m: return
segment = m.group(1)
checksum = checksum.lstrip("(").rstrip(")")
if slice is not None:
- slice = (int(m.group(5)), int(m.group(6)))
+ if m.group(5) is None:
+ # Abbreviated slice
+ slice = (0, int(m.group(7)))
+ else:
+ slice = (int(m.group(6)), int(m.group(7)))
return (segment, object, checksum, slice)
if (range_valid) {
char buf[64];
- sprintf(buf, "[%zu+%zu]", range_start, range_length);
+ if (range_start == 0) {
+ sprintf(buf, "[%zu]", range_length);
+ } else {
+ sprintf(buf, "[%zu+%zu]", range_start, range_length);
+ }
result += buf;
}
s = t;
while (*t >= '0' && *t <= '9')
t++;
- if (*t != '+')
- return ObjectReference();
- string val(s, t - s);
- range1 = atoll(val.c_str());
+ // Abbreviated-length only range?
+ if (*t == ']') {
+ string val(s, t - s);
+ range2 = atoll(val.c_str());
+ } else {
+ if (*t != '+')
+ return ObjectReference();
- t++;
- s = t;
- while (*t >= '0' && *t <= '9')
- t++;
- if (*t != ']')
- return ObjectReference();
+ string val(s, t - s);
+ range1 = atoll(val.c_str());
- val = string(s, t - s);
- range2 = atoll(val.c_str());
+ t++;
+ s = t;
+ while (*t >= '0' && *t <= '9')
+ t++;
+ if (*t != ']')
+ return ObjectReference();
+
+ val = string(s, t - s);
+ range2 = atoll(val.c_str());
+ }
have_range = true;
}
* range specifier is given, then by default the entire object is used.
* <range> ::= <start> "+" <length>
* Both <start> and <length> are decimal values. If included, the range is
- * enclosed in brackets.
+ * enclosed in brackets. As an abbreviation, if <start> is 0 then the range
+ * can be given as just <length> (no "+" needed).
*
* When both a checksum and a range are included, note that the checksum is
* taken over the entire original object, before the range is taken into