/**
******************************************************************************
* @file billmode.c
* @author TMC Scan Team
* @version V1.0.0
* @date 09/06/2019
* @brief This file provides the different modes of scanning.
******************************************************************************
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, TMC SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
*
© COPYRIGHT 2016 TMC
******************************************************************************
**/
#include "global.h"
static const unsigned char base64_suffix_map[256] =
{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255
};
const uint8_t TAXHead[3][2] = {{0x30, 0x31}, {0x31, 0x30}, {0x30, 0x34}};
const uint8_t BaiWangHead[7] = {0x5C, 0x30, 0x30, 0x30, 0x30, 0x32, 0x36};
const uint8_t HangXinHead[5] = {0x6C, 0x78, 0x6B, 0x70, 0x3A};
const uint8_t QuanMinETail[9] = "CHINAUMS_";
/**
* @function base64_decode
* @brief base64解码
* @param[in] *indata input data
* @param[in] inlen input data length
* @param[out] *outdata output data buf
* @param[out] *outlen output data length
* @return
*/
int base64_decode(const uint8_t *indata, uint16_t inlen, uint8_t *outdata, uint16_t *outlen)
{
int ret = 0;
if(indata == NULL || inlen <= 0 || outdata == NULL || outlen == NULL)
{
return ret = -1;
}
ret = inlen % 4;
if(ret != 0)
{
// 需要解码的数据不是4字节倍数
return ret = -2;
}
int t = 0, x = 0, y = 0, i = 0;
unsigned char c = 0;
int g = 3;
while((indata[x] != 0) && (x < inlen))
{
// 需要解码的数据对应的ASCII值对应base64_suffix_map的值
c = base64_suffix_map[indata[x++]];
if(c == 255) { return -1; } // 对应的值不在转码表中
if(c == 253) { continue; } // 对应的值是换行或者回车
if(c == 254) { c = 0; g--; } // 对应的值是'='
t = (t << 6) | c; // 将其依次放入一个int型中占3字节
if(++y == 4)
{
outdata[i++] = (unsigned char)((t >> 16) & 0xff);
if(g > 1) { outdata[i++] = (unsigned char)((t >> 8) & 0xff); }
if(g > 2) { outdata[i++] = (unsigned char)(t & 0xff); }
y = t = 0;
}
}
*outlen = (i - 4); //四位校验位
return ret;
}
/**
* @function TaxBillMode
* @brief 解析税务发票助手的数据
* @param[in] pCode 输入数据
* @return
*/
int TaxBillMode(BarData *pCode)
{
int ret, i = 0, j = 0;
uint8_t *pData = NULL;
pData = (uint8_t *) PREOUTBUF;
uint16_t dataLen = 0;
uint8_t *pOut = NULL;
pOut = (uint8_t *) POSOUTBUF;
// 需要解码的数据需要是4字节倍数
ret = (pCode->datalen - 4) % 4;
i = 0;
if(ret > 0)
{
while((4 - ret) != 0)
{
pCode->bardata[pCode->datalen - 1 + i] = '=';
ret++;
i++;
}
}
ret = base64_decode(pCode->bardata + 3, pCode->datalen - 4 + i, pData, &dataLen);
if(ret == 0)
{
i = 0;
while(i < dataLen)
{
if(pData[i] == 0x3C)
{
if((pData[i + 1] == 0x2F) && ((pData[i + 2] == 0x3E)))
{
pOut[j] = 0x20;
j++;
pOut[j] = 0x09;
j++;
i += 3;
}
else
{
pOut[j] = pData[i];
j++;
i++;
}
}
else
{
pOut[j] = pData[i];
j++;
i++;
}
}
Memcpy(pCode->bardata, pOut, j);
pCode->datalen = j;
return j;
}
else
{
return 0;
}
}
/**
* @function HangXinBillMode
* @brief 航信发票助手,从生成的码制上看,存在两种情况,一种数字开头,需要去掉多余位
* 另外一种直接打印即可
* @param[in] pCode 输入数据
* @return
*/
int HangXinBillMode(BarData *pCode)
{
int ret, i = 0, j = 0;
int base64codelen = pCode->datalen - 6;
uint8_t *pData = NULL;
pData = (uint8_t *) PREOUTBUF;
uint16_t dataLen = 0;
uint8_t *pOut = NULL;
pOut = (uint8_t *) POSOUTBUF;
// 需要解码的数据需要是4字节倍数
ret = base64codelen % 4;
i = 0;
if(ret > 0)
{
while((4 - ret) != 0)
{
pCode->bardata[pCode->datalen - 1 + i] = '=';
ret++;
i++;
}
}
ret = base64_decode(pCode->bardata + 5, pCode->datalen - 6 + i, pData, &dataLen);
if(ret == 0)
{
i = 0;
if((pData[0] >= 0x30) && (pData[0] <= 0x39))
{
i = 1;
dataLen = dataLen - 2;
}
while(i < dataLen)
{
if(pData[i] == 0x3C)
{
if((pData[i + 1] == 0x2F) && ((pData[i + 2] == 0x3E)))
{
pOut[j] = 0x20;
j++;
pOut[j] = 0x09;
j++;
i += 3;
}
else
{
pOut[j] = pData[i];
j++;
i++;
}
}
else
{
pOut[j] = pData[i];
j++;
i++;
}
}
Memcpy(pCode->bardata, pOut, j);
pCode->datalen = j;
return j;
}
else
{
return 0;
}
}
/**
* @function AliBillMode
* @brief 支付宝发票助手
* @param[in] pCode 输入数据
* @return
*/
int AliBillMode(BarData *pCode)
{
int i = 0, j = 0;
uint8_t *pOut = NULL;
pOut = (uint8_t *) POSOUTBUF;
i = 2;
j = 0;
while(i < pCode->datalen)
{
if(pCode->bardata[i] == 0xE2)
{
if((pCode->bardata[i + 1] == 0x86) && (pCode->bardata[i + 2] == 0x92))
{
pOut[j] = 0x20;
j++;
pOut[j] = 0x09;
j++;
i += 4;
}
else
{
pOut[j] = pCode->bardata[i];
i++;
j++;
}
}
else if((pCode->bardata[i] == 0x41) && (pCode->bardata[i + 1] == 0x4C))
{
if((pCode->bardata[i + 2] == 0x49) && (pCode->bardata[i + 3] == 0x50))
{
break;
}
else
{
pOut[j] = pCode->bardata[i];
i++;
j++;
}
}
else
{
pOut[j] = pCode->bardata[i];
i++;
j++;
}
}
if(j > 0)
{
Memcpy(pCode->bardata, pOut, j);
pCode->datalen = j;
}
else
{
return 0;
}
return j;
}
/**
* @function BaiWangBillMode
* @brief 百旺发票助手
* @param[in] pCode 输入数据
* @return
*/
int BaiWangBillMode(BarData *pCode)
{
int i = 0, j = 0;
uint8_t *pOut = NULL;
pOut = (uint8_t *) POSOUTBUF;
i = 9;
j = 0;
while(i < pCode->datalen)
{
if(pCode->bardata[i] == 0xE2)
{
if((pCode->bardata[i + 1] == 0x86) && (pCode->bardata[i + 2] == 0x92))
{
pOut[j] = 0x20;
j++;
pOut[j] = 0x09;
j++;
i += 4;
}
else
{
pOut[j] = pCode->bardata[i];
i++;
j++;
}
}
else
{
pOut[j] = pCode->bardata[i];
i++;
j++;
}
}
if(j > 0)
{
Memcpy(pCode->bardata, pOut, j);
pCode->datalen = j;
}
else
{
return 0;
}
return j;
}
/**
* @function QuanMinEBillMode
* @brief 全民E发票助手
* @param[in] pCode 输入数据
* @return
*/
int QuanMinEBillMode(BarData *pCode)
{
int i = 0, j = 0;
uint8_t *pOut = NULL;
pOut = (uint8_t *) POSOUTBUF;
i = 1;
j = 0;
while(i < (pCode->datalen - 9))
{
if(pCode->bardata[i] == 0xE2)
{
if((pCode->bardata[i + 1] == 0x86) && (pCode->bardata[i + 2] == 0x92))
{
pOut[j] = 0x20;
j++;
pOut[j] = 0x09;
j++;
i += 4;
}
else
{
pOut[j] = pCode->bardata[i];
i++;
j++;
}
}
else
{
pOut[j] = pCode->bardata[i];
i++;
j++;
}
}
if(j > 0)
{
Memcpy(pCode->bardata, pOut, j);
pCode->datalen = j;
}
else
{
return 0;
}
return j;
}
//增值税发票
int VATBillMode(BarData *pCode)
{
int i = 5, j = 0;
uint8_t *pOut = NULL;
pOut = (uint8_t *) POSOUTBUF;
for(i = 0; i < 3; i++)
{
if(Memcmp(&pCode->bardata[3], (uint8_t *)&TAXHead[i][0], 2) == TRUE)
{
break;
}
}
if(i >= 3)
{
return 0;
}
if(pCode->bardata[5] == ',')
{
for(i = 6; i < (pCode->datalen - 6); i++)
{
if(pCode->bardata[i] == ',')
{
pOut[j] = 0x09;
}
else
{
pOut[j] = pCode->bardata[i];
}
j++;
}
}
if(j > 0)
{
memcpy(pCode->bardata, pOut, j);
pCode->datalen = j;
}
else
{
return 0;
}
return j;
}
/**
* @function BillMode
* @brief 解析不同发票模式数据
* @param[in] pCode 输入数据
* @return 如果是发票数据,返回值大于0;否则返回0
*/
int BillMode(BarData *pCode)
{
int tmp;
/*如果符合发票模式,进行发票模式输出*/
/*税务发票助手*/
if((pCode->bardata[0] == '$') && (pCode->bardata[pCode->datalen - 1] == '$'))
{
if((pCode->bardata[1] == '0') && (pCode->bardata[2] == '1'))
{
tmp = TaxBillMode(pCode);
return tmp;
}
}
/*支付宝发票助手*/
if((pCode->bardata[0] == '1') && (pCode->bardata[pCode->datalen - 1] == 0x92))
{
if((pCode->bardata[pCode->datalen - 2] == 0x86) && (pCode->bardata[pCode->datalen - 3] == 0xE2))
{
tmp = AliBillMode(pCode);
return tmp;
}
}
//百旺发票助手
if((Memcmp(pCode->bardata, (uint8_t *) BaiWangHead, sizeof(BaiWangHead))) && (pCode->bardata[pCode->datalen - 1] == 0x92))
{
if((pCode->bardata[pCode->datalen - 2] == 0x86) && (pCode->bardata[pCode->datalen - 3] == 0xE2))
{
tmp = BaiWangBillMode(pCode);
return tmp;
}
}
//航信发票助手
if((Memcmp(pCode->bardata, (uint8_t *) HangXinHead, sizeof(HangXinHead))) && (pCode->bardata[pCode->datalen - 1] == '$'))
{
tmp = HangXinBillMode(pCode);
return tmp;
}
//全民E发票助手
if(pCode->bardata[0] == '1')
{
if(Memcmp(&pCode->bardata[pCode->datalen - 9], (uint8_t *) QuanMinETail, sizeof(QuanMinETail)))
{
tmp = QuanMinEBillMode(pCode);
return tmp;
}
}
//增值税发票
if((pCode->bartype == QR_Id) && (pCode->bardata[0] == '0'))
{
if((pCode->bardata[1] == '1') && (pCode->bardata[2] == ','))
{
tmp = VATBillMode(pCode);
return tmp;
}
}
return 0;
}