ruby_rnv 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ce0f617fe47044b9ccbf17170bef6c3e4eff2e058391c807f893ecc6927444b
4
- data.tar.gz: 1f1cd9b725b0ac0bb1c911a46b61cd972e530eb32a52b83436a4ef98d3eeacb2
3
+ metadata.gz: 076d290b71d2baddf3f6655f99471138ba7a348ce04ac509f246a92c007d2c27
4
+ data.tar.gz: '014108a35aacd5f4c78804ef9740f40e314b9f28968f038f0746375acc259fff'
5
5
  SHA512:
6
- metadata.gz: 39f3d4546aeaa960ae63fc05125cc66187821b28c2863d575f2d4a9073eeb09d7b7881a4f10d678092e3f4d7c11f02320af6ff176b5a25d8b62f57e3bec111f7
7
- data.tar.gz: f463ff1d5afcc72d8872475a26b397d24b7b25716fee83f025cc7ab3ddd038f4f591e810a350463eda65b1dc6b87ce8ea518a4470abc931d56e1322d8e100206
6
+ metadata.gz: 4e79a6d9727dbf1736df5b972acc8fb609b996ed224cf7346e42269af7777a07be42dad27ce11ae7db2d151be1a5c27d39169301289537d45ec12303aab129e7
7
+ data.tar.gz: a52f9058d874dd8083a892e0aff3ca55f68bae0bbc6f34446b31bf1922ee0d74e14693ab4d2ef6bb2cf270a1f384cf0b9f32fc1dbe764dbb6e4d2bd936ca7b0d
data/ext/rnv/ruby_rnv.c CHANGED
@@ -56,7 +56,7 @@ typedef struct document
56
56
 
57
57
  } document_t;
58
58
 
59
- VALUE RNV;
59
+ VALUE RNV, SchemaNotLoaded, Error, Document;
60
60
 
61
61
  // convert error code to symbol
62
62
  ID errno_to_id(int erno)
@@ -275,7 +275,7 @@ int ruby_verror_handler(rnv_t *rnv, int erno, char *format, va_list ap)
275
275
  // lazyly strip with ruby
276
276
  rb_funcall(error_str, rb_intern("strip!"), 0);
277
277
 
278
- VALUE err_class = rb_const_get(RNV, rb_intern("Error"));
278
+ VALUE err_class = Error;
279
279
  VALUE err_obj = rb_class_new_instance(0, NULL, err_class);
280
280
  rb_iv_set(err_obj, "@document", self);
281
281
  rb_iv_set(err_obj, "@code", error_erno);
@@ -317,61 +317,6 @@ int ruby_verror_handler(rnv_t *rnv, int erno, char *format, va_list ap)
317
317
  rb_ary_push(errors, err_obj);
318
318
  }
319
319
 
320
- /*
321
- * @return [String]
322
- */
323
- VALUE rb_error_inspect(VALUE self)
324
- {
325
- VALUE code = rb_iv_get(self, "@code");
326
- VALUE message = rb_iv_get(self, "@message");
327
- VALUE expected = rb_iv_get(self, "@expected");
328
- VALUE line = rb_iv_get(self, "@line");
329
- VALUE col = rb_iv_get(self, "@col");
330
-
331
- VALUE ret = rb_str_new2("#<RNV::Error ");
332
- ret = rb_str_cat2(ret, "code: :");
333
- ret = rb_str_append(ret, rb_obj_as_string(code));
334
- ret = rb_str_cat2(ret, ", ");
335
- ret = rb_str_cat2(ret, "message: '");
336
- ret = rb_str_append(ret, message);
337
- ret = rb_str_cat2(ret, "', ");
338
- ret = rb_str_cat2(ret, "expected: '");
339
- ret = rb_str_append(ret, expected);
340
- ret = rb_str_cat2(ret, "', ");
341
- ret = rb_str_cat2(ret, "line: ");
342
- ret = rb_str_append(ret, rb_obj_as_string(line));
343
- ret = rb_str_cat2(ret, ", ");
344
- ret = rb_str_cat2(ret, "col: ");
345
- ret = rb_str_append(ret, rb_obj_as_string(col));
346
- ret = rb_str_cat2(ret, ">");
347
- return ret;
348
- }
349
-
350
- /*
351
- * @return [String]
352
- */
353
- VALUE rb_error_to_s(VALUE self)
354
- {
355
- VALUE message = rb_iv_get(self, "@message");
356
- VALUE expected = rb_iv_get(self, "@expected");
357
- VALUE line = rb_iv_get(self, "@line");
358
- VALUE col = rb_iv_get(self, "@col");
359
-
360
- VALUE ret = rb_str_new2("");
361
-
362
- ret = rb_str_append(ret, rb_obj_as_string(line));
363
- ret = rb_str_cat2(ret, ":");
364
- ret = rb_str_append(ret, rb_obj_as_string(col));
365
-
366
- ret = rb_str_cat2(ret, ": error: ");
367
-
368
- ret = rb_str_append(ret, message);
369
- ret = rb_str_cat2(ret, "\n");
370
- ret = rb_str_append(ret, expected);
371
-
372
- return ret;
373
- }
374
-
375
320
  void document_free(document_t *document)
