X-Git-Url: http://git.cascardo.eti.br/?p=cascardo%2Flibreceita.git;a=blobdiff_plain;f=decfile.c;h=26ef3bce777f6daaed6caf5d9ab207ebcfdee9ec;hp=196f591b3f33d8480d3e368ea9c24d18c2406c80;hb=HEAD;hpb=9d3ece1dba6b6d5d1313a6cd68d0b56856690714 diff --git a/decfile.c b/decfile.c index 196f591..26ef3bc 100644 --- a/decfile.c +++ b/decfile.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2012-2013 Thadeu Lima de Souza Cascardo + * Copyright (C) 2012-2014 Thadeu Lima de Souza Cascardo + * Copyright (C) 2014 Alexandre Oliva * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,7 +24,13 @@ #include #include #include +#include #include "pmhash.h" +#include "rnet_message.h" + +#ifndef MAX +#define MAX(a,b) (a >= b) ? a : b +#endif struct rnet_decfile { char *filename; @@ -31,6 +38,7 @@ struct rnet_decfile { char **lines; int lines_len; struct pmhash *header; + struct rnet_message *message; }; /* @@ -53,7 +61,7 @@ static int append_line(struct rnet_decfile *decfile, char *line) return 0; out: decfile->lines_len -= 1; - return -1; + return -ENOMEM; } static void decfile_release_lines(struct rnet_decfile *decfile) @@ -66,14 +74,23 @@ static void decfile_release_lines(struct rnet_decfile *decfile) } static char * get_header(struct rnet_decfile *decfile); -static int parse_header(struct pmhash *hash, char *buffer); +static int parse_header_2013(struct pmhash *hash, char *buffer); +static int parse_header_2014(struct pmhash *hash, char *buffer); +static int decfile_parse_file(struct rnet_decfile *decfile); static int decfile_parse_header(struct rnet_decfile *decfile) { char *buffer = get_header(decfile); - if (!buffer || strlen(buffer) != 765) - return 1; - return parse_header(decfile->header, buffer); + if (!buffer) + return -EINVAL; + switch (strlen(buffer)) { + case RNET_HEADER_SIZE_2013: + return parse_header_2013(decfile->header, buffer); + case RNET_HEADER_SIZE_2014: + return parse_header_2014(decfile->header, buffer); + default: + return -EINVAL; + } } static int decfile_parse(struct rnet_decfile *decfile) @@ -90,22 +107,26 @@ static int decfile_parse(struct rnet_decfile *decfile) buffer = NULL; len = 0; } - if (!decfile_parse_header(decfile)) + if (!(r = decfile_parse_header(decfile)) && !(r = decfile_parse_file(decfile))) return 0; out: decfile_release_lines(decfile); - return -1; + return r; } struct rnet_decfile * rnet_decfile_open(char *filename) { struct rnet_decfile *decfile; + int r = -ENOMEM; decfile = malloc(sizeof(*decfile)); if (!decfile) return NULL; decfile->header = pmhash_new(); if (!decfile->header) goto out_header; + decfile->message = rnet_message_new(); + if (!decfile->message) + goto out_message; decfile->filename = strdup(filename); if (!decfile->filename) goto out_filename; @@ -114,7 +135,7 @@ struct rnet_decfile * rnet_decfile_open(char *filename) goto out_file; decfile->lines_len = 0; decfile->lines = NULL; - if (decfile_parse(decfile)) + if ((r = decfile_parse(decfile))) goto out_parse; return decfile; out_parse: @@ -122,9 +143,12 @@ out_parse: out_file: free(decfile->filename); out_filename: + rnet_message_del(decfile->message); +out_message: pmhash_del(decfile->header); out_header: free(decfile); + errno = -r; return NULL; } @@ -147,13 +171,16 @@ static char * get_header(struct rnet_decfile *decfile) return NULL; } -static int parse_header(struct pmhash *hash, char *buffer) +static int parse_header_2014(struct pmhash *hash, char *buffer) { + int r; char *p = buffer; char *key; char *val; + char *tail; #define parse(field, sz) \ + r = -ENOMEM; \ val = malloc(sz + 1); \ if (!val) \ goto out_val; \ @@ -168,6 +195,10 @@ static int parse_header(struct pmhash *hash, char *buffer) parse("sistema", 8); parse("exerc", 4); + if (strcmp(val, "2014")) { + r = -EINVAL; + goto out_val; + } parse("ano", 4); parse("codigo_recnet", 4); parse("in_ret", 1); @@ -178,6 +209,12 @@ static int parse_header(struct pmhash *hash, char *buffer) parse("nome", 60); parse("uf", 2); parse("hash", 10); + + if (p - buffer != RNET_HEADER_HEAD_2014) { + fprintf(stderr, "RNET_HEADER_HEAD_2014 in decfile.h needs to be adjusted to %ti\n", p - buffer); + goto out_val; + } + parse("in_cert", 1); parse("dt_nasc", 8); parse("in_comp", 1); @@ -211,6 +248,8 @@ static int parse_header(struct pmhash *hash, char *buffer) parse("cpf_rra2", 11); parse("trib_3rra", 1); parse("cpf_rra3", 11); + parse("trib_4rra", 1); + parse("cpf_rra4", 11); parse("vr_doacao", 13); parse("cnpj1", 14); parse("cnpj2", 14); @@ -245,19 +284,279 @@ static int parse_header(struct pmhash *hash, char *buffer) parse("vr_totisentos", 13); parse("vr_totexclusivo", 13); parse("vr_totpagamentos", 13); + parse("nr_conta", 13); + parse("nr_dv_conta", 2); + parse("in_dv_conta", 1); + + tail = p; + parse("versaotestpgd", 3); parse("controle", 10); + if (*p++ != '\r') { + fprintf(stderr, + "missing CR at the %tith header character\n", + p - buffer); + goto out_val; + } else if (*p++ != '\n') { + fprintf(stderr, + "missing LF at the %tith header character\n", + p - buffer); + goto out_val; + } else if (*p != 0) { + fprintf(stderr, + "missing NUL at the %tith header character\n", + p - buffer); + goto out_val; + } else if (p - buffer != RNET_HEADER_SIZE_2014) { + fprintf(stderr, "RNET_HEADER_SIZE_2014 in decfile.h needs to be adjusted to %ti,\nor parse_header in decfile.c needs updating\n", p - buffer); + goto out_val; + } else if (p - tail != RNET_HEADER_TAIL_2014) { + fprintf(stderr, "RNET_HEADER_TAIL_2014 in decfile.h needs to be adjusted to %ti\n", p - tail); + goto out_val; + } + return 0; out_add: free(key); out_key: free(val); out_val: - return -1; + return r; +} + +static int parse_header_2013(struct pmhash *hash, char *buffer) +{ + int r; + char *p = buffer; + char *key; + char *val; + char *tail; + +#define parse(field, sz) \ + r = -ENOMEM; \ + val = malloc(sz + 1); \ + if (!val) \ + goto out_val; \ + val[sz] = 0; \ + memcpy(val, p, sz); \ + p += sz; \ + key = strdup(field); \ + if (!key) \ + goto out_key; \ + if (pmhash_add(&hash, key, val)) \ + goto out_add; + + parse("sistema", 8); + parse("exerc", 4); + if (strcmp(val, "2013")) { + r = -EINVAL; + goto out_val; + } + parse("ano", 4); + parse("codigo_recnet", 4); + parse("in_ret", 1); + parse("cpf", 11); + parse("filler", 3); + parse("tipo_ni", 1); + parse("nr_versao", 3); + parse("nome", 60); + parse("uf", 2); + parse("hash", 10); + + if (p - buffer != RNET_HEADER_HEAD_2013) { + fprintf(stderr, "RNET_HEADER_HEAD_2013 in decfile.h needs to be adjusted to %ti\n", p - buffer); + goto out_val; + } + + parse("in_cert", 1); + parse("dt_nasc", 8); + parse("in_comp", 1); + parse("in_res", 1); + parse("in_gerada", 1); + parse("nr_recibo_anterior", 10); + parse("in_pgd", 1); + parse("so", 14); + parse("versao_so", 7); + parse("jvm", 9); + parse("nr_recibo", 10); + parse("municipio", 4); + parse("conjuge", 11); + parse("obrig", 1); + parse("impdevido", 13); + parse("nr_recibo", 10); + parse("in_seg", 1); + parse("imppago", 2); + parse("impant", 1); + parse("mudend", 1); + parse("cep", 8); + parse("debito", 1); + parse("banco", 3); + parse("agencia", 4); + parse("filler", 1); + parse("data_julgado", 8); + parse("imppagar", 13); + parse("tribfonte", 1); + parse("cpfrra", 11); + parse("trib_rra", 1); + parse("cpf_rra2", 11); + parse("trib_3rra", 1); + parse("cpf_rra3", 11); + parse("vr_doacao", 13); + parse("cnpj1", 14); + parse("cnpj2", 14); + parse("cnpj3", 14); + parse("cnpj4", 14); + parse("cpf_dep1", 11); + parse("dnas_dep1", 8); + parse("cpf_dep2", 11); + parse("dnas_dep2", 8); + parse("cpf_dep3", 11); + parse("dnas_dep3", 8); + parse("cpf_dep4", 11); + parse("dnas_dep4", 8); + parse("cpf_dep5", 11); + parse("dnas_dep5", 8); + parse("cpf_dep6", 11); + parse("dnas_dep6", 8); + parse("cnpj_med1", 14); + parse("cnpj_med2", 14); + parse("cpf_alim", 11); + parse("cpf_invent", 11); + parse("municipio", 40); + parse("contribuinte", 60); + parse("cpf_empregada", 11); + parse("hashcode", 12); + parse("data_nao_residente", 8); + parse("cpf_procurador", 11); + parse("obrigatoriedade", 3); + parse("rendtrib", 13); + parse("cnpj_prev", 14); + parse("cnpj_prev2", 14); + parse("vr_totisentos", 13); + parse("vr_totexclusivo", 13); + parse("vr_totpagamentos", 13); + + tail = p; + + parse("versaotestpgd", 3); + parse("controle", 10); + + if (*p++ != '\r') { + fprintf(stderr, + "missing CR at the %tith header character\n", + p - buffer); + goto out_val; + } else if (*p++ != '\n') { + fprintf(stderr, + "missing LF at the %tith header character\n", + p - buffer); + goto out_val; + } else if (*p != 0) { + fprintf(stderr, + "missing NUL at the %tith header character\n", + p - buffer); + goto out_val; + } else if (p - buffer != RNET_HEADER_SIZE_2013) { + fprintf(stderr, "RNET_HEADER_SIZE_2013 in decfile.h needs to be adjusted to %ti,\nor parse_header in decfile.c needs updating\n", p - buffer); + goto out_val; + } else if (p - tail != RNET_HEADER_TAIL_2013) { + fprintf(stderr, "RNET_HEADER_TAIL_2013 in decfile.h needs to be adjusted to %ti\n", p - tail); + goto out_val; + } + + return 0; +out_add: + free(key); +out_key: + free(val); +out_val: + return r; } char *rnet_decfile_get_header_field(struct rnet_decfile *decfile, char *field) { return pmhash_get(decfile->header, field); } + +/* returns true if register is declaration and not a receipt */ +static int decfile_reg_is_dec(char *line) +{ + if (line[0] >= '0' && line[0] <= '9' && + line[1] >= '0' && line[1] <= '9') + return 1; + if (!strncmp(line, "IRPF ", 8)) + return 1; + if (!strncmp(line, "T9", 2)) + return 1; + return 0; +} + +/* strip a register from its control number and append it to message */ +static int append_stripped_reg_ctrl(struct rnet_message **message, char *line) +{ + size_t len; + struct rnet_message *msg = *message; + int growth; + if (!decfile_reg_is_dec(line)) + return 0; + len = strlen(line); + if (len < 12) + return -EINVAL; + growth = msg->len + len - 10 - msg->alen; + if (growth > 0) { + if (rnet_message_expand(message, growth)) + return -ENOMEM; + msg = *message; + } + memcpy(&msg->buffer[msg->len], line, len - 12); + msg->buffer[msg->len + len - 12] = '\r'; + msg->buffer[msg->len + len - 11] = '\n'; + msg->len += len - 10; + return 0; +} + +static int decfile_parse_file(struct rnet_decfile *decfile) +{ + int i; + int r; + for (i = 0; i < decfile->lines_len; i++) { + r = append_stripped_reg_ctrl(&decfile->message, + decfile->lines[i]); + if (r) + return r; + } + return 0; +} + +struct rnet_message * rnet_decfile_get_file(struct rnet_decfile *decfile) +{ + return decfile->message; +} + +char * rnet_decfile_get_file_hash(struct rnet_decfile *decfile) +{ + char *hash; + size_t len; + if (gcry_md_test_algo(GCRY_MD_MD5)) + return NULL; + len = gcry_md_get_algo_dlen(GCRY_MD_MD5); + hash = malloc(len); + if (!hash) + return NULL; + gcry_md_hash_buffer(GCRY_MD_MD5, hash, decfile->message->buffer, + decfile->message->len); + return hash; +} + +char * rnet_decfile_get_header(struct rnet_decfile *decfile) +{ + return get_header(decfile); +} + +char * rnet_decfile_get_line(struct rnet_decfile *decfile, int i) +{ + if (i < decfile->lines_len) + return decfile->lines[i]; + return NULL; +}