M1卡控制位的解析源码的封装

额,最近在做关于M1卡读写的程序开发,由于控制位的问题因此要查询资料解决其解析与打包的问题,恰好在GITHUB上有一个很好的项目,附带上地址:点我看这个神奇的项目 ,我根据这位程序员的思路封装了自己的库(控制位的操作基本都是按位操作,好麻烦的说。我也想参透,乃至自己独立按照M1卡相关文档可以写出,奈何实力不够,被按位操作绕的眼花缭乱的),该有的注释,基本都在这个库里面加了,为了直观明了,我一个个根据文档上的对应的权限来使用了较多的if语句来实现,因此代码有些冗余,为了好理解每一句的作用暂时不修改优化,有需要的可以根据自己的需求定制优化。

好的,话不多说,上代码:
package test;

import java.util.HashMap;

public class AccessBitUitl {
	
	/*
	 * 控制位长度,4位字节八个十六进制字符
	 */
	public static final int CONTROLBIT_HEX_SIZE = 8;
	public static final int CONTROLBIT_BYTE_SIZE = 4;
	
	//可以实例化对象时使用的全局控制位缓存
	private byte[] mAcBytes = null;

	//静态工具库,default构造方法设为私有较好
	private AccessBitUitl() { /*This is don't need*/ }
	
	//有参构造方法,简化对相同控制位解析时方法调用的实现
	private AccessBitUitl(byte[] acBytes) { this.mAcBytes = acBytes; }
	
	/*
	 * 参考文档
	 * https://blog.csdn.net/liujianhua1989/article/details/72639307
	 * https://www.cnblogs.com/h2zZhou/p/5250703.html
	 * https://github.com/ikarus23/MifareClassicTool
	 */
	
	/*认证后可执行下列操作:
	1、读数据块,读操作支持普通的数据块(0-2)与电子钱包块与尾块(trail)
	2、写数据块,写操作支持普通的数据块(0-2)与电子钱包块与尾块(trail)
	3、减值:减少数据块内的数值,并将结果保存在临时内部数据寄存器中。(仅支持电子钱包块)
	4、加值:增加数据块内的数值,并将结果保存在数据寄存器中。(仅支持电子钱包块)
	5、恢复:将数据块内容移入数据寄存器。(仅支持电子钱包块)
	6、转存:将临时内部数据寄存器的内容写入数值块。 (仅支持电子钱包块)
	枚举操作类型,依次为 -> 读卡 , 写卡 , 增值 , 减值 , 恢复 , 转存
	*/
	public static enum Operation{ READ, WRITE, INCREMENT,DECREMENT, RESTORE, TRANSFER }
	
	//密钥的验证是有KeyA,KeyB的两种不同的选择的,
	//当控制位的条件成立时,Key也可当作鉴权值之一
	//三个枚举元素分别是 A密钥, B密钥,AB密钥,两者都没
	public static enum KeyType{ A , B , AB , NEVER }
	
	//对于一个扇区,能操作的只有两部分,一部分是数据块,一部分是尾部块
	public static enum SectorStructure{ DATA , TRAIL }
	
	/*
	 * 对数据块,能操作的总共有“三部分”,
	 * Block1和Block2和Block3,不同容量的卡块数量不同,
	 * 但是对于MIFARE CLASSIC CARD的兼容性来说,能操作的,就是“三部分”
	 */
	public static enum DataBlockStructure{ BLOCK0 , BLOCK1 , BLOCK2 , BLOCK3 }
	
	//对于特殊的块3,是有三部分的分割读写区域
	//其中分别是KeyA的读写,还有KeyB的读写, 还有控制位的读写
	//因此我们要根据要操作的区域对控制位进行解析鉴权
	public static enum TrailStructure{ KEYA , KEYB , CONTROLBIT }
	
	//对于控制位,是有C1 , C2, C3的编号
	public static enum ControlBitNum{ C1 , C2 , C3 }
	
