comparison src/org/tmatesoft/hg/internal/KeywordFilter.java @ 113:67ae317408c9

Filter implementation for newline translation
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 02 Feb 2011 21:19:02 +0100
parents d488c7638b87
children 46291ec605a0
comparison
equal deleted inserted replaced
112:d488c7638b87 113:67ae317408c9
20 import java.io.FileInputStream; 20 import java.io.FileInputStream;
21 import java.io.FileOutputStream; 21 import java.io.FileOutputStream;
22 import java.nio.ByteBuffer; 22 import java.nio.ByteBuffer;
23 import java.util.TreeMap; 23 import java.util.TreeMap;
24 24
25 import javax.swing.text.html.Option;
26
25 import org.tmatesoft.hg.core.Path; 27 import org.tmatesoft.hg.core.Path;
26 import org.tmatesoft.hg.repo.HgRepository; 28 import org.tmatesoft.hg.repo.HgRepository;
27 29
28 /** 30 /**
29 * 31 *
30 * @author Artem Tikhomirov 32 * @author Artem Tikhomirov
31 * @author TMate Software Ltd. 33 * @author TMate Software Ltd.
32 */ 34 */
33 public class KeywordFilter implements Filter { 35 public class KeywordFilter implements Filter {
36 // present implementation is stateless, however, filter use pattern shall not assume that. In fact, Factory may us that
34 private final boolean isExpanding; 37 private final boolean isExpanding;
35 private final TreeMap<String,String> keywords; 38 private final TreeMap<String,String> keywords;
36 private final int minBufferLen; 39 private final int minBufferLen;
37 40
38 /** 41 /**
43 isExpanding = expand; 46 isExpanding = expand;
44 keywords = new TreeMap<String,String>(); 47 keywords = new TreeMap<String,String>();
45 keywords.put("Id", "Id"); 48 keywords.put("Id", "Id");
46 keywords.put("Revision", "Revision"); 49 keywords.put("Revision", "Revision");
47 keywords.put("Author", "Author"); 50 keywords.put("Author", "Author");
51 keywords.put("Date", "Date");
52 keywords.put("LastChangedRevision", "LastChangedRevision");
53 keywords.put("LastChangedBy", "LastChangedBy");
54 keywords.put("LastChangedDate", "LastChangedDate");
55 keywords.put("Source", "Source");
56 keywords.put("Header", "Header");
57
48 int l = 0; 58 int l = 0;
49 for (String s : keywords.keySet()) { 59 for (String s : keywords.keySet()) {
50 if (s.length() > l) { 60 if (s.length() > l) {
51 l = s.length(); 61 l = s.length();
52 } 62 }
97 // bytes). To prevent this, either shall copy bytes [keywordStart..buffer.limit()) to local buffer and use it on the next invocation, 107 // bytes). To prevent this, either shall copy bytes [keywordStart..buffer.limit()) to local buffer and use it on the next invocation,
98 // or add lookup of the keywords right after first '$' is found (do not wait for closing '$'). For now, large enough src buffer would be sufficient 108 // or add lookup of the keywords right after first '$' is found (do not wait for closing '$'). For now, large enough src buffer would be sufficient
99 // not to run into such situation 109 // not to run into such situation
100 throw new IllegalStateException("Try src buffer of a greater size"); 110 throw new IllegalStateException("Try src buffer of a greater size");
101 } 111 }
102 rv = ByteBuffer.allocateDirect(keywordStart - x); 112 rv = ByteBuffer.allocate(keywordStart - x);
103 } 113 }
104 // copy all from source till latest possible kw start 114 // copy all from source till latest possible kw start
105 copySlice(src, x, keywordStart, rv); 115 copySlice(src, x, keywordStart, rv);
106 rv.flip(); 116 rv.flip();
107 // and tell caller we've consumed only to the potential kw start 117 // and tell caller we've consumed only to the potential kw start
110 } else if (src.get(i) == '$') { 120 } else if (src.get(i) == '$') {
111 // end of keyword, or start of a new one. 121 // end of keyword, or start of a new one.
112 String keyword; 122 String keyword;
113 if ((keyword = matchKeyword(src, keywordStart, i)) != null) { 123 if ((keyword = matchKeyword(src, keywordStart, i)) != null) {
114 if (rv == null) { 124 if (rv == null) {
115 rv = ByteBuffer.allocateDirect(isExpanding ? src.capacity() * 4 : src.capacity()); 125 // src.remaining(), not .capacity because src is not read, and remaining represents
126 // actual bytes count, while capacity - potential.
127 // Factor of 4 is pure guess and a HACK, need to be fixed with re-expanding buffer on demand
128 rv = ByteBuffer.allocate(isExpanding ? src.remaining() * 4 : src.remaining());
116 } 129 }
117 copySlice(src, x, keywordStart+1, rv); 130 copySlice(src, x, keywordStart+1, rv);
118 rv.put(keyword.getBytes()); 131 rv.put(keyword.getBytes());
119 if (isExpanding) { 132 if (isExpanding) {
120 rv.put((byte) ':'); 133 rv.put((byte) ':');
148 } 161 }
149 } 162 }
150 if (keywordStart != -1) { 163 if (keywordStart != -1) {
151 if (rv == null) { 164 if (rv == null) {
152 // no expansion happened yet, and we have potential kw start 165 // no expansion happened yet, and we have potential kw start
153 rv = ByteBuffer.allocateDirect(keywordStart - src.position()); 166 rv = ByteBuffer.allocate(keywordStart - src.position());
154 copySlice(src, src.position(), keywordStart, rv); 167 copySlice(src, src.position(), keywordStart, rv);
155 } 168 }
156 src.position(keywordStart); 169 src.position(keywordStart);
157 } 170 }
158 if (rv != null) { 171 if (rv != null) {
187 break; 200 break;
188 } 201 }
189 chars[i] = c; 202 chars[i] = c;
190 } 203 }
191 String kw = new String(chars, 0, i); 204 String kw = new String(chars, 0, i);
205 System.out.println(keywords.subMap("I", "J"));
206 System.out.println(keywords.subMap("A", "B"));
207 System.out.println(keywords.subMap("Au", "B"));
192 return keywords.get(kw); 208 return keywords.get(kw);
193 } 209 }
194 210
195 // copies part of the src buffer, [from..to). doesn't modify src position 211 // copies part of the src buffer, [from..to). doesn't modify src position
196 private static void copySlice(ByteBuffer src, int from, int to, ByteBuffer dst) { 212 static void copySlice(ByteBuffer src, int from, int to, ByteBuffer dst) {
197 if (to > src.limit()) { 213 if (to > src.limit()) {
198 throw new IllegalArgumentException("Bad right boundary"); 214 throw new IllegalArgumentException("Bad right boundary");
199 } 215 }
200 if (dst.remaining() < to - from) { 216 if (dst.remaining() < to - from) {
201 throw new IllegalArgumentException("Not enough room in the destination buffer"); 217 throw new IllegalArgumentException("Not enough room in the destination buffer");
204 dst.put(src.get(i)); 220 dst.put(src.get(i));
205 } 221 }
206 } 222 }
207 223
208 private static int indexOf(ByteBuffer b, char ch, int from, boolean newlineBreaks) { 224 private static int indexOf(ByteBuffer b, char ch, int from, boolean newlineBreaks) {
209 for (int i = from; i < b.limit(); i++) { 225 for (int i = from; i < b.limit(); i++) {
210 byte c = b.get(i); 226 byte c = b.get(i);
211 if (ch == c) { 227 if (ch == c) {
212 return i; 228 return i;
213 } 229 }
214 if (newlineBreaks && (c == '\n' || c == '\r')) { 230 if (newlineBreaks && (c == '\n' || c == '\r')) {
236 return "<Sample> sample@sample.org"; 252 return "<Sample> sample@sample.org";
237 } 253 }
238 254
239 public static class Factory implements Filter.Factory { 255 public static class Factory implements Filter.Factory {
240 256
241 public Filter create(HgRepository hgRepo, Path path) { 257 public Filter create(HgRepository hgRepo, Path path, Options opts) {
242 return new KeywordFilter(true); 258 return new KeywordFilter(true);
243 } 259 }
244 } 260 }
245 261
246 262
247 public static void main(String[] args) throws Exception { 263 public static void main(String[] args) throws Exception {
248 FileInputStream fis = new FileInputStream(new File("/temp/kwoutput.txt")); 264 FileInputStream fis = new FileInputStream(new File("/temp/kwoutput.txt"));
249 FileOutputStream fos = new FileOutputStream(new File("/temp/kwoutput2.txt")); 265 FileOutputStream fos = new FileOutputStream(new File("/temp/kwoutput2.txt"));
250 ByteBuffer b = ByteBuffer.allocateDirect(256); 266 ByteBuffer b = ByteBuffer.allocate(256);
251 KeywordFilter kwFilter = new KeywordFilter(false); 267 KeywordFilter kwFilter = new KeywordFilter(false);
252 while (fis.getChannel().read(b) != -1) { 268 while (fis.getChannel().read(b) != -1) {
253 b.flip(); // get ready to be read 269 b.flip(); // get ready to be read
254 ByteBuffer f = kwFilter.filter(b); 270 ByteBuffer f = kwFilter.filter(b);
255 fos.getChannel().write(f); 271 fos.getChannel().write(f); // XXX in fact, f may not be fully consumed
256 if (b.hasRemaining()) { 272 if (b.hasRemaining()) {
257 ByteBuffer remaining = b.slice(); 273 b.compact();
258 b.clear();
259 b.put(remaining);
260 } else { 274 } else {
261 b.clear(); 275 b.clear();
262 } 276 }
263 } 277 }
264 fis.close(); 278 fis.close();