Retrieve a string value.

@param data byte array
@param offset offset into byte array
@return string value
333567
public static final String getString(byte[] data, int offset)
   {
      return getString(data, offset, data.length - offset);
   }
968759
def get_string_from_data(self, offset, data):
        """"""
        s = self.get_bytes_from_data(offset, data)
        end = s.find(b'\0')
        if end >= 0:
            s = s[:end]
        return s
720721
public static String hexDecode(final char[] data) {
        try {
            val result = Hex.decodeHex(data);
            return new String(result, StandardCharsets.UTF_8);
        } catch (final Exception e) {
            return null;
        }
    }
581523
public void setData(byte[] data, int offset)
	{
		if (offset < 0 || offset > data.length)
			throw new KNXIllegalArgumentException("illegal offset " + offset);
		final int size = data.length - offset;
		if (size == 0)
			throw new KNXIllegalArgumentException("data length " + size
				+ " < KNX data type width " + Math.max(1, getTypeSize()));
		this.data = new short[size];
		for (int i = 0; i < size; ++i)
			this.data[i] = ubyte(data[offset + i]);
	}
790281
public static String formatBytes (byte[] data) {
    // If the data exists, format it.
    if (data != null) {
      return formatBytes(data, 0, data.length, true);
    }
    // Otherwise, return an empty String as the overloaded method would have done.
    else {
      return "";
    }
  }
33172
public static byte[] invert(final byte[] data)	{
		for (int i = data.length; --i >= 0;) {
			data[i] = (byte)~data[i];
		}
		return data;
	}
753745
public byte[] getData(byte[] dst, int offset)
	{
		final int items = Math.min(data.length, dst.length - offset) / stringLength;
		final int end = items * stringLength;
		if (end == 0)
			logger.error("destination range has to be multiple of 14 bytes "
				+ "for KNX strings");
		for (int i = 0; i < end; ++i)
			dst[offset + i] = (byte) data[i];
		return dst;
	}

	/* (non-Javadoc)
	 * @see tuwien.auto.calimero.dptxlator.DPTXlator#getSubTypes()
	 */
	public final Map getSubTypes()
	{
		return types;
	}

	/**
	 * @return the subtypes of the string translator type
	 * @see DPTXlator#getSubTypesStatic()
	 */
	protected static Map getSubTypesStatic()
	{
		return types;
	}

	private String fromDPT(int index)
	{
		final int offset = index * stringLength;
		final char[] output = new char[stringLength];
		int strlen = 0;
		for (int i = offset; i < (offset + stringLength) && data[i] != 0; ++i) {
			output[strlen] = (char) data[i];
			++strlen;
		}
		return new String(output, 0, strlen);
	}

	private void toDPT(byte[] buf, int offset)
	{
		// check character set, default to ASCII 7 bit encoding
		int rangeMax = 0x7f;
		if (dpt.equals(DPT_STRING_8859_1))
			rangeMax = 0xff;
		final int items = (buf.length - offset) / stringLength;
		if (items == 0) {
			logger.error("source range has to be multiple of 14 bytes for KNX strings");
			return;
		}
		data = new short[items * stringLength];
		// 7 bit encoded characters of ISO-8859-1 are equal to ASCII
		// the lower 256 characters of UCS correspond to ISO-8859-1
		for (int i = 0; i < data.length; ++i) {
			final short c = ubyte(buf[offset + i]);
			data[i] = c <= rangeMax ? c : replacement;
		}
	}
111956
@Nullable protected String encode(@Nullable byte[] data) {
    return data == null ? null : Base64.getUrlEncoder().encodeToString(data);
  }
31013
private FieldType getFieldType(byte[] data, int offset)
   {
      int fieldIndex = MPPUtility.getInt(data, offset);
      return FieldTypeHelper.mapTextFields(FieldTypeHelper.getInstance14(fieldIndex));
   }
