asn1_debug(const char    *prefix,	/* I - Prefix string */
           unsigned char *buffer,	/* I - Buffer */
           size_t        len,		/* I - Length of buffer */
           int           indent)	/* I - Indentation */
{
  size_t	i;			/* Looping var */
  unsigned char	*bufend;		/* End of buffer */
  int		integer;		/* Number value */
  int		oid[CUPS_SNMP_MAX_OID];	/* OID value */
  char		string[CUPS_SNMP_MAX_STRING];
					/* String value */
  unsigned char	value_type;		/* Type of value */
  unsigned	value_length;		/* Length of value */
  _cups_globals_t *cg = _cupsGlobals();	/* Global data */


#ifdef __clang_analyzer__ /* Suppress bogus clang error */
  memset(string, 0, sizeof(string));
#endif /* __clang_analyzer__ */

  if (cg->snmp_debug <= 0)
    return;

  if (cg->snmp_debug > 1 && indent == 0)
  {
   /*
    * Do a hex dump of the packet...
    */

    size_t j;

    fprintf(stderr, "%sHex Dump (%d bytes):\n", prefix, (int)len);

    for (i = 0; i < len; i += 16)
    {
      fprintf(stderr, "%s%04x:", prefix, (unsigned)i);

      for (j = 0; j < 16 && (i + j) < len; j ++)
      {
        if (j && !(j & 3))
	  fprintf(stderr, "  %02x", buffer[i + j]);
        else
	  fprintf(stderr, " %02x", buffer[i + j]);
      }

      while (j < 16)
      {
        if (j && !(j & 3))
	  fputs("    ", stderr);
	else
	  fputs("   ", stderr);

        j ++;
      }

      fputs("    ", stderr);

      for (j = 0; j < 16 && (i + j) < len; j ++)
        if (buffer[i + j] < ' ' || buffer[i + j] >= 0x7f)
	  putc('.', stderr);
	else
	  putc(buffer[i + j], stderr);

      putc('\n', stderr);
    }
  }

  if (indent == 0)
    fprintf(stderr, "%sMessage:\n", prefix);

  bufend = buffer + len;

  while (buffer < bufend)
  {
   /*
    * Get value type...
    */

    value_type   = (unsigned char)asn1_get_type(&buffer, bufend);
    value_length = asn1_get_length(&buffer, bufend);

    switch (value_type)
    {
      case CUPS_ASN1_BOOLEAN :
          integer = asn1_get_integer(&buffer, bufend, value_length);

          fprintf(stderr, "%s%*sBOOLEAN %d bytes %d\n", prefix, indent, "",
	          value_length, integer);
          break;

      case CUPS_ASN1_INTEGER :
          integer = asn1_get_integer(&buffer, bufend, value_length);

          fprintf(stderr, "%s%*sINTEGER %d bytes %d\n", prefix, indent, "",
	          value_length, integer);
          break;

      case CUPS_ASN1_COUNTER :
          integer = asn1_get_integer(&buffer, bufend, value_length);

          fprintf(stderr, "%s%*sCOUNTER %d bytes %u\n", prefix, indent, "",
	          value_length, (unsigned)integer);
          break;

      case CUPS_ASN1_GAUGE :
          integer = asn1_get_integer(&buffer, bufend, value_length);

          fprintf(stderr, "%s%*sGAUGE %d bytes %u\n", prefix, indent, "",
	          value_length, (unsigned)integer);
          break;

      case CUPS_ASN1_TIMETICKS :
          integer = asn1_get_integer(&buffer, bufend, value_length);

          fprintf(stderr, "%s%*sTIMETICKS %d bytes %u\n", prefix, indent, "",
	          value_length, (unsigned)integer);
          break;

      case CUPS_ASN1_OCTET_STRING :
          fprintf(stderr, "%s%*sOCTET STRING %d bytes \"%s\"\n", prefix,
	          indent, "", value_length,
		  asn1_get_string(&buffer, bufend, value_length, string,
				  sizeof(string)));
          break;

      case CUPS_ASN1_HEX_STRING :
	  asn1_get_string(&buffer, bufend, value_length, string,
			  sizeof(string));
          fprintf(stderr, "%s%*sHex-STRING %d bytes", prefix,
	          indent, "", value_length);
          for (i = 0; i < value_length; i ++)
	    fprintf(stderr, " %02X", string[i] & 255);
	  putc('\n', stderr);
          break;

      case CUPS_ASN1_NULL_VALUE :
          fprintf(stderr, "%s%*sNULL VALUE %d bytes\n", prefix, indent, "",
	          value_length);

	  buffer += value_length;
          break;

      case CUPS_ASN1_OID :
          integer = asn1_get_oid(&buffer, bufend, value_length, oid,
	                         CUPS_SNMP_MAX_OID);

          fprintf(stderr, "%s%*sOID %d bytes ", prefix, indent, "",
	          value_length);
	  for (i = 0; i < (unsigned)integer; i ++)
	    fprintf(stderr, ".%d", oid[i]);
	  putc('\n', stderr);
          break;

      case CUPS_ASN1_SEQUENCE :
          fprintf(stderr, "%s%*sSEQUENCE %d bytes\n", prefix, indent, "",
	          value_length);
          asn1_debug(prefix, buffer, value_length, indent + 4);

	  buffer += value_length;
          break;

      case CUPS_ASN1_GET_NEXT_REQUEST :
          fprintf(stderr, "%s%*sGet-Next-Request-PDU %d bytes\n", prefix,
	          indent, "", value_length);
          asn1_debug(prefix, buffer, value_length, indent + 4);

	  buffer += value_length;
          break;

      case CUPS_ASN1_GET_REQUEST :
          fprintf(stderr, "%s%*sGet-Request-PDU %d bytes\n", prefix, indent, "",
	          value_length);
          asn1_debug(prefix, buffer, value_length, indent + 4);

	  buffer += value_length;
          break;

      case CUPS_ASN1_GET_RESPONSE :
          fprintf(stderr, "%s%*sGet-Response-PDU %d bytes\n", prefix, indent,
	          "", value_length);
          asn1_debug(prefix, buffer, value_length, indent + 4);

	  buffer += value_length;
          break;

      default :
          fprintf(stderr, "%s%*sUNKNOWN(%x) %d bytes\n", prefix, indent, "",
	          value_type, value_length);

	  buffer += value_length;
          break;
    }
  }
}