static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr sdl)
{
	smart_str buf = {0};
	smart_str *out = &buf;
	int i;
	int type_num = 1;
	int encoder_num = 1;
	int f;
	const encode *enc;
	HashTable tmp_types;
	HashTable tmp_encoders;
	HashTable tmp_bindings;
	HashTable tmp_functions;

#ifdef ZEND_WIN32
	f = open(fn,O_CREAT|O_WRONLY|O_EXCL|O_BINARY,S_IREAD|S_IWRITE);
#else
	f = open(fn,O_CREAT|O_WRONLY|O_EXCL|O_BINARY,S_IREAD|S_IWRITE);
#endif
	if (f < 0) {return;}

	zend_hash_init(&tmp_types, 0, NULL, NULL, 0);
	zend_hash_init(&tmp_encoders, 0, NULL, NULL, 0);
	zend_hash_init(&tmp_bindings, 0, NULL, NULL, 0);
	zend_hash_init(&tmp_functions, 0, NULL, NULL, 0);

	WSDL_CACHE_PUT_N("wsdl", 4, out);
	WSDL_CACHE_PUT_1(WSDL_CACHE_VERSION,out);
	WSDL_CACHE_PUT_1(0,out);
	WSDL_CACHE_PUT_N(&t, sizeof(t), out);

	sdl_serialize_string(uri, out);
	sdl_serialize_string(sdl->source, out);
	sdl_serialize_string(sdl->target_ns, out);

	if (sdl->groups) {
		i = zend_hash_num_elements(sdl->groups);
	} else {
		i = 0;
	}
	WSDL_CACHE_PUT_INT(i, out);
	if (i > 0) {
		sdlTypePtr tmp;
		zval zv;

		ZEND_HASH_FOREACH_PTR(sdl->groups, tmp) {
			ZVAL_LONG(&zv, type_num);
			zend_hash_str_add(&tmp_types, (char*)&tmp, sizeof(tmp), &zv);
			++type_num;
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->types) {
		i = zend_hash_num_elements(sdl->types);
	} else {
		i = 0;
	}
	WSDL_CACHE_PUT_INT(i, out);
	if (i > 0) {
		sdlTypePtr tmp;
		zval zv;

		ZEND_HASH_FOREACH_PTR(sdl->types, tmp) {
			ZVAL_LONG(&zv,  type_num);
			zend_hash_str_add(&tmp_types, (char*)&tmp, sizeof(tmp), &zv);
			++type_num;
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->elements) {
		i = zend_hash_num_elements(sdl->elements);
	} else {
		i = 0;
	}
	WSDL_CACHE_PUT_INT(i, out);
	if (i > 0) {
		sdlTypePtr tmp;
		zval zv;

		ZEND_HASH_FOREACH_PTR(sdl->elements, tmp) {
			ZVAL_LONG(&zv, type_num);
			zend_hash_str_add(&tmp_types, (char*)&tmp, sizeof(tmp), &zv);
			++type_num;
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->encoders) {
		i = zend_hash_num_elements(sdl->encoders);
	} else {
		i = 0;
	}
	WSDL_CACHE_PUT_INT(i, out);
	if (i > 0) {
		encodePtr tmp;
		zval zv;

		ZEND_HASH_FOREACH_PTR(sdl->encoders, tmp) {
			ZVAL_LONG(&zv, encoder_num);
			zend_hash_str_add(&tmp_encoders, (char*)&tmp, sizeof(tmp), &zv);
			++encoder_num;
		} ZEND_HASH_FOREACH_END();
	}
	enc = defaultEncoding;
	while (enc->details.type != END_KNOWN_TYPES) {
		zval zv;

		ZVAL_LONG(&zv, encoder_num);
		zend_hash_str_add(&tmp_encoders, (char*)&enc, sizeof(encodePtr), &zv);
		enc++;
		++encoder_num;
	}

	if (sdl->groups) {
		sdlTypePtr tmp;
		zend_string *key;

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->groups, key, tmp) {
			sdl_serialize_key(key, out);
			sdl_serialize_type(tmp, &tmp_encoders, &tmp_types, out);
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->types) {
		sdlTypePtr tmp;
		zend_string *key;

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->types, key, tmp) {
			sdl_serialize_key(key, out);
			sdl_serialize_type(tmp, &tmp_encoders, &tmp_types, out);
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->elements) {
		sdlTypePtr tmp;
		zend_string *key;

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->elements, key, tmp) {
			sdl_serialize_key(key, out);
			sdl_serialize_type(tmp, &tmp_encoders, &tmp_types, out);
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->encoders) {
		encodePtr tmp;
		zend_string *key;

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->encoders, key, tmp) {
			sdl_serialize_key(key, out);
			sdl_serialize_encoder(tmp, &tmp_types, out);
		} ZEND_HASH_FOREACH_END();
	}

	/* serialize bindings */
	if (sdl->bindings) {
		i = zend_hash_num_elements(sdl->bindings);
	} else {
		i = 0;
	}
	WSDL_CACHE_PUT_INT(i, out);
	if (i > 0) {
		sdlBindingPtr tmp;
		int binding_num = 1;
		zval zv;
		zend_string *key;

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->bindings, key, tmp) {
			sdl_serialize_key(key, out);
			sdl_serialize_string(tmp->name, out);
			sdl_serialize_string(tmp->location, out);
			WSDL_CACHE_PUT_1(tmp->bindingType,out);
			if (tmp->bindingType == BINDING_SOAP && tmp->bindingAttributes != NULL) {
				sdlSoapBindingPtr binding = (sdlSoapBindingPtr)tmp->bindingAttributes;
				WSDL_CACHE_PUT_1(binding->style, out);
				WSDL_CACHE_PUT_1(binding->transport, out);
			} else {
				WSDL_CACHE_PUT_1(0,out);
			}

			ZVAL_LONG(&zv, binding_num);
			zend_hash_str_add(&tmp_bindings, (char*)&tmp, sizeof(tmp), &zv);
			binding_num++;
		} ZEND_HASH_FOREACH_END();
	}

	/* serialize functions */
	i = zend_hash_num_elements(&sdl->functions);
	WSDL_CACHE_PUT_INT(i, out);
	if (i > 0) {
		sdlFunctionPtr tmp;
		zval *binding_num, zv;
		int function_num = 1;
		zend_string *key;

		ZEND_HASH_FOREACH_STR_KEY_PTR(&sdl->functions, key, tmp) {
			sdl_serialize_key(key, out);
			sdl_serialize_string(tmp->functionName, out);
			sdl_serialize_string(tmp->requestName, out);
			sdl_serialize_string(tmp->responseName, out);

			if (tmp->binding) {
				binding_num = zend_hash_str_find(&tmp_bindings,(char*)&tmp->binding, sizeof(tmp->binding));
				if (binding_num) {
					WSDL_CACHE_PUT_INT(Z_LVAL_P(binding_num), out);
					if (Z_LVAL_P(binding_num) >= 0) {
						if (tmp->binding->bindingType == BINDING_SOAP && tmp->bindingAttributes != NULL) {
							sdlSoapBindingFunctionPtr binding = (sdlSoapBindingFunctionPtr)tmp->bindingAttributes;
							WSDL_CACHE_PUT_1(binding->style, out);
							sdl_serialize_string(binding->soapAction, out);
							sdl_serialize_soap_body(&binding->input, &tmp_encoders, &tmp_types, out);
							sdl_serialize_soap_body(&binding->output, &tmp_encoders, &tmp_types, out);
						} else {
							WSDL_CACHE_PUT_1(0,out);
						}
					}
				}
			}
			sdl_serialize_parameters(tmp->requestParameters, &tmp_encoders, &tmp_types, out);
			sdl_serialize_parameters(tmp->responseParameters, &tmp_encoders, &tmp_types, out);

			if (tmp->faults) {
				sdlFaultPtr fault;
				zend_string *key;

				WSDL_CACHE_PUT_INT(zend_hash_num_elements(tmp->faults), out);

				ZEND_HASH_FOREACH_STR_KEY_PTR(tmp->faults, key, fault) {
					sdl_serialize_key(key, out);
					sdl_serialize_string(fault->name, out);
					sdl_serialize_parameters(fault->details, &tmp_encoders, &tmp_types, out);
					if (tmp->binding->bindingType == BINDING_SOAP && fault->bindingAttributes != NULL) {
						sdlSoapBindingFunctionFaultPtr binding = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
						WSDL_CACHE_PUT_1(binding->use, out);
						if (binding->use == SOAP_ENCODED) {
							WSDL_CACHE_PUT_1(binding->encodingStyle, out);
						}
						sdl_serialize_string(binding->ns, out);
					} else {
						WSDL_CACHE_PUT_1(0, out);
					}
				} ZEND_HASH_FOREACH_END();
			} else {
				WSDL_CACHE_PUT_INT(0, out);
			}

			ZVAL_LONG(&zv, function_num);
			zend_hash_str_add(&tmp_functions, (char*)&tmp, sizeof(tmp), &zv);
			function_num++;
		} ZEND_HASH_FOREACH_END();
	}

	/* serialize requests */
	if (sdl->requests) {
		i = zend_hash_num_elements(sdl->requests);
	} else {
		i = 0;
	}
	WSDL_CACHE_PUT_INT(i, out);
	if (i > 0) {
		sdlFunctionPtr tmp;
		zval *function_num;
		zend_string *key;

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->requests, key, tmp) {
			function_num = zend_hash_str_find(&tmp_functions, (char*)&tmp, sizeof(tmp));
			WSDL_CACHE_PUT_INT(Z_LVAL_P(function_num), out);
			sdl_serialize_key(key, out);
		} ZEND_HASH_FOREACH_END();
	}

	php_ignore_value(write(f, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)));
	close(f);
	smart_str_free(&buf);
	zend_hash_destroy(&tmp_functions);
	zend_hash_destroy(&tmp_bindings);
	zend_hash_destroy(&tmp_encoders);
	zend_hash_destroy(&tmp_types);
}