View Javadoc

1   package com.aragost.javahg.internals;
2   
3   import java.io.ByteArrayOutputStream;
4   import java.io.FilterOutputStream;
5   import java.io.IOException;
6   import java.io.OutputStream;
7   import java.util.Map;
8   
9   public class PatternReplacingOutputStream extends FilterOutputStream {
10  
11      private enum State {
12          /**
13           * The normal state where bytes are directly written though to
14           * the underlying stream
15           */
16          NORMAL,
17          /**
18           * A '%' has just been seen, so potentially a named pattern
19           * will start
20           */
21          MAYBE_NAME_START,
22          /**
23           * Bytes written to the stream is part of a named pattern,
24           * i.o. recently '%{' was written to the stream
25           */
26          READING_NAME,
27          /**
28           * 
29           */
30          WRITING_REPLACEMENT;
31      };
32  
33      private final ByteArrayOutputStream nameBuffer = new ByteArrayOutputStream(20);
34  
35      private final Map<String, byte[]> replacements;
36  
37      private State state = State.NORMAL;
38  
39      public PatternReplacingOutputStream(OutputStream out, Map<String, byte[]> replacements) {
40          super(out);
41          this.replacements = replacements;
42      }
43  
44      @Override
45      public synchronized void write(int b) throws IOException {
46          switch (this.state) {
47          case NORMAL:
48              if (b == '%') {
49                  this.state = State.MAYBE_NAME_START;
50              } else {
51                  super.write(b);
52              }
53              break;
54          case MAYBE_NAME_START:
55              if (b == '{') {
56                  this.state = State.READING_NAME;
57              } else {
58                  super.write('%');
59                  if (b == '%') {
60                      this.state = State.NORMAL;
61                  } else {
62                      super.write(b);
63                  }
64              }
65              break;
66          case READING_NAME:
67              if (b == '}') {
68                  this.state = State.WRITING_REPLACEMENT;
69                  String name = new String(this.nameBuffer.toByteArray()); 
70                  this.nameBuffer.reset();
71                  byte[] replacement = this.replacements.get(name);
72                  if (replacement == null) {
73                      replacement = ("%{" + name + "=null}").getBytes();
74                  }
75                  this.out.write(replacement);
76                  this.state = State.NORMAL;
77              } else {
78                  this.nameBuffer.write(b);
79              }
80              break;
81          case WRITING_REPLACEMENT:
82              super.write(b);
83              break;
84          }
85      }
86  }