665150
public static byte[] decode(byte[] data)
	{
		if (data.length == 0)
		{
			return data;
		}
		int lastRealDataIndex = data.length - 1;
		while (data[lastRealDataIndex] == equalSign)
		{
			lastRealDataIndex--;
		}
		// original data digit is 8 bits long, but base64 digit is 6 bits long
		int padBytes = data.length - 1 - lastRealDataIndex;
		int byteLength = data.length * 6 / 8 - padBytes;
		byte[] result = new byte[byteLength];
		// Each 4 bytes of input (encoded) we end up with 3 bytes of output
		int dataIndex = 0;
		int resultIndex = 0;
		int allBits = 0;
		// how many result chunks we can process before getting to pad bytes
		int resultChunks = (lastRealDataIndex + 1) / 4;
		for (int i = 0; i < resultChunks; i++)
		{
			allBits = 0;
			// Loop 4 times gathering input bits (4 * 6 = 24)
			for (int j = 0; j < 4; j++)
			{
				allBits = allBits << 6 | decodeDigit(data[dataIndex++]);
			}
			// Loop 3 times generating output bits (3 * 8 = 24)
			for (int j = resultIndex + 2; j >= resultIndex; j--)
			{
				result[j] = (byte) (allBits & 0xff); // Bottom 8 bits
				allBits = allBits >>> 8;
			}
			resultIndex += 3; // processed 3 result bytes
		}
		// Now we do the extra bytes in case the original (non-encoded) data
		// was not multiple of 3 bytes
		switch (padBytes)
		{
			case 1:
				// 1 pad byte means 3 (4-1) extra Base64 bytes of input, 18
				// bits, of which only 16 are meaningful
				// Or: 2 bytes of result data
				allBits = 0;
				// Loop 3 times gathering input bits
				for (int j = 0; j < 3; j++)
				{
					allBits = allBits << 6 | decodeDigit(data[dataIndex++]);
				}
				// NOTE - The code below ends up being equivalent to allBits =
				// allBits>>>2
				// But we code it in a non-optimized way for clarity
				// The 4th, missing 6 bits are all 0
				allBits = allBits << 6;
				// The 3rd, missing 8 bits are all 0
				allBits = allBits >>> 8;
				// Loop 2 times generating output bits
				for (int j = resultIndex + 1; j >= resultIndex; j--)
				{
					result[j] = (byte) (allBits & 0xff); // Bottom 8
					// bits
					allBits = allBits >>> 8;
				}
				break;
			case 2:
				// 2 pad bytes mean 2 (4-2) extra Base64 bytes of input, 12 bits
				// of data, of which only 8 are meaningful
				// Or: 1 byte of result data
				allBits = 0;
				// Loop 2 times gathering input bits
				for (int j = 0; j < 2; j++)
				{
					allBits = allBits << 6 | decodeDigit(data[dataIndex++]);
				}
				// NOTE - The code below ends up being equivalent to allBits =
				// allBits>>>4
				// But we code it in a non-optimized way for clarity
				// The 3rd and 4th, missing 6 bits are all 0
				allBits = allBits << 6;
				allBits = allBits << 6;
				// The 3rd and 4th, missing 8 bits are all 0
				allBits = allBits >>> 8;
				allBits = allBits >>> 8;
				result[resultIndex] = (byte) (allBits & 0xff); // Bottom
				// 8
				// bits
				break;
		}
		return result;
	}
105034
public static int parseBE4BytesAsInt(byte[] data, int offset)
    {
        int value = ((data[offset + 0] & 0xFF) << 24)
                  | ((data[offset + 1] & 0xFF) << 16)
                  | ((data[offset + 2] & 0xFF) <<  8)
                  | ((data[offset + 3] & 0xFF));

        return value;
    }
946016
@Nullable protected byte[] decode(@Nullable String data) {
    return data == null ? null : Base64.getUrlDecoder().decode(data);
  }
