Check len macros during parsing.
[cascardo/libreceita.git] / decfile.c
1 /*
2  *  Copyright (C) 2012-2013  Thadeu Lima de Souza Cascardo <cascardo@minaslivre.org>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #define _GNU_SOURCE
20 #include "decfile.h"
21 #include <string.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <gcrypt.h>
27 #include "pmhash.h"
28 #include "rnet_message.h"
29
30 #ifndef MAX
31 #define MAX(a,b) (a >= b) ? a : b
32 #endif
33
34 struct rnet_decfile {
35         char *filename;
36         FILE *file;
37         char **lines;
38         int lines_len;
39         struct pmhash *header;
40         struct rnet_message *message;
41 };
42
43 /*
44  * line should be an allocated buffer given to append_line
45  * this means, free(line) will be called when decfile is released
46  */
47 static int append_line(struct rnet_decfile *decfile, char *line)
48 {
49         size_t len;
50         char **old_lines;
51         decfile->lines_len += 1;
52         len = sizeof(*decfile->lines) * decfile->lines_len;
53         old_lines = decfile->lines;
54         decfile->lines = realloc(decfile->lines, len);
55         if (!decfile->lines) {
56                 decfile->lines = old_lines;
57                 goto out;
58         }
59         decfile->lines[decfile->lines_len - 1] = line;
60         return 0;
61 out:
62         decfile->lines_len -= 1;
63         return -ENOMEM;
64 }
65
66 static void decfile_release_lines(struct rnet_decfile *decfile)
67 {
68         int i;
69         for (i = 0; i < decfile->lines_len; i++)
70                 free(decfile->lines[i]);
71         free(decfile->lines);
72         decfile->lines = NULL;
73 }
74
75 static char * get_header(struct rnet_decfile *decfile);
76 static int parse_header_2013(struct pmhash *hash, char *buffer);
77 static int parse_header_2014(struct pmhash *hash, char *buffer);
78 static int decfile_parse_file(struct rnet_decfile *decfile);
79
80 static int decfile_parse_header(struct rnet_decfile *decfile)
81 {
82         char *buffer = get_header(decfile);
83         if (!buffer)
84                 return -EINVAL;
85         switch (strlen(buffer)) {
86         case RNET_HEADER_SIZE_2013:
87                 return parse_header_2013(decfile->header, buffer);
88         case RNET_HEADER_SIZE_2014:
89                 return parse_header_2014(decfile->header, buffer);
90         default:
91                 return -EINVAL;
92         }
93 }
94
95 static int decfile_parse(struct rnet_decfile *decfile)
96 {
97         char *buffer = NULL;
98         size_t len = 0;
99         int r;
100         while ((r = getline(&buffer, &len, decfile->file)) > 0) {
101                 r = append_line(decfile, buffer);
102                 if (r) {
103                         free(buffer);
104                         goto out;
105                 }
106                 buffer = NULL;
107                 len = 0;
108         }
109         if (!(r = decfile_parse_header(decfile)) && !(r = decfile_parse_file(decfile)))
110                 return 0;
111 out:
112         decfile_release_lines(decfile);
113         return r;
114 }
115
116 struct rnet_decfile * rnet_decfile_open(char *filename)
117 {
118         struct rnet_decfile *decfile;
119         int r = -ENOMEM;
120         decfile = malloc(sizeof(*decfile));
121         if (!decfile)
122                 return NULL;
123         decfile->header = pmhash_new();
124         if (!decfile->header)
125                 goto out_header;
126         decfile->message = rnet_message_new();
127         if (!decfile->message)
128                 goto out_message;
129         decfile->filename = strdup(filename);
130         if (!decfile->filename)
131                 goto out_filename;
132         decfile->file = fopen(filename, "r");
133         if (!decfile->file)
134                 goto out_file;
135         decfile->lines_len = 0;
136         decfile->lines = NULL;
137         if ((r = decfile_parse(decfile)))
138                 goto out_parse;
139         return decfile;
140 out_parse:
141         fclose(decfile->file);
142 out_file:
143         free(decfile->filename);
144 out_filename:
145         rnet_message_del(decfile->message);
146 out_message:
147         pmhash_del(decfile->header);
148 out_header:
149         free(decfile);
150         errno = -r;
151         return NULL;
152 }
153
154 void rnet_decfile_close(struct rnet_decfile *decfile)
155 {
156         decfile_release_lines(decfile);
157         fclose(decfile->file);
158         free(decfile->filename);
159         free(decfile);
160 }
161
162 static char * get_header(struct rnet_decfile *decfile)
163 {
164         int i;
165         for (i = 0; i < decfile->lines_len; i++) {
166                 if (!strncmp(decfile->lines[i], "IRPF", 4)) {
167                         return decfile->lines[i];
168                 }
169         }
170         return NULL;
171 }
172
173 static int parse_header_2014(struct pmhash *hash, char *buffer)
174 {
175         int r;
176         char *p = buffer;
177         char *key;
178         char *val;
179         char *tail;
180
181 #define parse(field, sz) \
182         r = -ENOMEM; \
183         val = malloc(sz + 1); \
184         if (!val) \
185                 goto out_val; \
186         val[sz] = 0; \
187         memcpy(val, p, sz); \
188         p += sz; \
189         key = strdup(field); \
190         if (!key) \
191                 goto out_key; \
192         if (pmhash_add(&hash, key, val)) \
193                 goto out_add;
194
195         parse("sistema", 8);
196         parse("exerc", 4);
197         if (strcmp(val, "2014")) {
198                 r = -EINVAL;
199                 goto out_val;
200         }
201         parse("ano", 4);
202         parse("codigo_recnet", 4);
203         parse("in_ret", 1);
204         parse("cpf", 11);
205         parse("filler", 3);
206         parse("tipo_ni", 1);
207         parse("nr_versao", 3);
208         parse("nome", 60);
209         parse("uf", 2);
210         parse("hash", 10);
211
212         if (p - buffer != RNET_HEADER_HEAD_2014) {
213                 fprintf(stderr, "RNET_HEADER_HEAD_2014 in decfile.h needs to be adjusted to %i\n", p - buffer);
214                 goto out_val;
215         }
216
217         parse("in_cert", 1);
218         parse("dt_nasc", 8);
219         parse("in_comp", 1);
220         parse("in_res", 1);
221         parse("in_gerada", 1);
222         parse("nr_recibo_anterior", 10);
223         parse("in_pgd", 1);
224         parse("so", 14);
225         parse("versao_so", 7);
226         parse("jvm", 9);
227         parse("nr_recibo", 10);
228         parse("municipio", 4);
229         parse("conjuge", 11);
230         parse("obrig", 1);
231         parse("impdevido", 13);
232         parse("nr_recibo", 10);
233         parse("in_seg", 1);
234         parse("imppago", 2);
235         parse("impant", 1);
236         parse("mudend", 1);
237         parse("cep", 8);
238         parse("debito", 1);
239         parse("banco", 3);
240         parse("agencia", 4);
241         parse("filler", 1);
242         parse("data_julgado", 8);
243         parse("imppagar", 13);
244         parse("tribfonte", 1);
245         parse("cpfrra", 11);
246         parse("trib_rra", 1);
247         parse("cpf_rra2", 11);
248         parse("trib_3rra", 1);
249         parse("cpf_rra3", 11);
250         parse("trib_4rra", 1);
251         parse("cpf_rra4", 11);
252         parse("vr_doacao", 13);
253         parse("cnpj1", 14);
254         parse("cnpj2", 14);
255         parse("cnpj3", 14);
256         parse("cnpj4", 14);
257         parse("cpf_dep1", 11);
258         parse("dnas_dep1", 8);
259         parse("cpf_dep2", 11);
260         parse("dnas_dep2", 8);
261         parse("cpf_dep3", 11);
262         parse("dnas_dep3", 8);
263         parse("cpf_dep4", 11);
264         parse("dnas_dep4", 8);
265         parse("cpf_dep5", 11);
266         parse("dnas_dep5", 8);
267         parse("cpf_dep6", 11);
268         parse("dnas_dep6", 8);
269         parse("cnpj_med1", 14);
270         parse("cnpj_med2", 14);
271         parse("cpf_alim", 11);
272         parse("cpf_invent", 11);
273         parse("municipio", 40);
274         parse("contribuinte", 60);
275         parse("cpf_empregada", 11);
276         parse("hashcode", 12);
277         parse("data_nao_residente", 8);
278         parse("cpf_procurador", 11);
279         parse("obrigatoriedade", 3);
280         parse("rendtrib", 13);
281         parse("cnpj_prev", 14);
282         parse("cnpj_prev2", 14);
283         parse("vr_totisentos", 13);
284         parse("vr_totexclusivo", 13);
285         parse("vr_totpagamentos", 13);
286         parse("nr_conta", 13);
287         parse("nr_dv_conta", 2);
288         parse("in_dv_conta", 1);
289
290         tail = p;
291
292         parse("versaotestpgd", 3);
293         parse("controle", 10);
294
295         if (*p++ != '\r') {
296                 fprintf(stderr,
297                         "missing CR at the %ith header character\n",
298                         p - buffer);
299                 goto out_val;
300         } else if (*p++ != '\n') {
301                 fprintf(stderr,
302                         "missing LF at the %ith header character\n",
303                         p - buffer);
304                 goto out_val;
305         } else if (*p != 0) {
306                 fprintf(stderr,
307                         "missing NUL at the %ith header character\n",
308                         p - buffer);
309                 goto out_val;
310         } else if (p - buffer != RNET_HEADER_SIZE_2014) {
311                 fprintf(stderr, "RNET_HEADER_SIZE_2014 in decfile.h needs to be adjusted to %i,\nor parse_header in decfile.c needs updating\n", p - buffer);
312                 goto out_val;
313         } else if (p - tail != RNET_HEADER_TAIL_2014) {
314                 fprintf(stderr, "RNET_HEADER_TAIL_2014 in decfile.h needs to be adjusted to %i\n", p - tail);
315                 goto out_val;
316         }
317
318         return 0;
319 out_add:
320         free(key);
321 out_key:
322         free(val);
323 out_val:
324         return r;
325 }
326
327 static int parse_header_2013(struct pmhash *hash, char *buffer)
328 {
329         int r;
330         char *p = buffer;
331         char *key;
332         char *val;
333         char *tail;
334
335 #define parse(field, sz) \
336         r = -ENOMEM; \
337         val = malloc(sz + 1); \
338         if (!val) \
339                 goto out_val; \
340         val[sz] = 0; \
341         memcpy(val, p, sz); \
342         p += sz; \
343         key = strdup(field); \
344         if (!key) \
345                 goto out_key; \
346         if (pmhash_add(&hash, key, val)) \
347                 goto out_add;
348
349         parse("sistema", 8);
350         parse("exerc", 4);
351         if (strcmp(val, "2013")) {
352                 r = -EINVAL;
353                 goto out_val;
354         }
355         parse("ano", 4);
356         parse("codigo_recnet", 4);
357         parse("in_ret", 1);
358         parse("cpf", 11);
359         parse("filler", 3);
360         parse("tipo_ni", 1);
361         parse("nr_versao", 3);
362         parse("nome", 60);
363         parse("uf", 2);
364         parse("hash", 10);
365
366         if (p - buffer != RNET_HEADER_HEAD_2013) {
367                 fprintf(stderr, "RNET_HEADER_HEAD_2013 in decfile.h needs to be adjusted to %i\n", p - buffer);
368                 goto out_val;
369         }
370
371         parse("in_cert", 1);
372         parse("dt_nasc", 8);
373         parse("in_comp", 1);
374         parse("in_res", 1);
375         parse("in_gerada", 1);
376         parse("nr_recibo_anterior", 10);
377         parse("in_pgd", 1);
378         parse("so", 14);
379         parse("versao_so", 7);
380         parse("jvm", 9);
381         parse("nr_recibo", 10);
382         parse("municipio", 4);
383         parse("conjuge", 11);
384         parse("obrig", 1);
385         parse("impdevido", 13);
386         parse("nr_recibo", 10);
387         parse("in_seg", 1);
388         parse("imppago", 2);
389         parse("impant", 1);
390         parse("mudend", 1);
391         parse("cep", 8);
392         parse("debito", 1);
393         parse("banco", 3);
394         parse("agencia", 4);
395         parse("filler", 1);
396         parse("data_julgado", 8);
397         parse("imppagar", 13);
398         parse("tribfonte", 1);
399         parse("cpfrra", 11);
400         parse("trib_rra", 1);
401         parse("cpf_rra2", 11);
402         parse("trib_3rra", 1);
403         parse("cpf_rra3", 11);
404         parse("vr_doacao", 13);
405         parse("cnpj1", 14);
406         parse("cnpj2", 14);
407         parse("cnpj3", 14);
408         parse("cnpj4", 14);
409         parse("cpf_dep1", 11);
410         parse("dnas_dep1", 8);
411         parse("cpf_dep2", 11);
412         parse("dnas_dep2", 8);
413         parse("cpf_dep3", 11);
414         parse("dnas_dep3", 8);
415         parse("cpf_dep4", 11);
416         parse("dnas_dep4", 8);
417         parse("cpf_dep5", 11);
418         parse("dnas_dep5", 8);
419         parse("cpf_dep6", 11);
420         parse("dnas_dep6", 8);
421         parse("cnpj_med1", 14);
422         parse("cnpj_med2", 14);
423         parse("cpf_alim", 11);
424         parse("cpf_invent", 11);
425         parse("municipio", 40);
426         parse("contribuinte", 60);
427         parse("cpf_empregada", 11);
428         parse("hashcode", 12);
429         parse("data_nao_residente", 8);
430         parse("cpf_procurador", 11);
431         parse("obrigatoriedade", 3);
432         parse("rendtrib", 13);
433         parse("cnpj_prev", 14);
434         parse("cnpj_prev2", 14);
435         parse("vr_totisentos", 13);
436         parse("vr_totexclusivo", 13);
437         parse("vr_totpagamentos", 13);
438
439         tail = p;
440
441         parse("versaotestpgd", 3);
442         parse("controle", 10);
443
444         if (*p++ != '\r') {
445                 fprintf(stderr,
446                         "missing CR at the %ith header character\n",
447                         p - buffer);
448                 goto out_val;
449         } else if (*p++ != '\n') {
450                 fprintf(stderr,
451                         "missing LF at the %ith header character\n",
452                         p - buffer);
453                 goto out_val;
454         } else if (*p != 0) {
455                 fprintf(stderr,
456                         "missing NUL at the %ith header character\n",
457                         p - buffer);
458                 goto out_val;
459         } else if (p - buffer != RNET_HEADER_SIZE_2013) {
460                 fprintf(stderr, "RNET_HEADER_SIZE_2013 in decfile.h needs to be adjusted to %i,\nor parse_header in decfile.c needs updating\n", p - buffer);
461                 goto out_val;
462         } else if (p - tail != RNET_HEADER_TAIL_2013) {
463                 fprintf(stderr, "RNET_HEADER_TAIL_2013 in decfile.h needs to be adjusted to %i\n", p - tail);
464                 goto out_val;
465         }
466
467         return 0;
468 out_add:
469         free(key);
470 out_key:
471         free(val);
472 out_val:
473         return r;
474 }
475
476 char *rnet_decfile_get_header_field(struct rnet_decfile *decfile, char *field)
477 {
478         return pmhash_get(decfile->header, field);
479 }
480
481 /* returns true if register is declaration and not a receipt */
482 static int decfile_reg_is_dec(char *line)
483 {
484         if (line[0] >= '0' && line[0] <= '9' &&
485             line[1] >= '0' && line[1] <= '9')
486                 return 1;
487         if (!strncmp(line, "IRPF    ", 8))
488                 return 1;
489         if (!strncmp(line, "T9", 2))
490                 return 1;
491         return 0;
492 }
493
494 /* strip a register from its control number and append it to message */
495 static int append_stripped_reg_ctrl(struct rnet_message **message, char *line)
496 {
497         size_t len;
498         struct rnet_message *msg = *message;
499         int growth;
500         if (!decfile_reg_is_dec(line))
501                 return 0;
502         len = strlen(line);
503         if (len < 12)
504                 return -EINVAL;
505         growth = msg->len + len - 10 - msg->alen;
506         if (growth > 0) {
507                 if (rnet_message_expand(message, growth))
508                         return -ENOMEM;
509                 msg = *message;
510         }
511         memcpy(&msg->buffer[msg->len], line, len - 12);
512         msg->buffer[msg->len + len - 12] = '\r';
513         msg->buffer[msg->len + len - 11] = '\n';
514         msg->len += len - 10;
515         return 0;
516 }
517
518 static int decfile_parse_file(struct rnet_decfile *decfile)
519 {
520         int i;
521         int r;
522         for (i = 0; i < decfile->lines_len; i++) {
523                 r = append_stripped_reg_ctrl(&decfile->message,
524                                                 decfile->lines[i]);
525                 if (r)
526                         return r;
527         }
528         return 0;
529 }
530
531 struct rnet_message * rnet_decfile_get_file(struct rnet_decfile *decfile)
532 {
533         return decfile->message;
534 }
535
536 char * rnet_decfile_get_file_hash(struct rnet_decfile *decfile)
537 {
538         char *hash;
539         size_t len;
540         if (gcry_md_test_algo(GCRY_MD_MD5))
541                 return NULL;
542         len = gcry_md_get_algo_dlen(GCRY_MD_MD5);
543         hash = malloc(len);
544         if (!hash)
545                 return NULL;
546         gcry_md_hash_buffer(GCRY_MD_MD5, hash, decfile->message->buffer,
547                                         decfile->message->len);
548         return hash;
549 }
550
551 char * rnet_decfile_get_header(struct rnet_decfile *decfile)
552 {
553         return get_header(decfile);
554 }