下面列出了java.nio.ByteBuffer#mark ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
void processBuffer(ByteBuffer buf) {
// scan for newline
ByteBuffer line = buf.slice();
int i = 0;
buf.mark();
while(buf.remaining() > 0) {
i++;
if(buf.get() == '\n') {
buf.mark();
line.limit(i-1);
line(line);
i = 0;
line = buf.slice();
}
}
buf.reset();
}
private static String toHexdump(ByteBuffer bb) {
List<String> words = new ArrayList<>();
int i = 0;
bb.mark();
while (bb.hasRemaining()) {
if (i % 2 == 0) {
words.add("");
}
byte b = bb.get();
String hex = Integer.toHexString(256 + Byte.toUnsignedInt(b)).substring(1);
words.set(i / 2, words.get(i / 2) + hex);
i++;
}
bb.reset();
return words.stream().collect(Collectors.joining(" "));
}
@Test
public void testDirectReadFullyPosition() throws Exception {
ByteBuffer readBuffer = ByteBuffer.allocateDirect(10);
readBuffer.position(3);
readBuffer.mark();
FSDataInputStream hadoopStream = new FSDataInputStream(new MockHadoopInputStream(2, 3, 3));
MockBufferReader reader = new MockBufferReader(hadoopStream);
H2SeekableInputStream.readFully(reader, readBuffer);
Assert.assertEquals(10, readBuffer.position());
Assert.assertEquals(10, readBuffer.limit());
H2SeekableInputStream.readFully(reader, readBuffer);
Assert.assertEquals(10, readBuffer.position());
Assert.assertEquals(10, readBuffer.limit());
readBuffer.reset();
Assert.assertEquals("Buffer contents should match",
ByteBuffer.wrap(TEST_ARRAY, 0, 7), readBuffer);
}
private int findDesigBuf(ByteBuffer in, byte[][] desigs) {
if (desigs == null) return -1;
int i = 0;
while (i < desigs.length) {
if (desigs[i] != null && in.remaining() >= desigs[i].length) {
int j = 0;
in.mark();
while (j < desigs[i].length && in.get() == desigs[i][j]) { j++; }
if (j == desigs[i].length)
return i;
in.reset();
}
i++;
}
return -1;
}
static void test(String expectedCharset, byte[] input) throws Exception {
Charset cs = Charset.forName("x-JISAutoDetect");
CharsetDecoder autoDetect = cs.newDecoder();
Charset cs2 = Charset.forName(expectedCharset);
CharsetDecoder decoder = cs2.newDecoder();
ByteBuffer bb = ByteBuffer.allocate(128);
CharBuffer charOutput = CharBuffer.allocate(128);
CharBuffer charExpected = CharBuffer.allocate(128);
bb.put(input);
bb.flip();
bb.mark();
CoderResult result = autoDetect.decode(bb, charOutput, true);
checkCoderResult(result);
charOutput.flip();
String actual = charOutput.toString();
bb.reset();
result = decoder.decode(bb, charExpected, true);
checkCoderResult(result);
charExpected.flip();
String expected = charExpected.toString();
check(actual.equals(expected),
String.format("actual=%s expected=%s", actual, expected));
}
/**
* Detects the object type of an RLP encoded object. Note that it does not modify the read position in the ByteBuffer.
*
*
* @param bb ByteBuffer that contains RLP encoded object
* @return object type: EthereumUtil.RLP_OBJECTTYPE_ELEMENT or EthereumUtil.RLP_OBJECTTYPE_LIST or EthereumUtil.RLP_OBJECTTYPE_INVALID
*/
public static int detectRLPObjectType(ByteBuffer bb) {
bb.mark();
byte detector = bb.get();
int unsignedDetector=detector & 0xFF;
int result = EthereumUtil.RLP_OBJECTTYPE_INVALID;
if (unsignedDetector<=0x7f) {
result=EthereumUtil.RLP_OBJECTTYPE_ELEMENT;
} else
if ((unsignedDetector>=0x80) && (unsignedDetector<=0xb7)) {
result=EthereumUtil.RLP_OBJECTTYPE_ELEMENT;
} else
if ((unsignedDetector>=0xb8) && (unsignedDetector<=0xbf)) {
result=EthereumUtil.RLP_OBJECTTYPE_ELEMENT;
}
else
if ((unsignedDetector>=0xc0) && (unsignedDetector<=0xf7)) {
result=EthereumUtil.RLP_OBJECTTYPE_LIST;
} else
if ((unsignedDetector>=0xf8) && (unsignedDetector<=0xff)) {
result=EthereumUtil.RLP_OBJECTTYPE_LIST;
}
else {
result=EthereumUtil.RLP_OBJECTTYPE_INVALID;
LOG.error("Invalid RLP object type. Internal error or not RLP Data");
}
bb.reset();
return result;
}
@NonNull
private static BitBuffer create64BitFloatByteBuffer() {
double[] data = new double[2];
data[0] = 2.0f;
data[1] = 3.14f;
ByteBuffer byb = ByteBuffer.allocate(128);
byb.order(ByteOrder.nativeOrder());
byb.mark();
byb.putDouble(data[0]);
byb.putDouble(data[1]);
byb.reset();
BitBuffer bb = new BitBuffer(byb);
return bb;
}
/**
* finds the location of specified substring.
* @param value
* @param substring
* @return
*/
public static int findText(String value, String substring) {
//This method is copied from Hive's GenericUDFUtils.findText()
int start = 0;
byte[] valueBytes = value.getBytes();
byte[] substrBytes = substring.getBytes();
ByteBuffer src = ByteBuffer.wrap(valueBytes, 0, valueBytes.length);
ByteBuffer tgt = ByteBuffer.wrap(substrBytes, 0, substrBytes.length);
byte b = tgt.get();
src.position(start);
while (src.hasRemaining()) {
if (b == src.get()) { // matching first byte
src.mark(); // save position in loop
tgt.mark(); // save position in target
boolean found = true;
int pos = src.position() - 1;
while (tgt.hasRemaining()) {
if (!src.hasRemaining()) { // src expired first
tgt.reset();
src.reset();
found = false;
break;
}
if (!(tgt.get() == src.get())) {
tgt.reset();
src.reset();
found = false;
break; // no match
}
}
if (found) {
return pos;
}
}
}
return -1; // not found
}
private List<XmlAttribute> enumerateAttributes(ByteBuffer buffer) {
List<XmlAttribute> result = new ArrayList<>(attributeCount);
int offset = this.offset + getHeaderSize() + attributeStart;
int endOffset = offset + XmlAttribute.SIZE * attributeCount;
buffer.mark();
buffer.position(offset);
while (offset < endOffset) {
result.add(XmlAttribute.create(buffer, this));
offset += XmlAttribute.SIZE;
}
buffer.reset();
return result;
}
@Override
protected void processBuffer(final SocketChannel socketChannel, final ByteBuffer socketBuffer)
throws InterruptedException, IOException {
// get total bytes in buffer
final int total = socketBuffer.remaining();
final InetAddress sender = socketChannel.socket().getInetAddress();
try {
// go through the buffer parsing the RELP command
for (int i = 0; i < total; i++) {
byte currByte = socketBuffer.get();
// if we found the end of a frame, handle the frame and mark the buffer
if (decoder.process(currByte)) {
final RELPFrame frame = decoder.getFrame();
logger.debug("Received RELP frame with transaction {} and command {}",
new Object[] {frame.getTxnr(), frame.getCommand()});
final SocketChannelResponder responder = new SocketChannelResponder(socketChannel);
frameHandler.handle(frame, responder, sender.toString());
socketBuffer.mark();
}
}
logger.debug("Done processing buffer");
} catch (final RELPFrameException rfe) {
logger.error("Error reading RELP frames due to {}", new Object[] {rfe.getMessage()}, rfe);
// if an invalid frame or bad data was sent then the decoder will be left in a
// corrupted state, so lets close the connection and cause the client to re-establish
dispatcher.completeConnection(key);
}
}
@Test
public void testStringValues() throws Exception{
String str="{\"foo\":\"Hello World!\"}";
LazyObject obj1=new LazyObject(str);
Template t=obj1.extractTemplate();
ByteBuffer buf=ByteBuffer.allocate(4096);
buf.mark();
DictionaryCache dict=new DictionaryCache(100,2);
obj1.writeTemplateValues(buf,dict);
// System.out.println(str.length()+" vs "+buf.position());
buf.reset();
// System.out.println(t.read(buf,dict));
LazyObject obj2=(LazyObject)LazyElement.readFromTemplate(t,buf,dict);
assertEquals(obj1.getString("foo"),obj2.getString("foo"));
}
public static char[] readUtf8(ByteBuf byteBuf, int length) {
CharsetDecoder charsetDecoder = CharsetUtil.UTF_8.newDecoder();
int en = (int) (length * (double) charsetDecoder.maxCharsPerByte());
char[] ca = new char[en];
CharBuffer charBuffer = CharBuffer.wrap(ca);
ByteBuffer byteBuffer =
byteBuf.nioBufferCount() == 1
? byteBuf.internalNioBuffer(byteBuf.readerIndex(), length)
: byteBuf.nioBuffer(byteBuf.readerIndex(), length);
byteBuffer.mark();
try {
CoderResult cr = charsetDecoder.decode(byteBuffer, charBuffer, true);
if (!cr.isUnderflow()) cr.throwException();
cr = charsetDecoder.flush(charBuffer);
if (!cr.isUnderflow()) cr.throwException();
byteBuffer.reset();
byteBuf.skipBytes(length);
return safeTrim(charBuffer.array(), charBuffer.position());
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new IllegalStateException("unable to decode char array from the given buffer", x);
}
}
/**
* Calculate checksums for the given data.
*
* The 'mark' of the ByteBuffer parameters may be modified by this function,
* but the position is maintained.
*
* @param data the DirectByteBuffer pointing to the data to checksum.
* @param checksums the DirectByteBuffer into which checksums will be
* stored. Enough space must be available in this
* buffer to put the checksums.
*/
public void calculateChunkedSums(ByteBuffer data, ByteBuffer checksums) {
if (type.size == 0) return;
if (data.hasArray() && checksums.hasArray()) {
calculateChunkedSums(data.array(), data.arrayOffset() + data.position(), data.remaining(),
checksums.array(), checksums.arrayOffset() + checksums.position());
return;
}
if (NativeCrc32.isAvailable()) {
NativeCrc32.calculateChunkedSums(bytesPerChecksum, type.id,
checksums, data);
return;
}
data.mark();
checksums.mark();
try {
byte[] buf = new byte[bytesPerChecksum];
while (data.remaining() > 0) {
int n = Math.min(data.remaining(), bytesPerChecksum);
data.get(buf, 0, n);
summer.reset();
summer.update(buf, 0, n);
checksums.putInt((int)summer.getValue());
}
} finally {
data.reset();
checksums.reset();
}
}
private void runGCMWithSeparateBuffers(int mode, ByteBuffer buffer,
ByteBuffer textBB, int txtOffset, int dataLength,
AlgorithmParameters params) throws Exception {
// take offset into account
textBB.position(txtOffset);
textBB.mark();
// first, generate the cipher text at an allocated buffer
Cipher cipher = createCipher(mode, params);
cipher.updateAAD(buffer);
buffer.flip();
ByteBuffer outBB = ByteBuffer.allocateDirect(
cipher.getOutputSize(dataLength));
cipher.doFinal(textBB, outBB);// get cipher text in outBB
outBB.flip();
// restore positions
textBB.reset();
// next, generate cipher text again in a buffer that shares content
Cipher anotherCipher = createCipher(mode, params);
anotherCipher.updateAAD(buffer);
buffer.flip();
ByteBuffer buf2 = textBB.duplicate(); // buf2 shares textBuf context
buf2.limit(txtOffset + anotherCipher.getOutputSize(dataLength));
int dataProcessed2 = anotherCipher.doFinal(textBB, buf2);
buf2.position(txtOffset);
buf2.limit(txtOffset + dataProcessed2);
if (!buf2.equals(outBB)) {
throw new RuntimeException(
"Two results are not equal, mode:" + mode);
}
}
public static String stringUtf8( ByteBuffer bytes ) throws InvalidDataException {
CharsetDecoder decode = Charset.forName( "UTF8" ).newDecoder();
decode.onMalformedInput( codingErrorAction );
decode.onUnmappableCharacter( codingErrorAction );
// decode.replaceWith( "X" );
String s;
try {
bytes.mark();
s = decode.decode( bytes ).toString();
bytes.reset();
} catch ( CharacterCodingException e ) {
throw new InvalidDataException( CloseFrame.NO_UTF8, e );
}
return s;
}
/**
* Parses the Bitcoin transactions in a byte buffer.
*
* @param rawByteBuffer ByteBuffer from which the transactions have to be parsed
* @param noOfTransactions Number of expected transactions
*
* @return Array of transactions
*
*
*/
public List<BitcoinTransaction> parseTransactions(ByteBuffer rawByteBuffer,long noOfTransactions) {
ArrayList<BitcoinTransaction> resultTransactions = new ArrayList<>((int)noOfTransactions);
// read all transactions from ByteBuffer
for (int k=0;k<noOfTransactions;k++) {
// read version
int currentVersion=rawByteBuffer.getInt();
// read inCounter
byte[] currentInCounterVarInt=BitcoinUtil.convertVarIntByteBufferToByteArray(rawByteBuffer);
long currentNoOfInputs=BitcoinUtil.getVarInt(currentInCounterVarInt);
boolean segwit=false;
byte marker=1;
byte flag=0;
// check segwit marker
if (currentNoOfInputs==0) {
// this seems to be segwit - lets be sure
// check segwit flag
rawByteBuffer.mark();
byte segwitFlag = rawByteBuffer.get();
if (segwitFlag!=0) {
// load the real number of inputs
segwit=true;
marker=0;
flag=segwitFlag;
currentInCounterVarInt=BitcoinUtil.convertVarIntByteBufferToByteArray(rawByteBuffer);
currentNoOfInputs=BitcoinUtil.getVarInt(currentInCounterVarInt);
} else {
LOG.warn("It seems a block with 0 transaction inputs was found");
rawByteBuffer.reset();
}
}
// read inputs
List<BitcoinTransactionInput> currentTransactionInput = parseTransactionInputs(rawByteBuffer, currentNoOfInputs);
// read outCounter
byte[] currentOutCounterVarInt=BitcoinUtil.convertVarIntByteBufferToByteArray(rawByteBuffer);
long currentNoOfOutput=BitcoinUtil.getVarInt(currentOutCounterVarInt);
// read outputs
List<BitcoinTransactionOutput> currentTransactionOutput = parseTransactionOutputs(rawByteBuffer,currentNoOfOutput);
List<BitcoinScriptWitnessItem> currentListOfTransactionSegwits;
if (segwit) {
// read segwit data
// for each transaction input there is at least some segwit data item
// read scriptWitness size
currentListOfTransactionSegwits=new ArrayList<>();
for (int i=0;i<currentNoOfInputs;i++) {
// get no of witness items for input
byte[] currentWitnessCounterVarInt=BitcoinUtil.convertVarIntByteBufferToByteArray(rawByteBuffer);
long currentNoOfWitnesses=BitcoinUtil.getVarInt(currentWitnessCounterVarInt);
List<BitcoinScriptWitness> currentTransactionSegwit = new ArrayList<>((int)currentNoOfWitnesses);
for (int j=0;j<(int)currentNoOfWitnesses;j++) {
// read size of segwit script
byte[] currentTransactionSegwitScriptLength=BitcoinUtil.convertVarIntByteBufferToByteArray(rawByteBuffer);
long currentTransactionSegwitScriptSize=BitcoinUtil.getVarInt(currentTransactionSegwitScriptLength);
int currentTransactionSegwitScriptSizeInt= (int)currentTransactionSegwitScriptSize;
// read segwit script
byte[] currentTransactionInSegwitScript=new byte[currentTransactionSegwitScriptSizeInt];
rawByteBuffer.get(currentTransactionInSegwitScript,0,currentTransactionSegwitScriptSizeInt);
// add segwit
currentTransactionSegwit.add(new BitcoinScriptWitness(currentTransactionSegwitScriptLength,currentTransactionInSegwitScript));
}
currentListOfTransactionSegwits.add(new BitcoinScriptWitnessItem(currentWitnessCounterVarInt,currentTransactionSegwit));
}
} else {
currentListOfTransactionSegwits=new ArrayList<>();
}
// lock_time
int currentTransactionLockTime = rawByteBuffer.getInt();
// add transaction
resultTransactions.add(new BitcoinTransaction(marker,flag,currentVersion,currentInCounterVarInt,currentTransactionInput,currentOutCounterVarInt,currentTransactionOutput,currentListOfTransactionSegwits,currentTransactionLockTime));
}
return resultTransactions;
}
/**
* Verify that the given checksums match the given data.
*
* The 'mark' of the ByteBuffer parameters may be modified by this function,.
* but the position is maintained.
*
* @param data the DirectByteBuffer pointing to the data to verify.
* @param checksums the DirectByteBuffer pointing to a series of stored
* checksums
* @param fileName the name of the file being read, for error-reporting
* @param basePos the file position to which the start of 'data' corresponds
* @throws ChecksumException if the checksums do not match
*/
public void verifyChunkedSums(ByteBuffer data, ByteBuffer checksums,
String fileName, long basePos)
throws ChecksumException {
if (type.size == 0) return;
if (data.hasArray() && checksums.hasArray()) {
verifyChunkedSums(
data.array(), data.arrayOffset() + data.position(), data.remaining(),
checksums.array(), checksums.arrayOffset() + checksums.position(),
fileName, basePos);
return;
}
if (NativeCrc32.isAvailable()) {
NativeCrc32.verifyChunkedSums(bytesPerChecksum, type.id, checksums, data,
fileName, basePos);
return;
}
int startDataPos = data.position();
data.mark();
checksums.mark();
try {
byte[] buf = new byte[bytesPerChecksum];
byte[] sum = new byte[type.size];
while (data.remaining() > 0) {
int n = Math.min(data.remaining(), bytesPerChecksum);
checksums.get(sum);
data.get(buf, 0, n);
summer.reset();
summer.update(buf, 0, n);
int calculated = (int)summer.getValue();
int stored = (sum[0] << 24 & 0xff000000) |
(sum[1] << 16 & 0xff0000) |
(sum[2] << 8 & 0xff00) |
sum[3] & 0xff;
if (calculated != stored) {
long errPos = basePos + data.position() - startDataPos - n;
throw new ChecksumException(
"Checksum error: "+ fileName + " at "+ errPos +
" exp: " + stored + " got: " + calculated, errPos);
}
}
} finally {
data.reset();
checksums.reset();
}
}
@Override
public void unpack(ByteBuffer buf) throws IOException {
// Mark current position.
buf.mark();
int skipped=0;
short postlen=0;
int colheight=0;
int len=0; // How long is the WHOLE column, until the final FF?
int postno=0; // Actual number of posts.
int topdelta=0;
int prevdelta=-1; // HACK for DeepSea tall patches.
// Scan every byte until we encounter an 0xFF which definitively marks the end of a column.
while((topdelta=C2JUtils.toUnsignedByte(buf.get()))!=0xFF){
// From the wiki:
// A column's topdelta is compared to the previous column's topdelta
// (or to -1 if there is no previous column in this row). If the new
// topdelta is lesser than the previous, it is interpreted as a tall
// patch and the two values are added together, the sum serving as the
// current column's actual offset.
int tmp=topdelta;
if (topdelta<prevdelta) {
topdelta+=prevdelta;
}
prevdelta=tmp;
// First byte of a post should be its "topdelta"
guesspostdeltas[postno]=(short)topdelta;
guesspostofs[postno]=skipped+3; // 0 for first post
// Read one more byte...this should be the post length.
postlen=(short)C2JUtils.toUnsignedByte(buf.get());
guesspostlens[postno++]=(short) (postlen);
// So, we already read 2 bytes (topdelta + length)
// Two further bytes are padding so we can safely skip 2+2+postlen bytes until the next post
skipped+=4+postlen;
buf.position(buf.position()+2+postlen);
// Obviously, this adds to the height of the column, which might not be equal to the patch that
// contains it.
colheight+=postlen;
}
// Skip final padding byte ?
skipped++;
len = finalizeStatus(skipped, colheight, postno);
// Go back...and read the raw data. That's what will actually be used in the renderer.
buf.reset();
buf.get(data, 0, len);
}
static Document parseByteData(ByteBuffer byteData, String charsetName, String baseUri, Parser parser) {
String docData;
Document doc = null;
// look for BOM - overrides any other header or input
byteData.mark();
byte[] bom = new byte[4];
if (byteData.remaining() >= bom.length) {
byteData.get(bom);
byteData.rewind();
}
if (bom[0] == 0x00 && bom[1] == 0x00 && bom[2] == (byte) 0xFE && bom[3] == (byte) 0xFF || // BE
bom[0] == (byte) 0xFF && bom[1] == (byte) 0xFE && bom[2] == 0x00 && bom[3] == 0x00) { // LE
charsetName = "UTF-32"; // and I hope it's on your system
} else if (bom[0] == (byte) 0xFE && bom[1] == (byte) 0xFF || // BE
bom[0] == (byte) 0xFF && bom[1] == (byte) 0xFE) {
charsetName = "UTF-16"; // in all Javas
} else if (bom[0] == (byte) 0xEF && bom[1] == (byte) 0xBB && bom[2] == (byte) 0xBF) {
charsetName = "UTF-8"; // in all Javas
byteData.position(3); // 16 and 32 decoders consume the BOM to determine be/le; utf-8 should be consumed
}
if (charsetName == null) { // determine from meta. safe parse as UTF-8
// look for <meta http-equiv="Content-Type" content="text/html;charset=gb2312"> or HTML5 <meta charset="gb2312">
docData = Charset.forName(defaultCharset).decode(byteData).toString();
doc = parser.parseInput(docData, baseUri);
Element meta = doc.select("meta[http-equiv=content-type], meta[charset]").first();
if (meta != null) { // if not found, will keep utf-8 as best attempt
String foundCharset = null;
if (meta.hasAttr("http-equiv")) {
foundCharset = getCharsetFromContentType(meta.attr("content"));
}
if (foundCharset == null && meta.hasAttr("charset")) {
try {
if (Charset.isSupported(meta.attr("charset"))) {
foundCharset = meta.attr("charset");
}
} catch (IllegalCharsetNameException e) {
foundCharset = null;
}
}
if (foundCharset != null && foundCharset.length() != 0 && !foundCharset.equals(defaultCharset)) { // need to re-decode
foundCharset = foundCharset.trim().replaceAll("[\"']", "");
charsetName = foundCharset;
byteData.rewind();
docData = Charset.forName(foundCharset).decode(byteData).toString();
doc = null;
}
}
} else { // specified by content type header (or by user on file load)
Validate.notEmpty(charsetName, "Must set charset arg to character set of file to parse. Set to null to attempt to detect from HTML");
docData = Charset.forName(charsetName).decode(byteData).toString();
}
if (doc == null) {
doc = parser.parseInput(docData, baseUri);
doc.outputSettings().charset(charsetName);
}
return doc;
}
/**
* Returns {@link ProbeResult#SUPPORTED} if the given storage appears to begin with an expected keyword
* Returning {@code SUPPORTED} from this method does not guarantee that reading or writing will succeed,
* only that there appears to be a reasonable chance of success based on a brief inspection of the storage
* header.
*
* @param connector information about the storage (URL, stream, JDBC connection, <i>etc</i>).
* @return {@link ProbeResult#SUPPORTED} if the given storage seems to be readable.
* @throws DataStoreException if an I/O or SQL error occurred.
*/
@SuppressWarnings("null")
public final ProbeResult probeContent(final StorageConnector connector) throws DataStoreException {
char[] keyword = null;
int pos = 0;
try {
final ByteBuffer buffer = connector.getStorageAs(ByteBuffer.class);
final Reader reader;
if (buffer != null) {
buffer.mark();
reader = null;
} else {
// User gave us explicitly a Reader (e.g. a StringReader wrapping a String instance).
reader = connector.getStorageAs(Reader.class);
if (reader == null) {
return ProbeResult.UNSUPPORTED_STORAGE;
}
reader.mark(READ_AHEAD_LIMIT);
}
/*
* Ignore leading spaces and comments if any, then get a keyword no longer than 'maxLength'.
* That keyword shall be followed by [ or (, ignoring whitespaces.
*/
int c;
while ((c = nextAfterSpaces(buffer, reader)) == COMMENT) {
toEndOfLine(buffer, reader);
}
int s;
if ((s = isKeywordChar(c)) >= ACCEPT) {
keyword = new char[maxLength];
do {
if (s == ACCEPT) {
if (pos >= keyword.length) {
pos = 0; // Keyword too long.
break;
}
keyword[pos++] = (char) c;
}
c = (buffer == null) ? IOUtilities.readCodePoint(reader) : buffer.hasRemaining() ? (char) buffer.get() : -1;
} while ((s = isKeywordChar(c)) >= ACCEPT);
/*
* At this point we finished to read and store the keyword.
* Verify if the keyword is followed by a character that indicate a keyword end.
*/
if (Character.isWhitespace(c)) {
c = nextAfterSpaces(buffer, reader);
}
if (!isPostKeyword(c)) {
pos = 0;
}
}
if (buffer != null) {
buffer.reset();
} else {
reader.reset();
}
if (c < 0) {
return ProbeResult.INSUFFICIENT_BYTES;
}
} catch (IOException e) {
throw new DataStoreException(e);
}
return forKeyword(keyword, pos);
}