TEST(liblog, convertPrintable_validutf8) { auto input = u8"┬врд╣тВмЁРНИ"; auto output_size = convertPrintable(nullptr, input, strlen(input)); EXPECT_EQ(output_size, strlen(input)); char output[output_size]; output_size = convertPrintable(output, input, strlen(input)); EXPECT_EQ(output_size, strlen(input)); EXPECT_STREQ(input, output); }
TEST(liblog, convertPrintable_ascii) { auto input = "easy string, output same"; auto output_size = convertPrintable(nullptr, input, strlen(input)); EXPECT_EQ(output_size, strlen(input)); char output[output_size]; output_size = convertPrintable(output, input, strlen(input)); EXPECT_EQ(output_size, strlen(input)); EXPECT_STREQ(input, output); }
TEST(liblog, convertPrintable_invalidutf8) { auto input = "\x80\xC2\x01\xE0\xA4\x06\xE0\x06\xF0\x90\x8D\x06\xF0\x90\x06\xF0\x0E"; auto expected_output = "\\x80\\xC2\\x01\\xE0\\xA4\\x06\\xE0\\x06\\xF0\\x90\\x8D\\x06\\xF0\\x90\\x06\\xF0\\x0E"; auto output_size = convertPrintable(nullptr, input, strlen(input)); EXPECT_EQ(output_size, strlen(expected_output)); char output[output_size]; output_size = convertPrintable(output, input, strlen(input)); EXPECT_EQ(output_size, strlen(expected_output)); EXPECT_STREQ(expected_output, output); }
TEST(liblog, convertPrintable_escapes) { // Note that \t is not escaped. auto input = "escape\a\b\t\v\f\r\\"; auto expected_output = "escape\\a\\b\t\\v\\f\\r\\\\"; auto output_size = convertPrintable(nullptr, input, strlen(input)); EXPECT_EQ(output_size, strlen(expected_output)); char output[output_size]; output_size = convertPrintable(output, input, strlen(input)); EXPECT_EQ(output_size, strlen(expected_output)); EXPECT_STREQ(expected_output, output); }
TEST(liblog, convertPrintable_mixed) { auto input = u8"\x80\xC2┬врд╣тВмЁРНИ\x01\xE0\xA4\x06┬врд╣тВмЁРНИ\xE0\x06\a\b\xF0\x90┬врд╣тВмЁРНИ\x8D\x06\xF0\t\t\x90\x06\xF0\x0E"; auto expected_output = u8"\\x80\\xC2┬врд╣тВмЁРНИ\\x01\\xE0\\xA4\\x06┬врд╣тВмЁРНИ\\xE0\\x06\\a\\b\\xF0\\x90┬врд╣тВмЁРНИ\\x8D\\x06\\xF0\t\t" u8"\\x90\\x06\\xF0\\x0E"; auto output_size = convertPrintable(nullptr, input, strlen(input)); EXPECT_EQ(output_size, strlen(expected_output)); char output[output_size]; output_size = convertPrintable(output, input, strlen(input)); EXPECT_EQ(output_size, strlen(expected_output)); EXPECT_STREQ(expected_output, output); }
char *android_log_formatLogLine ( AndroidLogFormat *p_format, char *defaultBuffer, size_t defaultBufferSize, const AndroidLogEntry *entry, size_t *p_outLength) { #if !defined(_WIN32) struct tm tmBuf; #endif struct tm* ptm; char timeBuf[64]; /* good margin, 23+nul for msec, 26+nul for usec */ char prefixBuf[128], suffixBuf[128]; char priChar; int prefixSuffixIsHeaderFooter = 0; char * ret = NULL; priChar = filterPriToChar(entry->priority); size_t prefixLen = 0, suffixLen = 0; size_t len; /* * Get the current date/time in pretty form * * It's often useful when examining a log with "less" to jump to * a specific point in the file by searching for the date/time stamp. * For this reason it's very annoying to have regexp meta characters * in the time stamp. Don't use forward slashes, parenthesis, * brackets, asterisks, or other special chars here. * * The caller may have affected the timezone environment, this is * expected to be sensitive to that. */ #if !defined(_WIN32) ptm = localtime_r(&(entry->tv_sec), &tmBuf); #else ptm = localtime(&(entry->tv_sec)); #endif strftime(timeBuf, sizeof(timeBuf), &"%Y-%m-%d %H:%M:%S"[p_format->year_output ? 0 : 3], ptm); len = strlen(timeBuf); if (p_format->usec_time_output) { len += snprintf(timeBuf + len, sizeof(timeBuf) - len, ".%06ld", entry->tv_nsec / 1000); } else { len += snprintf(timeBuf + len, sizeof(timeBuf) - len, ".%03ld", entry->tv_nsec / 1000000); } if (p_format->zone_output) { strftime(timeBuf + len, sizeof(timeBuf) - len, " %z", ptm); } /* * Construct a buffer containing the log header and log message. */ if (p_format->colored_output) { prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[38;5;%dm", colorFromPri(entry->priority)); prefixLen = MIN(prefixLen, sizeof(prefixBuf)); suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), "\x1B[0m"); suffixLen = MIN(suffixLen, sizeof(suffixBuf)); } switch (p_format->format) { case FORMAT_TAG: len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c/%-8s: ", priChar, entry->tag); strcpy(suffixBuf + suffixLen, "\n"); ++suffixLen; break; case FORMAT_PROCESS: len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen, " (%s)\n", entry->tag); suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen); len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c(%5d) ", priChar, entry->pid); break; case FORMAT_THREAD: len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c(%5d:%5d) ", priChar, entry->pid, entry->tid); strcpy(suffixBuf + suffixLen, "\n"); ++suffixLen; break; case FORMAT_RAW: prefixBuf[prefixLen] = 0; len = 0; strcpy(suffixBuf + suffixLen, "\n"); ++suffixLen; break; case FORMAT_TIME: len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%s %c/%-8s(%5d): ", timeBuf, priChar, entry->tag, entry->pid); strcpy(suffixBuf + suffixLen, "\n"); ++suffixLen; break; case FORMAT_THREADTIME: len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%s %5d %5d %c %-8s: ", timeBuf, entry->pid, entry->tid, priChar, entry->tag); strcpy(suffixBuf + suffixLen, "\n"); ++suffixLen; break; case FORMAT_LONG: len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "[ %s %5d:%5d %c/%-8s ]\n", timeBuf, entry->pid, entry->tid, priChar, entry->tag); strcpy(suffixBuf + suffixLen, "\n\n"); suffixLen += 2; prefixSuffixIsHeaderFooter = 1; break; case FORMAT_BRIEF: default: len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid); strcpy(suffixBuf + suffixLen, "\n"); ++suffixLen; break; } /* snprintf has a weird return value. It returns what would have been * written given a large enough buffer. In the case that the prefix is * longer then our buffer(128), it messes up the calculations below * possibly causing heap corruption. To avoid this we double check and * set the length at the maximum (size minus null byte) */ prefixLen += MIN(len, sizeof(prefixBuf) - prefixLen); suffixLen = MIN(suffixLen, sizeof(suffixBuf)); /* the following code is tragically unreadable */ size_t numLines; char *p; size_t bufferSize; const char *pm; if (prefixSuffixIsHeaderFooter) { /* we're just wrapping message with a header/footer */ numLines = 1; } else { pm = entry->message; numLines = 0; /* * The line-end finding here must match the line-end finding * in for ( ... numLines...) loop below */ while (pm < (entry->message + entry->messageLen)) { if (*pm++ == '\n') numLines++; } /* plus one line for anything not newline-terminated at the end */ if (pm > entry->message && *(pm-1) != '\n') numLines++; } /* * this is an upper bound--newlines in message may be counted * extraneously */ bufferSize = (numLines * (prefixLen + suffixLen)) + 1; if (p_format->printable_output) { /* Calculate extra length to convert non-printable to printable */ bufferSize += convertPrintable(NULL, entry->message, entry->messageLen); } else { bufferSize += entry->messageLen; } if (defaultBufferSize >= bufferSize) { ret = defaultBuffer; } else { ret = (char *)malloc(bufferSize); if (ret == NULL) { return ret; } } ret[0] = '\0'; /* to start strcat off */ p = ret; pm = entry->message; if (prefixSuffixIsHeaderFooter) { strcat(p, prefixBuf); p += prefixLen; if (p_format->printable_output) { p += convertPrintable(p, entry->message, entry->messageLen); } else { strncat(p, entry->message, entry->messageLen); p += entry->messageLen; } strcat(p, suffixBuf); p += suffixLen; } else { while(pm < (entry->message + entry->messageLen)) { const char *lineStart; size_t lineLen; lineStart = pm; /* Find the next end-of-line in message */ while (pm < (entry->message + entry->messageLen) && *pm != '\n') pm++; lineLen = pm - lineStart; strcat(p, prefixBuf); p += prefixLen; if (p_format->printable_output) { p += convertPrintable(p, lineStart, lineLen); } else { strncat(p, lineStart, lineLen); p += lineLen; } strcat(p, suffixBuf); p += suffixLen; if (*pm == '\n') pm++; } } if (p_outLength != NULL) { *p_outLength = p - ret; } return ret; }