376
321
  {
377
322
  // FIXME : introduce *_delete functions
@@ -417,7 +362,8 @@ void document_free(document_t *document)
417
362
 
418
363
  free(document->rnv);
419
364
 
420
- free(document->text);
365
+ if (document->text)
366
+ free(document->text);
421
367
 
422
368
  ruby_xfree(document);
423
369
  }
@@ -450,9 +396,12 @@ VALUE rb_document_init(VALUE self)
450
396
  document->rnv->user_data = (void *)self;
451
397
  document->rnv->verror_handler = &ruby_verror_handler;
452
398
  document->nexp = 16; /* maximum number of candidates to display */
399
+ document->text = NULL;
453
400
 
454
401
  rb_iv_set(self, "@errors", rb_ary_new2(0));
455
402
 
403
+ rb_iv_set(self, "@libraries", rb_hash_new());
404
+
456
405
  return self;
457
406
  }
458
407
 
@@ -470,7 +419,7 @@ static void document_load(document_t *document)
470
419
  /*
471
420
  * load schema from a buffer
472
421
  * @param [String] r_str buffer
473
- * @return [String]
422
+ * @return [Boolean]
474
423
  */
475
424
  VALUE rb_document_load_string(VALUE self, VALUE r_str)
476
425
  {
@@ -489,40 +438,42 @@ VALUE rb_document_load_string(VALUE self, VALUE r_str)
489
438
  document->fn,
490
439
  RSTRING_PTR(r_str), RSTRING_LEN(r_str));
491
440
 
492
- document_load(document);
493
- return INT2NUM(document->ok);
441
+ if (document->opened)
442
+ {
443
+ document_load(document);
444
+ return Qtrue;
445
+ }
446
+ else
447
+ return Qfalse;
494
448
  }
495
449
 
496
450
  /*
497
451
  * load schema from a file
498
452
  * @param [String] r_fn filename
499
- * @return [String]
453
+ * @return [Boolean]
500
454
  */
501
455
  VALUE rb_document_load_file(VALUE self, VALUE r_fn)
502
456
  {
503
457
  document_t *document;
504
458
  Data_Get_Struct(self, document_t, document);
505
459
 
506
- switch (TYPE(r_fn))
507
- {
508
- case T_STRING:
509
- document->fn = RSTRING_PTR(r_fn);
460
+ Check_Type(r_fn, T_STRING);
510
461
 
511
- document->opened = rnl_fn(document->rnv,
512
- document->rnc_st,
513
- document->rn_st,
514
- document->rnd_st,
515
- document->fn);
462
+ document->fn = RSTRING_PTR(r_fn);
516
463
 
517
- break;
518
- case T_FILE: // TODO
519
- default:
520
- rb_raise(rb_eTypeError, "invalid argument");
521
- break;
522
- }
464
+ document->opened = rnl_fn(document->rnv,
465
+ document->rnc_st,
466
+ document->rn_st,
467
+ document->rnd_st,
468
+ document->fn);
523
469
 
524
- document_load(document);
525
- return INT2NUM(document->ok);
470
+ if (document->opened)
471
+ {
472
+ document_load(document);
473
+ return Qtrue;
474
+ }
475
+ else
476
+ return Qfalse;
526
477
  }
527
478
 
