_XimProtoGetICValues(
    XIC			 xic,
    XIMArg		*arg)
{
    Xic			 ic = (Xic)xic;
    Xim			 im = (Xim)ic->core.im;
    register XIMArg	*p;
    register XIMArg	*pp;
    register int	 n;
    CARD8		*buf;
    CARD16		*buf_s;
    INT16		 len;
    CARD32		 reply32[BUFSIZE/4];
    char		*reply = (char *)reply32;
    XPointer		 preply = NULL;
    int			 buf_size;
    int			 ret_code;
    char		*makeid_name;
    char		*decode_name;
    CARD16		*data = NULL;
    INT16		 data_len = 0;

#ifndef XIM_CONNECTABLE
    if (!IS_IC_CONNECTED(ic))
	return arg->name;
#else
    if (!IS_IC_CONNECTED(ic)) {
	if (IS_CONNECTABLE(im)) {
	    if (_XimConnectServer(im)) {
		if (!_XimReCreateIC(ic)) {
		    _XimDelayModeSetAttr(im);
	            return _XimDelayModeGetICValues(ic, arg);
		}
	    } else {
	        return _XimDelayModeGetICValues(ic, arg);
	    }
        } else {
	    return arg->name;
        }
    }
#endif /* XIM_CONNECTABLE */

    for (n = 0, p = arg; p && p->name; p++) {
	n++;
	if ((strcmp(p->name, XNPreeditAttributes) == 0)
	 || (strcmp(p->name, XNStatusAttributes) == 0)) {
	     n++;
	     for (pp = (XIMArg *)p->value; pp && pp->name; pp++)
	 	n++;
	}
    }

    if (!n)
	return (char *)NULL;

    buf_size =  sizeof(CARD16) * n;
    buf_size += XIM_HEADER_SIZE
	     + sizeof(CARD16)
	     + sizeof(CARD16)
	     + sizeof(INT16)
	     + XIM_PAD(2 + buf_size);

    if (!(buf = Xmalloc(buf_size)))
	return arg->name;
    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];

    makeid_name = _XimMakeICAttrIDList(ic, ic->private.proto.ic_resources,
				ic->private.proto.ic_num_resources, arg,
				&buf_s[3], &len, XIM_GETICVALUES);

    if (len > 0) {
	buf_s[0] = im->private.proto.imid;		/* imid */
	buf_s[1] = ic->private.proto.icid;		/* icid */
	buf_s[2] = len;				/* length of ic-attr-id */
	len += sizeof(INT16);                       /* sizeof length of attr */
	XIM_SET_PAD(&buf_s[2], len);		/* pad */
	len += sizeof(CARD16)			/* sizeof imid */
	     + sizeof(CARD16);			/* sizeof icid */

	_XimSetHeader((XPointer)buf, XIM_GET_IC_VALUES, 0, &len);
	if (!(_XimWrite(im, len, (XPointer)buf))) {
	    Xfree(buf);
	    return arg->name;
	}
	_XimFlush(im);
	Xfree(buf);
	buf_size = BUFSIZE;
	ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
				 _XimGetICValuesCheck, (XPointer)ic);
	if (ret_code == XIM_TRUE) {
	    preply = reply;
	} else if (ret_code == XIM_OVERFLOW) {
	    if (len <= 0) {
		preply = reply;
	    } else {
		buf_size = (int)len;
		preply = Xmalloc(len);
		ret_code = _XimRead(im, &len, preply, buf_size,
				_XimGetICValuesCheck, (XPointer)ic);
		if (ret_code != XIM_TRUE) {
		    if (preply != reply)
		        Xfree(preply);
		    return arg->name;
		}
	    }
	} else {
	    return arg->name;
	}
	buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
	if (*((CARD8 *)preply) == XIM_ERROR) {
	    _XimProcError(im, 0, (XPointer)&buf_s[3]);
	    if (reply != preply)
		Xfree(preply);
	    return arg->name;
	}
	data = &buf_s[4];
	data_len = buf_s[2];
    }
    else if (len < 0) {
	return arg->name;
    }

    decode_name = _XimDecodeICATTRIBUTE(ic, ic->private.proto.ic_resources,
			ic->private.proto.ic_num_resources, data, data_len,
			arg, XIM_GETICVALUES);
    if (reply != preply)
	Xfree(preply);

    if (decode_name)
	return decode_name;
    else
	return makeid_name;
}


_XimProtoSetIMValues(
    XIM			 xim,
    XIMArg		*arg)
{
    Xim			 im = (Xim)xim;
    XimDefIMValues	 im_values;
    INT16		 len;
    CARD16		*buf_s;
    char		*tmp;
    CARD32		 tmp_buf32[BUFSIZE/4];
    char		*tmp_buf = (char *)tmp_buf32;
    char		*buf;
    int			 buf_size;
    char		*data;
    int			 data_len;
    int			 ret_len;
    int			 total;
    XIMArg		*arg_ret;
    CARD32		 reply32[BUFSIZE/4];
    char		*reply = (char *)reply32;
    XPointer		 preply;
    int			 ret_code;
    char		*name;

#ifndef XIM_CONNECTABLE
    if (!IS_SERVER_CONNECTED(im))
	return arg->name;
#else
    if (!_XimSaveIMValues(im, arg))
	return arg->name;

    if (!IS_SERVER_CONNECTED(im)) {
	if (IS_CONNECTABLE(im)) {
	    if (!_XimConnectServer(im)) {
	        return _XimDelayModeSetIMValues(im, arg);
	    }
        } else {
	    return arg->name;
        }
    }
#endif /* XIM_CONNECTABLE */

    _XimGetCurrentIMValues(im, &im_values);
    buf = tmp_buf;
    buf_size = XIM_HEADER_SIZE + sizeof(CARD16) + sizeof(INT16);
    data_len = BUFSIZE - buf_size;
    total = 0;
    arg_ret = arg;
    for (;;) {
	data = &buf[buf_size];
	if ((name = _XimEncodeIMATTRIBUTE(im, im->core.im_resources,
		im->core.im_num_resources, arg, &arg_ret, data, data_len,
		&ret_len, (XPointer)&im_values, XIM_SETIMVALUES))) {
	    break;
	}

	total += ret_len;
	if (!(arg = arg_ret)) {
	    break;
	}

	buf_size += ret_len;
	if (buf == tmp_buf) {
	    if (!(tmp = Xmalloc(buf_size + data_len))) {
		return arg->name;
	    }
	    memcpy(tmp, buf, buf_size);
	    buf = tmp;
	} else {
	    if (!(tmp = Xrealloc(buf, (buf_size + data_len)))) {
		Xfree(buf);
		return arg->name;
	    }
	    buf = tmp;
	}
    }
    _XimSetCurrentIMValues(im, &im_values);

    if (!total)
	return (char *)NULL;

    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
    buf_s[0] = im->private.proto.imid;
    buf_s[1] = (INT16)total;

    len = (INT16)(sizeof(CARD16) + sizeof(INT16) + total);
    _XimSetHeader((XPointer)buf, XIM_SET_IM_VALUES, 0, &len);
    if (!(_XimWrite(im, len, (XPointer)buf))) {
	if (buf != tmp_buf)
	    Xfree(buf);
	return arg->name;
    }
    _XimFlush(im);
    if (buf != tmp_buf)
	Xfree(buf);
    buf_size = BUFSIZE;
    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
					 _XimSetIMValuesCheck, 0);
    if(ret_code == XIM_TRUE) {
	preply = reply;
    } else if(ret_code == XIM_OVERFLOW) {
	if(len <= 0) {
	    preply = reply;
	} else {
	    buf_size = (int)len;
	    preply = Xmalloc(buf_size);
	    ret_code = _XimRead(im, &len, reply, buf_size,
					_XimSetIMValuesCheck, 0);
	    if(ret_code != XIM_TRUE) {
		Xfree(preply);
		return arg->name;
	    }
	}
    } else
	return arg->name;
    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
    if (*((CARD8 *)preply) == XIM_ERROR) {
	_XimProcError(im, 0, (XPointer)&buf_s[3]);
	if(reply != preply)
	    Xfree(preply);
	return arg->name;
    }
    if(reply != preply)
	Xfree(preply);

    return name;
}


_XimAttributeToValue(
    Xic			  ic,
    XIMResourceList	  res,
    CARD16		 *data,
    INT16		  data_len,
    XPointer		  value,
    BITMASK32		  mode)
{
    switch (res->resource_size) {
    case XimType_SeparatorOfNestedList:
    case XimType_NEST:
	break;

    case XimType_CARD8:
    case XimType_CARD16:
    case XimType_CARD32:
    case XimType_Window:
    case XimType_XIMHotKeyState:
	_XCopyToArg((XPointer)data, (XPointer *)&value, data_len);
	break;

    case XimType_STRING8:
	{
	    char	*str;

	    if (!(value))
		return False;

	    if (!(str = Xmalloc(data_len + 1)))
		return False;

	    (void)memcpy(str, (char *)data, data_len);
	    str[data_len] = '\0';

	    *((char **)value) = str;
	    break;
	}

    case XimType_XIMStyles:
	{
	    CARD16		 num = data[0];
	    register CARD32	*style_list = (CARD32 *)&data[2];
	    XIMStyle		*style;
	    XIMStyles		*rep;
	    register int	 i;
	    char		*p;
	    unsigned int         alloc_len;

	    if (!(value))
		return False;

	    if (num > (USHRT_MAX / sizeof(XIMStyle)))
		return False;
	    if ((sizeof(num) + (num * sizeof(XIMStyle))) > data_len)
		return False;
	    alloc_len = sizeof(XIMStyles) + sizeof(XIMStyle) * num;
	    if (alloc_len < sizeof(XIMStyles))
		return False;
	    if (!(p = Xmalloc(alloc_len)))
		return False;

	    rep   = (XIMStyles *)p;
	    style = (XIMStyle *)(p + sizeof(XIMStyles));

	    for (i = 0; i < num; i++)
		style[i] = (XIMStyle)style_list[i];

	    rep->count_styles = (unsigned short)num;
	    rep->supported_styles = style;
	    *((XIMStyles **)value) = rep;
	    break;
	}

    case XimType_XRectangle:
	{
	    XRectangle	*rep;

	    if (!(value))
		return False;

	    if (!(rep = Xmalloc(sizeof(XRectangle))))
		return False;

	    rep->x      = data[0];
	    rep->y      = data[1];
	    rep->width  = data[2];
	    rep->height = data[3];
	    *((XRectangle **)value) = rep;
	    break;
	}

    case XimType_XPoint:
	{
	    XPoint	*rep;

	    if (!(value))
		return False;

	    if (!(rep = Xmalloc(sizeof(XPoint))))
		return False;

	    rep->x = data[0];
	    rep->y = data[1];
	    *((XPoint **)value) = rep;
	    break;
	}

    case XimType_XFontSet:
	{
	    INT16	 len = data[0];
	    char	*base_name;
	    XFontSet	 rep = (XFontSet)NULL;
	    char	**missing_list = NULL;
	    int		 missing_count;
	    char	*def_string;

	    if (!(value))
		return False;
	    if (!ic)
		return False;

	    if (!(base_name = Xmalloc(len + 1)))
		return False;

	    (void)strncpy(base_name, (char *)&data[1], (int)len);
	    base_name[len] = '\0';

	    if (mode & XIM_PREEDIT_ATTR) {
		if (!strcmp(base_name, ic->private.proto.preedit_font)) {
		    rep = ic->core.preedit_attr.fontset;
		} else if (!ic->private.proto.preedit_font_length) {
		    rep = XCreateFontSet(ic->core.im->core.display,
					base_name, &missing_list,
					&missing_count, &def_string);
		}
	    } else if (mode & XIM_STATUS_ATTR) {
		if (!strcmp(base_name, ic->private.proto.status_font)) {
		    rep = ic->core.status_attr.fontset;
		} else if (!ic->private.proto.status_font_length) {
		    rep = XCreateFontSet(ic->core.im->core.display,
					base_name, &missing_list,
					&missing_count, &def_string);
		}
	    }

	    Xfree(base_name);
	    Xfree(missing_list);
	    *((XFontSet *)value) = rep;
	    break;
	}

    case XimType_XIMHotKeyTriggers:
	{
	    CARD32			 num = *((CARD32 *)data);
	    register CARD32		*key_list = (CARD32 *)&data[2];
	    XIMHotKeyTrigger		*key;
	    XIMHotKeyTriggers		*rep;
	    register int		 i;
	    char			*p;
	    unsigned int		 alloc_len;

	    if (!(value))
		return False;

	    if (num > (UINT_MAX / sizeof(XIMHotKeyTrigger)))
		return False;
	    if ((sizeof(num) + (num * sizeof(XIMHotKeyTrigger))) > data_len)
		return False;
	    alloc_len = sizeof(XIMHotKeyTriggers)
		      + sizeof(XIMHotKeyTrigger) * num;
	    if (alloc_len < sizeof(XIMHotKeyTriggers))
		return False;
	    if (!(p = Xmalloc(alloc_len)))
		return False;

	    rep = (XIMHotKeyTriggers *)p;
	    key = (XIMHotKeyTrigger *)(p + sizeof(XIMHotKeyTriggers));

	    for (i = 0; i < num; i++, key_list += 3) {
		key[i].keysym        = (KeySym)key_list[0]; /* keysym */
		key[i].modifier      = (int)key_list[1];    /* modifier */
		key[i].modifier_mask = (int)key_list[2];    /* modifier_mask */
	    }

	    rep->num_hot_key = (int)num;
	    rep->key = key;
	    *((XIMHotKeyTriggers **)value) = rep;
	    break;
	}

    case XimType_XIMStringConversion:
	{
	    break;
	}

    default:
	return False;
    }
    return True;
}