	/*块具有相对于区的独立性,16扇区各自拥有独立的鉴权方式,
	 *块鉴权在控制位的约束下,对于密码的权限是依赖控制位的实现
	 *依据控制位的约束,密钥对于块进行上述操作是必须要条件成立
	 *每个数据块和尾块的读写条件均由3个bit定义,
	 *并以非取反和取反形式保存在各个区的尾块中。
	 **尾部块由C13 C23 C33三个控制位来控制,由于不是数据块,因此仅支持读写操作
	 *数据块2由C12 C22 C32三个控制位控制,由于是数据块,因此支持读写增值减值操作
	 *数据块1由C11 C21 C31三个控制位控制,由于是数据块,因此支持读写增值减值操作
	 *数据块0由C10 C20 C30三个控制位控制,由于是数据块,因此支持读写增值减值操作
	 */
	
	/*							警告,若控制位错误,将导致扇区锁死						*/
	
	/*
	 * 尾部块操作权限解析方法
	 * 根据传入的控制字节对操作进行解析,返回对应的ENUM对象
	 * @param c1 控制字节1
	 * @param c2 控制字节2
	 * @param c3 控制字节3
	 * @param opera 将要进行的操作
	 * @param whereToOpera 将要操作尾部块那一部分
	 */
	public static KeyType trailOperation(byte c1, byte c2, byte c3, 
			Operation opera, TrailStructure whereToOpera) {
		//判断传入的操作类型是否正确,如果不正确则直接返回NEVER
		//特别警告!!!在尾部块,操作仅限于支持读操作与写操作
		if(opera != Operation.READ && opera != Operation.WRITE) return KeyType.NEVER;
		//为了简化鉴权过程,先执行把操作为读的鉴权
		if(opera == Operation.READ) {
			//在尾部块的操作为在KeyA部分上进行的时候的鉴权
			if(whereToOpera == TrailStructure.KEYA) {
				//当控制位为000时KeyA部分禁止读
				if(c1 == 0 && c2 == 0 && c3 == 0) return KeyType.NEVER;
				//当控制位为001时KeyA部分禁止读
				if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.NEVER;
				//当控制位为010时KeyA部分禁止读
				if(c1 == 0 && c2 == 1 && c3 == 0) return KeyType.NEVER;
				//当控制位为011时KeyA部分禁止读
				if(c1 == 0 && c2 == 1 && c3 == 1) return KeyType.NEVER;
				//当控制位为100时KeyA部分禁止读
				if(c1 == 1 && c2 == 0 && c3 == 0) return KeyType.NEVER;
				//当控制位为101时KeyA部分禁止读
				if(c1 == 1 && c2 == 0 && c3 == 1) return KeyType.NEVER;
				//当控制位为110时KeyA部分禁止读
				if(c1 == 1 && c2 == 1 && c3 == 0) return KeyType.NEVER;
				//当控制位为111时KeyA部分禁止读
				if(c1 == 1 && c2 == 1 && c3 == 1) return KeyType.NEVER;
			}
			//在尾部块的操作为在控制位部分上进行的时候的鉴权
			if(whereToOpera == TrailStructure.CONTROLBIT) {
				//当控制位为000时控制位部分允许验证密钥A后读
				if(c1 == 0 && c2 == 0 && c3 == 0) return KeyType.A;
				//当控制位为001时控制位部分允许验证密钥A后读
				if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.A;
				//当控制位为010时控制位部分允许验证密钥A后读
				if(c1 == 0 && c2 == 1 && c3 == 0) return KeyType.A;
				//当控制位为011时控制位部分允许验证密钥A|B后读
				if(c1 == 0 && c2 == 1 && c3 == 1) return KeyType.AB;
				//当控制位为100时控制位部分允许验证密钥A|B后读
				if(c1 == 1 && c2 == 0 && c3 == 0) return KeyType.AB;
				//当控制位为101时控制位部分允许验证密钥A|B后读
				if(c1 == 1 && c2 == 0 && c3 == 1) return KeyType.AB;
				//当控制位为110时控制位部分允许验证密钥A|B后读
				if(c1 == 1 && c2 == 1 && c3 == 0) return KeyType.AB;
				//当控制位为111时控制位部分允许验证密钥A|B后读
				if(c1 == 1 && c2 == 1 && c3 == 1) return KeyType.AB;
			}
			//在尾部块的操作为在KeyB部分上进行的时候的鉴权
			if(whereToOpera == TrailStructure.KEYB) {
				//当控制位为000时KeyB部分允许验证密钥A后读
				if(c1 == 0 && c2 == 0 && c3 == 0) return KeyType.A;
				//当控制位为001时KeyB部分允许验证密钥A后读
				if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.A;
				//当控制位为010时KeyB部分允许验证密钥A后读
				if(c1 == 0 && c2 == 1 && c3 == 0) return KeyType.A;
				//当控制位为011时KeyB部分禁止读
				if(c1 == 0 && c2 == 1 && c3 == 1) return KeyType.NEVER;
				//当控制位为100时KeyB部分禁止读
				if(c1 == 1 && c2 == 0 && c3 == 0) return KeyType.NEVER;
				//当控制位为101时KeyB部分禁止读
				if(c1 == 1 && c2 == 0 && c3 == 1) return KeyType.NEVER;
				//当控制位为110时KeyB部分禁止读
				if(c1 == 1 && c2 == 1 && c3 == 0) return KeyType.NEVER;
				//当控制位为111时KeyB部分禁止读
				if(c1 == 1 && c2 == 1 && c3 == 1) return KeyType.NEVER;
			}
			
		}
		//然后再执行操作为写的鉴权
		if(opera == Operation.WRITE) {
			//在尾部块的操作为在KeyA部分上进行的时候的鉴权
			if(whereToOpera == TrailStructure.KEYA) {
				//当控制位为000时KeyA部分允许验证密钥A后写
				if(c1 == 0 && c2 == 0 && c3 == 0) return KeyType.A;
				//当控制位为001时KeyA部分允许验证密钥A后写
				if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.A;
				//当控制位为010时KeyA部分禁止写
				if(c1 == 0 && c2 == 1 && c3 == 0) return KeyType.NEVER;
				//当控制位为011时KeyA部分允许验证密钥B后写
				if(c1 == 0 && c2 == 1 && c3 == 1) return KeyType.B;
				//当控制位为100时KeyA部分允许验证密钥B后写
				if(c1 == 1 && c2 == 0 && c3 == 0) return KeyType.B;
				//当控制位为101时KeyA部分禁止写
				if(c1 == 1 && c2 == 0 && c3 == 1) return KeyType.NEVER;
				//当控制位为110时KeyA部分禁止写
				if(c1 == 1 && c2 == 1 && c3 == 0) return KeyType.NEVER;
				//当控制位为111时KeyA部分禁止写
				if(c1 == 1 && c2 == 1 && c3 == 1) return KeyType.NEVER;
			}
			//在尾部块的操作为在控制位部分上进行的时候的鉴权
			if(whereToOpera == TrailStructure.CONTROLBIT) {
				//当控制位为000时控制位部分允许验证密钥B后写
				if(c1 == 0 && c2 == 0 && c3 == 0) return KeyType.B;
				//当控制位为001时控制位部分允许验证密钥A后写
				if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.A;
				//当控制位为010时控制位部分禁止写
				if(c1 == 0 && c2 == 1 && c3 == 0) return KeyType.NEVER;
				//当控制位为011时控制位部分允许验证密钥B后写
				if(c1 == 0 && c2 == 1 && c3 == 1) return KeyType.B;
				//当控制位为100时控制位部分禁止写
				if(c1 == 1 && c2 == 0 && c3 == 0) return KeyType.NEVER;
				//当控制位为101时控制位部分允许验证密钥B后写
				if(c1 == 1 && c2 == 0 && c3 == 1) return KeyType.B;
				//当控制位为110时控制位部分禁止写
				if(c1 == 1 && c2 == 1 && c3 == 0) return KeyType.NEVER;
				//当控制位为111时控制位部分禁止写
				if(c1 == 1 && c2 == 1 && c3 == 1) return KeyType.NEVER;
			}
			//在尾部块的操作为在KeyB部分上进行的时候的鉴权
			if(whereToOpera == TrailStructure.KEYB) {
				//当控制位为000时KeyB部分允许验证密钥A后写
				if(c1 == 0 && c2 == 0 && c3 == 0) return KeyType.A;
				//当控制位为001时KeyB部分允许验证密钥A后写
				if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.A;
				//当控制位为010时KeyB部分禁止写
				if(c1 == 0 && c2 == 1 && c3 == 0) return KeyType.NEVER;
				//当控制位为011时KeyB部分允许验证密钥B后写
				if(c1 == 0 && c2 == 1 && c3 == 1) return KeyType.B;
				//当控制位为100时KeyB部分允许验证密钥B后写
				if(c1 == 1 && c2 == 0 && c3 == 0) return KeyType.B;
				//当控制位为101时KeyB部分禁止写
				if(c1 == 1 && c2 == 0 && c3 == 1) return KeyType.NEVER;
				//当控制位为110时KeyB部分禁止写
				if(c1 == 1 && c2 == 1 && c3 == 0) return KeyType.NEVER;
				//当控制位为111时KeyB部分禁止写
				if(c1 == 1 && c2 == 1 && c3 == 1) return KeyType.NEVER;
			}
		}
		//在条件都不成立时返回NEVER
		return KeyType.NEVER;
	}
	
