Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / wiretap / pppdump.c
blob6fb3c7761171c16b896aec1781089412e04da396
1 /* pppdump.c
3 * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
8 #include "config.h"
9 #include "pppdump.h"
10 #include "wtap-int.h"
11 #include "file_wrappers.h"
13 #include <stdlib.h>
14 #include <errno.h>
15 #include <string.h>
17 #include <wsutil/array.h>
18 #include <wsutil/ws_assert.h>
21 pppdump records
22 Daniel Thompson (STMicroelectronics) <daniel.thompson@st.com>
24 +------+
25 | 0x07 | Reset time
26 +------+------+------+------+
27 | t3 | t2 | t1 | t0 | t = time_t
28 +------+------+------+------+
30 +------+
31 | 0x06 | Time step (short)
32 +------+
33 | ts | ts = time step (tenths of seconds)
34 +------+
36 +------+
37 | 0x05 | Time step (long)
38 +------+------+------+------+
39 | ts3 | ts2 | ts1 | ts0 | ts = time step (tenths of seconds)
40 +------+------+------+------+
42 +------+
43 | 0x04 | Receive delimiter (not seen in practice)
44 +------+
46 +------+
47 | 0x03 | Send delimiter (not seen in practice)
48 +------+
50 +------+
51 | 0x02 | Received data
52 +------+------+
53 | n1 | n0 | n = number of bytes following
54 +------+------+
55 | data |
56 | |
58 +------+
59 | 0x01 | Sent data
60 +------+------+
61 | n1 | n0 | n = number of bytes following
62 +------+------+
63 | data |
64 | |
67 #define PPPD_SENT_DATA 0x01
68 #define PPPD_RECV_DATA 0x02
69 #define PPPD_SEND_DELIM 0x03
70 #define PPPD_RECV_DELIM 0x04
71 #define PPPD_TIME_STEP_LONG 0x05
72 #define PPPD_TIME_STEP_SHORT 0x06
73 #define PPPD_RESET_TIME 0x07
75 /* this buffer must be at least (2*PPPD_MTU) + sizeof(ppp_header) +
76 * sizeof(lcp_header) + sizeof(ipcp_header). PPPD_MTU is *very* rarely
77 * larger than 1500 so this value is fine.
79 * It's less than WTAP_MAX_PACKET_SIZE_STANDARD, so we don't have to worry about
80 * too-large packets.
82 #define PPPD_BUF_SIZE 8192
84 typedef enum {
85 DIRECTION_SENT,
86 DIRECTION_RECV
87 } direction_enum;
89 static bool pppdump_read(wtap *wth, wtap_rec *rec, Buffer *buf,
90 int *err, char **err_info, int64_t *data_offset);
91 static bool pppdump_seek_read(wtap *wth, int64_t seek_off,
92 wtap_rec *rec, Buffer *buf, int *err, char **err_info);
94 static int pppdump_file_type_subtype = -1;
96 void register_pppdump(void);
99 * Information saved about a packet, during the initial sequential pass
100 * through the file, to allow us to later re-read it when randomly
101 * reading packets.
103 * "offset" is the offset in the file of the first data chunk containing data
104 * from that packet; note that it may also contain data from previous
105 * packets.
107 * "num_bytes_to_skip" is the number of bytes from previous packets in that
108 * first data chunk.
110 * "dir" is the direction of the packet.
112 typedef struct {
113 int64_t offset;
114 int64_t num_bytes_to_skip;
115 direction_enum dir;
116 } pkt_id;
119 * Information about a packet currently being processed. There is one of
120 * these for the sent packet being processed and one of these for the
121 * received packet being processed, as we could be in the middle of
122 * processing both a received packet and a sent packet.
124 * "dir" is the direction of the packet.
126 * "cnt" is the number of bytes of packet data we've accumulated.
128 * "esc" is true if the next byte we see is escaped (and thus must be XORed
129 * with 0x20 before saving it), false otherwise.
131 * "buf" is a buffer containing the packet data we've accumulated.
133 * "id_offset" is the offset in the file of the first data chunk
134 * containing data from the packet we're processing.
136 * "sd_offset" is the offset in the file of the first data byte from
137 * the packet we're processing - which isn't necessarily right after
138 * the header of the first data chunk, as we may already have assembled
139 * packets from that chunk.
141 * "cd_offset" is the offset in the file of the current data chunk we're
142 * processing.
144 typedef struct {
145 direction_enum dir;
146 int cnt;
147 bool esc;
148 uint8_t buf[PPPD_BUF_SIZE];
149 int64_t id_offset;
150 int64_t sd_offset;
151 int64_t cd_offset;
152 } pkt_t;
155 * This keeps state used while processing records.
157 * "timestamp" is the seconds portion of the current time stamp value,
158 * as updated from PPPD_RESET_TIME, PPPD_TIME_STEP_LONG, and
159 * PPPD_TIME_STEP_SHORT records. "tenths" is the tenths-of-seconds
160 * portion.
162 * "spkt" and "rpkt" are "pkt_t" structures for the sent and received
163 * packets we're currently working on.
165 * "offset" is the current offset in the file.
167 * "num_bytes" and "pkt" are information saved when we finish accumulating
168 * the data for a packet, if the data chunk we're working on still has more
169 * data in it:
171 * "num_bytes" is the number of bytes of additional data remaining
172 * in the chunk after we've finished accumulating the data for the
173 * packet.
175 * "pkt" is the "pkt_t" for the type of packet the data chunk is for
176 * (sent or received packet).
178 * "seek_state" is another state structure used while processing records
179 * when doing a seek-and-read. (That structure doesn't itself have a
180 * "seek_state" structure.)
182 * "pids" is a GPtrArray of pointers to "pkt_id" structures for all the
183 * packets we've seen during the initial sequential pass, to allow us to
184 * later retrieve them with random accesses.
186 * "pkt_cnt" is the number of packets we've seen up to this point in the
187 * sequential pass.
189 typedef struct _pppdump_t {
190 time_t timestamp;
191 unsigned tenths;
192 pkt_t spkt;
193 pkt_t rpkt;
194 int64_t offset;
195 int num_bytes;
196 pkt_t *pkt;
197 struct _pppdump_t *seek_state;
198 GPtrArray *pids;
199 unsigned pkt_cnt;
200 } pppdump_t;
202 static int
203 process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, uint8_t *pd,
204 int *err, char **err_info, pkt_id *pid);
206 static bool
207 collate(pppdump_t *state, FILE_T fh, int *err, char **err_info, uint8_t *pd,
208 int *num_bytes, direction_enum *direction, pkt_id *pid,
209 int64_t num_bytes_to_skip);
211 static void
212 pppdump_close(wtap *wth);
214 static void
215 init_state(pppdump_t *state)
218 state->num_bytes = 0;
219 state->pkt = NULL;
221 state->spkt.dir = DIRECTION_SENT;
222 state->spkt.cnt = 0;
223 state->spkt.esc = false;
224 state->spkt.id_offset = 0;
225 state->spkt.sd_offset = 0;
226 state->spkt.cd_offset = 0;
228 state->rpkt.dir = DIRECTION_RECV;
229 state->rpkt.cnt = 0;
230 state->rpkt.esc = false;
231 state->rpkt.id_offset = 0;
232 state->rpkt.sd_offset = 0;
233 state->rpkt.cd_offset = 0;
235 state->seek_state = NULL;
236 state->offset = 0x100000; /* to detect errors during development */
240 wtap_open_return_val
241 pppdump_open(wtap *wth, int *err, char **err_info)
243 uint8_t buffer[6]; /* Looking for: 0x07 t3 t2 t1 t0 ID */
244 pppdump_t *state;
246 /* There is no file header, only packet records. Fortunately for us,
247 * timestamp records are separated from packet records, so we should
248 * find an "initial time stamp" (i.e., a "reset time" record, or
249 * record type 0x07) at the beginning of the file. We'll check for
250 * that, plus a valid record following the 0x07 and the four bytes
251 * representing the timestamp.
254 if (!wtap_read_bytes(wth->fh, buffer, sizeof(buffer),
255 err, err_info)) {
256 if (*err != WTAP_ERR_SHORT_READ)
257 return WTAP_OPEN_ERROR;
258 return WTAP_OPEN_NOT_MINE;
261 if (buffer[0] == PPPD_RESET_TIME &&
262 (buffer[5] == PPPD_SENT_DATA ||
263 buffer[5] == PPPD_RECV_DATA ||
264 buffer[5] == PPPD_TIME_STEP_LONG ||
265 buffer[5] == PPPD_TIME_STEP_SHORT ||
266 buffer[5] == PPPD_RESET_TIME)) {
268 goto my_file_type;
270 else {
271 return WTAP_OPEN_NOT_MINE;
274 my_file_type:
276 if (file_seek(wth->fh, 5, SEEK_SET, err) == -1)
277 return WTAP_OPEN_ERROR;
279 state = g_new(pppdump_t, 1);
280 wth->priv = (void *)state;
281 state->timestamp = pntoh32(&buffer[1]);
282 state->tenths = 0;
284 init_state(state);
286 state->offset = 5;
287 wth->file_encap = WTAP_ENCAP_PPP_WITH_PHDR;
288 wth->file_type_subtype = pppdump_file_type_subtype;
290 wth->snapshot_length = PPPD_BUF_SIZE; /* just guessing */
291 wth->subtype_read = pppdump_read;
292 wth->subtype_seek_read = pppdump_seek_read;
293 wth->subtype_close = pppdump_close;
294 wth->file_tsprec = WTAP_TSPREC_100_MSEC;
296 state->seek_state = g_new(pppdump_t,1);
298 /* If we have a random stream open, we're going to be reading
299 the file randomly; set up a GPtrArray of pointers to
300 information about how to retrieve the data for each packet. */
301 if (wth->random_fh != NULL)
302 state->pids = g_ptr_array_new();
303 else
304 state->pids = NULL;
305 state->pkt_cnt = 0;
308 * Add an IDB; we don't know how many interfaces were
309 * involved, so we just say one interface, about which
310 * we only know the link-layer type, snapshot length,
311 * and time stamp resolution.
313 wtap_add_generated_idb(wth);
315 return WTAP_OPEN_MINE;
318 /* Set part of the struct wtap_rec. */
319 static void
320 pppdump_set_phdr(wtap_rec *rec, int num_bytes,
321 direction_enum direction)
323 rec->rec_type = REC_TYPE_PACKET;
324 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
325 rec->rec_header.packet_header.len = num_bytes;
326 rec->rec_header.packet_header.caplen = num_bytes;
327 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
329 rec->rec_header.packet_header.pseudo_header.p2p.sent = (direction == DIRECTION_SENT ? true : false);
332 /* Find the next packet and parse it; called from wtap_read(). */
333 static bool
334 pppdump_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, char **err_info,
335 int64_t *data_offset)
337 int num_bytes;
338 direction_enum direction;
339 pppdump_t *state;
340 pkt_id *pid;
342 state = (pppdump_t *)wth->priv;
344 /* If we have a random stream open, allocate a structure to hold
345 the information needed to read this packet's data again. */
346 if (wth->random_fh != NULL) {
347 pid = g_new(pkt_id, 1);
348 if (!pid) {
349 *err = errno; /* assume a malloc failed and set "errno" */
350 return false;
352 pid->offset = 0;
353 } else
354 pid = NULL; /* sequential only */
356 ws_buffer_assure_space(buf, PPPD_BUF_SIZE);
357 if (!collate(state, wth->fh, err, err_info, ws_buffer_start_ptr(buf),
358 &num_bytes, &direction, pid, 0)) {
359 g_free(pid);
360 return false;
363 if (pid != NULL)
364 pid->dir = direction;
366 if (pid != NULL)
367 g_ptr_array_add(state->pids, pid);
368 /* The user's data_offset is not really an offset, but a packet number. */
369 *data_offset = state->pkt_cnt;
370 state->pkt_cnt++;
372 pppdump_set_phdr(rec, num_bytes, direction);
373 rec->presence_flags = WTAP_HAS_TS;
374 rec->ts.secs = state->timestamp;
375 rec->ts.nsecs = state->tenths * 100000000;
377 return true;
380 /* Returns number of bytes copied for record, -1 if failure.
382 * This is modeled after pppdump.c, the utility to parse pppd log files; it
383 * comes with the ppp distribution.
385 static int
386 process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, uint8_t *pd,
387 int *err, char **err_info, pkt_id *pid)
389 int c;
390 int num_bytes = n;
391 int num_written;
393 for (; num_bytes > 0; --num_bytes) {
394 c = file_getc(fh);
395 if (c == EOF) {
396 *err = file_error(fh, err_info);
397 if (*err == 0) {
398 *err = WTAP_ERR_SHORT_READ;
400 return -1;
402 state->offset++;
403 switch (c) {
404 case 0x7e:
406 * Flag Sequence for RFC 1662 HDLC-like
407 * framing.
409 * As this is a raw trace of octets going
410 * over the wire, and that might include
411 * the login sequence, there is no
412 * guarantee that *only* PPP traffic
413 * appears in this file, so there is no
414 * guarantee that the first 0x7e we see is
415 * a start flag sequence, and therefore we
416 * cannot safely ignore all characters up
417 * to the first 0x7e, and therefore we
418 * might end up with some bogus PPP
419 * packets.
421 if (pkt->cnt > 0) {
423 * We've seen stuff before this,
424 * so this is the end of a frame.
425 * Make a frame out of that stuff.
427 pkt->esc = false;
429 num_written = pkt->cnt;
430 pkt->cnt = 0;
431 if (num_written <= 0) {
432 return 0;
435 if (num_written > PPPD_BUF_SIZE) {
436 *err = WTAP_ERR_BAD_FILE;
437 *err_info = ws_strdup_printf("pppdump: File has %u-byte packet, bigger than maximum of %u",
438 num_written, PPPD_BUF_SIZE);
439 return -1;
442 memcpy(pd, pkt->buf, num_written);
445 * Remember the offset of the
446 * first record containing data
447 * for this packet, and how far
448 * into that record to skip to
449 * get to the beginning of the
450 * data for this packet; the number
451 * of bytes to skip into that record
452 * is the file offset of the first
453 * byte of this packet minus the
454 * file offset of the first byte of
455 * this record, minus 3 bytes for the
456 * header of this record (which, if
457 * we re-read this record, we will
458 * process, not skip).
460 if (pid) {
461 pid->offset = pkt->id_offset;
462 pid->num_bytes_to_skip =
463 pkt->sd_offset - pkt->id_offset - 3;
464 ws_assert(pid->num_bytes_to_skip >= 0);
467 num_bytes--;
468 if (num_bytes > 0) {
470 * There's more data in this
471 * record.
472 * Set the initial data offset
473 * for the next packet.
475 pkt->id_offset = pkt->cd_offset;
476 pkt->sd_offset = state->offset;
477 } else {
479 * There is no more data in
480 * this record.
481 * Thus, we don't have the
482 * initial data offset for
483 * the next packet.
485 pkt->id_offset = 0;
486 pkt->sd_offset = 0;
488 state->num_bytes = num_bytes;
489 state->pkt = pkt;
490 return num_written;
492 break;
494 case 0x7d:
496 * Control Escape octet for octet-stuffed
497 * RFC 1662 HDLC-like framing.
499 if (!pkt->esc) {
501 * Control Escape not preceded by
502 * Control Escape; discard it
503 * but XOR the next octet with
504 * 0x20.
506 pkt->esc = true;
507 break;
510 * Control Escape preceded by Control Escape;
511 * treat it as an ordinary character,
512 * by falling through.
515 /* FALL THROUGH */
516 default:
517 if (pkt->esc) {
519 * This character was preceded by
520 * Control Escape, so XOR it with
521 * 0x20, as per RFC 1662's octet-
522 * stuffed framing, and clear
523 * the flag saying that the
524 * character should be escaped.
526 c ^= 0x20;
527 pkt->esc = false;
530 if (pkt->cnt >= PPPD_BUF_SIZE) {
531 *err = WTAP_ERR_BAD_FILE;
532 *err_info = ws_strdup_printf("pppdump: File has %u-byte packet, bigger than maximum of %u",
533 pkt->cnt - 1, PPPD_BUF_SIZE);
534 return -1;
536 pkt->buf[pkt->cnt++] = c;
537 break;
541 /* we could have run out of bytes to read */
542 return 0;
545 /* Returns true if packet data copied, false if error occurred or EOF (no more records). */
546 static bool
547 collate(pppdump_t* state, FILE_T fh, int *err, char **err_info, uint8_t *pd,
548 int *num_bytes, direction_enum *direction, pkt_id *pid,
549 int64_t num_bytes_to_skip)
551 int id;
552 pkt_t *pkt = NULL;
553 int byte0, byte1;
554 int n, num_written = 0;
555 int64_t start_offset;
556 uint32_t time_long;
557 uint8_t time_short;
560 * Process any data left over in the current record when doing
561 * sequential processing.
563 if (state->num_bytes > 0) {
564 ws_assert(num_bytes_to_skip == 0);
565 pkt = state->pkt;
566 num_written = process_data(state, fh, pkt, state->num_bytes,
567 pd, err, err_info, pid);
569 if (num_written < 0) {
570 return false;
572 else if (num_written > 0) {
573 *num_bytes = num_written;
574 *direction = pkt->dir;
575 return true;
577 /* if 0 bytes written, keep processing */
578 } else {
580 * We didn't have any data left over, so the packet will
581 * start at the beginning of a record.
583 if (pid)
584 pid->num_bytes_to_skip = 0;
588 * That didn't get all the data for this packet, so process
589 * subsequent records.
591 start_offset = state->offset;
592 while ((id = file_getc(fh)) != EOF) {
593 state->offset++;
594 switch (id) {
595 case PPPD_SENT_DATA:
596 case PPPD_RECV_DATA:
597 pkt = id == PPPD_SENT_DATA ? &state->spkt : &state->rpkt;
600 * Save the offset of the beginning of
601 * the current record.
603 pkt->cd_offset = state->offset - 1;
606 * Get the length of the record.
608 byte0 = file_getc(fh);
609 if (byte0 == EOF)
610 goto done;
611 state->offset++;
612 byte1 = file_getc(fh);
613 if (byte1 == EOF)
614 goto done;
615 state->offset++;
616 n = (byte0 << 8) | byte1;
618 if (pkt->id_offset == 0) {
620 * We don't have the initial data
621 * offset for this packet, which
622 * means this is the first
623 * data record for that packet.
624 * Save the offset of the
625 * beginning of that record and
626 * the offset of the first data
627 * byte in the packet, which is
628 * the first data byte in the
629 * record.
631 pkt->id_offset = pkt->cd_offset;
632 pkt->sd_offset = state->offset;
635 if (n == 0)
636 continue;
638 ws_assert(num_bytes_to_skip < n);
639 while (num_bytes_to_skip) {
640 if (file_getc(fh) == EOF)
641 goto done;
642 state->offset++;
643 num_bytes_to_skip--;
644 n--;
646 num_written = process_data(state, fh, pkt, n,
647 pd, err, err_info, pid);
649 if (num_written < 0) {
650 return false;
652 else if (num_written > 0) {
653 *num_bytes = num_written;
654 *direction = pkt->dir;
655 return true;
657 /* if 0 bytes written, keep looping */
658 break;
660 case PPPD_SEND_DELIM:
661 case PPPD_RECV_DELIM:
662 /* What can we do? */
663 break;
665 case PPPD_RESET_TIME:
666 if (!wtap_read_bytes(fh, &time_long, sizeof(uint32_t), err, err_info))
667 return false;
668 state->offset += sizeof(uint32_t);
669 state->timestamp = pntoh32(&time_long);
670 state->tenths = 0;
671 break;
673 case PPPD_TIME_STEP_LONG:
674 if (!wtap_read_bytes(fh, &time_long, sizeof(uint32_t), err, err_info))
675 return false;
676 state->offset += sizeof(uint32_t);
677 state->tenths += pntoh32(&time_long);
679 if (state->tenths >= 10) {
680 state->timestamp += state->tenths / 10;
681 state->tenths = state->tenths % 10;
684 break;
686 case PPPD_TIME_STEP_SHORT:
687 if (!wtap_read_bytes(fh, &time_short, sizeof(uint8_t), err, err_info))
688 return false;
689 state->offset += sizeof(uint8_t);
690 state->tenths += time_short;
692 if (state->tenths >= 10) {
693 state->timestamp += state->tenths / 10;
694 state->tenths = state->tenths % 10;
697 break;
699 default:
700 /* XXX - bad file */
701 *err = WTAP_ERR_BAD_FILE;
702 *err_info = ws_strdup_printf("pppdump: bad ID byte 0x%02x", id);
703 return false;
708 done:
709 *err = file_error(fh, err_info);
710 if (*err == 0) {
711 if (state->offset != start_offset) {
713 * We read at least one byte, so we were working
714 * on a record; an EOF means that record was
715 * cut short.
717 *err = WTAP_ERR_SHORT_READ;
720 return false;
725 /* Used to read packets in random-access fashion */
726 static bool
727 pppdump_seek_read(wtap *wth,
728 int64_t seek_off,
729 wtap_rec *rec,
730 Buffer *buf,
731 int *err,
732 char **err_info)
734 int num_bytes;
735 uint8_t *pd;
736 direction_enum direction;
737 pppdump_t *state;
738 pkt_id *pid;
739 int64_t num_bytes_to_skip;
741 state = (pppdump_t *)wth->priv;
743 pid = (pkt_id *)g_ptr_array_index(state->pids, seek_off);
744 if (!pid) {
745 *err = WTAP_ERR_BAD_FILE; /* XXX - better error? */
746 *err_info = g_strdup("pppdump: PID not found for record");
747 return false;
750 if (file_seek(wth->random_fh, pid->offset, SEEK_SET, err) == -1)
751 return false;
753 init_state(state->seek_state);
754 state->seek_state->offset = pid->offset;
756 ws_buffer_assure_space(buf, PPPD_BUF_SIZE);
757 pd = ws_buffer_start_ptr(buf);
760 * We'll start reading at the first record containing data from
761 * this packet; however, that doesn't mean "collate()" will
762 * stop only when we've read that packet, as there might be
763 * data for packets going in the other direction as well, and
764 * we might finish processing one of those packets before we
765 * finish processing the packet we're reading.
767 * Therefore, we keep reading until we get a packet that's
768 * going in the direction we want.
770 num_bytes_to_skip = pid->num_bytes_to_skip;
771 do {
772 if (!collate(state->seek_state, wth->random_fh, err, err_info,
773 pd, &num_bytes, &direction, NULL, num_bytes_to_skip))
774 return false;
775 num_bytes_to_skip = 0;
776 } while (direction != pid->dir);
778 pppdump_set_phdr(rec, num_bytes, pid->dir);
780 return true;
783 static void
784 pppdump_close(wtap *wth)
786 pppdump_t *state;
788 state = (pppdump_t *)wth->priv;
790 if (state->seek_state) { /* should always be true */
791 g_free(state->seek_state);
794 if (state->pids) {
795 unsigned int i;
796 for (i = 0; i < g_ptr_array_len(state->pids); i++) {
797 g_free(g_ptr_array_index(state->pids, i));
799 g_ptr_array_free(state->pids, true);
803 static const struct supported_block_type pppdump_blocks_supported[] = {
805 * We support packet blocks, with no comments or other options.
807 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
810 static const struct file_type_subtype_info pppdump_info = {
811 "pppd log (pppdump format)", "pppd", NULL, NULL,
812 false, BLOCKS_SUPPORTED(pppdump_blocks_supported),
813 NULL, NULL, NULL
816 void register_pppdump(void)
818 pppdump_file_type_subtype = wtap_register_file_type_subtype(&pppdump_info);
821 * Register name for backwards compatibility with the
822 * wtap_filetypes table in Lua.
824 wtap_register_backwards_compatibility_lua_name("PPPDUMP",
825 pppdump_file_type_subtype);
829 * Editor modelines - https://www.wireshark.org/tools/modelines.html
831 * Local variables:
832 * c-basic-offset: 8
833 * tab-width: 8
834 * indent-tabs-mode: t
835 * End:
837 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
838 * :indentSize=8:tabSize=8:noTabs=false: