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);
}
Example #6
0
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;
}