ippReadIO(void       *src,		/* I - Data source */
          ipp_iocb_t cb,		/* I - Read callback function */
	  int        blocking,		/* I - Use blocking IO? */
	  ipp_t      *parent,		/* I - Parent request, if any */
          ipp_t      *ipp)		/* I - IPP data */
{
  int			n;		/* Length of data */
  unsigned char		*buffer,	/* Data buffer */
			string[IPP_MAX_TEXT],
					/* Small string buffer */
			*bufptr;	/* Pointer into buffer */
  ipp_attribute_t	*attr;		/* Current attribute */
  ipp_tag_t		tag;		/* Current tag */
  ipp_tag_t		value_tag;	/* Current value tag */
  _ipp_value_t		*value;		/* Current value */


  DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)src, (void *)cb, blocking, (void *)parent, (void *)ipp));
  DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp ? ipp->state : IPP_STATE_ERROR));

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

  if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
  {
    DEBUG_puts("1ippReadIO: Unable to get read buffer.");
    return (IPP_STATE_ERROR);
  }

  switch (ipp->state)
  {
    case IPP_STATE_IDLE :
        ipp->state ++; /* Avoid common problem... */

    case IPP_STATE_HEADER :
        if (parent == NULL)
	{
	 /*
          * Get the request header...
	  */

          if ((*cb)(src, buffer, 8) < 8)
	  {
	    DEBUG_puts("1ippReadIO: Unable to read header.");
	    _cupsBufferRelease((char *)buffer);
	    return (IPP_STATE_ERROR);
	  }

	 /*
          * Then copy the request header over...
	  */

          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];

          DEBUG_printf(("2ippReadIO: version=%d.%d", buffer[0], buffer[1]));
	  DEBUG_printf(("2ippReadIO: op_status=%04x",
	                ipp->request.any.op_status));
	  DEBUG_printf(("2ippReadIO: request_id=%d",
	                ipp->request.any.request_id));
        }

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

       /*
        * If blocking is disabled, stop here...
	*/

        if (!blocking)
	  break;

    case IPP_STATE_ATTRIBUTE :
        for (;;)
	{
	  if ((*cb)(src, buffer, 1) < 1)
	  {
	    DEBUG_puts("1ippReadIO: Callback returned EOF/error");
	    _cupsBufferRelease((char *)buffer);
	    return (IPP_STATE_ERROR);
	  }

	  DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));

	 /*
	  * Read this attribute...
	  */

          tag = (ipp_tag_t)buffer[0];
          if (tag == IPP_TAG_EXTENSION)
          {
           /*
            * Read 32-bit "extension" tag...
            */

	    if ((*cb)(src, buffer, 4) < 1)
	    {
	      DEBUG_puts("1ippReadIO: Callback returned EOF/error");
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
	    }

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

            if (tag & IPP_TAG_CUPS_CONST)
            {
             /*
              * Fail if the high bit is set in the tag...
              */

	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
	      DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag));
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
            }
          }

	  if (tag == IPP_TAG_END)
	  {
	   /*
	    * No more attributes left...
	    */

            DEBUG_puts("2ippReadIO: IPP_TAG_END.");

	    ipp->state = IPP_STATE_DATA;
	    break;
	  }
	  else if (tag == IPP_TAG_ZERO || (tag == IPP_TAG_OPERATION && ipp->curtag != IPP_TAG_ZERO))
	  {
	    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid group tag."), 1);
	    DEBUG_printf(("1ippReadIO: bad tag 0x%02x.", tag));
	    _cupsBufferRelease((char *)buffer);
	    return (IPP_STATE_ERROR);
	  }
          else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
	  {
	   /*
	    * Group tag...  Set the current group and continue...
	    */

            if (ipp->curtag == tag)
	      ipp->prev = ippAddSeparator(ipp);
            else if (ipp->current)
	      ipp->prev = ipp->current;

	    ipp->curtag  = tag;
	    ipp->current = NULL;
	    DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag, ippTagString(tag), (void *)ipp->prev));
	    continue;
	  }

          DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag,
	                ippTagString(tag)));

         /*
	  * Get the name...
	  */

          if ((*cb)(src, buffer, 2) < 2)
	  {
	    DEBUG_puts("1ippReadIO: unable to read name length.");
	    _cupsBufferRelease((char *)buffer);
	    return (IPP_STATE_ERROR);
	  }

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

          if (n >= IPP_BUF_SIZE)
	  {
	    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP name larger than 32767 bytes."), 1);
	    DEBUG_printf(("1ippReadIO: bad name length %d.", n));
	    _cupsBufferRelease((char *)buffer);
	    return (IPP_STATE_ERROR);
	  }

          DEBUG_printf(("2ippReadIO: name length=%d", n));

          if (n && parent)
          {
            _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid named IPP attribute in collection."), 1);
            DEBUG_puts("1ippReadIO: bad attribute name in collection.");
            return (IPP_STATE_ERROR);
          }
          else if (n == 0 && tag != IPP_TAG_MEMBERNAME && tag != IPP_TAG_END_COLLECTION)
	  {
	   /*
	    * More values for current attribute...
	    */

            if (ipp->current == NULL)
	    {
	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute has no name."), 1);
	      DEBUG_puts("1ippReadIO: Attribute without name and no current.");
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
	    }

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

	   /*
	    * Make sure we aren't adding a new value of a different
	    * type...
	    */

	    if (value_tag == IPP_TAG_ZERO)
	    {
	     /*
	      * Setting the value of a collection member...
	      */

	      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))
            {
	     /*
	      * String values can sometimes come across in different
	      * forms; accept sets of differing values...
	      */

	      if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG &&
	          (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) &&
		  tag != IPP_TAG_NOVALUE)
	      {
		_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		              _("IPP 1setOf attribute with incompatible value "
		                "tags."), 1);
		DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
			      value_tag, ippTagString(value_tag), tag,
			      ippTagString(tag)));
		_cupsBufferRelease((char *)buffer);
	        return (IPP_STATE_ERROR);
	      }

              if (value_tag != tag)
              {
                DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
                              attr->name, ippTagString(value_tag), ippTagString(tag)));
		ippSetValueTag(ipp, &attr, tag);
	      }
            }
	    else if (value_tag == IPP_TAG_INTEGER ||
	             value_tag == IPP_TAG_RANGE)
            {
	     /*
	      * Integer and rangeOfInteger values can sometimes be mixed; accept
	      * sets of differing values...
	      */

	      if (tag != IPP_TAG_INTEGER && tag != IPP_TAG_RANGE)
	      {
		_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		              _("IPP 1setOf attribute with incompatible value "
		                "tags."), 1);
		DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
			      value_tag, ippTagString(value_tag), tag,
			      ippTagString(tag)));
		_cupsBufferRelease((char *)buffer);
	        return (IPP_STATE_ERROR);
	      }

              if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE)
              {
               /*
                * Convert integer values to rangeOfInteger values...
                */

		DEBUG_printf(("1ippReadIO: Converting %s attribute to "
		              "rangeOfInteger.", attr->name));
                ippSetValueTag(ipp, &attr, IPP_TAG_RANGE);
              }
            }
	    else if (value_tag != tag)
	    {
	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
			    _("IPP 1setOf attribute with incompatible value "
			      "tags."), 1);
	      DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
	                    value_tag, ippTagString(value_tag), tag,
			    ippTagString(tag)));
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
            }

           /*
	    * Finally, reallocate the attribute array as needed...
	    */

	    if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL)
	    {
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
	    }
	  }
	  else if (tag == IPP_TAG_MEMBERNAME)
	  {
	   /*
	    * Name must be length 0!
	    */

	    if (n)
	    {
	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member name is not empty."), 1);
	      DEBUG_puts("1ippReadIO: member name not empty.");
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
	    }

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

	    attr = ipp->current = ipp_add_attr(ipp, NULL, ipp->curtag, IPP_TAG_ZERO, 1);
	    if (!attr)
	    {
	      _cupsSetHTTPError(HTTP_STATUS_ERROR);
	      DEBUG_puts("1ippReadIO: unable to allocate attribute.");
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
	    }

	    DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));

	    value = attr->values;
	  }
	  else if (tag != IPP_TAG_END_COLLECTION)
	  {
	   /*
	    * New attribute; read the name and add it...
	    */

	    if ((*cb)(src, buffer, (size_t)n) < n)
	    {
	      DEBUG_puts("1ippReadIO: unable to read name.");
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
	    }

	    buffer[n] = '\0';

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

	    if ((attr = ipp->current = ipp_add_attr(ipp, (char *)buffer, ipp->curtag, tag,
	                                            1)) == NULL)
	    {
	      _cupsSetHTTPError(HTTP_STATUS_ERROR);
	      DEBUG_puts("1ippReadIO: unable to allocate attribute.");
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
	    }

	    DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, ipp->prev=%p", buffer, (void *)ipp->current, (void *)ipp->prev));

	    value = attr->values;
	  }
	  else
	  {
	    attr  = NULL;
	    value = NULL;
	  }

	  if ((*cb)(src, buffer, 2) < 2)
	  {
	    DEBUG_puts("1ippReadIO: unable to read value length.");
	    _cupsBufferRelease((char *)buffer);
	    return (IPP_STATE_ERROR);
	  }

	  n = (buffer[0] << 8) | buffer[1];
          DEBUG_printf(("2ippReadIO: value length=%d", n));

	  if (n >= IPP_BUF_SIZE)
	  {
	    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
			  _("IPP value larger than 32767 bytes."), 1);
	    DEBUG_printf(("1ippReadIO: bad value length %d.", n));
	    _cupsBufferRelease((char *)buffer);
	    return (IPP_STATE_ERROR);
	  }

	  switch (tag)
	  {
	    case IPP_TAG_INTEGER :
	    case IPP_TAG_ENUM :
		if (n != 4)
		{
		  if (tag == IPP_TAG_INTEGER)
		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
				  _("IPP integer value not 4 bytes."), 1);
		  else
		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
				  _("IPP enum value not 4 bytes."), 1);
		  DEBUG_printf(("1ippReadIO: bad integer value length %d.", n));
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

	        if ((*cb)(src, buffer, 4) < 4)
		{
	          DEBUG_puts("1ippReadIO: Unable to read integer value.");
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

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

                if (attr->value_tag == IPP_TAG_RANGE)
                  value->range.lower = value->range.upper = n;
                else
		  value->integer = n;
	        break;

	    case IPP_TAG_BOOLEAN :
		if (n != 1)
		{
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP boolean value not 1 byte."),
		                1);
		  DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n));
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

	        if ((*cb)(src, buffer, 1) < 1)
		{
	          DEBUG_puts("1ippReadIO: Unable to read boolean value.");
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

                value->boolean = (char)buffer[0];
	        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 :
	       /*
	        * These value types are not supposed to have values, however
		* some vendors (Brother) do not implement IPP correctly and so
		* we need to map non-empty values to text...
		*/

	        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_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 :
	        if (n > 0)
	        {
		  if ((*cb)(src, buffer, (size_t)n) < n)
		  {
		    DEBUG_puts("1ippReadIO: unable to read string value.");
		    _cupsBufferRelease((char *)buffer);
		    return (IPP_STATE_ERROR);
		  }
		}

		buffer[n] = '\0';
		value->string.text = _cupsStrAlloc((char *)buffer);
		DEBUG_printf(("2ippReadIO: value=\"%s\"", value->string.text));
	        break;

	    case IPP_TAG_DATE :
		if (n != 11)
		{
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP date value not 11 bytes."), 1);
		  DEBUG_printf(("1ippReadIO: bad date value length %d.", n));
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

	        if ((*cb)(src, value->date, 11) < 11)
		{
	          DEBUG_puts("1ippReadIO: Unable to read date value.");
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}
	        break;

	    case IPP_TAG_RESOLUTION :
		if (n != 9)
		{
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                _("IPP resolution value not 9 bytes."), 1);
		  DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n));
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

	        if ((*cb)(src, buffer, 9) < 9)
		{
	          DEBUG_puts("1ippReadIO: Unable to read resolution value.");
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_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)
		{
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                _("IPP rangeOfInteger value not 8 bytes."), 1);
		  DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
		                "%d.", n));
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

	        if ((*cb)(src, buffer, 8) < 8)
		{
	          DEBUG_puts("1ippReadIO: Unable to read range value.");
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_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 < 4)
		{
		  if (tag == IPP_TAG_TEXTLANG)
		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                  _("IPP textWithLanguage value less than "
		                    "minimum 4 bytes."), 1);
		  else
		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                  _("IPP nameWithLanguage value less than "
		                    "minimum 4 bytes."), 1);
		  DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
		                "length %d.", n));
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

	        if ((*cb)(src, buffer, (size_t)n) < n)
		{
	          DEBUG_puts("1ippReadIO: Unable to read string w/language "
		             "value.");
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

                bufptr = buffer;

	       /*
	        * text-with-language and name-with-language are composite
		* values:
		*
		*    language-length
		*    language
		*    text-length
		*    text
		*/

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

		if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) || n >= (int)sizeof(string))
		{
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                _("IPP language length overflows value."), 1);
		  DEBUG_printf(("1ippReadIO: bad language value length %d.",
		                n));
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}
		else if (n >= IPP_MAX_LANGUAGE)
		{
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                _("IPP language length too large."), 1);
		  DEBUG_printf(("1ippReadIO: bad language value length %d.",
		                n));
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

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

		value->string.language = _cupsStrAlloc((char *)string);

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

		if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE))
		{
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                _("IPP string length overflows value."), 1);
		  DEBUG_printf(("1ippReadIO: bad string value length %d.", n));
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

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

            case IPP_TAG_BEGIN_COLLECTION :
	       /*
	        * Oh, boy, here comes a collection value, so read it...
		*/

                value->collection = ippNew();

                if (n > 0)
		{
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                _("IPP begCollection value not 0 bytes."), 1);
	          DEBUG_puts("1ippReadIO: begCollection tag with value length "
		             "> 0.");
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

		if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_STATE_ERROR)
		{
	          DEBUG_puts("1ippReadIO: Unable to read collection value.");
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}
                break;

            case IPP_TAG_END_COLLECTION :
		_cupsBufferRelease((char *)buffer);

                if (n > 0)
		{
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                _("IPP endCollection value not 0 bytes."), 1);
	          DEBUG_puts("1ippReadIO: endCollection tag with value length "
		             "> 0.");
		  return (IPP_STATE_ERROR);
		}

	        DEBUG_puts("1ippReadIO: endCollection tag...");
		return (ipp->state = IPP_STATE_DATA);

            case IPP_TAG_MEMBERNAME :
	       /*
	        * The value the name of the member in the collection, which
		* we need to carry over...
		*/

                if (!attr)
                {
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                _("IPP memberName with no attribute."), 1);
	          DEBUG_puts("1ippReadIO: Member name without attribute.");
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
                }
		else if (n == 0)
		{
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                _("IPP memberName value is empty."), 1);
	          DEBUG_puts("1ippReadIO: Empty member name value.");
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}
		else if ((*cb)(src, buffer, (size_t)n) < n)
		{
	          DEBUG_puts("1ippReadIO: Unable to read member name value.");
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

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

               /*
	        * Since collection members are encoded differently than
		* regular attributes, make sure we don't start with an
		* empty value...
		*/

                attr->num_values --;

		DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr->name));
		break;

            default : /* Other unsupported values */
                if (tag == IPP_TAG_STRING && n > IPP_MAX_LENGTH)
		{
		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
		                _("IPP octetString length too large."), 1);
		  DEBUG_printf(("1ippReadIO: bad octetString value length %d.",
		                n));
		  _cupsBufferRelease((char *)buffer);
		  return (IPP_STATE_ERROR);
		}

                value->unknown.length = n;

	        if (n > 0)
		{
		  if ((value->unknown.data = malloc((size_t)n)) == NULL)
		  {
		    _cupsSetHTTPError(HTTP_STATUS_ERROR);
		    DEBUG_puts("1ippReadIO: Unable to allocate value");
		    _cupsBufferRelease((char *)buffer);
		    return (IPP_STATE_ERROR);
		  }

	          if ((*cb)(src, value->unknown.data, (size_t)n) < n)
		  {
	            DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
		    _cupsBufferRelease((char *)buffer);
		    return (IPP_STATE_ERROR);
		  }
		}
		else
		  value->unknown.data = NULL;
	        break;
	  }

	 /*
          * If blocking is disabled, stop here...
	  */

          if (!blocking)
	    break;
	}
        break;

    case IPP_STATE_DATA :
        break;

    default :
        break; /* anti-compiler-warning-code */
  }

  DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp->state));
  _cupsBufferRelease((char *)buffer);

  return (ipp->state);
}