com.couchbase.client.core.deps.org.xbill.DNS.Generator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-io Show documentation
Show all versions of core-io Show documentation
The official Couchbase JVM Core IO Library
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2004 Brian Wellington ([email protected])
package com.couchbase.client.core.deps.org.xbill.DNS;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 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();
StringBuilder sb = new StringBuilder();
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 list.toArray(new Record[0]);
}
/**
* Converts the generate specification to a string containing the corresponding $GENERATE
* statement.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("$GENERATE ");
sb.append(start).append("-").append(end);
if (step > 1) {
sb.append("/").append(step);
}
sb.append(" ");
sb.append(namePattern).append(" ");
sb.append(ttl).append(" ");
if (dclass != DClass.IN || !Options.check("noPrintIN")) {
sb.append(DClass.string(dclass)).append(" ");
}
sb.append(Type.string(type)).append(" ");
sb.append(rdataPattern).append(" ");
return sb.toString();
}
}