| package org.apache.maven.plugins.enforcer.utils; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| |
| import java.io.FilterReader; |
| import java.io.IOException; |
| import java.io.Reader; |
| |
| /** |
| * Converts Unix line separators to Windows ones and vice-versa. |
| */ |
| public class NormalizeLineSeparatorReader |
| extends FilterReader |
| { |
| |
| private static final int EOL = -1; |
| |
| /** |
| * Type representing either Unix or Windows line separators |
| */ |
| public enum LineSeparator |
| { |
| WINDOWS( "\r\n", null ), UNIX( "\n", '\r' ); |
| |
| private final char[] separatorChars; |
| |
| private final Character notPrecededByChar; |
| |
| LineSeparator( String separator, Character notPrecededByChar ) |
| { |
| separatorChars = separator.toCharArray(); |
| this.notPrecededByChar = notPrecededByChar; |
| } |
| |
| enum MatchResult |
| { |
| NO_MATCH, |
| POTENTIAL_MATCH, |
| MATCH; |
| } |
| |
| /** |
| * Checks if two given characters match the line separator represented by this object. |
| * @param currentCharacter the character to check against |
| * @param previousCharacter optional previous character (may be {@code null}) |
| * @return one of {@link MatchResult} |
| */ |
| public MatchResult matches( char currentCharacter, Character previousCharacter ) |
| { |
| int len = separatorChars.length; |
| if ( currentCharacter == separatorChars[len - 1] ) |
| { |
| if ( len > 1 ) |
| { |
| if ( previousCharacter == null || previousCharacter != separatorChars[len - 1] ) |
| { |
| return MatchResult.NO_MATCH; |
| } |
| } |
| if ( notPrecededByChar != null ) |
| { |
| if ( previousCharacter != null && notPrecededByChar == previousCharacter ) |
| { |
| return MatchResult.NO_MATCH; |
| } |
| } |
| return MatchResult.MATCH; |
| } |
| else if ( len > 1 && currentCharacter == separatorChars[len - 2] ) |
| { |
| return MatchResult.POTENTIAL_MATCH; |
| } |
| return MatchResult.NO_MATCH; |
| } |
| }; |
| |
| final LineSeparator lineSeparator; |
| |
| Character bufferedCharacter; |
| |
| Character previousCharacter; |
| |
| public NormalizeLineSeparatorReader( Reader reader, LineSeparator lineSeparator ) |
| { |
| super( reader ); |
| this.lineSeparator = lineSeparator; |
| bufferedCharacter = null; |
| } |
| |
| @Override |
| public int read( char[] cbuf, int off, int len ) |
| throws IOException |
| { |
| int n; |
| for ( n = off; n < off + len; n++ ) |
| { |
| int readResult = read(); |
| if ( readResult == EOL ) |
| { |
| return n == 0 ? EOL : n; |
| } |
| else |
| { |
| cbuf[n] = (char) readResult; |
| } |
| } |
| return n; |
| } |
| |
| @Override |
| public int read() |
| throws IOException |
| { |
| // spool buffered characters, if any |
| if ( bufferedCharacter != null ) |
| { |
| char localBuffer = bufferedCharacter; |
| bufferedCharacter = null; |
| return localBuffer; |
| } |
| int readResult = super.read(); |
| if ( readResult == EOL ) |
| { |
| return readResult; |
| } |
| char currentCharacter = (char) readResult; |
| if ( lineSeparator == LineSeparator.UNIX ) |
| { |
| switch ( LineSeparator.WINDOWS.matches( currentCharacter, previousCharacter ) ) |
| { |
| case MATCH: |
| return lineSeparator.separatorChars[0]; |
| case POTENTIAL_MATCH: |
| previousCharacter = currentCharacter; |
| return read(); |
| default: |
| // fall-through |
| } |
| } |
| else |
| { // WINDOWS |
| // if current is unix, convert |
| switch ( LineSeparator.UNIX.matches( currentCharacter, previousCharacter ) ) |
| { |
| case MATCH: |
| bufferedCharacter = lineSeparator.separatorChars[1]; |
| // set buffered character and return current |
| return lineSeparator.separatorChars[0]; |
| case POTENTIAL_MATCH: |
| // invalid option |
| throw new IllegalStateException( "No potential matches expected for Unix line separator" ); |
| default: |
| // fall-through |
| } |
| } |
| previousCharacter = currentCharacter; |
| return currentCharacter; |
| } |
| |
| } |