summaryrefslogtreecommitdiff
path: root/qpid/extras/dispatch/src/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/extras/dispatch/src/parse.c')
-rw-r--r--qpid/extras/dispatch/src/parse.c379
1 files changed, 379 insertions, 0 deletions
diff --git a/qpid/extras/dispatch/src/parse.c b/qpid/extras/dispatch/src/parse.c
new file mode 100644
index 0000000000..5a9c26b7ca
--- /dev/null
+++ b/qpid/extras/dispatch/src/parse.c
@@ -0,0 +1,379 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <qpid/dispatch/alloc.h>
+#include <qpid/dispatch/ctools.h>
+#include <qpid/dispatch/parse.h>
+#include <qpid/dispatch/amqp.h>
+
+DEQ_DECLARE(dx_parsed_field_t, dx_parsed_field_list_t);
+
+struct dx_parsed_field_t {
+ DEQ_LINKS(dx_parsed_field_t);
+ dx_parsed_field_t *parent;
+ dx_parsed_field_list_t children;
+ uint8_t tag;
+ dx_field_iterator_t *raw_iter;
+ const char *parse_error;
+};
+
+ALLOC_DECLARE(dx_parsed_field_t);
+ALLOC_DEFINE(dx_parsed_field_t);
+
+
+static char *get_type_info(dx_field_iterator_t *iter, uint8_t *tag, uint32_t *length, uint32_t *count)
+{
+ if (dx_field_iterator_end(iter))
+ return "Insufficient Data to Determine Tag";
+ *tag = dx_field_iterator_octet(iter);
+ *count = 0;
+ *length = 0;
+
+ switch (*tag & 0xF0) {
+ case 0x40: *length = 0; break;
+ case 0x50: *length = 1; break;
+ case 0x60: *length = 2; break;
+ case 0x70: *length = 4; break;
+ case 0x80: *length = 8; break;
+ case 0x90: *length = 16; break;
+ case 0xB0:
+ case 0xD0:
+ case 0xF0:
+ *length += ((unsigned int) dx_field_iterator_octet(iter)) << 24;
+ *length += ((unsigned int) dx_field_iterator_octet(iter)) << 16;
+ *length += ((unsigned int) dx_field_iterator_octet(iter)) << 8;
+ // fall through to the next case
+
+ case 0xA0:
+ case 0xC0:
+ case 0xE0:
+ if (dx_field_iterator_end(iter))
+ return "Insufficient Data to Determine Length";
+ *length += (unsigned int) dx_field_iterator_octet(iter);
+ break;
+
+ default:
+ return "Invalid Tag - No Length Information";
+ }
+
+ switch (*tag & 0xF0) {
+ case 0xD0:
+ case 0xF0:
+ *count += ((unsigned int) dx_field_iterator_octet(iter)) << 24;
+ *count += ((unsigned int) dx_field_iterator_octet(iter)) << 16;
+ *count += ((unsigned int) dx_field_iterator_octet(iter)) << 8;
+ // fall through to the next case
+
+ case 0xC0:
+ case 0xE0:
+ if (dx_field_iterator_end(iter))
+ return "Insufficient Data to Determine Count";
+ *count += (unsigned int) dx_field_iterator_octet(iter);
+ break;
+ }
+
+ if ((*tag == DX_AMQP_MAP8 || *tag == DX_AMQP_MAP32) && (*count & 1))
+ return "Odd Number of Elements in a Map";
+
+ return 0;
+}
+
+
+static dx_parsed_field_t *dx_parse_internal(dx_field_iterator_t *iter, dx_parsed_field_t *p)
+{
+ dx_parsed_field_t *field = new_dx_parsed_field_t();
+ if (!field)
+ return 0;
+
+ DEQ_ITEM_INIT(field);
+ DEQ_INIT(field->children);
+ field->parent = p;
+ field->raw_iter = 0;
+
+ uint32_t length;
+ uint32_t count;
+
+ field->parse_error = get_type_info(iter, &field->tag, &length, &count);
+
+ if (!field->parse_error) {
+ field->raw_iter = dx_field_iterator_sub(iter, length);
+ if (count == 0 && length > 0)
+ dx_field_iterator_advance(iter, length);
+ for (uint32_t idx = 0; idx < count; idx++) {
+ dx_parsed_field_t *child = dx_parse_internal(field->raw_iter, field);
+ DEQ_INSERT_TAIL(field->children, child);
+ if (!dx_parse_ok(child)) {
+ field->parse_error = child->parse_error;
+ break;
+ }
+ }
+ }
+
+ return field;
+}
+
+
+dx_parsed_field_t *dx_parse(dx_field_iterator_t *iter)
+{
+ return dx_parse_internal(iter, 0);
+}
+
+
+void dx_parse_free(dx_parsed_field_t *field)
+{
+ if (!field)
+ return;
+
+ assert(field->parent == 0);
+ if (field->raw_iter)
+ dx_field_iterator_free(field->raw_iter);
+
+ dx_parsed_field_t *sub_field = DEQ_HEAD(field->children);
+ while (sub_field) {
+ dx_parsed_field_t *next = DEQ_NEXT(sub_field);
+ DEQ_REMOVE_HEAD(field->children);
+ sub_field->parent = 0;
+ dx_parse_free(sub_field);
+ sub_field = next;
+ }
+
+ free_dx_parsed_field_t(field);
+}
+
+
+int dx_parse_ok(dx_parsed_field_t *field)
+{
+ return field->parse_error == 0;
+}
+
+
+const char *dx_parse_error(dx_parsed_field_t *field)
+{
+ return field->parse_error;
+}
+
+
+uint8_t dx_parse_tag(dx_parsed_field_t *field)
+{
+ return field->tag;
+}
+
+
+dx_field_iterator_t *dx_parse_raw(dx_parsed_field_t *field)
+{
+ return field->raw_iter;
+}
+
+
+uint32_t dx_parse_as_uint(dx_parsed_field_t *field)
+{
+ uint32_t result = 0;
+
+ dx_field_iterator_reset(field->raw_iter);
+
+ switch (field->tag) {
+ case DX_AMQP_UINT:
+ result |= ((uint32_t) dx_field_iterator_octet(field->raw_iter)) << 24;
+
+ case DX_AMQP_USHORT:
+ result |= ((uint32_t) dx_field_iterator_octet(field->raw_iter)) << 16;
+ result |= ((uint32_t) dx_field_iterator_octet(field->raw_iter)) << 8;
+ // Fall Through...
+
+ case DX_AMQP_UBYTE:
+ case DX_AMQP_SMALLUINT:
+ case DX_AMQP_BOOLEAN:
+ result |= (uint32_t) dx_field_iterator_octet(field->raw_iter);
+ break;
+
+ case DX_AMQP_TRUE:
+ result = 1;
+ break;
+ }
+
+ return result;
+}
+
+
+uint64_t dx_parse_as_ulong(dx_parsed_field_t *field)
+{
+ uint64_t result = 0;
+
+ dx_field_iterator_reset(field->raw_iter);
+
+ switch (field->tag) {
+ case DX_AMQP_ULONG:
+ result |= ((uint64_t) dx_field_iterator_octet(field->raw_iter)) << 56;
+ result |= ((uint64_t) dx_field_iterator_octet(field->raw_iter)) << 48;
+ result |= ((uint64_t) dx_field_iterator_octet(field->raw_iter)) << 40;
+ result |= ((uint64_t) dx_field_iterator_octet(field->raw_iter)) << 32;
+ result |= ((uint64_t) dx_field_iterator_octet(field->raw_iter)) << 24;
+ result |= ((uint64_t) dx_field_iterator_octet(field->raw_iter)) << 16;
+ result |= ((uint64_t) dx_field_iterator_octet(field->raw_iter)) << 8;
+ // Fall Through...
+
+ case DX_AMQP_SMALLULONG:
+ result |= (uint64_t) dx_field_iterator_octet(field->raw_iter);
+ // Fall Through...
+
+ case DX_AMQP_ULONG0:
+ break;
+ }
+
+ return result;
+}
+
+
+int32_t dx_parse_as_int(dx_parsed_field_t *field)
+{
+ int32_t result = 0;
+
+ dx_field_iterator_reset(field->raw_iter);
+
+ switch (field->tag) {
+ case DX_AMQP_INT:
+ result |= ((int32_t) dx_field_iterator_octet(field->raw_iter)) << 24;
+
+ case DX_AMQP_SHORT:
+ result |= ((int32_t) dx_field_iterator_octet(field->raw_iter)) << 16;
+ result |= ((int32_t) dx_field_iterator_octet(field->raw_iter)) << 8;
+ // Fall Through...
+
+ case DX_AMQP_BYTE:
+ case DX_AMQP_SMALLINT:
+ case DX_AMQP_BOOLEAN:
+ result |= (int32_t) dx_field_iterator_octet(field->raw_iter);
+ break;
+
+ case DX_AMQP_TRUE:
+ result = 1;
+ break;
+ }
+
+ return result;
+}
+
+
+int64_t dx_parse_as_long(dx_parsed_field_t *field)
+{
+ int64_t result = 0;
+
+ dx_field_iterator_reset(field->raw_iter);
+
+ switch (field->tag) {
+ case DX_AMQP_LONG:
+ result |= ((int64_t) dx_field_iterator_octet(field->raw_iter)) << 56;
+ result |= ((int64_t) dx_field_iterator_octet(field->raw_iter)) << 48;
+ result |= ((int64_t) dx_field_iterator_octet(field->raw_iter)) << 40;
+ result |= ((int64_t) dx_field_iterator_octet(field->raw_iter)) << 32;
+ result |= ((int64_t) dx_field_iterator_octet(field->raw_iter)) << 24;
+ result |= ((int64_t) dx_field_iterator_octet(field->raw_iter)) << 16;
+ result |= ((int64_t) dx_field_iterator_octet(field->raw_iter)) << 8;
+ // Fall Through...
+
+ case DX_AMQP_SMALLLONG:
+ result |= (uint64_t) dx_field_iterator_octet(field->raw_iter);
+ break;
+ }
+
+ return result;
+}
+
+
+uint32_t dx_parse_sub_count(dx_parsed_field_t *field)
+{
+ uint32_t count = DEQ_SIZE(field->children);
+
+ if (field->tag == DX_AMQP_MAP8 || field->tag == DX_AMQP_MAP32)
+ count = count >> 1;
+
+ return count;
+}
+
+
+dx_parsed_field_t *dx_parse_sub_key(dx_parsed_field_t *field, uint32_t idx)
+{
+ if (field->tag != DX_AMQP_MAP8 && field->tag != DX_AMQP_MAP32)
+ return 0;
+
+ idx = idx << 1;
+ dx_parsed_field_t *key = DEQ_HEAD(field->children);
+ while (idx && key) {
+ idx--;
+ key = DEQ_NEXT(key);
+ }
+
+ return key;
+}
+
+
+dx_parsed_field_t *dx_parse_sub_value(dx_parsed_field_t *field, uint32_t idx)
+{
+ if (field->tag == DX_AMQP_MAP8 || field->tag == DX_AMQP_MAP32)
+ idx = (idx << 1) + 1;
+
+ dx_parsed_field_t *key = DEQ_HEAD(field->children);
+ while (idx && key) {
+ idx--;
+ key = DEQ_NEXT(key);
+ }
+
+ return key;
+}
+
+
+int dx_parse_is_map(dx_parsed_field_t *field)
+{
+ return field->tag == DX_AMQP_MAP8 || field->tag == DX_AMQP_MAP32;
+}
+
+
+int dx_parse_is_list(dx_parsed_field_t *field)
+{
+ return field->tag == DX_AMQP_LIST8 || field->tag == DX_AMQP_LIST32;
+}
+
+
+int dx_parse_is_scalar(dx_parsed_field_t *field)
+{
+ return DEQ_SIZE(field->children) == 0;
+}
+
+
+dx_parsed_field_t *dx_parse_value_by_key(dx_parsed_field_t *field, const char *key)
+{
+ uint32_t count = dx_parse_sub_count(field);
+
+ for (uint32_t idx = 0; idx < count; idx++) {
+ dx_parsed_field_t *sub = dx_parse_sub_key(field, idx);
+ if (!sub)
+ return 0;
+
+ dx_field_iterator_t *iter = dx_parse_raw(sub);
+ if (!iter)
+ return 0;
+
+ if (dx_field_iterator_equal(iter, (const unsigned char*) key)) {
+ return dx_parse_sub_value(field, idx);
+ }
+ }
+
+ return 0;
+}
+