	/*
	 * 数据块操作权限解析方法
	 * 根据传入的控制字节对操作进行解析,返回对应的ENUM对象
	 * @param c1 控制字节1
	 * @param c2 控制字节2
	 * @param c3 控制字节3
	 * @param opera 将要对数据块进行的操作
	 */
	public static KeyType generalOperation(byte c1, byte c2, byte c3, Operation opera) {
		//1、进行数据块读操作的鉴权
		if(opera == Operation.READ) {
			//在控制位为000时允许密钥AB后读
			if(c1 == 0 && c2 == 0 && c3 == 0) return KeyType.AB;
			//在控制位为010时允许密钥AB后读
			if(c1 == 0 && c2 == 1 && c3 == 0) return KeyType.AB;
			//在控制位为100时允许密钥AB后读
			if(c1 == 1 && c2 == 0 && c3 == 0) return KeyType.AB;
			//在控制位为110时允许密钥AB后读
			if(c1 == 1 && c2 == 1 && c3 == 0) return KeyType.AB;
			//在控制位为001时允许密钥AB后读
			if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.AB;
			//在控制位为011时允许密钥B后读
			if(c1 == 0 && c2 == 1 && c3 == 1) return KeyType.B;
			//在控制位为101时允许密钥B后读
			if(c1 == 1 && c2 == 0 && c3 == 1) return KeyType.B;
			//在控制位为111时禁止读
			if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.NEVER;
		}
		//1、进行数据块写操作的鉴权
		if(opera == Operation.WRITE) {
			//在控制位为000时允许密钥AB后写
			if(c1 == 0 && c2 == 0 && c3 == 0) return KeyType.AB;
			//在控制位为010时允许密钥B后写
			if(c1 == 0 && c2 == 1 && c3 == 0) return KeyType.B;
			//在控制位为100时允许密钥B后写
			if(c1 == 1 && c2 == 0 && c3 == 0) return KeyType.B;
			//在控制位为110时允许密钥B后写
			if(c1 == 1 && c2 == 1 && c3 == 0) return KeyType.B;
			//在控制位为001时禁止读
			if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.NEVER;
			//在控制位为011时允许密钥B后写
			if(c1 == 0 && c2 == 1 && c3 == 1) return KeyType.B;
			//在控制位为101时禁止写
			if(c1 == 1 && c2 == 0 && c3 == 1) return KeyType.NEVER;
			//在控制位为111时禁止写
			if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.NEVER;
		}
		//3、进行数据块增值操作的鉴权
		if(opera == Operation.INCREMENT) {
			//在控制位为000时允许密钥AB后增值
			if(c1 == 0 && c2 == 0 && c3 == 0) return KeyType.AB;
			//在控制位为010时允许密钥B后增值
			if(c1 == 0 && c2 == 1 && c3 == 0) return KeyType.NEVER;
			//在控制位为100时允许密钥B后增值
			if(c1 == 1 && c2 == 0 && c3 == 0) return KeyType.NEVER;
			//在控制位为110时允许密钥B后增值
			if(c1 == 1 && c2 == 1 && c3 == 0) return KeyType.B;
			//在控制位为001时禁止增值
			if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.NEVER;
			//在控制位为011时允许密钥B后增值
			if(c1 == 0 && c2 == 1 && c3 == 1) return KeyType.NEVER;
			//在控制位为101时禁止增值
			if(c1 == 1 && c2 == 0 && c3 == 1) return KeyType.NEVER;
			//在控制位为111时禁止增值
			if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.NEVER;
		}
		//4、进行数据块减值操作的鉴权
		//5、进行数据块恢复操作的鉴权
		//6、进行数据块转存操作的鉴权
		if(opera == Operation.DECREMENT || 
				opera == Operation.RESTORE || 
				opera == Operation.TRANSFER) {
			//在控制位为000时允许密钥AB后减值转存恢复
			if(c1 == 0 && c2 == 0 && c3 == 0) return KeyType.AB;
			//在控制位为010时允许密钥B后减值转存恢复
			if(c1 == 0 && c2 == 1 && c3 == 0) return KeyType.NEVER;
			//在控制位为100时允许密钥B后减值转存恢复
			if(c1 == 1 && c2 == 0 && c3 == 0) return KeyType.NEVER;
			//在控制位为110时允许密钥AB后减值转存恢复
			if(c1 == 1 && c2 == 1 && c3 == 0) return KeyType.AB;
			//在控制位为001时允许密钥AB后减值转存恢复
			if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.AB;
			//在控制位为011时禁止减值转存恢复
			if(c1 == 0 && c2 == 1 && c3 == 1) return KeyType.NEVER;
			//在控制位为101时禁止减值转存恢复
			if(c1 == 1 && c2 == 0 && c3 == 1) return KeyType.NEVER;
			//在控制位为111时禁止减值转存恢复
			if(c1 == 0 && c2 == 0 && c3 == 1) return KeyType.NEVER;
		}
		//在条件都不成立时返回NEVER
		return KeyType.NEVER;
	}
	