_XimAttributeToValue(
    Xic			  ic,
    XIMResourceList	  res,
    CARD16		 *data,
    INT16		  data_len,
    XPointer		  value,
    BITMASK32		  mode)
{
    switch (res->resource_size) {
    case XimType_SeparatorOfNestedList:
    case XimType_NEST:
	break;

    case XimType_CARD8:
    case XimType_CARD16:
    case XimType_CARD32:
    case XimType_Window:
    case XimType_XIMHotKeyState:
	_XCopyToArg((XPointer)data, (XPointer *)&value, data_len);
	break;

    case XimType_STRING8:
	{
	    char	*str;

	    if (!(value))
		return False;

	    if (!(str = Xmalloc(data_len + 1)))
		return False;

	    (void)memcpy(str, (char *)data, data_len);
	    str[data_len] = '\0';

	    *((char **)value) = str;
	    break;
	}

    case XimType_XIMStyles:
	{
	    INT16		 num = data[0];
	    register CARD32	*style_list = (CARD32 *)&data[2];
	    XIMStyle		*style;
	    XIMStyles		*rep;
	    register int	 i;
	    char		*p;
	    int			 alloc_len;

	    if (!(value))
		return False;

	    alloc_len = sizeof(XIMStyles) + sizeof(XIMStyle) * num;
	    if (!(p = Xmalloc(alloc_len)))
		return False;

	    rep   = (XIMStyles *)p;
	    style = (XIMStyle *)(p + sizeof(XIMStyles));

	    for (i = 0; i < num; i++)
		style[i] = (XIMStyle)style_list[i];

	    rep->count_styles = (unsigned short)num;
	    rep->supported_styles = style;
	    *((XIMStyles **)value) = rep;
	    break;
	}

    case XimType_XRectangle:
	{
	    XRectangle	*rep;

	    if (!(value))
		return False;

	    if (!(rep = Xmalloc(sizeof(XRectangle))))
		return False;

	    rep->x      = data[0];
	    rep->y      = data[1];
	    rep->width  = data[2];
	    rep->height = data[3];
	    *((XRectangle **)value) = rep;
	    break;
	}

    case XimType_XPoint:
	{
	    XPoint	*rep;

	    if (!(value))
		return False;

	    if (!(rep = Xmalloc(sizeof(XPoint))))
		return False;

	    rep->x = data[0];
	    rep->y = data[1];
	    *((XPoint **)value) = rep;
	    break;
	}

    case XimType_XFontSet:
	{
	    INT16	 len = data[0];
	    char	*base_name;
	    XFontSet	 rep = (XFontSet)NULL;
	    char	**missing_list = NULL;
	    int		 missing_count;
	    char	*def_string;

	    if (!(value))
		return False;
	    if (!ic)
		return False;

	    if (!(base_name = Xmalloc(len + 1)))
		return False;

	    (void)strncpy(base_name, (char *)&data[1], (int)len);
	    base_name[len] = '\0';

	    if (mode & XIM_PREEDIT_ATTR) {
		if (!strcmp(base_name, ic->private.proto.preedit_font)) {
		    rep = ic->core.preedit_attr.fontset;
		} else if (!ic->private.proto.preedit_font_length) {
		    rep = XCreateFontSet(ic->core.im->core.display,
					base_name, &missing_list,
					&missing_count, &def_string);
		}
	    } else if (mode & XIM_STATUS_ATTR) {
		if (!strcmp(base_name, ic->private.proto.status_font)) {
		    rep = ic->core.status_attr.fontset;
		} else if (!ic->private.proto.status_font_length) {
		    rep = XCreateFontSet(ic->core.im->core.display,
					base_name, &missing_list,
					&missing_count, &def_string);
		}
	    }

	    Xfree(base_name);
	    Xfree(missing_list);
	    *((XFontSet *)value) = rep;
	    break;
	}

    case XimType_XIMHotKeyTriggers:
	{
	    INT32			 num = *((CARD32 *)data);
	    register CARD32		*key_list = (CARD32 *)&data[2];
	    XIMHotKeyTrigger		*key;
	    XIMHotKeyTriggers		*rep;
	    register int		 i;
	    char			*p;
	    int				 alloc_len;

	    if (!(value))
		return False;

	    alloc_len = sizeof(XIMHotKeyTriggers)
		      + sizeof(XIMHotKeyTrigger) * num;
	    if (!(p = Xmalloc(alloc_len)))
		return False;

	    rep = (XIMHotKeyTriggers *)p;
	    key = (XIMHotKeyTrigger *)(p + sizeof(XIMHotKeyTriggers));

	    for (i = 0; i < num; i++, key_list += 3) {
		key[i].keysym        = (KeySym)key_list[0]; /* keysym */
		key[i].modifier      = (int)key_list[1];    /* modifier */
		key[i].modifier_mask = (int)key_list[2];    /* modifier_mask */
	    }

	    rep->num_hot_key = (int)num;
	    rep->key = key;
	    *((XIMHotKeyTriggers **)value) = rep;
	    break;
	}

    case XimType_XIMStringConversion:
	{
	    break;
	}

    default:
	return False;
    }
    return True;
}


_XimCountNumberOfAttr(
    INT16	 total,
    CARD16	*attr,
    int		*names_len)
{
    unsigned int n;
    INT16	 len;
    INT16	 min_len = sizeof(CARD16)	/* sizeof attribute ID */
			 + sizeof(CARD16)	/* sizeof type of value */
			 + sizeof(INT16);	/* sizeof length of attribute */

    n = 0;
    *names_len = 0;
    while (total > min_len) {
	len = attr[2];
	*names_len += (len + 1);
	len += (min_len + XIM_PAD(len + 2));
	total -= len;
	attr = (CARD16 *)((char *)attr + len);
	n++;
    }
    return n;
}


sftp_client_message sftp_get_client_message(sftp_session sftp) {
  ssh_session session = sftp->session;
  sftp_packet packet;
  sftp_client_message msg;
  ssh_buffer payload;
  int rc;

  msg = malloc(sizeof (struct sftp_client_message_struct));
  if (msg == NULL) {
    ssh_set_error_oom(session);
    return NULL;
  }
  ZERO_STRUCTP(msg);

  packet = sftp_packet_read(sftp);
  if (packet == NULL) {
    ssh_set_error_oom(session);
    sftp_client_message_free(msg);
    return NULL;
  }

  payload = packet->payload;
  msg->type = packet->type;
  msg->sftp = sftp;

  /* take a copy of the whole packet */
  msg->complete_message = ssh_buffer_new();
  ssh_buffer_add_data(msg->complete_message,
                      ssh_buffer_get(payload),
                      ssh_buffer_get_len(payload));

  ssh_buffer_get_u32(payload, &msg->id);

  switch(msg->type) {
    case SSH_FXP_CLOSE:
    case SSH_FXP_READDIR:
      msg->handle = ssh_buffer_get_ssh_string(payload);
      if (msg->handle == NULL) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      break;
    case SSH_FXP_READ:
      rc = ssh_buffer_unpack(payload,
                             "Sqd",
                             &msg->handle,
                             &msg->offset,
                             &msg->len);
      if (rc != SSH_OK) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      break;
    case SSH_FXP_WRITE:
      rc = ssh_buffer_unpack(payload,
                             "SqS",
                             &msg->handle,
                             &msg->offset,
                             &msg->data);
      if (rc != SSH_OK) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      break;
    case SSH_FXP_REMOVE:
    case SSH_FXP_RMDIR:
    case SSH_FXP_OPENDIR:
    case SSH_FXP_READLINK:
    case SSH_FXP_REALPATH:
      rc = ssh_buffer_unpack(payload,
                             "s",
                             &msg->filename);
      if (rc != SSH_OK) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      break;
    case SSH_FXP_RENAME:
    case SSH_FXP_SYMLINK:
      rc = ssh_buffer_unpack(payload,
                             "sS",
                             &msg->filename,
                             &msg->data);
      if (rc != SSH_OK) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      break;
    case SSH_FXP_MKDIR:
    case SSH_FXP_SETSTAT:
      rc = ssh_buffer_unpack(payload,
                             "s",
                             &msg->filename);
      if (rc != SSH_OK) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      msg->attr = sftp_parse_attr(sftp, payload, 0);
      if (msg->attr == NULL) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      break;
    case SSH_FXP_FSETSTAT:
      msg->handle = ssh_buffer_get_ssh_string(payload);
      if (msg->handle == NULL) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      msg->attr = sftp_parse_attr(sftp, payload, 0);
      if (msg->attr == NULL) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      break;
    case SSH_FXP_LSTAT:
    case SSH_FXP_STAT:
      rc = ssh_buffer_unpack(payload,
                             "s",
                             &msg->filename);
      if (rc != SSH_OK) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      if(sftp->version > 3) {
        ssh_buffer_unpack(payload, "d", &msg->flags);
      }
      break;
    case SSH_FXP_OPEN:
      rc = ssh_buffer_unpack(payload,
                             "sd",
                             &msg->filename,
                             &msg->flags);
      if (rc != SSH_OK) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      msg->attr = sftp_parse_attr(sftp, payload, 0);
      if (msg->attr == NULL) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      break;
    case SSH_FXP_FSTAT:
      rc = ssh_buffer_unpack(payload,
                             "S",
                             &msg->handle);
      if (rc != SSH_OK) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }
      break;
    case SSH_FXP_EXTENDED:
      rc = ssh_buffer_unpack(payload,
                             "s",
                             &msg->submessage);
      if (rc != SSH_OK) {
        ssh_set_error_oom(session);
        sftp_client_message_free(msg);
        return NULL;
      }

      if (strcmp(msg->submessage, "hardlink@openssh.com") == 0 ||
          strcmp(msg->submessage, "posix-rename@openssh.com") == 0) {
        rc = ssh_buffer_unpack(payload,
                               "sS",
                               &msg->filename,
                               &msg->data);
        if (rc != SSH_OK) {
          ssh_set_error_oom(session);
          sftp_client_message_free(msg);
          return NULL;
        }
      }
      break;
    default:
      ssh_set_error(sftp->session, SSH_FATAL,
                    "Received unhandled sftp message %d", msg->type);
      sftp_client_message_free(msg);
      return NULL;
  }

  return msg;
}


