diff options
Diffstat (limited to 'src/org/xbill/DNS/Generator.java')
-rw-r--r-- | src/org/xbill/DNS/Generator.java | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/src/org/xbill/DNS/Generator.java b/src/org/xbill/DNS/Generator.java new file mode 100644 index 0000000..a08d343 --- /dev/null +++ b/src/org/xbill/DNS/Generator.java @@ -0,0 +1,264 @@ +// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org) + +package org.xbill.DNS; + +import java.io.*; +import java.util.*; + +/** + * A representation of a $GENERATE statement in a master file. + * + * @author Brian Wellington + */ + +public class Generator { + +/** The start of the range. */ +public long start; + +/** The end of the range. */ +public long end; + +/** The step value of the range. */ +public long step; + +/** The pattern to use for generating record names. */ +public final String namePattern; + +/** The type of the generated records. */ +public final int type; + +/** The class of the generated records. */ +public final int dclass; + +/** The ttl of the generated records. */ +public final long ttl; + +/** The pattern to use for generating record data. */ +public final String rdataPattern; + +/** The origin to append to relative names. */ +public final Name origin; + +private long current; + +/** + * Indicates whether generation is supported for this type. + * @throws InvalidTypeException The type is out of range. + */ +public static boolean +supportedType(int type) { + Type.check(type); + return (type == Type.PTR || type == Type.CNAME || type == Type.DNAME || + type == Type.A || type == Type.AAAA || type == Type.NS); +} + +/** + * Creates a specification for generating records, as a $GENERATE + * statement in a master file. + * @param start The start of the range. + * @param end The end of the range. + * @param step The step value of the range. + * @param namePattern The pattern to use for generating record names. + * @param type The type of the generated records. The supported types are + * PTR, CNAME, DNAME, A, AAAA, and NS. + * @param dclass The class of the generated records. + * @param ttl The ttl of the generated records. + * @param rdataPattern The pattern to use for generating record data. + * @param origin The origin to append to relative names. + * @throws IllegalArgumentException The range is invalid. + * @throws IllegalArgumentException The type does not support generation. + * @throws IllegalArgumentException The dclass is not a valid class. + */ +public +Generator(long start, long end, long step, String namePattern, + int type, int dclass, long ttl, String rdataPattern, Name origin) +{ + if (start < 0 || end < 0 || start > end || step <= 0) + throw new IllegalArgumentException + ("invalid range specification"); + if (!supportedType(type)) + throw new IllegalArgumentException("unsupported type"); + DClass.check(dclass); + + this.start = start; + this.end = end; + this.step = step; + this.namePattern = namePattern; + this.type = type; + this.dclass = dclass; + this.ttl = ttl; + this.rdataPattern = rdataPattern; + this.origin = origin; + this.current = start; +} + +private String +substitute(String spec, long n) throws IOException { + boolean escaped = false; + byte [] str = spec.getBytes(); + StringBuffer sb = new StringBuffer(); + + for (int i = 0; i < str.length; i++) { + char c = (char)(str[i] & 0xFF); + if (escaped) { + sb.append(c); + escaped = false; + } else if (c == '\\') { + if (i + 1 == str.length) + throw new TextParseException + ("invalid escape character"); + escaped = true; + } else if (c == '$') { + boolean negative = false; + long offset = 0; + long width = 0; + long base = 10; + boolean wantUpperCase = false; + if (i + 1 < str.length && str[i + 1] == '$') { + // '$$' == literal '$' for backwards + // compatibility with old versions of BIND. + c = (char)(str[++i] & 0xFF); + sb.append(c); + continue; + } else if (i + 1 < str.length && str[i + 1] == '{') { + // It's a substitution with modifiers. + i++; + if (i + 1 < str.length && str[i + 1] == '-') { + negative = true; + i++; + } + while (i + 1 < str.length) { + c = (char)(str[++i] & 0xFF); + if (c == ',' || c == '}') + break; + if (c < '0' || c > '9') + throw new TextParseException( + "invalid offset"); + c -= '0'; + offset *= 10; + offset += c; + } + if (negative) + offset = -offset; + + if (c == ',') { + while (i + 1 < str.length) { + c = (char)(str[++i] & 0xFF); + if (c == ',' || c == '}') + break; + if (c < '0' || c > '9') + throw new + TextParseException( + "invalid width"); + c -= '0'; + width *= 10; + width += c; + } + } + + if (c == ',') { + if (i + 1 == str.length) + throw new TextParseException( + "invalid base"); + c = (char)(str[++i] & 0xFF); + if (c == 'o') + base = 8; + else if (c == 'x') + base = 16; + else if (c == 'X') { + base = 16; + wantUpperCase = true; + } + else if (c != 'd') + throw new TextParseException( + "invalid base"); + } + + if (i + 1 == str.length || str[i + 1] != '}') + throw new TextParseException + ("invalid modifiers"); + i++; + } + long v = n + offset; + if (v < 0) + throw new TextParseException + ("invalid offset expansion"); + String number; + if (base == 8) + number = Long.toOctalString(v); + else if (base == 16) + number = Long.toHexString(v); + else + number = Long.toString(v); + if (wantUpperCase) + number = number.toUpperCase(); + if (width != 0 && width > number.length()) { + int zeros = (int)width - number.length(); + while (zeros-- > 0) + sb.append('0'); + } + sb.append(number); + } else { + sb.append(c); + } + } + return sb.toString(); +} + +/** + * Constructs and returns the next record in the expansion. + * @throws IOException The name or rdata was invalid after substitutions were + * performed. + */ +public Record +nextRecord() throws IOException { + if (current > end) + return null; + String namestr = substitute(namePattern, current); + Name name = Name.fromString(namestr, origin); + String rdata = substitute(rdataPattern, current); + current += step; + return Record.fromString(name, type, dclass, ttl, rdata, origin); +} + +/** + * Constructs and returns all records in the expansion. + * @throws IOException The name or rdata of a record was invalid after + * substitutions were performed. + */ +public Record [] +expand() throws IOException { + List list = new ArrayList(); + for (long i = start; i < end; i += step) { + String namestr = substitute(namePattern, current); + Name name = Name.fromString(namestr, origin); + String rdata = substitute(rdataPattern, current); + list.add(Record.fromString(name, type, dclass, ttl, + rdata, origin)); + } + return (Record []) list.toArray(new Record[list.size()]); +} + +/** + * Converts the generate specification to a string containing the corresponding + * $GENERATE statement. + */ +public String +toString() { + StringBuffer sb = new StringBuffer(); + sb.append("$GENERATE "); + sb.append(start + "-" + end); + if (step > 1) + sb.append("/" + step); + sb.append(" "); + sb.append(namePattern + " "); + sb.append(ttl + " "); + if (dclass != DClass.IN || !Options.check("noPrintIN")) + sb.append(DClass.string(dclass) + " "); + sb.append(Type.string(type) + " "); + sb.append(rdataPattern + " "); + return sb.toString(); +} + +} |