fix bug with length-prefixed string as the last field
This commit is contained in:
parent
0b8ec4aa89
commit
1ef493f282
1 changed files with 28 additions and 2 deletions
30
src/srf.zig
30
src/srf.zig
|
|
@ -87,6 +87,8 @@ pub const Value = union(enum) {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
pub fn parse(allocator: std.mem.Allocator, str: []const u8, state: *ParseState, delimiter: u8, options: ParseOptions) ParseError!ValueWithMetaData {
|
pub fn parse(allocator: std.mem.Allocator, str: []const u8, state: *ParseState, delimiter: u8, options: ParseOptions) ParseError!ValueWithMetaData {
|
||||||
|
const debug = str.len > 2 and str[0] == '1' and str[1] == '1';
|
||||||
|
if (debug) log.debug("parsing {s}", .{str});
|
||||||
const type_val_sep_raw = std.mem.indexOfScalar(u8, str, ':');
|
const type_val_sep_raw = std.mem.indexOfScalar(u8, str, ':');
|
||||||
if (type_val_sep_raw == null) {
|
if (type_val_sep_raw == null) {
|
||||||
try parseError(allocator, options, "no type data or value after key", state.*);
|
try parseError(allocator, options, "no type data or value after key", state.*);
|
||||||
|
|
@ -144,7 +146,7 @@ pub const Value = union(enum) {
|
||||||
const val = it.first();
|
const val = it.first();
|
||||||
// we need to advance the column/partial_line_column of our parsing state
|
// we need to advance the column/partial_line_column of our parsing state
|
||||||
const total_chars = metadata.len + 1 + val.len;
|
const total_chars = metadata.len + 1 + val.len;
|
||||||
log.debug("num total_chars: {d}", .{total_chars});
|
// log.debug("num total_chars: {d}", .{total_chars});
|
||||||
state.column += total_chars;
|
state.column += total_chars;
|
||||||
state.partial_line_column += total_chars;
|
state.partial_line_column += total_chars;
|
||||||
const val_trimmed = std.mem.trim(u8, val, &std.ascii.whitespace);
|
const val_trimmed = std.mem.trim(u8, val, &std.ascii.whitespace);
|
||||||
|
|
@ -204,18 +206,21 @@ pub const Value = union(enum) {
|
||||||
.error_parsing = true,
|
.error_parsing = true,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
if (debug) log.debug("found fixed string size {d}. State {f}", .{ size, state });
|
||||||
// Update again for number of bytes. All failures beyond this point are
|
// Update again for number of bytes. All failures beyond this point are
|
||||||
// fatal, so this is safe.
|
// fatal, so this is safe.
|
||||||
state.column += size;
|
state.column += size;
|
||||||
state.partial_line_column += size;
|
state.partial_line_column += size;
|
||||||
|
if (debug) log.debug("New state {f}", .{state});
|
||||||
|
|
||||||
// If we are being asked specifically for bytes, we no longer care about
|
// If we are being asked specifically for bytes, we no longer care about
|
||||||
// delimiters. We just want raw bytes. This might adjust our line/column
|
// delimiters. We just want raw bytes. This might adjust our line/column
|
||||||
// in the parse state
|
// in the parse state
|
||||||
const rest_of_data = str[type_val_sep + 1 ..];
|
const rest_of_data = str[type_val_sep + 1 ..];
|
||||||
if (rest_of_data.len > size) {
|
if (rest_of_data.len >= size) {
|
||||||
// We fit on this line, everything is "normal"
|
// We fit on this line, everything is "normal"
|
||||||
const val = rest_of_data[0..size];
|
const val = rest_of_data[0..size];
|
||||||
|
if (debug) log.debug("val {s}", .{val});
|
||||||
return .{
|
return .{
|
||||||
.item_value = .{ .string = val },
|
.item_value = .{ .string = val },
|
||||||
};
|
};
|
||||||
|
|
@ -843,3 +848,24 @@ test "format all the things" {
|
||||||
defer parsed_compact.deinit();
|
defer parsed_compact.deinit();
|
||||||
try std.testing.expectEqualDeep(records, parsed_compact.records.items);
|
try std.testing.expectEqualDeep(records, parsed_compact.records.items);
|
||||||
}
|
}
|
||||||
|
test "compact format length-prefixed string as last field" {
|
||||||
|
// When a length-prefixed value is the last field on the line,
|
||||||
|
// rest_of_data.len == size exactly. The check on line 216 uses
|
||||||
|
// strict > instead of >=, falling through to the multi-line path
|
||||||
|
// where size - rest_of_data.len - 1 underflows.
|
||||||
|
const data =
|
||||||
|
\\#!srfv1
|
||||||
|
\\name::alice,desc:5:world
|
||||||
|
;
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var reader = std.Io.Reader.fixed(data);
|
||||||
|
const records = try parse(&reader, allocator, .{});
|
||||||
|
defer records.deinit();
|
||||||
|
try std.testing.expectEqual(@as(usize, 1), records.records.items.len);
|
||||||
|
const rec = records.records.items[0];
|
||||||
|
try std.testing.expectEqual(@as(usize, 2), rec.fields.len);
|
||||||
|
try std.testing.expectEqualStrings("name", rec.fields[0].key);
|
||||||
|
try std.testing.expectEqualStrings("alice", rec.fields[0].value.?.string);
|
||||||
|
try std.testing.expectEqualStrings("desc", rec.fields[1].key);
|
||||||
|
try std.testing.expectEqualStrings("world", rec.fields[1].value.?.string);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue