1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 module hunt.shiro.codec.CodecSupport;
20 
21 import hunt.shiro.util.ByteSource;
22 
23 import hunt.Exceptions;
24 
25 /**
26  * Base abstract class that provides useful encoding and decoding operations, especially for character data.
27  *
28  * @since 0.9
29  */
30 abstract class CodecSupport {
31 
32     /**
33      * Shiro's default preferred character encoding, equal to <b><code>UTF-8</code></b>.
34      */
35     enum string PREFERRED_ENCODING = "UTF-8";
36 
37     /**
38      * Converts the specified character array to a byte array using the Shiro's preferred encoding (UTF-8).
39      * <p/>
40      * This is a convenience method equivalent to calling the {@link #toBytes(String,String)} method with a
41      * a wrapping String and {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}, i.e.
42      * <p/>
43      * <code>toBytes( new String(chars), {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING} );</code>
44      *
45      * @param chars the character array to be converted to a byte array.
46      * @return the byte array of the UTF-8 encoded character array.
47      */
48     static byte[] toBytes(char[] chars) {
49         // return toBytes(new String(chars), PREFERRED_ENCODING);
50         return cast(byte[])chars;
51     }
52 
53     // /**
54     //  * Converts the specified character array into a byte array using the specified character encoding.
55     //  * <p/>
56     //  * This is a convenience method equivalent to calling the {@link #toBytes(String,String)} method with a
57     //  * a wrapping String and the specified encoding, i.e.
58     //  * <p/>
59     //  * <code>toBytes( new String(chars), encoding );</code>
60     //  *
61     //  * @param chars    the character array to be converted to a byte array
62     //  * @param encoding the character encoding to use to when converting to bytes.
63     //  * @return the bytes of the specified character array under the specified encoding.
64     //  * @throws CodecException if the JVM does not support the specified encoding.
65     //  */
66     // static byte[] toBytes(char[] chars, String encoding) throws CodecException {
67     //     return toBytes(new String(chars), encoding);
68     // }
69 
70     // /**
71     //  * Converts the specified source argument to a byte array with Shiro's
72     //  * {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}.
73     //  *
74     //  * @param source the string to convert to a byte array.
75     //  * @return the bytes representing the specified string under the {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}.
76     //  * @see #toBytes(String, String)
77     //  */
78     // static byte[] toBytes(String source) {
79     //     return toBytes(source, PREFERRED_ENCODING);
80     // }
81 
82     // /**
83     //  * Converts the specified source to a byte array via the specified encoding, throwing a
84     //  * {@link CodecException CodecException} if the encoding fails.
85     //  *
86     //  * @param source   the source string to convert to a byte array.
87     //  * @param encoding the encoding to use to use.
88     //  * @return the byte array of the specified source with the given encoding.
89     //  * @throws CodecException if the JVM does not support the specified encoding.
90     //  */
91     // static byte[] toBytes(String source, String encoding) {
92     //     try {
93     //         return source.getBytes(encoding);
94     //     } catch (UnsupportedEncodingException e) {
95     //         String msg = "Unable to convert source [" ~ source ~ "] to byte array using " ~
96     //                 "encoding '" ~ encoding ~ "'";
97     //         throw new CodecException(msg, e);
98     //     }
99     // }
100 
101     // /**
102     //  * Converts the specified byte array to a String using the {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}.
103     //  *
104     //  * @param bytes the byte array to turn into a String.
105     //  * @return the specified byte array as an encoded String ({@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}).
106     //  * @see #toString(byte[], String)
107     //  */
108     // static String toString(byte[] bytes) {
109     //     return toString(bytes, PREFERRED_ENCODING);
110     // }
111 
112     // /**
113     //  * Converts the specified byte array to a String using the specified character encoding.  This implementation
114     //  * does the same thing as <code>new {@link String#String(byte[], String) String(byte[], encoding)}</code>, but will
115     //  * wrap any {@link UnsupportedEncodingException} with a nicer runtime {@link CodecException}, allowing you to
116     //  * decide whether or not you want to catch the exception or let it propagate.
117     //  *
118     //  * @param bytes    the byte array to convert to a String
119     //  * @param encoding the character encoding used to encode the String.
120     //  * @return the specified byte array as an encoded String
121     //  * @throws CodecException if the JVM does not support the specified encoding.
122     //  */
123     // static String toString(byte[] bytes, String encoding) throws CodecException {
124     //     try {
125     //         return new String(bytes, encoding);
126     //     } catch (UnsupportedEncodingException e) {
127     //         String msg = "Unable to convert byte array to String with encoding '" ~ encoding ~ "'.";
128     //         throw new CodecException(msg, e);
129     //     }
130     // }
131 
132     // /**
133     //  * Returns the specified byte array as a character array using the
134     //  * {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}.
135     //  *
136     //  * @param bytes the byte array to convert to a char array
137     //  * @return the specified byte array encoded as a character array ({@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}).
138     //  * @see #toChars(byte[], String)
139     //  */
140     // static char[] toChars(byte[] bytes) {
141     //     return toChars(bytes, PREFERRED_ENCODING);
142     // }
143 
144     // /**
145     //  * Converts the specified byte array to a character array using the specified character encoding.
146     //  * <p/>
147     //  * Effectively calls <code>{@link #toString(byte[], String) toString(bytes,encoding)}.{@link String#toCharArray() toCharArray()};</code>
148     //  *
149     //  * @param bytes    the byte array to convert to a String
150     //  * @param encoding the character encoding used to encode the bytes.
151     //  * @return the specified byte array as an encoded char array
152     //  * @throws CodecException if the JVM does not support the specified encoding.
153     //  */
154     // static char[] toChars(byte[] bytes, String encoding) throws CodecException {
155     //     return toString(bytes, encoding).toCharArray();
156     // }
157 
158     /**
159      * Returns {@code true} if the specified object can be easily converted to bytes by instances of this class,
160      * {@code false} otherwise.
161      * <p/>
162      * The default implementation returns {@code true} IFF the specified object is an instance of one of the following
163      * types:
164      * <ul>
165      * <li>{@code byte[]}</li>
166      * <li>{@code char[]}</li>
167      * <li>{@link ByteSource}</li>
168      * <li>{@link String}</li>
169      * <li>{@link File}</li>
170      * </li>{@link InputStream}</li>
171      * </ul>
172      *
173      * @param o the object to test to see if it can be easily converted to a byte array
174      * @return {@code true} if the specified object can be easily converted to bytes by instances of this class,
175      *         {@code false} otherwise.
176      * @since 1.0
177      */
178     protected bool isByteSource(Object o) {
179         ByteSource bs = cast(ByteSource)o;
180         if(bs !is null)
181             return true;
182         
183         implementationMissing(false);
184         
185         return false;
186         // return o instanceof byte[] || o instanceof char[] || o instanceof String ||
187         //         o instanceof ByteSource || o instanceof File || o instanceof InputStream;
188     }
189 
190     /**
191      * Converts the specified Object into a byte array.
192      * <p/>
193      * If the argument is a {@code byte[]}, {@code char[]}, {@link ByteSource}, {@link String}, {@link File}, or
194      * {@link InputStream}, it will be converted automatically and returned.}
195      * <p/>
196      * If the argument is anything other than these types, it is passed to the
197      * {@link #objectToBytes(Object) objectToBytes} method which must be overridden by subclasses.
198      *
199      * @param o the Object to convert into a byte array
200      * @return a byte array representation of the Object argument.
201      */
202     protected byte[] toBytes(Object o) {
203         if (o is null) {
204             string msg = "Argument for byte conversion cannot be null.";
205             throw new IllegalArgumentException(msg);
206         }
207 
208         implementationMissing(false);
209         return null;
210         // if (o instanceof byte[]) {
211         //     return (byte[]) o;
212         // } else if (o instanceof ByteSource) {
213         //     return ((ByteSource) o).getBytes();
214         // } else if (o instanceof char[]) {
215         //     return toBytes((char[]) o);
216         // } else if (o instanceof String) {
217         //     return toBytes((String) o);
218         // } else if (o instanceof File) {
219         //     return toBytes((File) o);
220         // } else if (o instanceof InputStream) {
221         //     return toBytes((InputStream) o);
222         // } else {
223         //     return objectToBytes(o);
224         // }
225     }
226 
227     // /**
228     //  * Converts the specified Object into a String.
229     //  * <p/>
230     //  * If the argument is a {@code byte[]} or {@code char[]} it will be converted to a String using the
231     //  * {@link #PREFERRED_ENCODING}.  If a String, it will be returned as is.
232     //  * <p/>
233     //  * If the argument is anything other than these three types, it is passed to the
234     //  * {@link #objectToString(Object) objectToString} method.
235     //  *
236     //  * @param o the Object to convert into a byte array
237     //  * @return a byte array representation of the Object argument.
238     //  */
239     // protected String toString(Object o) {
240     //     if (o is null) {
241     //         String msg = "Argument for String conversion cannot be null.";
242     //         throw new IllegalArgumentException(msg);
243     //     }
244     //     if (o instanceof byte[]) {
245     //         return toString((byte[]) o);
246     //     } else if (o instanceof char[]) {
247     //         return new String((char[]) o);
248     //     } else if (o instanceof String) {
249     //         return (String) o;
250     //     } else {
251     //         return objectToString(o);
252     //     }
253     // }
254 
255     // protected byte[] toBytes(File file) {
256     //     if (file is null) {
257     //         throw new IllegalArgumentException("File argument cannot be null.");
258     //     }
259     //     try {
260     //         return toBytes(new FileInputStream(file));
261     //     } catch (FileNotFoundException e) {
262     //         String msg = "Unable to acquire InputStream for file [" ~ file ~ "]";
263     //         throw new CodecException(msg, e);
264     //     }
265     // }
266 
267     // /**
268     //  * Converts the specified {@link InputStream InputStream} into a byte array.
269     //  *
270     //  * @param in the InputStream to convert to a byte array
271     //  * @return the bytes of the input stream
272     //  * @throws IllegalArgumentException if the {@code InputStream} argument is {@code null}.
273     //  * @throws CodecException           if there is any problem reading from the {@link InputStream}.
274     //  * @since 1.0
275     //  */
276     // protected byte[] toBytes(InputStream in) {
277     //     if (in is null) {
278     //         throw new IllegalArgumentException("InputStream argument cannot be null.");
279     //     }
280     //     final int BUFFER_SIZE = 512;
281     //     ByteArrayOutputStream out = new ByteArrayOutputStream(BUFFER_SIZE);
282     //     byte[] buffer = new byte[BUFFER_SIZE];
283     //     int bytesRead;
284     //     try {
285     //         while ((bytesRead = in.read(buffer)) != -1) {
286     //             out.write(buffer, 0, bytesRead);
287     //         }
288     //         return out.toByteArray();
289     //     } catch (IOException ioe) {
290     //         throw new CodecException(ioe);
291     //     } finally {
292     //         try {
293     //             in.close();
294     //         } catch (IOException ignored) {
295     //         }
296     //         try {
297     //             out.close();
298     //         } catch (IOException ignored) {
299     //         }
300     //     }
301     // }
302 
303     // /**
304     //  * Default implementation throws a CodecException immediately since it can't infer how to convert the Object
305     //  * to a byte array.  This method must be overridden by subclasses if anything other than the three default
306     //  * types (listed in the {@link #toBytes(Object) toBytes(Object)} JavaDoc) are to be converted to a byte array.
307     //  *
308     //  * @param o the Object to convert to a byte array.
309     //  * @return a byte array representation of the Object argument.
310     //  */
311     // protected byte[] objectToBytes(Object o) {
312     //     String msg = "The " ~ getClass().getName() ~ " implementation only supports conversion to " ~
313     //             "byte[] if the source is of type byte[], char[], String, " ~ ByteSource.class.getName() +
314     //             " File or InputStream.  The instance provided as a method " ~
315     //             "argument is of type [" ~ o.getClass().getName() ~ "].  If you would like to convert " ~
316     //             "this argument type to a byte[], you can 1) convert the argument to one of the supported types " ~
317     //             "yourself and then use that as the method argument or 2) subclass " ~ getClass().getName() +
318     //             "and override the objectToBytes(Object o) method.";
319     //     throw new CodecException(msg);
320     // }
321 
322     // /**
323     //  * Default implementation merely returns <code>objectArgument.toString()</code>.  Subclasses can override this
324     //  * method for different mechanisms of converting an object to a String.
325     //  *
326     //  * @param o the Object to convert to a byte array.
327     //  * @return a String representation of the Object argument.
328     //  */
329     // protected String objectToString(Object o) {
330     //     return o.toString();
331     // }
332 }