All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hsqldb.util.preprocessor.Document Maven / Gradle / Ivy

There is a newer version: 10.0.0
Show newest version
/* Copyright (c) 2001-2022, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


package org.hsqldb.util.preprocessor;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/*
 * $Id: Document.java 6550 2022-06-08 11:09:08Z fredt $
 */
/**
 * Simple line-oriented text document ADT.
 *
 * @author Campbell Burnet (campbell-burnet@users dot sourceforge.net)
 * @version 2.7.0
 * @since 1.8.1
 */
@SuppressWarnings("ClassWithoutLogger")
public class Document {

    /**
     * for the given character set name.
     *
     * @param charsetName to test; {@code null} returns {@code false}.
     * @return {@code true} if supported, else {@code false}.
     */
    public static boolean isSupportedCharset(final String charsetName) {
        return charsetName != null
                && !charsetName.trim().isEmpty()
                && Charset.isSupported(charsetName);
    }

    private final List lines;

    /**
     * constructs a new, empty instance.
     */
    public Document() {
        this.lines = new ArrayList<>(16);
    }

    /**
     * Constructs a new instance that is effectively a copy of {@code source}.
     *
     * @param source to copy; may be {@code null}, which is treated like an
     *               {@code empty} instance.
     */
    public Document(final Document source) {
        this();
        if (source != null) {
            final Document target = this;
            target.appendDocument(source);
        }
    }

    /**
     * to this instance.
     *
     * @param line to add; must not be {@code null}.
     * @return this instance.
     * @throws IllegalArgumentException if {@code line} is {@code null}.
     */
    public Document addSouceLine(final String line) {
        if (line == null) {
            throw new IllegalArgumentException("line: null");
        }
        this.lines.add(line);
        return this;
    }

    /**
     * to this instance.
     *
     * @param source to append; may be {@code null}, which is treated like an
     *               {@code empty} instance.
     * @return this instance
     */
    @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
    public Document appendDocument(final Document source) {
        if (source != null && source.size() > 0) {
            this.lines.addAll(source.lines);
        }
        return this;
    }

    /**
     * this instance, making it {@link #isEmpty() empty}.
     *
     * @return this instance.
     */
    public Document clear() {
        this.lines.clear();
        return this;
    }

