1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.geronimo.javamail.store.imap.connection;
19
20 import java.io.ByteArrayOutputStream;
21
22 /**
23 * Simple extension to the ByteArrayOutputStream to allow inspection
24 * of the data while it is being accumulated.
25 */
26 public class IMAPResponseBuffer extends ByteArrayOutputStream {
27
28 public IMAPResponseBuffer() {
29 super();
30 }
31
32
33 /**
34 * Read a character from the byte array output stream buffer
35 * at the give position.
36 *
37 * @param index The requested index.
38 *
39 * @return The byte at the target index, or -1 if the index is out of
40 * bounds.
41 */
42 public int read(int index) {
43 if (index >= size()) {
44 return -1;
45 }
46 return buf[index];
47 }
48
49 /**
50 * Read a buffer of data from the output stream's accumulator
51 * buffer. This will copy the data into a target byte arrain.
52 *
53 * @param buffer The target byte array for returning the data.
54 * @param offset The offset of the source data within the output stream buffer.
55 * @param length The desired length.
56 *
57 * @return The count of bytes transferred into the buffer.
58 */
59 public int read(byte[] buffer, int offset, int length) {
60
61 int available = size() - offset;
62 length = Math.min(length, available);
63 // nothing to return? quit now.
64 if (length <= 0) {
65 return 0;
66 }
67 System.arraycopy(buf, offset, buffer, 0, length);
68 return length;
69 }
70
71 /**
72 * Search backwards through the buffer for a given byte.
73 *
74 * @param target The search character.
75 *
76 * @return The index relative to the buffer start of the given byte.
77 * Returns -1 if not found.
78 */
79 public int lastIndex(byte target) {
80 for (int i = size() - 1; i > 0; i--) {
81 if (buf[i] == target) {
82 return i;
83 }
84 }
85 return -1;
86 }
87
88
89 /**
90 * Return the last byte written to the output stream. Returns
91 * -1 if the stream is empty.
92 *
93 * @return The last byte written (or -1 if the stream is empty).
94 */
95 public int lastByte() {
96 if (size() > 0) {
97 return buf[size() - 1];
98 }
99 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