This project has retired. For details please refer to its Attic page.
LatinEntityResolutionReader xref
View Javadoc
1   package org.apache.archiva.xml;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.BufferedReader;
23  import java.io.IOException;
24  import java.io.Reader;
25  import java.util.regex.Matcher;
26  import java.util.regex.Pattern;
27  
28  /**
29   * LatinEntityResolutionReader - Read a Character Stream.
30   *
31   *
32   */
33  public class LatinEntityResolutionReader
34      extends Reader
35  {
36      private BufferedReader originalReader;
37  
38      private char leftover[];
39  
40      private Pattern entityPattern;
41  
42      public LatinEntityResolutionReader( Reader reader )
43      {
44          this.originalReader = new BufferedReader( reader );
45          this.entityPattern = Pattern.compile( "\\&[a-zA-Z]+\\;" );
46      }
47  
48      /**
49       * Read characters into a portion of an array. This method will block until some input is available, 
50       * an I/O error occurs, or the end of the stream is reached.
51       * 
52       * @param destbuf Destination buffer
53       * @param offset Offset (in destination buffer) at which to start storing characters
54       * @param length Maximum number of characters to read
55       * @return The number of characters read, or -1 if the end of the stream has been reached
56       * @throws IOException if an I/O error occurs.
57       */
58      @Override
59      public int read( char[] destbuf, int offset, int length )
60          throws IOException
61      {
62          int tmpLength;
63          int currentRequestedOffset = offset;
64          int currentRequestedLength = length;
65  
66          // Drain leftover from last read request.
67          if ( leftover != null )
68          {
69              if ( leftover.length > length )
70              {
71                  // Copy partial leftover.
72                  System.arraycopy( leftover, 0, destbuf, currentRequestedOffset, length );
73                  int copyLeftOverLength = leftover.length - length;
74  
75                  // Create new leftover of remaining.
76                  char tmp[] = new char[copyLeftOverLength];
77                  System.arraycopy( leftover, length, tmp, 0, copyLeftOverLength );
78                  leftover = new char[tmp.length];
79                  System.arraycopy( tmp, 0, leftover, 0, copyLeftOverLength );
80  
81                  // Return len
82                  return length;
83              }
84              else
85              {
86                  tmpLength = leftover.length;
87  
88                  // Copy full leftover
89                  System.arraycopy( leftover, 0, destbuf, currentRequestedOffset, tmpLength );
90  
91                  // Empty out leftover (as there is now none left)
92                  leftover = null;
93  
94                  // Adjust offset and lengths.
95                  currentRequestedOffset += tmpLength;
96                  currentRequestedLength -= tmpLength;
97              }
98          }
99  
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 }