1// Copyright (c) 2004-2009 Brian Wellington (bwelling@xbill.org)
2
3package org.xbill.DNS;
4
5/**
6 * Routines for deal with the lists of types found in NSEC/NSEC3 records.
7 *
8 * @author Brian Wellington
9 */
10
11import java.io.*;
12import java.util.*;
13
14final class TypeBitmap implements Serializable {
15
16private static final long serialVersionUID = -125354057735389003L;
17
18private TreeSet types;
19
20private
21TypeBitmap() {
22	types = new TreeSet();
23}
24
25public
26TypeBitmap(int [] array) {
27	this();
28	for (int i = 0; i < array.length; i++) {
29		Type.check(array[i]);
30		types.add(new Integer(array[i]));
31	}
32}
33
34public
35TypeBitmap(DNSInput in) throws WireParseException {
36	this();
37	int lastbase = -1;
38	while (in.remaining() > 0) {
39		if (in.remaining() < 2)
40			throw new WireParseException
41				("invalid bitmap descriptor");
42		int mapbase = in.readU8();
43		if (mapbase < lastbase)
44			throw new WireParseException("invalid ordering");
45		int maplength = in.readU8();
46		if (maplength > in.remaining())
47			throw new WireParseException("invalid bitmap");
48		for (int i = 0; i < maplength; i++) {
49			int current = in.readU8();
50			if (current == 0)
51				continue;
52			for (int j = 0; j < 8; j++) {
53				if ((current & (1 << (7 - j))) == 0)
54					continue;
55				int typecode = mapbase * 256 + + i * 8 + j;
56				types.add(Mnemonic.toInteger(typecode));
57			}
58		}
59	}
60}
61
62public
63TypeBitmap(Tokenizer st) throws IOException {
64	this();
65	while (true) {
66		Tokenizer.Token t = st.get();
67		if (!t.isString())
68			break;
69		int typecode = Type.value(t.value);
70		if (typecode < 0) {
71			throw st.exception("Invalid type: " + t.value);
72		}
73		types.add(Mnemonic.toInteger(typecode));
74	}
75	st.unget();
76}
77
78public int []
79toArray() {
80	int [] array = new int[types.size()];
81	int n = 0;
82	for (Iterator it = types.iterator(); it.hasNext(); )
83		array[n++] = ((Integer)it.next()).intValue();
84	return array;
85}
86
87public String
88toString() {
89	StringBuffer sb = new StringBuffer();
90	for (Iterator it = types.iterator(); it.hasNext(); ) {
91		int t = ((Integer)it.next()).intValue();
92		sb.append(Type.string(t));
93		if (it.hasNext())
94			sb.append(' ');
95	}
96	return sb.toString();
97}
98
99private static void
100mapToWire(DNSOutput out, TreeSet map, int mapbase) {
101	int arraymax = (((Integer)map.last()).intValue()) & 0xFF;
102	int arraylength = (arraymax / 8) + 1;
103	int [] array = new int[arraylength];
104	out.writeU8(mapbase);
105	out.writeU8(arraylength);
106	for (Iterator it = map.iterator(); it.hasNext(); ) {
107		int typecode = ((Integer)it.next()).intValue();
108		array[(typecode & 0xFF) / 8] |= (1 << ( 7 - typecode % 8));
109	}
110	for (int j = 0; j < arraylength; j++)
111		out.writeU8(array[j]);
112}
113
114public void
115toWire(DNSOutput out) {
116	if (types.size() == 0)
117		return;
118
119	int mapbase = -1;
120	TreeSet map = new TreeSet();
121
122	for (Iterator it = types.iterator(); it.hasNext(); ) {
123		int t = ((Integer)it.next()).intValue();
124		int base = t >> 8;
125		if (base != mapbase) {
126			if (map.size() > 0) {
127				mapToWire(out, map, mapbase);
128				map.clear();
129			}
130			mapbase = base;
131		}
132			map.add(new Integer(t));
133	}
134	mapToWire(out, map, mapbase);
135}
136
137public boolean
138empty() {
139	return types.isEmpty();
140}
141
142public boolean
143contains(int typecode) {
144	return types.contains(Mnemonic.toInteger(typecode));
145}
146
147}
148