Skip to content

Commit 86ca5fe

Browse files
committed
[schema] support new schema for binary validation: binType,minDims,maxDims
1 parent c5c01db commit 86ca5fe

File tree

3 files changed

+268
-47
lines changed

3 files changed

+268
-47
lines changed

jdict.m

Lines changed: 14 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@
245245
if ~isempty(kindschema)
246246
obj.setschema(kindschema);
247247
elseif isempty(obj.schema)
248-
error('Unknown kind "%s" and no schema defined. Use: uuid, date, time, datetime, ipv4, ipv6, email, uri, posint, nonnegative', kindval);
248+
error('Unknown kind "%s" and no schema defined. Use: uuid, date, time, datetime, email, uri', kindval);
249249
end
250250
obj.setattr(char(36), 'kind', kindval);
251251
if (isempty(obj.data))
@@ -1322,60 +1322,27 @@
13221322

13231323
% predefined schemas for known kinds
13241324
function schema = getkindschema_(kind)
1325+
schema = [];
1326+
int = @(mn, mx) struct('type', 'integer', 'minimum', mn, 'maximum', mx);
1327+
obj = @(p, r) struct('type', 'object', 'properties', p, 'required', {r});
1328+
bintypes = {'uint8', 'int8', 'uint16', 'int16', 'uint32', 'int32', 'uint64', 'int64', 'single', 'double', 'logical'};
13251329
switch lower(kind)
1326-
case 'bytes'
1327-
schema = struct('type', 'array', 'items', struct('type', 'integer', 'minimum', 0, 'maximum', 255));
13281330
case 'uuid'
1329-
schema = struct('type', 'object', ...
1330-
'properties', struct( ...
1331-
'time_low', struct('type', 'integer', 'minimum', 0, 'maximum', 4294967295), ... % 32-bit
1332-
'time_mid', struct('type', 'integer', 'minimum', 0, 'maximum', 65535), ... % 16-bit
1333-
'time_high', struct('type', 'integer', 'minimum', 0, 'maximum', 65535), ... % 16-bit
1334-
'clock_seq', struct('type', 'integer', 'minimum', 0, 'maximum', 65535), ... % 16-bit
1335-
'node', struct('type', 'integer', 'minimum', 0, 'maximum', 281474976710655)), ... % 48-bit
1336-
'required', {{'time_low', 'time_mid', 'time_high', 'clock_seq', 'node'}});
1331+
schema = obj(struct('time_low', int(0, 4294967295), 'time_mid', int(0, 65535), 'time_high', int(0, 65535), 'clock_seq', int(0, 65535), 'node', int(0, 281474976710655)), {'time_low', 'time_mid', 'time_high', 'clock_seq', 'node'});
13371332
case 'date'
1338-
schema = struct('type', 'object', ...
1339-
'properties', struct( ...
1340-
'year', struct('type', 'integer', 'minimum', 1, 'maximum', 9999), ...
1341-
'month', struct('type', 'integer', 'minimum', 1, 'maximum', 12), ...
1342-
'day', struct('type', 'integer', 'minimum', 1, 'maximum', 31)), ...
1343-
'required', {{'year', 'month', 'day'}});
1333+
schema = obj(struct('year', int(1, 9999), 'month', int(1, 12), 'day', int(1, 31)), {'year', 'month', 'day'});
13441334
case 'time'
1345-
schema = struct('type', 'object', ...
1346-
'properties', struct( ...
1347-
'hour', struct('type', 'integer', 'minimum', 0, 'maximum', 23), ...
1348-
'min', struct('type', 'integer', 'minimum', 0, 'maximum', 59), ...
1349-
'sec', struct('type', 'number', 'minimum', 0, 'exclusiveMaximum', 60)), ...
1350-
'required', {{'hour', 'min', 'sec'}});
1335+
schema = obj(struct('hour', int(0, 23), 'min', int(0, 59), 'sec', struct('type', 'number', 'minimum', 0, 'exclusiveMaximum', 60)), {'hour', 'min', 'sec'});
13511336
case 'datetime'
1352-
schema = struct('type', 'object', ...
1353-
'properties', struct( ...
1354-
'year', struct('type', 'integer', 'minimum', 1, 'maximum', 9999), ...
1355-
'month', struct('type', 'integer', 'minimum', 1, 'maximum', 12), ...
1356-
'day', struct('type', 'integer', 'minimum', 1, 'maximum', 31), ...
1357-
'hour', struct('type', 'integer', 'minimum', 0, 'maximum', 23), ...
1358-
'min', struct('type', 'integer', 'minimum', 0, 'maximum', 59), ...
1359-
'sec', struct('type', 'number', 'minimum', 0, 'exclusiveMaximum', 60)), ...
1360-
'required', {{'year', 'month', 'day', 'hour', 'min', 'sec'}});
1337+
schema = obj(struct('year', int(1, 9999), 'month', int(1, 12), 'day', int(1, 31), 'hour', int(0, 23), 'min', int(0, 59), 'sec', struct('type', 'number', 'minimum', 0, 'exclusiveMaximum', 60)), {'year', 'month', 'day', 'hour', 'min', 'sec'});
13611338
case 'email'
1362-
schema = struct('type', 'object', ...
1363-
'properties', struct( ...
1364-
'user', struct('type', 'string', 'minLength', 1), ...
1365-
'domain', struct('type', 'string', 'pattern', '^[^@\s]+\.[^@\s]+$')), ...
1366-
'required', {{'user', 'domain'}});
1339+
schema = obj(struct('user', struct('type', 'string', 'minLength', 1), 'domain', struct('type', 'string', 'pattern', '^[^@\s]+\.[^@\s]+$')), {'user', 'domain'});
13671340
case 'uri'
1368-
schema = struct('type', 'object', ...
1369-
'properties', struct( ...
1370-
'scheme', struct('type', 'string', 'pattern', '^[a-zA-Z][a-zA-Z0-9+.-]*$'), ...
1371-
'host', struct('type', 'string', 'minLength', 1), ...
1372-
'port', struct('type', 'integer', 'minimum', 0, 'maximum', 65535), ...
1373-
'path', struct('type', 'string'), ...
1374-
'query', struct('type', 'string'), ...
1375-
'fragment', struct('type', 'string')), ...
1376-
'required', {{'scheme', 'host'}});
1341+
schema = obj(struct('scheme', struct('type', 'string', 'pattern', '^[a-zA-Z][a-zA-Z0-9+.-]*$'), 'host', struct('type', 'string', 'minLength', 1), 'port', int(0, 65535), 'path', struct('type', 'string'), 'query', struct('type', 'string'), 'fragment', struct('type', 'string')), {'scheme', 'host'});
13771342
otherwise
1378-
schema = [];
1343+
if ismember(lower(kind), bintypes)
1344+
schema = struct('binType', lower(kind));
1345+
end
13791346
end
13801347
end
13811348

