ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/tomcat/util/buf/CharChunk.java

Path
ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/tomcat/util/buf/CharChunk.java
Status
scanned
Type
file
Name
CharChunk.java
Extension
.java
Programming language
Java
Mime type
text/plain
File type
ASCII text, with CRLF line terminators
Tag

      
    
Rootfs path

      
    
Size
17492 (17.1 KB)
MD5
05e5abcd463a139b6b5c5f6cf80b2d0b
SHA1
68d43077c3f034191f4e9e9055a8b7a7e9e6ea12
SHA256
b2da6901fb669b30fb9041d5c4d5d07bd3ea7cc96eaaa6918985b7ab9508f86c
SHA512

      
    
SHA1_git
44ceb395fec453f7fbcaeb678c829647349bce89
Is binary

      
    
Is text
True
Is archive

      
    
Is media

      
    
Is legal

      
    
Is manifest

      
    
Is readme

      
    
Is top level

      
    
Is key file

      
    
CharChunk.java | 17.1 KB |

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; import java.io.IOException; import java.io.Serial; /** * Utilities to manipulate char chunks. While String is the easiest way to manipulate chars ( search, substrings, etc), * it is known to not be the most efficient solution - Strings are designed as immutable and secure objects. */ public final class CharChunk extends AbstractChunk implements CharSequence { @Serial private static final long serialVersionUID = 1L; /** * Input interface, used when the buffer is empty. */ public interface CharInputChannel { /** * Read new characters. * * @return The number of characters read * * @throws IOException If an I/O error occurs during reading */ int realReadChars() throws IOException; } /** * When we need more space we'll either grow the buffer ( up to the limit ) or send it to a channel. */ public interface CharOutputChannel { /** * Send the bytes ( usually the internal conversion buffer ). Expect 8k output if the buffer is full. * * @param buf characters that will be written * @param off offset in the characters array * @param len length that will be written * * @throws IOException If an I/O occurs while writing the characters */ void realWriteChars(char[] buf, int off, int len) throws IOException; } // -------------------- // char[] private char[] buff; // transient as serialization is primarily for values via, e.g. JMX private transient CharInputChannel in = null; private transient CharOutputChannel out = null; /** * Creates a new, uninitialized CharChunk object. */ public CharChunk() { } public CharChunk(int initial) { allocate(initial, -1); } // -------------------- @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } // -------------------- Setup -------------------- public void allocate(int initial, int limit) { if (buff == null || buff.length < initial) { buff = new char[initial]; } setLimit(limit); start = 0; end = 0; isSet = true; hasHashCode = false; } /** * Sets the buffer to the specified sub array of characters. * * @param c the characters * @param off the start offset of the characters * @param len the length of the characters */ public void setChars(char[] c, int off, int len) { buff = c; start = off; end = start + len; isSet = true; hasHashCode = false; } /** * @return the buffer. */ public char[] getChars() { return getBuffer(); } /** * @return the buffer. */ public char[] getBuffer() { return buff; } /** * When the buffer is empty, read the data from the input channel. * * @param in The input channel */ public void setCharInputChannel(CharInputChannel in) { this.in = in; } /** * When the buffer is full, write the data to the output channel. Also used when large amount of data is appended. * If not set, the buffer will grow to the limit. * * @param out The output channel */ public void setCharOutputChannel(CharOutputChannel out) { this.out = out; } // -------------------- Adding data to the buffer -------------------- public void append(char c) throws IOException { makeSpace(1); int limit = getLimitInternal(); // couldn't make space if (end >= limit) { flushBuffer(); } buff[end++] = c; } public void append(CharChunk src) throws IOException { append(src.getBuffer(), src.getStart(), src.getLength()); } /** * Add data to the buffer. * * @param src Char array * @param off Offset * @param len Length * * @throws IOException Writing overflow data to the output channel failed */ public void append(char[] src, int off, int len) throws IOException { // will grow, up to limit makeSpace(len); int limit = getLimitInternal(); // Optimize on a common case. // If the buffer is empty and the source is going to fill up all the // space in buffer, may as well write it directly to the output, // and avoid an extra copy if (len == limit && end == start && out != null) { out.realWriteChars(src, off, len); return; } // if we are below the limit if (len <= limit - end) { System.arraycopy(src, off, buff, end, len); end += len; return; } // Need more space than we can afford, need to flush buffer. // The buffer is already at (or bigger than) limit. // Optimization: // If len-avail < length (i.e. after we fill the buffer with what we // can, the remaining will fit in the buffer) we'll just copy the first // part, flush, then copy the second part - 1 write and still have some // space for more. We'll still have 2 writes, but we write more on the first. if (len + end < 2 * limit) { /* * If the request length exceeds the size of the output buffer, flush the output buffer and then write the * data directly. We can't avoid 2 writes, but we can write more on the second */ int avail = limit - end; System.arraycopy(src, off, buff, end, avail); end += avail; flushBuffer(); System.arraycopy(src, off + avail, buff, end, len - avail); end += len - avail; } else { // len > buf.length + avail // long write - flush the buffer and write the rest // directly from source flushBuffer(); out.realWriteChars(src, off, len); } } /** * Append a string to the buffer. * * @param s The string * * @throws IOException Writing overflow data to the output channel failed */ public void append(String s) throws IOException { append(s, 0, s.length()); } /** * Append a string to the buffer. * * @param s The string * @param off Offset * @param len Length * * @throws IOException Writing overflow data to the output channel failed */ public void append(String s, int off, int len) throws IOException { if (s == null) { return; } // will grow, up to limit makeSpace(len); int limit = getLimitInternal(); int sOff = off; int sEnd = off + len; while (sOff < sEnd) { int d = Math.min(limit - end, sEnd - sOff); s.getChars(sOff, sOff + d, buff, end); sOff += d; end += d; if (end >= limit) { flushBuffer(); } } } // -------------------- Removing data from the buffer -------------------- public int subtract() throws IOException { if (checkEof()) { return -1; } return buff[start++]; } public int subtract(char[] dest, int off, int len) throws IOException { if (checkEof()) { return -1; } int n = Math.min(len, getLength()); System.arraycopy(buff, start, dest, off, n); start += n; return n; } private boolean checkEof() throws IOException { if ((end - start) == 0) { if (in == null) { return true; } return in.realReadChars() < 0; } return false; } /** * Send the buffer to the sink. Called by append() when the limit is reached. You can also call it explicitly to * force the data to be written. * * @throws IOException Writing overflow data to the output channel failed */ public void flushBuffer() throws IOException { // assert out!=null if (out == null) { throw new IOException( sm.getString("chunk.overflow", Integer.valueOf(getLimit()), Integer.valueOf(buff.length))); } out.realWriteChars(buff, start, end - start); end = start; } /** * Make space for len chars. If len is small, allocate a reserve space too. Never grow bigger than the limit or * {@link AbstractChunk#ARRAY_MAX_SIZE}. * * @param count The size */ public void makeSpace(int count) { int limit = getLimitInternal(); long newSize; long desiredSize = end + count; // Can't grow above the limit if (desiredSize > limit) { desiredSize = limit; } if (buff == null) { if (desiredSize < 256) { desiredSize = 256; // take a minimum } buff = new char[(int) desiredSize]; } // limit < buf.length (the buffer is already big) // or we already have space if (desiredSize <= buff.length) { return; } // grow in larger chunks if (desiredSize < 2L * buff.length) { newSize = buff.length * 2L; } else { newSize = buff.length * 2L + count; } if (newSize > limit) { newSize = limit; } char[] tmp = new char[(int) newSize]; // Some calling code assumes buffer will not be compacted System.arraycopy(buff, 0, tmp, 0, end); buff = tmp; } // -------------------- Conversion and getters -------------------- @Override public String toString() { if (isNull()) { return null; } else if (end - start == 0) { return ""; } return StringCache.toString(this); } public String toStringInternal() { return new String(buff, start, end - start); } // -------------------- equals -------------------- @Override public boolean equals(Object obj) { if (obj instanceof CharChunk) { return equals((CharChunk) obj); } return false; } /** * Compares the message bytes to the specified String object. * * @param s the String to compare * * @return <code>true</code> if the comparison succeeded, <code>false</code> otherwise */ public boolean equals(String s) { char[] c = buff; int len = end - start; if (c == null || len != s.length()) { return false; } int off = start; for (int i = 0; i < len; i++) { if (c[off++] != s.charAt(i)) { return false; } } return true; } /** * Compares the message bytes to the specified String object. * * @param s the String to compare * * @return <code>true</code> if the comparison succeeded, <code>false</code> otherwise */ public boolean equalsIgnoreCase(String s) { char[] c = buff; int len = end - start; if (c == null || len != s.length()) { return false; } int off = start; for (int i = 0; i < len; i++) { if (Ascii.toLower(c[off++]) != Ascii.toLower(s.charAt(i))) { return false; } } return true; } public boolean equals(CharChunk cc) { return equals(cc.getChars(), cc.getStart(), cc.getLength()); } public boolean equals(char[] b2, int off2, int len2) { char[] b1 = buff; if (b1 == null && b2 == null) { return true; } int len = end - start; if (len != len2 || b1 == null || b2 == null) { return false; } int off1 = start; while (len-- > 0) { if (b1[off1++] != b2[off2++]) { return false; } } return true; } /** * @return <code>true</code> if the message bytes starts with the specified string. * * @param s The string */ public boolean startsWith(String s) { char[] c = buff; int len = s.length(); if (c == null || len > end - start) { return false; } int off = start; for (int i = 0; i < len; i++) { if (c[off++] != s.charAt(i)) { return false; } } return true; } /** * Returns true if the buffer starts with the specified string. * * @param s the string * @param pos The position * * @return <code>true</code> if the start matches */ public boolean startsWithIgnoreCase(String s, int pos) { char[] c = buff; int len = s.length(); if (c == null || len + pos > end - start) { return false; } int off = start + pos; for (int i = 0; i < len; i++) { if (Ascii.toLower(c[off++]) != Ascii.toLower(s.charAt(i))) { return false; } } return true; } /** * @return <code>true</code> if the message bytes end with the specified string. * * @param s The string */ public boolean endsWith(String s) { char[] c = buff; int len = s.length(); if (c == null || len > end - start) { return false; } int off = end - len; for (int i = 0; i < len; i++) { if (c[off++] != s.charAt(i)) { return false; } } return true; } @Override protected int getBufferElement(int index) { return buff[index]; } public int indexOf(char c) { return indexOf(c, start); } /** * Returns the first instance of the given character in this CharChunk starting at the specified char. If the * character is not found, -1 is returned. <br> * * @param c The character * @param starting The start position * * @return The position of the first instance of the character or -1 if the character is not found. */ public int indexOf(char c, int starting) { int ret = indexOf(buff, start + starting, end, c); return (ret >= start) ? ret - start : -1; } /** * Returns the first instance of the given character in the given char array between the specified start and end. * <br> * * @param chars The array to search * @param start The point to start searching from in the array * @param end The point to stop searching in the array * @param s The character to search for * * @return The position of the first instance of the character or -1 if the character is not found. */ public static int indexOf(char[] chars, int start, int end, char s) { int offset = start; while (offset < end) { char c = chars[offset]; if (c == s) { return offset; } offset++; } return -1; } // -------------------- utils // Char sequence impl @Override public char charAt(int index) { return buff[index + start]; } @Override public CharSequence subSequence(int start, int end) { try { CharChunk result = (CharChunk) this.clone(); result.setStart(this.start + start); result.setEnd(this.start + end); return result; } catch (CloneNotSupportedException e) { // Cannot happen return null; } } @Override public int length() { return end - start; } }
Detected license expression
apache-2.0
Detected license expression (SPDX)
Apache-2.0
Percentage of license text
6.3
Copyrights

      
    
Holders

      
    
Authors

      
    
License detections License expression License expression SPDX
apache_2_0-4bde3f57-78aa-4201-96bf-531cba09e7de apache-2.0 Apache-2.0
URL Start line End line
http://www.apache.org/licenses/LICENSE-2.0 9 9