528
479
  /*
@@ -548,8 +499,61 @@ static void flush_text(document_t *document)
548
499
  document->text[document->n_txt = 0] = '\0';
549
500
  }
550
501
 
502
+ static int rb_dtl_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ, char *val, char *s, int n)
503
+ {
504
+ VALUE self = (VALUE)rnv->user_data;
505
+ VALUE libraries = rb_iv_get(self, "@libraries");
506
+ VALUE lib = rb_hash_aref(libraries, INT2FIX(uri));
507
+
508
+ VALUE ret = rb_funcall(lib, rb_intern("equal"), 4,
509
+ rb_str_new2(typ), rb_str_new2(val), rb_str_new2(s), INT2FIX(n));
510
+
511
+ return RTEST(ret);
512
+ }
513
+
514
+ static int rb_dtl_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ, char *ps, char *s, int n)
515
+ {
516
+ VALUE self = (VALUE)rnv->user_data;
517
+ VALUE libraries = rb_iv_get(self, "@libraries");
518
+ VALUE lib = rb_hash_aref(libraries, INT2FIX(uri));
519
+
520
+ VALUE ret = rb_funcall(lib, rb_intern("allows"), 4,
521
+ rb_str_new2(typ), rb_str_new2(ps), rb_str_new2(s), INT2FIX(n));
522
+
523
+ return RTEST(ret);
524
+ }
525
+
551
526
  /*
552
- * begin a new document
527
+ * add a new datatype library
528
+ * @see https://www.oasis-open.org/committees/relax-ng/spec-20010811.html#IDA1I1R
529
+ * @param [String] r_ns unique ns URL for this datatype
530
+ * @param [RNV::DataTypeLibrary] r_cb_obj
531
+ * @return [nil]
532
+ */
533
+ VALUE rb_document_add_dtl(VALUE self, VALUE r_ns, VALUE r_cb_obj)
534
+ {
535
+ document_t *document;
536
+ Data_Get_Struct(self, document_t, document);
537
+
538
+ if (document->opened)
539
+ {
540
+ Check_Type(r_ns, T_STRING);
541
+
542
+ char *suri = RSTRING_PTR(r_ns);
543
+
544
+ drv_add_dtl(document->rnv, document->drv_st, document->rn_st, suri, &rb_dtl_equal, &rb_dtl_allows);
545
+
546
+ int uri = document->drv_st->dtl[document->drv_st->n_dtl - 1].uri;
547
+
548
+ VALUE libraries = rb_iv_get(self, "@libraries");
549
+
550
+ rb_hash_aset(libraries, INT2FIX(uri), r_cb_obj);
551
+ }
552
+ return Qnil;
553
+ }
554
+
555
+ /*
556
+ * begin parsing a new document
553
557
  * @return [nil]
554
558
  */
555
559
  VALUE rb_document_begin(VALUE self)
@@ -557,6 +561,12 @@ VALUE rb_document_begin(VALUE self)
557
561
  document_t *document;
558
562
  Data_Get_Struct(self, document_t, document);
559
563
 
564
+ if (!document->opened)
565
+ rb_raise(SchemaNotLoaded, "schema was not loaded correctly");
566
+
567
+ // reset errors
568
+ rb_iv_set(self, "@errors", rb_ary_new2(0));
569
+
560
570
  m_free(document->text);
561
571
  document->text = (char *)m_alloc(document->len_txt = LEN_T, sizeof(char));
562
572
 
@@ -572,14 +582,17 @@ VALUE rb_document_begin(VALUE self)
572
582
  /*
573
583
  * to be called by SAX characters handler
574
584
  * @param [String] r_str characters
575
- * @return [Integer]
585
+ * @return [Boolean]
576
586
  */
577
587
  VALUE rb_document_characters(VALUE self, VALUE r_str)
578
588
  {
579
589
  document_t *document;
580
590
  Data_Get_Struct(self, document_t, document);
581
591
 
582
- if (document->opened && document->current != document->rnv->rn_notAllowed)
592
+ if (!document->opened)
593
+ rb_raise(SchemaNotLoaded, "schema was not loaded correctly");
594
+
595
+ if (document->current != document->rnv->rn_notAllowed)
583
596
  {
584
597
  Check_Type(r_str, T_STRING);
585
598
  char *s = RSTRING_PTR(r_str);
@@ -600,22 +613,26 @@ VALUE rb_document_characters(VALUE self, VALUE r_str)
600
613
  document->text[document->n_txt] = '\0'; /* '\0' guarantees that the text is bounded, and strto[ld] work for data */
601
614
  }
602
615
 
603
- return INT2NUM(document->ok);
616
+ return RTEST(document->ok);
604
617
  }
605
618
 
606
619
  /*
607
620
  * to be called by SAX start tag handler
608
621
  * @param [String] r_name tag name, must be in the form 'NS_URI:TAG_NAME'
609
- * @param [Array<String>] r_attrs flattened array of tag attributes in the form ['NS_URI:ATTR_NAME','ATTR_VALUE']
610
- * @return [Integer]
622
+ * @param [Array<Array<String>>] r_attrs flattened array of tag attributes in the form [['NS_URI:ATTR_NAME','ATTR_VALUE']]
623
+ * @return [Boolean]
611
624
  */
