001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.javamail.store.imap.connection;
019
020 import java.io.ByteArrayOutputStream;
021
022 /**
023 * Simple extension to the ByteArrayOutputStream to allow inspection
024 * of the data while it is being accumulated.
025 */
026 public class IMAPResponseBuffer extends ByteArrayOutputStream {
027
028 public IMAPResponseBuffer() {
029 super();
030 }
031
032
033 /**
034 * Read a character from the byte array output stream buffer
035 * at the give position.
036 *
037 * @param index The requested index.
038 *
039 * @return The byte at the target index, or -1 if the index is out of
040 * bounds.
041 */
042 public int read(int index) {
043 if (index >= size()) {
044 return -1;
045 }
046 return buf[index];
047 }
048
049 /**
050 * Read a buffer of data from the output stream's accumulator
051 * buffer. This will copy the data into a target byte arrain.
052 *
053 * @param buffer The target byte array for returning the data.
054 * @param offset The offset of the source data within the output stream buffer.
055 * @param length The desired length.
056 *
057 * @return The count of bytes transferred into the buffer.
058 */
059 public int read(byte[] buffer, int offset, int length) {
060
061 int available = size() - offset;
062 length = Math.min(length, available);
063 // nothing to return? quit now.
064 if (length <= 0) {
065 return 0;
066 }
067 System.arraycopy(buf, offset, buffer, 0, length);
068 return length;
069 }
070
071 /**
072 * Search backwards through the buffer for a given byte.
073 *
074 * @param target The search character.
075 *
076 * @return The index relative to the buffer start of the given byte.
077 * Returns -1 if not found.
078 */
079 public int lastIndex(byte target) {
080 for (int i = size() - 1; i > 0; i--) {
081 if (buf[i] == target) {
082 return i;
083 }
084 }
085 return -1;
086 }
087
088
089 /**
090 * Return the last byte written to the output stream. Returns
091 * -1 if the stream is empty.
092 *
093 * @return The last byte written (or -1 if the stream is empty).
094 */
095 public int lastByte() {
096 if (size() > 0) {
097 return buf[size() - 1];
098 }
099 return -1;
100 }
101
102
103 /**
104 * Retrieve an IMAP literal length value from the buffer. We
105 * have a literal length value IFF the last characters written
106 * to the buffer have the form "{nnnn}". This returns the
107 * integer value of the info inside the curly braces. Returns -1
108 * if a valid literal length is not found.
109 *
110 * @return A literal length value, or -1 if we don't have a literal
111 * signature at the end.
112 */
113 public int getLiteralLength() {
114 // was the last byte before the line break the close of the literal length?
115 if (lastByte() == '}') {
116 // locate the length start
117 int literalStart = lastIndex((byte)'{');
118 // no matching start, this can't be a literal.
119 if (literalStart == -1) {
120 return -1;
121 }
122
123 String lenString = new String(buf, literalStart + 1, size() - (literalStart + 2));
124 try {
125 return Integer.parseInt(lenString);
126 } catch (NumberFormatException e) {
127 e.printStackTrace();
128 }
129 }
130 // not a literal
131 return -1;
132 }
133 }
134