/* * Copyright (c) 2016 Couchbase, 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.couchbase.client.core.endpoint.util; import io.netty.buffer.ByteBuf; /** * An helper class providing utility methods to deal with parsing of structured * data (like JSON) inside a {@link ByteBuf} buffer. * * @author Simon Baslé * @since 1.1 */ public class ByteBufJsonHelper { /** * Shorthand for {@link ByteBuf#bytesBefore(byte)} with a simple char c, * finds the number of bytes until next occurrence of * the character c from the current readerIndex() in buf. * * @param buf the {@link ByteBuf buffer} to look into. * @param c the character to search for. * @return the number of bytes before the character or -1 if not found. * @see ByteBuf#bytesBefore(byte) */ public static final int findNextChar(ByteBuf buf, char c) { return buf.bytesBefore((byte) c); } /** * Find the number of bytes until next occurrence of the character c * from the current {@link ByteBuf#readerIndex() readerIndex} in buf, * with the twist that if this occurrence is prefixed by the prefix * character, we try to find another occurrence. * * @param buf the {@link ByteBuf buffer} to look into. * @param c the character to search for. * @param prefix the character to trigger a retry. * @return the position of the first occurrence of c that is not prefixed by prefix * or -1 if none found. */ public static final int findNextCharNotPrefixedBy(ByteBuf buf, char c, char prefix) { int found = buf.bytesBefore((byte) c); if (found < 1) { return found; } else { int from; while (found > -1 && (char) buf.getByte( buf.readerIndex() + found - 1) == prefix) { //advance from from = buf.readerIndex() + found + 1; //search again int next = buf.bytesBefore(from, buf.readableBytes() - from + buf.readerIndex(), (byte) c); if (next == -1) { return -1; } else { found += next + 1; } } return found; } } /** * Finds the position of the correct closing character, taking into account the fact that before the correct one, * other sub section with same opening and closing characters can be encountered. * * This implementation starts for the current {@link ByteBuf#readerIndex() readerIndex}. * * @param buf the {@link ByteBuf} where to search for the end of a section enclosed in openingChar and closingChar. * @param openingChar the section opening char, used to detect a sub-section. * @param closingChar the section closing char, used to detect the end of a sub-section / this section. * @return the section closing position or -1 if not found. */ public static int findSectionClosingPosition(ByteBuf buf, char openingChar, char closingChar) { return buf.forEachByte(new ClosingPositionBufProcessor(openingChar, closingChar, true)); } /** * Finds the position of the split character, taking into account the fact that the character * could be found escaped in strings (such occurrences are ignored). * * This implementation starts for the current {@link ByteBuf#readerIndex() readerIndex}. * * @param buf the {@link ByteBuf} where to search for the split character. * @param splitChar the split character to detect. * @return the split character position or -1 if not found. */ public static final int findSplitPosition(ByteBuf buf, char splitChar) { return buf.forEachByte(new SplitPositionBufProcessor(splitChar, true)); } /** * Finds the position of the correct closing character, taking into account the fact that before the correct one, * other sub section with same opening and closing characters can be encountered. * * This implementation starts for the current {@link ByteBuf#readerIndex() readerIndex} + startOffset. * * @param buf the {@link ByteBuf} where to search for the end of a section enclosed in openingChar and closingChar. * @param startOffset the offset at which to start reading (from buffer's readerIndex). * @param openingChar the section opening char, used to detect a sub-section. * @param closingChar the section closing char, used to detect the end of a sub-section / this section. * @return the section closing position or -1 if not found. */ public static int findSectionClosingPosition(ByteBuf buf, int startOffset, char openingChar, char closingChar) { int from = buf.readerIndex() + startOffset; int length = buf.writerIndex() - from; if (length < 0) { throw new IllegalArgumentException("startOffset must not go beyond the readable byte length of the buffer"); } return buf.forEachByte(from, length, new ClosingPositionBufProcessor(openingChar, closingChar, true)); } }