/* * Copyright (c) 2015-2016, Christoph Engelbert (aka noctarius) and * contributors. All rights reserved. * * 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.noctarius.tengi.spi.serialization.codec.impl.utf8; import com.noctarius.tengi.core.serialization.codec.Encoder; import java.io.UTFDataFormatException; class StringBasedUtfWriter extends AbstractBufferedUtfWriter { @Override public void writeShortUTF(Encoder encoder, String value, int beginIndex, int endIndex, byte[] buffer) throws Exception { int i; int c; int bufferPos = 0; int utfLengthLimit; int utfLength = calculateUtf8Length(value, beginIndex, endIndex); if (utfLength > 65535) { throw new UTFDataFormatException("encoded string too long:" + utfLength + " bytes"); } utfLengthLimit = utfLength; encoder.writeShort("length", (short) utfLength); if (buffer.length >= utfLengthLimit) { for (i = beginIndex; i < endIndex; i++) { c = value.charAt(i); if (!(c <= 0x007F && c >= 0x0001)) { break; } buffer[bufferPos++] = (byte) c; } for (; i < endIndex; i++) { c = value.charAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { // 0x0001 <= X <= 0x007F buffer[bufferPos++] = (byte) c; } else if (c > 0x07FF) { // 0x007F < X <= 0x7FFF buffer[bufferPos++] = (byte) (0xE0 | ((c >> 12) & 0x0F)); buffer[bufferPos++] = (byte) (0x80 | ((c >> 6) & 0x3F)); buffer[bufferPos++] = (byte) (0x80 | ((c) & 0x3F)); } else { // X == 0 or 0x007F < X < 0x7FFF buffer[bufferPos++] = (byte) (0xC0 | ((c >> 6) & 0x1F)); buffer[bufferPos++] = (byte) (0x80 | ((c) & 0x3F)); } } encoder.writeBytes("data", buffer, 0, bufferPos); } else { for (i = beginIndex; i < endIndex; i++) { c = value.charAt(i); if (!(c <= 0x007F && c >= 0x0001)) { break; } bufferPos = buffering(buffer, bufferPos, (byte) c, encoder); } for (; i < endIndex; i++) { c = value.charAt(i); if (c <= 0x007F && c >= 0x0001) { // 0x0001 <= X <= 0x007F bufferPos = buffering(buffer, bufferPos, (byte) c, encoder); } else if (c > 0x07FF) { // 0x007F < X <= 0x7FFF bufferPos = buffering(buffer, bufferPos, (byte) (0xE0 | ((c >> 12) & 0x0F)), encoder); bufferPos = buffering(buffer, bufferPos, (byte) (0x80 | ((c >> 6) & 0x3F)), encoder); bufferPos = buffering(buffer, bufferPos, (byte) (0x80 | ((c) & 0x3F)), encoder); } else { // X == 0 or 0x007F < X < 0x7FFF bufferPos = buffering(buffer, bufferPos, (byte) (0xC0 | ((c >> 6) & 0x1F)), encoder); bufferPos = buffering(buffer, bufferPos, (byte) (0x80 | ((c) & 0x3F)), encoder); } } int length = bufferPos % buffer.length; encoder.writeBytes("data", buffer, 0, length == 0 ? buffer.length : length); } } private int calculateUtf8Length(String value, int beginIndex, int endIndex) { int utfLength = 0; for (int i = beginIndex; i < endIndex; i++) { int c = value.charAt(i); if (c <= 0x007F && c >= 0x0001) { utfLength += 1; } else if (c > 0x07FF) { utfLength += 3; } else { utfLength += 2; } } return utfLength; } }