612
625
  VALUE rb_document_start_tag(VALUE self, VALUE r_name, VALUE r_attrs)
613
626
  {
614
627
  document_t *document;
615
628
  Data_Get_Struct(self, document_t, document);
616
629
 
617
- if (document->opened && document->current != document->rnv->rn_notAllowed)
630
+ if (!document->opened)
631
+ rb_raise(SchemaNotLoaded, "schema was not loaded correctly");
632
+
633
+ if (document->current != document->rnv->rn_notAllowed)
618
634
  {
635
+ int i;
619
636
  char *name;
620
637
  char **attrs;
621
638
 
@@ -623,20 +640,22 @@ VALUE rb_document_start_tag(VALUE self, VALUE r_name, VALUE r_attrs)
623
640
  name = RSTRING_PTR(r_name);
624
641
 
625
642
  Check_Type(r_attrs, T_ARRAY);
626
- unsigned int attrs_len = RARRAY_LEN(r_attrs);
643
+
644
+ // lazyly flatten with ruby
645
+ VALUE r_flat_attrs = rb_funcall(r_attrs, rb_intern("flatten"), 0);
646
+ unsigned int attrs_len = RARRAY_LEN(r_flat_attrs);
627
647
 
628
648
  attrs = malloc(sizeof(char *) * (attrs_len + 1));
629
649
 
630
- for (int i = 0; i < attrs_len; i++)
650
+ for (i = 0; i < attrs_len; i++)
631
651
  {
632
- attrs[i] = RSTRING_PTR(rb_ary_entry(r_attrs, i));
652
+ attrs[i] = RSTRING_PTR(rb_ary_entry(r_flat_attrs, i));
633
653
  }
634
654
  attrs[attrs_len] = 0; // zero terminated
635
655
 
636
656
  document->mixed = 1;
637
657
 
638
658
  flush_text(document);
639
- //printf("RNV START %d/%d %s %d\n", current, previous, name, attrs_len);
640
659
  document->ok = rnv_start_tag(document->rnv, document->drv_st, document->rn_st, document->rx_st,
641
660
  &document->current, &document->previous, (char *)name, (char **)attrs) &&
642
661
  document->ok;
@@ -645,20 +664,23 @@ VALUE rb_document_start_tag(VALUE self, VALUE r_name, VALUE r_attrs)
645
664
  free(attrs);
646
665
  }
647
666
 
648
- return INT2NUM(document->ok);
667
+ return RTEST(document->ok);
649
668
  }
650
669
 
651
670
  /*
652
671
  * to be called by SAX end tag handler
653
672
  * @param [String] r_name tag name, must be in the form 'NS_URI:TAG_NAME'
654
- * @return [Integer]
673
+ * @return [Boolean]
655
674
  */
656
675
  VALUE rb_document_end_tag(VALUE self, VALUE r_name)
657
676
  {
658
677
  document_t *document;
659
678
  Data_Get_Struct(self, document_t, document);
660
679
 
661
- if (document->opened && document->current != document->rnv->rn_notAllowed)
680
+ if (!document->opened)
681
+ rb_raise(SchemaNotLoaded, "schema was not loaded correctly");
682
+
683
+ if (document->current != document->rnv->rn_notAllowed)
662
684
  {
663
685
  char *name;
664
686
 
@@ -667,7 +689,6 @@ VALUE rb_document_end_tag(VALUE self, VALUE r_name)
667
689
 
668
690
  flush_text(document);
669
691
 
670
- //printf("RNV END %d/%d %s\n", current, previous, name);
671
692
  document->ok = rnv_end_tag(document->rnv, document->drv_st, document->rn_st,
672
693
  &document->current, &document->previous, (char *)name) &&
673
694
  document->ok;
@@ -675,7 +696,7 @@ VALUE rb_document_end_tag(VALUE self, VALUE r_name)
675
696
  document->mixed = 1;
676
697
  }
677
698
 
678
- return INT2NUM(document->ok);
699
+ return RTEST(document->ok);
679
700
  }
680
701
 
681
702
  // The initialization method for this module
