aboutsummaryrefslogtreecommitdiff
path: root/src/org/xbill/DNS/Generator.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/xbill/DNS/Generator.java')
-rw-r--r--src/org/xbill/DNS/Generator.java264
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();
+}
+
+}