📄 name.java
字号:
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)package org.xbill.DNS;import java.io.*;import java.text.*;/** * A representation of a domain name. It may either be absolute (fully * qualified) or relative. * * @author Brian Wellington */public class Name implements Comparable {private static final int LABEL_NORMAL = 0;private static final int LABEL_COMPRESSION = 0xC0;private static final int LABEL_MASK = 0xC0;/* The name data */private byte [] name;/* * Effectively an 8 byte array, where the low order byte stores the number * of labels and the 7 higher order bytes store per-label offsets. */private long offsets;/* Precomputed hashcode. */private int hashcode;private static final byte [] emptyLabel = new byte[] {(byte)0};private static final byte [] wildLabel = new byte[] {(byte)1, (byte)'*'};/** The root name */public static final Name root;/** The root name */public static final Name empty;/** The maximum length of a Name */private static final int MAXNAME = 255;/** The maximum length of a label a Name */private static final int MAXLABEL = 63;/** The maximum number of labels in a Name */private static final int MAXLABELS = 128;/** The maximum number of cached offsets */private static final int MAXOFFSETS = 7;/* Used for printing non-printable characters */private static final DecimalFormat byteFormat = new DecimalFormat();/* Used to efficiently convert bytes to lowercase */private static final byte lowercase[] = new byte[256];/* Used in wildcard names. */private static final Name wild;static { byteFormat.setMinimumIntegerDigits(3); for (int i = 0; i < lowercase.length; i++) { if (i < 'A' || i > 'Z') lowercase[i] = (byte)i; else lowercase[i] = (byte)(i - 'A' + 'a'); } root = new Name(); root.appendSafe(emptyLabel, 0, 1); empty = new Name(); empty.name = new byte[0]; wild = new Name(); wild.appendSafe(wildLabel, 0, 1);}privateName() {}private final voiddump(String prefix) { String s; try { s = toString(); } catch (Exception e) { s = "<unprintable>"; } System.out.println(prefix + ": " + s); int labels = labels(); for (int i = 0; i < labels; i++) System.out.print(offset(i) + " "); System.out.println(""); for (int i = 0; name != null && i < name.length; i++) System.out.print((name[i] & 0xFF) + " "); System.out.println("");}private final voidsetoffset(int n, int offset) { if (n >= MAXOFFSETS) return; int shift = 8 * (7 - n); offsets &= (~(0xFFL << shift)); offsets |= ((long)offset << shift);}private final intoffset(int n) { if (n == 0 && getlabels() == 0) return 0; if (n < 0 || n >= getlabels()) throw new IllegalArgumentException("label out of range"); if (n < MAXOFFSETS) { int shift = 8 * (7 - n); return ((int)(offsets >>> shift) & 0xFF); } else { int pos = offset(MAXOFFSETS - 1); for (int i = MAXOFFSETS - 1; i < n; i++) pos += (name[pos] + 1); return (pos); }}private final voidsetlabels(int labels) { offsets &= ~(0xFF); offsets |= labels;}private final intgetlabels() { return (int)(offsets & 0xFF);}private static final voidcopy(Name src, Name dst) { if (src.offset(0) == 0) { dst.name = src.name; dst.offsets = src.offsets; } else { int offset0 = src.offset(0); int namelen = src.name.length - offset0; int labels = src.labels(); dst.name = new byte[namelen]; System.arraycopy(src.name, offset0, dst.name, 0, namelen); for (int i = 0; i < labels && i < MAXOFFSETS; i++) dst.setoffset(i, src.offset(i) - offset0); dst.setlabels(labels); }}private final voidappend(byte [] array, int start, int n) throws NameTooLongException { int length = (name == null ? 0 : (name.length - offset(0))); int alength = 0; for (int i = 0, pos = start; i < n; i++) { int len = array[pos]; if (len > MAXLABEL) throw new IllegalStateException("invalid label"); len++; pos += len; alength += len; } int newlength = length + alength; if (newlength > MAXNAME) throw new NameTooLongException(); int labels = getlabels(); int newlabels = labels + n; if (newlabels > MAXLABELS) throw new IllegalStateException("too many labels"); byte [] newname = new byte[newlength]; if (length != 0) System.arraycopy(name, offset(0), newname, 0, length); System.arraycopy(array, start, newname, length, alength); name = newname; for (int i = 0, pos = length; i < n; i++) { setoffset(labels + i, pos); pos += (newname[pos] + 1); } setlabels(newlabels);}private static TextParseExceptionparseException(String str, String message) { return new TextParseException("'" + str + "': " + message);}private final voidappendFromString(String fullName, byte [] array, int start, int n)throws TextParseException{ try { append(array, start, n); } catch (NameTooLongException e) { throw parseException(fullName, "Name too long"); }}private final voidappendSafe(byte [] array, int start, int n) { try { append(array, start, n); } catch (NameTooLongException e) { }}/** * Create a new name from a string and an origin. This does not automatically * make the name absolute; it will be absolute if it has a trailing dot or an * absolute origin is appended. * @param s The string to be converted * @param origin If the name is not absolute, the origin to be appended. * @throws TextParseException The name is invalid. */publicName(String s, Name origin) throws TextParseException { if (s.equals("")) throw parseException(s, "empty name"); else if (s.equals("@")) { if (origin == null) copy(empty, this); else copy(origin, this); return; } else if (s.equals(".")) { copy(root, this); return; } int labelstart = -1; int pos = 1; byte [] label = new byte[MAXLABEL + 1]; boolean escaped = false; int digits = 0; int intval = 0; boolean absolute = false; for (int i = 0; i < s.length(); i++) { byte b = (byte) s.charAt(i); if (escaped) { if (b >= '0' && b <= '9' && digits < 3) { digits++; intval *= 10; intval += (b - '0'); if (intval > 255) throw parseException(s, "bad escape"); if (digits < 3) continue; b = (byte) intval; } else if (digits > 0 && digits < 3) throw parseException(s, "bad escape"); if (pos > MAXLABEL) throw parseException(s, "label too long"); labelstart = pos; label[pos++] = b; escaped = false; } else if (b == '\\') { escaped = true; digits = 0; intval = 0; } else if (b == '.') { if (labelstart == -1) throw parseException(s, "invalid empty label"); label[0] = (byte)(pos - 1); appendFromString(s, label, 0, 1); labelstart = -1; pos = 1; } else { if (labelstart == -1) labelstart = i; if (pos > MAXLABEL) throw parseException(s, "label too long"); label[pos++] = b; } } if (digits > 0 && digits < 3) throw parseException(s, "bad escape"); if (escaped) throw parseException(s, "bad escape"); if (labelstart == -1) { appendFromString(s, emptyLabel, 0, 1); absolute = true; } else { label[0] = (byte)(pos - 1); appendFromString(s, label, 0, 1); } if (origin != null && !absolute) appendFromString(s, origin.name, 0, origin.getlabels());}/** * Create a new name from a string. This does not automatically make the name * absolute; it will be absolute if it has a trailing dot. * @param s The string to be converted * @throws TextParseException The name is invalid. */publicName(String s) throws TextParseException { this(s, null);}/** * Create a new name from a string and an origin. This does not automatically * make the name absolute; it will be absolute if it has a trailing dot or an * absolute origin is appended. This is identical to the constructor, except * that it will avoid creating new objects in some cases. * @param s The string to be converted * @param origin If the name is not absolute, the origin to be appended. * @throws TextParseException The name is invalid. */public static NamefromString(String s, Name origin) throws TextParseException { if (s.equals("@") && origin != null) return origin; else if (s.equals(".")) return (root); return new Name(s, origin);}/** * Create a new name from a string. This does not automatically make the name * absolute; it will be absolute if it has a trailing dot. This is identical * to the constructor, except that it will avoid creating new objects in some * cases. * @param s The string to be converted * @throws TextParseException The name is invalid. */public static NamefromString(String s) throws TextParseException { return fromString(s, null);}/** * Create a new name from a constant string. This should only be used when the name is known to be good - that is, when it is constant. * @param s The string to be converted * @throws IllegalArgumentException The name is invalid. */public static NamefromConstantString(String s) { try { return fromString(s, null); } catch (TextParseException e) { throw new IllegalArgumentException("Invalid name '" + s + "'"); }}/** * Create a new name from DNS a wire format message * @param in A stream containing the DNS message which is currently * positioned at the start of the name to be read. */publicName(DNSInput in) throws WireParseException { int len, pos, currentpos; Name name2; boolean done = false; byte [] label = new byte[MAXLABEL + 1]; boolean savedState = false; while (!done) { len = in.readU8(); switch (len & LABEL_MASK) { case LABEL_NORMAL: if (getlabels() >= MAXLABELS) throw new WireParseException("too many labels"); if (len == 0) { append(emptyLabel, 0, 1); done = true; } else { label[0] = (byte)len; in.readByteArray(label, 1, len); append(label, 0, 1); } break; case LABEL_COMPRESSION: pos = in.readU8(); pos += ((len & ~LABEL_MASK) << 8); if (Options.check("verbosecompression")) System.err.println("currently " + in.current() + ", pointer to " + pos); if (pos >= in.current() - 2) throw new WireParseException("bad compression"); if (!savedState) { in.save(); savedState = true; } in.jump(pos); if (Options.check("verbosecompression")) System.err.println("current name '" + this + "', seeking to " + pos); break; default: throw new WireParseException("bad label type"); } } if (savedState) { in.restore(); }}/** * Create a new name from DNS wire format * @param b A byte array containing the wire format of the name. */publicName(byte [] b) throws IOException { this(new DNSInput(b));}/** * Create a new name by removing labels from the beginning of an existing Name
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -