Added ndn_BinaryXMLStructureDecoder_findElementEnd
diff --git a/ndn-cpp/encoding/BinaryXMLStructureDecoder.c b/ndn-cpp/encoding/BinaryXMLStructureDecoder.c
index a5568d4..e5668d6 100644
--- a/ndn-cpp/encoding/BinaryXMLStructureDecoder.c
+++ b/ndn-cpp/encoding/BinaryXMLStructureDecoder.c
@@ -4,9 +4,13 @@
  * BSD license, See the LICENSE file for more information.
  */
 
+#include <memory.h>
+#include "BinaryXML.h"
+#include "BinaryXMLDecoder.h"
 #include "BinaryXMLStructureDecoder.h"
 
-void ndn_BinaryXMLStructureDecoder_init(struct ndn_BinaryXMLStructureDecoder *self) {
+void ndn_BinaryXMLStructureDecoder_init(struct ndn_BinaryXMLStructureDecoder *self) 
+{
   self->gotElementEnd = 0;
   self->offset = 0;
   self->level = 0;
@@ -15,3 +19,131 @@
   self->useHeaderBuffer = 0;
   self->nBytesToRead = 0;
 }
+
+/**
+ * Set the state to READ_HEADER_OR_CLOSE and set up to start reading the header.
+ */
+static inline void startHeader(struct ndn_BinaryXMLStructureDecoder *self) {
+  self->headerLength = 0;
+  self->useHeaderBuffer = 0;
+  self->state = ndn_BinaryXMLStructureDecoder_READ_HEADER_OR_CLOSE;    
+}
+
+const char *ndn_BinaryXMLStructureDecoder_findElementEnd
+  (struct ndn_BinaryXMLStructureDecoder *self, const unsigned char *input, unsigned int inputLength) 
+{
+  if (self->gotElementEnd)
+    // Someone is calling when we already got the end.
+    return (const char *)0;
+  
+  struct ndn_BinaryXMLDecoder decoder;
+  ndn_BinaryXMLDecoder_init(&decoder, input, inputLength);
+  
+  while (1) {
+    if (self->offset >= inputLength)
+      // All the cases assume we have some input. Return and wait for more.
+      return (const char *)0;
+    
+    if (self->state == ndn_BinaryXMLStructureDecoder_READ_HEADER_OR_CLOSE) {
+      // First check for CLOSE.
+      if (self->headerLength == 0 && input[self->offset] == ndn_BinaryXML_CLOSE) {
+        ++self->offset;
+        // Close the level.
+        --self->level;
+        if (self->level == 0) {
+          // Finished.
+          self->gotElementEnd = 1;
+          return (const char *)0;
+        }
+        if (self->level < 0)
+          return "ndn_BinaryXMLStructureDecoder_findElementEnd: Unexpected close tag";
+          
+        // Get ready for the next header.
+        startHeader(self);
+        continue;
+      }
+        
+      unsigned int startingHeaderLength = self->headerLength;
+      while (1) {
+        if (self->offset >= inputLength) {
+          // We can't get all of the header bytes from this input. Save in headerBuffer.
+          if (self->headerLength > sizeof(self->headerBuffer))
+            return "ndn_BinaryXMLStructureDecoder_findElementEnd: Can't store more header bytes than the size of headerBuffer";
+          self->useHeaderBuffer = 1;
+          unsigned int nNewBytes = self->headerLength - startingHeaderLength;
+          memcpy(self->headerBuffer + startingHeaderLength, input + (self->offset - nNewBytes), nNewBytes);
+            
+          return (const char *)0;
+        }
+        unsigned int headerByte = (unsigned int)input[self->offset++];
+        ++self->headerLength;
+        if (headerByte & ndn_BinaryXML_TT_FINAL)
+          // Break and read the header.
+          break;
+      }
+        
+      unsigned int type;
+      unsigned int value;
+      if (self->useHeaderBuffer) {
+        // Copy the remaining bytes into headerBuffer.
+        if (self->headerLength > sizeof(self->headerBuffer))
+          return "ndn_BinaryXMLStructureDecoder_findElementEnd: Can't store more header bytes than the size of headerBuffer";
+        unsigned int nNewBytes = self->headerLength - startingHeaderLength;
+        memcpy(self->headerBuffer + startingHeaderLength, input + (self->offset - nNewBytes), nNewBytes);
+
+        // Use a local decoder just for the headerBuffer.
+        struct ndn_BinaryXMLDecoder bufferDecoder;
+        ndn_BinaryXMLDecoder_init(&bufferDecoder, self->headerBuffer, sizeof(self->headerBuffer));
+        if (ndn_BinaryXMLDecoder_decodeTypeAndValue(&decoder, &type, &value))
+          return "ndn_BinaryXMLStructureDecoder_findElementEnd: Can't read header type and value";
+      }
+      else {
+        // We didn't have to use the headerBuffer.
+        ndn_BinaryXMLDecoder_seek(&decoder, self->offset - self->headerLength);
+        if (ndn_BinaryXMLDecoder_decodeTypeAndValue(&decoder, &type, &value))
+          return "ndn_BinaryXMLStructureDecoder_findElementEnd: Can't read header type and value";
+      }
+        
+      // Set the next state based on the type.
+      if (type == ndn_BinaryXML_DATTR)
+        // We already consumed the item. READ_HEADER_OR_CLOSE again.
+        // Binary XML has rules about what must follow an attribute, but we are just scanning.
+        startHeader(self);
+      else if (type == ndn_BinaryXML_DTAG || type == ndn_BinaryXML_EXT) {
+        // Start a new level and READ_HEADER_OR_CLOSE again.
+        ++self->level;
+        startHeader(self);
+      }
+      else if (type == ndn_BinaryXML_TAG || type == ndn_BinaryXML_ATTR) {
+        if (type == ndn_BinaryXML_TAG)
+          // Start a new level and read the tag.
+          ++self->level;
+        // Minimum tag or attribute length is 1.
+        self->nBytesToRead = value + 1;
+        self->state = ndn_BinaryXMLStructureDecoder_READ_BYTES;
+        // Binary XML has rules about what must follow an attribute, but we are just scanning.
+      }
+      else if (type == ndn_BinaryXML_BLOB || type == ndn_BinaryXML_UDATA) {
+        self->nBytesToRead = value;
+        self->state = ndn_BinaryXMLStructureDecoder_READ_BYTES;
+      }
+      else
+        return "ndn_BinaryXMLStructureDecoder_findElementEnd: Unrecognized header type";
+    }  
+    else if (self->state == ndn_BinaryXMLStructureDecoder_READ_BYTES) {
+      unsigned int nRemainingBytes = inputLength - self->offset;
+      if (nRemainingBytes < self->nBytesToRead) {
+        // Need more.
+        self->offset += nRemainingBytes;
+        self->nBytesToRead -= nRemainingBytes;
+        return (const char *)0;
+      }
+      // Got the bytes. Read a new header or close.
+      self->offset += self->nBytesToRead;
+      startHeader(self);
+    }
+    else
+      // We don't expect this to happen.
+      return "ndn_BinaryXMLStructureDecoder_findElementEnd: Unrecognized state";
+  }
+}