/* 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.zzx.factorytest.nfc.card.pboc;
import java.util.ArrayList;
import java.util.Arrays;
import android.content.res.Resources;
import android.nfc.tech.IsoDep;
import com.zzx.factorytest.R;
import com.zzx.factorytest.nfc.Util;
import com.zzx.factorytest.nfc.card.CardManager;
import com.zzx.factorytest.nfc.tech.Iso7816;
public class PbocCard {
protected final static byte[] DFI_MF = { (byte) 0x3F, (byte) 0x00 };
protected final static byte[] DFI_EP = { (byte) 0x10, (byte) 0x01 };
protected final static byte[] DFN_PSE = { (byte) '1', (byte) 'P',
(byte) 'A', (byte) 'Y', (byte) '.', (byte) 'S', (byte) 'Y',
(byte) 'S', (byte) '.', (byte) 'D', (byte) 'D', (byte) 'F',
(byte) '0', (byte) '1', };
protected final static byte[] DFN_PXX = { (byte) 'P' };
protected final static int MAX_LOG = 10;
protected final static int SFI_EXTRA = 21;
protected final static int SFI_LOG = 24;
protected final static byte TRANS_CSU = 6;
protected final static byte TRANS_CSU_CPX = 9;
protected String name;
protected String id;
protected String serl;
protected String version;
protected String date;
protected String count;
protected String cash;
protected String log;
public static String load(IsoDep tech, Resources res) {
final Iso7816.Tag tag = new Iso7816.Tag(tech);
tag.connect();
PbocCard card = null;
do {
if ((card = ShenzhenTong.load(tag, res)) != null)
break;
if ((card = BeijingMunicipal.load(tag, res)) != null)
break;
if ((card = ChanganTong.load(tag, res)) != null)
break;
if ((card = WuhanTong.load(tag, res)) != null)
break;
if ((card = YangchengTong.load(tag, res)) != null)
break;
if ((card = HardReader.load(tag, res)) != null)
break;
} while (false);
tag.close();
return (card != null) ? card.toString(res) : null;
}
protected PbocCard(Iso7816.Tag tag) {
id = tag.getID().toString();
}
protected void parseInfo(Iso7816.Response data, int dec, boolean bigEndian) {
if (!data.isOkey() || data.size() < 30) {
serl = version = date = count = null;
return;
}
final byte[] d = data.getBytes();
if (dec < 1 || dec > 10) {
serl = Util.toHexString(d, 10, 10);
} else {
final int sn = bigEndian ? Util.toIntR(d, 19, dec) : Util.toInt(d,
20 - dec, dec);
serl = String.format("%d", 0xFFFFFFFFL & sn);
}
version = (d[9] != 0) ? String.valueOf(d[9]) : null;
date = String.format("%02X%02X.%02X.%02X - %02X%02X.%02X.%02X", d[20],
d[21], d[22], d[23], d[24], d[25], d[26], d[27]);
count = null;
}
protected static boolean addLog(final Iso7816.Response r,
ArrayList<byte[]> l) {
if (!r.isOkey())
return false;
final byte[] raw = r.getBytes();
final int N = raw.length - 23;
if (N < 0)
return false;
for (int s = 0, e = 0; s <= N; s = e) {
l.add(Arrays.copyOfRange(raw, s, (e = s + 23)));
}
return true;
}
protected static ArrayList<byte[]> readLog(Iso7816.Tag tag, int sfi) {
final ArrayList<byte[]> ret = new ArrayList<byte[]>(MAX_LOG);
final Iso7816.Response rsp = tag.readRecord(sfi);
if (rsp.isOkey()) {
addLog(rsp, ret);
} else {
for (int i = 1; i <= MAX_LOG; ++i) {
if (!addLog(tag.readRecord(sfi, i), ret))
break;
}
}
return ret;
}
protected void parseLog(ArrayList<byte[]>... logs) {
final StringBuilder r = new StringBuilder();
for (final ArrayList<byte[]> log : logs) {
if (log == null)
continue;
if (r.length() > 0)
r.append("<br />--------------");
for (final byte[] v : log) {
final int cash = Util.toInt(v, 5, 4);
if (cash > 0) {
r.append("<br />").append(
String.format("%02X%02X.%02X.%02X %02X:%02X ",
v[16], v[17], v[18], v[19], v[20], v[21],
v[22]));
final char t = (v[9] == TRANS_CSU || v[9] == TRANS_CSU_CPX) ? '-'
: '+';
r.append(t).append(Util.toAmountString(cash / 100.0f));
final int over = Util.toInt(v, 2, 3);
if (over > 0)
r.append(" [o:")
.append(Util.toAmountString(over / 100.0f))
.append(']');
r.append(" [").append(Util.toHexString(v, 10, 6))
.append(']');
}
}
}
this.log = r.toString();
}
protected void parseBalance(Iso7816.Response data) {
if (!data.isOkey() || data.size() < 4) {
cash = null;
return;
}
int n = Util.toInt(data.getBytes(), 0, 4);
if (n > 100000 || n < -100000)
n -= 0x80000000;
cash = Util.toAmountString(n / 100.0f);
}
protected String formatInfo(Resources res) {
if (serl == null)
return null;
final StringBuilder r = new StringBuilder();
r.append(res.getString(R.string.lab_serl)).append(' ').append(serl);
if (version != null) {
final String sv = res.getString(R.string.lab_ver);
r.append("<br />").append(sv).append(' ').append(version);
}
if (date != null) {
final String sd = res.getString(R.string.lab_date);
r.append("<br />").append(sd).append(' ').append(date);
}
if (count != null) {
final String so = res.getString(R.string.lab_op);
final String st = res.getString(R.string.lab_op_time);
r.append("<br />").append(so).append(' ').append(count).append(st);
}
return r.toString();
}
protected String formatLog(Resources res) {
if (log == null || log.length() < 1)
return null;
final StringBuilder ret = new StringBuilder();
final String sl = res.getString(R.string.lab_log);
ret.append("<b>").append(sl).append("</b><small>");
ret.append(log).append("</small>");
return ret.toString();
}
protected String formatBalance(Resources res) {
if (cash == null || cash.length() < 1)
return null;
final String s = res.getString(R.string.lab_balance);
final String c = res.getString(R.string.lab_cur_cny);
return new StringBuilder("<b>").append(s)
.append("<font color=\"teal\"> ").append(cash).append(' ')
.append(c).append("</font></b>").toString();
}
protected String toString(Resources res) {
final String info = formatInfo(res);
final String hist = formatLog(res);
final String cash = formatBalance(res);
return CardManager.buildResult(name, info, cash, hist);
}
}