2 * Copyright (C) 2012-2014 Thadeu Lima de Souza Cascardo <cascardo@minaslivre.org>
3 * Copyright (C) 2014 Alexandre Oliva <lxoliva@fsfla.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include "rnet_message.h"
32 #define MAX(a,b) (a >= b) ? a : b
40 struct pmhash *header;
41 struct rnet_message *message;
45 * line should be an allocated buffer given to append_line
46 * this means, free(line) will be called when decfile is released
48 static int append_line(struct rnet_decfile *decfile, char *line)
52 decfile->lines_len += 1;
53 len = sizeof(*decfile->lines) * decfile->lines_len;
54 old_lines = decfile->lines;
55 decfile->lines = realloc(decfile->lines, len);
56 if (!decfile->lines) {
57 decfile->lines = old_lines;
60 decfile->lines[decfile->lines_len - 1] = line;
63 decfile->lines_len -= 1;
67 static void decfile_release_lines(struct rnet_decfile *decfile)
70 for (i = 0; i < decfile->lines_len; i++)
71 free(decfile->lines[i]);
73 decfile->lines = NULL;
76 static char * get_header(struct rnet_decfile *decfile);
77 static int parse_header_2013(struct pmhash *hash, char *buffer);
78 static int parse_header_2014(struct pmhash *hash, char *buffer);
79 static int decfile_parse_file(struct rnet_decfile *decfile);
81 static int decfile_parse_header(struct rnet_decfile *decfile)
83 char *buffer = get_header(decfile);
86 switch (strlen(buffer)) {
87 case RNET_HEADER_SIZE_2013:
88 return parse_header_2013(decfile->header, buffer);
89 case RNET_HEADER_SIZE_2014:
90 return parse_header_2014(decfile->header, buffer);
96 static int decfile_parse(struct rnet_decfile *decfile)
101 while ((r = getline(&buffer, &len, decfile->file)) > 0) {
102 r = append_line(decfile, buffer);
110 if (!(r = decfile_parse_header(decfile)) && !(r = decfile_parse_file(decfile)))
113 decfile_release_lines(decfile);
117 struct rnet_decfile * rnet_decfile_open(char *filename)
119 struct rnet_decfile *decfile;
121 decfile = malloc(sizeof(*decfile));
124 decfile->header = pmhash_new();
125 if (!decfile->header)
127 decfile->message = rnet_message_new();
128 if (!decfile->message)
130 decfile->filename = strdup(filename);
131 if (!decfile->filename)
133 decfile->file = fopen(filename, "r");
136 decfile->lines_len = 0;
137 decfile->lines = NULL;
138 if ((r = decfile_parse(decfile)))
142 fclose(decfile->file);
144 free(decfile->filename);
146 rnet_message_del(decfile->message);
148 pmhash_del(decfile->header);
155 void rnet_decfile_close(struct rnet_decfile *decfile)
157 decfile_release_lines(decfile);
158 fclose(decfile->file);
159 free(decfile->filename);
163 static char * get_header(struct rnet_decfile *decfile)
166 for (i = 0; i < decfile->lines_len; i++) {
167 if (!strncmp(decfile->lines[i], "IRPF", 4)) {
168 return decfile->lines[i];
174 static int parse_header_2014(struct pmhash *hash, char *buffer)
182 #define parse(field, sz) \
184 val = malloc(sz + 1); \
188 memcpy(val, p, sz); \
190 key = strdup(field); \
193 if (pmhash_add(&hash, key, val)) \
198 if (strcmp(val, "2014")) {
203 parse("codigo_recnet", 4);
208 parse("nr_versao", 3);
213 if (p - buffer != RNET_HEADER_HEAD_2014) {
214 fprintf(stderr, "RNET_HEADER_HEAD_2014 in decfile.h needs to be adjusted to %li\n", p - buffer);
222 parse("in_gerada", 1);
223 parse("nr_recibo_anterior", 10);
226 parse("versao_so", 7);
228 parse("nr_recibo", 10);
229 parse("municipio", 4);
230 parse("conjuge", 11);
232 parse("impdevido", 13);
233 parse("nr_recibo", 10);
243 parse("data_julgado", 8);
244 parse("imppagar", 13);
245 parse("tribfonte", 1);
247 parse("trib_rra", 1);
248 parse("cpf_rra2", 11);
249 parse("trib_3rra", 1);
250 parse("cpf_rra3", 11);
251 parse("trib_4rra", 1);
252 parse("cpf_rra4", 11);
253 parse("vr_doacao", 13);
258 parse("cpf_dep1", 11);
259 parse("dnas_dep1", 8);
260 parse("cpf_dep2", 11);
261 parse("dnas_dep2", 8);
262 parse("cpf_dep3", 11);
263 parse("dnas_dep3", 8);
264 parse("cpf_dep4", 11);
265 parse("dnas_dep4", 8);
266 parse("cpf_dep5", 11);
267 parse("dnas_dep5", 8);
268 parse("cpf_dep6", 11);
269 parse("dnas_dep6", 8);
270 parse("cnpj_med1", 14);
271 parse("cnpj_med2", 14);
272 parse("cpf_alim", 11);
273 parse("cpf_invent", 11);
274 parse("municipio", 40);
275 parse("contribuinte", 60);
276 parse("cpf_empregada", 11);
277 parse("hashcode", 12);
278 parse("data_nao_residente", 8);
279 parse("cpf_procurador", 11);
280 parse("obrigatoriedade", 3);
281 parse("rendtrib", 13);
282 parse("cnpj_prev", 14);
283 parse("cnpj_prev2", 14);
284 parse("vr_totisentos", 13);
285 parse("vr_totexclusivo", 13);
286 parse("vr_totpagamentos", 13);
287 parse("nr_conta", 13);
288 parse("nr_dv_conta", 2);
289 parse("in_dv_conta", 1);
293 parse("versaotestpgd", 3);
294 parse("controle", 10);
298 "missing CR at the %lith header character\n",
301 } else if (*p++ != '\n') {
303 "missing LF at the %lith header character\n",
306 } else if (*p != 0) {
308 "missing NUL at the %lith header character\n",
311 } else if (p - buffer != RNET_HEADER_SIZE_2014) {
312 fprintf(stderr, "RNET_HEADER_SIZE_2014 in decfile.h needs to be adjusted to %li,\nor parse_header in decfile.c needs updating\n", p - buffer);
314 } else if (p - tail != RNET_HEADER_TAIL_2014) {
315 fprintf(stderr, "RNET_HEADER_TAIL_2014 in decfile.h needs to be adjusted to %li\n", p - tail);
328 static int parse_header_2013(struct pmhash *hash, char *buffer)
336 #define parse(field, sz) \
338 val = malloc(sz + 1); \
342 memcpy(val, p, sz); \
344 key = strdup(field); \
347 if (pmhash_add(&hash, key, val)) \
352 if (strcmp(val, "2013")) {
357 parse("codigo_recnet", 4);
362 parse("nr_versao", 3);
367 if (p - buffer != RNET_HEADER_HEAD_2013) {
368 fprintf(stderr, "RNET_HEADER_HEAD_2013 in decfile.h needs to be adjusted to %li\n", p - buffer);
376 parse("in_gerada", 1);
377 parse("nr_recibo_anterior", 10);
380 parse("versao_so", 7);
382 parse("nr_recibo", 10);
383 parse("municipio", 4);
384 parse("conjuge", 11);
386 parse("impdevido", 13);
387 parse("nr_recibo", 10);
397 parse("data_julgado", 8);
398 parse("imppagar", 13);
399 parse("tribfonte", 1);
401 parse("trib_rra", 1);
402 parse("cpf_rra2", 11);
403 parse("trib_3rra", 1);
404 parse("cpf_rra3", 11);
405 parse("vr_doacao", 13);
410 parse("cpf_dep1", 11);
411 parse("dnas_dep1", 8);
412 parse("cpf_dep2", 11);
413 parse("dnas_dep2", 8);
414 parse("cpf_dep3", 11);
415 parse("dnas_dep3", 8);
416 parse("cpf_dep4", 11);
417 parse("dnas_dep4", 8);
418 parse("cpf_dep5", 11);
419 parse("dnas_dep5", 8);
420 parse("cpf_dep6", 11);
421 parse("dnas_dep6", 8);
422 parse("cnpj_med1", 14);
423 parse("cnpj_med2", 14);
424 parse("cpf_alim", 11);
425 parse("cpf_invent", 11);
426 parse("municipio", 40);
427 parse("contribuinte", 60);
428 parse("cpf_empregada", 11);
429 parse("hashcode", 12);
430 parse("data_nao_residente", 8);
431 parse("cpf_procurador", 11);
432 parse("obrigatoriedade", 3);
433 parse("rendtrib", 13);
434 parse("cnpj_prev", 14);
435 parse("cnpj_prev2", 14);
436 parse("vr_totisentos", 13);
437 parse("vr_totexclusivo", 13);
438 parse("vr_totpagamentos", 13);
442 parse("versaotestpgd", 3);
443 parse("controle", 10);
447 "missing CR at the %lith header character\n",
450 } else if (*p++ != '\n') {
452 "missing LF at the %lith header character\n",
455 } else if (*p != 0) {
457 "missing NUL at the %lith header character\n",
460 } else if (p - buffer != RNET_HEADER_SIZE_2013) {
461 fprintf(stderr, "RNET_HEADER_SIZE_2013 in decfile.h needs to be adjusted to %li,\nor parse_header in decfile.c needs updating\n", p - buffer);
463 } else if (p - tail != RNET_HEADER_TAIL_2013) {
464 fprintf(stderr, "RNET_HEADER_TAIL_2013 in decfile.h needs to be adjusted to %li\n", p - tail);
477 char *rnet_decfile_get_header_field(struct rnet_decfile *decfile, char *field)
479 return pmhash_get(decfile->header, field);
482 /* returns true if register is declaration and not a receipt */
483 static int decfile_reg_is_dec(char *line)
485 if (line[0] >= '0' && line[0] <= '9' &&
486 line[1] >= '0' && line[1] <= '9')
488 if (!strncmp(line, "IRPF ", 8))
490 if (!strncmp(line, "T9", 2))
495 /* strip a register from its control number and append it to message */
496 static int append_stripped_reg_ctrl(struct rnet_message **message, char *line)
499 struct rnet_message *msg = *message;
501 if (!decfile_reg_is_dec(line))
506 growth = msg->len + len - 10 - msg->alen;
508 if (rnet_message_expand(message, growth))
512 memcpy(&msg->buffer[msg->len], line, len - 12);
513 msg->buffer[msg->len + len - 12] = '\r';
514 msg->buffer[msg->len + len - 11] = '\n';
515 msg->len += len - 10;
519 static int decfile_parse_file(struct rnet_decfile *decfile)
523 for (i = 0; i < decfile->lines_len; i++) {
524 r = append_stripped_reg_ctrl(&decfile->message,
532 struct rnet_message * rnet_decfile_get_file(struct rnet_decfile *decfile)
534 return decfile->message;
537 char * rnet_decfile_get_file_hash(struct rnet_decfile *decfile)
541 if (gcry_md_test_algo(GCRY_MD_MD5))
543 len = gcry_md_get_algo_dlen(GCRY_MD_MD5);
547 gcry_md_hash_buffer(GCRY_MD_MD5, hash, decfile->message->buffer,
548 decfile->message->len);
552 char * rnet_decfile_get_header(struct rnet_decfile *decfile)
554 return get_header(decfile);