+// https://github.com/binaryfoo/emv-bertlv/blob/master/src/main/resources/fields/visa-cvr.txt
+static void emv_tag_dump_cvr(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
+ if (!tlv || tlv->len < 1) {
+ PRINT_INDENT(level);
+ fprintf(f, "\tINVALID!\n");
+ return;
+ }
+
+ if (tlv->len != tlv->value[0] + 1) {
+ PRINT_INDENT(level);
+ fprintf(f, "\tINVALID length!\n");
+ return;
+ }
+
+ if (tlv->len >= 2) {
+ // AC1
+ PRINT_INDENT(level);
+ if ((tlv->value[1] & 0xC0) == 0x00) fprintf(f, "\tAC1: AAC (Transaction declined)\n");
+ if ((tlv->value[1] & 0xC0) == 0x40) fprintf(f, "\tAC1: TC (Transaction approved)\n");
+ if ((tlv->value[1] & 0xC0) == 0x80) fprintf(f, "\tAC1: ARQC (Online authorisation requested)\n");
+ if ((tlv->value[1] & 0xC0) == 0xC0) fprintf(f, "\tAC1: RFU\n");
+ // AC2
+ PRINT_INDENT(level);
+ if ((tlv->value[1] & 0x30) == 0x00) fprintf(f, "\tAC2: AAC (Transaction declined)\n");
+ if ((tlv->value[1] & 0x30) == 0x10) fprintf(f, "\tAC2: TC (Transaction approved)\n");
+ if ((tlv->value[1] & 0x30) == 0x20) fprintf(f, "\tAC2: not requested (ARQC)\n");
+ if ((tlv->value[1] & 0x30) == 0x30) fprintf(f, "\tAC2: RFU\n");
+ }
+ if (tlv->len >= 3 && (tlv->value[2] >> 4)) {
+ PRINT_INDENT(level);
+ fprintf(f, "\tPIN try: %x\n", tlv->value[2] >> 4);
+ }
+ if (tlv->len >= 4 && (tlv->value[3] & 0x0F)) {
+ PRINT_INDENT(level);
+ fprintf(f, "\tIssuer discretionary bits: %x\n", tlv->value[3] & 0x0F);
+ }
+ if (tlv->len >= 5 && (tlv->value[4] >> 4)) {
+ PRINT_INDENT(level);
+ fprintf(f, "\tSuccessfully processed issuer script commands: %x\n", tlv->value[4] >> 4);
+ }
+
+ // mask 0F 0F F0 0F
+ uint8_t data[20] = {0};
+ memcpy(data, &tlv->value[1], tlv->len - 1);
+ data[0] &= 0x0F;
+ data[1] &= 0x0F;
+ data[2] &= 0xF0;
+ data[3] &= 0x0F;
+ const struct tlv bit_tlv = {
+ .tag = tlv->tag,
+ .len = tlv->len - 1,
+ .value = data,
+ };
+ const struct emv_tag bit_tag = {
+ .tag = tag->tag,
+ .name = tag->name,
+ .type = EMV_TAG_BITMASK,
+ .data = EMV_CVR,
+ };
+
+ if (data[0] || data[1] || data[2] || data[3])
+ emv_tag_dump_bitmask(&bit_tlv, &bit_tag, f, level);
+
+ return;
+}
+
+// EMV Book 3
+static void emv_tag_dump_cid(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
+ if (!tlv || tlv->len < 1) {
+ PRINT_INDENT(level);
+ fprintf(f, "\tINVALID!\n");
+ return;
+ }
+
+ PRINT_INDENT(level);
+ if ((tlv->value[0] & EMVAC_AC_MASK) == EMVAC_AAC) fprintf(f, "\tAC1: AAC (Transaction declined)\n");
+ if ((tlv->value[0] & EMVAC_AC_MASK) == EMVAC_TC) fprintf(f, "\tAC1: TC (Transaction approved)\n");
+ if ((tlv->value[0] & EMVAC_AC_MASK) == EMVAC_ARQC) fprintf(f, "\tAC1: ARQC (Online authorisation requested)\n");
+ if ((tlv->value[0] & EMVAC_AC_MASK) == EMVAC_AC_MASK) fprintf(f, "\tAC1: RFU\n");
+
+ if (tlv->value[0] & EMVCID_ADVICE) {
+ PRINT_INDENT(level);
+ fprintf(f, "\tAdvice required!\n");
+ }
+
+ if (tlv->value[0] & EMVCID_REASON_MASK) {
+ PRINT_INDENT(level);
+ fprintf(f, "\tReason/advice/referral code: ");
+ switch((tlv->value[0] & EMVCID_REASON_MASK)) {
+ case 0:
+ fprintf(f, "No information given\n");
+ break;
+ case 1:
+ fprintf(f, "Service not allowed\n");
+ break;
+ case 2:
+ fprintf(f, "PIN Try Limit exceeded\n");
+ break;
+ case 3:
+ fprintf(f, "Issuer authentication failed\n");
+ break;
+ default:
+ fprintf(f, "\tRFU: %2x\n", (tlv->value[0] & EMVCID_REASON_MASK));
+ break;
+ }
+ }
+
+ return;
+}
+