apr_status_t h2_push_diary_digest_get(h2_push_diary *diary, apr_pool_t *pool,
                                      int maxP, const char *authority,
                                      const char **pdata, apr_size_t *plen)
{
    int nelts, N, i;
    unsigned char log2n, log2pmax;
    gset_encoder encoder;
    apr_uint64_t *hashes;
    apr_size_t hash_count;

    nelts = diary->entries->nelts;

    if ((apr_uint32_t)nelts > APR_UINT32_MAX) {
        /* should not happen */
        return APR_ENOTIMPL;
    }
    N = ceil_power_of_2(nelts);
    log2n = h2_log2(N);

    /* Now log2p is the max number of relevant bits, so that
     * log2p + log2n == mask_bits. We can use a lower log2p
     * and have a shorter set encoding...
     */
    log2pmax = h2_log2(ceil_power_of_2(maxP));

    memset(&encoder, 0, sizeof(encoder));
    encoder.diary = diary;
    encoder.log2p = H2MIN(diary->mask_bits - log2n, log2pmax);
    encoder.mask_bits = log2n + encoder.log2p;
    encoder.delta_bits = diary->mask_bits - encoder.mask_bits;
    encoder.fixed_bits = encoder.log2p;
    encoder.fixed_mask = 1;
    encoder.fixed_mask = (encoder.fixed_mask << encoder.fixed_bits) - 1;
    encoder.pool = pool;
    encoder.datalen = 512;
    encoder.data = apr_pcalloc(encoder.pool, encoder.datalen);

    encoder.data[0] = log2n;
    encoder.data[1] = encoder.log2p;
    encoder.offset = 1;
    encoder.bit = 8;
    encoder.last = 0;

    /* Intentional no APLOGNO */
    ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, pool,
                  "h2_push_diary_digest_get: %d entries, N=%d, log2n=%d, "
                  "mask_bits=%d, enc.mask_bits=%d, delta_bits=%d, enc.log2p=%d, authority=%s",
                  (int)nelts, (int)N, (int)log2n, diary->mask_bits,
                  (int)encoder.mask_bits, (int)encoder.delta_bits,
                  (int)encoder.log2p, authority);

    if (!authority || !diary->authority
        || !strcmp("*", authority) || !strcmp(diary->authority, authority)) {
        hash_count = diary->entries->nelts;
        hashes = apr_pcalloc(encoder.pool, hash_count);
        for (i = 0; i < hash_count; ++i) {
            hashes[i] = ((&APR_ARRAY_IDX(diary->entries, i, h2_push_diary_entry))->hash
                         >> encoder.delta_bits);
        }

        qsort(hashes, hash_count, sizeof(apr_uint64_t), cmp_puint64);
        for (i = 0; i < hash_count; ++i) {
            if (!i || (hashes[i] != hashes[i-1])) {
                gset_encode_next(&encoder, hashes[i]);
            }
        }
        /* Intentional no APLOGNO */
        ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, pool,
                      "h2_push_diary_digest_get: golomb compressed hashes, %d bytes",
                      (int)encoder.offset + 1);
    }
    *pdata = (const char *)encoder.data;
    *plen = encoder.offset + 1;

    return APR_SUCCESS;
}


apr_array_header_t *h2_push_collect_update(h2_stream *stream,
                                           const struct h2_request *req,
                                           const struct h2_headers *res)
{
    h2_session *session = stream->session;
    const char *cache_digest = apr_table_get(req->headers, "Cache-Digest");
    apr_array_header_t *pushes;
    apr_status_t status;

    if (cache_digest && session->push_diary) {
        status = h2_push_diary_digest64_set(session->push_diary, req->authority,
                                            cache_digest, stream->pool);
        if (status != APR_SUCCESS) {
            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c,
                          H2_SSSN_LOG(APLOGNO(03057), session,
                          "push diary set from Cache-Digest: %s"), cache_digest);
        }
    }
    pushes = h2_push_collect(stream->pool, req, stream->push_policy, res);
    return h2_push_diary_update(stream->session, pushes);
}


pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
		    const char *pin)
{
	CK_RV rv;
	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
	CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
	CK_KEY_TYPE keyType = CKK_RSA;
	CK_ATTRIBUTE searchTemplate[] =
	{
		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
		{ CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) },
		{ CKA_LABEL, NULL, 0 }
	};
	CK_ULONG cnt;
	CK_ATTRIBUTE *attr;
	pk11_object_t *rsa;
	pk11_context_t *pk11_ctx = NULL;
	isc_result_t ret;
	unsigned int i;

	UNUSED(pin);

	rsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*rsa));
	if (rsa == NULL)
		return (ISC_R_NOMEMORY);
	memset(rsa, 0, sizeof(*rsa));
	rsa->object = CK_INVALID_HANDLE;
	rsa->ontoken = true;
	rsa->reqlogon = true;
	key->keydata.pkey = rsa;

	rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2);
	if (rsa->repr == NULL)
		DST_RET(ISC_R_NOMEMORY);
	memset(rsa->repr, 0, sizeof(*attr) * 2);
	rsa->attrcnt = 2;
	attr = rsa->repr;
	attr[0].type = CKA_MODULUS;
	attr[1].type = CKA_PUBLIC_EXPONENT;

	ret = pk11_parse_uri(rsa, label, key->mctx, OP_RSA);
	if (ret != ISC_R_SUCCESS)
		goto err;

	pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
						  sizeof(*pk11_ctx));
	if (pk11_ctx == NULL)
		DST_RET(ISC_R_NOMEMORY);
	ret = pk11_get_session(pk11_ctx, OP_RSA, true, false,
			       rsa->reqlogon, NULL, rsa->slot);
	if (ret != ISC_R_SUCCESS)
		goto err;

	attr = pk11_attribute_bytype(rsa, CKA_LABEL);
	if (attr == NULL) {
		attr = pk11_attribute_bytype(rsa, CKA_ID);
		INSIST(attr != NULL);
		searchTemplate[3].type = CKA_ID;
	}
	searchTemplate[3].pValue = attr->pValue;
	searchTemplate[3].ulValueLen = attr->ulValueLen;

	PK11_RET(pkcs_C_FindObjectsInit,
		 (pk11_ctx->session, searchTemplate, (CK_ULONG) 4),
		 DST_R_CRYPTOFAILURE);
	PK11_RET(pkcs_C_FindObjects,
		 (pk11_ctx->session, &hKey, (CK_ULONG) 1, &cnt),
		 DST_R_CRYPTOFAILURE);
	(void) pkcs_C_FindObjectsFinal(pk11_ctx->session);
	if (cnt == 0)
		DST_RET(ISC_R_NOTFOUND);
	if (cnt > 1)
		DST_RET(ISC_R_EXISTS);

	attr = rsa->repr;
	PK11_RET(pkcs_C_GetAttributeValue,
		 (pk11_ctx->session, hKey, attr, 2),
		 DST_R_CRYPTOFAILURE);
	for (i = 0; i <= 1; i++) {
		attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen);
		if (attr[i].pValue == NULL)
			DST_RET(ISC_R_NOMEMORY);
		memset(attr[i].pValue, 0, attr[i].ulValueLen);
	}
	PK11_RET(pkcs_C_GetAttributeValue,
		 (pk11_ctx->session, hKey, attr, 2),
		 DST_R_CRYPTOFAILURE);

	keyClass = CKO_PRIVATE_KEY;
	PK11_RET(pkcs_C_FindObjectsInit,
		 (pk11_ctx->session, searchTemplate, (CK_ULONG) 4),
		 DST_R_CRYPTOFAILURE);
	PK11_RET(pkcs_C_FindObjects,
		 (pk11_ctx->session, &rsa->object, (CK_ULONG) 1, &cnt),
		 DST_R_CRYPTOFAILURE);
	(void) pkcs_C_FindObjectsFinal(pk11_ctx->session);
	if (cnt == 0)
		DST_RET(ISC_R_NOTFOUND);
	if (cnt > 1)
		DST_RET(ISC_R_EXISTS);

	if (engine != NULL) {
		key->engine = isc_mem_strdup(key->mctx, engine);
		if (key->engine == NULL)
			DST_RET(ISC_R_NOMEMORY);
	}

	key->label = isc_mem_strdup(key->mctx, label);
	if (key->label == NULL)
		DST_RET(ISC_R_NOMEMORY);

	attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT);
	INSIST(attr != NULL);
	if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS)
		DST_RET(ISC_R_RANGE);

	attr = pk11_attribute_bytype(rsa, CKA_MODULUS);
	INSIST(attr != NULL);
	key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);

	pk11_return_session(pk11_ctx);
	isc_safe_memwipe(pk11_ctx, sizeof(*pk11_ctx));
	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));

	return (ISC_R_SUCCESS);

    err:
	pkcs11rsa_destroy(key);
	if (pk11_ctx != NULL) {
		pk11_return_session(pk11_ctx);
		isc_safe_memwipe(pk11_ctx, sizeof(*pk11_ctx));
		isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
	}

	return (ret);
}


do_compose_group16(pdf14_buf *tos, pdf14_buf *nos, pdf14_buf *maskbuf,
                   int x0, int x1, int y0, int y1, int n_chan, bool additive,
                   const pdf14_nonseparable_blending_procs_t * pblend_procs,
                   bool has_matte, bool overprint, gx_color_index drawn_comps,
                   gs_memory_t *memory, gx_device *dev)
{
    int num_spots = tos->num_spots;
    uint16_t alpha = tos->alpha;
    uint16_t shape = tos->shape;
    gs_blend_mode_t blend_mode = tos->blend_mode;
    uint16_t *tos_ptr =
        (uint16_t *)(void *)(tos->data + (x0 - tos->rect.p.x)*2 +
                             (y0 - tos->rect.p.y) * tos->rowstride);
    uint16_t *nos_ptr =
        (uint16_t *)(void *)(nos->data + (x0 - nos->rect.p.x)*2 +
                             (y0 - nos->rect.p.y) * nos->rowstride);
    uint16_t *mask_row_ptr = NULL;
    int tos_planestride = tos->planestride;
    int nos_planestride = nos->planestride;
    uint16_t mask_bg_alpha = 0; /* Quiet compiler. */
    bool tos_isolated = tos->isolated;
    bool nos_isolated = nos->isolated;
    bool nos_knockout = nos->knockout;
    uint16_t *nos_alpha_g_ptr;
    int tos_shape_offset = n_chan * tos_planestride;
    int tos_alpha_g_offset = tos_shape_offset + (tos->has_shape ? tos_planestride : 0);
    bool tos_has_tag = tos->has_tags;
    int tos_tag_offset = tos_planestride * (tos->n_planes - 1);
    int nos_shape_offset = n_chan * nos_planestride;
    int nos_alpha_g_offset = nos_shape_offset + (nos->has_shape ? nos_planestride : 0);
    int nos_tag_offset = nos_planestride * (nos->n_planes - 1);
    const uint16_t *mask_tr_fn = NULL; /* Quiet compiler. */
    bool has_mask = false;
    uint16_t *backdrop_ptr = NULL;
    pdf14_device *pdev = (pdf14_device *)dev;
#if RAW_DUMP
    uint16_t *composed_ptr = NULL;
    int width = x1 - x0;
#endif
    art_pdf_compose_group16_fn fn;

    if ((tos->n_chan == 0) || (nos->n_chan == 0))
        return;
    rect_merge(nos->dirty, tos->dirty);
    if (nos->has_tags)
        if_debug7m('v', memory,
                   "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, tag = %d, bm = %d\n",
                   y0, y1, x1 - x0, alpha, shape, dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS, blend_mode);
    else
        if_debug6m('v', memory,
                   "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, bm = %d\n",
                   y0, y1, x1 - x0, alpha, shape, blend_mode);
    if (!nos->has_shape)
        nos_shape_offset = 0;
    if (!nos->has_tags)
        nos_tag_offset = 0;
    if (nos->has_alpha_g) {
        nos_alpha_g_ptr = nos_ptr + (nos_alpha_g_offset>>1);
    } else
        nos_alpha_g_ptr = NULL;
    if (nos->backdrop != NULL) {
        backdrop_ptr =
            (uint16_t *)(void *)(nos->backdrop + (x0 - nos->rect.p.x)*2 +
                                 (y0 - nos->rect.p.y) * nos->rowstride);
    }
    if (blend_mode != BLEND_MODE_Compatible && blend_mode != BLEND_MODE_Normal)
        overprint = false;

    if (maskbuf != NULL) {
        unsigned int tmp;
        mask_tr_fn = (uint16_t *)maskbuf->transfer_fn;
        /* Make sure we are in the mask buffer */
        if (maskbuf->data != NULL) {
            mask_row_ptr =
                (uint16_t *)(void *)(maskbuf->data + (x0 - maskbuf->rect.p.x)*2 +
                                     (y0 - maskbuf->rect.p.y) * maskbuf->rowstride);
            has_mask = true;
        }
        /* We may have a case, where we are outside the maskbuf rect. */
        /* We would have avoided creating the maskbuf->data */
        /* In that case, we should use the background alpha value */
        /* See discussion on the BC entry in the PDF spec.   */
        mask_bg_alpha = maskbuf->alpha;
        /* Adjust alpha by the mask background alpha.   This is only used
           if we are outside the soft mask rect during the filling operation */
        mask_bg_alpha = interp16(mask_tr_fn, mask_bg_alpha);
        tmp = alpha * mask_bg_alpha + 0x8000;
        mask_bg_alpha = (tmp + (tmp >> 8)) >> 8;
    }
    n_chan--; /* Now the true number of colorants (i.e. not including alpha)*/
#if RAW_DUMP
    composed_ptr = nos_ptr;
    dump_raw_buffer(memory, y1-y0, width, tos->n_planes, tos_planestride, tos->rowstride,
                    "bImageTOS", (byte *)tos_ptr, tos->deep);
    dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
                    "cImageNOS", (byte *)nos_ptr, tos->deep);
    if (maskbuf !=NULL && maskbuf->data != NULL) {
        dump_raw_buffer(memory, maskbuf->rect.q.y - maskbuf->rect.p.y,
                        maskbuf->rect.q.x - maskbuf->rect.p.x, maskbuf->n_planes,
                        maskbuf->planestride, maskbuf->rowstride, "dMask",
                        maskbuf->data, maskbuf->deep);
    }
