ox 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ox might be problematic. Click here for more details.

@@ -51,6 +51,18 @@ extern "C" {
51
51
  #define TRACE 1
52
52
  #define DEBUG 2
53
53
 
54
+ #define XSD_DATE 0x0001
55
+ #define WITH_XML 0x0002
56
+ #define WITH_INST 0x0004
57
+ #define WITH_DTD 0x0008
58
+ #define CIRCULAR 0x0010
59
+
60
+ #define XSD_DATE_SET 0x0100
61
+ #define WITH_XML_SET 0x0200
62
+ #define WITH_INST_SET 0x0400
63
+ #define WITH_DTD_SET 0x0800
64
+ #define CIRCULAR_SET 0x1000
65
+
54
66
  typedef enum {
55
67
  UseObj = 1,
56
68
  UseAttr = 2,
@@ -66,11 +78,25 @@ typedef enum {
66
78
  } Use;
67
79
 
68
80
  typedef enum {
69
- StrictEffort = 0,
70
- TolerantEffort = 1,
71
- AutoEffort = 2,
81
+ StrictEffort = 's',
82
+ TolerantEffort = 't',
83
+ AutoEffort = 'a',
84
+ NoEffort = 0,
72
85
  } Effort;
73
86
 
87
+ typedef enum {
88
+ Yes = 'y',
89
+ No = 'n',
90
+ NotSet = 0
91
+ } YesNo;
92
+
93
+ typedef enum {
94
+ ObjMode = 'o',
95
+ GenMode = 'g',
96
+ LimMode = 'l',
97
+ NoMode = 0
98
+ } LoadMode;
99
+
74
100
  typedef enum {
75
101
  NoCode = 0,
76
102
  ArrayCode = 'a',
@@ -111,7 +137,7 @@ typedef struct _Helper {
111
137
  typedef struct _PInfo *PInfo;
112
138
 
113
139
  typedef struct _ParseCallbacks {
114
- void (*add_prolog)(PInfo pi, const char *version, const char *encoding, const char *standalone);
140
+ void (*instruct)(PInfo pi, const char *target, Attr attrs);
115
141
  void (*add_doctype)(PInfo pi, const char *docType);
116
142
  void (*add_comment)(PInfo pi, const char *comment);
117
143
  void (*add_cdata)(PInfo pi, const char *cdata, size_t len);
@@ -142,11 +168,24 @@ struct _PInfo {
142
168
  Effort effort;
143
169
  };
144
170
 
171
+ typedef struct _Options {
172
+ char encoding[64]; // encoding, stored in the option to avoid GC invalidation in default values
173
+ int indent; // indention for dump, default 2
174
+ int trace; // trace level
175
+ char with_dtd; // YesNo
176
+ char with_xml; // YesNo
177
+ char with_instruct; // YesNo
178
+ char circular; // YesNo
179
+ char xsd_date; // YesNo
180
+ char mode; // LoadMode
181
+ char effort; // Effort
182
+ } *Options;
183
+
145
184
  extern VALUE parse(char *xml, ParseCallbacks pcb, char **endp, int trace, Effort effort);
146
185
  extern void _raise_error(const char *msg, const char *xml, const char *current, const char* file, int line);
147
186
 
148
- extern char* write_obj_to_str(VALUE obj, int indent, int xsd_date, int circular);
149
- extern void write_obj_to_file(VALUE obj, const char *path, int indent, int xsd_date, int circular);
187
+ extern char* write_obj_to_str(VALUE obj, Options copts);
188
+ extern void write_obj_to_file(VALUE obj, const char *path, Options copts);
150
189
 
151
190
  extern VALUE Ox;
152
191
 
@@ -36,7 +36,7 @@
36
36
  #include "ruby.h"
37
37
  #include "ox.h"
38
38
 
39
- static void read_prolog(PInfo pi);
39
+ static void read_instruction(PInfo pi);
40
40
  static void read_doctype(PInfo pi);
41
41
  static void read_comment(PInfo pi);
42
42
  static void read_element(PInfo pi);
@@ -115,7 +115,7 @@ parse(char *xml, ParseCallbacks pcb, char **endp, int trace, Effort effort) {
115
115
  switch (*pi.s) {
116
116
  case '?': // prolog
117
117
  pi.s++;
118
- read_prolog(&pi);
118
+ read_instruction(&pi);
119
119
  break;
120
120
  case '!': /* comment or doctype */
121
121
  pi.s++;
@@ -150,77 +150,49 @@ parse(char *xml, ParseCallbacks pcb, char **endp, int trace, Effort effort) {
150
150
  /* Entered after the "<?" sequence. Ready to read the rest.
151
151
  */
152
152
  static void
153
- read_prolog(PInfo pi) {
154
- char *version = 0;
155
- char *encoding = 0;
156
- char *standalone = 0;
157
- char *name;
158
- char *end;
159
- char c;
160
-
161
- // skip xml string
162
- if (0 != strncasecmp("xml", pi->s, 3)) {
163
- raise_error("invalid format, expected 'xml'", pi->str, pi->s);
164
- }
165
- pi->s += 3; // past xml
166
- /* looking for ?> to terminate the prolog */
167
- while ('?' != *pi->s) {
168
- if ('\0' == *pi->s) {
169
- raise_error("invalid format, prolog not terminated", pi->str, pi->s);
170
- }
171
- name = read_name_token(pi);
172
- end = pi->s;
173
- next_non_white(pi);
174
- c = *pi->s;
175
- *end = '\0'; // terminate name
176
- if ('=' == c) {
177
- // Figure out what the token is, read a value for it, and check
178
- // against supported values.
179
- pi->s++;
180
- next_non_white(pi);
181
- if (0 == strcasecmp("version", name)) {
182
- version = read_quoted_value(pi);
183
- if (validateProlog &&
184
- (0 != strcmp("1.0", version) &&
185
- 0 != strcmp("1.1", version))) {
186
- raise_error("invalid format, wrong XML version", pi->str, pi->s);
187
- }
188
- } else if (0 == strcasecmp("encoding", name)) {
189
- encoding = read_quoted_value(pi);
190
- /*
191
- if (validateProlog && 0 != strcasecmp("UTF-8", encoding)) {
192
- raise_error("invalid format, only UTF-8 supported", pi->str, pi->s);
193
- }
194
- */
195
- } else if (0 == strcasecmp("standalone", name)) {
196
- standalone = read_quoted_value(pi);
197
- if (validateProlog && 0 != strcmp("yes", standalone)) {
198
- raise_error("invalid format, only standalone XML supported", pi->str, pi->s);
199
- }
200
- } else {
201
- raise_error("invalid format, unknown prolog attribute", pi->str, pi->s);
202
- }
203
- } else if ('?' == c) {
204
- pi->s++;
205
- if ('>' != *pi->s++) {
206
- raise_error("invalid format, prolog not terminated", pi->str, pi->s);
207
- }
208
- return;
209
- } else {
210
- raise_error("invalid format, prolog format error", pi->str, pi->s);
211
- }
212
- }
213
- if ('\0' == pi->s) {
214
- raise_error("invalid format, prolog not terminated", pi->str, pi->s);
215
- }
216
- if ('?' == *pi->s) {
217
- pi->s++;
153
+ read_instruction(PInfo pi) {
154
+ struct _Attr attrs[MAX_ATTRS + 1];
155
+ Attr a = attrs;
156
+ char *target;
157
+ char *end;
158
+ char c;
159
+
160
+ memset(attrs, 0, sizeof(attrs));
161
+ target = read_name_token(pi);
162
+ end = pi->s;
163
+ next_non_white(pi);
164
+ c = *pi->s;
165
+ *end = '\0'; // terminate name
166
+ if ('?' != c) {
167
+ while ('?' != *pi->s) {
168
+ if ('\0' == *pi->s) {
169
+ raise_error("invalid format, processing instruction not terminated", pi->str, pi->s);
170
+ }
171
+ next_non_white(pi);
172
+ a->name = read_name_token(pi);
173
+ end = pi->s;
174
+ next_non_white(pi);
175
+ if ('=' != *pi->s++) {
176
+ raise_error("invalid format, no attribute value", pi->str, pi->s);
177
+ }
178
+ *end = '\0'; // terminate name
179
+ // read value
180
+ next_non_white(pi);
181
+ a->value = read_quoted_value(pi);
182
+ a++;
183
+ if (MAX_ATTRS <= (a - attrs)) {
184
+ raise_error("too many attributes", pi->str, pi->s);
185
+ }
186
+ }
187
+ if ('?' == *pi->s) {
188
+ pi->s++;
189
+ }
218
190
  }
219
191
  if ('>' != *pi->s++) {
220
- raise_error("invalid format, prolog not terminated", pi->str, pi->s);
192
+ raise_error("invalid format, processing instruction not terminated", pi->str, pi->s);
221
193
  }
222
- if (0 != pi->pcb->add_prolog) {
223
- pi->pcb->add_prolog(pi, version, encoding, standalone);
194
+ if (0 != pi->pcb->instruct) {
195
+ pi->pcb->instruct(pi, target, attrs);
224
196
  }
225
197
  }
226
198
 
@@ -492,7 +464,7 @@ read_text(PInfo pi) {
492
464
  }
493
465
  b = alloc_buf + pos;
494
466
  }
495
- end = alloc_buf + size;
467
+ end = alloc_buf + size - 2;
496
468
  }
497
469
  if (spc) {
498
470
  *b++ = ' ';
@@ -503,9 +475,11 @@ read_text(PInfo pi) {
503
475
  }
504
476
  }
505
477
  *b = '\0';
506
- pi->pcb->add_text(pi, buf, ('/' == *(pi->s + 1)));
507
478
  if (0 != alloc_buf) {
479
+ pi->pcb->add_text(pi, alloc_buf, ('/' == *(pi->s + 1)));
508
480
  free(alloc_buf);
481
+ } else {
482
+ pi->pcb->add_text(pi, buf, ('/' == *(pi->s + 1)));
509
483
  }
510
484
  }
511
485
 
data/lib/ox.rb CHANGED
@@ -83,10 +83,11 @@
83
83
  # doc2 = Ox.parse(xml)
84
84
  # puts "Same? #{doc == doc2}"
85
85
  module Ox
86
- # Current version of the module.
87
- VERSION = '1.0.0'
86
+ private
87
+ @@keep = []
88
88
  end
89
89
 
90
+ require 'ox/version'
90
91
  require 'ox/node'
91
92
  require 'ox/comment'
92
93
  require 'ox/cdata'
@@ -54,35 +54,35 @@ module Ox
54
54
  end
55
55
  alias == eql?
56
56
 
57
- end # Bag
58
-
59
- # Define a new class based on the Ox::Bag class. This is used internally in
60
- # the Ox module and is available to service wrappers that receive XML
61
- # requests that include Objects of Classes not defined in the storage
62
- # process.
63
- # [classname] Class name or symbol that includes Module names
64
- def self.define_class(classname)
65
- classname = classname.to_s unless classname.is_a?(String)
66
- tokens = classname.split('::').map { |n| n.to_sym }
67
- raise "Invalid classname '#{classname}" if tokens.empty?
68
- m = Object
69
- tokens[0..-2].each do |sym|
57
+ # Define a new class based on the Ox::Bag class. This is used internally in
58
+ # the Ox module and is available to service wrappers that receive XML
59
+ # requests that include Objects of Classes not defined in the storage
60
+ # process.
61
+ # [classname] Class name or symbol that includes Module names
62
+ def self.define_class(classname)
63
+ classname = classname.to_s unless classname.is_a?(String)
64
+ tokens = classname.split('::').map { |n| n.to_sym }
65
+ raise "Invalid classname '#{classname}" if tokens.empty?
66
+ m = Object
67
+ tokens[0..-2].each do |sym|
68
+ if m.const_defined?(sym)
69
+ m = m.const_get(sym)
70
+ else
71
+ c = Module.new
72
+ m.const_set(sym, c)
73
+ m = c
74
+ end
75
+ end
76
+ sym = tokens[-1]
70
77
  if m.const_defined?(sym)
71
- m = m.const_get(sym)
78
+ c = m.const_get(sym)
72
79
  else
73
- c = Module.new
80
+ c = Class.new(Ox::Bag)
74
81
  m.const_set(sym, c)
75
- m = c
76
82
  end
83
+ c
77
84
  end
78
- sym = tokens[-1]
79
- if m.const_defined?(sym)
80
- c = m.const_get(sym)
81
- else
82
- c = Class.new(Ox::Bag)
83
- m.const_set(sym, c)
84
- end
85
- c
86
- end
85
+
86
+ end # Bag
87
87
 
88
88
  end # Ox
@@ -0,0 +1,5 @@
1
+
2
+ module Ox
3
+ # Current version of the module.
4
+ VERSION = '1.2.0'
5
+ end
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby -wW1
2
+
3
+ $: << '../lib'
4
+ $: << '../ext'
5
+
6
+ if __FILE__ == $0
7
+ if (i = ARGV.index('-I'))
8
+ x,path = ARGV.slice!(i, 2)
9
+ $: << path
10
+ end
11
+ end
12
+
13
+ require 'ox'
14
+
15
+ def oxpoo(cnt = 100000)
16
+ xml = "<?xml version=\"1.0\"?>\n<a>\n <m>inc</m>\n <i>1</i>\n</a>\n"
17
+ cnt.times do |i|
18
+ obj = Ox.load(xml, :mode => :object)
19
+ #puts "#{obj} (#{obj.class})"
20
+ raise "decode ##{i} not equal; #{obj.inspect} != '#{[:inc, 1] }'" unless [:inc, 1] == obj
21
+ end
22
+ end
23
+
24
+ oxpoo()
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby -wW1
2
+
3
+ $: << '../lib'
4
+ $: << '../ext'
5
+
6
+ if __FILE__ == $0
7
+ if (i = ARGV.index('-I'))
8
+ x,path = ARGV.slice!(i, 2)
9
+ $: << path
10
+ end
11
+ end
12
+
13
+ require 'ox'
14
+
15
+ def bug2()
16
+ s = File.read('long.pdf')
17
+ puts "size before: #{s.size}"
18
+
19
+ # s = "Hello\x00\x00\x00there."
20
+ xml = Ox.dump(s, mode: :object)
21
+ #puts "xml size: #{xml.size}"
22
+ s2 = Ox.load(xml, mode: :object)
23
+ puts "size after: #{s2.size}"
24
+ #puts s2
25
+ b1 = s.bytes
26
+ b2 = s2.bytes
27
+ (0..s2.bytesize).each do |i|
28
+ puts "#{s.getbyte(i)} #{s2.getbyte(i)}"
29
+ if s.getbyte(i) != s2.getbyte(i)
30
+ puts "stopped at #{i}"
31
+ break
32
+ end
33
+ end
34
+ puts "byte sizes #{s.bytesize} #{s2.bytesize}"
35
+ puts "char sizes #{s.size} #{s2.size}"
36
+ end
37
+
38
+ bug2()
@@ -22,7 +22,51 @@ opts.on("-h", "--help", "Show this display") { puts opts; Process
22
22
  files = opts.parse(ARGV)
23
23
 
24
24
  class Func < ::Test::Unit::TestCase
25
-
25
+
26
+ def test_get_options
27
+ opts = Ox.default_options()
28
+ assert_equal(opts, {
29
+ :encoding=>nil,
30
+ :indent=>2,
31
+ :trace=>0,
32
+ :with_dtd=>false,
33
+ :with_xml=>false,
34
+ :with_instructions=>false,
35
+ :circular=>false,
36
+ :xsd_date=>false,
37
+ :mode=>nil,
38
+ :effort=>:strict})
39
+ end
40
+
41
+ def test_set_options
42
+ orig = {
43
+ :encoding=>nil,
44
+ :indent=>2,
45
+ :trace=>0,
46
+ :with_dtd=>false,
47
+ :with_xml=>true,
48
+ :with_instructions=>false,
49
+ :circular=>false,
50
+ :xsd_date=>false,
51
+ :mode=>nil,
52
+ :effort=>:strict}
53
+ o2 = {
54
+ :encoding=>"UTF-8",
55
+ :indent=>4,
56
+ :trace=>1,
57
+ :with_dtd=>true,
58
+ :with_xml=>false,
59
+ :with_instructions=>true,
60
+ :circular=>true,
61
+ :xsd_date=>true,
62
+ :mode=>:object,
63
+ :effort=>:tolerant }
64
+ Ox.default_options = o2
65
+ opts = Ox.default_options()
66
+ assert_equal(opts, o2);
67
+ Ox.default_options = orig # return to original
68
+ end
69
+
26
70
  def test_nil
27
71
  dump_and_load(nil, false)
28
72
  end
@@ -133,7 +177,32 @@ class Func < ::Test::Unit::TestCase
133
177
  assert_equal(loaded.class.to_s, 'Bad')
134
178
  assert_equal(loaded.class.superclass.to_s, 'Ox::Bag')
135
179
  end
136
-
180
+
181
+ def test_xml_instruction
182
+ xml = Ox.dump("test", mode: :object, with_xml: false)
183
+ assert_equal(xml, "<s>test</s>\n")
184
+ xml = Ox.dump("test", mode: :object, with_xml: true)
185
+ assert_equal(xml, "<?xml version=\"1.0\"?>\n<s>test</s>\n")
186
+ xml = Ox.dump("test", mode: :object, with_xml: true, encoding: 'UTF-8')
187
+ assert_equal(xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<s>test</s>\n")
188
+ end
189
+
190
+ def test_ox_instruction
191
+ xml = Ox.dump("test", mode: :object, with_xml: true, with_instructions: true)
192
+ assert_equal(xml, "<?xml version=\"1.0\"?>\n<?ox version=\"1.0\" mode=\"object\"?>\n<s>test</s>\n")
193
+ xml = Ox.dump("test", mode: :object, with_instructions: true)
194
+ assert_equal(xml, "<?ox version=\"1.0\" mode=\"object\"?>\n<s>test</s>\n")
195
+ xml = Ox.dump("test", mode: :object, with_instructions: true, circular: true, xsd_date: true)
196
+ assert_equal(xml, "<?ox version=\"1.0\" mode=\"object\" circular=\"yes\" xsd_date=\"yes\"?>\n<s i=\"1\">test</s>\n")
197
+ xml = Ox.dump("test", mode: :object, with_instructions: true, circular: false, xsd_date: false)
198
+ assert_equal(xml, "<?ox version=\"1.0\" mode=\"object\" circular=\"no\" xsd_date=\"no\"?>\n<s>test</s>\n")
199
+ end
200
+
201
+ def test_dtd
202
+ xml = Ox.dump("test", mode: :object, with_dtd: true)
203
+ assert_equal(xml, "<!DOCTYPE s SYSTEM \"ox.dtd\">\n<s>test</s>\n")
204
+ end
205
+
137
206
  def test_class
138
207
  dump_and_load(Bag, false)
139
208
  end
@@ -215,6 +284,14 @@ class Func < ::Test::Unit::TestCase
215
284
  loaded
216
285
  end
217
286
 
287
+ def test_instructions
288
+ xml = Ox.dump("test", with_instructions: true)
289
+ puts xml
290
+ obj = Ox.load(xml) # should convert it to an object
291
+ assert_equal("test", obj)
292
+ end
293
+
294
+
218
295
  end
219
296
 
220
297
  class Bag