	/*
	 * 密钥B可读性判断方法
	 * 返回TRUE则keyB可读并可用于存储数据的访问控制条件
	 * 尾块和key A被预定义为传输配置状态。
	 * 因为在传输配置状态下key B可读,
	 * (KeyB可读的情况下)新卡必须用keyA认证。
	 * @param c1 控制字节1
	 * @param c2 控制字节2
	 * @param c3 控制字节3
	 */
	public static boolean isKeyBReadable(byte c1, byte c2, byte c3) {
		return c1 == 0	
				//在控制位为000时密钥B可读
                && (c2 == 0 && c3 == 0)
                //在控制位为010时密钥B可读
                || (c2 == 1 && c3 == 0)
                //在控制位为001时密钥B可读
                || (c2 == 0 && c3 == 1);
    }
	
	/*
	 * 传输配置状态检测方法
	 * @param c1 控制字节1
	 * @param c2 控制字节2
	 * @param c3 控制字节3
	 * @param block 要操作的区域
	 */
	public static boolean isTranspotConfiguration(byte c1, byte c2, byte c3,
			SectorStructure block) {
		if(c1 == 0 && c2 == 0) {
			//操作数据块的情况下如果控制位为000则为传输配置状态
			if(block == SectorStructure.DATA && c3 == 0) return true;
			//操作尾部块的情况下如果控制位为001则为传输配置状态
			if(block == SectorStructure.TRAIL && c3 == 1) return true;
		}
		return false;
	}
	
