Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2010 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.streamhtmlparser.util;
     18 
     19 /**
     20  * Records (stores) characters supplied one at a time conditional on
     21  * whether recording is currently enabled.
     22  *
     23  * <p>When {@link #maybeRecord(char)} is called, it will add the
     24  * supplied character to the recording buffer but only if
     25  * recording is in progress. This is useful in our
     26  * {@link com.google.security.streamhtmlparser.HtmlParser}
     27  * as the caller logic to enable/disable recording is decoupled from the logic
     28  * of recording.
     29  *
     30  * <p>This is a specialized class - of no use to external code -
     31  * which aims to be 100% compatible with the corresponding logic
     32  * in the C-version of the HtmlParser, specifically in
     33  * <code>statemachine.c</code>. In particular:
     34  * <ul>
     35  *   <li>The {@code startRecording()} and {@code stopRecording()} methods
     36  *       may be called repeatedly without interleaving since the C version is
     37  *       not guaranteed to interleave them.
     38  *   <li>There is a size limit to the recording buffer as set in
     39  *       {@link #RECORDING_BUFFER_SIZE}. Once the size is
     40  *       reached, no further characters are recorded regardless of whether
     41  *       recording is currently enabled.
     42  * </ul>
     43  */
     44 public class CharacterRecorder {
     45 
     46   /**
     47    * How many characters can be recorded before stopping to accept new
     48    * ones. Set to one less than in the C-version as we do not need
     49    * to reserve a character for the terminating null.
     50    */
     51   public static final int RECORDING_BUFFER_SIZE = 255;
     52 
     53   /**
     54    * This is where characters provided for recording are stored. Given
     55    * that the <code>CharacterRecorder</code> object is re-used, might as well
     56    * allocate the full size from the get-go.
     57    */
     58   private final StringBuilder sb;
     59 
     60   /** Holds whether we are currently recording characters or not. */
     61   private boolean recording;
     62 
     63   /**
     64    * Constructs an empty character recorder of fixed size currently
     65    * not recording. See {@link #RECORDING_BUFFER_SIZE} for the size.
     66    */
     67   public CharacterRecorder() {
     68     sb = new StringBuilder(RECORDING_BUFFER_SIZE);
     69     recording = false;
     70   }
     71 
     72   /**
     73    * Constructs a character recorder of fixed size that is a copy
     74    * of the one provided. In particular it has the same recording
     75    * setting and the same contents.
     76    *
     77    * @param aCharacterRecorder the {@code CharacterRecorder} to copy
     78    */
     79   public CharacterRecorder(CharacterRecorder aCharacterRecorder) {
     80     recording = aCharacterRecorder.recording;
     81     sb = new StringBuilder(RECORDING_BUFFER_SIZE);
     82     sb.append(aCharacterRecorder.getContent());
     83   }
     84 
     85   /**
     86    * Enables recording for incoming characters. The recording buffer is cleared
     87    * of content it may have contained.
     88    */
     89   public void startRecording() {
     90     // This is very fast, no memory (re-) allocation will take place.
     91     sb.setLength(0);
     92     recording = true;
     93   }
     94 
     95   /**
     96    * Disables recording further characters.
     97    */
     98   public void stopRecording() {
     99     recording = false;
    100   }
    101 
    102   /**
    103    * Records the {@code input} if recording is currently on and we
    104    * have space available in the buffer. If recording is not
    105    * currently on, this method will not perform any action.
    106    *
    107    * @param input the character to record
    108    */
    109   public void maybeRecord(char input) {
    110     if (recording && (sb.length() < RECORDING_BUFFER_SIZE)) {
    111       sb.append(input);
    112     }
    113   }
    114 
    115   /**
    116    * Empties the underlying storage but does not change the recording
    117    * state [i.e whether we are recording or not incoming characters].
    118    */
    119   public void clear() {
    120     sb.setLength(0);
    121   }
    122 
    123   /**
    124    * Empties the underlying storage and resets the recording indicator
    125    * to indicate we are not recording currently.
    126    */
    127   public void reset() {
    128     clear();
    129     recording = false;
    130   }
    131 
    132   /**
    133    * Returns the characters recorded in a {@code String} form. This
    134    * method has no side-effects, the characters remain stored as is.
    135    *
    136    * @return the contents in a {@code String} form
    137    */
    138   public String getContent() {
    139     return sb.toString();
    140   }
    141 
    142   /**
    143    * Returns whether or not we are currently recording incoming characters.
    144    *
    145    * @return {@code true} if we are recording, {@code false} otherwise
    146    */
    147   public boolean isRecording() {
    148     return recording;
    149   }
    150 
    151   /**
    152    * Returns the full state of the object in a human readable form. The
    153    * format of the returned {@code String} is not specified and is
    154    * subject to change.
    155    *
    156    * @return the full state of this object
    157    */
    158   @Override
    159   public String toString() {
    160     return String.format("In recording: %s; Value: %s", isRecording(),
    161                          sb.toString());
    162   }
    163 }
    164