@@ -683,21 +704,15 @@ void Init_rnv()
683
704
  {
684
705
  RNV = rb_define_module("RNV");
685
706
 
686
- VALUE Error = rb_define_class_under(RNV, "Error", rb_cObject);
707
+ SchemaNotLoaded = rb_define_class_under(RNV, "SchemaNotLoaded", rb_eStandardError);
687
708
 
688
- rb_define_method(Error, "inspect", rb_error_inspect, 0);
689
- rb_define_method(Error, "to_s", rb_error_to_s, 0);
709
+ Error = rb_define_class_under(RNV, "Error", rb_cObject);
690
710
 
691
711
  /*
692
712
  * error symbol code
693
713
  * @return [Symbol]
694
714
  */
695
715
  rb_define_attr(Error, "code", 1, 0);
696
- /*
697
- * error message
698
- * @return [String]
699
- */
700
- rb_define_attr(Error, "message", 1, 0);
701
716
  /*
702
717
  * error line
703
718
  * @return [Integer]
@@ -708,8 +723,18 @@ void Init_rnv()
708
723
  * @return [Integer]
709
724
  */
710
725
  rb_define_attr(Error, "col", 1, 0);
726
+ /*
727
+ * error message
728
+ * @return [String]
729
+ */
730
+ rb_define_attr(Error, "message", 1, 0);
731
+ /*
732
+ * what was expected
733
+ * @return [String]
734
+ */
735
+ rb_define_attr(Error, "expected", 1, 0);
711
736
 
712
- VALUE Document = rb_define_class_under(RNV, "Document", rb_cObject);
737
+ Document = rb_define_class_under(RNV, "Document", rb_cObject);
713
738
 
714
739
  rb_define_alloc_func(Document, rb_document_alloc);
715
740
  rb_define_method(Document, "initialize", rb_document_init, 0);
@@ -718,6 +743,8 @@ void Init_rnv()
718
743
  rb_define_method(Document, "load_string", rb_document_load_string, 1);
719
744
  rb_define_method(Document, "valid?", rb_document_valid, 0);
720
745
 
746
+ rb_define_method(Document, "add_datatype_library", rb_document_add_dtl, 2);
747
+
721
748
  rb_define_method(Document, "start_document", rb_document_begin, 0);
722
749
  rb_define_method(Document, "start_tag", rb_document_start_tag, 2);
723
750
  rb_define_method(Document, "characters", rb_document_characters, 1);
data/ext/rnv/src/drv.c CHANGED
@@ -13,12 +13,6 @@
13
13
  #include "er.h"
14
14
  #include "drv.h"
15
15
 
16
- struct dtl {
17
- int uri;
18
- int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n);
19
- int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n);
20
- };
21
-
22
16
  #define LEN_DTL DRV_LEN_DTL
23
17
  #define LEN_M DRV_LEN_M
24
18
  #define PRIME_M DRV_PRIME_M
@@ -112,10 +106,10 @@ static void accept_m(rnv_t *rnv, drv_st_t *drv_st) {
112
106
  if(drv_st->i_m==drv_st->len_m) drv_st->memo=(int(*)[M_SIZE])m_stretch(drv_st->memo,drv_st->len_m=2*drv_st->i_m,drv_st->i_m,sizeof(int[M_SIZE]));
113
107
  }
114
108
 
115
- static int fallback_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n) {return 1;}
116
- static int fallback_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n) {return 1;}
109
+ static int fallback_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n) {return 1;}
110
+ static int fallback_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n) {return 1;}
117
111
 
118
- static int builtin_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n) {
112
+ static int builtin_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n) {
119
113
  int dt=rn_newDatatype(rnv, rn_st, 0,typ-rnv->rn_string);
120
114
  if(dt==rnv->rn_dt_string) return s_cmpn(val,s,n)==0;
121
115
  else if(dt==rnv->rn_dt_token) return s_tokcmpn(val,s,n)==0;
@@ -123,7 +117,7 @@ static int builtin_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,c
123
117
  return 0;
124
118
  }
125
119
 
126
- static int builtin_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n) {return 1;}
120
+ static int builtin_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n) {return 1;}
127
121
 
128
122
  static void windup(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st);
129
123
 
@@ -140,11 +134,11 @@ void drv_init(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, rx_st_t *rx_st) {
140
134
  windup(rnv, drv_st, rn_st);
141
135
  }
142
136
 
143
- static int emb_xsd_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n) {
137
+ static int emb_xsd_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n) {
144
138
  return xsd_allows(rx_st, typ,ps,s,n);
145
139
  }
146
140
 
147
- static int emb_xsd_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n) {
141
+ static int emb_xsd_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n) {
148
142
  return xsd_equal(rx_st, typ,val,s,n);
149
143
  }
150
144
 
@@ -160,7 +154,9 @@ void drv_clear(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st) {
160
154
  windup(rnv, drv_st, rn_st);
161
155
  }
162
156
 
163
- void drv_add_dtl(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, char *suri,int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n),int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n)) {
157
+ void drv_add_dtl(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, char *suri,
158
+ int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n),
159
+ int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n)) {
164
160
  if(drv_st->n_dtl==drv_st->len_dtl) drv_st->dtl=(struct dtl *)m_stretch(drv_st->dtl,drv_st->len_dtl=drv_st->n_dtl*2,drv_st->n_dtl,sizeof(struct dtl));
165
161
  drv_st->dtl[drv_st->n_dtl].uri=rn_newString(rnv, rn_st, suri);
166
162
  drv_st->dtl[drv_st->n_dtl].equal=equal;
@@ -381,13 +377,13 @@ static int text(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, drv_st_t *drv_st, in
381
377
  ret=rn_nullable(list(rnv, rn_st, rx_st, drv_st, p1,s,n))?rnv->rn_empty:rnv->rn_notAllowed;
382
378
  break;
383
379
  case RN_P_DATA: rn_Data(p,dt,ps); rn_Datatype(dt,lib,typ);
384
- ret=getdtl(rnv, drv_st, lib)->allows(rnv,rn_st,rx_st,rnv->rn_string+typ,rnv->rn_string+ps,s,n)?rnv->rn_empty:rnv->rn_notAllowed;
380
+ ret=getdtl(rnv, drv_st, lib)->allows(rnv,rn_st,rx_st, lib, rnv->rn_string+typ,rnv->rn_string+ps,s,n)?rnv->rn_empty:rnv->rn_notAllowed;
385
381
  break;
386
382
  case RN_P_DATA_EXCEPT: rn_DataExcept(p,p1,p2);
387
383
  ret=text(rnv, rn_st, rx_st, drv_st, p1,s,n)==rnv->rn_empty&&!rn_nullable(text(rnv, rn_st, rx_st, drv_st, p2,s,n))?rnv->rn_empty:rnv->rn_notAllowed;
388
384
  break;
389
385
  case RN_P_VALUE: rn_Value(p,dt,val); rn_Datatype(dt,lib,typ);
390
- ret=getdtl(rnv, drv_st, lib)->equal(rnv,rn_st,rx_st, rnv->rn_string+typ,rnv->rn_string+val,s,n)?rnv->rn_empty:rnv->rn_notAllowed;
386
+ ret=getdtl(rnv, drv_st, lib)->equal(rnv,rn_st,rx_st, lib, rnv->rn_string+typ,rnv->rn_string+val,s,n)?rnv->rn_empty:rnv->rn_notAllowed;
391
387
  break;
392
388
  default: assert(0);
393
389
  }
data/ext/rnv/src/drv.h CHANGED
@@ -9,13 +9,21 @@
9
9
 
10
10
  #define DRV_ER_NODTL 0
11
11
 
12
+ struct dtl {
13
+ int uri;
14
+ int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n);
15
+ int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n);
16
+ };
17
+
12
18
  extern void drv_default_verror_handler(rnv_t *rnv, int erno,va_list ap);
13
19
 
14
20
  extern void drv_init(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, rx_st_t *rx_st);
15
21
  extern void drv_clear(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st);
16
22
 
17
23
  /* Expat passes character data unterminated. Hence functions that can deal with cdata expect the length of the data */
18
- extern void drv_add_dtl(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, char *suri,int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n),int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n));
24
+ extern void drv_add_dtl(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, char *suri,
25
+ int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n),
26
+ int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n));
19
27
 
20
28
  extern int drv_start_tag_open(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, int p,char *suri,char *sname);
21
29
  extern int drv_start_tag_open_recover(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, int p,char *suri,char *sname);
data/lib/rnv.rb CHANGED
@@ -1,2 +1,5 @@
1
1
  require 'rnv/rnv'
2
+ require 'rnv/error'
2
3
  require 'rnv/validator'
4
+ require 'rnv/data_type_library'
5
+ require 'rnv/pre_processor'
@@ -0,0 +1,23 @@
1
+ module RNV
2
+ # Datatype library callback object
3
+ # @see https://www.oasis-open.org/committees/relax-ng/spec-20010811.html#IDA1I1R
4
+ class DataTypeLibrary
5
+ # @param [String] typ
6
+ # @param [String] val
7
+ # @param [String] s
8
+ # @param [Integer] n
9
+ # @return [Boolean]
10
+ def equal(typ, val, s, n)
11
+ true
12
+ end
13
+
14
+ # @param [String] typ
15
+ # @param [String] ps
16
+ # @param [String] s
17
+ # @param [Integer] n
18
+ # @return [Boolean]
19
+ def allows(typ, ps, s, n)
20
+ true
21
+ end
22
+ end
23
+ end
data/lib/rnv/error.rb ADDED
@@ -0,0 +1,13 @@
1
+ module RNV
2
+ class Error
3
+ # @return [String]
4
+ def to_s
5
+ "#{@line}:#{@col}:error: #{@message}\n#{@expected}"
6
+ end
7
+
8
+ # @return [String]
9
+ def inspect
10
+ "#<RNV::Error code: :#{@code}, message: '#{@message}', expected: '#{@expected} line: #{@line}, column: #{@col}>"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ module RNV
2
+ # Object to modify data before validation (eg: HTML5 data-* attributes)
3
+ class PreProcessor
4
+ # replace attributes before validate
5
+ # @param [Array<Array<String>>] attrs
6
+ # @return [Array<Array<String>>]
7
+ def attributes(attrs)
8
+ attrs
9
+ end
10
+
11
+ # replace tag name before validate
12
+ # @param [String] tag
13
+ # @return [String]
14
+ def tag(tag)
15
+ tag
16
+ end
17
+
18
+ # replace content text before validate
19
+ # @param [String] txt
20
+ # @return [String]
21
+ def text(txt)
22
+ txt
23
+ end
24
+ end
25
+ end
data/lib/rnv/validator.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  require 'nokogiri'
2
2
  require 'rnv/rnv'
3
+ require 'rnv/pre_processor'
3
4
 
4
5
  module RNV
5
6
  # @!visibility private
6
7
  class NokogiriSaxDocument < Nokogiri::XML::SAX::Document
7
8
  # @return [Nokogiri::XML::SAX::ParserContext]
8
- attr_accessor :ctx
9
+ attr_accessor :ctx, :pre_processor
9
10
  # @param [RNV::Document] document
10
11
  def initialize(document)
11
12
  @document = document
@@ -15,23 +16,23 @@ module RNV
15
16
  update_line_col
16
17
  tag_attrs = attrs.map { |attr| [attr.uri ? "#{attr.uri}:#{attr.localname}" : attr.localname, attr.value] }
17
18
  tag_name = uri ? "#{uri}:#{name}" : name
18
- @document.start_tag(tag_name, tag_attrs.flatten)
19
+ @document.start_tag(@pre_processor.tag(tag_name), @pre_processor.attributes(tag_attrs))
19
20
  end
20
21
 
21
22
  def end_element_namespace(name, prefix = nil, uri = nil)
22
23
  update_line_col
23
24
  tag_name = uri ? "#{uri}:#{name}" : name
24
- @document.end_tag(tag_name)
25
+ @document.end_tag(@pre_processor.tag(tag_name))
25
26
  end
26
27
 
27
28
  def characters str
28
29
  update_line_col
29
- @document.characters(str)
30
+ @document.characters(@pre_processor.text(str))
30
31
  end
31
32
 
32
33
  def cdata_block str
33
34
  update_line_col
34
- @document.characters(str)
35
+ @document.characters(@pre_processor.(str))
35
36
  end
36
37
 
37
38
  private
@@ -57,25 +58,29 @@ module RNV
57
58
  end
58
59
 
59
60
  # @param [String] str RNC schema buffer
61
+ # @return [Boolean] true if schema loaded successfuly
60
62
  def load_schema_from_string(str)
61
63
  @document.load_string(str)
62
64
  end
63
65
 
64
66
  # @param [String] file RNC schema filename
67
+ # @return [Boolean] true if schema loaded successfuly
65
68
  def load_schema_from_file(file)
66
69
  @document.load_file(file)
67
70
  end
68
71
 
69
72
  # parse and validate buffer
70
73
  # @param [String] str XML buffer to parse
74
+ # @param [RNV::PreProcessor] pre_processor an optional pre-processor for tag and attributes data
71
75
  # @return [Boolean] true if valid
72
- def parse_string(str)
73
- @document.errors = [] # reset errors
76
+ def parse_string(str, pre_processor = PreProcessor.new)
74
77
  @document.start_document
75
78
  rnv_doc = NokogiriSaxDocument.new(@document)
79
+ rnv_doc.pre_processor = pre_processor
76
80
 
77
81
  parser = Nokogiri::XML::SAX::Parser.new(rnv_doc)
78
82
  parser.parse_memory(str) do |ctx|
83
+ ctx.replace_entities = true
79
84
  rnv_doc.ctx = ctx
80
85
  end
81
86
 
@@ -84,16 +89,18 @@ module RNV
84
89
 
85
90
  # parse and validate file
86
91
  # @param [String, File] xml XML file to parse
92
+ # @param [RNV::PreProcessor] pre_processor an optional pre-processor for tag and attributes data
87
93
  # @return [Boolean] true if valid
88
- def parse_file(xml)
89
- @document.errors = [] # reset errors
94
+ def parse_file(xml, pre_processor = PreProcessor.new)
90
95
  @document.start_document
91
96
  rnv_doc = NokogiriSaxDocument.new(@document)
97
+ rnv_doc.pre_processor = pre_processor
92
98
 
93
99
  file = xml.is_a?(File) ? xml : File.open(xml)
94
100
 
95
101
  parser = Nokogiri::XML::SAX::Parser.new(rnv_doc)
96
102
  parser.parse(file) do |ctx|
103
+ ctx.replace_entities = true
97
104
  rnv_doc.ctx = ctx
98
105
  end
99
106
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_rnv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julien Boulnois
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-07 00:00:00.000000000 Z
11
+ date: 2021-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -147,9 +147,11 @@ files:
147
147
  - ext/rnv/src/xsd_tm.c
148
148
  - ext/rnv/src/xsd_tm.h
149
149
  - lib/rnv.rb
150
- - lib/rnv/ox_sax_document.rb
150
+ - lib/rnv/data_type_library.rb
151
+ - lib/rnv/error.rb
152
+ - lib/rnv/pre_processor.rb
151
153
  - lib/rnv/validator.rb
152
- homepage:
154
+ homepage: https://github.com/immateriel/ruby_rnv
153
155
  licenses:
154
156
  - MIT
155
157
  metadata: {}
@@ -171,5 +173,5 @@ requirements: []
171
173
  rubygems_version: 3.0.8
172
174
  signing_key:
173
175
  specification_version: 4
174
- summary: RelaxNG compact syntax validator
176
+ summary: RelaxNG compact syntax validator for Ruby
175
177
  test_files: []
@@ -1,84 +0,0 @@
1
- class OxSaxDocument < ::Ox::Sax
2
- attr_accessor :current_element, :current_attributes, :current_ns
3
-
4
- def initialize(document)
5
- @document = document
6
- @current_ns = {}
7
- @pos = nil
8
- @line = nil
9
- @column = nil
10
- end
11
-
12
- def start_element(name)
13
- save_line_col
14
- @current_element = name.to_s
15
- @current_attributes = []
16
- end
17
-
18
- def end_element(name)
19
- save_line_col
20
- @document.end_tag(name_with_ns_uri(name.to_s))
21
- @current_element = nil
22
- end
23
-
24
- def attr(name, value)
25
- if @current_element
26
- if name.to_s.start_with?("xmlns")
27
- ns = name.to_s.split(":")
28
- @current_ns[ns.length > 1 ? ns.last : ""] = value.to_s
29
- else
30
- @current_attributes << name_with_ns_uri(name.to_s, false)
31
- @current_attributes << value.to_s
32
- end
33
- end
34
- end
35
-
36
- def attrs_done
37
- save_line_col
38
- if @current_element
39
- @document.start_tag(name_with_ns_uri(@current_element), @current_attributes)
40
- @current_element = nil
41
- end
42
- end
43
-
44
- def text(value)
45
- save_line_col
46
- @document.characters(value)
47
- end
48
-
49
- if false
50
- def value(value)
51
- save_line_col
52
- @document.characters(value.as_s)
53
- end
54
- end
55
-
56
- def instruct(inst)
57
- end
58
-
59
- private
60
- def get_ns_uri(ns)
61
- @current_ns[ns] ? "#{@current_ns[ns]}:" : ""
62
- end
63
-
64
- def name_with_ns_uri(name, explicit_xmlns = true)
65
- name_with_ns = name.split(":")
66
- if name_with_ns.length > 1
67
- "#{get_ns_uri(name_with_ns.first)}#{name_with_ns.last}"
68
- else
69
- if explicit_xmlns
70
- "#{get_ns_uri("")}#{name_with_ns.first}"
71
- else
72
- name
73
- end
74
- end
75
- end
76
-
77
- def save_line_col
78
- @document.last_line = @line
79
- @document.last_col = @column
80
- end
81
- end
82
-
83
- # handler = OxSaxDocument.new(@document)
84
- # Ox.sax_parse(handler, file)