text: /*
   * dname.h -- Domain name handling.
   *
   * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
   *
   * See LICENSE for the license.
   *
   */
  
  #ifndef _DNAME_H_
  #define _DNAME_H_
  
  #include <assert.h>
  #include <stdio.h>
  
  #include "buffer.h"
  #include "region-allocator.h"
  
  #if defined(NAMEDB_UPPERCASE) || defined(USE_NAMEDB_UPPERCASE)
  #define DNAME_NORMALIZE        toupper
  #else
  #define DNAME_NORMALIZE        tolower
  #endif
  
  
  /*
   * Domain names stored in memory add some additional information to be
   * able to quickly index and compare by label.
   */
  typedef struct dname dname_type;
  struct dname
  {
  	/*
  	 * The size (in bytes) of the domain name in wire format.
  	 */
  	uint8_t name_size;
  
  	/*
  	 * The number of labels in this domain name (including the
  	 * root label).
  	 */
  	uint8_t label_count;
  
  	/*
  	  uint8_t label_offsets[label_count];
  	  uint8_t name[name_size];
  	*/
  };
  
  
  /*
   * Construct a new domain name based on NAME in wire format.  NAME
   * cannot contain compression pointers.
   *
   * Pre: NAME != NULL.
   */
  const dname_type *dname_make(region_type *region, const uint8_t *name,
  			     int normalize);
  
  /*
   * Construct a new domain name based on wire format dname stored at
   * PACKET's current position.  Compression pointers are followed.  The
   * PACKET's current position is changed to the end of the wire format
   * dname or set to just after the first compression pointer.
   */
  const dname_type *dname_make_from_packet(region_type *region,
  					 buffer_type *packet,
  					 int allow_pointers,
  					 int normalize);
  
  /*
   * parse wireformat from packet (following pointers) into the
   * given buffer. Returns length in buffer or 0 on error.
   * buffer must be MAXDOMAINLEN+1 long.
   */
  int dname_make_wire_from_packet(uint8_t *buf,
  				buffer_type *packet,
  				int allow_pointers);
  
  /*
   * Construct a new domain name based on the ASCII representation NAME.
   * If ORIGIN is not NULL and NAME is not terminated by a "." the
   * ORIGIN is appended to the result.  NAME can contain escape
   * sequences.
   *
   * Returns NULL on failure.  Otherwise a newly allocated domain name
   * is returned.
   *
   * Pre: name != NULL.
   */
  const dname_type *dname_parse(region_type *region, const char *name);
  
  /*
   * parse ascii string to wireformat domain name (without compression ptrs)
   * returns 0 on failure, the length of the wireformat on success.
   * the result is stored in the wirefmt which must be at least MAXDOMAINLEN
   * in size. On failure, the wirefmt can be altered.
   */
  int dname_parse_wire(uint8_t* wirefmt, const char* name);
  
  /*
   * Return NULL if DNAME is NULL or a copy of DNAME otherwise.
   */
  const dname_type *dname_copy(region_type *region, const dname_type *dname);
  
  
  /*
   * Copy the most significant LABEL_COUNT labels from dname.
   */
  const dname_type *dname_partial_copy(region_type *region,
  				     const dname_type *dname,
  				     uint8_t label_count);
  
  
  /*
   * The origin of DNAME.
   */
  const dname_type *dname_origin(region_type *region, const dname_type *dname);
  
  /*
   * Return true if LEFT is a subdomain of RIGHT.
   */
  int dname_is_subdomain(const dname_type *left, const dname_type *right);
  
  
  /*
   * Offsets into NAME for each label starting with the most
   * significant label (the root label, followed by the TLD,
   * etc).
   */
  static inline const uint8_t *
  dname_label_offsets(const dname_type *dname)
  {
  	return (const uint8_t *) ((const char *) dname + sizeof(dname_type));
  }
  
  
  /*
   * The actual name in wire format (a sequence of label, each
   * prefixed by a length byte, terminated by a zero length
   * label).
   */
  static inline const uint8_t *
  dname_name(const dname_type *dname)
  {
  	return (const uint8_t *) ((const char *) dname
  				  + sizeof(dname_type)
  				  + dname->label_count * sizeof(uint8_t));
  }
  
  
  /*
   * Return the label for DNAME specified by LABEL_INDEX.  The first
   * label (LABEL_INDEX == 0) is the root label, the next label is the
   * TLD, etc.
   *
   * Pre: dname != NULL && label_index < dname->label_count.
   */
  static inline const uint8_t *
  dname_label(const dname_type *dname, uint8_t label)
  {
  	uint8_t label_index;
  
  	assert(dname != NULL);
  	assert(label < dname->label_count);
  
  	label_index = dname_label_offsets(dname)[label];
  	assert(label_index < dname->name_size);
  
  	return dname_name(dname) + label_index;
  }
  
  
  /*
   * Compare two domain names.  The comparison defines a lexographical
   * ordering based on the domain name's labels, starting with the most
   * significant label.
   *
   * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT >
   * RIGHT.  The comparison is case sensitive.
   *
   * Pre: left != NULL && right != NULL
   */
  int dname_compare(const dname_type *left, const dname_type *right);
  
  
  /*
   * Compare two labels.  The comparison defines a lexographical
   * ordering based on the characters in the labels.
   *
   * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT >
   * RIGHT.  The comparison is case sensitive.
   *
   * Pre: left != NULL && right != NULL
   *      label_is_normal(left) && label_is_normal(right)
   */
  int label_compare(const uint8_t *left, const uint8_t *right);
  
  
  /*
   * Returns the number of labels that match in LEFT and RIGHT, starting
   * with the most significant label.  Because the root label always
   * matches, the result will always be >= 1.
   *
   * Pre: left != NULL && right != NULL
   */
  uint8_t dname_label_match_count(const dname_type *left,
  				const dname_type *right);
  
  
  /*
   * The total size (in bytes) allocated to store DNAME.
   *
   * Pre: dname != NULL
   */
  static inline size_t
  dname_total_size(const dname_type *dname)
  {
  	return (sizeof(dname_type)
  		+ ((((size_t)dname->label_count) + ((size_t)dname->name_size))
  		   * sizeof(uint8_t)));
  }
  
  
  /*
   * Is LABEL a normal LABEL (not a pointer or reserved)?
   *
   * Pre: label != NULL;
   */
  static inline int
  label_is_normal(const uint8_t *label)
  {
  	assert(label);
  	return (label[0] & 0xc0) == 0;
  }
  
  
  /*
   * Is LABEL a pointer?
   *
   * Pre: label != NULL;
   */
  static inline int
  label_is_pointer(const uint8_t *label)
  {
  	assert(label);
  	return (label[0] & 0xc0) == 0xc0;
  }
  
  
  /*
   * LABEL's pointer location.
   *
   * Pre: label != NULL && label_is_pointer(label)
   */
  static inline uint16_t
  label_pointer_location(const uint8_t *label)
  {
  	assert(label);
  	assert(label_is_pointer(label));
  	return ((uint16_t) (label[0] & ~0xc0) << 8) | (uint16_t) label[1];
  }
  
  
  /*
   * Length of LABEL.
   *
   * Pre: label != NULL && label_is_normal(label)
   */
  static inline uint8_t
  label_length(const uint8_t *label)
  {
  	assert(label);
  	assert(label_is_normal(label));
  	return label[0];
  }
  
  
  /*
   * The data of LABEL.
   *
   * Pre: label != NULL && label_is_normal(label)
   */
  static inline const uint8_t *
  label_data(const uint8_t *label)
  {
  	assert(label);
  	assert(label_is_normal(label));
  	return label + 1;
  }
  
  
  /*
   * Is LABEL the root label?
   *
   * Pre: label != NULL
   */
  static inline int
  label_is_root(const uint8_t *label)
  {
  	assert(label);
  	return label[0] == 0;
  }
  
  
  /*
   * Is LABEL the wildcard label?
   *
   * Pre: label != NULL
   */
  static inline int
  label_is_wildcard(const uint8_t *label)
  {
  	assert(label);
  	return label[0] == 1 && label[1] == '*';
  }
  
  
  /*
   * The next label of LABEL.
   *
   * Pre: label != NULL
   *      label_is_normal(label)
   *      !label_is_root(label)
   */
  static inline const uint8_t *
  label_next(const uint8_t *label)
  {
  	assert(label);
  	assert(label_is_normal(label));
  	assert(!label_is_root(label));
  	return label + label_length(label) + 1;
  }
  
  
  /*
   * Convert DNAME to its string representation.  The result points to a
   * static buffer that is overwritten the next time this function is
   * invoked.
   *
   * If ORIGIN is provided and DNAME is a subdomain of ORIGIN the dname
   * will be represented relative to ORIGIN.
   *
   * Pre: dname != NULL
   */
  const char *dname_to_string(const dname_type *dname,
  			    const dname_type *origin);
  
  
  /*
   * Create a dname containing the single label specified by STR
   * followed by the root label.
   */
  const dname_type *dname_make_from_label(region_type *region,
  					const uint8_t *label,
  					const size_t length);
  
  
  /*
   * Concatenate two dnames.
   */
  const dname_type *dname_concatenate(region_type *region,
  				    const dname_type *left,
  				    const dname_type *right);
  
  
  /*
   * Perform DNAME substitution on a name, replace src with dest.
   * Name must be a subdomain of src. The returned name is a subdomain of dest.
   * Returns NULL if the result domain name is too long.
   */
  const dname_type *dname_replace(region_type* region,
  				const dname_type* name,
  				const dname_type* src,
  				const dname_type* dest);
  
  /** Convert uncompressed wireformat dname to a string */
  char* wiredname2str(const uint8_t* dname);
  /** convert uncompressed label to string */
  char* wirelabel2str(const uint8_t* label);
  /** check if two uncompressed dnames of the same total length are equal */
  int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len);
  
  #endif /* _DNAME_H_ */
  