1344586
public byte[] getData(byte[] dst, int offset)
	{
		final int end = Math.min(data.length, dst.length - offset) & ~7;
		for (int i = 0; i < end; ++i)
			dst[offset + i] = (byte) data[i];
		return dst;
	}

	/**
	 * Specifies the formatting to use for date/time string representations returned by
	 * the translator.
	 * <p>
	 * A string in extended format contains all valid information of the date/time type.
	 * In extended format, additionally the day of week, daylight time, work-day and clock
	 * synchronization signal information is considered in the output format. Otherwise
	 * this fields are always ignored, i.e only clock fault, year, month, day, hour,
	 * minute and second will get used, if valid.
	 * <p>
	 * The used format is extended by default.
	 * 
	 * @param extended string format to use, <code>true</code> for extended format
	 */
	public final void useValueFormat(boolean extended)
	{
		extFormat = extended;
	}

	/* (non-Javadoc)
	 * @see tuwien.auto.calimero.dptxlator.DPTXlator#getSubTypes()
	 */
	public Map getSubTypes()
	{
		return types;
	}

	/**
	 * @return the subtypes of the date with time translator type
	 * @see DPTXlator#getSubTypesStatic()
	 */
	protected static Map getSubTypesStatic()
	{
		return types;
	}

	private void checkRange(int field, int v)
	{
		if (v < MIN_VALUES[field] || v > MAX_VALUES[field])
			throw new KNXIllegalArgumentException(FIELDS[field] + " out of range: " + v);
	}

	// check on hour = 24, minutes and seconds have to be 0
	private boolean check24Hours(int hr, int min, int sec)
	{
		if (hr != 24 || min == 0 && sec == 0)
			return true;
		return false;
	}

	private String fromDPT(int index)
	{
		if (getBit(index, FAULT))
			return "corrupted date/time";
		final StringBuffer sb = new StringBuffer(20);
		final int i = index * 8;
		// year
		if (!getBit(index, NO_YEAR))
			sb.append(data[i] + MIN_YEAR);
		if (!getBit(index, NO_DATE)) {
			// month
			sb.append('/').append(data[i + 1]);
			// day
			sb.append('/').append(data[i + 2]);
		}
		if (extFormat) {
			if (!getBit(index, NO_DOW))
				sb.append(", ").append(DAYS[data[i + 3] >> 5]);
			if (!getBit(index, NO_WD))
				sb.append(getBit(index, WD) ? " (" : " (no ").append(WORKDAY_SIGN)
					.append(')');
		}
		if (!getBit(index, NO_TIME)) {
			// hr:min:sec
			sb.append(' ').append(data[i + 3] & 0x1F);
			sb.append(':').append(data[i + 4]).append(':').append(data[i + 5]);
			// daylight saving time
			if (extFormat && getBit(index, DST))
				sb.append(' ').append(DAYLIGHT_SIGN);
		}
		if (extFormat)
			sb.append(getBitEx(index, QUALITY) ? ", in " : ", no ").append(SYNC_SIGN);
		return sb.toString();
	}

	private long fromDPTMilliseconds(int index) throws KNXFormatException
	{
		if (getBit(index, FAULT) || !isValidField(index, YEAR)
			|| !isValidField(index, DATE))
			throw new KNXFormatException("insufficient information for calendar");
		initCalendar();
		final int i = index * 8;
		synchronized (c) {
			c.clear();
			c.set(data[i] + MIN_YEAR, data[i + 1] - 1, data[i + 2]);
			if (isValidField(index, TIME)) {
				// we use 23:59:59.999 in calendar for 24:00:00
				final boolean cheat = (data[i + 3] & 0x1F) == 24;
				c.set(Calendar.HOUR_OF_DAY, cheat ? 23 : data[i + 3] & 0x1F);
				c.set(Calendar.MINUTE, cheat ? 59 : data[i + 4]);
				c.set(Calendar.SECOND, cheat ? 59 : data[i + 5]);
				if (cheat)
					c.set(Calendar.MILLISECOND, 999);
			}
			try {
				final long ms = c.getTimeInMillis();
				if (isValidField(index, DAY_OF_WEEK)) {
					int day = c.get(Calendar.DAY_OF_WEEK);
					day = day == Calendar.SUNDAY ? 7 : day - 1;
					if ((data[i + 3] >> 5) != day)
						throw new KNXFormatException("differing day of week");
				}
				if (getDateTimeFlag(index, DAYLIGHT) != (c.get(Calendar.DST_OFFSET) != 0))
					throw new KNXFormatException("differing daylight saving time");
				return ms;
			}
			catch (final IllegalArgumentException e) {
				throw new KNXFormatException("invalid calendar value " + e.getMessage());
			}
		}
	}

	private boolean getDateTimeFlag(int index, int field)
	{
		if (field == CLOCK_SYNC)
			return getBitEx(index, QUALITY);
		final int f = field - WORKDAY;
		if (f < 0 || f >= FLAG_MASKS.length)
			throw new KNXIllegalArgumentException("illegal field");
		return getBit(index, FLAG_MASKS[f]);
	}

	private boolean isValidField(int index, int field)
	{
		return !getBit(index, FIELD_MASKS[field]);
	}

	private boolean getBit(int index, int mask)
	{
		return (data[8 * index + 6] & mask) != 0;
	}

	private boolean getBitEx(int index, int mask)
	{
		return (data[8 * index + 7] & mask) != 0;
	}

	private void set(short[] dst, int index, int field, int v)
	{
		checkRange(field, v);
		final int i = 8 * index + field;
		if (field == YEAR)
			dst[i] = (short) (v - MIN_YEAR);
		else if (field == DOW)
			// NOTE: DoW id is not field index
			dst[i - 3] = (short) (v << 5 | (dst[i - 3] & 0x1F));
		else if (field == HOUR)
			dst[i] = (short) (v | (dst[i] & 0xE0));
		else
			dst[i] = (short) v;
	}

	private void setBit(int index, int mask, boolean bit)
	{
		setBit(data, index, mask, bit);
	}

	private void setBit(short[] dst, int index, int mask, boolean bit)
	{
		if (bit)
			dst[8 * index + 6] |= mask;
		else
			dst[8 * index + 6] &= ~mask;
	}

	private void setBitEx(int index, int mask, boolean bit)
	{
		setBitEx(data, index, mask, bit);
	}

	private void setBitEx(short[] v, int index, int mask, boolean bit)
	{
		if (bit)
			v[8 * index + 7] |= mask;
		else
			v[8 * index + 7] &= ~mask;
	}

	// dst is assumed to be cleared
	protected void toDPT(String value, short[] dst, int index) throws KNXFormatException
	{
		final StringTokenizer t = new StringTokenizer(value, ":-/ (,.)");
		final int k = 8 * index;
		// dpt fields: yr mth day [doW hr] min sec [dst wd] sync
		// mark all fields not used
		dst[k + 6] = NO_WD | NO_YEAR | NO_DATE | NO_DOW | NO_TIME;

		int sync = 0;
		int day = 0;
		final int maxTokens = 10;
		final short[] numbers = new short[maxTokens];
		int count = 0;
		// parse whole string, only handle word and year tokens, store numbers
		for (int i = 0; i < maxTokens && t.hasMoreTokens(); ++i) {
			final String s = t.nextToken();
			try {
				final short no = Short.parseShort(s);
				if (no < 0)
					throw logThrow(LogLevel.WARN, "negative date/time " + s, null, s);
				if (no >= MIN_YEAR && no <= MAX_YEAR) {
					set(dst, index, YEAR, no);
					setBit(dst, index, NO_YEAR, false);
				}
				else
					numbers[count++] = no;
			}
			catch (final NumberFormatException e) {
				// parse number failed, check for word token
				if (s.equalsIgnoreCase(DAYLIGHT_SIGN))
					setBit(dst, index, DST, true);
				else if (s.equalsIgnoreCase(WORKDAY_SIGN)) {
					setBit(dst, index, NO_WD, false);
					setBit(dst, index, WD, true);
				}
				else if (s.equalsIgnoreCase("no") || s.equalsIgnoreCase("in")) {
					if (++sync > 1 || !t.hasMoreTokens()
						|| !t.nextToken().equalsIgnoreCase(SYNC_SIGN))
						throw logThrow(LogLevel.WARN, s + ": '" + SYNC_SIGN
							+ "' expected", null, s);
					// check sync'd or not sync'd
					if (s.charAt(0) == 'i' || s.charAt(0) == 'I')
						setBitEx(dst, index, QUALITY, true);
				}
				else if (s.length() == 3 && ++day == 1) {
					final String prefix = s.toLowerCase();
					int dow = DAYS.length - 1;
					while (dow >= 0 && !DAYS[dow].toLowerCase().startsWith(prefix))
						--dow;
					final boolean anyday = dow == 0 && t.hasMoreTokens()
						&& t.nextToken().equalsIgnoreCase("day");
					if (dow <= 0 && !anyday)
						throw logThrow(LogLevel.WARN, s + ": wrong weekday", null, s);
					set(dst, index, DOW, dow);
					setBit(dst, index, NO_DOW, false);
				}
				else
					throw logThrow(LogLevel.WARN, "wrong date/time " + s, null, s);
			}
		}
		// find out date/time combination, and store numbers into fields
		if (count == 0)
			return;
		if (count == 1 || count == 4)
			throw logThrow(LogLevel.WARN, "ambiguous date/time " + value, null, value);
		int field = count == 3 ? HOUR : MONTH;
		if (field == HOUR || count == 5)
			setBit(dst, index, NO_TIME, false);
		if (field == MONTH)
			setBit(dst, index, NO_DATE, false);
		for (int i = 0; i < count; ++i, ++field)
			set(dst, index, field, numbers[i]);
		// check time field, if set
		if (field == SECOND + 1
			&& !check24Hours(numbers[count - 3], numbers[count - 2], numbers[count - 1]))
			throw logThrow(LogLevel.WARN, "incorrect time " + value, null, value);
	}

	private static synchronized void initCalendar()
	{
		if (c == null) {
			c = Calendar.getInstance();
			c.setLenient(false);
		}
	}
}
471061
public static final int getShort(byte[] data, int offset)
   {
      int result = 0;
      int i = offset;
      for (int shiftBy = 0; shiftBy < 16; shiftBy += 8)
      {
         result |= ((data[i] & 0xff)) << shiftBy;
         ++i;
      }
      return result;
   }
245754
public static String readString(DataInput in) throws IOException {
    int length = readVInt(in);
    if (length == -1) return null;
    byte[] buffer = new byte[length];
    in.readFully(buffer);
    return Text.decode(buffer);
  }
684754
static public byte[] getBytes(StringBuffer data) {
        if (null == data) {
            return null;
        }
        int len = data.length();
        char[] chars = new char[len];
        data.getChars(0, len, chars, 0);
        byte[] bytes = new byte[len];
        for (int i = 0; i < len; i++) {
            bytes[i] = (byte) chars[i];
        }
        return bytes;
    }
731850
public static byte[] decode(String data) {
	// TODO: when we move to Java 8 change to
	// https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Decoder.html
	return org.apache.commons.codec.binary.Base64.decodeBase64(data);
    }