#endif

    /* You might hope that has_mask iff maskbuf != NULL, but this is
     * not the case. Certainly we can see cases where maskbuf != NULL
     * and has_mask = 0. What's more, treating such cases as being
     * has_mask = 0 causes diffs. */
#ifdef TRACK_COMPOSE_GROUPS
    {
        int code = 0;

        code += !!nos_knockout;
        code += (!!nos_isolated)<<1;
        code += (!!tos_isolated)<<2;
        code += (!!tos->has_shape)<<3;
        code += (!!tos_has_tag)<<4;
        code += (!!additive)<<5;
        code += (!!overprint)<<6;
        code += (!!has_mask || maskbuf != NULL)<<7;
        code += (!!has_matte)<<8;
        code += (backdrop_ptr != NULL)<<9;
        code += (num_spots != 0)<<10;
        code += blend_mode<<11;

        if (track_compose_groups == 0)
        {
            atexit(dump_track_compose_groups);
            track_compose_groups = 1;
        }
        compose_groups[code]++;
    }
#endif

    /* We have tested the files on the cluster to see what percentage of
     * files/devices hit the different options. */
    if (nos_knockout)
        fn = &compose_group16_knockout; /* Small %ages, nothing more than 1.1% */
    else if (blend_mode != 0)
        fn = &compose_group16_nonknockout_blend; /* Small %ages, nothing more than 2% */
    else if (tos->has_shape == 0 && tos_has_tag == 0 && nos_isolated == 0 && nos_alpha_g_ptr == NULL &&
             nos_shape_offset == 0 && nos_tag_offset == 0 && backdrop_ptr == NULL && has_matte == 0 && num_spots == 0 &&
             overprint == 0) {
             /* Additive vs Subtractive makes no difference in normal blend mode with no spots */
        if (tos_isolated) {
            if (has_mask || maskbuf) {/* 7% */
                /* AirPrint test case hits this */
                if (maskbuf && maskbuf->rect.p.x <= x0 && maskbuf->rect.p.y <= y0 &&
                    maskbuf->rect.q.x >= x1 && maskbuf->rect.q.y >= y1)
                    fn = &compose_group16_nonknockout_nonblend_isolated_allmask_common;
                else
                    fn = &compose_group16_nonknockout_nonblend_isolated_mask_common;
            } else /* 14% */
                fn = &compose_group16_nonknockout_nonblend_isolated_nomask_common;
        } else {
            if (has_mask || maskbuf) /* 4% */
                fn = &compose_group16_nonknockout_nonblend_nonisolated_mask_common;
            else /* 15% */
                fn = &compose_group16_nonknockout_nonblend_nonisolated_nomask_common;
        }
    } else
        fn = compose_group16_nonknockout_noblend_general;

    tos_planestride >>= 1;
    tos_shape_offset >>= 1;
    tos_alpha_g_offset >>= 1;
    tos_tag_offset >>= 1;
    nos_planestride >>= 1;
    nos_shape_offset >>= 1;
    nos_tag_offset >>= 1;
    fn(tos_ptr, tos_isolated, tos_planestride, tos->rowstride>>1, alpha, shape, blend_mode, tos->has_shape,
                  tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag,
                  nos_ptr, nos_isolated, nos_planestride, nos->rowstride>>1, nos_alpha_g_ptr, nos_knockout,
                  nos_shape_offset, nos_tag_offset,
                  mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
                  backdrop_ptr,
                  has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1,
                  pblend_procs, pdev);

#if RAW_DUMP
    dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride<<1, nos->rowstride,
                    "eComposed", (byte *)composed_ptr, nos->deep);
    global_index++;
#endif
}


FILE *open_dumpfile(SRC_Instance inst, const char *mode)
{
  FILE *f;
  char filename[PATH_MAX], *dumpdir;

  dumpdir = CNF_GetDumpDir();
  if (dumpdir[0] == '\0') {
    LOG(LOGS_WARN, "dumpdir not specified");
    return NULL;
  }

  /* Include IP address in the name for NTP sources, or reference ID in hex */
  if ((inst->type == SRC_NTP &&
       snprintf(filename, sizeof (filename), "%s/%s.dat", dumpdir,
                source_to_string(inst)) >= sizeof (filename)) ||
      (inst->type != SRC_NTP &&
       snprintf(filename, sizeof (filename), "%s/refid:%08"PRIx32".dat",
                dumpdir, inst->ref_id) >= sizeof (filename))) {
    LOG(LOGS_WARN, "dumpdir too long");
    return NULL;
  }

  f = fopen(filename, mode);
  if (!f && mode[0] != 'r')
    LOG(LOGS_WARN, "Could not open dump file for %s",
        source_to_string(inst));

  return f;
}


LOG_OpenFileLog(const char *log_file)
{
  FILE *f;

  if (log_file) {
    f = fopen(log_file, "a");
    if (!f)
      LOG_FATAL("Could not open log file %s", log_file);
  } else {
    f = stderr;
  }

  /* Enable line buffering */
  setvbuf(f, NULL, _IOLBF, BUFSIZ);

  if (file_log && file_log != stderr)
    fclose(file_log);

  file_log = f;
}


SCK_RemoveSocket(int sock_fd)
{
  union sockaddr_all saddr;
  socklen_t saddr_len;

  saddr_len = sizeof (saddr);

  if (getsockname(sock_fd, &saddr.sa, &saddr_len) < 0) {
    DEBUG_LOG("getsockname() failed : %s", strerror(errno));
    return 0;
  }

  if (saddr_len > sizeof (saddr) || saddr_len <= sizeof (saddr.sa.sa_family) ||
      saddr.sa.sa_family != AF_UNIX)
    return 0;

  if (unlink(saddr.un.sun_path) < 0) {
    DEBUG_LOG("unlink(%s) failed : %s", saddr.un.sun_path, strerror(errno));
    return 0;
  }

  DEBUG_LOG("Removed %s", saddr.un.sun_path);

  return 1;
}


HttpHeaderEntry::parse(const char *field_start, const char *field_end, const http_hdr_owner_type msgType)
{
    /* note: name_start == field_start */
    const char *name_end = (const char *)memchr(field_start, ':', field_end - field_start);
    int name_len = name_end ? name_end - field_start :0;
    const char *value_start = field_start + name_len + 1;   /* skip ':' */
    /* note: value_end == field_end */

    ++ HeaderEntryParsedCount;

    /* do we have a valid field name within this field? */

    if (!name_len || name_end > field_end)
        return NULL;

    if (name_len > 65534) {
        /* String must be LESS THAN 64K and it adds a terminating NULL */
        // TODO: update this to show proper name_len in Raw markup, but not print all that
        debugs(55, 2, "ignoring huge header field (" << Raw("field_start", field_start, 100) << "...)");
        return NULL;
    }

    /*
     * RFC 7230 section 3.2.4:
     * "No whitespace is allowed between the header field-name and colon.
     * ...
     *  A server MUST reject any received request message that contains
     *  whitespace between a header field-name and colon with a response code
     *  of 400 (Bad Request).  A proxy MUST remove any such whitespace from a
     *  response message before forwarding the message downstream."
     */
    if (xisspace(field_start[name_len - 1])) {

        if (msgType == hoRequest)
            return nullptr;

        // for now, also let relaxed parser remove this BWS from any non-HTTP messages
        const bool stripWhitespace = (msgType == hoReply) ||
                                     Config.onoff.relaxed_header_parser;
        if (!stripWhitespace)
            return nullptr; // reject if we cannot strip

        debugs(55, Config.onoff.relaxed_header_parser <= 0 ? 1 : 2,
               "NOTICE: Whitespace after header name in '" << getStringPrefix(field_start, field_end-field_start) << "'");

        while (name_len > 0 && xisspace(field_start[name_len - 1]))
            --name_len;

        if (!name_len) {
            debugs(55, 2, "found header with only whitespace for name");
            return NULL;
        }
    }

    /* now we know we can parse it */

    debugs(55, 9, "parsing HttpHeaderEntry: near '" <<  getStringPrefix(field_start, field_end-field_start) << "'");

    /* is it a "known" field? */
    Http::HdrType id = Http::HeaderLookupTable.lookup(field_start,name_len).id;
    debugs(55, 9, "got hdr-id=" << id);

    String name;

    String value;

    if (id == Http::HdrType::BAD_HDR)
        id = Http::HdrType::OTHER;

    /* set field name */
    if (id == Http::HdrType::OTHER)
        name.limitInit(field_start, name_len);
    else
        name = Http::HeaderLookupTable.lookup(id).name;

    /* trim field value */
    while (value_start < field_end && xisspace(*value_start))
        ++value_start;

    while (value_start < field_end && xisspace(field_end[-1]))
        --field_end;

    if (field_end - value_start > 65534) {
        /* String must be LESS THAN 64K and it adds a terminating NULL */
        debugs(55, 2, "WARNING: found '" << name << "' header of " << (field_end - value_start) << " bytes");
        return NULL;
    }

    /* set field value */
    value.limitInit(value_start, field_end - value_start);

    if (id != Http::HdrType::BAD_HDR)
        ++ headerStatsTable[id].seenCount;

    debugs(55, 9, "parsed HttpHeaderEntry: '" << name << ": " << value << "'");

    return new HttpHeaderEntry(id, name.termedBuf(), value.termedBuf());
}


clientProcessRequest(ConnStateData *conn, const Http1::RequestParserPointer &hp, Http::Stream *context)
{
    ClientHttpRequest *http = context->http;
    bool chunked = false;
    bool mustReplyToOptions = false;
    bool unsupportedTe = false;
    bool expectBody = false;

    // We already have the request parsed and checked, so we
    // only need to go through the final body/conn setup to doCallouts().
    assert(http->request);
    HttpRequest::Pointer request = http->request;

    // temporary hack to avoid splitting this huge function with sensitive code
    const bool isFtp = !hp;

    // Some blobs below are still HTTP-specific, but we would have to rewrite
    // this entire function to remove them from the FTP code path. Connection
    // setup and body_pipe preparation blobs are needed for FTP.

    request->manager(conn, http->al);

    request->flags.accelerated = http->flags.accel;
    request->flags.sslBumped=conn->switchedToHttps();
    // TODO: decouple http->flags.accel from request->flags.sslBumped
    request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
                              !conn->port->allow_direct : 0;
    request->sources |= isFtp ? HttpMsg::srcFtp :
                        ((request->flags.sslBumped || conn->port->transport.protocol == AnyP::PROTO_HTTPS) ? HttpMsg::srcHttps : HttpMsg::srcHttp);
#if USE_AUTH
    if (request->flags.sslBumped) {
        if (conn->getAuth() != NULL)
            request->auth_user_request = conn->getAuth();
    }
#endif

    if (internalCheck(request->url.path())) {
        if (internalHostnameIs(request->url.host()) && request->url.port() == getMyPort()) {
            debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true));
            http->flags.internal = true;
        } else if (Config.onoff.global_internal_static && internalStaticCheck(request->url.path())) {
            debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (global_internal_static on)");
            request->url.setScheme(AnyP::PROTO_HTTP, "http");
            request->url.host(internalHostname());
            request->url.port(getMyPort());
            http->flags.internal = true;
            http->setLogUriToRequestUri();
        } else
            debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (not this proxy)");
    }

    request->flags.internal = http->flags.internal;

    if (!isFtp) {
        // XXX: for non-HTTP messages instantiate a different HttpMsg child type
        // for now Squid only supports HTTP requests
        const AnyP::ProtocolVersion &http_ver = hp->messageProtocol();
        assert(request->http_ver.protocol == http_ver.protocol);
        request->http_ver.major = http_ver.major;
        request->http_ver.minor = http_ver.minor;
    }

    if (request->header.chunked()) {
        chunked = true;
    } else if (request->header.has(Http::HdrType::TRANSFER_ENCODING)) {
        const String te = request->header.getList(Http::HdrType::TRANSFER_ENCODING);
        // HTTP/1.1 requires chunking to be the last encoding if there is one
        unsupportedTe = te.size() && te != "identity";
    } // else implied identity coding

    mustReplyToOptions = (request->method == Http::METHOD_OPTIONS) &&
                         (request->header.getInt64(Http::HdrType::MAX_FORWARDS) == 0);
    if (!urlCheckRequest(request.getRaw()) || mustReplyToOptions || unsupportedTe) {
        clientStreamNode *node = context->getClientReplyContext();
        conn->quitAfterError(request.getRaw());
        clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
        assert (repContext);
        repContext->setReplyToError(ERR_UNSUP_REQ, Http::scNotImplemented, request->method, NULL,
                                    conn->clientConnection->remote, request.getRaw(), NULL, NULL);
        assert(context->http->out.offset == 0);
        context->pullData();
        clientProcessRequestFinished(conn, request);
        return;
    }

    if (!chunked && !clientIsContentLengthValid(request.getRaw())) {
        clientStreamNode *node = context->getClientReplyContext();
        clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
        assert (repContext);
        conn->quitAfterError(request.getRaw());
        repContext->setReplyToError(ERR_INVALID_REQ,
                                    Http::scLengthRequired, request->method, NULL,
                                    conn->clientConnection->remote, request.getRaw(), NULL, NULL);
        assert(context->http->out.offset == 0);
        context->pullData();
        clientProcessRequestFinished(conn, request);
        return;
    }

    clientSetKeepaliveFlag(http);
    // Let tunneling code be fully responsible for CONNECT requests
    if (http->request->method == Http::METHOD_CONNECT) {
        context->mayUseConnection(true);
        conn->flags.readMore = false;
    }

