1993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira/**
2993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Copyright (c) 2006, Google Inc.
3993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
4993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
5993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * you may not use this file except in compliance with the License.
6993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * You may obtain a copy of the License at
7993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
8993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *     http://www.apache.org/licenses/LICENSE-2.0
9993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
10993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Unless required by applicable law or agreed to in writing, software
11993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
12993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * See the License for the specific language governing permissions and
14993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * limitations under the License.
15993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */
16993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
171bdbfefe4b144c7b031a1d9242a0fa061a0ae6b5Scott Kennedypackage com.google.android.mail.common.base;
18993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
191bdbfefe4b144c7b031a1d9242a0fa061a0ae6b5Scott Kennedyimport static com.google.android.mail.common.base.Preconditions.checkNotNull;
20993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
21993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereiraimport java.io.IOException;
22993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
23993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira/**
24993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * An object that converts literal text into a format safe for inclusion in a particular context
25993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * (such as an XML document). Typically (but not always), the inverse process of "unescaping" the
26993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * text is performed automatically by the relevant parser.
27993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
28993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p>For example, an XML escaper would convert the literal string {@code "Foo<Bar>"} into {@code
29993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * "Foo&lt;Bar&gt;"} to prevent {@code "<Bar>"} from being confused with an XML tag. When the
30993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * resulting XML document is parsed, the parser API will return this text as the original literal
31993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * string {@code "Foo<Bar>"}.
32993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
33993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p>A {@code CharEscaper} instance is required to be stateless, and safe when used concurrently by
34993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * multiple threads.
35993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
36993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p>Several popular escapers are defined as constants in the class {@link CharEscapers}. To create
37993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * your own escapers, use {@link CharEscaperBuilder}, or extend this class and implement the {@link
38993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * #escape(char)} method.
39993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
40993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @author sven@google.com (Sven Mawson)
41993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */
42993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereirapublic abstract class CharEscaper extends Escaper {
43993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
44993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Returns the escaped form of a given literal string.
45993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
46993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param string the literal string to be escaped
47993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @return the escaped form of {@code string}
48993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws NullPointerException if {@code string} is null
49993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
50993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  @Override public String escape(String string) {
51993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    checkNotNull(string);
52993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    // Inlineable fast-path loop which hands off to escapeSlow() only if needed
53993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    int length = string.length();
54993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    for (int index = 0; index < length; index++) {
55993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      if (escape(string.charAt(index)) != null) {
56993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        return escapeSlow(string, index);
57993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      }
58993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
59993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return string;
60993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
61993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
62993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
63993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Returns an {@code Appendable} instance which automatically escapes all text appended to it
64993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * before passing the resulting text to an underlying {@code Appendable}.
65993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
66993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * <p>The methods of the returned object will propagate any exceptions thrown by the underlying
67993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * {@code Appendable}, and will throw {@link NullPointerException} if asked to append {@code
68993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * null}, but do not otherwise throw any exceptions.
69993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
70993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * <p>The escaping behavior is identical to that of {@link #escape(String)}, so the following code
71993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * is always equivalent to {@code escaper.escape(string)}: <pre>   {@code
72993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
73993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *   StringBuilder sb = new StringBuilder();
74993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *   escaper.escape(sb).append(string);
75993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *   return sb.toString();}</pre>
76993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
77993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param out the underlying {@code Appendable} to append escaped output to
78993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @return an {@code Appendable} which passes text to {@code out} after escaping it
79993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws NullPointerException if {@code out} is null.
80993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
81993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  @Override public Appendable escape(final Appendable out) {
82993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    checkNotNull(out);
83993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
84993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return new Appendable() {
85993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      @Override public Appendable append(CharSequence csq) throws IOException {
86993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        out.append(escape(csq.toString()));
87993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        return this;
88993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      }
89993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
90993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      @Override public Appendable append(CharSequence csq, int start, int end) throws IOException {
91993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        out.append(escape(csq.subSequence(start, end).toString()));
92993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        return this;
93993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      }
94993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
95993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      @Override public Appendable append(char c) throws IOException {
96993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        char[] escaped = escape(c);
97993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        if (escaped == null) {
98993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira          out.append(c);
99993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        } else {
100993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira          for (char e : escaped) {
101993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira            out.append(e);
102993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira          }
103993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        }
104993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        return this;
105993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      }
106993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    };
107993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
108993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
109993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
110993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Returns the escaped form of a given literal string, starting at the given index. This method is
111993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * called by the {@link #escape(String)} method when it discovers that escaping is required. It is
112993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * protected to allow subclasses to override the fastpath escaping function to inline their
113993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * escaping test. See {@link CharEscaperBuilder} for an example usage.
114993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
115993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param s the literal string to be escaped
116993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param index the index to start escaping from
117993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @return the escaped form of {@code string}
118993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws NullPointerException if {@code string} is null
119993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
120993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  protected String escapeSlow(String s, int index) {
121993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    int slen = s.length();
122993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
123993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    // Get a destination buffer and setup some loop variables.
124993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    char[] dest = Platform.charBufferFromThreadLocal();
125993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    int destSize = dest.length;
126993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    int destIndex = 0;
127993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    int lastEscape = 0;
128993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
129993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    // Loop through the rest of the string, replacing when needed into the
130993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    // destination buffer, which gets grown as needed as well.
131993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    for (; index < slen; index++) {
132993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
133993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      // Get a replacement for the current character.
134993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      char[] r = escape(s.charAt(index));
135993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
136993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      // If no replacement is needed, just continue.
137993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      if (r == null) continue;
138993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
139993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      int rlen = r.length;
140993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      int charsSkipped = index - lastEscape;
141993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
142993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      // This is the size needed to add the replacement, not the full size needed by the string. We
143993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      // only regrow when we absolutely must.
144993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      int sizeNeeded = destIndex + charsSkipped + rlen;
145993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      if (destSize < sizeNeeded) {
146993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        destSize = sizeNeeded + (slen - index) + DEST_PAD;
147993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        dest = growBuffer(dest, destIndex, destSize);
148993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      }
149993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
150993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      // If we have skipped any characters, we need to copy them now.
151993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      if (charsSkipped > 0) {
152993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        s.getChars(lastEscape, index, dest, destIndex);
153993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        destIndex += charsSkipped;
154993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      }
155993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
156993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      // Copy the replacement string into the dest buffer as needed.
157993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      if (rlen > 0) {
158993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        System.arraycopy(r, 0, dest, destIndex, rlen);
159993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        destIndex += rlen;
160993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      }
161993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      lastEscape = index + 1;
162993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
163993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
164993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    // Copy leftover characters if there are any.
165993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    int charsLeft = slen - lastEscape;
166993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (charsLeft > 0) {
167993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      int sizeNeeded = destIndex + charsLeft;
168993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      if (destSize < sizeNeeded) {
169993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
170993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        // Regrow and copy, expensive! No padding as this is the final copy.
171993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        dest = growBuffer(dest, destIndex, sizeNeeded);
172993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      }
173993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      s.getChars(lastEscape, slen, dest, destIndex);
174993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      destIndex = sizeNeeded;
175993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
176993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return new String(dest, 0, destIndex);
177993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
178993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
179993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
180993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Returns the escaped form of the given character, or {@code null} if this character does not
181993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * need to be escaped. If an empty array is returned, this effectively strips the input character
182993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * from the resulting text.
183993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
184993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * <p>If the character does not need to be escaped, this method should return {@code null}, rather
185993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * than a one-character array containing the character itself. This enables the escaping algorithm
186993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * to perform more efficiently.
187993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
188993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * <p>An escaper is expected to be able to deal with any {@code char} value, so this method should
189993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * not throw any exceptions.
190993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
191993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param c the character to escape if necessary
192993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @return the replacement characters, or {@code null} if no escaping was needed
193993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
194993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  protected abstract char[] escape(char c);
195993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
196993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
197993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Helper method to grow the character buffer as needed, this only happens once in a while so it's
198993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * ok if it's in a method call. If the index passed in is 0 then no copying will be done.
199993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
200993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  private static char[] growBuffer(char[] dest, int index, int size) {
201993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    char[] copy = new char[size];
202993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (index > 0) {
203993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      System.arraycopy(dest, 0, copy, 0, index);
204993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
205993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return copy;
206993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
207993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
208993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
209993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * The amount of padding to use when growing the escape buffer.
210993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
211993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  private static final int DEST_PAD = 32;
212993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira}