View Javadoc
1   /*
2   Copyright (c) 2013 James Ahlborn
3   
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7   
8       http://www.apache.org/licenses/LICENSE-2.0
9   
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16  
17  package com.healthmarketscience.jackcess.impl;
18  
19  import java.nio.ByteBuffer;
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  
24  /**
25   * Utility class for constructing {@code byte[]s} where the final size of the
26   * data is not known beforehand.  The API is similar to {@code ByteBuffer} but
27   * the data is not actually written to a {@code byte[]} until {@link
28   * #toBuffer} or {@link #toArray} is called.
29   *
30   * @author James Ahlborn
31   */
32  public class ByteArrayBuilder 
33  {
34    private int _pos;
35    private final List<Data> _data = new ArrayList<Data>();
36  
37    public ByteArrayBuilder() {
38    }
39  
40    public int position() {
41      return _pos;
42    }
43  
44    public ByteArrayBuilder reserveInt() {
45      return reserve(4);
46    }
47  
48    public ByteArrayBuilder reserveShort() {
49      return reserve(2);
50    }
51  
52    public ByteArrayBuilder reserve(int bytes) {
53      _pos += bytes;
54      return this;
55    }
56  
57    public ByteArrayBuilder put(byte val) {
58      return put(new ByteData(_pos, val));
59    }
60  
61    public ByteArrayBuilder putInt(int val) {
62      return putInt(_pos, val);
63    }
64  
65    public ByteArrayBuilder putInt(int pos, int val) {
66      return put(new IntData(pos, val));
67    }
68  
69    public ByteArrayBuilder putShort(short val) {
70      return putShort(_pos, val);
71    }
72  
73    public ByteArrayBuilder putShort(int pos, short val) {
74      return put(new ShortData(pos, val));
75    }
76  
77    public ByteArrayBuilder put(byte[] val) {
78      return put(new BytesData(_pos, val));
79    }
80  
81    public ByteArrayBuilder put(ByteBuffer val) {
82      return put(new BufData(_pos, val));
83    }
84  
85    private ByteArrayBuilder put(Data data) {
86      _data.add(data);
87      int endPos = data.getEndPos();
88      if(endPos > _pos) {
89        _pos = endPos;
90      }
91      return this;
92    }
93  
94    public ByteBuffer toBuffer() {
95      return toBuffer(PageChannel.wrap(new byte[_pos]));
96    }
97  
98    public ByteBuffer toBuffer(ByteBuffer buf) {
99      for(Data data : _data) {
100       data.write(buf);
101     }
102     buf.rewind();
103     return buf;
104   }
105 
106   public byte[] toArray() {
107     return toBuffer().array();
108   }
109 
110   private static abstract class Data
111   {
112     private int _pos;
113     
114     protected Data(int pos) {
115       _pos = pos;
116     }
117 
118     public int getPos() {
119       return _pos;
120     }
121 
122     public int getEndPos() {
123       return getPos() + size();
124     }
125 
126     public abstract int size();
127 
128     public abstract void write(ByteBuffer buf);
129   }
130 
131   private static final class IntData extends Data
132   {
133     private final int _val;
134 
135     private IntData(int pos, int val) {
136       super(pos);
137       _val = val;
138     }
139 
140     @Override
141     public int size() {
142       return 4;
143     }
144 
145     @Override
146     public void write(ByteBuffer buf) {
147       buf.putInt(getPos(), _val);
148     }
149   }
150 
151   private static final class ShortData extends Data
152   {
153     private final short _val;
154 
155     private ShortData(int pos, short val) {
156       super(pos);
157       _val = val;
158     }
159 
160     @Override
161     public int size() {
162       return 2;
163     }
164 
165     @Override
166     public void write(ByteBuffer buf) {
167       buf.putShort(getPos(), _val);
168     }
169   }
170 
171   private static final class ByteData extends Data
172   {
173     private final byte _val;
174 
175     private ByteData(int pos, byte val) {
176       super(pos);
177       _val = val;
178     }
179 
180     @Override
181     public int size() {
182       return 1;
183     }
184 
185     @Override
186     public void write(ByteBuffer buf) {
187       buf.put(getPos(), _val);
188     }
189   }
190 
191   private static final class BytesData extends Data
192   {
193     private final byte[] _val;
194 
195     private BytesData(int pos, byte[] val) {
196       super(pos);
197       _val = val;
198     }
199 
200     @Override
201     public int size() {
202       return _val.length;
203     }
204 
205     @Override
206     public void write(ByteBuffer buf) {
207       buf.position(getPos());
208       buf.put(_val);
209     }
210   }
211 
212   private static final class BufData extends Data
213   {
214     private final ByteBuffer _val;
215 
216     private BufData(int pos, ByteBuffer val) {
217       super(pos);
218       _val = val;
219     }
220 
221     @Override
222     public int size() {
223       return _val.remaining();
224     }
225 
226     @Override
227     public void write(ByteBuffer buf) {
228       buf.position(getPos());
229       buf.put(_val);
230     }
231   }
232 }