#if USE_OPENSSL
    if (conn->switchedToHttps() && conn->serveDelayedError(context)) {
        clientProcessRequestFinished(conn, request);
        return;
    }
#endif

    /* Do we expect a request-body? */
    expectBody = chunked || request->content_length > 0;
    if (!context->mayUseConnection() && expectBody) {
        request->body_pipe = conn->expectRequestBody(
                                 chunked ? -1 : request->content_length);

        /* Is it too large? */
        if (!chunked && // if chunked, we will check as we accumulate
                clientIsRequestBodyTooLargeForPolicy(request->content_length)) {
            clientStreamNode *node = context->getClientReplyContext();
            clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
            assert (repContext);
            conn->quitAfterError(request.getRaw());
            repContext->setReplyToError(ERR_TOO_BIG,
                                        Http::scPayloadTooLarge, Http::METHOD_NONE, NULL,
                                        conn->clientConnection->remote, http->request, NULL, NULL);
            assert(context->http->out.offset == 0);
            context->pullData();
            clientProcessRequestFinished(conn, request);
            return;
        }

        if (!isFtp) {
            // We may stop producing, comm_close, and/or call setReplyToError()
            // below, so quit on errors to avoid http->doCallouts()
            if (!conn->handleRequestBodyData()) {
                clientProcessRequestFinished(conn, request);
                return;
            }

            if (!request->body_pipe->productionEnded()) {
                debugs(33, 5, "need more request body");
                context->mayUseConnection(true);
                assert(conn->flags.readMore);
            }
        }
    }

    http->calloutContext = new ClientRequestContext(http);

    http->doCallouts();

    clientProcessRequestFinished(conn, request);
}


HttpHeader::clean()
{

    assert(owner > hoNone && owner < hoEnd);
    debugs(55, 7, "cleaning hdr: " << this << " owner: " << owner);

    PROF_start(HttpHeaderClean);

    if (owner <= hoReply) {
        /*
         * An unfortunate bug.  The entries array is initialized
         * such that count is set to zero.  httpHeaderClean() seems to
         * be called both when 'hdr' is created, and destroyed.  Thus,
         * we accumulate a large number of zero counts for 'hdr' before
         * it is ever used.  Can't think of a good way to fix it, except
         * adding a state variable that indicates whether or not 'hdr'
         * has been used.  As a hack, just never count zero-sized header
         * arrays.
         */
        if (!entries.empty())
            HttpHeaderStats[owner].hdrUCountDistr.count(entries.size());

        ++ HttpHeaderStats[owner].destroyedCount;

        HttpHeaderStats[owner].busyDestroyedCount += entries.size() > 0;
    } // if (owner <= hoReply)

    for (HttpHeaderEntry *e : entries) {
        if (e == nullptr)
            continue;
        if (!Http::any_valid_header(e->id)) {
            debugs(55, DBG_CRITICAL, "BUG: invalid entry (" << e->id << "). Ignored.");
        } else {
            if (owner <= hoReply)
                HttpHeaderStats[owner].fieldTypeDistr.count(e->id);
            delete e;
        }
    }

    entries.clear();
    httpHeaderMaskInit(&mask, 0);
    len = 0;
    conflictingContentLength_ = false;
    PROF_stop(HttpHeaderClean);
}


init_om(
    XOM om)
{
    XLCd lcd = om->core.lcd;
    XOMGenericPart *gen = XOM_GENERIC(om);
    OMData data;
    XlcCharSet *charset_list;
    FontData font_data;
    char **required_list;
    XOrientation *orientation;
    char **value, buf[BUFSIZ], *bufptr;
    int count = 0, num = 0, length = 0;

    _XlcGetResource(lcd, "XLC_FONTSET", "on_demand_loading", &value, &count);
    if (count > 0 && _XlcCompareISOLatin1(*value, "True") == 0)
	gen->on_demand_loading = True;

    _XlcGetResource(lcd, "XLC_FONTSET", "object_name", &value, &count);
    if (count > 0) {
	gen->object_name = strdup(*value);
	if (gen->object_name == NULL)
	    return False;
    }

    for (num = 0; ; num++) {

        snprintf(buf, sizeof(buf), "fs%d.charset.name", num);
        _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);

        if( count < 1){
            snprintf(buf, sizeof(buf), "fs%d.charset", num);
            _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
            if (count < 1)
                break;
        }

	data = add_data(om);
	if (data == NULL)
	    return False;

	charset_list = Xmalloc(sizeof(XlcCharSet) * count);
	if (charset_list == NULL)
	    return False;
	data->charset_list = charset_list;
	data->charset_count = count;

	while (count-- > 0){
	    *charset_list++ = _XlcGetCharSet(*value++);
        }
        snprintf(buf, sizeof(buf), "fs%d.charset.udc_area", num);
        _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
        if( count > 0){
            UDCArea udc;
            int i,flag = 0;
            udc = Xmalloc(count * sizeof(UDCAreaRec));
	    if (udc == NULL)
	        return False;
            for(i=0;i<count;i++){
                sscanf(value[i],"\\x%lx,\\x%lx", &(udc[i].start),
		       &(udc[i].end));
            }
            for(i=0;i<data->charset_count;i++){
		if(data->charset_list[i]->udc_area == NULL){
		    data->charset_list[i]->udc_area     = udc;
		    data->charset_list[i]->udc_area_num = count;
		    flag = 1;
		}
            }
	    if(flag == 0){
		Xfree(udc);
	    }
        }

        snprintf(buf, sizeof(buf), "fs%d.font.primary", num);
        _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
        if (count < 1){
            snprintf(buf, sizeof(buf), "fs%d.font", num);
            _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
            if (count < 1)
                return False;
        }

	font_data = read_EncodingInfo(count,value);
	if (font_data == NULL)
	    return False;

	data->font_data = font_data;
	data->font_data_count = count;

        snprintf(buf, sizeof(buf), "fs%d.font.substitute", num);
        _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
        if (count > 0){
            font_data = read_EncodingInfo(count,value);
            if (font_data == NULL)
	        return False;
            data->substitute      = font_data;
            data->substitute_num = count;
        } else {
            snprintf(buf, sizeof(buf), "fs%d.font", num);
            _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
            if (count < 1) {
                data->substitute      = NULL;
                data->substitute_num = 0;
	    } else {
                font_data = read_EncodingInfo(count,value);
                data->substitute      = font_data;
                data->substitute_num = count;
	    }
	}
        read_vw(lcd,data,num);
	length += strlen(data->font_data->name) + 1;
    }

    /* required charset list */
    required_list = Xmalloc(sizeof(char *) * gen->data_num);
    if (required_list == NULL)
	return False;

    om->core.required_charset.charset_list = required_list;
    om->core.required_charset.charset_count = gen->data_num;

    count = gen->data_num;
    data = gen->data;

    if (count > 0) {
	bufptr = Xmalloc(length);
	if (bufptr == NULL) {
	    Xfree(required_list);
	    return False;
	}

	for ( ; count-- > 0; data++) {
	    strcpy(bufptr, data->font_data->name);
	    *required_list++ = bufptr;
	    bufptr += strlen(bufptr) + 1;
	}
    }

    /* orientation list */
    orientation = Xmalloc(sizeof(XOrientation) * 2);
    if (orientation == NULL)
	return False;

    orientation[0] = XOMOrientation_LTR_TTB;
    orientation[1] = XOMOrientation_TTB_RTL;
    om->core.orientation_list.orientation = orientation;
    om->core.orientation_list.num_orientation = 2;

    /* directional dependent drawing */
    om->core.directional_dependent = False;

    /* contextual drawing */
    om->core.contextual_drawing = False;

    /* context dependent */
    om->core.context_dependent = False;

    return True;
}


static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap,
					struct nfs4_label *label)
{
	uint32_t pi = 0;
	uint32_t lfs = 0;
	__u32 len;
	__be32 *p;
	int status = 0;

	if (unlikely(bitmap[2] & (FATTR4_WORD2_SECURITY_LABEL - 1U)))
		return -EIO;
	if (likely(bitmap[2] & FATTR4_WORD2_SECURITY_LABEL)) {
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			return -EIO;
		lfs = be32_to_cpup(p++);
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			return -EIO;
		pi = be32_to_cpup(p++);
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			return -EIO;
		len = be32_to_cpup(p++);
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			return -EIO;
		if (len < NFS4_MAXLABELLEN) {
			if (label) {
				memcpy(label->label, p, len);
				label->len = len;
				label->pi = pi;
				label->lfs = lfs;
				status = NFS_ATTR_FATTR_V4_SECURITY_LABEL;
			}
			bitmap[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
		} else
			printk(KERN_WARNING "%s: label too long (%u)!\n",
					__func__, len);
	}
	if (label && label->label)
		dprintk("%s: label=%s, len=%d, PI=%d, LFS=%d\n", __func__,
			(char *)label->label, label->len, label->pi, label->lfs);
	return status;
}


absl::optional<std::string> canonicalizePath(absl::string_view original_path) {
  std::string canonical_path;
  url::Component in_component(0, original_path.size());
  url::Component out_component;
  url::StdStringCanonOutput output(&canonical_path);
  if (!CanonicalizePath(original_path.data(), in_component, &output, &out_component)) {
    return absl::nullopt;
  } else {
    output.Complete();
    return absl::make_optional(std::move(canonical_path));
  }
}


TEST(Url, ParsingTest) {
  // Test url with no explicit path (with and without port).
  validateUrl("http://www.host.com", "http", "www.host.com", "/", 80);
  validateUrl("http://www.host.com:80", "http", "www.host.com", "/", 80);

  // Test url with "/" path.
  validateUrl("http://www.host.com:80/", "http", "www.host.com", "/", 80);
  validateUrl("http://www.host.com/", "http", "www.host.com", "/", 80);

  // Test url with "?".
  validateUrl("http://www.host.com:80/?", "http", "www.host.com", "/?", 80);
  validateUrl("http://www.host.com/?", "http", "www.host.com", "/?", 80);

  // Test url with "?" but without slash.
  validateUrl("http://www.host.com:80?", "http", "www.host.com", "/?", 80);
  validateUrl("http://www.host.com?", "http", "www.host.com", "/?", 80);

  // Test url with multi-character path.
  validateUrl("http://www.host.com:80/path", "http", "www.host.com", "/path", 80);
  validateUrl("http://www.host.com/path", "http", "www.host.com", "/path", 80);

  // Test url with multi-character path and ? at the end.
  validateUrl("http://www.host.com:80/path?", "http", "www.host.com", "/path?", 80);
  validateUrl("http://www.host.com/path?", "http", "www.host.com", "/path?", 80);

  // Test https scheme.
  validateUrl("https://www.host.com", "https", "www.host.com", "/", 443);

  // Test url with query parameter.
  validateUrl("http://www.host.com:80/?query=param", "http", "www.host.com", "/?query=param", 80);
  validateUrl("http://www.host.com/?query=param", "http", "www.host.com", "/?query=param", 80);

  // Test url with query parameter but without slash. It will be normalized.
  validateUrl("http://www.host.com:80?query=param", "http", "www.host.com", "/?query=param", 80);
  validateUrl("http://www.host.com?query=param", "http", "www.host.com", "/?query=param", 80);

  // Test url with multi-character path and query parameter.
  validateUrl("http://www.host.com:80/path?query=param", "http", "www.host.com",
              "/path?query=param", 80);
  validateUrl("http://www.host.com/path?query=param", "http", "www.host.com", "/path?query=param",
              80);

  // Test url with multi-character path and more than one query parameter.
  validateUrl("http://www.host.com:80/path?query=param&query2=param2", "http", "www.host.com",
              "/path?query=param&query2=param2", 80);
  validateUrl("http://www.host.com/path?query=param&query2=param2", "http", "www.host.com",
              "/path?query=param&query2=param2", 80);

  // Test url with multi-character path, more than one query parameter and fragment
  validateUrl("http://www.host.com:80/path?query=param&query2=param2#fragment", "http",
              "www.host.com", "/path?query=param&query2=param2#fragment", 80);
  validateUrl("http://www.host.com/path?query=param&query2=param2#fragment", "http", "www.host.com",
              "/path?query=param&query2=param2#fragment", 80);

  // Test url with non-default ports.
  validateUrl("https://www.host.com:8443", "https", "www.host.com:8443", "/", 8443);
  validateUrl("http://www.host.com:8080", "http", "www.host.com:8080", "/", 8080);
}


void validateUrl(absl::string_view raw_url, absl::string_view expected_scheme,
                 absl::string_view expected_host_port, absl::string_view expected_path,
                 uint16_t expected_port) {
  Utility::Url url;
  ASSERT_TRUE(url.initialize(raw_url, /*is_connect=*/false)) << "Failed to initialize " << raw_url;
  EXPECT_EQ(url.scheme(), expected_scheme);
  EXPECT_EQ(url.hostAndPort(), expected_host_port);
  EXPECT_EQ(url.pathAndQueryParams(), expected_path);
  EXPECT_EQ(url.port(), expected_port);
}


bool Url::initializeForConnect(GURL&& url) {
  // CONNECT requests can only contain "hostname:port"
  // https://github.com/nodejs/http-parser/blob/d9275da4650fd1133ddc96480df32a9efe4b059b/http_parser.c#L2503-L2506.
  if (!url.is_valid() || url.IsStandard()) {
    return false;
  }

  const auto& parsed = url.parsed_for_possibly_invalid_spec();
  // The parsed.scheme contains the URL's hostname (stored by GURL). While host and port have -1
  // as its length.
  if (parsed.scheme.len <= 0 || parsed.host.len > 0 || parsed.port.len > 0) {
    return false;
  }

  host_and_port_ = url.possibly_invalid_spec();
  const auto& parts = StringUtil::splitToken(host_and_port_, ":", /*keep_empty_string=*/true,
                                             /*trim_whitespace=*/false);
  if (parts.size() != 2 || static_cast<size_t>(parsed.scheme.len) != parts.at(0).size() ||
      !validPortForConnect(parts.at(1))) {
    return false;
  }

  return true;
}


void HeaderMapImpl::setReference(const LowerCaseString& key, absl::string_view value) {
  HeaderString ref_key(key);
  HeaderString ref_value(value);
  remove(key);
  insertByKey(std::move(ref_key), std::move(ref_value));
}


TEST(Context, EmptyHeadersAttributes) {
  HeadersWrapper<Http::RequestHeaderMap> headers(nullptr);
  auto header = headers[CelValue::CreateStringView(Referer)];
  EXPECT_FALSE(header.has_value());
  EXPECT_EQ(0, headers.size());
  EXPECT_TRUE(headers.empty());
}


  absl::optional<CelValue> operator[](CelValue key) const override {
    if (value_ == nullptr || !key.IsString()) {
      return {};
    }
    auto str = std::string(key.StringOrDie().value());
    if (!Http::validHeaderString(str)) {
      // Reject key if it is an invalid header string
      return {};
    }
    auto out = value_->get(Http::LowerCaseString(str));
    return convertHeaderEntry(out);
  }


void HeaderMapImpl::appendCopy(const LowerCaseString& key, absl::string_view value) {
  // TODO(#9221): converge on and document a policy for coalescing multiple headers.
  auto* entry = getExisting(key);
  if (entry) {
    const uint64_t added_size = appendToHeader(entry->value(), value);
    addSize(added_size);
  } else {
    addCopy(key, value);
  }
}


TEST(HeaderMapImplTest, SetCopy) {
  TestRequestHeaderMapImpl headers;
  LowerCaseString foo("hello");
  headers.setCopy(foo, "world");
  EXPECT_EQ("world", headers.get(foo)->value().getStringView());

  // Overwrite value.
  headers.setCopy(foo, "monde");
  EXPECT_EQ("monde", headers.get(foo)->value().getStringView());

  // Add another foo header.
  headers.addCopy(foo, "monde2");
  EXPECT_EQ(headers.size(), 2);

  // Only the first foo header is overridden.
  headers.setCopy(foo, "override-monde");
  EXPECT_EQ(headers.size(), 2);

  HeaderAndValueCb cb;

  InSequence seq;
  EXPECT_CALL(cb, Call("hello", "override-monde"));
  EXPECT_CALL(cb, Call("hello", "monde2"));
  headers.iterate(cb.asIterateCb());

  // Test setting an empty string and then overriding.
  EXPECT_EQ(2UL, headers.remove(foo));
  EXPECT_EQ(headers.size(), 0);
  const std::string empty;
  headers.setCopy(foo, empty);
  EXPECT_EQ(headers.size(), 1);
  headers.setCopy(foo, "not-empty");
  EXPECT_EQ(headers.get(foo)->value().getStringView(), "not-empty");

  // Use setCopy with inline headers both indirectly and directly.
  headers.clear();
  EXPECT_EQ(headers.size(), 0);
  headers.setCopy(Headers::get().Path, "/");
  EXPECT_EQ(headers.size(), 1);
  EXPECT_EQ(headers.getPathValue(), "/");
  headers.setPath("/foo");
  EXPECT_EQ(headers.size(), 1);
  EXPECT_EQ(headers.getPathValue(), "/foo");
}


void fail(Context* ctx, const char* message) {
  fprintf(stderr, "%s\n", message);
  exit(1);
}


static BROTLI_INLINE double FastLog2(size_t v) {
  if (v < sizeof(kLog2Table) / sizeof(kLog2Table[0])) {
    return kLog2Table[v];
  }
#if !(BROTLI_HAVE_LOG2)
  return log((double)v) * LOG_2_INV;
#else
  return log2((double)v);
#endif
}


static BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) {
  return kInsExtra[inscode];
}


static BROTLI_INLINE uint32_t BlockLengthPrefixCode(uint32_t len) {
  uint32_t code = (len >= 177) ? (len >= 753 ? 20 : 14) : (len >= 41 ? 7 : 0);
  while (code < (BROTLI_NUM_BLOCK_LEN_SYMBOLS - 1) &&
      len >= kBlockLengthPrefixCode[code + 1].offset) ++code;
  return code;
}


proto_register_blip(void)
{
	static hf_register_info hf[] = {
	{ &hf_blip_message_number,
		{ "Message Number", "blip.messagenum", FT_UINT64, BASE_DEC,
			NULL, 0x0, NULL, HFILL }
	},
	{ &hf_blip_frame_flags,
		{ "Frame Flags", "blip.frameflags", FT_UINT8, BASE_HEX | BASE_EXT_STRING,
			&flag_combos_ext, 0x0, NULL, HFILL }
	},
	{ &hf_blip_properties_length,
		{ "Properties Length", "blip.propslength", FT_UINT64, BASE_DEC,
			NULL, 0x0, NULL, HFILL }
	},
	{ &hf_blip_properties,
		{ "Properties", "blip.props", FT_STRING, STR_UNICODE,
			NULL, 0x0, NULL, HFILL }
		},
	{ &hf_blip_message_body,
		{ "Message Body", "blip.messagebody", FT_STRING, STR_UNICODE,
			NULL, 0x0, NULL, HFILL }
	},
	{ &hf_blip_ack_size,
		{ "ACK num bytes", "blip.numackbytes", FT_UINT64, BASE_DEC,
			NULL, 0x0, NULL, HFILL }
	},
	{ &hf_blip_checksum,
		{ "Checksum", "blip.checksum", FT_UINT32, BASE_DEC,
			NULL, 0x0, NULL, HFILL }
	}
	};

	/* Setup protocol subtree array */
	static gint *ett[] = {
		&ett_blip
	};

	proto_blip = proto_register_protocol("BLIP Couchbase Mobile", "BLIP", "blip");

	proto_register_field_array(proto_blip, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));

	blip_handle = register_dissector("blip", dissect_blip, proto_blip);
}


static void agent_connect(UdscsConnection *conn)
{
    struct agent_data *agent_data;
    agent_data = g_new0(struct agent_data, 1);
    GError *err = NULL;
    gint pid;

    if (session_info) {
        pid = vdagent_connection_get_peer_pid(VDAGENT_CONNECTION(conn), &err);
        if (err || pid <= 0) {
            static const char msg[] = "Could not get peer PID, disconnecting new client";
            if (err) {
                syslog(LOG_ERR, "%s: %s", msg, err->message);
                g_error_free(err);
            } else {
                syslog(LOG_ERR, "%s", msg);
            }
            agent_data_destroy(agent_data);
            udscs_server_destroy_connection(server, conn);
            return;
        }

        agent_data->session = session_info_session_for_pid(session_info, pid);
    }

    g_object_set_data_full(G_OBJECT(conn), "agent_data", agent_data,
                           (GDestroyNotify) agent_data_destroy);
    udscs_write(conn, VDAGENTD_VERSION, 0, 0,
                (uint8_t *)VERSION, strlen(VERSION) + 1);
    update_active_session_connection(conn);

    if (device_info) {
        forward_data_to_session_agent(VDAGENTD_GRAPHICS_DEVICE_INFO,
                                      (uint8_t *) device_info, device_info_size);
    }
}


long vt_compat_ioctl(struct tty_struct *tty,
	     unsigned int cmd, unsigned long arg)
{
	struct vc_data *vc = tty->driver_data;
	struct console_font_op op;	/* used in multiple places here */
	void __user *up = compat_ptr(arg);
	int perm;

	/*
	 * To have permissions to do most of the vt ioctls, we either have
	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
	 */
	perm = 0;
	if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
		perm = 1;

	switch (cmd) {
	/*
	 * these need special handlers for incompatible data structures
	 */
	case PIO_FONTX:
	case GIO_FONTX:
		return compat_fontx_ioctl(cmd, up, perm, &op);

	case KDFONTOP:
		return compat_kdfontop_ioctl(up, perm, &op, vc);

	case PIO_UNIMAP:
	case GIO_UNIMAP:
		return compat_unimap_ioctl(cmd, up, perm, vc);

	/*
	 * all these treat 'arg' as an integer
	 */
	case KIOCSOUND:
	case KDMKTONE:
#ifdef CONFIG_X86
	case KDADDIO:
	case KDDELIO:
#endif
	case KDSETMODE:
	case KDMAPDISP:
	case KDUNMAPDISP:
	case KDSKBMODE:
	case KDSKBMETA:
	case KDSKBLED:
	case KDSETLED:
	case KDSIGACCEPT:
	case VT_ACTIVATE:
	case VT_WAITACTIVE:
	case VT_RELDISP:
	case VT_DISALLOCATE:
	case VT_RESIZE:
	case VT_RESIZEX:
		return vt_ioctl(tty, cmd, arg);

	/*
	 * the rest has a compatible data structure behind arg,
	 * but we have to convert it to a proper 64 bit pointer.
	 */
	default:
		return vt_ioctl(tty, cmd, (unsigned long)up);
	}
}


