File indexing completed on 2024-05-20 22:39:47
0001 #include "EventFilter/Utilities/interface/writer.h"
0002 #include <utility>
0003 #include <cassert>
0004 #include <cstdio>
0005 #include <cstring>
0006 #include <iostream>
0007 #include <sstream>
0008 #include <iomanip>
0009
0010 #if _MSC_VER >= 1400
0011 #pragma warning(disable : 4996)
0012 #endif
0013
0014 namespace jsoncollector {
0015 namespace Json {
0016
0017 static bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
0018
0019 static bool containsControlCharacter(const char *str) {
0020 while (*str) {
0021 if (isControlCharacter(*(str++)))
0022 return true;
0023 }
0024 return false;
0025 }
0026 static void uintToString(unsigned int value, char *¤t) {
0027 *--current = 0;
0028 do {
0029 *--current = (value % 10) + '0';
0030 value /= 10;
0031 } while (value != 0);
0032 }
0033
0034 std::string valueToString(Int value) {
0035 char buffer[32];
0036 char *current = buffer + sizeof(buffer);
0037 bool isNegative = value < 0;
0038 if (isNegative)
0039 value = -value;
0040 uintToString(UInt(value), current);
0041 if (isNegative)
0042 *--current = '-';
0043 assert(current >= buffer);
0044 return current;
0045 }
0046
0047 std::string valueToString(UInt value) {
0048 char buffer[32];
0049 char *current = buffer + sizeof(buffer);
0050 uintToString(value, current);
0051 assert(current >= buffer);
0052 return current;
0053 }
0054
0055 std::string valueToString(double value) {
0056 char buffer[32];
0057 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
0058 sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
0059 #else
0060 sprintf(buffer, "%#.16g", value);
0061 #endif
0062 char *ch = buffer + strlen(buffer) - 1;
0063 if (*ch != '0')
0064 return buffer;
0065 while (ch > buffer && *ch == '0') {
0066 --ch;
0067 }
0068 char *last_nonzero = ch;
0069 while (ch >= buffer) {
0070 switch (*ch) {
0071 case '0':
0072 case '1':
0073 case '2':
0074 case '3':
0075 case '4':
0076 case '5':
0077 case '6':
0078 case '7':
0079 case '8':
0080 case '9':
0081 --ch;
0082 continue;
0083 case '.':
0084
0085 *(last_nonzero + 2) = '\0';
0086 return buffer;
0087 default:
0088 return buffer;
0089 }
0090 }
0091 return buffer;
0092 }
0093
0094 std::string valueToString(bool value) { return value ? "true" : "false"; }
0095
0096 std::string valueToQuotedString(const char *value) {
0097
0098 if (strpbrk(value, "\"\\\b\f\n\r\t") == nullptr && !containsControlCharacter(value))
0099 return std::string("\"") + value + "\"";
0100
0101
0102
0103 unsigned maxsize = strlen(value) * 2 + 3;
0104 std::string result;
0105 result.reserve(maxsize);
0106 result += "\"";
0107 for (const char *c = value; *c != 0; ++c) {
0108 switch (*c) {
0109 case '\"':
0110 result += "\\\"";
0111 break;
0112 case '\\':
0113 result += "\\\\";
0114 break;
0115 case '\b':
0116 result += "\\b";
0117 break;
0118 case '\f':
0119 result += "\\f";
0120 break;
0121 case '\n':
0122 result += "\\n";
0123 break;
0124 case '\r':
0125 result += "\\r";
0126 break;
0127 case '\t':
0128 result += "\\t";
0129 break;
0130
0131
0132
0133
0134
0135
0136
0137
0138 default:
0139 if (isControlCharacter(*c)) {
0140 std::ostringstream oss;
0141 oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
0142 result += oss.str();
0143 } else {
0144 result += *c;
0145 }
0146 break;
0147 }
0148 }
0149 result += "\"";
0150 return result;
0151 }
0152
0153
0154
0155 Writer::~Writer() {}
0156
0157
0158
0159
0160 FastWriter::FastWriter() : yamlCompatiblityEnabled_(false) {}
0161
0162 void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
0163
0164 std::string FastWriter::write(const Value &root) {
0165 document_ = "";
0166 writeValue(root);
0167 document_ += "\n";
0168 return document_;
0169 }
0170
0171 void FastWriter::writeValue(const Value &value) {
0172 switch (value.type()) {
0173 case nullValue:
0174 document_ += "null";
0175 break;
0176 case intValue:
0177 document_ += valueToString(value.asInt());
0178 break;
0179 case uintValue:
0180 document_ += valueToString(value.asUInt());
0181 break;
0182 case realValue:
0183 document_ += valueToString(value.asDouble());
0184 break;
0185 case stringValue:
0186 document_ += valueToQuotedString(value.asCString());
0187 break;
0188 case booleanValue:
0189 document_ += valueToString(value.asBool());
0190 break;
0191 case arrayValue: {
0192 document_ += "[";
0193 int size = value.size();
0194 for (int index = 0; index < size; ++index) {
0195 if (index > 0)
0196 document_ += ",";
0197 writeValue(value[index]);
0198 }
0199 document_ += "]";
0200 } break;
0201 case objectValue: {
0202 Value::Members members(value.getMemberNames());
0203 document_ += "{";
0204 for (Value::Members::iterator it = members.begin(); it != members.end(); ++it) {
0205 const std::string &name = *it;
0206 if (it != members.begin())
0207 document_ += ",";
0208 document_ += valueToQuotedString(name.c_str());
0209 document_ += yamlCompatiblityEnabled_ ? ": " : ":";
0210 writeValue(value[name]);
0211 }
0212 document_ += "}";
0213 } break;
0214 }
0215 }
0216
0217
0218
0219
0220 StyledWriter::StyledWriter() : rightMargin_(74), indentSize_(3) {}
0221
0222 std::string StyledWriter::write(const Value &root) {
0223 document_ = "";
0224 addChildValues_ = false;
0225 indentString_ = "";
0226 writeCommentBeforeValue(root);
0227 writeValue(root);
0228 writeCommentAfterValueOnSameLine(root);
0229 document_ += "\n";
0230 return document_;
0231 }
0232
0233 void StyledWriter::writeValue(const Value &value) {
0234 switch (value.type()) {
0235 case nullValue:
0236 pushValue("null");
0237 break;
0238 case intValue:
0239 pushValue(valueToString(value.asInt()));
0240 break;
0241 case uintValue:
0242 pushValue(valueToString(value.asUInt()));
0243 break;
0244 case realValue:
0245 pushValue(valueToString(value.asDouble()));
0246 break;
0247 case stringValue:
0248 pushValue(valueToQuotedString(value.asCString()));
0249 break;
0250 case booleanValue:
0251 pushValue(valueToString(value.asBool()));
0252 break;
0253 case arrayValue:
0254 writeArrayValue(value);
0255 break;
0256 case objectValue: {
0257 Value::Members members(value.getMemberNames());
0258 if (members.empty())
0259 pushValue("{}");
0260 else {
0261 writeWithIndent("{");
0262 indent();
0263 Value::Members::iterator it = members.begin();
0264 while (true) {
0265 const std::string &name = *it;
0266 const Value &childValue = value[name];
0267 writeCommentBeforeValue(childValue);
0268 writeWithIndent(valueToQuotedString(name.c_str()));
0269 document_ += " : ";
0270 writeValue(childValue);
0271 if (++it == members.end()) {
0272 writeCommentAfterValueOnSameLine(childValue);
0273 break;
0274 }
0275 document_ += ",";
0276 writeCommentAfterValueOnSameLine(childValue);
0277 }
0278 unindent();
0279 writeWithIndent("}");
0280 }
0281 } break;
0282 }
0283 }
0284
0285 void StyledWriter::writeArrayValue(const Value &value) {
0286 unsigned size = value.size();
0287 if (size == 0)
0288 pushValue("[]");
0289 else {
0290 bool isArrayMultiLine = isMultineArray(value);
0291 if (isArrayMultiLine) {
0292 writeWithIndent("[");
0293 indent();
0294 bool hasChildValue = !childValues_.empty();
0295 unsigned index = 0;
0296 while (true) {
0297 const Value &childValue = value[index];
0298 writeCommentBeforeValue(childValue);
0299 if (hasChildValue)
0300 writeWithIndent(childValues_[index]);
0301 else {
0302 writeIndent();
0303 writeValue(childValue);
0304 }
0305 if (++index == size) {
0306 writeCommentAfterValueOnSameLine(childValue);
0307 break;
0308 }
0309 document_ += ",";
0310 writeCommentAfterValueOnSameLine(childValue);
0311 }
0312 unindent();
0313 writeWithIndent("]");
0314 } else
0315 {
0316 assert(childValues_.size() == size);
0317 document_ += "[ ";
0318 for (unsigned index = 0; index < size; ++index) {
0319 if (index > 0)
0320 document_ += ", ";
0321 document_ += childValues_[index];
0322 }
0323 document_ += " ]";
0324 }
0325 }
0326 }
0327
0328 bool StyledWriter::isMultineArray(const Value &value) {
0329 int size = value.size();
0330 bool isMultiLine = size * 3 >= rightMargin_;
0331 childValues_.clear();
0332 for (int index = 0; index < size && !isMultiLine; ++index) {
0333 const Value &childValue = value[index];
0334 isMultiLine = isMultiLine || ((childValue.isArray() || childValue.isObject()) && !childValue.empty());
0335 }
0336 if (!isMultiLine)
0337 {
0338 childValues_.reserve(size);
0339 addChildValues_ = true;
0340 int lineLength = 4 + (size - 1) * 2;
0341 for (int index = 0; index < size && !isMultiLine; ++index) {
0342 writeValue(value[index]);
0343 lineLength += int(childValues_[index].length());
0344 isMultiLine = isMultiLine && hasCommentForValue(value[index]);
0345 }
0346 addChildValues_ = false;
0347 isMultiLine = isMultiLine || lineLength >= rightMargin_;
0348 }
0349 return isMultiLine;
0350 }
0351
0352 void StyledWriter::pushValue(const std::string &value) {
0353 if (addChildValues_)
0354 childValues_.push_back(value);
0355 else
0356 document_ += value;
0357 }
0358
0359 void StyledWriter::writeIndent() {
0360 if (!document_.empty()) {
0361 char last = document_[document_.length() - 1];
0362 if (last == ' ')
0363 return;
0364 if (last != '\n')
0365 document_ += '\n';
0366 }
0367 document_ += indentString_;
0368 }
0369
0370 void StyledWriter::writeWithIndent(const std::string &value) {
0371 writeIndent();
0372 document_ += value;
0373 }
0374
0375 void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); }
0376
0377 void StyledWriter::unindent() {
0378 assert(int(indentString_.size()) >= indentSize_);
0379 indentString_.resize(indentString_.size() - indentSize_);
0380 }
0381
0382 void StyledWriter::writeCommentBeforeValue(const Value &root) {
0383 if (!root.hasComment(commentBefore))
0384 return;
0385 document_ += normalizeEOL(root.getComment(commentBefore));
0386 document_ += "\n";
0387 }
0388
0389 void StyledWriter::writeCommentAfterValueOnSameLine(const Value &root) {
0390 if (root.hasComment(commentAfterOnSameLine))
0391 document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
0392
0393 if (root.hasComment(commentAfter)) {
0394 document_ += "\n";
0395 document_ += normalizeEOL(root.getComment(commentAfter));
0396 document_ += "\n";
0397 }
0398 }
0399
0400 bool StyledWriter::hasCommentForValue(const Value &value) {
0401 return value.hasComment(commentBefore) || value.hasComment(commentAfterOnSameLine) ||
0402 value.hasComment(commentAfter);
0403 }
0404
0405 std::string StyledWriter::normalizeEOL(const std::string &text) {
0406 std::string normalized;
0407 normalized.reserve(text.length());
0408 const char *begin = text.c_str();
0409 const char *end = begin + text.length();
0410 const char *current = begin;
0411 while (current != end) {
0412 char c = *current++;
0413 if (c == '\r')
0414 {
0415 if (*current == '\n')
0416 ++current;
0417 normalized += '\n';
0418 } else
0419 normalized += c;
0420 }
0421 return normalized;
0422 }
0423
0424
0425
0426
0427 StyledStreamWriter::StyledStreamWriter(std::string indentation)
0428 : document_(nullptr), rightMargin_(74), indentation_(indentation) {}
0429
0430 void StyledStreamWriter::write(std::ostream &out, const Value &root) {
0431 document_ = &out;
0432 addChildValues_ = false;
0433 indentString_ = "";
0434 writeCommentBeforeValue(root);
0435 writeValue(root);
0436 writeCommentAfterValueOnSameLine(root);
0437 *document_ << "\n";
0438 document_ = nullptr;
0439 }
0440
0441 void StyledStreamWriter::writeValue(const Value &value) {
0442 switch (value.type()) {
0443 case nullValue:
0444 pushValue("null");
0445 break;
0446 case intValue:
0447 pushValue(valueToString(value.asInt()));
0448 break;
0449 case uintValue:
0450 pushValue(valueToString(value.asUInt()));
0451 break;
0452 case realValue:
0453 pushValue(valueToString(value.asDouble()));
0454 break;
0455 case stringValue:
0456 pushValue(valueToQuotedString(value.asCString()));
0457 break;
0458 case booleanValue:
0459 pushValue(valueToString(value.asBool()));
0460 break;
0461 case arrayValue:
0462 writeArrayValue(value);
0463 break;
0464 case objectValue: {
0465 Value::Members members(value.getMemberNames());
0466 if (members.empty())
0467 pushValue("{}");
0468 else {
0469 writeWithIndent("{");
0470 indent();
0471 Value::Members::iterator it = members.begin();
0472 while (true) {
0473 const std::string &name = *it;
0474 const Value &childValue = value[name];
0475 writeCommentBeforeValue(childValue);
0476 writeWithIndent(valueToQuotedString(name.c_str()));
0477 *document_ << " : ";
0478 writeValue(childValue);
0479 if (++it == members.end()) {
0480 writeCommentAfterValueOnSameLine(childValue);
0481 break;
0482 }
0483 *document_ << ",";
0484 writeCommentAfterValueOnSameLine(childValue);
0485 }
0486 unindent();
0487 writeWithIndent("}");
0488 }
0489 } break;
0490 }
0491 }
0492
0493 void StyledStreamWriter::writeArrayValue(const Value &value) {
0494 unsigned size = value.size();
0495 if (size == 0)
0496 pushValue("[]");
0497 else {
0498 bool isArrayMultiLine = isMultineArray(value);
0499 if (isArrayMultiLine) {
0500 writeWithIndent("[");
0501 indent();
0502 bool hasChildValue = !childValues_.empty();
0503 unsigned index = 0;
0504 while (true) {
0505 const Value &childValue = value[index];
0506 writeCommentBeforeValue(childValue);
0507 if (hasChildValue)
0508 writeWithIndent(childValues_[index]);
0509 else {
0510 writeIndent();
0511 writeValue(childValue);
0512 }
0513 if (++index == size) {
0514 writeCommentAfterValueOnSameLine(childValue);
0515 break;
0516 }
0517 *document_ << ",";
0518 writeCommentAfterValueOnSameLine(childValue);
0519 }
0520 unindent();
0521 writeWithIndent("]");
0522 } else
0523 {
0524 assert(childValues_.size() == size);
0525 *document_ << "[ ";
0526 for (unsigned index = 0; index < size; ++index) {
0527 if (index > 0)
0528 *document_ << ", ";
0529 *document_ << childValues_[index];
0530 }
0531 *document_ << " ]";
0532 }
0533 }
0534 }
0535
0536 bool StyledStreamWriter::isMultineArray(const Value &value) {
0537 int size = value.size();
0538 bool isMultiLine = size * 3 >= rightMargin_;
0539 childValues_.clear();
0540 for (int index = 0; index < size && !isMultiLine; ++index) {
0541 const Value &childValue = value[index];
0542 isMultiLine = isMultiLine || ((childValue.isArray() || childValue.isObject()) && !childValue.empty());
0543 }
0544 if (!isMultiLine)
0545 {
0546 childValues_.reserve(size);
0547 addChildValues_ = true;
0548 int lineLength = 4 + (size - 1) * 2;
0549 for (int index = 0; index < size && !isMultiLine; ++index) {
0550 writeValue(value[index]);
0551 lineLength += int(childValues_[index].length());
0552 isMultiLine = isMultiLine && hasCommentForValue(value[index]);
0553 }
0554 addChildValues_ = false;
0555 isMultiLine = isMultiLine || lineLength >= rightMargin_;
0556 }
0557 return isMultiLine;
0558 }
0559
0560 void StyledStreamWriter::pushValue(const std::string &value) {
0561 if (addChildValues_)
0562 childValues_.push_back(value);
0563 else
0564 *document_ << value;
0565 }
0566
0567 void StyledStreamWriter::writeIndent() {
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580 *document_ << '\n' << indentString_;
0581 }
0582
0583 void StyledStreamWriter::writeWithIndent(const std::string &value) {
0584 writeIndent();
0585 *document_ << value;
0586 }
0587
0588 void StyledStreamWriter::indent() { indentString_ += indentation_; }
0589
0590 void StyledStreamWriter::unindent() {
0591 assert(indentString_.size() >= indentation_.size());
0592 indentString_.resize(indentString_.size() - indentation_.size());
0593 }
0594
0595 void StyledStreamWriter::writeCommentBeforeValue(const Value &root) {
0596 if (!root.hasComment(commentBefore))
0597 return;
0598 *document_ << normalizeEOL(root.getComment(commentBefore));
0599 *document_ << "\n";
0600 }
0601
0602 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value &root) {
0603 if (root.hasComment(commentAfterOnSameLine))
0604 *document_ << " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
0605
0606 if (root.hasComment(commentAfter)) {
0607 *document_ << "\n";
0608 *document_ << normalizeEOL(root.getComment(commentAfter));
0609 *document_ << "\n";
0610 }
0611 }
0612
0613 bool StyledStreamWriter::hasCommentForValue(const Value &value) {
0614 return value.hasComment(commentBefore) || value.hasComment(commentAfterOnSameLine) ||
0615 value.hasComment(commentAfter);
0616 }
0617
0618 std::string StyledStreamWriter::normalizeEOL(const std::string &text) {
0619 std::string normalized;
0620 normalized.reserve(text.length());
0621 const char *begin = text.c_str();
0622 const char *end = begin + text.length();
0623 const char *current = begin;
0624 while (current != end) {
0625 char c = *current++;
0626 if (c == '\r')
0627 {
0628 if (*current == '\n')
0629 ++current;
0630 normalized += '\n';
0631 } else
0632 normalized += c;
0633 }
0634 return normalized;
0635 }
0636
0637 std::ostream &operator<<(std::ostream &sout, const Value &root) {
0638 Json::StyledStreamWriter writer;
0639 writer.write(sout, root);
0640 return sout;
0641 }
0642
0643 }
0644 }