/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.tika.mime;

import java.util.HashMap;
import java.util.Map;

/**
 * Registry of known Internet media types.
 */
public class MediaTypeRegistry {

    /**
     * Registry of known media types, including type aliases. All the types
     * in this map are base types, i.e. they have no parameters. A canonical
     * media type is handled as an identity mapping, while an alias is stored
     * as a mapping from the alias to the corresponding canonical type.
     */
    private final Map<MediaType, MediaType> registry =
        new HashMap<MediaType, MediaType>();

    /**
     * Known type inheritance relationships. The mapping is from a media type
     * to the closest supertype. All types in this map are canonical and have
     * no parameters.
     */
    private final Map<MediaType, MediaType> inheritance =
        new HashMap<MediaType, MediaType>();

    public void addType(MediaType type) {
        if (type == null || type.hasParameters()) {
            throw new IllegalArgumentException();
        } else if (registry.containsKey(type)) {
            throw new IllegalStateException();
        } else {
            registry.put(type, type);
        }
    }

    public void addAlias(MediaType type, MediaType alias) {
        if (type == null || alias == null
                || type.hasParameters() || alias.hasParameters()) {
            throw new IllegalArgumentException();
        } else if (!registry.containsKey(type) || registry.containsKey(alias)) {
            throw new IllegalStateException();
        } else {
            registry.put(alias, type);
        }
    }

    public MediaType normalize(MediaType type) {
        MediaType canonical = registry.get(type.getBaseType());
        if (canonical == null) {
            return type;
        } else if (type.hasParameters()) {
            return new MediaType(canonical, type.getParameters());
        } else {
            return canonical;
        }
    }

    /**
     * Returns the supertype of the given type. If the given type has any
     * parameters, then the respective base type is returned. Otherwise
     * built-in heuristics like text/... -&gt; text/plain and
     * .../...+xml -&gt; application/xml are used in addition to explicit
     * type inheritance rules read from the media type database. Finally
     * application/octet-stream is returned for all types for which no other
     * supertype is known, and the return value for application/octet-stream
     * is <code>null</code>.
     *
     * @param type media type
     * @return supertype, or <code>null</code> for application/octet-stream
     */
    public MediaType getSuperType(MediaType type) {
        if (type.hasParameters()) {
            return type;
        } else if (inheritance.containsKey(type)) {
            return inheritance.get(type);
        } else if (type.getSubtype().endsWith("+xml")) {
            return MediaType.APPLICATION_XML;
        } else if (type.getSubtype().endsWith("+zip")) {
            return MediaType.APPLICATION_ZIP;
        } else if ("text".equals(type.getType())
                && !MediaType.TEXT_PLAIN.equals(type)) {
            return MediaType.TEXT_PLAIN;
        } else if (!MediaType.OCTET_STREAM.equals(type)) {
            return MediaType.OCTET_STREAM;
        } else {
            return null;
        }
    }

}

@@ -3526,32 +3526,46 @@
      return type
+.getBaseType()
 ;%0A        %7D else

Improve supertype handling in type registry