static unsigned char *PopRunlengthPacket(Image *image,unsigned char *pixels,
  size_t length,PixelInfo *pixel,ExceptionInfo *exception)
{
  if (image->storage_class != DirectClass)
    {
      unsigned int
        value;

      value=(unsigned int) ClampToQuantum(pixel->index);
      switch (image->depth)
      {
        case 32:
        {
          *pixels++=(unsigned char) (value >> 24);
          *pixels++=(unsigned char) (value >> 16);
        }
        case 16:
          *pixels++=(unsigned char) (value >> 8);
        case 8:
        {
          *pixels++=(unsigned char) value;
          break;
        }
        default:
          (void) ThrowMagickException(exception,GetMagickModule(),
            CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
      }
      switch (image->depth)
      {
        case 32:
        {
          unsigned int
            long_value;

          if (image->alpha_trait != UndefinedPixelTrait)
            {
              long_value=ScaleQuantumToLong(ClampToQuantum(pixel->alpha));
              pixels=PopLongPixel(MSBEndian,long_value,pixels);
            }
          break;
        }
        case 16:
        {
          unsigned short
            short_value;

          if (image->alpha_trait != UndefinedPixelTrait)
            {
              short_value=ScaleQuantumToShort(ClampToQuantum(pixel->alpha));
              pixels=PopShortPixel(MSBEndian,short_value,pixels);
            }
          break;
        }
        case 8:
        {
          unsigned char
            char_value;

          if (image->alpha_trait != UndefinedPixelTrait)
            {
              char_value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
                pixel->alpha));
              pixels=PopCharPixel(char_value,pixels);
            }
          break;
        }
        default:
          (void) ThrowMagickException(exception,GetMagickModule(),
            CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
      }
      *pixels++=(unsigned char) length;
      return(pixels);
    }
  switch (image->depth)
  {
    case 32:
    {
      unsigned int
        value;

      value=ScaleQuantumToLong(ClampToQuantum(pixel->red));
      pixels=PopLongPixel(MSBEndian,value,pixels);
      if (IsGrayColorspace(image->colorspace) == MagickFalse)
        {
          value=ScaleQuantumToLong(ClampToQuantum(pixel->green));
          pixels=PopLongPixel(MSBEndian,value,pixels);
          value=ScaleQuantumToLong(ClampToQuantum(pixel->blue));
          pixels=PopLongPixel(MSBEndian,value,pixels);
        }
      if (image->colorspace == CMYKColorspace)
        {
          value=ScaleQuantumToLong(ClampToQuantum(pixel->black));
          pixels=PopLongPixel(MSBEndian,value,pixels);
        }
      if (image->alpha_trait != UndefinedPixelTrait)
        {
          value=ScaleQuantumToLong(ClampToQuantum(pixel->alpha));
          pixels=PopLongPixel(MSBEndian,value,pixels);
        }
      break;
    }
    case 16:
    {
      unsigned short
        value;

      value=ScaleQuantumToShort(ClampToQuantum(pixel->red));
      pixels=PopShortPixel(MSBEndian,value,pixels);
      if (IsGrayColorspace(image->colorspace) == MagickFalse)
        {
          value=ScaleQuantumToShort(ClampToQuantum(pixel->green));
          pixels=PopShortPixel(MSBEndian,value,pixels);
          value=ScaleQuantumToShort(ClampToQuantum(pixel->blue));
          pixels=PopShortPixel(MSBEndian,value,pixels);
        }
      if (image->colorspace == CMYKColorspace)
        {
          value=ScaleQuantumToShort(ClampToQuantum(pixel->black));
          pixels=PopShortPixel(MSBEndian,value,pixels);
        }
      if (image->alpha_trait != UndefinedPixelTrait)
        {
          value=ScaleQuantumToShort(ClampToQuantum(pixel->alpha));
          pixels=PopShortPixel(MSBEndian,value,pixels);
        }
      break;
    }
    case 8:
    {
      unsigned char
        value;

      value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(pixel->red));
      pixels=PopCharPixel(value,pixels);
      if (IsGrayColorspace(image->colorspace) == MagickFalse)
        {
          value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
            pixel->green));
          pixels=PopCharPixel(value,pixels);
          value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(pixel->blue));
          pixels=PopCharPixel(value,pixels);
        }
      if (image->colorspace == CMYKColorspace)
        {
          value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
            pixel->black));
          pixels=PopCharPixel(value,pixels);
        }
      if (image->alpha_trait != UndefinedPixelTrait)
        {
          value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
            pixel->alpha));
          pixels=PopCharPixel(value,pixels);
        }
      break;
    }
    default:
      (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
        "ImageDepthNotSupported","`%s'",image->filename);
  }
  *pixels++=(unsigned char) length;
  return(pixels);
}


static MagickBooleanType WritePALMImage(const ImageInfo *image_info,
  Image *image,ExceptionInfo *exception)
{
  MagickBooleanType
    status;

  MagickOffsetType
    currentOffset,
    offset,
    scene;

  MagickSizeType
    cc;

  PixelInfo
    transpix;

  QuantizeInfo
    *quantize_info;

  register ssize_t
    x;

  register const Quantum
    *p;

  register Quantum
    *q;

  ssize_t
    y;

  size_t
    count,
    bits_per_pixel,
    bytes_per_row,
    imageListLength,
    nextDepthOffset,
    one;

  unsigned char
    bit,
    byte,
    color,
    *last_row,
    *one_row,
    *ptr,
    version;

  unsigned int
    transparentIndex;

  unsigned short
    color16,
    flags;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
  if (status == MagickFalse)
    return(status);
  quantize_info=AcquireQuantizeInfo(image_info);
  flags=0;
  currentOffset=0;
  transparentIndex=0;
  transpix.red=0.0;
  transpix.green=0.0;
  transpix.blue=0.0;
  transpix.alpha=0.0;
  one=1;
  version=0;
  scene=0;
  imageListLength=GetImageListLength(image);
  do
  {
    (void) TransformImageColorspace(image,sRGBColorspace,exception);
    count=GetNumberColors(image,NULL,exception);
    for (bits_per_pixel=1; (one << bits_per_pixel) < count; bits_per_pixel*=2) ;
    if (bits_per_pixel > 16)
      bits_per_pixel=16;
    else
      if (bits_per_pixel < 16)
        (void) TransformImageColorspace(image,image->colorspace,exception);
    if (bits_per_pixel < 8)
      {
        (void) TransformImageColorspace(image,GRAYColorspace,exception);
        (void) SetImageType(image,PaletteType,exception);
        (void) SortColormapByIntensity(image,exception);
      }
    if ((image->storage_class == PseudoClass) && (image->colors > 256))
      (void) SetImageStorageClass(image,DirectClass,exception);
    if (image->storage_class == PseudoClass)
      flags|=PALM_HAS_COLORMAP_FLAG;
    else
      flags|=PALM_IS_DIRECT_COLOR;
    (void) WriteBlobMSBShort(image,(unsigned short) image->columns); /* width */
    (void) WriteBlobMSBShort(image,(unsigned short) image->rows);  /* height */
    bytes_per_row=((image->columns+(16/bits_per_pixel-1))/(16/
      bits_per_pixel))*2;
    (void) WriteBlobMSBShort(image,(unsigned short) bytes_per_row);
    if ((image_info->compression == RLECompression) ||
        (image_info->compression == FaxCompression))
      flags|=PALM_IS_COMPRESSED_FLAG;
    (void) WriteBlobMSBShort(image, flags);
    (void) WriteBlobByte(image,(unsigned char) bits_per_pixel);
    if (bits_per_pixel > 1)
      version=1;
    if ((image_info->compression == RLECompression) ||
        (image_info->compression == FaxCompression))
      version=2;
    (void) WriteBlobByte(image,version);
    (void) WriteBlobMSBShort(image,0);  /* nextDepthOffset */
    (void) WriteBlobByte(image,(unsigned char) transparentIndex);
    if (image_info->compression == RLECompression)
      (void) WriteBlobByte(image,PALM_COMPRESSION_RLE);
    else
      if (image_info->compression == FaxCompression)
        (void) WriteBlobByte(image,PALM_COMPRESSION_SCANLINE);
      else
        (void) WriteBlobByte(image,PALM_COMPRESSION_NONE);
    (void) WriteBlobMSBShort(image,0);  /* reserved */
    offset=16;
    if (bits_per_pixel == 16)
      {
        (void) WriteBlobByte(image,5);  /* # of bits of red */
        (void) WriteBlobByte(image,6);  /* # of bits of green */
        (void) WriteBlobByte(image,5);  /* # of bits of blue */
        (void) WriteBlobByte(image,0);  /* reserved by Palm */
        (void) WriteBlobMSBLong(image,0);  /* no transparent color, YET */
        offset+=8;
      }
    if (bits_per_pixel == 8)
      {
        if (flags & PALM_HAS_COLORMAP_FLAG)  /* Write out colormap */
          {
            quantize_info->dither_method=IdentifyPaletteImage(image,exception)
              == MagickFalse ? RiemersmaDitherMethod : NoDitherMethod;
            quantize_info->number_colors=image->colors;
            (void) QuantizeImage(quantize_info,image,exception);
            (void) WriteBlobMSBShort(image,(unsigned short) image->colors);
            for (count = 0; count < image->colors; count++)
            {
              (void) WriteBlobByte(image,(unsigned char) count);
              (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
                image->colormap[count].red)));
              (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
                image->colormap[count].green)));
              (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
                image->colormap[count].blue)));
            }
            offset+=2+count*4;
          }
      else  /* Map colors to Palm standard colormap */
        {
          Image
            *affinity_image;

          affinity_image=ConstituteImage(256,1,"RGB",CharPixel,&PalmPalette,
            exception);
          (void) TransformImageColorspace(affinity_image,
            affinity_image->colorspace,exception);
          (void) RemapImage(quantize_info,image,affinity_image,exception);
          for (y=0; y < (ssize_t) image->rows; y++)
          {
            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (Quantum *) NULL)
              break;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              SetPixelIndex(image,(Quantum) FindColor(&image->colormap[(ssize_t)
                GetPixelIndex(image,q)]),q);
              q+=GetPixelChannels(image);
            }
          }
          affinity_image=DestroyImage(affinity_image);
        }
      }
    if (flags & PALM_IS_COMPRESSED_FLAG)
      (void) WriteBlobMSBShort(image,0);  /* fill in size later */
    last_row=(unsigned char *) NULL;
    if (image_info->compression == FaxCompression)
      {
        last_row=(unsigned char *) AcquireQuantumMemory(bytes_per_row+256,
          sizeof(*last_row));
        if (last_row == (unsigned char *) NULL)
          {
            quantize_info=DestroyQuantizeInfo(quantize_info);
            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
          }
      }
    one_row=(unsigned char *) AcquireQuantumMemory(bytes_per_row+256,
      sizeof(*one_row));
    if (one_row == (unsigned char *) NULL)
      {
        if (last_row != (unsigned char *) NULL)
          last_row=(unsigned char *) RelinquishMagickMemory(last_row);
        quantize_info=DestroyQuantizeInfo(quantize_info);
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
      }
    for (y=0; y < (ssize_t) image->rows; y++)
    {
      ptr=one_row;
      (void) memset(ptr,0,bytes_per_row);
      p=GetVirtualPixels(image,0,y,image->columns,1,exception);
      if (p == (const Quantum *) NULL)
        break;
      if (bits_per_pixel == 16)
        {
          for (x=0; x < (ssize_t) image->columns; x++)
          {
            color16=(unsigned short) ((((31*(size_t) GetPixelRed(image,p))/
              (size_t) QuantumRange) << 11) | (((63*(size_t)
              GetPixelGreen(image,p))/(size_t) QuantumRange) << 5) |
              ((31*(size_t) GetPixelBlue(image,p))/(size_t) QuantumRange));
            if (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)
              {
                transpix.red=(MagickRealType) GetPixelRed(image,p);
                transpix.green=(MagickRealType) GetPixelGreen(image,p);
                transpix.blue=(MagickRealType) GetPixelBlue(image,p);
                transpix.alpha=(MagickRealType) GetPixelAlpha(image,p);
                flags|=PALM_HAS_TRANSPARENCY_FLAG;
              }
            *ptr++=(unsigned char) ((color16 >> 8) & 0xff);
            *ptr++=(unsigned char) (color16 & 0xff);
            p+=GetPixelChannels(image);
          }
        }
      else
        {
          byte=0x00;
          bit=(unsigned char) (8-bits_per_pixel);
          for (x=0; x < (ssize_t) image->columns; x++)
          {
            if (bits_per_pixel >= 8)
              color=(unsigned char) GetPixelIndex(image,p);
            else
              color=(unsigned char) (GetPixelIndex(image,p)*
                ((one << bits_per_pixel)-1)/MagickMax(1*image->colors-1,1));
            byte|=color << bit;
            if (bit != 0)
              bit-=(unsigned char) bits_per_pixel;
            else
              {
                *ptr++=byte;
                byte=0x00;
                bit=(unsigned char) (8-bits_per_pixel);
              }
            p+=GetPixelChannels(image);
          }
          if ((image->columns % (8/bits_per_pixel)) != 0)
            *ptr++=byte;
        }
      if (image_info->compression == RLECompression)
        {
          x=0;
          while (x < (ssize_t) bytes_per_row)
          {
            byte=one_row[x];
            count=1;
            while ((one_row[++x] == byte) && (count < 255) &&
                   (x < (ssize_t) bytes_per_row))
              count++;
            (void) WriteBlobByte(image,(unsigned char) count);
            (void) WriteBlobByte(image,(unsigned char) byte);
          }
        }
      else
        if (image_info->compression == FaxCompression)
          {
            char
              tmpbuf[8],
              *tptr;

            for (x = 0;  x < (ssize_t) bytes_per_row;  x += 8)
            {
              tptr = tmpbuf;
              for (bit=0, byte=0; bit < (unsigned char) MagickMin(8,(ssize_t) bytes_per_row-x); bit++)
              {
                if ((y == 0) || (last_row[x + bit] != one_row[x + bit]))
                  {
                    byte |= (1 << (7 - bit));
                    *tptr++ = (char) one_row[x + bit];
                  }
              }
              (void) WriteBlobByte(image, byte);
              (void) WriteBlob(image,tptr-tmpbuf,(unsigned char *) tmpbuf);
            }
            (void) memcpy(last_row,one_row,bytes_per_row);
          }
        else
          (void) WriteBlob(image,bytes_per_row,one_row);
      }
    if (flags & PALM_HAS_TRANSPARENCY_FLAG)
      {
        offset=SeekBlob(image,currentOffset+6,SEEK_SET);
        (void) WriteBlobMSBShort(image,flags);
        offset=SeekBlob(image,currentOffset+12,SEEK_SET);
        (void) WriteBlobByte(image,(unsigned char) transparentIndex);  /* trans index */
      }
    if (bits_per_pixel == 16)
      {
        offset=SeekBlob(image,currentOffset+20,SEEK_SET);
        (void) WriteBlobByte(image,0);  /* reserved by Palm */
        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.red)/
          QuantumRange));
        (void) WriteBlobByte(image,(unsigned char) ((63*transpix.green)/
          QuantumRange));
        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.blue)/
          QuantumRange));
      }
    if (flags & PALM_IS_COMPRESSED_FLAG)  /* fill in size now */
      {
        offset=SeekBlob(image,currentOffset+offset,SEEK_SET);
        (void) WriteBlobMSBShort(image,(unsigned short) (GetBlobSize(image)-
          currentOffset-offset));
      }
    if (one_row != (unsigned char *) NULL)
      one_row=(unsigned char *) RelinquishMagickMemory(one_row);
    if (last_row != (unsigned char *) NULL)
      last_row=(unsigned char *) RelinquishMagickMemory(last_row);
    if (GetNextImageInList(image) == (Image *) NULL)
      break;
    /* padding to 4 byte word */
    for (cc=(GetBlobSize(image)) % 4; cc > 0; cc--)
      (void) WriteBlobByte(image,0);
    /* write nextDepthOffset and return to end of image */
    offset=SeekBlob(image,currentOffset+10,SEEK_SET);
    nextDepthOffset=(size_t) ((GetBlobSize(image)-currentOffset)/4);
    (void) WriteBlobMSBShort(image,(unsigned short) nextDepthOffset);
    currentOffset=(MagickOffsetType) GetBlobSize(image);
    offset=SeekBlob(image,currentOffset,SEEK_SET);
    image=SyncNextImageInList(image);
    status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
    if (status == MagickFalse)
      break;
  } while (image_info->adjoin != MagickFalse);
  quantize_info=DestroyQuantizeInfo(quantize_info);
  (void) CloseBlob(image);
  return(MagickTrue);
}


