public static int decodeConsecutiveOctets(StringBuilder dest, String s, int start)
  {
    final int n = s.length();

    if (start >= n)
    {
      throw new IllegalArgumentException("Cannot decode from index " + start + " of a length-" + n + " string");
    }

    if (s.charAt(start) != '%')
    {
      throw new IllegalArgumentException("Must begin decoding from a percent-escaped octet, but found '" + s.charAt(start) + "'");
    }

    if (start + 3 < n && s.charAt(start + 3) == '%')
    {
      // If there are multiple consecutive encoded octets, decode all into bytes
      ByteBuffer bb = decodeConsecutiveOctets(s, start);
      int numCharsConsumed = bb.limit() * 3;
      // Decode the bytes into a string
      decodeBytes(dest, bb);
      return numCharsConsumed;
    }
    else if (start + 2 < n)
    {
      // Else, decode just one octet
      byte b = decodeOctet(s, start + 1);
      decodeByte(dest, b);
      return 3;
    }

    throw new IllegalArgumentException("Malformed percent-encoded octet at index " + start);
  }
@Test(dataProvider = "invalidConsecutiveOctetData")
  public void testDecodeInvalidConsecutiveOctets(String encoded, int startIndex, String expectedErrorMessage)
  {
    IllegalArgumentException exception = null;

    try
    {
      URIDecoderUtils.decodeConsecutiveOctets(new StringBuilder(), encoded, startIndex);
    }
    catch (IllegalArgumentException e)
    {
      exception = e;
    }

    Assert.assertNotNull(exception, "Expected exception when decoding consecutive bytes for string \"" + encoded + "\".");
    Assert.assertEquals(exception.getMessage(), expectedErrorMessage, "Unexpected error message during decoding.");
  }