diff options
author | Shuyi Chen <shuyichen@google.com> | 2013-05-22 14:51:55 -0700 |
---|---|---|
committer | Shuyi Chen <shuyichen@google.com> | 2013-05-22 17:19:30 -0700 |
commit | d7955ce24d294fb2014c59d11fca184471056f44 (patch) | |
tree | e260500b0b7639127038495d46a0ad6dcbb6d96c /src/org/xbill/DNS/Master.java | |
parent | 8f4ce9ea0de51fee918bffe19c434612d6bbb2d7 (diff) | |
download | smack-kitkat-mr1-release.tar.gz |
Add android smack source.HEADandroid-wear-5.0.0_r1android-sdk-4.4.2_r1.0.1android-sdk-4.4.2_r1android-l-preview_r2android-cts-5.1_r9android-cts-5.1_r8android-cts-5.1_r7android-cts-5.1_r6android-cts-5.1_r5android-cts-5.1_r4android-cts-5.1_r3android-cts-5.1_r28android-cts-5.1_r27android-cts-5.1_r26android-cts-5.1_r25android-cts-5.1_r24android-cts-5.1_r23android-cts-5.1_r22android-cts-5.1_r21android-cts-5.1_r20android-cts-5.1_r2android-cts-5.1_r19android-cts-5.1_r18android-cts-5.1_r17android-cts-5.1_r16android-cts-5.1_r15android-cts-5.1_r14android-cts-5.1_r13android-cts-5.1_r10android-cts-5.1_r1android-cts-5.0_r9android-cts-5.0_r8android-cts-5.0_r7android-cts-5.0_r6android-cts-5.0_r5android-cts-5.0_r4android-cts-5.0_r3android-cts-4.4_r4android-cts-4.4_r1android-5.1.1_r9android-5.1.1_r8android-5.1.1_r7android-5.1.1_r6android-5.1.1_r5android-5.1.1_r4android-5.1.1_r38android-5.1.1_r37android-5.1.1_r36android-5.1.1_r35android-5.1.1_r34android-5.1.1_r33android-5.1.1_r30android-5.1.1_r3android-5.1.1_r29android-5.1.1_r28android-5.1.1_r26android-5.1.1_r25android-5.1.1_r24android-5.1.1_r23android-5.1.1_r22android-5.1.1_r20android-5.1.1_r2android-5.1.1_r19android-5.1.1_r18android-5.1.1_r17android-5.1.1_r16android-5.1.1_r15android-5.1.1_r14android-5.1.1_r13android-5.1.1_r12android-5.1.1_r10android-5.1.1_r1android-5.1.0_r5android-5.1.0_r4android-5.1.0_r3android-5.1.0_r1android-5.0.2_r3android-5.0.2_r1android-5.0.1_r1android-5.0.0_r7android-5.0.0_r6android-5.0.0_r5.1android-5.0.0_r5android-5.0.0_r4android-5.0.0_r3android-5.0.0_r2android-5.0.0_r1android-4.4w_r1android-4.4_r1.2.0.1android-4.4_r1.2android-4.4_r1.1.0.1android-4.4_r1.1android-4.4_r1.0.1android-4.4_r1android-4.4_r0.9android-4.4_r0.8android-4.4_r0.7android-4.4.4_r2.0.1android-4.4.4_r2android-4.4.4_r1.0.1android-4.4.4_r1android-4.4.3_r1.1.0.1android-4.4.3_r1.1android-4.4.3_r1.0.1android-4.4.3_r1android-4.4.2_r2.0.1android-4.4.2_r2android-4.4.2_r1.0.1android-4.4.2_r1android-4.4.1_r1.0.1android-4.4.1_r1android-4.3_r3.1android-4.3_r3android-4.3_r2.3android-4.3_r2.2android-4.3_r2.1android-4.3_r2android-4.3_r1.1android-4.3_r1android-4.3_r0.9.1android-4.3_r0.9android-4.3.1_r1tools_r22.2mastermainlollipop-wear-releaselollipop-releaselollipop-mr1-wfc-releaselollipop-mr1-releaselollipop-mr1-fi-releaselollipop-mr1-devlollipop-mr1-cts-releaselollipop-devlollipop-cts-releasel-previewkitkat-wearkitkat-releasekitkat-mr2.2-releasekitkat-mr2.1-releasekitkat-mr2-releasekitkat-mr1.1-releasekitkat-mr1-releasekitkat-devkitkat-cts-releasekitkat-cts-devjb-mr2.0.0-releasejb-mr2.0-releasejb-mr2-releasejb-mr2-devidea133-weekly-releaseidea133
Change-Id: I49ce97136c17173c4ae3965c694af6e7bc49897d
Diffstat (limited to 'src/org/xbill/DNS/Master.java')
-rw-r--r-- | src/org/xbill/DNS/Master.java | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/src/org/xbill/DNS/Master.java b/src/org/xbill/DNS/Master.java new file mode 100644 index 0000000..c795a9c --- /dev/null +++ b/src/org/xbill/DNS/Master.java @@ -0,0 +1,427 @@ +// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org) + +package org.xbill.DNS; + +import java.io.*; +import java.util.*; + +/** + * A DNS master file parser. This incrementally parses the file, returning + * one record at a time. When directives are seen, they are added to the + * state and used when parsing future records. + * + * @author Brian Wellington + */ + +public class Master { + +private Name origin; +private File file; +private Record last = null; +private long defaultTTL; +private Master included = null; +private Tokenizer st; +private int currentType; +private int currentDClass; +private long currentTTL; +private boolean needSOATTL; + +private Generator generator; +private List generators; +private boolean noExpandGenerate; + +Master(File file, Name origin, long initialTTL) throws IOException { + if (origin != null && !origin.isAbsolute()) { + throw new RelativeNameException(origin); + } + this.file = file; + st = new Tokenizer(file); + this.origin = origin; + defaultTTL = initialTTL; +} + +/** + * Initializes the master file reader and opens the specified master file. + * @param filename The master file. + * @param origin The initial origin to append to relative names. + * @param ttl The initial default TTL. + * @throws IOException The master file could not be opened. + */ +public +Master(String filename, Name origin, long ttl) throws IOException { + this(new File(filename), origin, ttl); +} + +/** + * Initializes the master file reader and opens the specified master file. + * @param filename The master file. + * @param origin The initial origin to append to relative names. + * @throws IOException The master file could not be opened. + */ +public +Master(String filename, Name origin) throws IOException { + this(new File(filename), origin, -1); +} + +/** + * Initializes the master file reader and opens the specified master file. + * @param filename The master file. + * @throws IOException The master file could not be opened. + */ +public +Master(String filename) throws IOException { + this(new File(filename), null, -1); +} + +/** + * Initializes the master file reader. + * @param in The input stream containing a master file. + * @param origin The initial origin to append to relative names. + * @param ttl The initial default TTL. + */ +public +Master(InputStream in, Name origin, long ttl) { + if (origin != null && !origin.isAbsolute()) { + throw new RelativeNameException(origin); + } + st = new Tokenizer(in); + this.origin = origin; + defaultTTL = ttl; +} + +/** + * Initializes the master file reader. + * @param in The input stream containing a master file. + * @param origin The initial origin to append to relative names. + */ +public +Master(InputStream in, Name origin) { + this(in, origin, -1); +} + +/** + * Initializes the master file reader. + * @param in The input stream containing a master file. + */ +public +Master(InputStream in) { + this(in, null, -1); +} + +private Name +parseName(String s, Name origin) throws TextParseException { + try { + return Name.fromString(s, origin); + } + catch (TextParseException e) { + throw st.exception(e.getMessage()); + } +} + +private void +parseTTLClassAndType() throws IOException { + String s; + boolean seen_class = false; + + + // This is a bit messy, since any of the following are legal: + // class ttl type + // ttl class type + // class type + // ttl type + // type + seen_class = false; + s = st.getString(); + if ((currentDClass = DClass.value(s)) >= 0) { + s = st.getString(); + seen_class = true; + } + + currentTTL = -1; + try { + currentTTL = TTL.parseTTL(s); + s = st.getString(); + } + catch (NumberFormatException e) { + if (defaultTTL >= 0) + currentTTL = defaultTTL; + else if (last != null) + currentTTL = last.getTTL(); + } + + if (!seen_class) { + if ((currentDClass = DClass.value(s)) >= 0) { + s = st.getString(); + } else { + currentDClass = DClass.IN; + } + } + + if ((currentType = Type.value(s)) < 0) + throw st.exception("Invalid type '" + s + "'"); + + // BIND allows a missing TTL for the initial SOA record, and uses + // the SOA minimum value. If the SOA is not the first record, + // this is an error. + if (currentTTL < 0) { + if (currentType != Type.SOA) + throw st.exception("missing TTL"); + needSOATTL = true; + currentTTL = 0; + } +} + +private long +parseUInt32(String s) { + if (!Character.isDigit(s.charAt(0))) + return -1; + try { + long l = Long.parseLong(s); + if (l < 0 || l > 0xFFFFFFFFL) + return -1; + return l; + } + catch (NumberFormatException e) { + return -1; + } +} + +private void +startGenerate() throws IOException { + String s; + int n; + + // The first field is of the form start-end[/step] + // Regexes would be useful here. + s = st.getIdentifier(); + n = s.indexOf("-"); + if (n < 0) + throw st.exception("Invalid $GENERATE range specifier: " + s); + String startstr = s.substring(0, n); + String endstr = s.substring(n + 1); + String stepstr = null; + n = endstr.indexOf("/"); + if (n >= 0) { + stepstr = endstr.substring(n + 1); + endstr = endstr.substring(0, n); + } + long start = parseUInt32(startstr); + long end = parseUInt32(endstr); + long step; + if (stepstr != null) + step = parseUInt32(stepstr); + else + step = 1; + if (start < 0 || end < 0 || start > end || step <= 0) + throw st.exception("Invalid $GENERATE range specifier: " + s); + + // The next field is the name specification. + String nameSpec = st.getIdentifier(); + + // Then the ttl/class/type, in the same form as a normal record. + // Only some types are supported. + parseTTLClassAndType(); + if (!Generator.supportedType(currentType)) + throw st.exception("$GENERATE does not support " + + Type.string(currentType) + " records"); + + // Next comes the rdata specification. + String rdataSpec = st.getIdentifier(); + + // That should be the end. However, we don't want to move past the + // line yet, so put back the EOL after reading it. + st.getEOL(); + st.unget(); + + generator = new Generator(start, end, step, nameSpec, + currentType, currentDClass, currentTTL, + rdataSpec, origin); + if (generators == null) + generators = new ArrayList(1); + generators.add(generator); +} + +private void +endGenerate() throws IOException { + // Read the EOL that we put back before. + st.getEOL(); + + generator = null; +} + +private Record +nextGenerated() throws IOException { + try { + return generator.nextRecord(); + } + catch (Tokenizer.TokenizerException e) { + throw st.exception("Parsing $GENERATE: " + e.getBaseMessage()); + } + catch (TextParseException e) { + throw st.exception("Parsing $GENERATE: " + e.getMessage()); + } +} + +/** + * Returns the next record in the master file. This will process any + * directives before the next record. + * @return The next record. + * @throws IOException The master file could not be read, or was syntactically + * invalid. + */ +public Record +_nextRecord() throws IOException { + Tokenizer.Token token; + String s; + + if (included != null) { + Record rec = included.nextRecord(); + if (rec != null) + return rec; + included = null; + } + if (generator != null) { + Record rec = nextGenerated(); + if (rec != null) + return rec; + endGenerate(); + } + while (true) { + Name name; + + token = st.get(true, false); + if (token.type == Tokenizer.WHITESPACE) { + Tokenizer.Token next = st.get(); + if (next.type == Tokenizer.EOL) + continue; + else if (next.type == Tokenizer.EOF) + return null; + else + st.unget(); + if (last == null) + throw st.exception("no owner"); + name = last.getName(); + } + else if (token.type == Tokenizer.EOL) + continue; + else if (token.type == Tokenizer.EOF) + return null; + else if (((String) token.value).charAt(0) == '$') { + s = token.value; + + if (s.equalsIgnoreCase("$ORIGIN")) { + origin = st.getName(Name.root); + st.getEOL(); + continue; + } else if (s.equalsIgnoreCase("$TTL")) { + defaultTTL = st.getTTL(); + st.getEOL(); + continue; + } else if (s.equalsIgnoreCase("$INCLUDE")) { + String filename = st.getString(); + File newfile; + if (file != null) { + String parent = file.getParent(); + newfile = new File(parent, filename); + } else { + newfile = new File(filename); + } + Name incorigin = origin; + token = st.get(); + if (token.isString()) { + incorigin = parseName(token.value, + Name.root); + st.getEOL(); + } + included = new Master(newfile, incorigin, + defaultTTL); + /* + * If we continued, we wouldn't be looking in + * the new file. Recursing works better. + */ + return nextRecord(); + } else if (s.equalsIgnoreCase("$GENERATE")) { + if (generator != null) + throw new IllegalStateException + ("cannot nest $GENERATE"); + startGenerate(); + if (noExpandGenerate) { + endGenerate(); + continue; + } + return nextGenerated(); + } else { + throw st.exception("Invalid directive: " + s); + } + } else { + s = token.value; + name = parseName(s, origin); + if (last != null && name.equals(last.getName())) { + name = last.getName(); + } + } + + parseTTLClassAndType(); + last = Record.fromString(name, currentType, currentDClass, + currentTTL, st, origin); + if (needSOATTL) { + long ttl = ((SOARecord)last).getMinimum(); + last.setTTL(ttl); + defaultTTL = ttl; + needSOATTL = false; + } + return last; + } +} + +/** + * Returns the next record in the master file. This will process any + * directives before the next record. + * @return The next record. + * @throws IOException The master file could not be read, or was syntactically + * invalid. + */ +public Record +nextRecord() throws IOException { + Record rec = null; + try { + rec = _nextRecord(); + } + finally { + if (rec == null) { + st.close(); + } + } + return rec; +} + +/** + * Specifies whether $GENERATE statements should be expanded. Whether + * expanded or not, the specifications for generated records are available + * by calling {@link #generators}. This must be called before a $GENERATE + * statement is seen during iteration to have an effect. + */ +public void +expandGenerate(boolean wantExpand) { + noExpandGenerate = !wantExpand; +} + +/** + * Returns an iterator over the generators specified in the master file; that + * is, the parsed contents of $GENERATE statements. + * @see Generator + */ +public Iterator +generators() { + if (generators != null) + return Collections.unmodifiableList(generators).iterator(); + else + return Collections.EMPTY_LIST.iterator(); +} + +protected void +finalize() { + st.close(); +} + +} |