/*************************************************************************** * * This file is part of the 'NDEF Tools for Android' project at * http://code.google.com/p/ndef-tools-for-android/ * * 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 org.ndeftools.wellknown; import java.nio.charset.Charset; import java.util.Locale; import org.ndeftools.Record; import android.nfc.NdefRecord; /** * Well-known text record. <br/><br/> * * Contains text, locale and string encoding. To be used as a lightweight, general purpose text field with support for internationalization and language information. * * @author Adrian Stabiszewski (as@nfctools.org) * */ public class TextRecord extends Record { private static final byte LANGUAGE_CODE_MASK = 0x1F; private static final short TEXT_ENCODING_MASK = 0x80; public static final Charset UTF8 = Charset.forName("UTF-8"); public static final Charset UTF16 = Charset.forName("UTF-16BE"); public static TextRecord parseNdefRecord(NdefRecord ndefRecord) { byte[] payload = ndefRecord.getPayload(); int status = payload[0] & 0xff; int languageCodeLength = (status & TextRecord.LANGUAGE_CODE_MASK); String languageCode = new String(payload, 1, languageCodeLength); Charset textEncoding = ((status & TEXT_ENCODING_MASK) != 0) ? TextRecord.UTF16 : TextRecord.UTF8; return new TextRecord(new String(payload, 1 + languageCodeLength, payload.length - languageCodeLength - 1, textEncoding), textEncoding, new Locale(languageCode)); } private String text; private Charset encoding; private Locale locale; public TextRecord(String key, String text) { this(text, UTF8, Locale.getDefault()); setKey(key); } public TextRecord(String text) { this(text, UTF8, Locale.getDefault()); } public TextRecord(String text, Locale locale) { this(text, UTF8, locale); } public TextRecord(String text, Charset encoding, Locale locale) { this.encoding = encoding; this.text = text; this.locale = locale; if (!encoding.equals(UTF8) && !encoding.equals(UTF16)) { throw new IllegalArgumentException("Expected UTF-8 or UTF-16 encoding, not " + encoding.displayName()); } } public TextRecord() { } public String getText() { return text; } public Locale getLocale() { return locale; } public Charset getEncoding() { return encoding; } public void setText(String text) { this.text = text; } public void setEncoding(Charset encoding) { if (!encoding.equals(UTF8) && !encoding.equals(UTF16)) throw new IllegalArgumentException("unsupported encoding. only utf8 and utf16 are allowed."); this.encoding = encoding; } public void setLocale(Locale locale) { this.locale = locale; } public boolean hasText() { return text != null; } public boolean hasLocale() { return locale != null; } public boolean hasEncoding() { return encoding != null; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((encoding == null) ? 0 : encoding.hashCode()); result = prime * result + ((locale == null) ? 0 : locale.hashCode()); result = prime * result + ((text == null) ? 0 : text.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; TextRecord other = (TextRecord)obj; if (encoding == null) { if (other.encoding != null) return false; } else if (!encoding.equals(other.encoding)) return false; if (locale == null) { if (other.locale != null) return false; } else if (!locale.equals(other.locale)) return false; if (text == null) { if (other.text != null) return false; } else if (!text.equals(other.text)) return false; return true; } @Override public NdefRecord getNdefRecord() { if(!hasLocale()) { throw new IllegalArgumentException("Expected locale"); } if(!hasEncoding()) { throw new IllegalArgumentException("Expected encoding"); } if(!hasText()) { throw new IllegalArgumentException("Expected text"); } byte[] languageData = (locale.getLanguage() + (locale.getCountry() == null || locale.getCountry().length() == 0 ? "" : ("-" + locale.getCountry()))).getBytes(); if (languageData.length > TextRecord.LANGUAGE_CODE_MASK) { throw new IllegalArgumentException("Expected language code length <= 32 bytes, not " + languageData.length + " bytes"); } byte[] textData = text.getBytes(encoding); byte[] payload = new byte[1 + languageData.length + textData.length]; byte status = (byte)(languageData.length | (TextRecord.UTF16.equals(encoding) ? 0x80 : 0x00)); payload[0] = status; System.arraycopy(languageData, 0, payload, 1, languageData.length); System.arraycopy(textData, 0, payload, 1 + languageData.length, textData.length); return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, id != null ? id : EMPTY, payload); } }