summaryrefslogtreecommitdiffstats
path: root/wiretap/logcat_text.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /wiretap/logcat_text.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'wiretap/logcat_text.c')
-rw-r--r--wiretap/logcat_text.c762
1 files changed, 762 insertions, 0 deletions
diff --git a/wiretap/logcat_text.c b/wiretap/logcat_text.c
new file mode 100644
index 00000000..ced74396
--- /dev/null
+++ b/wiretap/logcat_text.c
@@ -0,0 +1,762 @@
+/* logcat_text.c
+ *
+ * Copyright 2014, Michal Orynicz for Tieto Corporation
+ * Copyright 2014, Michal Labedzki for Tieto Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "wtap-int.h"
+#include "file_wrappers.h"
+
+#include "logcat_text.h"
+#include "logcat.h"
+
+struct dumper_t {
+ int type;
+};
+
+static int logcat_text_brief_file_type_subtype = -1;
+static int logcat_text_process_file_type_subtype = -1;
+static int logcat_text_tag_file_type_subtype = -1;
+static int logcat_text_thread_file_type_subtype = -1;
+static int logcat_text_time_file_type_subtype = -1;
+static int logcat_text_threadtime_file_type_subtype = -1;
+static int logcat_text_long_file_type_subtype = -1;
+
+void register_logcat_text(void);
+
+/* 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)
+{
+ const struct logger_entry *log_entry;
+ const struct logger_entry_v2 *log_entry_v2;
+ gint version;
+ const guint8 *msg_payload = NULL;
+ guint8 *msg_part;
+ guint8 *msg_end;
+ guint16 msg_len;
+
+ log_entry = (const struct logger_entry *)(const void *) pd;
+ log_entry_v2 = (const struct logger_entry_v2 *)(const void *) 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 = (const guint8 *) (log_entry + 1);
+ } else if (version == 2) {
+ /* v2 is 4 bytes longer */
+ msg_payload = (const guint8 *) (log_entry_v2 + 1);
+ 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;
+ struct tm *tm;
+
+ datetime = (time_t) seconds;
+
+ switch (dumper->type) {
+ case WTAP_ENCAP_LOGCAT_BRIEF:
+ return ws_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 ws_strdup_printf("%c(%5i) %s (%s)\n",
+ priority, pid, log, "");
+ case WTAP_ENCAP_LOGCAT_TAG:
+ return ws_strdup_printf("%c/%-8s: %s\n",
+ priority, tag, log);
+ case WTAP_ENCAP_LOGCAT_THREAD:
+ return ws_strdup_printf("%c(%5i:%5i) %s\n",
+ priority, pid, tid, log);
+ case WTAP_ENCAP_LOGCAT_TIME:
+ tm = gmtime(&datetime);
+ if (tm != NULL) {
+ strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
+ tm);
+ return ws_strdup_printf("%s.%03i %c/%-8s(%5i): %s\n",
+ time_buffer, milliseconds, priority, tag, pid, log);
+ } else {
+ return ws_strdup_printf("Not representable %c/%-8s(%5i): %s\n",
+ priority, tag, pid, log);
+ }
+ case WTAP_ENCAP_LOGCAT_THREADTIME:
+ tm = gmtime(&datetime);
+ if (tm != NULL) {
+ strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
+ tm);
+ return ws_strdup_printf("%s.%03i %5i %5i %c %-8s: %s\n",
+ time_buffer, milliseconds, pid, tid, priority, tag, log);
+ } else {
+ return ws_strdup_printf("Not representable %5i %5i %c %-8s: %s\n",
+ pid, tid, priority, tag, log);
+ }
+ case WTAP_ENCAP_LOGCAT_LONG:
+ tm = gmtime(&datetime);
+ if (tm != NULL) {
+ strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
+ tm);
+ return ws_strdup_printf("[ %s.%03i %5i:%5i %c/%-8s ]\n%s\n\n",
+ time_buffer, milliseconds, pid, tid, priority, tag, log);
+ } else {
+ return ws_strdup_printf("[ Not representable %5i:%5i %c/%-8s ]\n%s\n\n",
+ pid, tid, priority, tag, log);
+ }
+ default:
+ return NULL;
+ }
+
+}
+
+static void get_time(gchar *string, wtap_rec *rec) {
+ gint ms;
+ struct tm date;
+ time_t seconds;
+
+ if (6 == sscanf(string, "%d-%d %d:%d:%d.%d", &date.tm_mon, &date.tm_mday, &date.tm_hour,
+ &date.tm_min, &date.tm_sec, &ms)) {
+ date.tm_year = 70;
+ date.tm_mon -= 1;
+ date.tm_isdst = -1;
+ seconds = mktime(&date);
+ rec->ts.secs = seconds;
+ rec->ts.nsecs = (int) (ms * 1e6);
+ rec->presence_flags = WTAP_HAS_TS;
+ } else {
+ rec->presence_flags = 0;
+ rec->ts.secs = (time_t) 0;
+ rec->ts.nsecs = 0;
+ }
+}
+
+static gboolean logcat_text_read_packet(FILE_T fh, wtap_rec *rec,
+ Buffer *buf, gint file_type) {
+ gint8 *pd;
+ gchar *cbuff;
+ gchar *ret = NULL;
+
+ cbuff = (gchar*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
+ do {
+ ret = file_gets(cbuff, WTAP_MAX_PACKET_SIZE_STANDARD, fh);
+ } while (NULL != ret && 3 > strlen(cbuff) && !file_eof(fh));
+
+ if (NULL == ret || 3 > strlen(cbuff)) {
+ g_free(cbuff);
+ return FALSE;
+ }
+
+ if (logcat_text_long_file_type_subtype == file_type &&
+ !g_regex_match_simple(SPECIAL_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW), G_REGEX_MATCH_NOTEMPTY)) {
+ gint64 file_off = 0;
+ gchar *lbuff;
+ int err;
+ gchar *ret2 = NULL;
+
+ lbuff = (gchar*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
+ file_off = file_tell(fh);
+ ret2 = file_gets(lbuff,WTAP_MAX_PACKET_SIZE_STANDARD, fh);
+ while (NULL != ret2 && 2 < strlen(lbuff) && !file_eof(fh)) {
+ (void) g_strlcat(cbuff,lbuff,WTAP_MAX_PACKET_SIZE_STANDARD);
+ file_off = file_tell(fh);
+ ret2 = file_gets(lbuff,WTAP_MAX_PACKET_SIZE_STANDARD, fh);
+ }
+
+ if(NULL == ret2 || 2 < strlen(lbuff)) {
+ g_free(cbuff);
+ g_free(lbuff);
+ return FALSE;
+ }
+
+ file_seek(fh,file_off,SEEK_SET,&err);
+ g_free(lbuff);
+ }
+
+ rec->rec_type = REC_TYPE_PACKET;
+ rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
+ rec->rec_header.packet_header.caplen = (guint32)strlen(cbuff);
+ rec->rec_header.packet_header.len = rec->rec_header.packet_header.caplen;
+
+ ws_buffer_assure_space(buf, rec->rec_header.packet_header.caplen + 1);
+ pd = ws_buffer_start_ptr(buf);
+ if ((logcat_text_time_file_type_subtype == file_type
+ || logcat_text_threadtime_file_type_subtype == file_type
+ || logcat_text_long_file_type_subtype == file_type)
+ && '-' != cbuff[0]) { /* the last part filters out the -- beginning of... lines */
+ if (logcat_text_long_file_type_subtype == file_type) {
+ get_time(cbuff+2, rec);
+ } else {
+ get_time(cbuff, rec);
+ }
+ } else {
+ rec->presence_flags = 0;
+ rec->ts.secs = (time_t) 0;
+ rec->ts.nsecs = 0;
+ }
+ memcpy(pd, cbuff, rec->rec_header.packet_header.caplen + 1);
+ g_free(cbuff);
+ return TRUE;
+}
+
+static gboolean logcat_text_read(wtap *wth, wtap_rec *rec,
+ Buffer *buf, int *err _U_ , gchar **err_info _U_, gint64 *data_offset) {
+ *data_offset = file_tell(wth->fh);
+
+ return logcat_text_read_packet(wth->fh, rec, buf, wth->file_type_subtype);
+}
+
+static gboolean logcat_text_seek_read(wtap *wth, gint64 seek_off,
+ wtap_rec *rec, Buffer *buf, int *err, 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, rec, buf,
+ wth->file_type_subtype)) {
+ if (*err == 0)
+ *err = WTAP_ERR_SHORT_READ;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+wtap_open_return_val logcat_text_open(wtap *wth, int *err, gchar **err_info _U_) {
+ gchar *cbuff;
+ gchar *ret = NULL;
+
+ if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
+ return WTAP_OPEN_ERROR;
+
+ cbuff = (gchar*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
+ do {
+ ret = file_gets(cbuff, WTAP_MAX_PACKET_SIZE_STANDARD, wth->fh);
+ } while (NULL != ret && !file_eof(wth->fh)
+ && ((3 > strlen(cbuff))
+ || g_regex_match_simple(SPECIAL_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
+ G_REGEX_MATCH_NOTEMPTY)));
+
+ if (g_regex_match_simple(BRIEF_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = logcat_text_brief_file_type_subtype;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_BRIEF;
+ } else if (g_regex_match_simple(TAG_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = logcat_text_tag_file_type_subtype;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_TAG;
+ } else if (g_regex_match_simple(PROCESS_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = logcat_text_process_file_type_subtype;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_PROCESS;
+ } else if (g_regex_match_simple(TIME_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = logcat_text_time_file_type_subtype;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_TIME;
+ } else if (g_regex_match_simple(THREAD_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = logcat_text_thread_file_type_subtype;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_THREAD;
+ } else if (g_regex_match_simple(THREADTIME_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = logcat_text_threadtime_file_type_subtype;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_THREADTIME;
+ } else if (g_regex_match_simple(LONG_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
+ G_REGEX_MATCH_NOTEMPTY)) {
+ wth->file_type_subtype = logcat_text_long_file_type_subtype;
+ wth->file_encap = WTAP_ENCAP_LOGCAT_LONG;
+ } else {
+ g_free(cbuff);
+ return WTAP_OPEN_NOT_MINE;
+ }
+
+ if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
+ g_free(cbuff);
+ return WTAP_OPEN_ERROR;
+ }
+ wth->snapshot_length = 0;
+
+ wth->subtype_read = logcat_text_read;
+ wth->subtype_seek_read = logcat_text_seek_read;
+ wth->file_tsprec = WTAP_TSPREC_USEC;
+ g_free(cbuff);
+ return WTAP_OPEN_MINE;
+}
+
+static 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:
+ case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
+ return 0;
+ default:
+ return WTAP_ERR_UNWRITABLE_ENCAP;
+ }
+}
+
+static 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:
+ case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
+ return 0;
+ default:
+ return WTAP_ERR_UNWRITABLE_ENCAP;
+ }
+}
+
+static 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:
+ case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
+ return 0;
+ default:
+ return WTAP_ERR_UNWRITABLE_ENCAP;
+ }
+}
+
+static 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:
+ case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
+ return 0;
+ default:
+ return WTAP_ERR_UNWRITABLE_ENCAP;
+ }
+}
+
+static 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:
+ case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
+ return 0;
+ default:
+ return WTAP_ERR_UNWRITABLE_ENCAP;
+ }
+}
+
+static 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:
+ case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
+ return 0;
+ default:
+ return WTAP_ERR_UNWRITABLE_ENCAP;
+ }
+}
+
+static 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:
+ case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
+ return 0;
+ default:
+ return WTAP_ERR_UNWRITABLE_ENCAP;
+ }
+}
+
+static gboolean logcat_text_dump_text(wtap_dumper *wdh,
+ const wtap_rec *rec,
+ const guint8 *pd, int *err, gchar **err_info)
+{
+ 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 guint8 *msg_payload = NULL;
+ 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 (rec->rec_type != REC_TYPE_PACKET) {
+ *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
+ return FALSE;
+ }
+
+ /*
+ * Make sure this packet doesn't have a link-layer type that
+ * differs from the one for the file.
+ */
+ if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) {
+ *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+ return FALSE;
+ }
+
+ switch (wdh->file_encap) {
+ case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
+ {
+ gint skipped_length;
+
+ skipped_length = logcat_exported_pdu_length(pd);
+ pd += skipped_length;
+
+ if (!wtap_dump_file_write(wdh, (const gchar*) pd, rec->rec_header.packet_header.caplen - skipped_length, err)) {
+ return FALSE;
+ }
+ }
+ break;
+ case WTAP_ENCAP_LOGCAT:
+ /* Skip EXPORTED_PDU*/
+ if (wdh->file_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 = &rec->rec_header.packet_header.pseudo_header;
+
+ logcat_version = pseudo_header->logcat.version;
+ }
+
+ log_entry = (const struct logger_entry *)(const void *) pd;
+ log_entry_v2 = (const struct logger_entry_v2 *)(const void *) 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) {
+ msg_payload = (const guint8 *) (log_entry + 1);
+
+ priority = get_priority(msg_payload[0]);
+ tag = msg_payload + 1;
+ msg_pre_skip = 1 + (gint) strlen(tag) + 1;
+ msg_begin = msg_payload + msg_pre_skip;
+ } else if (logcat_version == 2) {
+ msg_payload = (const guint8 *) (log_entry_v2 + 1);
+
+ priority = get_priority(msg_payload[0]);
+ tag = msg_payload + 1;
+ msg_pre_skip = 1 + (gint) strlen(tag) + 1;
+ msg_begin = msg_payload + msg_pre_skip;
+ } else {
+ *err = WTAP_ERR_UNWRITABLE_REC_DATA;
+ *err_info = ws_strdup_printf("logcat: version %d isn't supported",
+ logcat_version);
+ 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;
+ }
+ } 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->file_encap) {
+ if (!wtap_dump_file_write(wdh, (const gchar*) pd, rec->rec_header.packet_header.caplen, err)) {
+ return FALSE;
+ }
+ } else {
+ *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean logcat_text_dump_open(wtap_dumper *wdh, guint dump_type) {
+ struct dumper_t *dumper;
+
+ dumper = g_new(struct dumper_t, 1);
+ dumper->type = dump_type;
+
+ wdh->priv = dumper;
+ wdh->subtype_write = logcat_text_dump_text;
+
+ return TRUE;
+}
+
+static gboolean logcat_text_brief_dump_open(wtap_dumper *wdh, int *err _U_, gchar **err_info _U_) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_BRIEF);
+}
+
+static gboolean logcat_text_process_dump_open(wtap_dumper *wdh, int *err _U_, gchar **err_info _U_) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_PROCESS);
+}
+
+static gboolean logcat_text_tag_dump_open(wtap_dumper *wdh, int *err _U_, gchar **err_info _U_) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_TAG);
+}
+
+static gboolean logcat_text_time_dump_open(wtap_dumper *wdh, int *err _U_, gchar **err_info _U_) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_TIME);
+}
+
+static gboolean logcat_text_thread_dump_open(wtap_dumper *wdh, int *err _U_, gchar **err_info _U_) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_THREAD);
+}
+
+static gboolean logcat_text_threadtime_dump_open(wtap_dumper *wdh, int *err _U_, gchar **err_info _U_) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_THREADTIME);
+}
+
+static gboolean logcat_text_long_dump_open(wtap_dumper *wdh, int *err _U_, gchar **err_info _U_) {
+ return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_LONG);
+}
+
+static const struct supported_block_type logcat_text_brief_blocks_supported[] = {
+ /*
+ * We support packet blocks, with no comments or other options.
+ */
+ { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
+};
+
+static const struct file_type_subtype_info logcat_text_brief_info = {
+ "Android Logcat Brief text format", "logcat-brief", NULL, NULL,
+ FALSE, BLOCKS_SUPPORTED(logcat_text_brief_blocks_supported),
+ logcat_text_brief_dump_can_write_encap, logcat_text_brief_dump_open, NULL
+};
+
+static const struct supported_block_type logcat_text_process_blocks_supported[] = {
+ /*
+ * We support packet blocks, with no comments or other options.
+ */
+ { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
+};
+
+static const struct file_type_subtype_info logcat_text_process_info = {
+ "Android Logcat Process text format", "logcat-process", NULL, NULL,
+ FALSE, BLOCKS_SUPPORTED(logcat_text_process_blocks_supported),
+ logcat_text_process_dump_can_write_encap, logcat_text_process_dump_open, NULL
+};
+
+static const struct supported_block_type logcat_text_tag_blocks_supported[] = {
+ /*
+ * We support packet blocks, with no comments or other options.
+ */
+ { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
+};
+
+static const struct file_type_subtype_info logcat_text_tag_info = {
+ "Android Logcat Tag text format", "logcat-tag", NULL, NULL,
+ FALSE, BLOCKS_SUPPORTED(logcat_text_tag_blocks_supported),
+ logcat_text_tag_dump_can_write_encap, logcat_text_tag_dump_open, NULL
+};
+
+static const struct supported_block_type logcat_text_thread_blocks_supported[] = {
+ /*
+ * We support packet blocks, with no comments or other options.
+ */
+ { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
+};
+
+static const struct file_type_subtype_info logcat_text_thread_info = {
+ "Android Logcat Thread text format", "logcat-thread", NULL, NULL,
+ FALSE, BLOCKS_SUPPORTED(logcat_text_thread_blocks_supported),
+ logcat_text_thread_dump_can_write_encap, logcat_text_thread_dump_open, NULL
+};
+
+static const struct supported_block_type logcat_text_time_blocks_supported[] = {
+ /*
+ * We support packet blocks, with no comments or other options.
+ */
+ { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
+};
+
+static const struct file_type_subtype_info logcat_text_time_info = {
+ "Android Logcat Time text format", "logcat-time", NULL, NULL,
+ FALSE, BLOCKS_SUPPORTED(logcat_text_time_blocks_supported),
+ logcat_text_time_dump_can_write_encap, logcat_text_time_dump_open, NULL
+};
+
+static const struct supported_block_type logcat_text_threadtime_blocks_supported[] = {
+ /*
+ * We support packet blocks, with no comments or other options.
+ */
+ { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
+};
+
+static const struct file_type_subtype_info logcat_text_threadtime_info = {
+ "Android Logcat Threadtime text format", "logcat-threadtime", NULL, NULL,
+ FALSE, BLOCKS_SUPPORTED(logcat_text_threadtime_blocks_supported),
+ logcat_text_threadtime_dump_can_write_encap, logcat_text_threadtime_dump_open, NULL
+};
+
+static const struct supported_block_type logcat_text_long_blocks_supported[] = {
+ /*
+ * We support packet blocks, with no comments or other options.
+ */
+ { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
+};
+
+static const struct file_type_subtype_info logcat_text_long_info = {
+ "Android Logcat Long text format", "logcat-long", NULL, NULL,
+ FALSE, BLOCKS_SUPPORTED(logcat_text_long_blocks_supported),
+ logcat_text_long_dump_can_write_encap, logcat_text_long_dump_open, NULL
+};
+
+void register_logcat_text(void)
+{
+ logcat_text_brief_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_brief_info);
+ logcat_text_process_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_process_info);
+ logcat_text_tag_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_tag_info);
+ logcat_text_thread_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_thread_info);
+ logcat_text_time_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_time_info);
+ logcat_text_threadtime_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_threadtime_info);
+ logcat_text_long_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_long_info);
+
+ /*
+ * Register names for backwards compatibility with the
+ * wtap_filetypes table in Lua.
+ */
+ wtap_register_backwards_compatibility_lua_name("LOGCAT_BRIEF",
+ logcat_text_brief_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("LOGCAT_PROCESS",
+ logcat_text_process_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("LOGCAT_TAG",
+ logcat_text_tag_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("LOGCAT_THREAD",
+ logcat_text_thread_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("LOGCAT_TIME",
+ logcat_text_time_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("LOGCAT_THREADTIME",
+ logcat_text_threadtime_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("LOGCAT_LONG",
+ logcat_text_long_file_type_subtype);
+}
+
+/*
+ * Editor modelines - https://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:
+ */