/*
* Copyright (c) 2017-2024 OARC, Inc.
* Copyright (c) 2011-2017, IIS - The Internet Foundation in Sweden
* All rights reserved.
*
* This file is part of PacketQ.
*
* PacketQ 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 3 of the License, or
* (at your option) any later version.
*
* PacketQ 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 PacketQ. If not, see .
*/
#ifndef __packetq_output_h
#define __packetq_output_h
#include
#include
namespace packetq {
class Output {
char m_buffer[0x10000];
char m_diglut[0x100][4];
int m_len;
int m_tot;
public:
Output()
{
for (int i = 0; i < 256; i++)
snprintf(m_diglut[i], 4, "%d", i);
m_len = 0;
m_tot = 0;
}
~Output()
{
// print();
}
void reset() { m_len = 0; }
void print()
{
if (!m_len)
return;
fwrite(m_buffer, m_len, 1, stdout);
m_tot += m_len;
m_len = 0;
}
void flush()
{
print();
fflush(stdout);
}
inline void add_q_string(const char* p)
{
m_buffer[m_len++] = '"';
add_string_esc_json(p);
m_buffer[m_len++] = '"';
}
inline void add_string_esc_json(const char* p)
{
static const char lut[] = "0123456789ABCDEF";
if (m_len > sizeof(m_buffer) / 2)
print();
char c;
while ((c = *p++)) {
if (c == '\\') {
m_buffer[m_len++] = '\\';
c = '\\';
} else if (c == '"') {
m_buffer[m_len++] = '\\';
} else if (c < 0x20) {
m_buffer[m_len++] = '\\';
m_buffer[m_len++] = 'u';
m_buffer[m_len++] = '0';
m_buffer[m_len++] = '0';
m_buffer[m_len++] = lut[(c >> 4) & 0xf];
m_buffer[m_len++] = lut[c & 0xf];
continue;
}
m_buffer[m_len++] = c;
}
}
inline void add_string_esc_xml(const char* p)
{
if (m_len > sizeof(m_buffer) / 2)
print();
char c;
while ((c = *p++) > 'A') {
m_buffer[m_len++] = c;
}
if (c == 0)
return;
p--;
while ((c = *p++)) {
if (c == '>') {
m_buffer[m_len++] = '&';
add_string("gt");
c = ';';
}
if (c == '<') {
m_buffer[m_len++] = '&';
add_string("lt");
c = ';';
}
if (c == '\'') {
m_buffer[m_len++] = '&';
add_string("apos");
c = ';';
}
if (c == '"') {
m_buffer[m_len++] = '&';
add_string("quot");
c = ';';
}
m_buffer[m_len++] = c;
if (c == '&') {
add_string("amp;");
}
}
}
inline void check()
{
if (m_len > sizeof(m_buffer) / 2)
print();
}
inline void add_string(const char* p)
{
check();
char c;
while ((c = *p++)) {
m_buffer[m_len++] = c;
}
}
inline void add_hex_ushort(unsigned short v)
{
static const char lut[] = "0123456789abcdef";
if (v & 0xf000) {
m_buffer[m_len++] = lut[v >> 12];
m_buffer[m_len++] = lut[(v >> 8) & 0xf];
m_buffer[m_len++] = lut[(v >> 4) & 0xf];
m_buffer[m_len++] = lut[v & 0xf];
return;
}
if (v & 0xf00) {
m_buffer[m_len++] = lut[(v >> 8) & 0xf];
m_buffer[m_len++] = lut[(v >> 4) & 0xf];
m_buffer[m_len++] = lut[v & 0xf];
return;
}
if (v & 0xf0) {
m_buffer[m_len++] = lut[(v >> 4) & 0xf];
m_buffer[m_len++] = lut[v & 0xf];
return;
}
m_buffer[m_len++] = lut[v & 0xf];
}
inline void add_attr_ipv6(const char* name, unsigned char* addr)
{
check();
add_string_q(name);
m_buffer[m_len++] = '=';
m_buffer[m_len++] = '"';
unsigned short digs[8];
unsigned char* p = addr;
int longest_run = 0;
int longest_p = 9;
int cur_run = 0;
for (int i = 0; i < 8; i++) {
digs[i] = ((unsigned short)(p[0]) << 8) | (unsigned short)(p[1]);
if (digs[i] == 0) {
cur_run++;
if ((cur_run > 1) && (cur_run > longest_run)) {
longest_run = cur_run;
longest_p = i + 1 - cur_run;
}
} else
cur_run = 0;
p += 2;
}
for (int i = 0; i < 8; i++) {
if (i >= longest_p && i < longest_p + longest_run) {
if (i == longest_p) {
if (i == 0)
m_buffer[m_len++] = ':';
m_buffer[m_len++] = ':';
}
} else {
add_hex_ushort(digs[i]);
if (i != 7)
m_buffer[m_len++] = ':';
}
}
m_buffer[m_len++] = '"';
m_buffer[m_len++] = ' ';
}
inline void add_attr_ipv4(const char* p, unsigned int i)
{
check();
add_string_q(p);
m_buffer[m_len++] = '=';
m_buffer[m_len++] = '"';
add_string_q(m_diglut[i & 255]);
m_buffer[m_len++] = '.';
add_string_q(m_diglut[(i >> 8) & 255]);
m_buffer[m_len++] = '.';
add_string_q(m_diglut[(i >> 16) & 255]);
m_buffer[m_len++] = '.';
add_string_q(m_diglut[(i >> 24)]);
m_buffer[m_len++] = '"';
m_buffer[m_len++] = ' ';
}
inline void add_attr_bool(const char* p, bool i)
{
if (!i)
return;
check();
add_string_q(p);
m_buffer[m_len++] = '=';
m_buffer[m_len++] = '"';
m_buffer[m_len++] = i ? '1' : '0';
m_buffer[m_len++] = '"';
m_buffer[m_len++] = ' ';
}
inline void add_int(unsigned int i)
{
check();
if (i < 256) {
add_string_q(m_diglut[i & 255]);
} else {
unsigned char d[64];
unsigned char* cd = d;
while (i > 0 && cd < (&d[0] + sizeof(d))) {
unsigned int n = i;
i = i / 100;
n = n - (i * 100);
*cd++ = n;
}
if (cd != d) {
unsigned char t = *--cd;
add_string_q(m_diglut[t]);
}
while (cd != d) {
unsigned char t = *--cd;
if (t >= 10)
add_string_q(m_diglut[t]);
else {
m_buffer[m_len++] = '0';
m_buffer[m_len++] = '0' + t;
}
}
}
}
inline void add_attr_int(const char* p, unsigned int i)
{
check();
if (i == 0)
return;
add_string_q(p);
m_buffer[m_len++] = '=';
m_buffer[m_len++] = '"';
add_int(i);
m_buffer[m_len++] = '"';
m_buffer[m_len++] = ' ';
}
inline void add_attr_str(const char* p, const char* t)
{
add_string(p);
m_buffer[m_len++] = '=';
m_buffer[m_len++] = '"';
add_string_esc_json(t);
m_buffer[m_len++] = '"';
m_buffer[m_len++] = ' ';
}
private:
inline void add_string_q(const char* p)
{
char c;
while ((c = *p++)) {
m_buffer[m_len++] = c;
}
}
};
class Str_conv {
char m_buffer[0x10000];
char m_diglut[0x100][4];
int m_len;
int m_tot;
public:
Str_conv()
{
for (int i = 0; i < 256; i++)
snprintf(m_diglut[i], 4, "%d", i);
m_len = 0;
m_tot = 0;
}
~Str_conv()
{
// print();
}
const char* get()
{
m_buffer[m_len] = 0;
return m_buffer;
}
int get_len() { return m_len; }
void reset() { m_len = 0; }
inline void add_attr_ipv6(unsigned char* addr)
{
unsigned short digs[8];
unsigned char* p = &addr[14];
int longest_run = 0;
int longest_p = 9;
int cur_run = 0;
for (int i = 0; i < 8; i++) {
digs[i] = ((unsigned short)(p[1]) << 8) | (unsigned short)(p[0]);
if (digs[i] == 0) {
cur_run++;
if ((cur_run > 1) && (cur_run > longest_run)) {
longest_run = cur_run;
longest_p = i + 1 - cur_run;
}
} else
cur_run = 0;
p -= 2;
}
for (int i = 0; i < 8; i++) {
if (i >= longest_p && i < longest_p + longest_run) {
if (i == longest_p) {
if (i == 0)
m_buffer[m_len++] = ':';
m_buffer[m_len++] = ':';
}
} else {
add_hex_ushort(digs[i]);
if (i != 7)
m_buffer[m_len++] = ':';
}
}
}
inline void add_string_q(const char* p)
{
char c;
while ((c = *p++)) {
m_buffer[m_len++] = c;
}
}
inline void add_attr_ipv4(unsigned int i)
{
add_string_q(m_diglut[(i >> 24)]);
m_buffer[m_len++] = '.';
add_string_q(m_diglut[(i >> 16) & 255]);
m_buffer[m_len++] = '.';
add_string_q(m_diglut[(i >> 8) & 255]);
m_buffer[m_len++] = '.';
add_string_q(m_diglut[(i >> 0) & 255]);
}
inline void add_hex_ushort(unsigned short v)
{
static const char lut[] = "0123456789abcdef";
if (v & 0xf000) {
m_buffer[m_len++] = lut[v >> 12];
m_buffer[m_len++] = lut[(v >> 8) & 0xf];
m_buffer[m_len++] = lut[(v >> 4) & 0xf];
m_buffer[m_len++] = lut[v & 0xf];
return;
}
if (v & 0xf00) {
m_buffer[m_len++] = lut[(v >> 8) & 0xf];
m_buffer[m_len++] = lut[(v >> 4) & 0xf];
m_buffer[m_len++] = lut[v & 0xf];
return;
}
if (v & 0xf0) {
m_buffer[m_len++] = lut[(v >> 4) & 0xf];
m_buffer[m_len++] = lut[v & 0xf];
return;
}
m_buffer[m_len++] = lut[v & 0xf];
}
};
extern Output g_output;
} // namespace packetq
#endif // __packetq_output_h