blob: fcc36f11b8351da210a6f48078519b41bbc4cad2 [file] [log] [blame]
/*
* This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to
* determine its end.
*
* @author: Jeff Thompson
* See COPYING for copyright and distribution information.
*/
var BinaryXMLStructureDecoder = function BinaryXMLDecoder() {
this.gotElementEnd = false;
this.offset = 0;
this.level = 0;
this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
this.headerStartOffset = 0;
this.nBytesToRead = 0;
};
BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE = 0;
BinaryXMLStructureDecoder.READ_BYTES = 1;
/*
* Continue scanning input starting from this.offset. If found the end of the element
* which started at offset 0 then return true, else false.
* If this returns false, you should read more into input and call again.
* You have to pass in input each time because the array could be reallocated.
* This throws an exception for badly formed ccnb.
*/
BinaryXMLStructureDecoder.prototype.findElementEnd = function(
// byte array
input)
{
if (this.gotElementEnd)
// Someone is calling when we already got the end.
return true;
var decoder = new BinaryXMLDecoder(input);
while (true) {
if (this.offset >= input.length)
// All the cases assume we have some input.
return false;
switch (this.state) {
case BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE:
// First check for XML_CLOSE.
if (this.offset == this.headerStartOffset && input[this.offset] == XML_CLOSE) {
++this.offset;
// Close the level.
--this.level;
if (this.level == 0)
// Finished.
return true;
if (this.level < 0)
throw new Error("BinaryXMLStructureDecoder: Unexepected close tag at offset " +
(this.offset - 1));
// Get ready for the next header.
this.headerStartOffset = this.offset;
break;
}
while (true) {
if (this.offset >= input.length)
return false;
if (input[this.offset++] & XML_TT_NO_MORE)
// Break and read the header.
break;
}
decoder.seek(this.headerStartOffset);
var typeAndVal = decoder.decodeTypeAndVal();
if (typeAndVal == null)
throw new Error("BinaryXMLStructureDecoder: Can't read header starting at offset " +
this.headerStartOffset);
// Set the next state based on the type.
var type = typeAndVal.t;
if (type == XML_DATTR)
// We already consumed the item. READ_HEADER_OR_CLOSE again.
// ccnb has rules about what must follow an attribute, but we are just scanning.
this.headerStartOffset = this.offset;
else if (type == XML_DTAG || type == XML_EXT) {
// Start a new level and READ_HEADER_OR_CLOSE again.
++this.level;
this.headerStartOffset = this.offset;
}
else if (type == XML_TAG || type == XML_ATTR) {
if (type == XML_TAG)
// Start a new level and read the tag.
++this.level;
// Minimum tag or attribute length is 1.
this.nBytesToRead = typeAndVal.v + 1;
this.state = BinaryXMLStructureDecoder.READ_BYTES;
// ccnb has rules about what must follow an attribute, but we are just scanning.
}
else if (type == XML_BLOB || type == XML_UDATA) {
this.nBytesToRead = typeAndVal.v;
this.state = BinaryXMLStructureDecoder.READ_BYTES;
}
else
throw new Error("BinaryXMLStructureDecoder: Unrecognized header type " + type);
break;
case BinaryXMLStructureDecoder.READ_BYTES:
var nRemainingBytes = input.length - this.offset;
if (nRemainingBytes < this.nBytesToRead) {
// Need more.
this.offset += nRemainingBytes;
this.nBytesToRead -= nRemainingBytes;
return false;
}
// Got the bytes. Read a new header or close.
this.offset += this.nBytesToRead;
this.headerStartOffset = this.offset;
this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
break;
default:
// We don't expect this to happen.
throw new Error("BinaryXMLStructureDecoder: Unrecognized state " + this.state);
}
}
};