Skip to main content
summaryrefslogtreecommitdiffstats
blob: fa41ac4800e4e1015bad7b8c7f2b48f728e3b99e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*******************************************************************************
 * Copyright (c) 2004, 2007 Boeing.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Boeing - initial API and implementation
 *******************************************************************************/
package org.eclipse.osee.framework.jdk.core.util;

import java.io.IOException;
import java.io.Reader;
import java.util.Arrays;

/**
 * @author Robert A. Fisher
 */
public final class Readers {

   /**
    * Forward a reader until just after the balanced close of the given xml element name. It is assumed that the
    * balanced open end of the element was just read off of the reader.
    * 
    * @param reader The reader to pull the data from
    * @param appendable If supplied, all data read from the reader is appended to the appendable
    * @param elementName The name of the element, including the namespace if applicable
    * @throws IllegalArgumentException If reader is null
    * @throws IllegalArgumentException If elementName is null
    * @throws IllegalStateException If the balanced closing tag is not found before the reader is emptied
    */
   public static final void xmlForward(Reader reader, Appendable appendable, CharSequence elementName) throws IOException {
      if (reader == null) {
         throw new IllegalArgumentException("reader can not be null");
      }
      if (elementName == null) {
         throw new IllegalArgumentException("elementName can not be null");
      }

      final String CLOSE_TAG = "</" + elementName + ">";
      final String EMPTY_TAG = "<" + elementName + "/>";
      final String OPEN_TAG = "<" + elementName + ">";
      final String OPEN_TAG_WITH_ATTR = "<" + elementName + " ";
      final CharSequence[] TAGS = {CLOSE_TAG, EMPTY_TAG, OPEN_TAG, OPEN_TAG_WITH_ATTR};

      int elementDepthCount = 1;
      StringBuilder read = null;
      if (appendable != null) {
         read = new StringBuilder();
      }

      CharSequence stopTag;

      while (elementDepthCount > 0) {
         if ((stopTag = forward(reader, appendable, TAGS)) == null) {
            throw new IllegalStateException("end of reader met when expecting an end of a tag");
         }

         if (stopTag == CLOSE_TAG) {
            elementDepthCount--;
         } else if (stopTag == OPEN_TAG) {
            elementDepthCount++;
         } else if (stopTag == OPEN_TAG_WITH_ATTR) {
            if (forward(reader, (Appendable) read, ">") == null) {
               throw new IllegalStateException("end of reader met when expecting >");
            }

            if (!read.toString().endsWith("/>")) {
               elementDepthCount++;
            }

            if (appendable != null) {
               appendable.append(read);
               read.setLength(0);
            }
         } else if (stopTag == EMPTY_TAG) {
            // no effect on the stack count
         } else {
            throw new IllegalStateException("unexpected element returned");
         }
      }
   }

   /**
    * Forward a reader to just after the specified CharSequence.
    * 
    * @return The sequence that was found which stopped the forwarding. A null is returned if no sequence was found
    * @throws IllegalArgumentException if any parameter is null
    * @throws IllegalArgumentException if any of the sequences elements are length zero
    */
   public static final CharSequence forward(Reader reader, CharSequence... sequences) throws IOException {
      return forward(reader, null, sequences);
   }

   /**
    * Forward a reader to just after the specified CharSequence. If an appendable is supplied then all characters
    * consumed from the reader will be appended to the appendable.
    * 
    * @return The sequence that was found which stopped the forwarding. A null is returned if no sequence was found
    * @throws IllegalArgumentException if reader is null
    * @throws IllegalArgumentException if sequences is null
    * @throws IllegalArgumentException if any of the sequences elements are length zero
    */
   public static final CharSequence forward(Reader reader, Appendable appendable, CharSequence... sequences) throws IOException {
      if (reader == null) {
         throw new IllegalArgumentException("reader can not be null");
      }
      if (sequences == null) {
         throw new IllegalArgumentException("sequences can not be null");
      }
      if (sequences.length == 0) {
         throw new IllegalArgumentException("must provide at least one sequence");
      }

      // Precalculate all of the lengths and check for unacceptable data
      int[] lengths = new int[sequences.length];
      for (int x = 0; x < sequences.length; x++) {
         if (sequences[x] == null) {
            throw new IllegalArgumentException("character sequence can not be null");
         }

         lengths[x] = sequences[x].length();

         if (lengths[x] == 0) {
            throw new IllegalArgumentException("character sequence can not have length zero");
         }
      }

      int[] seqIndex = new int[sequences.length];
      Arrays.fill(seqIndex, 0);

      char[] buffer = new char[1];

      while (reader.read(buffer) != -1) {
         if (appendable != null) {
            appendable.append(buffer[0]);
         }

         for (int x = 0; x < sequences.length; x++) {
            // Check if the last value read is inline with the next valid character for the sequence
            if (sequences[x].charAt(seqIndex[x]) == buffer[0]) {
               seqIndex[x]++;
               // Check if the whole sequence has been detected in the stream
               if (seqIndex[x] == lengths[x]) {
                  return sequences[x];
               }
            } else {
               seqIndex[x] = 0;
            }
         }
      }

      return null;
   }
}

Back to the top