1 /*
2     etterfilter -- the actual compiler
3 
4     Copyright (C) ALoR & NaGA
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 
22 #include <ef.h>
23 #include <ef_functions.h>
24 #include <ec_filter.h>
25 
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 
30 
31 /* protos */
32 
33 static void print_progress_bar(struct filter_op *fop);
34 static size_t create_data_segment(u_char **data, struct filter_header *fh, struct filter_op *fop, size_t n);
35 static size_t add_data_segment(u_char **data, size_t base, u_char **string, size_t slen);
36 
37 /*******************************************/
38 
write_output(void)39 int write_output(void)
40 {
41    int fd;
42    struct filter_op *fop;
43    struct filter_header fh;
44    size_t ninst, i, data_len;
45    u_char pad = 0, *data = NULL;
46 
47    /* conver the tree to an array of filter_op */
48    ninst = compile_tree(&fop);
49 
50    if (fop == NULL)
51       return -E_NOTHANDLED;
52 
53    if (ninst == 0)
54       return -E_INVALID;
55 
56    /* create the file */
57    fd = open(EF_GBL_OPTIONS->output_file, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0644);
58    ON_ERROR(fd, -1, "Can't create file %s", EF_GBL_OPTIONS->output_file);
59 
60    /* display the message */
61    USER_MSG(" Writing output to \'%s\' ", EF_GBL_OPTIONS->output_file);
62 
63    /* compute the header */
64    fh.magic = htons(EC_FILTER_MAGIC);
65    strncpy(fh.version, EC_VERSION, sizeof(fh.version));
66    fh.data = sizeof(fh);
67 
68    data_len = create_data_segment(&data, &fh, fop, ninst);
69 
70    /* write the header */
71    write(fd, &fh, sizeof(struct filter_header));
72 
73    /* write the data segment */
74    write(fd, data, data_len);
75 
76    /* write padding to next 8-byte boundary */
77    for (i = 0; i < fh.code - (fh.data + data_len); i++)
78       write(fd, &pad, 1);
79 
80    /* write the instructions */
81    for (i = 0; i < ninst; i++) {
82       print_progress_bar(&fop[i]);
83       write(fd, &fop[i], sizeof(struct filter_op));
84    }
85 
86    close(fd);
87 
88    USER_MSG(" done.\n\n");
89 
90    USER_MSG(" -> Script encoded into %d instructions.\n\n", (int)(i - 1));
91 
92    return E_SUCCESS;
93 }
94 
95 /*
96  * creates the data segment into an byte array supplied as argument data
97  * and update the file header instruction pointer 8-byte aligned
98  *
99  * returns length of the data segment
100  */
create_data_segment(u_char ** data,struct filter_header * fh,struct filter_op * fop,size_t n)101 static size_t create_data_segment(u_char** data, struct filter_header *fh, struct filter_op *fop, size_t n)
102 {
103    size_t i, len = 0;
104 
105    for (i = 0; i < n; i++) {
106 
107       switch(fop[i].opcode) {
108          case FOP_FUNC:
109             if (fop[i].op.func.slen) {
110                ef_debug(1, "@");
111                len += add_data_segment(data, len, &fop[i].op.func.string, fop[i].op.func.slen);
112             }
113             if (fop[i].op.func.rlen) {
114                ef_debug(1, "@");
115                len += add_data_segment(data, len, &fop[i].op.func.replace, fop[i].op.func.rlen);
116             }
117             break;
118 
119          case FOP_TEST:
120             if (fop[i].op.test.slen) {
121                ef_debug(1, "@");
122                len += add_data_segment(data, len, &fop[i].op.test.string, fop[i].op.test.slen);
123             }
124             break;
125 
126          case FOP_ASSIGN:
127             if (fop[i].op.assign.slen) {
128                ef_debug(1, "@");
129                len += add_data_segment(data, len, &fop[i].op.test.string, fop[i].op.test.slen);
130             }
131             break;
132       }
133 
134    }
135 
136    /* where starts the code ? */
137    fh->code = fh->data + len;
138    /* 8-byte aligned please */
139    if (fh->code % 8)
140       fh->code += 8 - fh->code % 8;
141 
142 
143    return len;
144 }
145 
146 
147 /*
148  * add a string to the buffer
149  */
add_data_segment(u_char ** data,size_t base,u_char ** string,size_t slen)150 static size_t add_data_segment(u_char **data, size_t base, u_char **string, size_t slen)
151 {
152    /* make room for the new string */
153    SAFE_REALLOC(*data, base + slen + 1);
154 
155    /* copy the string, NULL separated */
156    memcpy(*data + base, *string, slen + 1);
157 
158    /*
159     * change the pointer to the new string location
160     * it is an offset from the base of the data segment
161     */
162    *string = (u_char *)base;
163 
164    /* retur the len of the added string */
165    return slen + 1;
166 }
167 
168 /*
169  * prints a differnt sign for every different instruction
170  */
print_progress_bar(struct filter_op * fop)171 static void print_progress_bar(struct filter_op *fop)
172 {
173    switch(fop->opcode) {
174       case FOP_EXIT:
175          ef_debug(1, "!");
176          break;
177       case FOP_TEST:
178          ef_debug(1, "?");
179          break;
180       case FOP_ASSIGN:
181          ef_debug(1, "=");
182          break;
183       case FOP_FUNC:
184          ef_debug(1, ".");
185          break;
186       case FOP_JMP:
187          ef_debug(1, ":");
188          break;
189       case FOP_JTRUE:
190       case FOP_JFALSE:
191          ef_debug(1, ";");
192          break;
193    }
194 }
195 
196 /* EOF */
197 
198 // vim:ts=3:expandtab
199 
200