    /**
     * if at least one line in this instance contains the given sequence.
     * 

* Note: each line is tested separately; no test is performed to see * if the sequence spans more than one line. *

* * @param sequence to test. * @return {@code true} if the condition holds, else {@code false}. */ public boolean contains(final CharSequence sequence) { if (sequence == null) { return false; } final String toFind = sequence.toString(); final List list = this.lines; final int size = list.size(); for (int i = 0; i < size; i++) { if (-1 < list.get(i).indexOf(toFind, 0)) { return true; } } return false; } /** * from this instance at the given index. * * @param index at which to remove a line. * @return this instance. * @throws IndexOutOfBoundsException if the index is out of range * ({@code index < 0 || index >= size())} */ public Document deleteSourceLine(final int index) { this.lines.remove(index); return this; } /** * if the given document has effectively the same content as this instance. * * @param document to test; may be {@code null}, which is treated as * {@link #isEmpty() empty}. * @return {@code true} if the content of the given {@code document} is * equal to the content of this instance, as per * {@link List#equals(Object)}. */ @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject") public boolean contentEquals(final Document document) { return (document == this) ? true : document == null ? this.isEmpty() : this.lines.equals(document.lines); } /** * at the given index. * * @param index at which to retrieve the line. * @return the line at the given index. * @throws IndexOutOfBoundsException if the index is out of range * ({@code index < 0 || index >= size()}) */ public String getSourceLine(final int index) { return this.lines.get(index); } /** * if this instance contains no lines. * * @return {@code true} if {@link #size()} {@code == 0}, else {@code false}. */ public boolean isEmpty() { return this.lines.isEmpty(); } /** * at the specified index. * * @param index at which the specified line is to be inserted * @param line to be inserted * @return this instance * @throws NullPointerException if the specified line is {@code null}. * @throws IndexOutOfBoundsException if the index is out of range * ({@code index < 0 || index >= size()}) */ public Document insertSourceLine(final int index, final String line) { if (line == null) { throw new IllegalArgumentException("line: null"); } this.lines.add(index, line); return this; } /** * as if by invoking {@code this.clear().appendDocument(source)}. * * @param source content used to replace the existing content of this * instance; may be {@code null}, which is treated as * {@link #isEmpty() empty}. * @return this instance. */ public Document replaceWith(final Document source) { return this.clear().appendDocument(source); } /** * at the specified index in this instance. * * @param index index of the line to replace * @param line to be stored at the specified index * @return this instance. * @throws NullPointerException if the specified line is {@code null}. * @throws IndexOutOfBoundsException if the index is out of range * ({@code index < 0 || index >= size()}) */ public Document setSourceLine(final int index, final String line) { if (line == null) { throw new IllegalArgumentException("null"); } this.lines.set(index, line); return this; } /** * of this instance, as the number of lines. * * @return the number of lines in this instance. */ public int size() { return this.lines.size(); } // ------------------------ I/O convenience methods ---------------------------- /** * this instance from the given input stream using the given character * encoding. *

* Note: it is the responsibility of the caller to close the input * stream. *

* * @param inputStream from which to load; must not be {@code null}. * @param encoding {@code null} for the system default. * @return this object. * @throws IOException if an I/O error occurs. * @throws IllegalArgumentException if the encoding is not supported. * @throws NullPointerException if the inputStream is {@code null}. */ public Document load(final InputStream inputStream, final String encoding) throws IOException, IllegalArgumentException, NullPointerException { return load((Object) inputStream, encoding); } /** * this instance from the given reader. *

* Note: it is the responsibility of the caller to close the reader. *

* * @param reader from which to load; must not be {@code null}. * @return this object. * @throws IOException in an I/O error occurs. * @throws NullPointerException if the reader is {@code null}. */ public Document load(final Reader reader) throws IOException, NullPointerException { return load(reader, null); } /** * this instance from the given file using the given character encoding. *

* Note: the underlying file input stream is closed automatically. *

* * @param file from which to load; {@code null} is treated the empty * path. * @param encoding {@code null} for the system default. * @return this object. * @throws IOException in an I/O error occurs. * @throws IllegalArgumentException if the encoding is not supported. */ public Document load(final File file, final String encoding) throws IOException, IllegalArgumentException { return load((Object) (file == null ? new File("") : file), encoding); } /** * this instance from the given abstract file path using the given character * encoding. *

* Note: the underlying file input stream is closed automatically. *

* * @param path from which to load; {@code null} is treated the empty * path. * @param encoding {@code null} for the system default. * @return this object. * @throws IOException in an I/O error occurs. * @throws IllegalArgumentException if the encoding is not supported. */ public Document load(final String path, final String encoding) throws IOException, IllegalArgumentException { return load((Object) (path == null ? "" : path), encoding); } /** * this instance from the given source. *

* Note: if the source is an InputStream or Reader, it is the * responsibility of the caller to close; otherwise, the underlying file * input stream is closed automatically. *

* * @param source required; by default, must be an instance of an * InputStream, Reader, File, or String denoting an * abstract file path. * @param encoding optional; ignored if source is a Writer. {@code null} is * taken to be {@link Charset#defaultCharset()}. * @return this instance. * @throws IOException if an I/O error occurs. * @throws NullPointerException if source is {@code null}. * @throws IllegalArgumentException if the encoding is not supported. */ @SuppressWarnings("NestedAssignment") protected Document load(final Object source, final String encoding) throws IOException, NullPointerException, IllegalArgumentException { if (source == null) { throw new NullPointerException("source must not be null."); } Charset charset = (source instanceof Reader || encoding == null) ? Charset.defaultCharset() : null; if (charset == null && isSupportedCharset(encoding)) { charset = Charset.forName(encoding); } else { throw new IllegalArgumentException("encoding: " + encoding); } BufferedReader reader = null; boolean close = false; if (source instanceof InputStream) { final InputStream is = (InputStream) source; final InputStreamReader isr = new InputStreamReader(is, charset); reader = new BufferedReader(isr); } else if (source instanceof File) { final InputStream fis = new FileInputStream((File) source); final InputStreamReader isr = new InputStreamReader(fis, charset); close = true; reader = new BufferedReader(isr); } else if (source instanceof String) { final InputStream fis = new FileInputStream((String) source); final InputStreamReader isr = new InputStreamReader(fis, charset); close = true; reader = new BufferedReader(isr); } else if (source instanceof BufferedReader) { reader = (BufferedReader) source; } else if (source instanceof Reader) { reader = new BufferedReader((Reader) source); } else { throw new IOException("unhandled load source: " + source); // NOI18N } clear(); String line; final List list = this.lines; try { while (null != (line = reader.readLine())) { list.add(line); } } finally { if (close) { try { reader.close(); } catch (IOException ex) { } } } return this; } /** * to the given output stream using the given character encoding. *

* Note: it is the responsibility of the caller to close the output * stream. *

* * @param outputStream to which to save; must not be {@code null}. * @param encoding {@code null} for the system default. * @return this object. * @throws IOException if an I/O error occurs. * @throws IllegalArgumentException if the encoding is not supported. * @throws NullPointerException if the output stream is {@code null}. */ public Document save(final OutputStream outputStream, final String encoding) throws IOException { return save((Object) outputStream, encoding); } /** * to the given file using the given character encoding. * * @param file to which to save; {@code null} is treated as having an * empty path * @param encoding {@code null} for the system default. * @return this object. * @throws IOException if an I/O error occurs. * @throws IllegalArgumentException if the encoding is not supported. */ public Document save(final File file, final String encoding) throws IOException, IllegalArgumentException { return save((Object) (file == null ? new File("") : file), encoding); } /** * to the given abstract file path using the given character encoding. * * @param path to which to save; {@code null} is treated as the empty * path; * @param encoding {@code null} for the system default. * @return this object. * @throws IOException if an I/O error occurs. * @throws IllegalArgumentException if the encoding is not supported. */ public Document save(final String path, final String encoding) throws IOException, IllegalArgumentException { return save((Object) (path == null ? "" : path), encoding); } /** * to the given writer. *

* Note: it is the responsibility of the caller to close the writer. *

* * @param writer to which to save; must not be {@code null}. * @return this object. * @throws IOException if an I/O error occurs. * @throws NullPointerException if the writer is {@code null}. */ public Document save(final Writer writer) throws IOException { return save(writer, null); } /** * this instance to the given target. *

* Note: if the target is an OutputStream or Writer, it is the * responsibility of the caller to close; otherwise, the underlying file * output stream is closed automatically. *

* * @param target required; by default, must be an instance of an * OutputStream, Writer, File, or String denoting an * abstract file path. * @param encoding optional; does not apply to Writer. {@code null} is taken * to be {@link Charset#defaultCharset()}. * @return this instance. * @throws IOException if an I/O error occurs. * @throws NullPointerException if target is {@code null}. */ protected Document save(final Object target, final String encoding) throws IOException { if (target == null) { throw new NullPointerException("target must not be null."); } Charset charset = (target instanceof Writer || encoding == null) ? Charset.defaultCharset() : null; if (charset == null && isSupportedCharset(encoding)) { charset = Charset.forName(encoding); } else { throw new IllegalArgumentException("encoding: " + encoding); } BufferedWriter writer = null; boolean close = false; if (target instanceof OutputStream) { final OutputStream os = (OutputStream) target; final OutputStreamWriter osw = new OutputStreamWriter(os, charset); writer = new BufferedWriter(osw); } else if (target instanceof File) { final OutputStream fos = new FileOutputStream((File) target); final OutputStreamWriter osw = new OutputStreamWriter(fos, charset); close = true; writer = new BufferedWriter(osw); } else if (target instanceof String) { OutputStream fos = new FileOutputStream((String) target); final OutputStreamWriter osw = new OutputStreamWriter(fos, charset); close = true; writer = new BufferedWriter(osw); } else if (target instanceof BufferedWriter) { writer = (BufferedWriter) target; } else if (target instanceof Writer) { writer = new BufferedWriter(writer); } else { throw new IOException("unhandled save target: " + target); } final List list = this.lines; final int count = list.size(); try { for (int i = 0; i < count; i++) { writer.write(list.get(i)); writer.newLine(); } writer.flush(); } finally { if (close) { try { writer.close(); } catch (IOException ignored) { } } } return this; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy