View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.assembly.utils;
20  
21  import java.io.BufferedReader;
22  import java.io.BufferedWriter;
23  import java.io.File;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.InputStreamReader;
27  import java.io.OutputStreamWriter;
28  import java.io.RandomAccessFile;
29  import java.nio.file.Files;
30  
31  import org.apache.maven.plugins.assembly.format.AssemblyFormattingException;
32  
33  /**
34   * Line Ending class which contains convenience methods to change line endings.
35   */
36  public final class LineEndingsUtils {
37  
38      private LineEndingsUtils() {
39          // prevent creations of instances.
40      }
41  
42      /**
43       * Converts the line endings of a file, writing a new file. The encoding of reading and writing can be specified.
44       *
45       * @param source      The source file, not null
46       * @param dest        The destination file, not null
47       * @param lineEndings This is the result of the getLineEndingChars(..) method in this utility class; the actual
48       *                    line-ending characters, not null.
49       * @param atEndOfFile The end-of-file line ending, if true then the resulting file will have a new line at the end
50       *                    even if the input didn't have one, if false then the resulting file will have no new line at
51       *                    the end even if the input did have one, null to determine whether to have a new line at the
52       *                    end of the file based on the input file
53       * @param encoding    The encoding to use, null for platform encoding
54       * @throws IOException .
55       */
56      public static void convertLineEndings(
57              final File source, File dest, LineEndings lineEndings, final Boolean atEndOfFile, String encoding)
58              throws IOException {
59          // MASSEMBLY-637, MASSEMBLY-96
60          // find characters at the end of the file
61          // needed to preserve the last line ending
62          // only check for LF (as CRLF also ends in LF)
63          String eofChars = "";
64          if (atEndOfFile == null) {
65              if (source.length() >= 1) {
66                  try (RandomAccessFile raf = new RandomAccessFile(source, "r")) {
67                      raf.seek(source.length() - 1);
68                      byte last = raf.readByte();
69                      if (last == '\n') {
70                          eofChars = lineEndings.getLineEndingCharacters();
71                      }
72                  }
73              }
74          } else if (atEndOfFile) {
75              eofChars = lineEndings.getLineEndingCharacters();
76          }
77  
78          try (BufferedReader in = getBufferedReader(source, encoding);
79                  BufferedWriter out = getBufferedWriter(dest, encoding)) {
80              String line = in.readLine();
81              while (line != null) {
82                  out.write(line);
83                  line = in.readLine();
84                  if (line != null) {
85                      out.write(lineEndings.getLineEndingCharacters());
86                  } else {
87                      out.write(eofChars);
88                  }
89              }
90          }
91      }
92  
93      private static BufferedReader getBufferedReader(File source, String encoding) throws IOException {
94          if (encoding == null) {
95              // platform encoding
96              return new BufferedReader(new InputStreamReader(Files.newInputStream(source.toPath())));
97          } else {
98              // MASSEMBLY-371
99              return new BufferedReader(new InputStreamReader(Files.newInputStream(source.toPath()), encoding));
100         }
101     }
102 
103     private static BufferedWriter getBufferedWriter(File dest, String encoding) throws IOException {
104         if (encoding == null) {
105             // platform encoding
106             return new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(dest.toPath())));
107         } else {
108             // MASSEMBLY-371
109             return new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(dest.toPath()), encoding));
110         }
111     }
112 
113     /**
114      * Converts the line endings of a file, writing a new file. The encoding of reading and writing can be specified.
115      *
116      * @param in          The source reader
117      * @param lineEndings This is the result of the getLineEndingChars(..) method in this utility class; the actual
118      *                    line-ending characters, not null.
119      * @return an input stream that enforces a specifi line ending style
120      */
121     @SuppressWarnings("resource")
122     public static InputStream lineEndingConverter(InputStream in, LineEndings lineEndings) throws IOException {
123         return lineEndings.isNewLine()
124                 ? new LinuxLineFeedInputStream(in, false)
125                 : lineEndings.isCrLF() ? new WindowsLineFeedInputStream(in, false) : in;
126     }
127 
128     public static LineEndings getLineEnding(/* nullable */ String lineEnding) throws AssemblyFormattingException {
129         LineEndings result = LineEndings.keep;
130         if (lineEnding != null) {
131             try {
132                 result = LineEndings.valueOf(lineEnding);
133             } catch (IllegalArgumentException e) {
134                 throw new AssemblyFormattingException("Illegal lineEnding specified: '" + lineEnding + "'", e);
135             }
136         }
137         return result;
138     }
139 
140     /**
141      * Returns the appopriate line ending characters for the specified style
142      *
143      * @param lineEnding The name of the line ending style,
144      *                   see org.apache.maven.plugin.assembly.utils.LineEndings#valueOf
145      * @return The proper line ending characters
146      * @throws AssemblyFormattingException
147      */
148     public static String getLineEndingCharacters(/* nullable */ String lineEnding) throws AssemblyFormattingException {
149         String value = lineEnding;
150 
151         if (lineEnding != null) {
152             try {
153                 value = LineEndings.valueOf(lineEnding).getLineEndingCharacters();
154             } catch (IllegalArgumentException e) {
155                 throw new AssemblyFormattingException("Illegal lineEnding specified: '" + lineEnding + "'", e);
156             }
157         }
158 
159         return value;
160     }
161 }