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 }