]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/util/URIUtil.java
Merge "Revert "Default property editing restores assertions""
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / util / URIUtil.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.databoard.util;
13
14 import java.io.UnsupportedEncodingException;
15 import java.nio.charset.Charset;
16
17 /**
18  * <a href="http://www.simantics.org/wiki/index.php/URI">Simantics URI and identifier escape specification.
19  * 
20  * @author Hannu Niemist&ouml;
21  */
22 public final class URIUtil {
23
24     static final Charset UTF8        = Charset.forName("UTF-8");
25
26     static final byte[]  encodeTable = new byte[128];
27     static final byte[]  encodeTable2 = new byte[128]; // for non-bijection filenames
28
29     static {
30         for (int i = 0; i < 128; ++i) {
31             char c = (char) i;
32             if (c == ' ')
33                 encodeTable[i] = '_';
34             
35             else if (Character.isJavaIdentifierPart(c) && c != '_' && c != '$') {
36                 encodeTable[i] = (byte) i;
37             } else
38                 encodeTable[i] = -1;
39         }
40         
41         for (int i = 0; i < 128; ++i) {
42             char c = (char) i;
43             if (c == ' ' || c == '_' || c == '(' || c== ')')
44                 encodeTable2[i] = (byte) i;
45             else if (c == '/')
46                 encodeTable2[i] = (byte) '-';
47             else if (c == ' ')
48                 encodeTable2[i] = (byte) '_';
49             else if (c == '-' || c == '.')
50                 encodeTable2[i] = (byte) i;
51             else if (Character.isJavaIdentifierPart(c) && c != '_' && c != '$') {
52                 encodeTable2[i] = (byte) i;
53             } else
54                 encodeTable2[i] = -1;
55         }
56         
57     }
58
59     public static byte[] encode(String str, byte escapeChar, boolean identifier) throws UnsupportedEncodingException {
60         byte[] bytes = str.getBytes(UTF8);
61
62         boolean prefixWithUnderscore = identifier && bytes.length > 0 && (bytes[0] == '_' || Character.isDigit(bytes[0]));
63
64         // First calculate the length
65         int length = bytes.length;
66         for (byte b : bytes) {
67             if (b < 0 || encodeTable[b] == -1)
68                 length += 2;
69         }
70         if (prefixWithUnderscore)
71             length += 1;
72
73         // Then encode
74         if (length == bytes.length) {
75             for (int i = 0; i < length; ++i)
76                 bytes[i] = encodeTable[bytes[i]];
77             return bytes;
78         } else {
79             byte[] result = new byte[length];
80             int pos = 0;
81             if (prefixWithUnderscore) {
82                 result[pos++] = '_';
83             }
84             for (byte b : bytes) {
85                 int ib = (int) b;
86                 if (ib >= 0) {
87                     byte eb = encodeTable[ib];
88                     if (eb >= 0) {
89                         result[pos++] = eb;
90                         continue;
91                     }
92                 } else
93                     ib += 256;
94
95                 result[pos++] = escapeChar;
96                 result[pos++] = (byte) Character.forDigit(ib >> 4, 16);
97                 result[pos++] = (byte) Character.forDigit(ib & 15, 16);
98             }
99             return result;
100         }
101     }
102     
103     public static byte[] encodeFilename(String str, byte escapeChar, boolean identifier) throws UnsupportedEncodingException {
104         byte[] bytes = str.getBytes(UTF8);
105
106         boolean prefixWithUnderscore = identifier && bytes.length > 0 && (bytes[0] == '_' || Character.isDigit(bytes[0]));
107
108         // First calculate the length
109         int length = bytes.length;
110         for (byte b : bytes) {
111             if (b < 0 || encodeTable2[b] == -1)
112                 length += 2;
113         }
114         if (prefixWithUnderscore)
115             length += 1;
116
117         // Then encode
118         if (length == bytes.length) {
119             for (int i = 0; i < length; ++i)
120                 bytes[i] = encodeTable2[bytes[i]];
121             return bytes;
122         } else {
123             byte[] result = new byte[length];
124             int pos = 0;
125             if (prefixWithUnderscore) {
126                 result[pos++] = '_';
127             }
128             for (byte b : bytes) {
129                 int ib = (int) b;
130                 if (ib >= 0) {
131                     byte eb = encodeTable2[ib];
132                     if (eb >= 0) {
133                         result[pos++] = eb;
134                         continue;
135                     }
136                 } else
137                     ib += 256;
138
139                 result[pos++] = escapeChar;
140                 result[pos++] = (byte) Character.forDigit(ib >> 4, 16);
141                 result[pos++] = (byte) Character.forDigit(ib & 15, 16);
142             }
143             return result;
144         }
145     }
146     
147     public static String encodeFilename(String str) {
148         try {
149             byte[] result = encodeFilename(str, (byte) '%', false);
150             return new String(result, 0, result.length);
151         } catch (UnsupportedEncodingException e) {
152             // Should never happen when using UTF-8
153             throw new Error(e);
154         }
155
156     }
157
158     public static String encodeURI(String str) {
159         try {
160             byte[] result = encode(str, (byte) '%', false);
161             return new String(result, 0, result.length);
162         } catch (UnsupportedEncodingException e) {
163             // Should never happen when using UTF-8
164             throw new Error(e);
165         }
166
167     }
168
169     public static String encodeIdentifier(String str) {
170         try {
171             byte[] result = encode(str, (byte) '$', true);
172             return new String(result, 0, result.length);
173         } catch (UnsupportedEncodingException e) {
174             // Should never happen when using UTF-8
175             throw new Error(e);
176         }
177
178     }
179
180     public static String decode(byte[] bytes, byte escapeChar, boolean identifier) {
181         int length = 0;
182         int startPos = 0;
183         {
184             int i = 0;
185             // Skip '_' prefix if necessary
186             if (identifier && bytes.length > 0 && bytes[0] == '_') {
187                 startPos = 1;
188                 i = 1;
189             }
190             for (; i < bytes.length; ++i) {
191                 byte b = bytes[i];
192                 if (b == escapeChar)
193                     i += 2;
194                 ++length;
195             }
196         }
197         int pos = 0;
198         byte[] result = new byte[length];
199         for (int i = startPos; i < bytes.length; ++i) {
200             byte b = bytes[i];
201             if (b == escapeChar) {
202                 int c = Character.digit((char) bytes[++i], 16);
203                 c *= 16;
204                 c += Character.digit((char) bytes[++i], 16);
205                 result[pos] = (byte) c;
206             } else {
207                 if (b == '_')
208                     result[pos] = ' ';
209                 else
210                     result[pos] = b;
211             }
212             ++pos;
213         }
214         return new String(result, UTF8);
215     }
216
217     public static String decodeURI(String str) {
218         return decode(str.getBytes(), (byte) '%', false);
219     }
220
221     public static String decodeIdentifier(String str) {
222         return decode(str.getBytes(), (byte) '$', true);
223     }
224
225     /**
226      * Escape any of the following characters: <code><>:"/\|?*</code> with %nn.
227      * 
228      * @param str a file name, not a full file path
229      * @return original string or escaped file name if encoding is needed
230      */
231     public static String encodeFilename2(String str) {
232         return encodeFilename2(str, '%');
233     }
234
235     private static String encodeFilename2(String str, char escapeChar) {
236         // First calculate the length
237         int originalLength = str.length();
238         int length = originalLength;
239         for (int i = 0; i < originalLength; ++i) {
240             char c = str.charAt(i);
241             if (c < 128 && fileNameEncodeTable[(int) c] == -1)
242                 length += 2;
243         }
244
245         if (length == originalLength)
246             return str;
247
248         char[] result = new char[length];
249         int pos = 0;
250         for (int i = 0; i < originalLength; ++i) {
251             char c = str.charAt(i);
252             int ic = c;
253             if (c >= 128) {
254                 // Never escape any non-ASCII characters. Those should work.
255                 result[pos++] = c;
256             } else {
257                 int ec = fileNameEncodeTable[ic];
258                 if (ec >= 0) {
259                     result[pos++] = (char) ec;
260                 } else {
261                     result[pos++] = escapeChar;
262                     result[pos++] = Character.forDigit(ic >> 4, 16);
263                     result[pos++] = Character.forDigit(ic & 15, 16);
264                 }
265             }
266         }
267         return new String(result);
268     }
269
270     static final int[] fileNameEncodeTable = new int[128]; // for UTF-16 non-bijection filenames
271
272     static {
273         for (int i = 0; i < fileNameEncodeTable.length; ++i) {
274             if (i < 32) {
275                 // Control characters are all in need of escapes
276                 fileNameEncodeTable[i] = -1;
277             } else {
278                 switch ((char) i) {
279                 // Denied characters in windows file names
280                 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
281                 case '<': case '>': case ':': case '"': case '/': case '\\': case '|': case '?': case '*':
282                     fileNameEncodeTable[i] = -1;
283                     break;
284                 default:
285                     fileNameEncodeTable[i] = i;
286                     break;
287                 }
288             }
289         }
290     }
291
292 }