ipp_free_values(ipp_attribute_t *attr,	/* I - Attribute to free values from */
                int             element,/* I - First value to free */
                int             count)	/* I - Number of values to free */
{
  int		i;			/* Looping var */
  _ipp_value_t	*value;			/* Current value */


  DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", (void *)attr, element, count));

  if (!(attr->value_tag & IPP_TAG_CUPS_CONST))
  {
   /*
    * Free values as needed...
    */

    switch (attr->value_tag)
    {
      case IPP_TAG_TEXTLANG :
      case IPP_TAG_NAMELANG :
	  if (element == 0 && count == attr->num_values &&
	      attr->values[0].string.language)
	  {
	    _cupsStrFree(attr->values[0].string.language);
	    attr->values[0].string.language = NULL;
	  }
	  /* Fall through to other string values */

      case IPP_TAG_TEXT :
      case IPP_TAG_NAME :
      case IPP_TAG_RESERVED_STRING :
      case IPP_TAG_KEYWORD :
      case IPP_TAG_URI :
      case IPP_TAG_URISCHEME :
      case IPP_TAG_CHARSET :
      case IPP_TAG_LANGUAGE :
      case IPP_TAG_MIMETYPE :
	  for (i = count, value = attr->values + element;
	       i > 0;
	       i --, value ++)
	  {
	    _cupsStrFree(value->string.text);
	    value->string.text = NULL;
	  }
	  break;

      case IPP_TAG_UNSUPPORTED_VALUE :
      case IPP_TAG_DEFAULT :
      case IPP_TAG_UNKNOWN :
      case IPP_TAG_NOVALUE :
      case IPP_TAG_NOTSETTABLE :
      case IPP_TAG_DELETEATTR :
      case IPP_TAG_ADMINDEFINE :
      case IPP_TAG_INTEGER :
      case IPP_TAG_ENUM :
      case IPP_TAG_BOOLEAN :
      case IPP_TAG_DATE :
      case IPP_TAG_RESOLUTION :
      case IPP_TAG_RANGE :
	  break;

      case IPP_TAG_BEGIN_COLLECTION :
	  for (i = count, value = attr->values + element;
	       i > 0;
	       i --, value ++)
	  {
	    ippDelete(value->collection);
	    value->collection = NULL;
	  }
	  break;

      case IPP_TAG_STRING :
      default :
	  for (i = count, value = attr->values + element;
	       i > 0;
	       i --, value ++)
	  {
	    if (value->unknown.data)
	    {
	      free(value->unknown.data);
	      value->unknown.data = NULL;
	    }
	  }
	  break;
    }
  }

 /*
  * If we are not freeing values from the end, move the remaining values up...
  */

  if ((element + count) < attr->num_values)
    memmove(attr->values + element, attr->values + element + count,
            (size_t)(attr->num_values - count - element) * sizeof(_ipp_value_t));

  attr->num_values -= count;
}
ipp_free_values(ipp_attribute_t *attr,	 
                int             element, 
                int             count)	 
{
  int		i;			 
  _ipp_value_t	*value;			 


  DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", (void *)attr, element, count));

  if (!(attr->value_tag & IPP_TAG_CUPS_CONST))
  {
    

    switch (attr->value_tag)
    {
      case IPP_TAG_TEXTLANG :
      case IPP_TAG_NAMELANG :
	  if (element == 0 && count == attr->num_values &&
	      attr->values[0].string.language)
	  {
	    _cupsStrFree(attr->values[0].string.language);
	    attr->values[0].string.language = NULL;
	  }
	   

      case IPP_TAG_TEXT :
      case IPP_TAG_NAME :
      case IPP_TAG_RESERVED_STRING :
      case IPP_TAG_KEYWORD :
      case IPP_TAG_URI :
      case IPP_TAG_URISCHEME :
      case IPP_TAG_CHARSET :
      case IPP_TAG_LANGUAGE :
      case IPP_TAG_MIMETYPE :
	  for (i = count, value = attr->values + element;
	       i > 0;
	       i --, value ++)
	  {
	    _cupsStrFree(value->string.text);
	    value->string.text = NULL;
	  }
	  break;

      case IPP_TAG_UNSUPPORTED_VALUE :
      case IPP_TAG_DEFAULT :
      case IPP_TAG_UNKNOWN :
      case IPP_TAG_NOVALUE :
      case IPP_TAG_NOTSETTABLE :
      case IPP_TAG_DELETEATTR :
      case IPP_TAG_ADMINDEFINE :
      case IPP_TAG_INTEGER :
      case IPP_TAG_ENUM :
      case IPP_TAG_BOOLEAN :
      case IPP_TAG_DATE :
      case IPP_TAG_RESOLUTION :
      case IPP_TAG_RANGE :
	  break;

      case IPP_TAG_BEGIN_COLLECTION :
	  for (i = count, value = attr->values + element;
	       i > 0;
	       i --, value ++)
	  {
	    ippDelete(value->collection);
	    value->collection = NULL;
	  }
	  break;

      case IPP_TAG_STRING :
      default :
	  for (i = count, value = attr->values + element;
	       i > 0;
	       i --, value ++)
	  {
	    if (value->unknown.data)
	    {
	      free(value->unknown.data);
	      value->unknown.data = NULL;
	    }
	  }
	  break;
    }
  }

  

  if ((element + count) < attr->num_values)
    memmove(attr->values + element, attr->values + element + count,
            (size_t)(attr->num_values - count - element) * sizeof(_ipp_value_t));

  attr->num_values -= count;
}