3 * Copyright 2014, Michal Labedzki for Tieto Corporation
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "file_wrappers.h"
43 enum dump_type_t type;
46 static gchar get_priority(const guint8 *priority) {
47 static gchar priorities[] = "??VDIWEFS";
49 if (*priority >= (guint8) sizeof(priorities))
52 return priorities[(int) *priority];
55 static gchar *logcat_log(const struct dumper_t *dumper, guint32 seconds,
56 gint microseconds, gint pid, gint tid, gchar priority, const gchar *tag,
59 gchar time_buffer[15];
62 datetime = (time_t) seconds;
64 switch (dumper->type) {
66 return g_strdup_printf("%c/%s(%5i): %s\n",
67 priority, tag, pid, log);
69 return g_strdup_printf("%c(%5i) %s (%s)\n",
70 priority, pid, log, tag);
72 return g_strdup_printf("%c/%s: %s\n",
75 return g_strdup_printf("%c(%5i:%5i) %s\n",
76 priority, pid, tid, log);
78 strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
80 return g_strdup_printf("%s.%03i %c/%s(%5i): %s\n",
81 time_buffer, microseconds, priority, tag, pid, log);
83 strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
85 return g_strdup_printf("%s.%03i %5i:%5i %c %s: %s\n",
86 time_buffer, microseconds, pid, tid, priority, tag, log);
88 strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
90 return g_strdup_printf("[ %s.%03i %5i:%5i %c/%s ]\n%s\n\n",
91 time_buffer, microseconds, pid, tid, priority, tag, log);
98 static gint detect_version(wtap *wth, int *err, gchar **err_info)
101 guint16 payload_length;
102 guint16 try_header_size;
109 file_offset = file_tell(wth->fh);
111 bytes_read = file_read(&tmp, 2, wth->fh);
112 if (bytes_read != 2) {
113 *err = file_error(wth->fh, err_info);
114 if (*err == 0 && bytes_read != 0)
115 *err = WTAP_ERR_SHORT_READ;
118 payload_length = pletoh16(&tmp);
120 bytes_read = file_read(&tmp, 2, wth->fh);
121 if (bytes_read != 2) {
122 *err = file_error(wth->fh, err_info);
123 if (*err == 0 && bytes_read != 0)
124 *err = WTAP_ERR_SHORT_READ;
127 try_header_size = pletoh16(&tmp);
129 buffer = (guint8 *) g_malloc(5 * 4 + payload_length);
130 bytes_read = file_read(buffer, 5 * 4 + payload_length, wth->fh);
131 if (bytes_read != 5 * 4 + payload_length) {
132 if (bytes_read != 4 * 4 + payload_length) {
133 *err = file_error(wth->fh, err_info);
134 if (*err == 0 && bytes_read != 0)
135 *err = WTAP_ERR_SHORT_READ;
141 if (try_header_size == 24) {
142 tag_length = (guint32)strlen(buffer + 5 * 4 + 1) + 1;
143 log_length = (guint32)strlen(buffer + 5 * 4 + 1 + tag_length) + 1;
144 if (payload_length == 1 + tag_length + log_length) {
150 tag_length = (guint32)strlen(buffer + 4 * 4 + 1) + 1;
151 log_length = (guint32)strlen(buffer + 4 * 4 + 1 + tag_length) + 1;
152 if (payload_length == 1 + tag_length + log_length) {
153 if (file_seek(wth->fh, file_offset + 4 * 4 + 1 + tag_length + log_length, SEEK_SET, err) == -1) {
165 static gboolean logcat_read_packet(struct logcat_phdr *logcat, FILE_T fh,
166 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
170 guint16 payload_length;
174 bytes_read = file_read(&tmp, 2, fh);
175 if (bytes_read != 2) {
176 *err = file_error(fh, err_info);
177 if (*err == 0 && bytes_read != 0)
178 *err = WTAP_ERR_SHORT_READ;
181 payload_length = pletoh16(tmp);
183 if (logcat->version == 1) {
184 packet_size = 5 * 4 + payload_length;
185 } else if (logcat->version == 2) {
186 packet_size = 6 * 4 + payload_length;
191 buffer_assure_space(buf, packet_size);
192 pd = buffer_start_ptr(buf);
194 /* Copy the first two bytes of the packet. */
197 /* Read the rest of the packet. */
198 bytes_read = file_read(pd + 2, packet_size - 2, fh);
199 if (bytes_read != packet_size - 2) {
200 *err = file_error(fh, err_info);
202 *err = WTAP_ERR_SHORT_READ;
206 phdr->presence_flags = WTAP_HAS_TS;
207 phdr->ts.secs = (time_t) pletoh32(pd + 12);
208 phdr->ts.nsecs = (int) pletoh32(pd + 16);
209 phdr->caplen = packet_size;
210 phdr->len = packet_size;
212 phdr->pseudo_header.logcat.version = logcat->version;
217 static gboolean logcat_read(wtap *wth, int *err, gchar **err_info,
220 *data_offset = file_tell(wth->fh);
222 return logcat_read_packet((struct logcat_phdr *) wth->priv, wth->fh,
223 &wth->phdr, wth->frame_buffer, err, err_info);
226 static gboolean logcat_seek_read(wtap *wth, gint64 seek_off,
227 struct wtap_pkthdr *phdr, Buffer *buf,
228 int *err, gchar **err_info)
230 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
233 if (!logcat_read_packet((struct logcat_phdr *) wth->priv, wth->random_fh,
234 phdr, buf, err, err_info)) {
236 *err = WTAP_ERR_SHORT_READ;
242 int logcat_open(wtap *wth, int *err, gchar **err_info _U_)
245 gchar *local_err_info;
248 struct logcat_phdr *logcat;
250 /* check first 3 packets (or 2 or 1 if EOF) versions to check file format is correct */
251 version = detect_version(wth, &local_err, &local_err_info);
255 tmp_version = detect_version(wth, &local_err, &local_err_info);
256 if (tmp_version < 0 && !file_eof(wth->fh)) {
258 } else if (tmp_version > 0) {
259 if (tmp_version != version)
262 tmp_version = detect_version(wth, &local_err, &local_err_info);
263 if (tmp_version != version && !file_eof(wth->fh))
267 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
270 logcat = (struct logcat_phdr *) g_malloc(sizeof(struct logcat_phdr));
271 logcat->version = version;
275 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT;
276 wth->file_encap = WTAP_ENCAP_LOGCAT;
277 wth->snapshot_length = 0;
279 wth->subtype_read = logcat_read;
280 wth->subtype_seek_read = logcat_seek_read;
281 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
286 int logcat_dump_can_write_encap(int encap)
288 if (encap == WTAP_ENCAP_PER_PACKET)
289 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
291 if (encap != WTAP_ENCAP_LOGCAT)
292 return WTAP_ERR_UNSUPPORTED_ENCAP;
297 static gboolean logcat_binary_dump(wtap_dumper *wdh,
298 const struct wtap_pkthdr *phdr,
299 const guint8 *pd, int *err)
301 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
304 wdh->bytes_dumped += phdr->caplen;
309 gboolean logcat_binary_dump_open(wtap_dumper *wdh, int *err)
311 wdh->subtype_write = logcat_binary_dump;
312 wdh->subtype_close = NULL;
314 switch (wdh->file_type_subtype) {
315 case WTAP_FILE_TYPE_SUBTYPE_LOGCAT:
316 wdh->tsprecision = WTAP_FILE_TSPREC_USEC;
320 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
327 static gboolean logcat_dump_text(wtap_dumper *wdh,
328 const struct wtap_pkthdr *phdr,
329 const guint8 *pd, int *err)
339 const gchar *str_begin;
340 const gchar *str_end;
341 const guint32 *datetime;
342 const guint32 *nanoseconds;
343 const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
344 const struct dumper_t *dumper = (const struct dumper_t *) wdh->priv;
346 if (pseudo_header->logcat.version == 1) {
347 pid = (const gint *) (pd + 4);
348 tid = (const gint *) (pd + 2 * 4);
349 datetime = (const guint32 *) (pd + 3 * 4);
350 nanoseconds = (const guint32 *) (pd + 4 * 4);
351 priority = get_priority((const guint8 *) (pd + 5 * 4));
352 tag = (const gchar *) (pd + 5 * 4 + 1);
353 log = tag + strlen(tag) + 1;
354 } else if (pseudo_header->logcat.version == 2) {
355 pid = (const gint *) (pd + 4);
356 tid = (const gint *) (pd + 2 * 4);
357 datetime = (const guint32 *) (pd + 3 * 4);
358 nanoseconds = (const guint32 *) (pd + 4 * 4);
359 priority = get_priority((const guint8 *) (pd + 6 * 4));
360 tag = (const char *) (pd + 6 * 4 + 1);
361 log = tag + strlen(tag) + 1;
363 *err = WTAP_ERR_UNSUPPORTED;
367 str_begin = str_end = log;
368 while (dumper->type != DUMP_LONG && (str_end = strchr(str_begin, '\n'))) {
369 log_part = (gchar *) g_malloc(str_end - str_begin + 1);
370 g_strlcpy(log_part, str_begin, str_end - str_begin);
371 log_part[str_end - str_begin] = '\0';
372 str_begin = str_end + 1;
374 buf = logcat_log(dumper, *datetime, *nanoseconds / 1000000, *pid, *tid,
375 priority, tag, log_part);
381 length = (guint32)strlen(buf);
383 if (!wtap_dump_file_write(wdh, buf, length, err)) {
388 wdh->bytes_dumped += length;
393 if (*str_begin != '\0') {
394 log_part = (gchar *) g_malloc(strlen(str_begin) + 1);
395 g_strlcpy(log_part, str_begin, strlen(str_begin));
396 log_part[strlen(str_begin)] = '\0';
398 buf = logcat_log(dumper, *datetime, *nanoseconds / 1000000, *pid, *tid,
399 priority, tag, log_part);
405 length = (guint32)strlen(buf);
407 if (!wtap_dump_file_write(wdh, buf, length, err)) {
412 wdh->bytes_dumped += length;
419 gboolean logcat_text_brief_dump_open(wtap_dumper *wdh, int *err _U_)
421 struct dumper_t *dumper;
423 dumper = (struct dumper_t *) g_malloc(sizeof(struct dumper_t));
424 dumper->type = DUMP_BRIEF;
427 wdh->subtype_write = logcat_dump_text;
428 wdh->subtype_close = NULL;
433 gboolean logcat_text_process_dump_open(wtap_dumper *wdh, int *err _U_)
435 struct dumper_t *dumper;
437 dumper = (struct dumper_t *) g_malloc(sizeof(struct dumper_t));
438 dumper->type = DUMP_PROCESS;
441 wdh->subtype_write = logcat_dump_text;
442 wdh->subtype_close = NULL;
447 gboolean logcat_text_tag_dump_open(wtap_dumper *wdh, int *err _U_)
449 struct dumper_t *dumper;
451 dumper = (struct dumper_t *) g_malloc(sizeof(struct dumper_t));
452 dumper->type = DUMP_TAG;
455 wdh->subtype_write = logcat_dump_text;
456 wdh->subtype_close = NULL;
461 gboolean logcat_text_time_dump_open(wtap_dumper *wdh, int *err _U_)
463 struct dumper_t *dumper;
465 dumper = (struct dumper_t *) g_malloc(sizeof(struct dumper_t));
466 dumper->type = DUMP_TIME;
469 wdh->subtype_write = logcat_dump_text;
470 wdh->subtype_close = NULL;
475 gboolean logcat_text_thread_dump_open(wtap_dumper *wdh, int *err _U_)
477 struct dumper_t *dumper;
479 dumper = (struct dumper_t *) g_malloc(sizeof(struct dumper_t));
480 dumper->type = DUMP_THREAD;
483 wdh->subtype_write = logcat_dump_text;
484 wdh->subtype_close = NULL;
489 gboolean logcat_text_threadtime_dump_open(wtap_dumper *wdh, int *err _U_)
491 struct dumper_t *dumper;
493 dumper = (struct dumper_t *) g_malloc(sizeof(struct dumper_t));
494 dumper->type = DUMP_THREADTIME;
497 wdh->subtype_write = logcat_dump_text;
498 wdh->subtype_close = NULL;
503 gboolean logcat_text_long_dump_open(wtap_dumper *wdh, int *err _U_)
505 struct dumper_t *dumper;
507 dumper = (struct dumper_t *) g_malloc(sizeof(struct dumper_t));
508 dumper->type = DUMP_LONG;
511 wdh->subtype_write = logcat_dump_text;
512 wdh->subtype_close = NULL;
518 * Editor modelines - http://www.wireshark.org/tools/modelines.html
523 * indent-tabs-mode: nil
526 * vi: set shiftwidth=4 tabstop=8 expandtab:
527 * :indentSize=4:tabSize=8:noTabs=true: