    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.text.translate;
    018
    019import java.io.IOException;
    020import java.io.Writer;
    021
    022import org.apache.commons.lang3.Range;
    023
    024/**
    025 * Translates codepoints to their XML numeric entity escaped value.
    026 *
    027 * @since 1.0
    028 */
    029public class NumericEntityEscaper extends CodePointTranslator {
    030
    031    /** whether to escape between the boundaries or outside them. */
    032    private final boolean between;
    033    /** range from lowest codepoint to highest codepoint. */
    034    private final Range<Integer> range;
    035    /**
    036     * <p>Constructs a <code>NumericEntityEscaper</code> for the specified range. This is
    037     * the underlying method for the other constructors/builders. The <code>below</code>
    038     * and <code>above</code> boundaries are inclusive when <code>between</code> is
    039     * <code>true</code> and exclusive when it is <code>false</code>. </p>
    040     *
    041     * @param below int value representing the lowest codepoint boundary
    042     * @param above int value representing the highest codepoint boundary
    043     * @param between whether to escape between the boundaries or outside them
    044     */
    045    private NumericEntityEscaper(final int below, final int above, final boolean between) {
    046        this.range = Range.between(below, above);
    047        this.between = between;
    048    }
    049
    050    /**
    051     * <p>Constructs a <code>NumericEntityEscaper</code> for all characters. </p>
    052     */
    053    public NumericEntityEscaper() {
    054        this(0, Integer.MAX_VALUE, true);
    055    }
    056
    057    /**
    058     * <p>Constructs a <code>NumericEntityEscaper</code> below the specified value (exclusive). </p>
    059     *
    060     * @param codepoint below which to escape
    061     * @return the newly created {@code NumericEntityEscaper} instance
    062     */
    063    public static NumericEntityEscaper below(final int codepoint) {
    064        return outsideOf(codepoint, Integer.MAX_VALUE);
    065    }
    066
    067    /**
    068     * <p>Constructs a <code>NumericEntityEscaper</code> above the specified value (exclusive). </p>
    069     *
    070     * @param codepoint above which to escape
    071     * @return the newly created {@code NumericEntityEscaper} instance
    072     */
    073    public static NumericEntityEscaper above(final int codepoint) {
    074        return outsideOf(0, codepoint);
    075    }
    076
    077    /**
    078     * <p>Constructs a <code>NumericEntityEscaper</code> between the specified values (inclusive). </p>
    079     *
    080     * @param codepointLow above which to escape
    081     * @param codepointHigh below which to escape
    082     * @return the newly created {@code NumericEntityEscaper} instance
    083     */
    084    public static NumericEntityEscaper between(final int codepointLow, final int codepointHigh) {
    085        return new NumericEntityEscaper(codepointLow, codepointHigh, true);
    086    }
    087
    088    /**
    089     * <p>Constructs a <code>NumericEntityEscaper</code> outside of the specified values (exclusive). </p>
    090     *
    091     * @param codepointLow below which to escape
    092     * @param codepointHigh above which to escape
    093     * @return the newly created {@code NumericEntityEscaper} instance
    094     */
    095    public static NumericEntityEscaper outsideOf(final int codepointLow, final int codepointHigh) {
    096        return new NumericEntityEscaper(codepointLow, codepointHigh, false);
    097    }
    098
    099    /**
    100     * {@inheritDoc}
    101     */
    102    @Override
    103    public boolean translate(final int codepoint, final Writer out) throws IOException {
    104        if (this.between != this.range.contains(codepoint)) {
    105            return false;
    106        }
    107        out.write("&#");
    108        out.write(Integer.toString(codepoint, 10));
    109        out.write(';');
    110        return true;
    111    }
    112}