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";
+ }
+}
diff --git a/ndn-cpp/encoding/BinaryXMLStructureDecoder.h b/ndn-cpp/encoding/BinaryXMLStructureDecoder.h
index ad10fcf..58a595f 100644
--- a/ndn-cpp/encoding/BinaryXMLStructureDecoder.h
+++ b/ndn-cpp/encoding/BinaryXMLStructureDecoder.h
@@ -23,11 +23,26 @@
int nBytesToRead;
};
-const int ndn_BinaryXMLStructureDecoder_READ_HEADER_OR_CLOSE = 0;
-const int ndn_BinaryXMLStructureDecoder_READ_BYTES = 1;
+enum {
+ ndn_BinaryXMLStructureDecoder_READ_HEADER_OR_CLOSE,
+ ndn_BinaryXMLStructureDecoder_READ_BYTES
+};
void ndn_BinaryXMLStructureDecoder_init(struct ndn_BinaryXMLStructureDecoder *self);
+/**
+ * Continue scanning input starting from self->offset to find the element end. On return, you must check
+ * self->gotElementEnd: If the end of the element which started at offset 0 is found,
+ * then self->gotElementEnd is 1 and self->offset is the length of the element. Otherwise, self-forElementEnd is 0
+ * which means you should read more into input and call again.
+ * @param self pointer to the ndn_BinaryXMLStructureDecoder struct
+ * @param input the input buffer. You have to pass in input each time because the buffer could be reallocated.
+ * @param inputLength the number of bytes in input.
+ * @return 0 for success, else an error string
+ */
+const char *ndn_BinaryXMLStructureDecoder_findElementEnd
+ (struct ndn_BinaryXMLStructureDecoder *self, const unsigned char *input, unsigned int inputLength);
+
#ifdef __cplusplus
}
#endif