+%module XML_Template_SWIG
+
+%{
+
+#include "../c++11/xml-template.h"
+
+bool is_associative_array(HashTable *ht)
+{
+ if (ht->nNumOfElements == 0) {
+ return true;
+ }
+ for (unsigned i = 0; i < ht->nNumOfElements; ++i) {
+ char buf[32];
+ sprintf(buf, "%u", i);
+ if (!zend_hash_exists(ht, buf, strlen(buf))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+Directive* convert_php_objects_to_directive(zval *obj)
+{
+ switch (Z_TYPE_P(obj)) {
+ case IS_ARRAY: {
+ HashTable *ht = Z_ARRVAL_P(obj);
+ if (is_associative_array(ht)) {
+ std::unordered_map<std::string, Directive *> my_map;
+ for (zend_hash_internal_pointer_reset(ht); zend_hash_has_more_elements(ht) == SUCCESS; zend_hash_move_forward(ht)) {
+ char *str_key;
+ ulong num_key;
+ zend_hash_get_current_key(ht, &str_key, &num_key, 0);
+
+ std::string key;
+ if (zend_hash_get_current_key_type(ht) == HASH_KEY_IS_STRING) {
+ key = str_key;
+ } else {
+ char buf[32];
+ sprintf(buf, "%lu", num_key);
+ key = buf;
+ }
+
+ zval **data;
+ zend_hash_get_current_data(ht, (void **)&data);
+ my_map.insert(make_pair(key, convert_php_objects_to_directive(*data)));
+ }
+ return new Substitute(my_map);
+ } else {
+ printf("ARRAY\n");
+ }
+ break;
+ }
+ case IS_STRING: {
+ char *str = Z_STRVAL_P(obj);
+ return new Replace(str);
+ }
+ default:
+ printf("WARNING: Unknown type %d!\n", Z_TYPE_P(obj));
+ break;
+ }
+
+ return NULL;
+}
+
+%}
+
+%typemap(in) Directive* {
+ $1 = convert_php_objects_to_directive(*$input);
+}
+
+xmlDocPtr process_file(const char *input_filename, Directive *root_directive, bool clean);
+void output_to_fd_and_free(xmlDocPtr doc, int fd);
+