View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package edu.internet2.middleware.grouperClientExt.org.apache.commons.codec.net;
19  
20  import java.io.UnsupportedEncodingException;
21  import java.nio.charset.Charset;
22  import java.nio.charset.StandardCharsets;
23  
24  import edu.internet2.middleware.grouperClientExt.org.apache.commons.codec.CodecPolicy;
25  import edu.internet2.middleware.grouperClientExt.org.apache.commons.codec.DecoderException;
26  import edu.internet2.middleware.grouperClientExt.org.apache.commons.codec.EncoderException;
27  import edu.internet2.middleware.grouperClientExt.org.apache.commons.codec.StringDecoder;
28  import edu.internet2.middleware.grouperClientExt.org.apache.commons.codec.StringEncoder;
29  import edu.internet2.middleware.grouperClientExt.org.apache.commons.codec.binary.Base64;
30  import edu.internet2.middleware.grouperClientExt.org.apache.commons.codec.binary.BaseNCodec;
31  
32  /**
33   * Identical to the Base64 encoding defined by <a href="http://www.ietf.org/rfc/rfc1521.txt">RFC 1521</a>
34   * and allows a character set to be specified.
35   * <p>
36   * <a href="http://www.ietf.org/rfc/rfc1522.txt">RFC 1522</a> describes techniques to allow the encoding of non-ASCII
37   * text in various portions of a RFC 822 [2] message header, in a manner which is unlikely to confuse existing message
38   * handling software.
39   * </p>
40   * <p>
41   * This class is immutable and thread-safe.
42   * </p>
43   *
44   * @see <a href="http://www.ietf.org/rfc/rfc1522.txt">MIME (Multipurpose Internet Mail Extensions) Part Two: Message
45   *          Header Extensions for Non-ASCII Text</a>
46   *
47   * @since 1.3
48   */
49  public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder {
50  
51      /**
52       * The default decoding policy.
53       */
54      private static final CodecPolicy DECODING_POLICY_DEFAULT = CodecPolicy.LENIENT;
55  
56      /**
57       * The default Charset used for string decoding and encoding.
58       */
59      private final Charset charset;
60  
61      /**
62       * If true then decoding should throw an exception for impossible combinations of bits at the
63       * end of the byte input. The default is to decode as much of them as possible.
64       */
65      private final CodecPolicy decodingPolicy;
66  
67      /**
68       * Default constructor.
69       */
70      public BCodec() {
71          this(StandardCharsets.UTF_8);
72      }
73  
74      /**
75       * Constructor which allows for the selection of a default Charset
76       *
77       * @param charset
78       *            the default string Charset to use.
79       *
80       * @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
81       * @since 1.7
82       */
83      public BCodec(final Charset charset) {
84          this(charset, DECODING_POLICY_DEFAULT);
85      }
86  
87      /**
88       * Constructor which allows for the selection of a default Charset.
89       *
90       * @param charset
91       *            the default string Charset to use.
92       * @param decodingPolicy The decoding policy.
93       *
94       * @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
95       * @since 1.15
96       */
97      public BCodec(final Charset charset, final CodecPolicy decodingPolicy) {
98          this.charset = charset;
99          this.decodingPolicy = decodingPolicy;
100     }
101 
102     /**
103      * Constructor which allows for the selection of a default Charset
104      *
105      * @param charsetName
106      *            the default Charset to use.
107      * @throws java.nio.charset.UnsupportedCharsetException
108      *             If the named Charset is unavailable
109      * @since 1.7 throws UnsupportedCharsetException if the named Charset is unavailable
110      * @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
111      */
112     public BCodec(final String charsetName) {
113         this(Charset.forName(charsetName));
114     }
115 
116     /**
117      * Returns true if decoding behavior is strict. Decoding will raise a
118      * {@link DecoderException} if trailing bits are not part of a valid Base64 encoding.
119      *
120      * <p>The default is false for lenient encoding. Decoding will compose trailing bits
121      * into 8-bit bytes and discard the remainder.
122      *
123      * @return true if using strict decoding
124      * @since 1.15
125      */
126     public boolean isStrictDecoding() {
127         return decodingPolicy == CodecPolicy.STRICT;
128     }
129 
130     @Override
131     protected String getEncoding() {
132         return "B";
133     }
134 
135     @Override
136     protected byte[] doEncoding(final byte[] bytes) {
137         if (bytes == null) {
138             return null;
139         }
140         return Base64.encodeBase64(bytes);
141     }
142 
143     @Override
144     protected byte[] doDecoding(final byte[] bytes) {
145         if (bytes == null) {
146             return null;
147         }
148         return new Base64(0, BaseNCodec.getChunkSeparator(), false, decodingPolicy).decode(bytes);
149     }
150 
151     /**
152      * Encodes a string into its Base64 form using the specified Charset. Unsafe characters are escaped.
153      *
154      * @param strSource
155      *            string to convert to Base64 form
156      * @param sourceCharset
157      *            the Charset for {@code value}
158      * @return Base64 string
159      * @throws EncoderException
160      *             thrown if a failure condition is encountered during the encoding process.
161      * @since 1.7
162      */
163     public String encode(final String strSource, final Charset sourceCharset) throws EncoderException {
164         if (strSource == null) {
165             return null;
166         }
167         return encodeText(strSource, sourceCharset);
168     }
169 
170     /**
171      * Encodes a string into its Base64 form using the specified Charset. Unsafe characters are escaped.
172      *
173      * @param strSource
174      *            string to convert to Base64 form
175      * @param sourceCharset
176      *            the Charset for {@code value}
177      * @return Base64 string
178      * @throws EncoderException
179      *             thrown if a failure condition is encountered during the encoding process.
180      */
181     public String encode(final String strSource, final String sourceCharset) throws EncoderException {
182         if (strSource == null) {
183             return null;
184         }
185         try {
186             return this.encodeText(strSource, sourceCharset);
187         } catch (final UnsupportedEncodingException e) {
188             throw new EncoderException(e.getMessage(), e);
189         }
190     }
191 
192     /**
193      * Encodes a string into its Base64 form using the default Charset. Unsafe characters are escaped.
194      *
195      * @param strSource
196      *            string to convert to Base64 form
197      * @return Base64 string
198      * @throws EncoderException
199      *             thrown if a failure condition is encountered during the encoding process.
200      */
201     @Override
202     public String encode(final String strSource) throws EncoderException {
203         if (strSource == null) {
204             return null;
205         }
206         return encode(strSource, this.getCharset());
207     }
208 
209     /**
210      * Decodes a Base64 string into its original form. Escaped characters are converted back to their original
211      * representation.
212      *
213      * @param value
214      *            Base64 string to convert into its original form
215      * @return original string
216      * @throws DecoderException
217      *             A decoder exception is thrown if a failure condition is encountered during the decode process.
218      */
219     @Override
220     public String decode(final String value) throws DecoderException {
221         if (value == null) {
222             return null;
223         }
224         try {
225             return this.decodeText(value);
226         } catch (final UnsupportedEncodingException | IllegalArgumentException e) {
227             throw new DecoderException(e.getMessage(), e);
228         }
229     }
230 
231     /**
232      * Encodes an object into its Base64 form using the default Charset. Unsafe characters are escaped.
233      *
234      * @param value
235      *            object to convert to Base64 form
236      * @return Base64 object
237      * @throws EncoderException
238      *             thrown if a failure condition is encountered during the encoding process.
239      */
240     @Override
241     public Object encode(final Object value) throws EncoderException {
242         if (value == null) {
243             return null;
244         } else if (value instanceof String) {
245             return encode((String) value);
246         } else {
247             throw new EncoderException("Objects of type " +
248                   value.getClass().getName() +
249                   " cannot be encoded using BCodec");
250         }
251     }
252 
253     /**
254      * Decodes a Base64 object into its original form. Escaped characters are converted back to their original
255      * representation.
256      *
257      * @param value
258      *            Base64 object to convert into its original form
259      * @return original object
260      * @throws DecoderException
261      *             Thrown if the argument is not a {@code String}. Thrown if a failure condition is encountered
262      *             during the decode process.
263      */
264     @Override
265     public Object decode(final Object value) throws DecoderException {
266         if (value == null) {
267             return null;
268         } else if (value instanceof String) {
269             return decode((String) value);
270         } else {
271             throw new DecoderException("Objects of type " +
272                   value.getClass().getName() +
273                   " cannot be decoded using BCodec");
274         }
275     }
276 
277     /**
278      * Gets the default Charset name used for string decoding and encoding.
279      *
280      * @return the default Charset name
281      * @since 1.7
282      */
283     public Charset getCharset() {
284         return this.charset;
285     }
286 
287     /**
288      * Gets the default Charset name used for string decoding and encoding.
289      *
290      * @return the default Charset name
291      */
292     public String getDefaultCharset() {
293         return this.charset.name();
294     }
295 }