	/*
	 * 解析控制字节的方法
	 * @param controlBit 长度为4byte的控制位
	 * @param block 枚举对象,用于判断要解析的块的控制位的鉴权
	 * 返回对应的区块的控制权限_对应的byte
	 */
	public static HashMap<ControlBitNum,Byte> unpackAccessInfo(byte[] controlBit, DataBlockStructure block) {
		//控制位长度查错
		if(controlBit.length != CONTROLBIT_BYTE_SIZE) {
			throw new RuntimeException("The ControlBit length is error!!!");
		}
		//存结果的图表
		HashMap<ControlBitNum,Byte> result = new HashMap<>();
		//建立一个矩阵数组,存控制位换算结果
		//三个控制位,四个块
		byte[][] acMatrix = new byte[3][4];
		//验证控制位的可行性
        if (	(byte)((controlBit[1]>>>4)&0x0F)  ==
                        (byte)((controlBit[0]^0xFF)&0x0F) &&
                (byte)(controlBit[2]&0x0F) ==
                        (byte)(((controlBit[0]^0xFF)>>>4)&0x0F) &&
                (byte)((controlBit[2]>>>4)&0x0F)  ==
                        (byte)((controlBit[1]^0xFF)&0x0F)) {
            // C1, Block 0-3
            for (int i = 0; i < 4; i++) {
                acMatrix[0][i] = (byte)((controlBit[1]>>>4+i)&0x01);
            }
            // C2, Block 0-3
            for (int i = 0; i < 4; i++) {
                acMatrix[1][i] = (byte)((controlBit[2]>>>i)&0x01);
            }
            // C3, Block 0-3
            for (int i = 0; i < 4; i++) {
                acMatrix[2][i] = (byte)((controlBit[2]>>>4+i)&0x01);
            }
        }
		if(block == DataBlockStructure.BLOCK0) {
			result.put(ControlBitNum.C1, acMatrix[0][0]);
			result.put(ControlBitNum.C2, acMatrix[1][0]);
			result.put(ControlBitNum.C3, acMatrix[2][0]);
			return result;
		}
		if(block == DataBlockStructure.BLOCK1) {
			result.put(ControlBitNum.C1, acMatrix[0][1]);
			result.put(ControlBitNum.C2, acMatrix[1][1]);
			result.put(ControlBitNum.C3, acMatrix[2][1]);
			return result;
		}
		if(block == DataBlockStructure.BLOCK2) {
			result.put(ControlBitNum.C1, acMatrix[0][2]);
			result.put(ControlBitNum.C2, acMatrix[1][2]);
			result.put(ControlBitNum.C3, acMatrix[2][2]);
			return result;
		}
		if(block == DataBlockStructure.BLOCK3) {
			result.put(ControlBitNum.C1, acMatrix[0][3]);
			result.put(ControlBitNum.C2, acMatrix[1][3]);
			result.put(ControlBitNum.C3, acMatrix[2][3]);
			return result;
		}
		return null;
	}
	
