1/**
2 * Copyright (c) 2008, http://www.snakeyaml.org
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.yaml.snakeyaml.issues.issue99;
17
18import java.io.BufferedInputStream;
19import java.io.IOException;
20import java.io.InputStream;
21import java.util.Map;
22
23import junit.framework.TestCase;
24
25import org.yaml.snakeyaml.Util;
26import org.yaml.snakeyaml.Yaml;
27import org.yaml.snakeyaml.YamlDocument;
28import org.yaml.snakeyaml.constructor.AbstractConstruct;
29import org.yaml.snakeyaml.constructor.Constructor;
30import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
31import org.yaml.snakeyaml.nodes.Node;
32import org.yaml.snakeyaml.nodes.ScalarNode;
33import org.yaml.snakeyaml.nodes.Tag;
34
35/**
36 * Example for issue 99
37 *
38 * @see <a href="http://code.google.com/p/snakeyaml/issues/detail?id=99"></a>
39 */
40public class YamlBase64Test extends TestCase {
41
42    /**
43     * test base64 decoding
44     */
45    public void testBase64() throws IOException {
46        String text = Util.getLocalResource("issues/issue99-base64_literal.yaml");
47        String[] lines = text.split("\n");
48        String all = "";
49        for (int i = 1; i < lines.length; i++) {// skip first line
50            all = all + lines[i].trim();
51        }
52        // System.out.println(all);
53        byte[] decoded = Base64Coder.decode(all.toCharArray());
54        assertEquals(3737, decoded.length);
55        checkBytes(decoded);
56    }
57
58    @SuppressWarnings("unchecked")
59    public void testYamlBase64Loading() throws IOException {
60        Yaml yaml = new Yaml();
61        InputStream inputStream = YamlBase64Test.class
62                .getResourceAsStream("/issues/issue99-base64_double_quoted.yaml");
63        Map<String, Object> bean = (Map<String, Object>) yaml.load(inputStream);
64        byte[] jpeg = (byte[]) bean.get("jpegPhoto");
65        checkBytes(jpeg);
66        inputStream.close();
67    }
68
69    private void checkBytes(byte[] jpeg) throws IOException {
70        InputStream input;
71        input = YamlDocument.class.getClassLoader().getResourceAsStream("issues/issue99.jpeg");
72        BufferedInputStream is = new BufferedInputStream(input);
73        int i = 0;
74        while (i < jpeg.length) {
75            int etalon = is.read();
76            if (jpeg[i] < 0) {
77                assertEquals(etalon, jpeg[i] + 256);
78            } else {
79                assertEquals(etalon, jpeg[i]);
80            }
81            i++;
82        }
83        is.close();
84    }
85
86    /**
87     * In the literal scalar all the line breaks are significant
88     *
89     * @throws IOException
90     */
91    public void testYamlBase64LoadingLiteral() throws IOException {
92        Yaml yaml = new Yaml();
93        InputStream inputStream = YamlBase64Test.class
94                .getResourceAsStream("/issues/issue99-base64_literal.yaml");
95        try {
96            yaml.load(inputStream);
97            fail("In the literal scalar all the line breaks are significant");
98        } catch (Exception e) {
99            assertEquals("Length of Base64 encoded input string is not a multiple of 4.",
100                    e.getMessage());
101        } finally {
102            inputStream.close();
103        }
104    }
105
106    /**
107     * Redefine the !!binary global tag in a way that it ignores all the white
108     * spaces to be able to use literal scalar
109     */
110    @SuppressWarnings("unchecked")
111    public void testRedefineBinaryTag() throws IOException {
112        Yaml yaml = new Yaml(new SpecialContructor(Tag.BINARY));
113        InputStream inputStream = YamlBase64Test.class
114                .getResourceAsStream("/issues/issue99-base64_literal.yaml");
115        Map<String, Object> bean = (Map<String, Object>) yaml.load(inputStream);
116        byte[] jpeg = (byte[]) bean.get("jpegPhoto");
117        checkBytes(jpeg);
118        inputStream.close();
119    }
120
121    private class SpecialContructor extends Constructor {
122        public SpecialContructor(Tag tag) {
123            this.yamlConstructors.put(tag, new MyBinaryConstructor());
124        }
125
126        private class MyBinaryConstructor extends AbstractConstruct {
127            public Object construct(Node node) {
128                String contentWithNewLines = constructScalar((ScalarNode) node).toString();
129                String noNewLines = contentWithNewLines.replaceAll("\\s", "");
130                byte[] decoded = Base64Coder.decode(noNewLines.toCharArray());
131                return decoded;
132            }
133        }
134    }
135
136    /**
137     * Define a local tag to ignore all the white spaces to be able to use
138     * literal scalar
139     */
140    @SuppressWarnings("unchecked")
141    public void testLocalBinaryTag() throws IOException {
142        Yaml yaml = new Yaml(new SpecialContructor(new Tag("!beautiful")));
143        InputStream inputStream = YamlBase64Test.class
144                .getResourceAsStream("/issues/issue99-base64_literal_custom_tag.yaml");
145        Map<String, Object> bean = (Map<String, Object>) yaml.load(inputStream);
146        byte[] jpeg = (byte[]) bean.get("jpegPhoto");
147        checkBytes(jpeg);
148        inputStream.close();
149    }
150}
151