001package ball.io;
002/*-
003 * ##########################################################################
004 * Utilities
005 * $Id: BOMCharsetMap.java 5285 2020-02-05 04:23:21Z ball $
006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/ball-util/trunk/src/main/java/ball/io/BOMCharsetMap.java $
007 * %%
008 * Copyright (C) 2008 - 2020 Allen D. Ball
009 * %%
010 * Licensed under the Apache License, Version 2.0 (the "License");
011 * you may not use this file except in compliance with the License.
012 * You may obtain a copy of the License at
013 *
014 *      http://www.apache.org/licenses/LICENSE-2.0
015 *
016 * Unless required by applicable law or agreed to in writing, software
017 * distributed under the License is distributed on an "AS IS" BASIS,
018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019 * See the License for the specific language governing permissions and
020 * limitations under the License.
021 * ##########################################################################
022 */
023import java.nio.charset.Charset;
024import java.util.Collections;
025import java.util.LinkedHashMap;
026import java.util.Map;
027
028import static java.nio.charset.StandardCharsets.UTF_16BE;
029import static java.nio.charset.StandardCharsets.UTF_16LE;
030import static java.nio.charset.StandardCharsets.UTF_8;
031import static java.util.stream.Collectors.joining;
032
033/**
034 * Byte order mark to {@link Charset} {@link Map} implementation.
035 *
036 * {@include #INSTANCE}
037 *
038 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
039 * @version $Revision: 5285 $
040 */
041public class BOMCharsetMap extends LinkedHashMap<byte[],Charset> {
042    private static final long serialVersionUID = -4968264081542792700L;
043
044    /**
045     * Unmodifiable instance of {@link BOMCharsetMap}.
046     */
047    public static final Map<byte[],Charset> INSTANCE =
048        Collections.unmodifiableMap(new BOMCharsetMap());
049
050    /**
051     * Sole constructor.
052     */
053    protected BOMCharsetMap() {
054        super();
055
056        put(bytes(0x00, 0x00, 0xFE, 0xFF), Charset.forName("UTF-32BE"));
057        put(bytes(0xFF, 0xFE, 0x00, 0x00), Charset.forName("UTF-32LE"));
058
059        put(bytes(0xEF, 0xBB, 0xBF), UTF_8);
060
061        put(bytes(0xFE, 0xFF), UTF_16BE);
062        put(bytes(0xFF, 0xFE), UTF_16LE);
063    }
064
065    private static byte[] bytes(int... elements) {
066        byte[] bytes = new byte[elements.length];
067
068        for (int i = 0; i < bytes.length; i += 1) {
069            bytes[i] = (byte) (elements[i] & 0xFF);
070        }
071
072        return bytes;
073    }
074
075    @Override
076    public String toString() {
077        String string =
078            entrySet().stream()
079            .map(t -> toString(t.getKey()) + "=" + toString(t.getValue()))
080            .collect(joining(", ", "{", "}"));
081
082        return string;
083    }
084
085    private String toString(byte[] bytes) {
086        StringBuilder buffer = new StringBuilder();
087
088        buffer.append("[");
089
090        for (int i = 0; i < bytes.length; i += 1) {
091            if (i > 0) {
092                buffer.append(", ");
093            }
094
095            buffer.append(String.format("0x%02X", bytes[i]));
096        }
097
098        buffer.append("]");
099
100        return buffer.toString();
101    }
102
103    private String toString(Charset charset) {
104        return (charset != null) ? charset.name() : null;
105    }
106}