	/*
	 * 打包控制字节的方法
	 * @param controlBit 全部控制位的实现,当有四个对象,每个对象里有用C1 , C2 , C3
	 * 三个键值对,对应四个块的三个控制位
	 * 返回全部区块的控制权限_对应的byte(三个,不包括预留字节)
	 */
	public static byte[] packAccessInfo(HashMap<DataBlockStructure,HashMap<ControlBitNum,Byte>> controlBit) {
		//建立一个矩阵数组,存控制位换算结果
		//三个控制位,四个块,从图表中取出来填充到矩阵数组中
		byte[][] acMatrix = new byte[3][4];
		//外层迭代
		for(int i = 0; i < 3; ++i) {
			//内层迭代
			for(int j = 0; j < 4; ++j) {
				acMatrix[i][j] = 
						//取出对应扇区的控制比特位封包
						controlBit.get(DataBlockStructure.values()[j])
						//取出封包中的比特位打包进矩阵中
						.get(ControlBitNum.values()[i]);
			}
		}
		//开始将比特矩阵数组转化为字节数组
		if (acMatrix != null && acMatrix.length == 3) {
            for (int i = 0; i < 3; i++) {
                if (acMatrix[i].length != 4)
                    // Error.
                    return null;
            }
        } else {
            // Error.
            return null;
        }
        byte[] acBytes = new byte[3];
        // Byte 6, Bit 0-3.
        acBytes[0] = (byte)((acMatrix[0][0]^0xFF)&0x01);
        acBytes[0] |= (byte)(((acMatrix[0][1]^0xFF)<<1)&0x02);
        acBytes[0] |= (byte)(((acMatrix[0][2]^0xFF)<<2)&0x04);
        acBytes[0] |= (byte)(((acMatrix[0][3]^0xFF)<<3)&0x08);
        // Byte 6, Bit 4-7.
        acBytes[0] |= (byte)(((acMatrix[1][0]^0xFF)<<4)&0x10);
        acBytes[0] |= (byte)(((acMatrix[1][1]^0xFF)<<5)&0x20);
        acBytes[0] |= (byte)(((acMatrix[1][2]^0xFF)<<6)&0x40);
        acBytes[0] |= (byte)(((acMatrix[1][3]^0xFF)<<7)&0x80);
        // Byte 7, Bit 0-3.
        acBytes[1] = (byte)((acMatrix[2][0]^0xFF)&0x01);
        acBytes[1] |= (byte)(((acMatrix[2][1]^0xFF)<<1)&0x02);
        acBytes[1] |= (byte)(((acMatrix[2][2]^0xFF)<<2)&0x04);
        acBytes[1] |= (byte)(((acMatrix[2][3]^0xFF)<<3)&0x08);
        // Byte 7, Bit 4-7.
        acBytes[1] |= (byte)((acMatrix[0][0]<<4)&0x10);
        acBytes[1] |= (byte)((acMatrix[0][1]<<5)&0x20);
        acBytes[1] |= (byte)((acMatrix[0][2]<<6)&0x40);
        acBytes[1] |= (byte)((acMatrix[0][3]<<7)&0x80);
        // Byte 8, Bit 0-3.
        acBytes[2] = (byte)(acMatrix[1][0]&0x01);
        acBytes[2] |= (byte)((acMatrix[1][1]<<1)&0x02);
        acBytes[2] |= (byte)((acMatrix[1][2]<<2)&0x04);
        acBytes[2] |= (byte)((acMatrix[1][3]<<3)&0x08);
        // Byte 8, Bit 4-7.
        acBytes[2] |= (byte)((acMatrix[2][0]<<4)&0x10);
        acBytes[2] |= (byte)((acMatrix[2][1]<<5)&0x20);
        acBytes[2] |= (byte)((acMatrix[2][2]<<6)&0x40);
        acBytes[2] |= (byte)((acMatrix[2][3]<<7)&0x80);

        return acBytes;
	}
	
