/* NFCard is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
NFCard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Wget. If not, see <http://www.gnu.org/licenses/>.
Additional permission under GNU GPL version 3 section 7 */
package com.sinpo.xnfc.tech;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import android.nfc.tech.NfcF;
import com.sinpo.xnfc.Util;
public class FeliCa {
public static final byte[] EMPTY = {};
protected byte[] data;
protected FeliCa() {
}
protected FeliCa(byte[] bytes) {
data = (bytes == null) ? FeliCa.EMPTY : bytes;
}
public int size() {
return data.length;
}
public byte[] getBytes() {
return data;
}
@Override
public String toString() {
return Util.toHexString(data, 0, data.length);
}
public final static class IDm extends FeliCa {
public static final byte[] EMPTY = { 0, 0, 0, 0, 0, 0, 0, 0, };
public IDm(byte[] bytes) {
super((bytes == null || bytes.length < 8) ? IDm.EMPTY : bytes);
}
public final String getManufactureCode() {
return Util.toHexString(data, 0, 2);
}
public final String getCardIdentification() {
return Util.toHexString(data, 2, 6);
}
public boolean isEmpty() {
final byte[] d = data;
for (final byte v : d) {
if (v != 0)
return false;
}
return true;
}
}
public final static class PMm extends FeliCa {
public static final byte[] EMPTY = { 0, 0, 0, 0, 0, 0, 0, 0, };
public PMm(byte[] bytes) {
super((bytes == null || bytes.length < 8) ? PMm.EMPTY : bytes);
}
public final String getIcCode() {
return Util.toHexString(data, 0, 2);
}
public final String getMaximumResponseTime() {
return Util.toHexString(data, 2, 6);
}
}
public final static class SystemCode extends FeliCa {
public static final byte[] EMPTY = { 0, 0, };
public SystemCode(byte[] sc) {
super((sc == null || sc.length < 2) ? SystemCode.EMPTY : sc);
}
public int toInt() {
return toInt(data);
}
public static int toInt(byte[] data) {
return 0x0000FFFF & ((data[0] << 8) | (0x000000FF & data[1]));
}
}
public final static class ServiceCode extends FeliCa {
public static final byte[] EMPTY = { 0, 0, };
public static final int T_UNKNOWN = 0;
public static final int T_RANDOM = 1;
public static final int T_CYCLIC = 2;
public static final int T_PURSE = 3;
public ServiceCode(byte[] sc) {
super((sc == null || sc.length < 2) ? ServiceCode.EMPTY : sc);
}
public ServiceCode(int code) {
this(new byte[] { (byte) (code & 0xFF), (byte) (code >> 8) });
}
public boolean isEncrypt() {
return (data[0] & 0x1) == 0;
}
public boolean isWritable() {
final int f = data[0] & 0x3F;
return (f & 0x2) == 0 || f == 0x13 || f == 0x12;
}
public int getAccessAttr() {
return data[0] & 0x3F;
}
public int getDataType() {
final int f = data[0] & 0x3F;
if ((f & 0x10) == 0)
return T_PURSE;
return ((f & 0x04) == 0) ? T_RANDOM : T_CYCLIC;
}
}
public final static class Block extends FeliCa {
public Block() {
data = new byte[16];
}
public Block(byte[] bytes) {
super((bytes == null || bytes.length < 16) ? new byte[16] : bytes);
}
}
public final static class BlockListElement extends FeliCa {
private static final byte LENGTH_2_BYTE = (byte) 0x80;
private static final byte LENGTH_3_BYTE = (byte) 0x00;
// private static final byte ACCESSMODE_DECREMENT = (byte) 0x00;
// private static final byte ACCESSMODE_CACHEBACK = (byte) 0x01;
private final byte lengthAndaccessMode;
private final byte serviceCodeListOrder;
public BlockListElement(byte mode, byte order, byte... blockNumber) {
if (blockNumber.length > 1) {
lengthAndaccessMode = (byte) (mode | LENGTH_2_BYTE & 0xFF);
} else {
lengthAndaccessMode = (byte) (mode | LENGTH_3_BYTE & 0xFF);
}
serviceCodeListOrder = (byte) (order & 0x0F);
data = (blockNumber == null) ? FeliCa.EMPTY : blockNumber;
}
@Override
public byte[] getBytes() {
if ((this.lengthAndaccessMode & LENGTH_2_BYTE) == 1) {
ByteBuffer buff = ByteBuffer.allocate(2);
buff.put(
(byte) ((this.lengthAndaccessMode | this.serviceCodeListOrder) & 0xFF))
.put(data[0]);
return buff.array();
} else {
ByteBuffer buff = ByteBuffer.allocate(3);
buff.put(
(byte) ((this.lengthAndaccessMode | this.serviceCodeListOrder) & 0xFF))
.put(data[1]).put(data[0]);
return buff.array();
}
}
}
public final static class MemoryConfigurationBlock extends FeliCa {
public MemoryConfigurationBlock(byte[] bytes) {
super((bytes == null || bytes.length < 4) ? new byte[4] : bytes);
}
public boolean isNdefSupport() {
return (data == null) ? false : (data[3] & (byte) 0xff) == 1;
}
public void setNdefSupport(boolean ndefSupport) {
data[3] = (byte) (ndefSupport ? 1 : 0);
}
public boolean isWritable(int... addrs) {
if (data == null)
return false;
boolean result = true;
for (int a : addrs) {
byte b = (byte) ((a & 0xff) + 1);
if (a < 8) {
result &= (data[0] & b) == b;
continue;
} else if (a < 16) {
result &= (data[1] & b) == b;
continue;
} else
result &= (data[2] & b) == b;
}
return result;
}
}
public final static class Service extends FeliCa {
private final ServiceCode[] serviceCodes;
private final BlockListElement[] blockListElements;
public Service(ServiceCode[] codes, BlockListElement... blocks) {
serviceCodes = (codes == null) ? new ServiceCode[0] : codes;
blockListElements = (blocks == null) ? new BlockListElement[0]
: blocks;
}
@Override
public byte[] getBytes() {
int length = 0;
for (ServiceCode s : this.serviceCodes) {
length += s.getBytes().length;
}
for (BlockListElement b : blockListElements) {
length += b.getBytes().length;
}
ByteBuffer buff = ByteBuffer.allocate(length);
for (ServiceCode s : this.serviceCodes) {
buff.put(s.getBytes());
}
for (BlockListElement b : blockListElements) {
buff.put(b.getBytes());
}
return buff.array();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (ServiceCode s : serviceCodes) {
sb.append(s.toString());
}
for (BlockListElement b : blockListElements) {
sb.append(b.toString());
}
return sb.toString();
}
}
public final static class Command extends FeliCa {
private final int length;
private final byte code;
private final IDm idm;
public Command(final byte[] bytes) {
this(bytes[0], Arrays.copyOfRange(bytes, 1, bytes.length));
}
public Command(byte code, final byte... bytes) {
this.code = code;
if (bytes.length >= 8) {
idm = new IDm(Arrays.copyOfRange(bytes, 0, 8));
data = Arrays.copyOfRange(bytes, 8, bytes.length);
} else {
idm = null;
data = bytes;
}
length = bytes.length + 2;
}
public Command(byte code, IDm idm, final byte... bytes) {
this.code = code;
this.idm = idm;
this.data = bytes;
this.length = idm.getBytes().length + data.length + 2;
}
public Command(byte code, byte[] idm, final byte... bytes) {
this.code = code;
this.idm = new IDm(idm);
this.data = bytes;
this.length = idm.length + data.le
- 1
- 2
- 3
- 4
- 5
- 6
前往页