jsonschema.m

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,15 @@
164164
end
165165
end
166166

167+
% binary type and dimensions
168+
if isnumeric(data) || islogical(data)
169+
[isvalid, errmsg] = validatebinary(data, schema, path);
170+
if ~isvalid
171+
valid = false;
172+
errors = [errors errmsg];
173+
end
174+
end
175+
167176
% string
168177
if ischar(data) || isa(data, 'string')
169178
[isvalid, errmsg] = validatestring(char(data), schema, path);
@@ -347,6 +356,59 @@
347356
end
348357
end
349358

359+
%% -------------------------------------------------------------------------
360+
function [valid, errors] = validatebinary(data, schema, path)
361+
362+
valid = true;
363+
errors = {};
364+
365+
% binType validation
366+
if isKey(schema, 'binType')
367+
bintype = schema('binType');
368+
validtypes = {'uint8', 'int8', 'uint16', 'int16', 'uint32', 'int32', 'uint64', 'int64', 'single', 'double', 'logical'};
369+
if ~ismember(bintype, validtypes)
370+
valid = false;
371+
errors{end + 1} = sprintf('%s: invalid binType "%s"', path, bintype);
372+
elseif ~(isnumeric(data) || islogical(data)) || ~strcmp(class(data), bintype)
373+
valid = false;
374+
errors{end + 1} = sprintf('%s: expected %s, got %s', path, bintype, class(data));
375+
end
376+
end
377+
378+
% minDims/maxDims validation
379+
actualsize = size(data);
380+
for dimtype = {'minDims', 'maxDims'}
381+
if isKey(schema, dimtype{1})
382+
dims = schema(dimtype{1});
383+
if iscell(dims)
384+
dims = [dims{:}];
385+
end
386+
if (length(dims) == 1)
387+
if (~isvector(data))
388+
errors{end + 1} = sprintf('%s: length of dim is %d, violates %s %d', path, i, length(actualsize), dimtype{1}, length(dims));
389+
else
390+
actualsize = max(actualsize);
391+
end
392+
end
393+
ismin = strcmp(dimtype{1}, 'minDims');
394+
checklen = min(length(actualsize), length(dims));
395+
if ismin
396+
actualsize = [actualsize ones(1, max(0, length(dims) - length(actualsize)))];
397+
checklen = length(dims);
398+
end
399+
for i = 1:checklen
400+
if (ismin && actualsize(i) < dims(i)) || (~ismin && actualsize(i) > dims(i))
401+
valid = false;
402+
errors{end + 1} = sprintf('%s: dim %d is %d, violates %s %d', path, i, actualsize(i), dimtype{1}, dims(i));
403+
end
404+
end
405+
if ~ismin && length(actualsize) > length(dims) && any(actualsize(length(dims) + 1:end) > 1)
406+
valid = false;
407+
errors{end + 1} = sprintf('%s: has %d dimensions, %s only specifies %d', path, ndims(data), dimtype{1}, length(dims));
408+
end
409+
end
410+
end
411+
350412
%% -------------------------------------------------------------------------
351413
function [valid, errors] = validatestring(str, schema, path)
352414

@@ -664,6 +726,26 @@
664726
schematype = 'array';
665727
end
666728

729+
% Handle binType with minDims
730+
if isKey(schema, 'binType')
731+
bintype = schema('binType');
732+
if isKey(schema, 'minDims')
733+
dims = schema('minDims');
734+
if iscell(dims)
735+
dims = [dims{:}];
736+
end
737+
else
738+
dims = 1;
739+
end
740+
switch bintype
741+
case 'logical'
742+
output = false(dims);
743+
otherwise
744+
output = zeros(dims, bintype);
745+
end
746+
return
747+
end
748+
667749
switch schematype
668750
case 'null'
669751
output = [];

0 commit comments

Comments
 (0)