blob: fcc36f11b8351da210a6f48078519b41bbc4cad2 [file] [log] [blame]
Jeff Thompsondad617b2012-10-14 17:11:41 -07001/*
2 * This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to
3 * determine its end.
4 *
Jeff Thompson146d7de2012-11-17 16:15:28 -08005 * @author: Jeff Thompson
Jeff Thompsondad617b2012-10-14 17:11:41 -07006 * See COPYING for copyright and distribution information.
7 */
8
9var BinaryXMLStructureDecoder = function BinaryXMLDecoder() {
10 this.gotElementEnd = false;
11 this.offset = 0;
12 this.level = 0;
13 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
14 this.headerStartOffset = 0;
Jeff Thompson11dc9b62012-11-28 19:21:20 -080015 this.nBytesToRead = 0;
Jeff Thompsondad617b2012-10-14 17:11:41 -070016};
17
18BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE = 0;
19BinaryXMLStructureDecoder.READ_BYTES = 1;
20
21/*
22 * Continue scanning input starting from this.offset. If found the end of the element
23 * which started at offset 0 then return true, else false.
24 * If this returns false, you should read more into input and call again.
25 * You have to pass in input each time because the array could be reallocated.
26 * This throws an exception for badly formed ccnb.
27 */
28BinaryXMLStructureDecoder.prototype.findElementEnd = function(
29 // byte array
30 input)
31{
32 if (this.gotElementEnd)
33 // Someone is calling when we already got the end.
34 return true;
35
36 var decoder = new BinaryXMLDecoder(input);
37
38 while (true) {
39 if (this.offset >= input.length)
40 // All the cases assume we have some input.
41 return false;
42
43 switch (this.state) {
44 case BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE:
45 // First check for XML_CLOSE.
46 if (this.offset == this.headerStartOffset && input[this.offset] == XML_CLOSE) {
47 ++this.offset;
48 // Close the level.
49 --this.level;
50 if (this.level == 0)
51 // Finished.
52 return true;
53 if (this.level < 0)
54 throw new Error("BinaryXMLStructureDecoder: Unexepected close tag at offset " +
55 (this.offset - 1));
56
57 // Get ready for the next header.
58 this.headerStartOffset = this.offset;
59 break;
60 }
61
62 while (true) {
63 if (this.offset >= input.length)
64 return false;
65 if (input[this.offset++] & XML_TT_NO_MORE)
66 // Break and read the header.
67 break;
68 }
69
70 decoder.seek(this.headerStartOffset);
71 var typeAndVal = decoder.decodeTypeAndVal();
72 if (typeAndVal == null)
73 throw new Error("BinaryXMLStructureDecoder: Can't read header starting at offset " +
74 this.headerStartOffset);
75
76 // Set the next state based on the type.
77 var type = typeAndVal.t;
78 if (type == XML_DATTR)
79 // We already consumed the item. READ_HEADER_OR_CLOSE again.
80 // ccnb has rules about what must follow an attribute, but we are just scanning.
81 this.headerStartOffset = this.offset;
82 else if (type == XML_DTAG || type == XML_EXT) {
83 // Start a new level and READ_HEADER_OR_CLOSE again.
84 ++this.level;
85 this.headerStartOffset = this.offset;
86 }
87 else if (type == XML_TAG || type == XML_ATTR) {
88 if (type == XML_TAG)
89 // Start a new level and read the tag.
90 ++this.level;
91 // Minimum tag or attribute length is 1.
Jeff Thompson11dc9b62012-11-28 19:21:20 -080092 this.nBytesToRead = typeAndVal.v + 1;
Jeff Thompsondad617b2012-10-14 17:11:41 -070093 this.state = BinaryXMLStructureDecoder.READ_BYTES;
94 // ccnb has rules about what must follow an attribute, but we are just scanning.
95 }
96 else if (type == XML_BLOB || type == XML_UDATA) {
Jeff Thompson11dc9b62012-11-28 19:21:20 -080097 this.nBytesToRead = typeAndVal.v;
Jeff Thompsondad617b2012-10-14 17:11:41 -070098 this.state = BinaryXMLStructureDecoder.READ_BYTES;
99 }
100 else
101 throw new Error("BinaryXMLStructureDecoder: Unrecognized header type " + type);
102 break;
103
104 case BinaryXMLStructureDecoder.READ_BYTES:
Jeff Thompson11dc9b62012-11-28 19:21:20 -0800105 var nRemainingBytes = input.length - this.offset;
106 if (nRemainingBytes < this.nBytesToRead) {
Jeff Thompsondad617b2012-10-14 17:11:41 -0700107 // Need more.
Jeff Thompson11dc9b62012-11-28 19:21:20 -0800108 this.offset += nRemainingBytes;
109 this.nBytesToRead -= nRemainingBytes;
Jeff Thompsondad617b2012-10-14 17:11:41 -0700110 return false;
111 }
112 // Got the bytes. Read a new header or close.
Jeff Thompson11dc9b62012-11-28 19:21:20 -0800113 this.offset += this.nBytesToRead;
Jeff Thompsondad617b2012-10-14 17:11:41 -0700114 this.headerStartOffset = this.offset;
115 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
116 break;
117
118 default:
119 // We don't expect this to happen.
120 throw new Error("BinaryXMLStructureDecoder: Unrecognized state " + this.state);
121 }
122 }
123};