/* * Copyright (C) 2010 Google Inc. * * Licensed 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. */ package com.google.streamhtmlparser.util; /** * Records (stores) characters supplied one at a time conditional on * whether recording is currently enabled. * *

When {@link #maybeRecord(char)} is called, it will add the * supplied character to the recording buffer but only if * recording is in progress. This is useful in our * {@link com.google.security.streamhtmlparser.HtmlParser} * as the caller logic to enable/disable recording is decoupled from the logic * of recording. * *

This is a specialized class - of no use to external code - * which aims to be 100% compatible with the corresponding logic * in the C-version of the HtmlParser, specifically in * statemachine.c. In particular: *

*/ public class CharacterRecorder { /** * How many characters can be recorded before stopping to accept new * ones. Set to one less than in the C-version as we do not need * to reserve a character for the terminating null. */ public static final int RECORDING_BUFFER_SIZE = 255; /** * This is where characters provided for recording are stored. Given * that the CharacterRecorder object is re-used, might as well * allocate the full size from the get-go. */ private final StringBuilder sb; /** Holds whether we are currently recording characters or not. */ private boolean recording; /** * Constructs an empty character recorder of fixed size currently * not recording. See {@link #RECORDING_BUFFER_SIZE} for the size. */ public CharacterRecorder() { sb = new StringBuilder(RECORDING_BUFFER_SIZE); recording = false; } /** * Constructs a character recorder of fixed size that is a copy * of the one provided. In particular it has the same recording * setting and the same contents. * * @param aCharacterRecorder the {@code CharacterRecorder} to copy */ public CharacterRecorder(CharacterRecorder aCharacterRecorder) { recording = aCharacterRecorder.recording; sb = new StringBuilder(RECORDING_BUFFER_SIZE); sb.append(aCharacterRecorder.getContent()); } /** * Enables recording for incoming characters. The recording buffer is cleared * of content it may have contained. */ public void startRecording() { // This is very fast, no memory (re-) allocation will take place. sb.setLength(0); recording = true; } /** * Disables recording further characters. */ public void stopRecording() { recording = false; } /** * Records the {@code input} if recording is currently on and we * have space available in the buffer. If recording is not * currently on, this method will not perform any action. * * @param input the character to record */ public void maybeRecord(char input) { if (recording && (sb.length() < RECORDING_BUFFER_SIZE)) { sb.append(input); } } /** * Empties the underlying storage but does not change the recording * state [i.e whether we are recording or not incoming characters]. */ public void clear() { sb.setLength(0); } /** * Empties the underlying storage and resets the recording indicator * to indicate we are not recording currently. */ public void reset() { clear(); recording = false; } /** * Returns the characters recorded in a {@code String} form. This * method has no side-effects, the characters remain stored as is. * * @return the contents in a {@code String} form */ public String getContent() { return sb.toString(); } /** * Returns whether or not we are currently recording incoming characters. * * @return {@code true} if we are recording, {@code false} otherwise */ public boolean isRecording() { return recording; } /** * Returns the full state of the object in a human readable form. The * format of the returned {@code String} is not specified and is * subject to change. * * @return the full state of this object */ @Override public String toString() { return String.format("In recording: %s; Value: %s", isRecording(), sb.toString()); } }