1 /* Jackson JSON-processor.
2  *
3  * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
4  */
5 package com.fasterxml.jackson.core;
6 
7 /**
8  * Container for commonly used Base64 variants:
9  *<ul>
10  * <li> {@link #MIME}
11  * <li> {@link #MIME_NO_LINEFEEDS}
12  * <li> {@link #PEM}
13  * <li> {@link #MODIFIED_FOR_URL}
14  * </ul>
15  *
16  * @author Tatu Saloranta
17  */
18 public final class Base64Variants
19 {
20     final static String STD_BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
21 
22     /**
23      * This variant is what most people would think of "the standard"
24      * Base64 encoding.
25      *<p>
26      * See <a href="http://en.wikipedia.org/wiki/Base64">wikipedia Base64 entry</a> for details.
27      *<p>
28      * Note that although this can be thought of as the standard variant,
29      * it is <b>not</b> the default for Jackson: no-linefeeds alternative
30      * is because of JSON requirement of escaping all linefeeds.
31      */
32     public final static Base64Variant MIME;
33     static {
34         MIME = new Base64Variant("MIME", STD_BASE64_ALPHABET, true, '=', 76);
35     }
36 
37     /**
38      * Slightly non-standard modification of {@link #MIME} which does not
39      * use linefeeds (max line length set to infinite). Useful when linefeeds
40      * wouldn't work well (possibly in attributes), or for minor space savings
41      * (save 1 linefeed per 76 data chars, ie. ~1.4% savings).
42      */
43     public final static Base64Variant MIME_NO_LINEFEEDS;
44     static {
45         MIME_NO_LINEFEEDS = new Base64Variant(MIME, "MIME-NO-LINEFEEDS", Integer.MAX_VALUE);
46     }
47 
48     /**
49      * This variant is the one that predates {@link #MIME}: it is otherwise
50      * identical, except that it mandates shorter line length.
51      */
52     public final static Base64Variant PEM = new Base64Variant(MIME, "PEM", true, '=', 64);
53 
54     /**
55      * This non-standard variant is usually used when encoded data needs to be
56      * passed via URLs (such as part of GET request). It differs from the
57      * base {@link #MIME} variant in multiple ways.
58      * First, no padding is used: this also means that it generally can not
59      * be written in multiple separate but adjacent chunks (which would not
60      * be the usual use case in any case). Also, no linefeeds are used (max
61      * line length set to infinite). And finally, two characters (plus and
62      * slash) that would need quoting in URLs are replaced with more
63      * optimal alternatives (hyphen and underscore, respectively).
64      */
65     public final static Base64Variant MODIFIED_FOR_URL;
66     static {
67         StringBuilder sb = new StringBuilder(STD_BASE64_ALPHABET);
68         // Replace plus with hyphen, slash with underscore (and no padding)
69         sb.setCharAt(sb.indexOf("+"), '-');
70         sb.setCharAt(sb.indexOf("/"), '_');
71         // And finally, let's not split lines either, wouldn't work too well with URLs
72         MODIFIED_FOR_URL = new Base64Variant("MODIFIED-FOR-URL", sb.toString(), false, Base64Variant.PADDING_CHAR_NONE, Integer.MAX_VALUE);
73     }
74 
75     /**
76      * Method used to get the default variant ("MIME_NO_LINEFEEDS") for cases
77      * where caller does not explicitly specify the variant.
78      * We will prefer no-linefeed version because linefeeds in JSON values
79      * must be escaped, making linefeed-containing variants sub-optimal.
80      */
getDefaultVariant()81     public static Base64Variant getDefaultVariant() {
82         return MIME_NO_LINEFEEDS;
83     }
84 
85     /**
86      * @since 2.1
87      */
valueOf(String name)88     public static Base64Variant valueOf(String name) throws IllegalArgumentException
89     {
90         if (MIME._name.equals(name)) {
91             return MIME;
92         }
93         if (MIME_NO_LINEFEEDS._name.equals(name)) {
94             return MIME_NO_LINEFEEDS;
95         }
96         if (PEM._name.equals(name)) {
97             return PEM;
98         }
99         if (MODIFIED_FOR_URL._name.equals(name)) {
100             return MODIFIED_FOR_URL;
101         }
102         if (name == null) {
103             name = "<null>";
104         } else {
105             name = "'"+name+"'";
106         }
107         throw new IllegalArgumentException("No Base64Variant with name "+name);
108     }
109 }
110