	/**
     * Convert the Access Condition bytes to a matrix containing the
     * resolved C1, C2 and C3 for each block.
     * @param acBytes 控制位字节数组
     * @return 返回由3字节的控制位解析出来的控制位(bit)矩阵
     * null will be returned.
     */
    public static byte[][] acBytesToACMatrix(byte acBytes[]) {
        // ACs correct?
        // C1 (Byte 7, 4-7) == ~C1 (Byte 6, 0-3) and
        // C2 (Byte 8, 0-3) == ~C2 (Byte 6, 4-7) and
        // C3 (Byte 8, 4-7) == ~C3 (Byte 7, 0-3)
        byte[][] acMatrix = new byte[3][4];
        if (acBytes.length > 2 &&
                (byte)((acBytes[1]>>>4)&0x0F)  ==
                        (byte)((acBytes[0]^0xFF)&0x0F) &&
                (byte)(acBytes[2]&0x0F) ==
                        (byte)(((acBytes[0]^0xFF)>>>4)&0x0F) &&
                (byte)((acBytes[2]>>>4)&0x0F)  ==
                        (byte)((acBytes[1]^0xFF)&0x0F)) {
            // C1, Block 0-3
            for (int i = 0; i < 4; i++) {
                acMatrix[0][i] = (byte)((acBytes[1]>>>4+i)&0x01);
            }
            // C2, Block 0-3
            for (int i = 0; i < 4; i++) {
                acMatrix[1][i] = (byte)((acBytes[2]>>>i)&0x01);
            }
            // C3, Block 0-3
            for (int i = 0; i < 4; i++) {
                acMatrix[2][i] = (byte)((acBytes[2]>>>4+i)&0x01);
            }
            return acMatrix;
        }
        return null;
    }

