All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.devnied.emvnfccard.parser.apdu.impl.DataFactory Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2019 MILLAU Julien
 *
 * 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 com.github.devnied.emvnfccard.parser.apdu.impl;

import com.github.devnied.emvnfccard.model.enums.IKeyEnum;
import com.github.devnied.emvnfccard.parser.apdu.annotation.AnnotationData;
import com.github.devnied.emvnfccard.utils.EnumUtils;
import fr.devnied.bitlib.BitUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.Date;

/**
 * Factory to parse data
 *
 * @author MILLAU Julien
 */
public final class DataFactory {

	/**
	 * Logger of this class
	 */
	public static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class.getName());

	/**
	 * Constant for EN1545-1 (Date format)
	 */
	public static final int BCD_DATE = 1;

	public static final int CPCL_DATE = 2;

	/**
	 * Half byte size
	 */
	public static final int HALF_BYTE_SIZE = 4;

	/**
	 * BCD format
	 */
	public static final String BCD_FORMAT = "BCD_Format";

	/**
	 * Method to get a date from the bytes array
	 *
	 * @param pAnnotation
	 *            annotation data
	 * @param pBit
	 *            table bytes
	 * @return The date read of null
	 */
	private static Date getDate(final AnnotationData pAnnotation, final BitUtils pBit) {
		Date date = null;
		if (pAnnotation.getDateStandard() == BCD_DATE) {
			date = pBit.getNextDate(pAnnotation.getSize(), pAnnotation.getFormat(), true);
		} else if (pAnnotation.getDateStandard() == CPCL_DATE) {
			date = calculateCplcDate(pBit.getNextByte(pAnnotation.getSize()));
		} else {
			date = pBit.getNextDate(pAnnotation.getSize(), pAnnotation.getFormat());
		}
		return date;
	}


	/**
	 * Takes a date value as used in CPLC Date fields (represented by 2 bytes)
	 *
	 * @param dateBytes raw bytes
	 * @throws IllegalArgumentException when the data size is wrong
	 * @return the date
	 */
	public static Date calculateCplcDate(byte[] dateBytes)
			throws IllegalArgumentException {
		if (dateBytes == null || dateBytes.length != 2) {
			throw new IllegalArgumentException(
					"Error! CLCP Date values consist always of exactly 2 bytes");
		}
		// Check empty date
		if (dateBytes[0] == 0 && dateBytes[1] == 0){
			return null;
		}
		// current time
		Calendar now = Calendar.getInstance();

		int currenctYear = now.get(Calendar.YEAR);
		int startYearOfCurrentDecade = currenctYear - (currenctYear % 10);

		int days = 100 * (dateBytes[0] & 0xF) + 10 * (0xF & dateBytes[1] >>> 4) + (dateBytes[1] & 0xF);

		if (days > 366) {
			throw new IllegalArgumentException(
					"Invalid date (or are we parsing it wrong??)");
		}

		Calendar calculatedDate = Calendar.getInstance();
		calculatedDate.clear();
		int year = startYearOfCurrentDecade + (0xF & dateBytes[0] >>> 4);
		calculatedDate.set(Calendar.YEAR, year);
		calculatedDate.set(Calendar.DAY_OF_YEAR, days);
		while (calculatedDate.after(now)) {
			year = year - 10;
			calculatedDate.clear();
			calculatedDate.set(Calendar.YEAR, year);
			calculatedDate.set(Calendar.DAY_OF_YEAR, days);
		}
		return calculatedDate.getTime();
	}

	/**
	 * This method is used to get an integer
	 *
	 * @param pAnnotation
	 *            annotation
	 * @param pBit
	 *            bit array
	 * @return the integer value
	 */
	private static int getInteger(final AnnotationData pAnnotation, final BitUtils pBit) {
		return pBit.getNextInteger(pAnnotation.getSize());
	}

	/**
	 * Method to read and object from the bytes tab
	 *
	 * @param pAnnotation
	 *            all information data
	 * @param pBit
	 *            bytes tab
	 * @return an object
	 */
	public static Object getObject(final AnnotationData pAnnotation, final BitUtils pBit) {
		Object obj = null;
		Class clazz = pAnnotation.getField().getType();

		if (clazz.equals(Integer.class)) {
			obj = getInteger(pAnnotation, pBit);
		} else if (clazz.equals(Float.class)) {
			obj = getFloat(pAnnotation, pBit);
		} else if (clazz.equals(String.class)) {
			obj = getString(pAnnotation, pBit);
		} else if (clazz.equals(Date.class)) {
			obj = getDate(pAnnotation, pBit);
		} else if (clazz.isEnum()) {
			obj = getEnum(pAnnotation, pBit);
		}
		return obj;
	}

	/**
	 * Method use to get float
	 *
	 * @param pAnnotation
	 *            annotation
	 * @param pBit
	 *            bit utils
	 * @return
	 */
	private static Float getFloat(final AnnotationData pAnnotation, final BitUtils pBit) {
		Float ret = null;

		if (BCD_FORMAT.equals(pAnnotation.getFormat())) {
			ret = Float.parseFloat(pBit.getNextHexaString(pAnnotation.getSize()));
		} else {
			ret = (float) getInteger(pAnnotation, pBit);
		}

		return ret;
	}

	/**
	 * This method is used to get an enum with his key
	 *
	 * @param pAnnotation
	 *            annotation
	 * @param pBit
	 *            bit array
	 */
	@SuppressWarnings("unchecked")
	private static IKeyEnum getEnum(final AnnotationData pAnnotation, final BitUtils pBit) {
		int val = 0;
		try {
			val = Integer.parseInt(pBit.getNextHexaString(pAnnotation.getSize()), pAnnotation.isReadHexa() ? 16 : 10);
		} catch (NumberFormatException nfe) {
			// do nothing
		}
		return EnumUtils.getValue(val, (Class) pAnnotation.getField().getType());
	}

	/**
	 * This method get a string (Hexa or ASCII) from a bit table
	 *
	 * @param pAnnotation
	 *            annotation data
	 * @param pBit
	 *            bit table
	 * @return A string
	 */
	private static String getString(final AnnotationData pAnnotation, final BitUtils pBit) {
		String obj = null;

		if (pAnnotation.isReadHexa()) {
			obj = pBit.getNextHexaString(pAnnotation.getSize());
		} else {
			obj = pBit.getNextString(pAnnotation.getSize()).trim();
		}

		return obj;
	}

	/**
	 * Private constructor
	 */
	private DataFactory() {
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy