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

laika.io.Input.scala Maven / Gradle / Ivy

/*
 * Copyright 2013-2016 the original author or authors.
 *
 * Licensed 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 laika.io
 
import java.io._

import laika.ast.Path
import laika.io.IO.FileBased
import laika.parse.ParserContext

import scala.io.Codec

/** Represents the input for a parser, abstracting over various types of IO resources. 
 *  
 *  For parsers that use the parser combinators of this library,
 *  this trait offers a convenient `asParserInput` method. Other types of parsers
 *  may use the `java.io.Reader` provided by the `asReader` method. 
 * 
 *  @author Jens Halm
 */
trait Input {

  /** The input as a `java.io.Reader`.
   */
  def asReader: java.io.Reader

  /** The input as a `ParserContext` instance for Laika's parser combinators.
   */
  def asParserInput: ParserContext
  
  /** The full path of this input.
   *  This path is always an absolute path
   *  from the root of the (virtual) input tree,
   *  therefore does not represent the filesystem
   *  path in case of file I/O.
   */
  def path: Path
  
  /** The local name of this input.
   */
  lazy val name: String = path.name
  
}

/** Factory methods for creating Input instances from different types of IO resources.
 * 
 *  @author Jens Halm
 */
object Input {
  
  /** Represents any input that can be used as binary input.
   */
  trait Binary {
    def asBinaryInput: BinaryInput
  }
  
  /** A sub-trait for binary input which can only be created
   *  from a stream or a file, not from a `java.io.Reader` instance
   *  or from a `String`.
   */
  trait BinaryInput {
  
    def asStream: InputStream
    
  }
  
  private class StringInput (source: String, val path: Path) extends Input {
    
    def asReader: java.io.Reader = new StringReader(source)
  
    def asParserInput: ParserContext = ParserContext(source)
    
  }
  
  private class ReaderInput (val asReader: java.io.Reader, val path: Path) extends Input {
   
    def asParserInput: ParserContext = ParserContext(asReader)

  }
  
  private class StreamInput (stream: InputStream, val path: Path, codec: Codec) extends Input with Binary {
   
    def asBinaryInput: BinaryInput = new BinaryInput {
      val asStream = stream
    }
    
    def asParserInput: ParserContext = ParserContext(asReader)
    
    lazy val asReader: java.io.Reader = new BufferedReader(new InputStreamReader(stream, codec.decoder))
    
  }
  
  private class AutocloseStreamInput (stream: InputStream, p: Path, codec: Codec) extends StreamInput(stream,p,codec) with Closeable {
    
    override def asBinaryInput: BinaryInput = new BinaryInput with Closeable {
      val asStream = stream
      def close = stream close
    }
    
    def close: Unit = asReader.close
    
  }
  
  class LazyFileInput (val file: File, val path: Path, codec: Codec) extends Input with Binary with FileBased with Closeable {
    
    private lazy val delegate = new AutocloseStreamInput(new FileInputStream(file), path, codec)
    
    def asReader: java.io.Reader = delegate.asReader
    def asParserInput: ParserContext = ParserContext(delegate.asReader, file.length.toInt)
    def close: Unit = delegate.close
    def asBinaryInput: BinaryInput = delegate.asBinaryInput
  }
  
  class LazyClasspathInput (val resource: String, val path: Path, codec: Codec) extends Input with Binary with Closeable {
    
    private lazy val delegate = new AutocloseStreamInput(getClass.getResourceAsStream(resource), path, codec)
    
    def asReader: java.io.Reader = delegate.asReader
    def asParserInput: ParserContext = delegate.asParserInput
    def close: Unit = delegate.close
    def asBinaryInput: BinaryInput = delegate.asBinaryInput
  }
  
  /** Creates a new Input instance from the specified source string.
   *  
   *  @param source the string to parse
   *  @param path the path of the document in the virtual tree 
   */
  def fromString (source: String, path: Path = Path.Root): Input = new StringInput(source, path)

  /** Creates a new Input instance for the file with the specified name.
   *  
   *  @param name the name of the file
   *  @param codec the character encoding of the file, if not specified the platform default will be used.
   */
  def fromFile (name: String)(implicit codec: Codec): Input with Binary with Closeable 
    = new LazyFileInput(new File(name), Path(name), codec)
  
  /** Creates a new Input instance for the specified file.
   *  
   *  @param file the file to use as input
   *  @param codec the character encoding of the file, if not specified the platform default will be used.
   */
  def fromFile (file: File)(implicit codec: Codec): Input with Binary with Closeable 
    = new LazyFileInput(file, Path(file.getName), codec)
  
  /** Creates a new Input instance for the specified file.
   *  
   *  @param file the file to use as input
   *  @param virtualPath the path of the document in the virtual tree
   *  @param codec the character encoding of the file, if not specified the platform default will be used.
   */
  def fromFile (file: File, virtualPath: Path)(implicit codec: Codec): Input with Binary with Closeable 
    = new LazyFileInput(file, virtualPath / file.getName, codec)
  
  /** Creates a new Input instance for the specified classpath resource.
   *  
   *  @param resource the name of the resource on the classpath
   *  @param virtualPath the path of the document in the virtual tree 
   *  @param codec the character encoding of the input, if not specified the platform default will be used.
   */
  def fromClasspath (resource: String, virtualPath: Path)(implicit codec: Codec): Input with Binary with Closeable
    = new LazyClasspathInput(resource, virtualPath, codec)
  
  /** Creates a new Input instance for the specified InputStream.
   *  
   *  @param stream the stream to read character data from
   *  @param path the (potentially virtual) path of the input source
   *  @param codec the character encoding used by the text input, if not specified the platform default will be used.
   */
  def fromStream (stream: InputStream, path: Path = Path.Root)(implicit codec: Codec): Input with Binary = new StreamInput(stream, path, codec)
  
  /** Creates a new Input instance for the specified Reader.
   *  
   *  @param reader the reader to read character data from
   *  @param path the (potentially virtual) path of the input source
   */
  def fromReader (reader: java.io.Reader, path: Path = Path.Root): Input = new ReaderInput(reader, path)
  
  
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy