Added BinaryXMLStructureDecoder.  Use it in NDNSocketTransportService to detect the end of the input (instead of the hack to try to decode a ContentObject).
diff --git a/js/encoding/BinaryXMLStructureDecoder.js b/js/encoding/BinaryXMLStructureDecoder.js
new file mode 100644
index 0000000..4ad3de9
--- /dev/null
+++ b/js/encoding/BinaryXMLStructureDecoder.js
@@ -0,0 +1,121 @@
+/*
+ * This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to 
+ * determine its end.
+ * 
+ * @author: ucla-cs
+ * 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.readBytesEndOffset = 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.readBytesEndOffset = this.offset + 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.readBytesEndOffset = this.offset + typeAndVal.v;
+                    this.state = BinaryXMLStructureDecoder.READ_BYTES;
+                }
+                else
+                    throw new Error("BinaryXMLStructureDecoder: Unrecognized header type " + type);
+                break;
+            
+            case BinaryXMLStructureDecoder.READ_BYTES:
+                if (input.length < this.readBytesEndOffset) {
+                    // Need more.
+                    this.offset = input.length;
+                    return false;
+                }
+                // Got the bytes.  Read a new header or close.
+                this.offset = this.readBytesEndOffset;
+                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);
+        }
+    }
+};