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