/***************************************************************************
*
* 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.Arrays;
import java.util.Locale;
import org.ndeftools.Record;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.net.Uri;
import android.nfc.NdefRecord;
import android.os.Build;
/**
* Well-known URI Record. <br/><br/>
*
* Contains a single URI as defined by RFC 3986 - represented in a compact manner.
*
* @author Adrian Stabiszewski (as@nfctools.org)
*
*/
public class UriRecord extends Record {
private static final short TNF_WELL_KNOWN = 0x01;
private static final byte[] RTD_URI = {0x55}; // "U"
@SuppressLint("NewApi")
public static UriRecord parseNdefRecord(NdefRecord ndefRecord) {
if (Build.VERSION.SDK_INT >= 16) {
return new UriRecord(ndefRecord.toUri());
} else {
byte[] payload = ndefRecord.getPayload();
if (payload.length < 2) {
return null;
}
// payload[0] contains the URI Identifier Code, as per
// NFC Forum "URI Record Type Definition" section 3.2.2.
int prefixIndex = (payload[0] & (byte)0xFF);
if (prefixIndex < 0 || prefixIndex >= URI_PREFIX_MAP.length) {
return null;
}
String prefix = URI_PREFIX_MAP[prefixIndex];
String suffix = new String(Arrays.copyOfRange(payload, 1, payload.length),
Charset.forName("UTF-8"));
return new UriRecord(Uri.parse(prefix + suffix));
}
}
public static final Charset DEFAULT_URI_CHARSET = Charset.forName("UTF-8");
/**
* NFC Forum "URI Record Type Definition"<p>
* This is a mapping of "URI Identifier Codes" to URI string prefixes,
* per section 3.2.2 of the NFC Forum URI Record Type Definition document.
*/
@Deprecated
private static final String[] URI_PREFIX_MAP = new String[] {
"", // 0x00
"http://www.", // 0x01
"https://www.", // 0x02
"http://", // 0x03
"https://", // 0x04
"tel:", // 0x05
"mailto:", // 0x06
"ftp://anonymous:anonymous@", // 0x07
"ftp://ftp.", // 0x08
"ftps://", // 0x09
"sftp://", // 0x0A
"smb://", // 0x0B
"nfs://", // 0x0C
"ftp://", // 0x0D
"dav://", // 0x0E
"news:", // 0x0F
"telnet://", // 0x10
"imap:", // 0x11
"rtsp://", // 0x12
"urn:", // 0x13
"pop:", // 0x14
"sip:", // 0x15
"sips:", // 0x16
"tftp:", // 0x17
"btspp://", // 0x18
"btl2cap://", // 0x19
"btgoep://", // 0x1A
"tcpobex://", // 0x1B
"irdaobex://", // 0x1C
"file://", // 0x1D
"urn:epc:id:", // 0x1E
"urn:epc:tag:", // 0x1F
"urn:epc:pat:", // 0x20
"urn:epc:raw:", // 0x21
"urn:epc:", // 0x22
};
private Uri uri;
public UriRecord(Uri uri) {
this.uri = uri;
}
public UriRecord() {
}
public UriRecord(String uriString) {
this(Uri.parse(uriString));
}
public Uri getUri() {
return uri;
}
public void setUri(Uri uri) {
this.uri = uri;
}
public boolean hasUri() {
return uri != null;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((uri == null) ? 0 : uri.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;
UriRecord other = (UriRecord)obj;
if (uri == null) {
if (other.uri != null)
return false;
}
else if (!uri.equals(other.uri))
return false;
return true;
}
@Override
public NdefRecord getNdefRecord() {
if(!hasUri()) {
throw new IllegalArgumentException("Expected URI");
}
if (Build.VERSION.SDK_INT >= 14) {
return NdefRecord.createUri(uri);
} else {
return createUri(uri);
}
}
@SuppressLint("NewApi")
public static NdefRecord createUri(Uri uri) {
if (uri == null) throw new NullPointerException("uri is null");
uri = normalizeScheme(uri);
String uriString = uri.toString();
if (uriString.length() == 0) throw new IllegalArgumentException("uri is empty");
byte prefix = 0;
for (int i = 1; i < URI_PREFIX_MAP.length; i++) {
if (uriString.startsWith(URI_PREFIX_MAP[i])) {
prefix = (byte) i;
uriString = uriString.substring(URI_PREFIX_MAP[i].length());
break;
}
}
byte[] uriBytes = uriString.getBytes(Charset.forName("UTF-8"));
byte[] recordBytes = new byte[uriBytes.length + 1];
recordBytes[0] = prefix;
System.arraycopy(uriBytes, 0, recordBytes, 1, uriBytes.length);
return new NdefRecord(TNF_WELL_KNOWN, RTD_URI, new byte[]{}, recordBytes);
}
public static Uri normalizeScheme(Uri uri) {
String scheme = uri.getScheme();
if (scheme == null) return uri; // give up
String lowerScheme = scheme.toLowerCase(Locale.US);
if (scheme.equals(lowerScheme)) return uri; // no change
return uri.buildUpon().scheme(lowerScheme).build();
}
}