static inline unsigned char ScaleQuantumToChar(const Quantum quantum)
{
#if !defined(MAGICKCORE_HDRI_SUPPORT)
  return((unsigned char) (((quantum+128UL)-((quantum+128UL) >> 8)) >> 8));
#else
  if (quantum <= 0.0)
    return(0);
  if ((quantum/257.0) >= 255.0)
    return(255);
  return((unsigned char) (quantum/257.0+0.5));
#endif
}


static int IntensityCompare(const void *x,const void *y)
{
  PixelInfo
    *color_1,
    *color_2;

  ssize_t
    intensity;

  color_1=(PixelInfo *) x;
  color_2=(PixelInfo *) y;
  intensity=(ssize_t) (GetPixelInfoIntensity((const Image *) NULL,color_1)-
    GetPixelInfoIntensity((const Image *) NULL,color_2));
  return((int) intensity);
}


raptor_xml_writer_start_element_common(raptor_xml_writer* xml_writer,
                                       raptor_xml_element* element,
                                       int auto_empty)
{
  raptor_iostream* iostr = xml_writer->iostr;
  raptor_namespace_stack *nstack = xml_writer->nstack;
  int depth = xml_writer->depth;
  int auto_indent = XML_WRITER_AUTO_INDENT(xml_writer);
  struct nsd *nspace_declarations = NULL;
  size_t nspace_declarations_count = 0;
  unsigned int i;

  /* max is 1 per element and 1 for each attribute + size of declared */
  if(nstack) {
    int nspace_max_count = element->attribute_count+1;
    if(element->declared_nspaces)
      nspace_max_count += raptor_sequence_size(element->declared_nspaces);
    if(element->xml_language)
      nspace_max_count++;

    nspace_declarations = RAPTOR_CALLOC(struct nsd*, nspace_max_count,
                                        sizeof(struct nsd));
    if(!nspace_declarations)
      return 1;
  }

  if(element->name->nspace) {
    if(nstack && !raptor_namespaces_namespace_in_scope(nstack, element->name->nspace)) {
      nspace_declarations[0].declaration=
        raptor_namespace_format_as_xml(element->name->nspace,
                                       &nspace_declarations[0].length);
      if(!nspace_declarations[0].declaration)
        goto error;
      nspace_declarations[0].nspace = element->name->nspace;
      nspace_declarations_count++;
    }
  }

  if(nstack && element->attributes) {
    for(i = 0; i < element->attribute_count; i++) {
      /* qname */
      if(element->attributes[i]->nspace) {
        /* Check if we need a namespace declaration attribute */
        if(nstack &&
           !raptor_namespaces_namespace_in_scope(nstack, element->attributes[i]->nspace) && element->attributes[i]->nspace != element->name->nspace) {
          /* not in scope and not same as element (so already going to be declared)*/
          unsigned int j;
          int declare_me = 1;

          /* check it wasn't an earlier declaration too */
          for(j = 0; j < nspace_declarations_count; j++)
            if(nspace_declarations[j].nspace == element->attributes[j]->nspace) {
              declare_me = 0;
              break;
            }

          if(declare_me) {
            nspace_declarations[nspace_declarations_count].declaration=
              raptor_namespace_format_as_xml(element->attributes[i]->nspace,
                                             &nspace_declarations[nspace_declarations_count].length);
            if(!nspace_declarations[nspace_declarations_count].declaration)
              goto error;
            nspace_declarations[nspace_declarations_count].nspace = element->attributes[i]->nspace;
            nspace_declarations_count++;
          }
        }
      }

      /* Add the attribute + value */
      nspace_declarations[nspace_declarations_count].declaration=
        raptor_qname_format_as_xml(element->attributes[i],
                                   &nspace_declarations[nspace_declarations_count].length);
      if(!nspace_declarations[nspace_declarations_count].declaration)
        goto error;
      nspace_declarations[nspace_declarations_count].nspace = NULL;
      nspace_declarations_count++;

    }
  }

  if(nstack && element->declared_nspaces &&
     raptor_sequence_size(element->declared_nspaces) > 0) {
    for(i = 0; i< (unsigned int)raptor_sequence_size(element->declared_nspaces); i++) {
      raptor_namespace* nspace = (raptor_namespace*)raptor_sequence_get_at(element->declared_nspaces, i);
      unsigned int j;
      int declare_me = 1;

      /* check it wasn't an earlier declaration too */
      for(j = 0; j < nspace_declarations_count; j++)
        if(nspace_declarations[j].nspace == nspace) {
          declare_me = 0;
          break;
        }

      if(declare_me) {
        nspace_declarations[nspace_declarations_count].declaration=
          raptor_namespace_format_as_xml(nspace,
                                         &nspace_declarations[nspace_declarations_count].length);
        if(!nspace_declarations[nspace_declarations_count].declaration)
          goto error;
        nspace_declarations[nspace_declarations_count].nspace = nspace;
        nspace_declarations_count++;
      }

    }
  }

  if(nstack && element->xml_language) {
    size_t lang_len = strlen(RAPTOR_GOOD_CAST(char*, element->xml_language));
#define XML_LANG_PREFIX_LEN 10
    size_t buf_length = XML_LANG_PREFIX_LEN + lang_len + 1;
    unsigned char* buffer = RAPTOR_MALLOC(unsigned char*, buf_length + 1);
    const char quote = '\"';
    unsigned char* p;

    memcpy(buffer, "xml:lang=\"", XML_LANG_PREFIX_LEN);
    p = buffer + XML_LANG_PREFIX_LEN;
    p += raptor_xml_escape_string(xml_writer->world,
                                  element->xml_language, lang_len,
                                  p, buf_length, quote);
    *p++ = quote;
    *p = '\0';

    nspace_declarations[nspace_declarations_count].declaration = buffer;
    nspace_declarations[nspace_declarations_count].length = buf_length;
    nspace_declarations[nspace_declarations_count].nspace = NULL;
    nspace_declarations_count++;
  }

  raptor_iostream_write_byte('<', iostr);

  if(element->name->nspace && element->name->nspace->prefix_length > 0) {
    raptor_iostream_counted_string_write((const char*)element->name->nspace->prefix,
                                         element->name->nspace->prefix_length,
                                         iostr);
    raptor_iostream_write_byte(':', iostr);
  }
  raptor_iostream_counted_string_write((const char*)element->name->local_name,
                                       element->name->local_name_length,
                                       iostr);

  /* declare namespaces and attributes */
  if(nspace_declarations_count) {
    int need_indent = 0;

    /* sort them into the canonical order */
    qsort((void*)nspace_declarations,
          nspace_declarations_count, sizeof(struct nsd),
          raptor_xml_writer_nsd_compare);

    /* declare namespaces first */
    for(i = 0; i < nspace_declarations_count; i++) {
      if(!nspace_declarations[i].nspace)
        continue;

      if(auto_indent && need_indent) {
        /* indent attributes */
        raptor_xml_writer_newline(xml_writer);
        xml_writer->depth++;
        raptor_xml_writer_indent(xml_writer);
        xml_writer->depth--;
      }
      raptor_iostream_write_byte(' ', iostr);
      raptor_iostream_counted_string_write((const char*)nspace_declarations[i].declaration,
                                           nspace_declarations[i].length,
                                           iostr);
      RAPTOR_FREE(char*, nspace_declarations[i].declaration);
      nspace_declarations[i].declaration = NULL;
      need_indent = 1;

      if(raptor_namespace_stack_start_namespace(nstack,
                                                (raptor_namespace*)nspace_declarations[i].nspace,
                                                depth))
        goto error;
    }

    /* declare attributes */
    for(i = 0; i < nspace_declarations_count; i++) {
      if(nspace_declarations[i].nspace)
        continue;

      if(auto_indent && need_indent) {
        /* indent attributes */
        raptor_xml_writer_newline(xml_writer);
        xml_writer->depth++;
        raptor_xml_writer_indent(xml_writer);
        xml_writer->depth--;
      }
      raptor_iostream_write_byte(' ', iostr);
      raptor_iostream_counted_string_write((const char*)nspace_declarations[i].declaration,
                                           nspace_declarations[i].length,
                                           iostr);
      need_indent = 1;

      RAPTOR_FREE(char*, nspace_declarations[i].declaration);
      nspace_declarations[i].declaration = NULL;
    }
  }

  if(!auto_empty)
    raptor_iostream_write_byte('>', iostr);

  if(nstack)
    RAPTOR_FREE(stringarray, nspace_declarations);

  return 0;

  /* Clean up nspace_declarations on error */
  error:

  for(i = 0; i < nspace_declarations_count; i++) {
    if(nspace_declarations[i].declaration)
      RAPTOR_FREE(char*, nspace_declarations[i].declaration);
  }

  RAPTOR_FREE(stringarray, nspace_declarations);

  return 1;
}