wiretap: fix code according to clang-tidy.
[metze/wireshark/wip.git] / wiretap / logcat_text.c
1 /* logcat_text.c
2  *
3  * Copyright 2014, Michal Orynicz for Tieto Corporation
4  * Copyright 2014, Michal Labedzki for Tieto Corporation
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8
9 #include "config.h"
10
11 #include <string.h>
12
13 #include "wtap-int.h"
14 #include "file_wrappers.h"
15
16 #include "logcat_text.h"
17 #include "logcat.h"
18
19 struct dumper_t {
20     int type;
21 };
22
23 /* Returns '?' for invalid priorities */
24 static gchar get_priority(const guint8 priority) {
25     static gchar priorities[] = "??VDIWEFS";
26
27     if (priority >= (guint8) sizeof(priorities))
28         return '?';
29
30     return priorities[priority];
31 }
32
33 static gint buffered_detect_version(const guint8 *pd)
34 {
35     const struct logger_entry     *log_entry;
36     const struct logger_entry_v2  *log_entry_v2;
37     gint                     version;
38     const guint8            *msg_payload = NULL;
39     guint8                  *msg_part;
40     guint8                  *msg_end;
41     guint16                  msg_len;
42
43     log_entry    = (const struct logger_entry *)(const void *) pd;
44     log_entry_v2 = (const struct logger_entry_v2 *)(const void *) pd;
45
46     /* must contain at least priority and two nulls as separator */
47     if (log_entry->len < 3)
48         return -1;
49
50     /* payload length may not exceed the maximum payload size */
51     if (log_entry->len > LOGGER_ENTRY_MAX_PAYLOAD)
52         return -1;
53
54     /* cannot rely on __pad being 0 for v1, use heuristics to find out what
55      * version is in use. First assume the smallest msg. */
56     for (version = 1; version <= 2; ++version) {
57         if (version == 1) {
58             msg_payload = (const guint8 *) (log_entry + 1);
59         } else if (version == 2) {
60             /* v2 is 4 bytes longer */
61             msg_payload = (const guint8 *) (log_entry_v2 + 1);
62             if (log_entry_v2->hdr_size != sizeof(*log_entry_v2))
63                 continue;
64         }
65
66         /* A v2 msg has a 32-bit userid instead of v1 priority */
67         if (get_priority(msg_payload[0]) == '?')
68             continue;
69
70         /* Is there a terminating '\0' for the tag? */
71         msg_part = (guint8 *) memchr(msg_payload, '\0', log_entry->len - 1);
72         if (msg_part == NULL)
73             continue;
74
75         /* if msg is '\0'-terminated, is it equal to the payload len? */
76         ++msg_part;
77         msg_len = (guint16)(log_entry->len - (msg_part - msg_payload));
78         msg_end = (guint8 *) memchr(msg_part, '\0', msg_len);
79         /* is the end of the buffer (-1) equal to the end of msg? */
80         if (msg_end && (msg_payload + log_entry->len - 1 != msg_end))
81             continue;
82
83         return version;
84     }
85
86     return -1;
87 }
88
89 static gchar *logcat_log(const struct dumper_t *dumper, guint32 seconds,
90         gint milliseconds, gint pid, gint tid, gchar priority, const gchar *tag,
91         const gchar *log)
92 {
93     gchar  time_buffer[15];
94     time_t datetime;
95     struct tm *tm;
96
97     datetime = (time_t) seconds;
98
99     switch (dumper->type) {
100         case WTAP_ENCAP_LOGCAT_BRIEF:
101             return g_strdup_printf("%c/%-8s(%5i): %s\n",
102                     priority, tag, pid, log);
103         case WTAP_ENCAP_LOGCAT_PROCESS:
104             /* NOTE: Last parameter should be "process name", not tag;
105                      Unfortunately, we do not have process name */
106             return g_strdup_printf("%c(%5i) %s  (%s)\n",
107                     priority, pid, log, "");
108         case WTAP_ENCAP_LOGCAT_TAG:
109             return g_strdup_printf("%c/%-8s: %s\n",
110                    priority, tag, log);
111         case WTAP_ENCAP_LOGCAT_THREAD:
112             return g_strdup_printf("%c(%5i:%5i) %s\n",
113                     priority, pid, tid, log);
114         case WTAP_ENCAP_LOGCAT_TIME:
115             tm = gmtime(&datetime);
116             if (tm != NULL) {
117                 strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
118                         tm);
119                 return g_strdup_printf("%s.%03i %c/%-8s(%5i): %s\n",
120                         time_buffer, milliseconds, priority, tag, pid, log);
121             } else {
122                 return g_strdup_printf("Not representable %c/%-8s(%5i): %s\n",
123                         priority, tag, pid, log);
124             }
125         case WTAP_ENCAP_LOGCAT_THREADTIME:
126             tm = gmtime(&datetime);
127             if (tm != NULL) {
128                 strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
129                         tm);
130                 return g_strdup_printf("%s.%03i %5i %5i %c %-8s: %s\n",
131                         time_buffer, milliseconds, pid, tid, priority, tag, log);
132             } else {
133                 return g_strdup_printf("Not representable %5i %5i %c %-8s: %s\n",
134                         pid, tid, priority, tag, log);
135             }
136         case WTAP_ENCAP_LOGCAT_LONG:
137             tm = gmtime(&datetime);
138             if (tm != NULL) {
139                 strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
140                         tm);
141                 return g_strdup_printf("[ %s.%03i %5i:%5i %c/%-8s ]\n%s\n\n",
142                         time_buffer, milliseconds, pid, tid, priority, tag, log);
143             } else {
144                 return g_strdup_printf("[ Not representable %5i:%5i %c/%-8s ]\n%s\n\n",
145                         pid, tid, priority, tag, log);
146             }
147         default:
148             return NULL;
149     }
150
151 }
152
153 static void get_time(gchar *string, wtap_rec *rec) {
154     gint ms;
155     struct tm date;
156     time_t seconds;
157
158     if (6 == sscanf(string, "%d-%d %d:%d:%d.%d", &date.tm_mon, &date.tm_mday, &date.tm_hour,
159                     &date.tm_min, &date.tm_sec, &ms)) {
160         date.tm_year = 70;
161         date.tm_mon -= 1;
162         date.tm_isdst = -1;
163         seconds = mktime(&date);
164         rec->ts.secs = seconds;
165         rec->ts.nsecs = (int) (ms * 1e6);
166         rec->presence_flags = WTAP_HAS_TS;
167     } else {
168         rec->presence_flags = 0;
169         rec->ts.secs = (time_t) 0;
170         rec->ts.nsecs = 0;
171     }
172 }
173
174 static gboolean logcat_text_read_packet(FILE_T fh, wtap_rec *rec,
175         Buffer *buf, gint file_type) {
176     gint8 *pd;
177     gchar *cbuff;
178     gchar *ret = NULL;
179
180     cbuff = (gchar*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
181     do {
182         ret = file_gets(cbuff, WTAP_MAX_PACKET_SIZE_STANDARD, fh);
183     } while (NULL != ret && 3 > strlen(cbuff) && !file_eof(fh));
184
185     if (NULL == ret || 3 > strlen(cbuff)) {
186         g_free(cbuff);
187         return FALSE;
188     }
189
190     if (WTAP_FILE_TYPE_SUBTYPE_LOGCAT_LONG == file_type &&
191             !g_regex_match_simple(SPECIAL_STRING, cbuff, (GRegexCompileFlags)((gint) G_REGEX_ANCHORED | (gint) G_REGEX_RAW), G_REGEX_MATCH_NOTEMPTY)) {
192         gint64 file_off = 0;
193         gchar *lbuff;
194         int err;
195         gchar *ret2 = NULL;
196
197         lbuff = (gchar*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
198         file_off = file_tell(fh);
199         ret2 = file_gets(lbuff,WTAP_MAX_PACKET_SIZE_STANDARD, fh);
200         while (NULL != ret2 && 2 < strlen(lbuff) && !file_eof(fh)) {
201             g_strlcat(cbuff,lbuff,WTAP_MAX_PACKET_SIZE_STANDARD);
202             file_off = file_tell(fh);
203             ret2 = file_gets(lbuff,WTAP_MAX_PACKET_SIZE_STANDARD, fh);
204         }
205
206         if(NULL == ret2 || 2 < strlen(lbuff)) {
207             g_free(cbuff);
208             g_free(lbuff);
209             return FALSE;
210         }
211
212         file_seek(fh,file_off,SEEK_SET,&err);
213         g_free(lbuff);
214     }
215
216     rec->rec_type = REC_TYPE_PACKET;
217     rec->rec_header.packet_header.caplen = (guint32)strlen(cbuff);
218     rec->rec_header.packet_header.len = rec->rec_header.packet_header.caplen;
219
220     ws_buffer_assure_space(buf, rec->rec_header.packet_header.caplen + 1);
221     pd = ws_buffer_start_ptr(buf);
222     if ((WTAP_FILE_TYPE_SUBTYPE_LOGCAT_TIME == file_type
223             || WTAP_FILE_TYPE_SUBTYPE_LOGCAT_THREADTIME == file_type
224             || WTAP_FILE_TYPE_SUBTYPE_LOGCAT_LONG == file_type)
225             && '-' != cbuff[0]) { /* the last part filters out the -- beginning of... lines */
226         if (WTAP_FILE_TYPE_SUBTYPE_LOGCAT_LONG == file_type) {
227             get_time(cbuff+2, rec);
228         } else {
229             get_time(cbuff, rec);
230         }
231     } else {
232         rec->presence_flags = 0;
233         rec->ts.secs = (time_t) 0;
234         rec->ts.nsecs = 0;
235     }
236     memcpy(pd, cbuff, rec->rec_header.packet_header.caplen + 1);
237     g_free(cbuff);
238     return TRUE;
239 }
240
241 static gboolean logcat_text_read(wtap *wth, int *err _U_ , gchar **err_info _U_,
242         gint64 *data_offset) {
243     *data_offset = file_tell(wth->fh);
244
245     return logcat_text_read_packet(wth->fh, &wth->rec, wth->rec_data,
246             wth->file_type_subtype);
247 }
248
249 static gboolean logcat_text_seek_read(wtap *wth, gint64 seek_off,
250         wtap_rec *rec, Buffer *buf, int *err, gchar **err_info _U_) {
251     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
252         return FALSE;
253
254     if (!logcat_text_read_packet(wth->random_fh, rec, buf,
255             wth->file_type_subtype)) {
256         if (*err == 0)
257             *err = WTAP_ERR_SHORT_READ;
258         return FALSE;
259     }
260     return TRUE;
261 }
262
263 wtap_open_return_val logcat_text_open(wtap *wth, int *err, gchar **err_info _U_) {
264     gchar *cbuff;
265     gchar *ret = NULL;
266
267     if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
268         return WTAP_OPEN_ERROR;
269
270     cbuff = (gchar*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
271     do {
272         ret = file_gets(cbuff, WTAP_MAX_PACKET_SIZE_STANDARD, wth->fh);
273     } while (NULL != ret && !file_eof(wth->fh)
274             && ((3 > strlen(cbuff))
275                     || g_regex_match_simple(SPECIAL_STRING, cbuff, (GRegexCompileFlags)((gint) G_REGEX_ANCHORED | (gint) G_REGEX_RAW),
276                             G_REGEX_MATCH_NOTEMPTY)));
277
278     if (g_regex_match_simple(BRIEF_STRING, cbuff, (GRegexCompileFlags)((gint) G_REGEX_ANCHORED | (gint) G_REGEX_RAW),
279             G_REGEX_MATCH_NOTEMPTY)) {
280         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_BRIEF;
281         wth->file_encap = WTAP_ENCAP_LOGCAT_BRIEF;
282     } else if (g_regex_match_simple(TAG_STRING, cbuff, (GRegexCompileFlags)((gint) G_REGEX_ANCHORED | (gint) G_REGEX_RAW),
283             G_REGEX_MATCH_NOTEMPTY)) {
284         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_TAG;
285         wth->file_encap = WTAP_ENCAP_LOGCAT_TAG;
286     } else if (g_regex_match_simple(PROCESS_STRING, cbuff, (GRegexCompileFlags)((gint) G_REGEX_ANCHORED | (gint) G_REGEX_RAW),
287             G_REGEX_MATCH_NOTEMPTY)) {
288         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_PROCESS;
289         wth->file_encap = WTAP_ENCAP_LOGCAT_PROCESS;
290     } else if (g_regex_match_simple(TIME_STRING, cbuff, (GRegexCompileFlags)((gint) G_REGEX_ANCHORED | (gint) G_REGEX_RAW),
291             G_REGEX_MATCH_NOTEMPTY)) {
292         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_TIME;
293         wth->file_encap = WTAP_ENCAP_LOGCAT_TIME;
294     } else if (g_regex_match_simple(THREAD_STRING, cbuff, (GRegexCompileFlags)((gint) G_REGEX_ANCHORED | (gint) G_REGEX_RAW),
295             G_REGEX_MATCH_NOTEMPTY)) {
296         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_THREAD;
297         wth->file_encap = WTAP_ENCAP_LOGCAT_THREAD;
298     } else if (g_regex_match_simple(THREADTIME_STRING, cbuff, (GRegexCompileFlags)((gint) G_REGEX_ANCHORED | (gint) G_REGEX_RAW),
299             G_REGEX_MATCH_NOTEMPTY)) {
300         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_THREADTIME;
301         wth->file_encap = WTAP_ENCAP_LOGCAT_THREADTIME;
302     } else if (g_regex_match_simple(LONG_STRING, cbuff, (GRegexCompileFlags)((gint) G_REGEX_ANCHORED | (gint) G_REGEX_RAW),
303             G_REGEX_MATCH_NOTEMPTY)) {
304         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_LONG;
305         wth->file_encap = WTAP_ENCAP_LOGCAT_LONG;
306     } else {
307         g_free(cbuff);
308         return WTAP_OPEN_NOT_MINE;
309     }
310
311     if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
312         g_free(cbuff);
313         return WTAP_OPEN_ERROR;
314     }
315     wth->snapshot_length = 0;
316
317     wth->subtype_read = logcat_text_read;
318     wth->subtype_seek_read = logcat_text_seek_read;
319     wth->file_tsprec = WTAP_TSPREC_USEC;
320     g_free(cbuff);
321     return WTAP_OPEN_MINE;
322 }
323
324 int logcat_text_brief_dump_can_write_encap(int encap) {
325     if (encap == WTAP_ENCAP_PER_PACKET)
326         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
327
328     switch (encap) {
329     case WTAP_ENCAP_LOGCAT:
330     case WTAP_ENCAP_LOGCAT_BRIEF:
331     case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
332         return 0;
333     default:
334         return WTAP_ERR_UNWRITABLE_ENCAP;
335     }
336 }
337
338 int logcat_text_process_dump_can_write_encap(int encap) {
339     if (encap == WTAP_ENCAP_PER_PACKET)
340         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
341
342     switch (encap) {
343     case WTAP_ENCAP_LOGCAT:
344     case WTAP_ENCAP_LOGCAT_PROCESS:
345     case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
346         return 0;
347     default:
348         return WTAP_ERR_UNWRITABLE_ENCAP;
349     }
350 }
351
352 int logcat_text_tag_dump_can_write_encap(int encap) {
353     if (encap == WTAP_ENCAP_PER_PACKET)
354         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
355
356     switch (encap) {
357     case WTAP_ENCAP_LOGCAT:
358     case WTAP_ENCAP_LOGCAT_TAG:
359     case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
360         return 0;
361     default:
362         return WTAP_ERR_UNWRITABLE_ENCAP;
363     }
364 }
365
366 int logcat_text_time_dump_can_write_encap(int encap) {
367     if (encap == WTAP_ENCAP_PER_PACKET)
368         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
369
370     switch (encap) {
371     case WTAP_ENCAP_LOGCAT:
372     case WTAP_ENCAP_LOGCAT_TIME:
373     case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
374         return 0;
375     default:
376         return WTAP_ERR_UNWRITABLE_ENCAP;
377     }
378 }
379
380 int logcat_text_thread_dump_can_write_encap(int encap) {
381     if (encap == WTAP_ENCAP_PER_PACKET)
382         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
383
384     switch (encap) {
385     case WTAP_ENCAP_LOGCAT:
386     case WTAP_ENCAP_LOGCAT_THREAD:
387     case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
388         return 0;
389     default:
390         return WTAP_ERR_UNWRITABLE_ENCAP;
391     }
392 }
393
394 int logcat_text_threadtime_dump_can_write_encap(int encap) {
395     if (encap == WTAP_ENCAP_PER_PACKET)
396         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
397
398     switch (encap) {
399     case WTAP_ENCAP_LOGCAT:
400     case WTAP_ENCAP_LOGCAT_THREADTIME:
401     case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
402         return 0;
403     default:
404         return WTAP_ERR_UNWRITABLE_ENCAP;
405     }
406 }
407
408 int logcat_text_long_dump_can_write_encap(int encap) {
409     if (encap == WTAP_ENCAP_PER_PACKET)
410         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
411
412     switch (encap) {
413     case WTAP_ENCAP_LOGCAT:
414     case WTAP_ENCAP_LOGCAT_LONG:
415     case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
416         return 0;
417     default:
418         return WTAP_ERR_UNWRITABLE_ENCAP;
419     }
420 }
421
422 static gboolean logcat_text_dump_text(wtap_dumper *wdh,
423     const wtap_rec *rec,
424     const guint8 *pd, int *err, gchar **err_info)
425 {
426     gchar                          *buf;
427     gint                            length;
428     gchar                           priority;
429     const struct logger_entry      *log_entry;
430     const struct logger_entry_v2   *log_entry_v2;
431     gint                            payload_length;
432     const gchar                    *tag;
433     gint32                          pid;
434     gint32                          tid;
435     gint32                          seconds;
436     gint32                          milliseconds;
437     const guint8                   *msg_payload = NULL;
438     const gchar                    *msg_begin;
439     gint                            msg_pre_skip;
440     gchar                          *log;
441     gchar                          *log_part;
442     gchar                          *log_next;
443     gint                           logcat_version;
444     const struct dumper_t          *dumper        = (const struct dumper_t *) wdh->priv;
445
446     /* We can only write packet records. */
447     if (rec->rec_type != REC_TYPE_PACKET) {
448         *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
449         return FALSE;
450     }
451
452     /*
453      * Make sure this packet doesn't have a link-layer type that
454      * differs from the one for the file.
455      */
456     if (wdh->encap != rec->rec_header.packet_header.pkt_encap) {
457         *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
458         return FALSE;
459     }
460
461     switch (wdh->encap) {
462     case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
463         {
464             gint skipped_length;
465
466             skipped_length = logcat_exported_pdu_length(pd);
467             pd += skipped_length;
468
469             if (!wtap_dump_file_write(wdh, (const gchar*) pd, rec->rec_header.packet_header.caplen - skipped_length, err)) {
470                 return FALSE;
471             }
472         }
473         break;
474     case WTAP_ENCAP_LOGCAT:
475         /* Skip EXPORTED_PDU*/
476         if (wdh->encap == WTAP_ENCAP_WIRESHARK_UPPER_PDU) {
477             gint skipped_length;
478
479             skipped_length = logcat_exported_pdu_length(pd);
480             pd += skipped_length;
481
482             logcat_version = buffered_detect_version(pd);
483         } else {
484             const union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
485
486             logcat_version = pseudo_header->logcat.version;
487         }
488
489         log_entry    = (const struct logger_entry *)(const void *) pd;
490         log_entry_v2 = (const struct logger_entry_v2 *)(const void *) pd;
491
492         payload_length = GINT32_FROM_LE(log_entry->len);
493         pid = GINT32_FROM_LE(log_entry->pid);
494         tid = GINT32_FROM_LE(log_entry->tid);
495         seconds = GINT32_FROM_LE(log_entry->sec);
496         milliseconds = GINT32_FROM_LE(log_entry->nsec) / 1000000;
497
498         /* msg: <prio:1><tag:N>\0<msg:N>\0 with N >= 0, last \0 can be missing */
499         if (logcat_version == 1) {
500             msg_payload = (const guint8 *) (log_entry + 1);
501
502             priority = get_priority(msg_payload[0]);
503             tag = msg_payload + 1;
504             msg_pre_skip = 1 + (gint) strlen(tag) + 1;
505             msg_begin = msg_payload + msg_pre_skip;
506         } else if (logcat_version == 2) {
507             msg_payload = (const guint8 *) (log_entry_v2 + 1);
508
509             priority = get_priority(msg_payload[0]);
510             tag = msg_payload + 1;
511             msg_pre_skip = 1 + (gint) strlen(tag) + 1;
512             msg_begin = msg_payload + msg_pre_skip;
513         } else {
514             *err = WTAP_ERR_UNWRITABLE_REC_DATA;
515             *err_info = g_strdup_printf("logcat: version %d isn't supported",
516                                         logcat_version);
517             return FALSE;
518         }
519
520         /* copy the message part. If a nul byte was missing, it will be added. */
521         log = g_strndup(msg_begin, payload_length - msg_pre_skip);
522
523         /* long format: display one header followed by the whole message (which may
524          * contain new lines). Other formats: include tag, etc. with each line */
525         log_next = log;
526         do {
527             log_part = log_next;
528             if (dumper->type == WTAP_ENCAP_LOGCAT_LONG) {
529                 /* read until end, there is no next string */
530                 log_next = NULL;
531             } else {
532                 /* read until next newline */
533                 log_next = strchr(log_part, '\n');
534                 if (log_next != NULL) {
535                     *log_next = '\0';
536                     ++log_next;
537                     /* ignore trailing newline */
538                     if (*log_next == '\0') {
539                         log_next = NULL;
540                     }
541                 }
542             }
543
544             buf = logcat_log(dumper, seconds, milliseconds, pid, tid, priority, tag, log_part);
545             if (!buf) {
546                 g_free(log);
547                 return FALSE;
548             }
549             length = (guint32) strlen(buf);
550
551             if (!wtap_dump_file_write(wdh, buf, length, err)) {
552                 g_free(log);
553                 return FALSE;
554             }
555
556             wdh->bytes_dumped += length;
557         } while (log_next != NULL );
558
559         g_free(log);
560
561         break;
562     case WTAP_ENCAP_LOGCAT_BRIEF:
563     case WTAP_ENCAP_LOGCAT_TAG:
564     case WTAP_ENCAP_LOGCAT_PROCESS:
565     case WTAP_ENCAP_LOGCAT_TIME:
566     case WTAP_ENCAP_LOGCAT_THREAD:
567     case WTAP_ENCAP_LOGCAT_THREADTIME:
568     case WTAP_ENCAP_LOGCAT_LONG:
569         if (dumper->type == wdh->encap) {
570             if (!wtap_dump_file_write(wdh, (const gchar*) pd, rec->rec_header.packet_header.caplen, err)) {
571                 return FALSE;
572             }
573         } else {
574             *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
575             return FALSE;
576         }
577     }
578
579     return TRUE;
580 }
581
582 static gboolean logcat_text_dump_open(wtap_dumper *wdh, guint dump_type, int *err _U_) {
583     struct dumper_t *dumper;
584
585     dumper = (struct dumper_t *) g_malloc(sizeof(struct dumper_t));
586     dumper->type = dump_type;
587
588     wdh->priv = dumper;
589     wdh->subtype_write = logcat_text_dump_text;
590
591     return TRUE;
592 }
593
594 gboolean logcat_text_brief_dump_open(wtap_dumper *wdh, int *err) {
595     return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_BRIEF, err);
596 }
597
598 gboolean logcat_text_process_dump_open(wtap_dumper *wdh, int *err) {
599     return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_PROCESS, err);
600 }
601
602 gboolean logcat_text_tag_dump_open(wtap_dumper *wdh, int *err) {
603     return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_TAG, err);
604 }
605
606 gboolean logcat_text_time_dump_open(wtap_dumper *wdh, int *err) {
607     return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_TIME, err);
608 }
609
610 gboolean logcat_text_thread_dump_open(wtap_dumper *wdh, int *err) {
611     return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_THREAD, err);
612 }
613
614 gboolean logcat_text_threadtime_dump_open(wtap_dumper *wdh, int *err) {
615     return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_THREADTIME, err);
616 }
617
618 gboolean logcat_text_long_dump_open(wtap_dumper *wdh, int *err) {
619     return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_LONG, err);
620 }
621
622 /*
623  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
624  *
625  * Local variables:
626  * c-basic-offset: 4
627  * tab-width: 8
628  * indent-tabs-mode: nil
629  * End:
630  *
631  * vi: set shiftwidth=4 tabstop=8 expandtab:
632  * :indentSize=4:tabSize=8:noTabs=true:
633  */