This project has retired. For details please refer to its Attic page.
Source code
001package org.apache.archiva.xml;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.BufferedReader;
023import java.io.IOException;
024import java.io.Reader;
025import java.util.regex.Matcher;
026import java.util.regex.Pattern;
027
028/**
029 * LatinEntityResolutionReader - Read a Character Stream.
030 *
031 *
032 */
033public class LatinEntityResolutionReader
034    extends Reader
035{
036    private BufferedReader originalReader;
037
038    private char leftover[];
039
040    private Pattern entityPattern;
041
042    public LatinEntityResolutionReader( Reader reader )
043    {
044        this.originalReader = new BufferedReader( reader );
045        this.entityPattern = Pattern.compile( "\\&[a-zA-Z]+\\;" );
046    }
047
048    /**
049     * Read characters into a portion of an array. This method will block until some input is available, 
050     * an I/O error occurs, or the end of the stream is reached.
051     * 
052     * @param destbuf Destination buffer
053     * @param offset Offset (in destination buffer) at which to start storing characters
054     * @param length Maximum number of characters to read
055     * @return The number of characters read, or -1 if the end of the stream has been reached
056     * @throws IOException if an I/O error occurs.
057     */
058    @Override
059    public int read( char[] destbuf, int offset, int length )
060        throws IOException
061    {
062        int tmpLength;
063        int currentRequestedOffset = offset;
064        int currentRequestedLength = length;
065
066        // Drain leftover from last read request.
067        if ( leftover != null )
068        {
069            if ( leftover.length > length )
070            {
071                // Copy partial leftover.
072                System.arraycopy( leftover, 0, destbuf, currentRequestedOffset, length );
073                int copyLeftOverLength = leftover.length - length;
074
075                // Create new leftover of remaining.
076                char tmp[] = new char[copyLeftOverLength];
077                System.arraycopy( leftover, length, tmp, 0, copyLeftOverLength );
078                leftover = new char[tmp.length];
079                System.arraycopy( tmp, 0, leftover, 0, copyLeftOverLength );
080
081                // Return len
082                return length;
083            }
084            else
085            {
086                tmpLength = leftover.length;
087
088                // Copy full leftover
089                System.arraycopy( leftover, 0, destbuf, currentRequestedOffset, tmpLength );
090
091                // Empty out leftover (as there is now none left)
092                leftover = null;
093
094                // Adjust offset and lengths.
095                currentRequestedOffset += tmpLength;
096                currentRequestedLength -= tmpLength;
097            }
098        }
099
100        StringBuilder sbuf = getExpandedBuffer( currentRequestedLength );
101
102        // Have we reached the end of the buffer?
103        if ( sbuf == null )
104        {
105            // Do we have content?
106            if ( currentRequestedOffset > offset )
107            {
108                // Signal that we do, by calculating length.
109                return ( currentRequestedOffset - offset );
110            }
111
112            // No content. signal end of buffer.
113            return -1;
114        }
115
116        // Copy from expanded buf whatever length we can accomodate.
117        tmpLength = Math.min( sbuf.length(), currentRequestedLength );
118        sbuf.getChars( 0, tmpLength, destbuf, currentRequestedOffset );
119
120        // Create the leftover (if any)
121        if ( tmpLength < sbuf.length() )
122        {
123            leftover = new char[sbuf.length() - tmpLength];
124            sbuf.getChars( tmpLength, tmpLength + leftover.length, leftover, 0 );
125        }
126
127        // Calculate Actual Length and return.
128        return ( currentRequestedOffset - offset ) + tmpLength;
129    }
130
131    private StringBuilder getExpandedBuffer( int minimumLength )
132        throws IOException
133    {
134        StringBuilder buf = null;
135        String line = this.originalReader.readLine();
136        boolean done = ( line == null );
137
138        while ( !done )
139        {
140            if ( buf == null )
141            {
142                buf = new StringBuilder();
143            }
144
145            buf.append( expandLine( line ) );
146
147            // Add newline only if there is more data.
148            if ( this.originalReader.ready() )
149            {
150                buf.append( "\n" );
151            }
152
153            if ( buf.length() > minimumLength )
154            {
155                done = true;
156            }
157            else
158            {
159                line = this.originalReader.readLine();
160                done = ( line == null );
161            }
162        }
163
164        return buf;
165    }
166
167    private String expandLine( String line )
168    {
169        StringBuilder ret = new StringBuilder();
170
171        int offset = 0;
172        String entity;
173        Matcher mat = this.entityPattern.matcher( line );
174        while ( mat.find( offset ) )
175        {
176            ret.append( line.substring( offset, mat.start() ) );
177            entity = mat.group();
178            ret.append( LatinEntities.resolveEntity( entity ) );
179            offset = mat.start() + entity.length();
180        }
181        ret.append( line.substring( offset ) );
182
183        return ret.toString();
184    }
185
186    @Override
187    public void close()
188        throws IOException
189    {
190        this.originalReader.close();
191    }
192}