View Javadoc
1   /*
2    * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this program; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17   *
18   * Additionally licensed with:
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   */
32  package org.spf4j.base;
33  
34  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
35  import java.io.IOException;
36  import java.nio.CharBuffer;
37  import javax.annotation.Nonnull;
38  
39  /**
40   *
41   * @author Zoltan Farkas
42   */
43  public final class AppendableUtils {
44  
45    private static final ThreadLocal<char[]> BUFF = new ThreadLocal<char[]>() {
46  
47      @Override
48      @SuppressFBWarnings("SUA_SUSPICIOUS_UNINITIALIZED_ARRAY")
49      protected char[] initialValue() {
50        return new char[64];
51      }
52  
53    };
54  
55    private static final char[] DIGITS = {
56      '0', '1', '2', '3', '4', '5',
57      '6', '7', '8', '9', 'a', 'b',
58      'c', 'd', 'e', 'f', 'g', 'h',
59      'i', 'j', 'k', 'l', 'm', 'n',
60      'o', 'p', 'q', 'r', 's', 't',
61      'u', 'v', 'w', 'x', 'y', 'z'
62    };
63  
64  
65    private AppendableUtils() { }
66  
67      /**
68     * Utility method to escape java strings to json strings.
69     *
70     * @param toEscape - the java string to escape.
71     * @param jsonString - the destination json String builder.
72     */
73    public static void escapeJsonString(@Nonnull final CharSequence toEscape, final StringBuilder jsonString) {
74  
75      int len = toEscape.length();
76      for (int i = 0; i < len; i++) {
77        char c = toEscape.charAt(i);
78        appendJsonStringEscapedChar(c, jsonString);
79      }
80  
81    }
82  
83    public static void escapeJsonString(@Nonnull final CharSequence toEscape, final Appendable jsonString)
84            throws IOException {
85      int len = toEscape.length();
86      for (int i = 0; i < len; i++) {
87        char c = toEscape.charAt(i);
88        appendJsonStringEscapedChar(c, jsonString);
89      }
90    }
91  
92    public static void appendJsonStringEscapedChar(final char c, final StringBuilder jsonString) {
93      switch (c) {
94        case '\\':
95        case '"':
96          jsonString.append('\\');
97          jsonString.append(c);
98          break;
99        case '\b':
100         jsonString.append("\\b");
101         break;
102       case '\t':
103         jsonString.append("\\t");
104         break;
105       case '\n':
106         jsonString.append("\\n");
107         break;
108       case '\f':
109         jsonString.append("\\f");
110         break;
111       case '\r':
112         jsonString.append("\\r");
113         break;
114       default:
115         if (c < ' ') {
116           jsonString.append("\\u");
117           appendUnsignedStringPadded(jsonString, (int) c, 4, 4);
118         } else {
119           jsonString.append(c);
120         }
121     }
122   }
123 
124   public static void appendJsonStringEscapedChar(final char c, final Appendable jsonString) throws IOException {
125     switch (c) {
126       case '\\':
127       case '"':
128         jsonString.append('\\');
129         jsonString.append(c);
130         break;
131       case '\b':
132         jsonString.append("\\b");
133         break;
134       case '\t':
135         jsonString.append("\\t");
136         break;
137       case '\n':
138         jsonString.append("\\n");
139         break;
140       case '\f':
141         jsonString.append("\\f");
142         break;
143       case '\r':
144         jsonString.append("\\r");
145         break;
146       default:
147         if (c < ' ') {
148           jsonString.append("\\u");
149           appendUnsignedStringPadded(jsonString, (int) c, 4, 4);
150         } else {
151           jsonString.append(c);
152         }
153     }
154   }
155 
156   public static void appendUnsignedStringPadded(final StringBuilder sb, final int nr, final int shift,
157           final int padTo) {
158     long i = nr;
159     char[] buf = BUFF.get();
160     int charPos = 32;
161     int radix = 1 << shift;
162     long mask = radix - 1;
163     do {
164       buf[--charPos] = DIGITS[(int) (i & mask)];
165       i >>>= shift;
166     } while (i != 0);
167     final int nrChars = 32 - charPos;
168     if (nrChars > padTo) {
169       throw new IllegalArgumentException("Your pad to value " + padTo
170               + " is to small, must be at least " + nrChars);
171     } else {
172       for (int j = 0, n = padTo - nrChars; j < n; j++) {
173         sb.append('0');
174       }
175     }
176     sb.append(buf, charPos, nrChars);
177   }
178 
179 
180   public static void appendUnsignedStringPadded(final Appendable sb, final int nr, final int shift,
181           final int padTo) throws IOException {
182     long i = nr;
183     char[] buf = BUFF.get();
184     int charPos = 32;
185     int radix = 1 << shift;
186     long mask = radix - 1;
187     do {
188       buf[--charPos] = DIGITS[(int) (i & mask)];
189       i >>>= shift;
190     } while (i != 0);
191     final int nrChars = 32 - charPos;
192     if (nrChars > padTo) {
193       throw new IllegalArgumentException("Your pad to value " + padTo
194               + " is to small, must be at least " + nrChars);
195     } else {
196       for (int j = 0, n = padTo - nrChars; j < n; j++) {
197         sb.append('0');
198       }
199     }
200     sb.append(CharBuffer.wrap(buf), charPos, charPos + nrChars);
201   }
202 
203   public static void appendUnsignedString(final StringBuilder sb, final long nr, final int shift) {
204     long i = nr;
205     char[] buf = BUFF.get();
206     int charPos = 64;
207     int radix = 1 << shift;
208     long mask = radix - 1;
209     do {
210       buf[--charPos] = DIGITS[(int) (i & mask)];
211       i >>>= shift;
212     } while (i != 0);
213     sb.append(buf, charPos, 64 - charPos);
214   }
215 
216   public static void appendUnsignedString(final StringBuilder sb, final int nr, final int shift) {
217     long i = nr;
218     char[] buf = BUFF.get();
219     int charPos = 32;
220     int radix = 1 << shift;
221     long mask = radix - 1;
222     do {
223       buf[--charPos] = DIGITS[(int) (i & mask)];
224       i >>>= shift;
225     } while (i != 0);
226     sb.append(buf, charPos, 32 - charPos);
227   }
228 
229   public static void appendSpaces(final Appendable to, final int nrSpaces) throws IOException {
230     for (int i = 0; i < nrSpaces; i++) {
231       to.append(' ');
232     }
233   }
234 
235   public static void appendSpaces(final StringBuilder to, final int nrSpaces) {
236     for (int i = 0; i < nrSpaces; i++) {
237       to.append(' ');
238     }
239   }
240 
241 
242 }