From fdd45a8942de49264ba38868f869d11be15ef712bca7454fd5d21c171b016795 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Fri, 4 Apr 2025 21:55:56 +0300 Subject: [PATCH] Ability to compare strings in schemas --- c/lib/schema.c | 28 ++++++++++++++++++++++++++++ go/schema/check.go | 23 ++++++++++++++++++++++- spec/schema/cmds.texi | 3 +++ spec/schema/tcl.texi | 3 +++ tcl/schema2bin | 10 ++++++++++ tcl/schemas/encrypted.tcl | 3 +-- tcl/schemas/pub.tcl | 3 +-- 7 files changed, 68 insertions(+), 5 deletions(-) diff --git a/c/lib/schema.c b/c/lib/schema.c index 2d8c1eb..7251dd3 100644 --- a/c/lib/schema.c +++ b/c/lib/schema.c @@ -15,6 +15,7 @@ #include #include +#include #include "atom.h" #include "frombe.h" @@ -22,6 +23,7 @@ #include "schema.h" static const char CmdEach[] = "*"; +static const char CmdEq[] = "="; static const char CmdExists[] = "E"; static const char CmdGT[] = ">"; static const char CmdLT[] = "<"; @@ -243,6 +245,32 @@ Eached: } err.msg = "TAKE"; err.code = KEKSSchemaErrNo; + } else if (KEKSStrEqual(&(schema->list[idxSchema].atom), CmdEq)) { + err.msg = "EQ"; + if ((*taken) == SIZE_MAX) { + err.code = KEKSSchemaErrNo; + } else { + idxSchema = schema->list[idxSchema].next; + if (idxSchema == 0) { + err.code = KEKSSchemaErrInvalidSchema; + err.msg = "wrong number of args"; + return err; + } + err.offSchema = schema->offsets[idxSchema]; + if (schema->list[idxSchema].atom.typ != KEKSItemStr) { + err.code = KEKSSchemaErrInvalidSchema; + err.msg = "non-str EQ"; + return err; + } + err.code = ((schema->list[idxSchema].atom.v.str.len == + data->list[*taken].atom.v.str.len) && + (memcmp( + schema->list[idxSchema].atom.v.str.ptr, + data->list[*taken].atom.v.str.ptr, + schema->list[idxSchema].atom.v.str.len) == 0)) ? + KEKSSchemaErrNo : + KEKSSchemaErrInvalidData; + } } else if (KEKSStrEqual(&(schema->list[idxSchema].atom), CmdEach)) { err.msg = "EACH"; (*eachInList) = false; diff --git a/go/schema/check.go b/go/schema/check.go index df779be..9e0f2e6 100644 --- a/go/schema/check.go +++ b/go/schema/check.go @@ -30,6 +30,7 @@ import ( const ( CmdEach = "*" + CmdEq = "=" CmdExists = "E" CmdGT = ">" CmdLT = "<" @@ -107,6 +108,26 @@ func Check(schemaName string, schemas map[string][][]any, data any) error { default: return fmt.Errorf("%s: %d: %s: non-iterable", schemaName, i, cmd) } + case CmdEq: + if vs == nil { + continue + } + if len(act) != 2 { + return fmt.Errorf("%s: %d: %s: wrong number of args", schemaName, i, cmd) + } + expect, ok := act[1].(string) + if !ok { + return fmt.Errorf("%s: %d: %s: bad str: %+v", schemaName, i, cmd, act[1]) + } + for _, v := range vs { + got, ok := v.(string) + if !ok { + return fmt.Errorf("%s: %d: %s: not str: %T", schemaName, i, cmd, v) + } + if got != expect { + return fmt.Errorf("%s: %d: %s: !=", schemaName, i, cmd) + } + } case CmdType: if vs == nil { continue @@ -193,10 +214,10 @@ func Check(schemaName string, schemas map[string][][]any, data any) error { if vs == nil { continue } - var expect int64 if len(act) != 2 { return fmt.Errorf("%s: %d: %s: wrong number of args", schemaName, i, cmd) } + var expect int64 switch v := act[1].(type) { case uint64: expect = int64(v) diff --git a/spec/schema/cmds.texi b/spec/schema/cmds.texi index 4d1d90e..f37f324 100644 --- a/spec/schema/cmds.texi +++ b/spec/schema/cmds.texi @@ -59,6 +59,9 @@ maximal time precision. "p" is integer with following possible values: @item 18 -- up to attoseconds; @end itemize +@item = v +Check that chosen (if it exists) string element's value equals to "v". + @end table For example let's check "our" structure, described in CDDL as: diff --git a/spec/schema/tcl.texi b/spec/schema/tcl.texi index c529314..05d5862 100644 --- a/spec/schema/tcl.texi +++ b/spec/schema/tcl.texi @@ -64,4 +64,7 @@ Check that "k" element's length is greater than zero. @item IS-SET k Check that "k" is non-empty set (map with NIL values). +@item STR= k v +Check that "k" is a string with value "v". + @end table diff --git a/tcl/schema2bin b/tcl/schema2bin index 6df461e..159054d 100755 --- a/tcl/schema2bin +++ b/tcl/schema2bin @@ -28,6 +28,7 @@ proc TAKE {v} { proc EXISTS {} {return {{LIST {{STR E}}}}} proc !EXISTS {} {return {{LIST {{STR !E}}}}} proc EACH {} {return {{LIST {{STR *}}}}} +proc EQ {v} {subst {{LIST {{STR =} {STR $v}}}}} proc TYPE {vs} { set l {{STR T}} foreach v $vs { @@ -70,6 +71,15 @@ proc !HAS {k} { }] } +proc STR= {k v} { + evals [subst { + {TAKE $k} + {TYPE {STR}} + {TAKE $k} + {EQ $v} + }] +} + proc LEN= {k l} { evals [subst { {TAKE $k} diff --git a/tcl/schemas/encrypted.tcl b/tcl/schemas/encrypted.tcl index c864fea..4c218c3 100644 --- a/tcl/schemas/encrypted.tcl +++ b/tcl/schemas/encrypted.tcl @@ -37,8 +37,7 @@ balloon-cost { kem-balloon-blake2b-hkdf { {HAS a} - {TYPE= a {STR}} - {!EMPTY a} + {STR= a balloon-blake2b-hkdf} {HAS cek} {TYPE= cek {BIN}} {HAS salt} diff --git a/tcl/schemas/pub.tcl b/tcl/schemas/pub.tcl index 376d65b..4ca815a 100644 --- a/tcl/schemas/pub.tcl +++ b/tcl/schemas/pub.tcl @@ -21,8 +21,7 @@ pub { load { {HAS t} - {TYPE= t {STR}} - {!EMPTY t} + {STR= t pub} {HAS v} {SCHEMA= v pub-load} } -- 2.48.1