    /**
     * 把矩阵控制位(比特类型的矩阵数组)转换为3字节的控制位
     * @param acMatrix bit类型的控制位矩阵数组
     * @return 返回3字节的字节数组
     */
    public static byte[] acMatrixToACBytes(byte acMatrix[][]) {
        if (acMatrix != null && acMatrix.length == 3) {
            for (int i = 0; i < 3; i++) {
                if (acMatrix[i].length != 4)
                    // Error.
                    return null;
            }
        } else {
            // Error.
            return null;
        }
        byte[] acBytes = new byte[3];
        // Byte 6, Bit 0-3.
        acBytes[0] = (byte)((acMatrix[0][0]^0xFF)&0x01);
        acBytes[0] |= (byte)(((acMatrix[0][1]^0xFF)<<1)&0x02);
        acBytes[0] |= (byte)(((acMatrix[0][2]^0xFF)<<2)&0x04);
        acBytes[0] |= (byte)(((acMatrix[0][3]^0xFF)<<3)&0x08);
        // Byte 6, Bit 4-7.
        acBytes[0] |= (byte)(((acMatrix[1][0]^0xFF)<<4)&0x10);
        acBytes[0] |= (byte)(((acMatrix[1][1]^0xFF)<<5)&0x20);
        acBytes[0] |= (byte)(((acMatrix[1][2]^0xFF)<<6)&0x40);
        acBytes[0] |= (byte)(((acMatrix[1][3]^0xFF)<<7)&0x80);
        // Byte 7, Bit 0-3.
        acBytes[1] = (byte)((acMatrix[2][0]^0xFF)&0x01);
        acBytes[1] |= (byte)(((acMatrix[2][1]^0xFF)<<1)&0x02);
        acBytes[1] |= (byte)(((acMatrix[2][2]^0xFF)<<2)&0x04);
        acBytes[1] |= (byte)(((acMatrix[2][3]^0xFF)<<3)&0x08);
        // Byte 7, Bit 4-7.
        acBytes[1] |= (byte)((acMatrix[0][0]<<4)&0x10);
        acBytes[1] |= (byte)((acMatrix[0][1]<<5)&0x20);
        acBytes[1] |= (byte)((acMatrix[0][2]<<6)&0x40);
        acBytes[1] |= (byte)((acMatrix[0][3]<<7)&0x80);
        // Byte 8, Bit 0-3.
        acBytes[2] = (byte)(acMatrix[1][0]&0x01);
        acBytes[2] |= (byte)((acMatrix[1][1]<<1)&0x02);
        acBytes[2] |= (byte)((acMatrix[1][2]<<2)&0x04);
        acBytes[2] |= (byte)((acMatrix[1][3]<<3)&0x08);
        // Byte 8, Bit 4-7.
        acBytes[2] |= (byte)((acMatrix[2][0]<<4)&0x10);
        acBytes[2] |= (byte)((acMatrix[2][1]<<5)&0x20);
        acBytes[2] |= (byte)((acMatrix[2][2]<<6)&0x40);
        acBytes[2] |= (byte)((acMatrix[2][3]<<7)&0x80);
        
        return acBytes;
    }
    
    /*
     * 根据一个控制位来进行所有的操作时使用的对象
     * @param acBytes 控制位字节,四字节的控制位字节数组
     * @return 返回this
     */
    public static AccessBitUitl operaOneAc(byte[] acBytes) {
    	return new AccessBitUitl(acBytes);
    }
    
    
    /*
     * 重载unpackAccessInfo,简化调用
     */
    public HashMap<ControlBitNum,Byte> unpackAccessInfo(DataBlockStructure block){
    	return unpackAccessInfo(mAcBytes,block);
    }
    
    /*
     * 重载unpackAccessInfo,简化调用
     */
    public HashMap<DataBlockStructure,HashMap<ControlBitNum,Byte>> unpackAccessInfo(){
    	DataBlockStructure[] blocks = { DataBlockStructure.BLOCK0 ,
    			DataBlockStructure.BLOCK1 , 
    			DataBlockStructure.BLOCK2 , 
    			DataBlockStructure.BLOCK3 };
    	HashMap<DataBlockStructure,HashMap<ControlBitNum,Byte>> result = new HashMap<DataBlockStructure,HashMap<ControlBitNum,Byte>>();
    	for(int i = 0; i < 4; ++i) {
    		result.put(blocks[i] , unpackAccessInfo(blocks[i]));
    	}
    	return result;
    }
    
    
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值