예제 #1
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddRanges(ipp_t      *ipp,		
             ipp_tag_t  group,		
	     const char *name,		
	     int        num_values,	
	     const int  *lower,		
	     const int  *upper)		
{
  int			i;		
  ipp_attribute_t	*attr;		
  ipp_value_t		*value;		

  if (!ipp || !name || num_values < 1)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
    return (NULL);

  attr->name      = stralloc(name);
  attr->group_tag = group;
  attr->value_tag = IPP_TAG_RANGE;

  if (lower != NULL && upper != NULL)
    for (i = 0, value = attr->values;
	 i < num_values;
	 i ++, value ++)
    {
      value->range.lower = lower[i];
      value->range.upper = upper[i];
    }

  return (attr);
}
예제 #2
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t	*			
ippAddOctetString(ipp_t      *ipp,	
                  ipp_tag_t  group,	
                  const char *name,	
                  const void *data,	
		  int        datalen)	
{
  ipp_attribute_t	*attr;		


  if (ipp == NULL || name == NULL)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, 1)) == NULL)
    return (NULL);

  attr->name                     = stralloc(name);
  attr->group_tag                = group;
  attr->value_tag                = IPP_TAG_STRING;
  attr->values[0].unknown.length = datalen;

  if (data)
  {
    if ((attr->values[0].unknown.data = malloc(datalen)) == NULL)
    {
      ippDeleteAttribute(ipp, attr);
      return (NULL);
    }

    memcpy(attr->values[0].unknown.data, data, datalen);
  }

  return (attr);
}
예제 #3
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddResolutions(ipp_t      *ipp,	
        	  ipp_tag_t  group,	
		  const char *name,	
		  int        num_values,
		  ipp_res_t  units,	
		  const int  *xres,	
		  const int  *yres)	
{
  int			i;		
  ipp_attribute_t	*attr;		
  ipp_value_t		*value;		

  if (!ipp || !name || num_values < 1)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
    return (NULL);

  attr->name      = stralloc(name);
  attr->group_tag = group;
  attr->value_tag = IPP_TAG_RESOLUTION;

  if (xres != NULL && yres != NULL)
    for (i = 0, value = attr->values;
	 i < num_values;
	 i ++, value ++)
    {
      value->resolution.xres  = xres[i];
      value->resolution.yres  = yres[i];
      value->resolution.units = units;
    }

  return (attr);
}
예제 #4
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddCollections(
    ipp_t       *ipp,			
    ipp_tag_t   group,			
    const char  *name,			
    int         num_values,		
    const ipp_t **values)		
{
  int			i;		
  ipp_attribute_t	*attr;		
  ipp_value_t		*value;		

  if (!ipp || !name || num_values < 1)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
    return (NULL);

  attr->name      = stralloc(name);
  attr->group_tag = group;
  attr->value_tag = IPP_TAG_BEGIN_COLLECTION;

  if (values != NULL)
  {
    for (i = 0, value = attr->values;
	 i < num_values;
	 i ++, value ++)
    {
      value->collection = (ipp_t *)values[i];
      value->collection->use ++;
    }
  }

  return (attr);
}
예제 #5
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddIntegers(ipp_t      *ipp,		
               ipp_tag_t  group,	
	       ipp_tag_t  type,		
	       const char *name,	
	       int        num_values,	
	       const int  *values)	
{
  int			i;		
  ipp_attribute_t	*attr;		
  ipp_value_t		*value;		

  if (!ipp || !name || num_values < 1)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
    return (NULL);

  attr->name      = stralloc(name);
  attr->group_tag = group;
  attr->value_tag = type;

  if (values != NULL)
    for (i = 0, value = attr->values;
	 i < num_values;
	 i ++, value ++)
      value->integer = values[i];

  return (attr);
}
예제 #6
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddResolution(ipp_t      *ipp,	
        	 ipp_tag_t  group,	
		 const char *name,	
		 ipp_res_t  units,	
		 int        xres,	
		 int        yres)	
{
  ipp_attribute_t	*attr;		

  if (!ipp || !name)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, 1)) == NULL)
    return (NULL);

  attr->name                       = stralloc(name);
  attr->group_tag                  = group;
  attr->value_tag                  = IPP_TAG_RESOLUTION;
  attr->values[0].resolution.xres  = xres;
  attr->values[0].resolution.yres  = yres;
  attr->values[0].resolution.units = units;

  return (attr);
}
예제 #7
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddBooleans(ipp_t      *ipp,		
               ipp_tag_t  group,	
	       const char *name,	
	       int        num_values,	
	       const char *values)	
{
  int			i;		
  ipp_attribute_t	*attr;		
  ipp_value_t		*value;		

  if (!ipp || !name || num_values < 1)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
    return (NULL);

  attr->name      = stralloc(name);
  attr->group_tag = group;
  attr->value_tag = IPP_TAG_BOOLEAN;

  if (values != NULL)
    for (i = 0, value = attr->values;
	 i < num_values;
	 i ++, value ++)
      value->boolean = values[i];

  return (attr);
}
예제 #8
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddSeparator(ipp_t *ipp)		
{
  ipp_attribute_t	*attr;		

  if (!ipp)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, 0)) == NULL)
    return (NULL);

  attr->group_tag = IPP_TAG_ZERO;
  attr->value_tag = IPP_TAG_ZERO;

  return (attr);
}
예제 #9
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *
ippAddString(ipp_t      *ipp,
             ipp_tag_t  group,
			 ipp_tag_t  type,
             const char *name,
             const char *charset,
             const char *value)
{
  ipp_attribute_t	*attr;		
  char		buffer[1024],	
			*bufptr;	

  if (!ipp || !name)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, 1)) == NULL)
    return (NULL);

  if (type == IPP_TAG_LANGUAGE && !strcaseinsensitivecmp(value, "C"))
    value = "en";

  if ((type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET) && value)
  {
    strncpy(buffer, value, sizeof(buffer));
    value = buffer;

    for (bufptr = buffer; *bufptr; bufptr ++)
      if (*bufptr == '_')
        *bufptr = '-';
      else
        *bufptr = tolower(*bufptr & 255);
  }

  attr->name                     = stralloc(name);
  attr->group_tag                = group;
  attr->value_tag                = type;
  attr->values[0].string.charset = ((int)type & IPP_TAG_COPY) ? (char *)charset :
                                   charset ? stralloc(charset) : NULL;
  attr->values[0].string.text    = ((int)type & IPP_TAG_COPY) ? (char *)value :
                                   value ? stralloc(value) : NULL;

  return (attr);
}
예제 #10
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddBoolean(ipp_t      *ipp,		
              ipp_tag_t  group,		
              const char *name,		
              char       value)		
{
  ipp_attribute_t	*attr;		

  if (!ipp || !name)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, 1)) == NULL)
    return (NULL);

  attr->name              = stralloc(name);
  attr->group_tag         = group;
  attr->value_tag         = IPP_TAG_BOOLEAN;
  attr->values[0].boolean = value;

  return (attr);
}
예제 #11
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddDate(ipp_t             *ipp,	
           ipp_tag_t         group,	
	   const char        *name,	
	   const ipp_uchar_t *value)	
{
  ipp_attribute_t	*attr;		

  if (!ipp || !name || !value)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, 1)) == NULL)
    return (NULL);

  attr->name      = stralloc(name);
  attr->group_tag = group;
  attr->value_tag = IPP_TAG_DATE;
  memcpy(attr->values[0].date, value, 11);

  return (attr);
}
예제 #12
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddInteger(ipp_t      *ipp,		
              ipp_tag_t  group,		
	      ipp_tag_t  type,		
              const char *name,		
              int        value)		
{
  ipp_attribute_t	*attr;		

  if (!ipp || !name)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, 1)) == NULL)
    return (NULL);

  attr->name              = stralloc(name);
  attr->group_tag         = group;
  attr->value_tag         = type;
  attr->values[0].integer = value;

  return (attr);
}
예제 #13
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddCollection(ipp_t      *ipp,	
                 ipp_tag_t  group,	
		 const char *name,	
		 ipp_t      *value)	
{
  ipp_attribute_t	*attr;		

  if (!ipp || !name)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, 1)) == NULL)
    return (NULL);

  attr->name                 = stralloc(name);
  attr->group_tag            = group;
  attr->value_tag            = IPP_TAG_BEGIN_COLLECTION;
  attr->values[0].collection = value;

  value->use ++;

  return (attr);
}
예제 #14
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddRange(ipp_t      *ipp,		
            ipp_tag_t  group,		
	    const char *name,		
	    int        lower,		
	    int        upper)		
{
  ipp_attribute_t	*attr;		

  if (!ipp || !name)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, 1)) == NULL)
    return (NULL);

  attr->name                  = stralloc(name);
  attr->group_tag             = group;
  attr->value_tag             = IPP_TAG_RANGE;
  attr->values[0].range.lower = lower;
  attr->values[0].range.upper = upper;

  return (attr);
}
예제 #15
0
void
cupsEncodeOptions2(
    ipp_t         *ipp,			/* I - Request to add to */
    int           num_options,		/* I - Number of options */
    cups_option_t *options,		/* I - Options */
    ipp_tag_t     group_tag)		/* I - Group to encode */
{
  int		i, j;			/* Looping vars */
  int		count;			/* Number of values */
  char		*s,			/* Pointer into option value */
		*val,			/* Pointer to option value */
		*copy,			/* Copy of option value */
		*sep,			/* Option separator */
		quote;			/* Quote character */
  ipp_attribute_t *attr;		/* IPP attribute */
  ipp_tag_t	value_tag;		/* IPP value tag */
  cups_option_t	*option;		/* Current option */
  ipp_t		*collection;		/* Collection value */
  int		num_cols;		/* Number of collection values */
  cups_option_t	*cols;			/* Collection values */


  DEBUG_printf(("cupsEncodeOptions2(ipp=%p, num_options=%d, options=%p, "
                "group_tag=%x)", ipp, num_options, options, group_tag));

 /*
  * Range check input...
  */

  if (!ipp || num_options < 1 || !options)
    return;

 /*
  * Do special handling for the document-format/raw options...
  */

  if (group_tag == IPP_TAG_OPERATION)
  {
   /*
    * Handle the document format stuff first...
    */

    if ((val = (char *)cupsGetOption("document-format", num_options, options)) != NULL)
      ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
        	   NULL, val);
    else if (cupsGetOption("raw", num_options, options))
      ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
        	   NULL, "application/vnd.cups-raw");
    else
      ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
        	   NULL, "application/octet-stream");
  }

 /*
  * Then loop through the options...
  */

  for (i = num_options, option = options; i > 0; i --, option ++)
  {
    _ipp_option_t	*match;		/* Matching attribute */


   /*
    * Skip document format options that are handled above...
    */

    if (!_cups_strcasecmp(option->name, "raw") ||
        !_cups_strcasecmp(option->name, "document-format") ||
	!option->name[0])
      continue;

   /*
    * Figure out the proper value and group tags for this option...
    */

    if ((match = _ippFindOption(option->name)) != NULL)
    {
      if (match->group_tag != group_tag)
        continue;

      value_tag = match->value_tag;
    }
    else
    {
      int	namelen;		/* Length of name */


      namelen = (int)strlen(option->name);

      if (namelen < 9 || strcmp(option->name + namelen - 8, "-default"))
      {
	if (group_tag != IPP_TAG_JOB)
          continue;
      }
      else if (group_tag != IPP_TAG_PRINTER)
        continue;

      if (!_cups_strcasecmp(option->value, "true") ||
          !_cups_strcasecmp(option->value, "false"))
	value_tag = IPP_TAG_BOOLEAN;
      else
	value_tag = IPP_TAG_NAME;
    }

   /*
    * Count the number of values...
    */

    if (match && match->multivalue)
    {
      for (count = 1, sep = option->value, quote = 0; *sep; sep ++)
      {
	if (*sep == quote)
	  quote = 0;
	else if (!quote && (*sep == '\'' || *sep == '\"'))
	{
	 /*
	  * Skip quoted option value...
	  */

	  quote = *sep++;
	}
	else if (*sep == ',' && !quote)
	  count ++;
	else if (*sep == '\\' && sep[1])
	  sep ++;
      }
    }
    else
      count = 1;

    DEBUG_printf(("2cupsEncodeOptions2: option=\"%s\", count=%d",
                  option->name, count));

   /*
    * Allocate memory for the attribute values...
    */

    if ((attr = _ippAddAttr(ipp, count)) == NULL)
    {
     /*
      * Ran out of memory!
      */

      DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for attributes!");
      return;
    }

   /*
    * Now figure out what type of value we have...
    */

    attr->group_tag = group_tag;
    attr->value_tag = value_tag;

   /*
    * Copy the name over...
    */

    attr->name = _cupsStrAlloc(option->name);

    if (count > 1)
    {
     /*
      * Make a copy of the value we can fiddle with...
      */

      if ((copy = strdup(option->value)) == NULL)
      {
       /*
	* Ran out of memory!
	*/

	DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for value copy!");
	ippDeleteAttribute(ipp, attr);
	return;
      }

      val = copy;
    }
    else
    {
     /*
      * Since we have a single value, use the value directly...
      */

      val  = option->value;
      copy = NULL;
    }

   /*
    * Scan the value string for values...
    */

    for (j = 0, sep = val; j < count; val = sep, j ++)
    {
     /*
      * Find the end of this value and mark it if needed...
      */

      if (count > 1)
      {
	for (quote = 0; *sep; sep ++)
	{
	  if (*sep == quote)
	  {
	   /*
	    * Finish quoted value...
	    */

	    quote = 0;
	  }
	  else if (!quote && (*sep == '\'' || *sep == '\"'))
	  {
	   /*
	    * Handle quoted option value...
	    */

	    quote = *sep;
	  }
	  else if (*sep == ',' && count > 1)
	    break;
	  else if (*sep == '\\' && sep[1])
	  {
	   /*
	    * Skip quoted character...
	    */

	    sep ++;
	  }
	}

	if (*sep == ',')
	  *sep++ = '\0';
      }

     /*
      * Copy the option value(s) over as needed by the type...
      */

      switch (attr->value_tag)
      {
	case IPP_TAG_INTEGER :
	case IPP_TAG_ENUM :
	   /*
	    * Integer/enumeration value...
	    */

            attr->values[j].integer = strtol(val, &s, 10);

            DEBUG_printf(("2cupsEncodeOptions2: Added integer option value "
	                  "%d...", attr->values[j].integer));
            break;

	case IPP_TAG_BOOLEAN :
	    if (!_cups_strcasecmp(val, "true") ||
	        !_cups_strcasecmp(val, "on") ||
	        !_cups_strcasecmp(val, "yes"))
	    {
	     /*
	      * Boolean value - true...
	      */

	      attr->values[j].boolean = 1;

              DEBUG_puts("2cupsEncodeOptions2: Added boolean true value...");
	    }
	    else
	    {
	     /*
	      * Boolean value - false...
	      */

	      attr->values[j].boolean = 0;

              DEBUG_puts("2cupsEncodeOptions2: Added boolean false value...");
	    }
            break;

	case IPP_TAG_RANGE :
	   /*
	    * Range...
	    */

            if (*val == '-')
	    {
	      attr->values[j].range.lower = 1;
	      s = val;
	    }
	    else
	      attr->values[j].range.lower = strtol(val, &s, 10);

	    if (*s == '-')
	    {
	      if (s[1])
		attr->values[j].range.upper = strtol(s + 1, NULL, 10);
	      else
		attr->values[j].range.upper = 2147483647;
            }
	    else
	      attr->values[j].range.upper = attr->values[j].range.lower;

	    DEBUG_printf(("2cupsEncodeOptions2: Added range option value "
	                  "%d-%d...", attr->values[j].range.lower,
			  attr->values[j].range.upper));
            break;

	case IPP_TAG_RESOLUTION :
	   /*
	    * Resolution...
	    */

	    attr->values[j].resolution.xres = strtol(val, &s, 10);

	    if (*s == 'x')
	      attr->values[j].resolution.yres = strtol(s + 1, &s, 10);
	    else
	      attr->values[j].resolution.yres = attr->values[j].resolution.xres;

	    if (!_cups_strcasecmp(s, "dpc"))
              attr->values[j].resolution.units = IPP_RES_PER_CM;
            else
              attr->values[j].resolution.units = IPP_RES_PER_INCH;

	    DEBUG_printf(("2cupsEncodeOptions2: Added resolution option value "
	                  "%s...", val));
            break;

	case IPP_TAG_STRING :
           /*
	    * octet-string
	    */

            attr->values[j].unknown.length = (int)strlen(val);
	    attr->values[j].unknown.data   = strdup(val);

            DEBUG_printf(("2cupsEncodeOptions2: Added octet-string value "
	                  "\"%s\"...", (char *)attr->values[j].unknown.data));
            break;

        case IPP_TAG_BEGIN_COLLECTION :
	   /*
	    * Collection value
	    */

	    num_cols   = cupsParseOptions(val, 0, &cols);
	    if ((collection = ippNew()) == NULL)
	    {
	      cupsFreeOptions(num_cols, cols);

	      if (copy)
	        free(copy);

	      ippDeleteAttribute(ipp, attr);
	      return;
            }

	    attr->values[j].collection = collection;
	    cupsEncodeOptions2(collection, num_cols, cols, IPP_TAG_JOB);
            cupsFreeOptions(num_cols, cols);
	    break;

	default :
	    if ((attr->values[j].string.text = _cupsStrAlloc(val)) == NULL)
	    {
	     /*
	      * Ran out of memory!
	      */

	      DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for string!");

	      if (copy)
	        free(copy);

	      ippDeleteAttribute(ipp, attr);
	      return;
	    }

	    DEBUG_printf(("2cupsEncodeOptions2: Added string value \"%s\"...",
	                  val));
            break;
      }
    }

    if (copy)
      free(copy);
  }
}
예제 #16
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_attribute_t *			
ippAddStrings(
    ipp_t              *ipp,		
    ipp_tag_t          group,		
    ipp_tag_t          type,		
    const char         *name,		
    int                num_values,	
    const char         *charset,	
    const char * const *values)		
{
  int			i;		
  ipp_attribute_t	*attr;		
  ipp_value_t		*value;		
  char			buffer[1024],	
			*bufptr;	

  if (!ipp || !name || num_values < 1)
    return (NULL);

  if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
    return (NULL);

  attr->name      = stralloc(name);
  attr->group_tag = group;
  attr->value_tag = type;

  for (i = 0, value = attr->values;
       i < num_values;
       i ++, value ++)
  {
    if (i == 0)
      value->string.charset = ((int)type & IPP_TAG_COPY) ? (char *)charset :
                                   charset ? stralloc(charset) : NULL;
    else
      value->string.charset = attr->values[0].string.charset;

    if (values != NULL)
    {
      if ((int)type & IPP_TAG_COPY)
        value->string.text = (char *)values[i];
      else if (type == IPP_TAG_LANGUAGE && !strcaseinsensitivecmp(values[i], "C"))
      {

	value->string.text = ((int)type & IPP_TAG_COPY) ? "en" :
                                      "en";
      }
      else if (type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET)
      {
	strncpy(buffer, values[i], sizeof(buffer));

	for (bufptr = buffer; *bufptr; bufptr ++)
	  if (*bufptr == '_')
	    *bufptr = '-';
	  else
	    *bufptr = tolower(*bufptr & 255);

	value->string.text = stralloc(buffer);
      }
      else
	value->string.text = stralloc(values[i]);

    }
  }

  return (attr);
}
예제 #17
0
파일: ipp.c 프로젝트: daddyreb/Bigit_Genie
ipp_state_t				
ippReadIO(void       *src,		
          ipp_iocb_t cb,		
	  int        blocking,		
	  ipp_t      *parent,		
          ipp_t      *ipp)		
{
  int			n;		
  unsigned char		*buffer,	
			string[IPP_MAX_NAME],
					
			*bufptr;	
  ipp_attribute_t	*attr;		
  ipp_tag_t		tag;		
  ipp_tag_t		value_tag;	
  ipp_value_t		*value;		

  if (!src || !ipp)
    return (IPP_ERROR);

  if ((buffer = ipp_buffer_get()) == NULL)
  {
    return (IPP_ERROR);
  }

  switch (ipp->state)
  {
    case IPP_IDLE :
        ipp->state = (ipp_state_t)(ipp->state+1); 

    case IPP_HEADER :
        if (parent == NULL)
	{
      if ((*cb)(src, buffer, 8) < 8)
	  {
	    ipp_buffer_release(buffer);
	    return (IPP_ERROR);
	  }
          ipp->request.any.version[0]  = buffer[0];
          ipp->request.any.version[1]  = buffer[1];
          ipp->request.any.op_status   = (buffer[2] << 8) | buffer[3];
          ipp->request.any.request_id  = (((((buffer[4] << 8) | buffer[5]) << 8) |
	                        	 buffer[6]) << 8) | buffer[7];
        }

        ipp->state   = IPP_ATTRIBUTE;
	ipp->current = NULL;
	ipp->curtag  = IPP_TAG_ZERO;
	ipp->prev    = ipp->last;

        if (!blocking)
	  break;

    case IPP_ATTRIBUTE :
        for (;;)
	{
	  if ((*cb)(src, buffer, 1) < 1)
	  {
	    ipp_buffer_release(buffer);
	    return (IPP_ERROR);
	  }
          tag = (ipp_tag_t)buffer[0];

	  if (tag == IPP_TAG_END)
	  {
	    ipp->state = IPP_DATA;
	    break;
	  }
          else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
	  {
		  if (ipp->curtag == tag)
	      ipp->prev = ippAddSeparator(ipp);
            else if (ipp->current)
	      ipp->prev = ipp->current;

	    ipp->curtag  = tag;
	    ipp->current = NULL;
	    continue;
	  }

          if ((*cb)(src, buffer, 2) < 2)
	  {
	    ipp_buffer_release(buffer);
	    return (IPP_ERROR);
	  }

          n = (buffer[0] << 8) | buffer[1];

          if (n >= IPP_BUF_SIZE)
	  {
	    ipp_buffer_release(buffer);
	    return (IPP_ERROR);
	  }

          if (n == 0 && tag != IPP_TAG_MEMBERNAME &&
	      tag != IPP_TAG_END_COLLECTION)
	  {
        if (ipp->current == NULL)
	    {
	      ipp_buffer_release(buffer);
	      return (IPP_ERROR);
	    }

            attr      = ipp->current;
	    value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);

	    if (value_tag == IPP_TAG_ZERO)
	    {
	      attr->value_tag = tag;
	    }
	    else if (value_tag == IPP_TAG_TEXTLANG ||
	             value_tag == IPP_TAG_NAMELANG ||
		     (value_tag >= IPP_TAG_TEXT &&
		      value_tag <= IPP_TAG_MIMETYPE))
            {
	      if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG &&
	          (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) &&
		  tag != IPP_TAG_NOVALUE)
	      {
		ipp_buffer_release(buffer);
	        return (IPP_ERROR);
	      }
            }
	    else if (value_tag != tag)
	    {
	      ipp_buffer_release(buffer);
	      return (IPP_ERROR);
            }
	    if (attr->num_values == 1 ||
	        (attr->num_values > 0 &&
	         (attr->num_values & (IPP_MAX_VALUES - 1)) == 0))
	    {
	      ipp_attribute_t	*temp;	

              if ((temp = (ipp_attribute_t *)realloc(attr, sizeof(ipp_attribute_t) +
	                                (attr->num_values + IPP_MAX_VALUES - 1) *
					sizeof(ipp_value_t))) == NULL)
	      {
		ipp_buffer_release(buffer);
	        return (IPP_ERROR);
	      }

              if (temp != attr)
	      {
        	if (ipp->prev)
	          ipp->prev->next = temp;
		else
	          ipp->attrs = temp;

        	attr = ipp->current = ipp->last = temp;
	      }
	    }
	  }
	  else if (tag == IPP_TAG_MEMBERNAME)
	  {
	    if (n)
	    {
	      ipp_buffer_release(buffer);
	      return (IPP_ERROR);
	    }

            if (ipp->current)
	      ipp->prev = ipp->current;

	    attr = ipp->current = _ippAddAttr(ipp, 1);

	    attr->group_tag  = ipp->curtag;
	    attr->value_tag  = IPP_TAG_ZERO;
	    attr->num_values = 0;
	  }
	  else if (tag != IPP_TAG_END_COLLECTION)
	  {
		if ((*cb)(src, buffer, n) < n)
	    {
	      ipp_buffer_release(buffer);
	      return (IPP_ERROR);
	    }

	    buffer[n] = '\0';

            if (ipp->current)
	      ipp->prev = ipp->current;

	    if ((attr = ipp->current = _ippAddAttr(ipp, 1)) == NULL)
	    {
	      ipp_buffer_release(buffer);
	      return (IPP_ERROR);
	    }

	    attr->group_tag  = ipp->curtag;
	    attr->value_tag  = tag;
	    attr->name       = stralloc((char *)buffer);
	    attr->num_values = 0;
	  }
	  else
	    attr = NULL;

          if (tag != IPP_TAG_END_COLLECTION)
            value = attr->values + attr->num_values;
	  else
	    value = NULL;

	  if ((*cb)(src, buffer, 2) < 2)
	  {
	    ipp_buffer_release(buffer);
	    return (IPP_ERROR);
	  }

	  n = (buffer[0] << 8) | buffer[1];

	  switch (tag)
	  {
	    case IPP_TAG_INTEGER :
	    case IPP_TAG_ENUM :
		if (n != 4)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

	        if ((*cb)(src, buffer, 4) < 4)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

		n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
		    buffer[3];

                value->integer = n;
	        break;

	    case IPP_TAG_BOOLEAN :
		if (n != 1)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

	        if ((*cb)(src, buffer, 1) < 1)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

                value->boolean = buffer[0];
	        break;

            case IPP_TAG_NOVALUE :
	    case IPP_TAG_NOTSETTABLE :
	    case IPP_TAG_DELETEATTR :
	    case IPP_TAG_ADMINDEFINE :
	    if (attr->value_tag == tag)
		{
		  if (n == 0)
		    break;

		  attr->value_tag = IPP_TAG_TEXT;
		}

	    case IPP_TAG_TEXT :
	    case IPP_TAG_NAME :
	    case IPP_TAG_KEYWORD :
	    case IPP_TAG_URI :
	    case IPP_TAG_URISCHEME :
	    case IPP_TAG_CHARSET :
	    case IPP_TAG_LANGUAGE :
	    case IPP_TAG_MIMETYPE :
		if (n >= IPP_BUF_SIZE)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

		if ((*cb)(src, buffer, n) < n)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

		buffer[n] = '\0';
		value->string.text = stralloc((char *)buffer);
	        break;

	    case IPP_TAG_DATE :
		if (n != 11)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

	        if ((*cb)(src, value->date, 11) < 11)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}
	        break;

	    case IPP_TAG_RESOLUTION :
		if (n != 9)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

	        if ((*cb)(src, buffer, 9) < 9)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

                value->resolution.xres =
		    (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
		    buffer[3];
                value->resolution.yres =
		    (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
		    buffer[7];
                value->resolution.units =
		    (ipp_res_t)buffer[8];
	        break;

	    case IPP_TAG_RANGE :
		if (n != 8)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

	        if ((*cb)(src, buffer, 8) < 8)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

                value->range.lower =
		    (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
		    buffer[3];
                value->range.upper =
		    (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
		    buffer[7];
	        break;

	    case IPP_TAG_TEXTLANG :
	    case IPP_TAG_NAMELANG :
	        if (n >= IPP_BUF_SIZE || n < 4)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

	        if ((*cb)(src, buffer, n) < n)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

        bufptr = buffer;

		n = (bufptr[0] << 8) | bufptr[1];

		if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) ||
		    n >= sizeof(string))
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

		memcpy(string, bufptr + 2, n);
		string[n] = '\0';

		value->string.charset = stralloc((char *)string);

                bufptr += 2 + n;
		n = (bufptr[0] << 8) | bufptr[1];

		if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE))
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

		bufptr[2 + n] = '\0';
                value->string.text = stralloc((char *)bufptr + 2);
	        break;

            case IPP_TAG_BEGIN_COLLECTION :

            value->collection = ippNew();

                if (n > 0)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

		if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_ERROR)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}
                break;

            case IPP_TAG_END_COLLECTION :
		ipp_buffer_release(buffer);

                if (n > 0)
		{
		  return (IPP_ERROR);
		}
		return (ipp->state = IPP_DATA);

            case IPP_TAG_MEMBERNAME :

		if (n >= IPP_BUF_SIZE)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

	        if ((*cb)(src, buffer, n) < n)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

		buffer[n] = '\0';
		attr->name = stralloc((char *)buffer);

                attr->num_values --;
		break;

            default : 
		if (n > IPP_MAX_LENGTH)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

		if (!value)
		{
		  ipp_buffer_release(buffer);
		  return (IPP_ERROR);
		}

                value->unknown.length = n;
	        if (n > 0)
		{
		  if ((value->unknown.data = malloc(n)) == NULL)
		  {
		    ipp_buffer_release(buffer);
		    return (IPP_ERROR);
		  }

                  if ((*cb)(src,(ipp_uchar_t *)value->unknown.data, n) < n)
		  {
		    ipp_buffer_release(buffer);
		    return (IPP_ERROR);
		  }
		}
		else
		  value->unknown.data = NULL;
	        break;
	  }

          attr->num_values ++;

          if (!blocking)
	    break;
	}
        break;

    case IPP_DATA :
        break;

    default :
        break; 
  }
  ipp_buffer_release(buffer);

  return (ipp->state);
}