xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
                           xmlCharEncodingOutputFunc escaping) {
    int nbchars = 0; /* number of chars to output to I/O */
    int ret;         /* return from function call */
    int written = 0; /* number of char written to I/O so far */
    int oldwritten=0;/* loop guard */
    int chunk;       /* number of byte currently processed from str */
    int len;         /* number of bytes in str */
    int cons;        /* byte from str consumed */

    if ((out == NULL) || (out->error) || (str == NULL) ||
        (out->buffer == NULL) ||
	(xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
        return(-1);
    len = strlen((const char *)str);
    if (len < 0) return(0);
    if (out->error) return(-1);
    if (escaping == NULL) escaping = xmlEscapeContent;

    do {
        oldwritten = written;

        /*
	 * how many bytes to consume and how many bytes to store.
	 */
	cons = len;
	chunk = xmlBufAvail(out->buffer) - 1;

        /*
	 * make sure we have enough room to save first, if this is
	 * not the case force a flush, but make sure we stay in the loop
	 */
	if (chunk < 40) {
	    if (xmlBufGrow(out->buffer, 100) < 0)
	        return(-1);
            oldwritten = -1;
	    continue;
	}

	/*
	 * first handle encoding stuff.
	 */
	if (out->encoder != NULL) {
	    /*
	     * Store the data in the incoming raw buffer
	     */
	    if (out->conv == NULL) {
		out->conv = xmlBufCreate();
	    }
	    ret = escaping(xmlBufEnd(out->buffer) ,
	                   &chunk, str, &cons);
	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
	        return(-1);
            xmlBufAddLen(out->buffer, chunk);

	    if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
		goto done;

	    /*
	     * convert as much as possible to the output buffer.
	     */
	    ret = xmlCharEncOutput(out, 0);
	    if ((ret < 0) && (ret != -3)) {
		xmlIOErr(XML_IO_ENCODER, NULL);
		out->error = XML_IO_ENCODER;
		return(-1);
	    }
	    nbchars = xmlBufUse(out->conv);
	} else {
	    ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
	        return(-1);
            xmlBufAddLen(out->buffer, chunk);
	    nbchars = xmlBufUse(out->buffer);
	}
	str += cons;
	len -= cons;

	if ((nbchars < MINLEN) && (len <= 0))
	    goto done;

	if (out->writecallback) {
	    /*
	     * second write the stuff to the I/O channel
	     */
	    if (out->encoder != NULL) {
		ret = out->writecallback(out->context,
                           (const char *)xmlBufContent(out->conv), nbchars);
		if (ret >= 0)
		    xmlBufShrink(out->conv, ret);
	    } else {
		ret = out->writecallback(out->context,
                           (const char *)xmlBufContent(out->buffer), nbchars);
		if (ret >= 0)
		    xmlBufShrink(out->buffer, ret);
	    }
	    if (ret < 0) {
		xmlIOErr(XML_IO_WRITE, NULL);
		out->error = XML_IO_WRITE;
		return(ret);
	    }
	    out->written += ret;
	} else if (xmlBufAvail(out->buffer) < MINLEN) {
	    xmlBufGrow(out->buffer, MINLEN);
	}
	written += nbchars;
    } while ((len > 0) && (oldwritten != written));

done:
#ifdef DEBUG_INPUT
    xmlGenericError(xmlGenericErrorContext,
	    "I/O: wrote %d chars\n", written);
#endif
    return(written);
}