summaryrefslogtreecommitdiff
path: root/wiretap/logcat_text.c
diff options
context:
space:
mode:
authorMichaƂ Orynicz <michal.orynicz@tieto.com>2014-05-14 09:45:23 +0200
committerAnders Broman <a.broman58@gmail.com>2014-08-06 06:46:50 +0000
commit1a02ca0150e434d9ddc7c023267c9097a059b6be (patch)
tree4d7f3812bc71e659ff792355d12028137e06232a /wiretap/logcat_text.c
parent71d07bcbbf08eac22432203c2c464fdce13b9467 (diff)
downloadwireshark-1a02ca0150e434d9ddc7c023267c9097a059b6be.tar.gz
Add support for android logcat text files
Wireshark already supports reading and writing logcat logs saved in binary files. Binary format, although better, is used less often than saving those logs to text files. This patch extends wireshark's support for android logcat logs to reading and writing logcat logs in text files. Features: * support for tag, brief, process, thread, time, threadtime and long formats * saving in original format * it's generally awesome Change-Id: I013d6ac2da876d9a2b39b740219eb398d03830f6 Reviewed-on: https://code.wireshark.org/review/1802 Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'wiretap/logcat_text.c')
-rw-r--r--wiretap/logcat_text.c593
1 files changed, 593 insertions, 0 deletions
diff --git a/wiretap/logcat_text.c b/wiretap/logcat_text.c
new file mode 100644
index 0000000000..a24a853f6d
--- /dev/null
+++ b/wiretap/logcat_text.c
@@ -0,0 +1,593 @@
+/* logcat_text.c
+ *
+ * Copyright 2014, Michal Orynicz for Tieto Corporation
+ * Copyright 2014, Michal Labedzki for Tieto Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <time.h>
+
+#include "wtap-int.h"
+#include "file_wrappers.h"
+#include "wsutil/buffer.h"
+
+#include "logcat_text.h"
+#include "logcat.h"
+
+/* Basically the same regexes are present in epan/packet-logcat-text.c */
+#define SPECIAL_STRING "[-]+ beginning of \\/"
+#define BRIEF_STRING "[IVDWEF]/.*\\( *\\d*\\): .*"
+#define TAG_STRING "[IVDWEF]/.*: .*"
+#define TIME_STRING "\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3} [IVDWE]/.*\\( *\\d*\\): .*"
+#define THREAD_STRING "[IVDWEF]\\( *\\d+: *\\d+\\) .*"
+#define PROCESS_STRING "[IVDWEF]\\( *\\d+\\) .*"
+#define THREADTIME_STRING "\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3} *\\d+ *\\d+ [IVDWEF] .+: +"
+#define LONG_STRING "\\[ (\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3}) +(\\d+): +(\\d+) ([IVDWEF])/(.+) ]"
+
+struct dumper_t {
+ int type;
+};
+
+/* Returns '?' for invalid priorities */
+static gchar get_priority(const guint8 priority) {
+ static gchar priorities[] = "??VDIWEFS";
+
+ if (priority >= (guint8) sizeof(priorities))
+ return '?';
+
+ return priorities[priority];
+}
+
+static gint buffered_detect_version(const guint8 *pd)
+{
+ struct logger_entry *log_entry;
+ struct logger_entry_v2 *log_entry_v2;
+ gint version;
+ guint8 *msg_payload = NULL;
+ guint8 *msg_part;
+ guint8 *msg_end;
+ guint16 msg_len;
+
+ log_entry_v2 = (struct logger_entry_v2 *) pd;
+ log_entry = (struct logger_entry *) pd;
+
+ /* must contain at least priority and two nulls as separator */
+ if (log_entry->len < 3)
+ return -1;
+
+ /* payload length may not exceed the maximum payload size */
+ if (log_entry->len > LOGGER_ENTRY_MAX_PAYLOAD)
+ return -1;
+
+ /* cannot rely on __pad being 0 for v1, use heuristics to find out what
+ * version is in use. First assume the smallest msg. */
+ for (version = 1; version <= 2; ++version) {
+ if (version == 1) {
+ msg_payload = log_entry->msg;
+ } else if (version == 2) {
+ /* v2 is 4 bytes longer */
+ msg_payload = log_entry_v2->msg;
+ if (log_entry_v2->hdr_size != sizeof(*log_entry_v2))
+ continue;
+ }
+
+ /* A v2 msg has a 32-bit userid instead of v1 priority */
+ if (get_priority(msg_payload[0]) == '?')
+ continue;
+
+ /* Is there a terminating '\0' for the tag? */
+ msg_part = (guint8 *) memchr(msg_payload, '\0', log_entry->len - 1);
+ if (msg_part == NULL)
+ continue;
+
+ /* if msg is '\0'-terminated, is it equal to the payload len? */
+ ++msg_part;
+ msg_len = (guint16)(log_entry->len - (msg_part - msg_payload));
+ msg_end = (guint8 *) memchr(msg_part, '\0', msg_len);
+ /* is the end of the buffer (-1) equal to the end of msg? */
+ if (msg_end && (msg_payload + log_entry->len - 1 != msg_end))
+ continue;
+
+ return version;
+ }
+
+ return -1;
+}
+
+static gchar *logcat_log(const struct dumper_t *dumper, guint32 seconds,
+ gint milliseconds, gint pid, gint tid, gchar priority, const gchar *tag,
+ const gchar *log)
+{
+ gchar time_buffer[15];
+ time_t datetime;
+
+ datetime = (time_t) seconds;
+
+ switch (dumper->type) {
+ case WTAP_ENCAP_LOGCAT_BRIEF:
+ return g_strdup_printf("%c/%-8s(%5i): %s\n",
+ priority, tag, pid, log);
+ case WTAP_ENCAP_LOGCAT_PROCESS:
+ /* NOTE: Last parameter should be "process name", not tag;
+ Unfortunately, we do not have process name */
+ return g_strdup_printf("%c(%5i) %s (%s)\n",
+ priority, pid, log, "");
+ case WTAP_ENCAP_LOGCAT_TAG:
+ return g_strdup_printf("%c/%-8s: %s\n",
+ priority, tag, log);
+ case WTAP_ENCAP_LOGCAT_THREAD:
+ return g_strdup_printf("%c(%5i:%5i) %s\n",
+ priority, pid, tid, log);
+ case WTAP_ENCAP_LOGCAT_TIME:
+ strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
+ gmtime(&datetime));
+ return g_strdup_printf("%s.%03i %c/%-8s(%5i): %s\n",
+ time_buffer, milliseconds, priority, tag, pid, log);
+ case WTAP_ENCAP_LOGCAT_THREADTIME:
+ strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
+ gmtime(&datetime));
+ return g_strdup_printf("%s.%03i %5i %5i %c %-8s: %s\n",
+ time_buffer, milliseconds, pid, tid, priority, tag, log);
+ case WTAP_ENCAP_LOGCAT_LONG:
+ strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
+ gmtime(&datetime));
+ return g_strdup_printf("[ %s.%03i %5i:%5i %c/%-8s ]\n%s\n\n",
+ time_buffer, milliseconds, pid, tid, priority, tag, log);
+ default:
+ return NULL;
+ }
+
+}
+
+static void get_time(gchar *string, struct wtap_pkthdr *phdr) {
+ gint day, month, hrs, min, sec, ms;
+ GDateTime *date = NULL;
+ gint64 seconds;
+
+ if (6 == sscanf(string, "%d-%d %d:%d:%d.%d", &month, &day, &hrs, &min, &sec, &ms)) {
+ date = g_date_time_new_local(1970, month, day, hrs, min,
+ (gdouble) sec + ((gdouble) ms) * 0.001);
+ seconds = g_date_time_to_unix(date);
+ phdr->ts.secs = (time_t) seconds;
+ phdr->ts.nsecs = (int) ms * 1e6;
+ phdr->presence_flags = WTAP_HAS_TS;
+ g_date_time_unref(date);
+ } else {
+ phdr->presence_flags = 0;
+ phdr->ts.secs = (time_t) 0;
+ phdr->ts.nsecs = (int) 0;
+ }
+}
+
+static gboolean logcat_text_read_packet(FILE_T fh, struct wtap_pkthdr *phdr,
+ Buffer *buf, gint file_type) {
+ gint8 *pd;
+ gchar cbuff[WTAP_MAX_PACKET_SIZE];
+ gchar *ret = NULL;
+
+ do {
+ ret = file_gets(cbuff, WTAP_MAX_PACKET_SIZE, fh);
+ } while (NULL != ret && 3 > strlen(cbuff) && !file_eof(fh));
+
+ if (NULL == ret || 3 > strlen(cbuff)) {
+ return FALSE;
+ }
+
+ if (WTAP_FILE_TYPE_SUBTYPE_LOGCAT_LONG == file_type &&
+ !g_regex_match_simple(SPECIAL_STRING, cbuff, G_REGEX_ANCHORED, G_REGEX_MATCH_NOTEMPTY)) {
+ gint64 file_off = 0;
+ gchar lbuff[WTAP_MAX_PACKET_SIZE];
+ int err;
+ gchar *ret2 = NULL;
+
+ file_off = file_tell(fh);
+ ret2 = file_gets(lbuff,WTAP_MAX_PACKET_SIZE, fh);
+ while (NULL != ret2 && 2 < strlen(lbuff) && !file_eof(fh)) {
+ g_strlcat(cbuff,lbuff,WTAP_MAX_PACKET_SIZE);
+ file_off = file_tell(fh);
+ ret2 = file_gets(lbuff,WTAP_MAX_PACKET_SIZE, fh);
+ }
+
+ if(NULL == ret2 || 2 < strlen(lbuff)) {
+ return FALSE;
+ }
+
+ file_seek(fh,file_off,SEEK_SET,&err);
+ }
+
+ phdr->rec_type = REC_TYPE_PACKET;
+ phdr->caplen = strlen(cbuff);
+ phdr->len = phdr->caplen;
+
+ ws_buffer_assure_space(buf, phdr->caplen + 1);
+ pd = ws_buffer_start_ptr(buf);
+ if ((WTAP_FILE_TYPE_SUBTYPE_LOGCAT_TIME == file_type
+ || WTAP_FILE_TYPE_SUBTYPE_LOGCAT_THREADTIME == file_type
+ || WTAP_FILE_TYPE_SUBTYPE_LOGCAT_LONG == file_type)
+ && '-' != cbuff[0]) { /* the last part filters out the -- beginning of... lines */
+ if (WTAP_FILE_TYPE_SUBTYPE_LOGCAT_LONG == file_type) {
+ get_time(cbuff+2, phdr);
+ } else {
+ get_time(cbuff, phdr);
+ }
+ } else {
+ phdr->presence_flags = 0;
+ phdr->ts.secs = (time_t) 0;
+ phdr->ts.nsecs = (int) 0;
+ }
+ memcpy(pd, cbuff, phdr->caplen + 1);
+ return TRUE;
+}
+
+static gboolean logcat_text_read(wtap *wth, int *err _U_ , gchar **err_info _U_,
+ gint64 *data_offset _U_) {
+ *data_offset = file_tell(wth->fh);
+
+ return logcat_text_read_packet(wth->fh, &wth->phdr, wth->frame_buffer,
+ wth->file_type_subtype);
+}
+
+static gboolean logcat_text_seek_read(wtap *wth, gint64 seek_off,
+ struct wtap_pkthdr *phdr, Buffer *buf, int *err _U_, gchar **err_info _U_) {
+ if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
+ return FALSE;
+
+ if (!logcat_text_read_packet(wth->random_fh, phdr, buf,
+ wth->file_type_subtype)) {
+ if (*err == 0)
+ *err = WTAP_ERR_SHORT_READ;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+int logcat_text_open(wtap *wth, int *err, gchar **err_info _U_) {
+ gchar cbuff[WTAP_MAX_PACKET_SIZE];
+ gchar *ret = NULL;
+
+ if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
+ return -1;
+
+ do {
+ ret = file_gets(cbuff, WTAP_MAX_PACKET_SIZE, wth->fh);
+ } while (NULL != ret && !file_eof(wth->fh)
+ && ((3 > strlen(cbuff))
+ || g_regex_match_simple(SPECIAL_STRING, cbuff, G_REGEX_ANCHORED,
+ G_REGEX_MATCH_NOTEMPTY)));
+
+ if (g_regex_match_simple(BRIEF_STRING, cbuff, G_REGEX_ANCHORED,
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_BRIEF;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_BRIEF;
+ } else if (g_regex_match_simple(TAG_STRING, cbuff, G_REGEX_ANCHORED,
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_TAG;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_TAG;
+ } else if (g_regex_match_simple(PROCESS_STRING, cbuff, G_REGEX_ANCHORED,
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_PROCESS;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_PROCESS;
+ } else if (g_regex_match_simple(TIME_STRING, cbuff, G_REGEX_ANCHORED,
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_TIME;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_TIME;
+ } else if (g_regex_match_simple(THREAD_STRING, cbuff, G_REGEX_ANCHORED,
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_THREAD;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_THREAD;
+ } else if (g_regex_match_simple(THREADTIME_STRING, cbuff, G_REGEX_ANCHORED,
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_THREADTIME;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_THREADTIME;
+ } else if (g_regex_match_simple(LONG_STRING, cbuff, G_REGEX_ANCHORED,
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT_LONG;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_LONG;
+ } else {
+ return -1;
+ }
+
+ if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
+ return -1;
+
+ wth->snapshot_length = 0;
+
+ wth->subtype_read = logcat_text_read;
+ wth->subtype_seek_read = logcat_text_seek_read;
+ wth->tsprecision = WTAP_FILE_TSPREC_USEC;
+ return 1;
+}
+
+int logcat_text_brief_dump_can_write_encap(int encap) {
+ if (encap == WTAP_ENCAP_PER_PACKET)
+ return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+
+ switch (encap) {
+ case WTAP_ENCAP_LOGCAT:
+ case WTAP_ENCAP_LOGCAT_BRIEF:
+ return 0;
+ default:
+ return WTAP_ERR_UNSUPPORTED_ENCAP;
+ }
+}
+
+int logcat_text_process_dump_can_write_encap(int encap) {
+ if (encap == WTAP_ENCAP_PER_PACKET)
+ return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+
+ switch (encap) {
+ case WTAP_ENCAP_LOGCAT:
+ case WTAP_ENCAP_LOGCAT_PROCESS:
+ return 0;
+ default:
+ return WTAP_ERR_UNSUPPORTED_ENCAP;
+ }
+}
+
+int logcat_text_tag_dump_can_write_encap(int encap) {
+ if (encap == WTAP_ENCAP_PER_PACKET)
+ return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+
+ switch (encap) {
+ case WTAP_ENCAP_LOGCAT:
+ case WTAP_ENCAP_LOGCAT_TAG:
+ return 0;
+ default:
+ return WTAP_ERR_UNSUPPORTED_ENCAP;
+ }
+}
+
+int logcat_text_time_dump_can_write_encap(int encap) {
+ if (encap == WTAP_ENCAP_PER_PACKET)
+ return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+
+ switch (encap) {
+ case WTAP_ENCAP_LOGCAT:
+ case WTAP_ENCAP_LOGCAT_TIME:
+ return 0;
+ default:
+ return WTAP_ERR_UNSUPPORTED_ENCAP;
+ }
+}
+
+int logcat_text_thread_dump_can_write_encap(int encap) {
+ if (encap == WTAP_ENCAP_PER_PACKET)
+ return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+
+ switch (encap) {
+ case WTAP_ENCAP_LOGCAT:
+ case WTAP_ENCAP_LOGCAT_THREAD:
+ return 0;
+ default:
+ return WTAP_ERR_UNSUPPORTED_ENCAP;
+ }
+}
+
+int logcat_text_threadtime_dump_can_write_encap(int encap) {
+ if (encap == WTAP_ENCAP_PER_PACKET)
+ return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+
+ switch (encap) {
+ case WTAP_ENCAP_LOGCAT:
+ case WTAP_ENCAP_LOGCAT_THREADTIME:
+ return 0;
+ default:
+ return WTAP_ERR_UNSUPPORTED_ENCAP;
+ }
+}
+
+int logcat_text_long_dump_can_write_encap(int encap) {
+ if (encap == WTAP_ENCAP_PER_PACKET)
+ return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+
+ switch (encap) {
+ case WTAP_ENCAP_LOGCAT:
+ case WTAP_ENCAP_LOGCAT_LONG:
+ return 0;
+ default:
+ return WTAP_ERR_UNSUPPORTED_ENCAP;
+ }
+}
+
+static gboolean logcat_text_dump_text(wtap_dumper *wdh,
+ const struct wtap_pkthdr *phdr,
+ const guint8 *pd, int *err)
+{
+ gchar *buf;
+ gint length;
+ gchar priority;
+ const struct logger_entry *log_entry;
+ const struct logger_entry_v2 *log_entry_v2;
+ gint payload_length;
+ const gchar *tag;
+ gint32 pid;
+ gint32 tid;
+ gint32 seconds;
+ gint32 milliseconds;
+ const gchar *msg_begin;
+ gint msg_pre_skip;
+ gchar *log;
+ gchar *log_part;
+ gchar *log_next;
+ gint logcat_version;
+ const struct dumper_t *dumper = (const struct dumper_t *) wdh->priv;
+
+ /* We can only write packet records. */
+ if (phdr->rec_type != REC_TYPE_PACKET) {
+ *err = WTAP_ERR_REC_TYPE_UNSUPPORTED;
+ return FALSE;
+ }
+
+ switch (wdh->encap) {
+ case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
+ case WTAP_ENCAP_LOGCAT:
+ /* Skip EXPORTED_PDU*/
+ if (wdh->encap == WTAP_ENCAP_WIRESHARK_UPPER_PDU) {
+ gint skipped_length;
+
+ skipped_length = logcat_exported_pdu_length(pd);
+ pd += skipped_length;
+
+ logcat_version = buffered_detect_version(pd);
+ } else {
+ const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
+
+ logcat_version = pseudo_header->logcat.version;
+ }
+
+ log_entry = (struct logger_entry *) pd;
+ log_entry_v2 = (struct logger_entry_v2 *) pd;
+
+ payload_length = GINT32_FROM_LE(log_entry->len);
+ pid = GINT32_FROM_LE(log_entry->pid);
+ tid = GINT32_FROM_LE(log_entry->tid);
+ seconds = GINT32_FROM_LE(log_entry->sec);
+ milliseconds = GINT32_FROM_LE(log_entry->nsec) / 1000000;
+
+ /* msg: <prio:1><tag:N>\0<msg:N>\0 with N >= 0, last \0 can be missing */
+ if (logcat_version == 1) {
+ priority = get_priority(log_entry->msg[0]);
+ tag = log_entry->msg + 1;
+ msg_pre_skip = 1 + (gint) strlen(tag) + 1;
+ msg_begin = log_entry->msg + msg_pre_skip;
+ } else if (logcat_version == 2) {
+ priority = get_priority(log_entry_v2->msg[0]);
+ tag = log_entry_v2->msg + 1;
+ msg_pre_skip = 1 + (gint) strlen(tag) + 1;
+ msg_begin = log_entry_v2->msg + msg_pre_skip;
+ } else {
+ *err = WTAP_ERR_UNSUPPORTED;
+ return FALSE;
+ }
+
+ /* copy the message part. If a nul byte was missing, it will be added. */
+ log = g_strndup(msg_begin, payload_length - msg_pre_skip);
+
+ /* long format: display one header followed by the whole message (which may
+ * contain new lines). Other formats: include tag, etc. with each line */
+ log_next = log;
+ do {
+ log_part = log_next;
+ if (dumper->type == WTAP_ENCAP_LOGCAT_LONG) {
+ /* read until end, there is no next string */
+ log_next = NULL;
+ } else {
+ /* read until next newline */
+ log_next = strchr(log_part, '\n');
+ if (log_next != NULL) {
+ *log_next = '\0';
+ ++log_next;
+ /* ignore trailing newline */
+ if (*log_next == '\0') {
+ log_next = NULL;
+ }
+ }
+ }
+
+ buf = logcat_log(dumper, seconds, milliseconds, pid, tid, priority, tag, log_part);
+ if (!buf) {
+ g_free(log);
+ return FALSE;
+ }
+ length = (guint32) strlen(buf);
+
+ if (!wtap_dump_file_write(wdh, buf, length, err)) {
+ g_free(log);
+ return FALSE;
+ }
+
+ wdh->bytes_dumped += length;
+ } while (log_next != NULL );
+
+ g_free(log);
+
+ break;
+ case WTAP_ENCAP_LOGCAT_BRIEF:
+ case WTAP_ENCAP_LOGCAT_TAG:
+ case WTAP_ENCAP_LOGCAT_PROCESS:
+ case WTAP_ENCAP_LOGCAT_TIME:
+ case WTAP_ENCAP_LOGCAT_THREAD:
+ case WTAP_ENCAP_LOGCAT_THREADTIME:
+ case WTAP_ENCAP_LOGCAT_LONG:
+ if (dumper->type == wdh->encap) {
+ if (!wtap_dump_file_write(wdh, (gchar*) pd, phdr->caplen, err)) {
+ return FALSE;
+ }
+ } else {
+ *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean logcat_text_dump_open(wtap_dumper *wdh, guint dump_type, int *err _U_) {
+ struct dumper_t *dumper;
+
+ dumper = (struct dumper_t *) g_malloc(sizeof(struct dumper_t));
+ dumper->type = dump_type;
+
+ wdh->priv = dumper;
+ wdh->subtype_write = logcat_text_dump_text;
+ wdh->subtype_close = NULL;
+
+ return TRUE;
+}
+
+gboolean logcat_text_brief_dump_open(wtap_dumper *wdh, int *err) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_BRIEF, err);
+}
+
+gboolean logcat_text_process_dump_open(wtap_dumper *wdh, int *err) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_PROCESS, err);
+}
+
+gboolean logcat_text_tag_dump_open(wtap_dumper *wdh, int *err) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_TAG, err);
+}
+
+gboolean logcat_text_time_dump_open(wtap_dumper *wdh, int *err) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_TIME, err);
+}
+
+gboolean logcat_text_thread_dump_open(wtap_dumper *wdh, int *err) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_THREAD, err);
+}
+
+gboolean logcat_text_threadtime_dump_open(wtap_dumper *wdh, int *err) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_THREADTIME, err);
+}
+
+gboolean logcat_text_long_dump_open(wtap_dumper *wdh, int *err) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_LONG, err);
+}
+
+/*
+ * Editor modelines - http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */