annotate vamp-server/convert.cpp @ 294:df381a2e6fa1

Fix compiler warning re mismatching enum types
author Chris Cannam <cannam@all-day-breakfast.com>
date Wed, 03 Jan 2024 18:12:35 +0000
parents bd543e74a9bf
children
rev   line source
c@116 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@118 2 /*
c@118 3 Piper C++
c@118 4
c@118 5 An API for audio analysis and feature extraction plugins.
c@118 6
c@118 7 Centre for Digital Music, Queen Mary, University of London.
c@118 8 Copyright 2006-2016 Chris Cannam and QMUL.
c@118 9
c@118 10 Permission is hereby granted, free of charge, to any person
c@118 11 obtaining a copy of this software and associated documentation
c@118 12 files (the "Software"), to deal in the Software without
c@118 13 restriction, including without limitation the rights to use, copy,
c@118 14 modify, merge, publish, distribute, sublicense, and/or sell copies
c@118 15 of the Software, and to permit persons to whom the Software is
c@118 16 furnished to do so, subject to the following conditions:
c@118 17
c@118 18 The above copyright notice and this permission notice shall be
c@118 19 included in all copies or substantial portions of the Software.
c@118 20
c@118 21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
c@118 22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
c@118 23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
c@118 24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
c@118 25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
c@118 26 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
c@118 27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
c@118 28
c@118 29 Except as contained in this notice, the names of the Centre for
c@118 30 Digital Music; Queen Mary, University of London; and Chris Cannam
c@118 31 shall not be used in advertising or otherwise to promote the sale,
c@118 32 use or other dealings in this Software without prior written
c@118 33 authorization.
c@118 34 */
c@75 35
c@75 36 #include "vamp-json/VampJson.h"
c@75 37 #include "vamp-capnp/VampnProto.h"
c@75 38 #include "vamp-support/RequestOrResponse.h"
c@75 39 #include "vamp-support/PreservingPluginHandleMapper.h"
c@75 40
c@75 41 #include <iostream>
c@75 42 #include <sstream>
c@75 43 #include <stdexcept>
c@75 44
c@91 45 #include <capnp/serialize.h>
c@91 46
c@123 47 // for _setmode stuff
c@123 48 #ifdef _WIN32
c@123 49 #include <io.h>
c@123 50 #include <fcntl.h>
c@123 51 #endif
c@123 52
c@75 53 using namespace std;
c@75 54 using namespace json11;
c@97 55 using namespace piper_vamp;
c@75 56
c@75 57 void usage()
c@75 58 {
c@75 59 string myname = "piper-convert";
c@75 60 cerr << "\n" << myname <<
c@116 61 ": Validate and convert Piper request and response messages\n\n"
c@116 62 " Usage: " << myname << " [-i <informat>] [-o <outformat>] request\n"
c@116 63 " " << myname << " [-i <informat>] [-o <outformat>] response\n\n"
c@116 64 " where\n"
c@116 65 " <informat>: the format to read from stdin\n"
c@116 66 " (\"json\" or \"capnp\", default is \"json\")\n"
c@116 67 " <outformat>: the format to convert to and write to stdout\n"
c@116 68 " (\"json\", \"json-b64\" or \"capnp\", default is \"json\")\n"
c@116 69 " request|response: whether messages are Vamp request or response type\n\n"
c@116 70 "If <informat> and <outformat> differ, convert from <informat> to <outformat>.\n"
c@116 71 "If <informat> and <outformat> are the same, just check validity of incoming\n"
c@116 72 "messages and pass them to output.\n\n"
c@116 73 "Specifying \"json-b64\" as output format forces base64 encoding for process and\n"
c@116 74 "feature blocks, unlike the \"json\" output format which uses text encoding.\n"
c@116 75 "The \"json\" input format accepts either.\n\n";
c@75 76
c@75 77 exit(2);
c@75 78 }
c@75 79
c@75 80 Json
c@75 81 convertRequestJson(string input, string &err)
c@75 82 {
c@75 83 Json j = Json::parse(input, err);
c@75 84 if (err != "") {
c@116 85 err = "invalid json: " + err;
c@116 86 return {};
c@75 87 }
c@75 88 if (!j.is_object()) {
c@116 89 err = "object expected at top level";
c@75 90 } else if (!j["method"].is_string()) {
c@116 91 err = "string expected for method field";
c@75 92 } else if (!j["params"].is_null() && !j["params"].is_object()) {
c@116 93 err = "object expected for params field";
c@75 94 }
c@75 95 return j;
c@75 96 }
c@75 97
c@75 98 Json
c@75 99 convertResponseJson(string input, string &err)
c@75 100 {
c@75 101 Json j = Json::parse(input, err);
c@75 102 if (err != "") {
c@116 103 err = "invalid json: " + err;
c@116 104 return {};
c@75 105 }
c@75 106 if (!j.is_object()) {
c@116 107 err = "object expected at top level";
c@75 108 } else {
c@75 109 if (!j["result"].is_object()) {
c@75 110 if (!j["error"].is_object()) {
c@75 111 err = "expected either result or error object";
c@75 112 }
c@75 113 }
c@75 114 }
c@75 115 return j;
c@75 116 }
c@75 117
c@75 118 //!!! Lots of potential for refactoring the conversion classes based
c@75 119 //!!! on the common matter in the following eight functions...
c@75 120
c@75 121 PreservingPluginHandleMapper mapper;
c@75 122
c@75 123 static RequestOrResponse::RpcId
c@75 124 readJsonId(const Json &j)
c@75 125 {
c@75 126 RequestOrResponse::RpcId id;
c@75 127
c@75 128 if (j["id"].is_number()) {
c@75 129 id.type = RequestOrResponse::RpcId::Number;
c@75 130 id.number = j["id"].number_value();
c@75 131 } else if (j["id"].is_string()) {
c@75 132 id.type = RequestOrResponse::RpcId::Tag;
c@75 133 id.tag = j["id"].string_value();
c@75 134 } else {
c@75 135 id.type = RequestOrResponse::RpcId::Absent;
c@75 136 }
c@75 137
c@75 138 return id;
c@75 139 }
c@75 140
c@75 141 static Json
c@75 142 writeJsonId(const RequestOrResponse::RpcId &id)
c@75 143 {
c@75 144 if (id.type == RequestOrResponse::RpcId::Number) {
c@75 145 return id.number;
c@75 146 } else if (id.type == RequestOrResponse::RpcId::Tag) {
c@75 147 return id.tag;
c@75 148 } else {
c@75 149 return Json();
c@75 150 }
c@75 151 }
c@75 152
cannam@294 153 template <typename Reader, typename Id>
c@75 154 static RequestOrResponse::RpcId
c@75 155 readCapnpId(const Reader &r)
c@75 156 {
c@75 157 int number;
c@75 158 string tag;
c@75 159 switch (r.getId().which()) {
cannam@294 160 case Id::Which::NUMBER:
c@75 161 number = r.getId().getNumber();
c@75 162 return { RequestOrResponse::RpcId::Number, number, "" };
cannam@294 163 case Id::Which::TAG:
c@75 164 tag = r.getId().getTag();
c@75 165 return { RequestOrResponse::RpcId::Tag, 0, tag };
cannam@294 166 case Id::Which::NONE:
c@75 167 return { RequestOrResponse::RpcId::Absent, 0, "" };
c@75 168 }
cannam@153 169 return { RequestOrResponse::RpcId::Absent, 0, "" };
c@75 170 }
c@75 171
c@75 172 template <typename Builder>
c@75 173 static void
c@75 174 buildCapnpId(Builder &b, const RequestOrResponse::RpcId &id)
c@75 175 {
c@75 176 switch (id.type) {
c@75 177 case RequestOrResponse::RpcId::Number:
c@75 178 b.getId().setNumber(id.number);
c@75 179 break;
c@75 180 case RequestOrResponse::RpcId::Tag:
c@75 181 b.getId().setTag(id.tag);
c@75 182 break;
c@75 183 case RequestOrResponse::RpcId::Absent:
c@75 184 b.getId().setNone();
c@75 185 break;
c@75 186 }
c@75 187 }
c@75 188
c@75 189 RequestOrResponse
cannam@158 190 readRequestJson(string &err, bool &eof)
c@75 191 {
c@75 192 RequestOrResponse rr;
c@75 193 rr.direction = RequestOrResponse::Request;
c@75 194
c@75 195 string input;
c@75 196 if (!getline(cin, input)) {
c@116 197 // the EOF case, not actually an error
cannam@158 198 eof = true;
c@116 199 return rr;
c@75 200 }
c@75 201
c@75 202 Json j = convertRequestJson(input, err);
c@75 203 if (err != "") return {};
c@75 204
c@75 205 rr.type = VampJson::getRequestResponseType(j, err);
c@75 206 if (err != "") return {};
c@75 207
c@75 208 rr.id = readJsonId(j);
c@75 209
c@75 210 VampJson::BufferSerialisation serialisation =
c@75 211 VampJson::BufferSerialisation::Array;
c@75 212
c@75 213 switch (rr.type) {
c@75 214
c@75 215 case RRType::List:
c@130 216 rr.listRequest = VampJson::toRpcRequest_List(j, err);
c@116 217 break;
c@75 218 case RRType::Load:
c@116 219 rr.loadRequest = VampJson::toRpcRequest_Load(j, err);
c@116 220 break;
c@75 221 case RRType::Configure:
c@116 222 rr.configurationRequest = VampJson::toRpcRequest_Configure(j, mapper, err);
c@116 223 break;
c@75 224 case RRType::Process:
c@116 225 rr.processRequest = VampJson::toRpcRequest_Process(j, mapper, serialisation, err);
c@116 226 break;
c@75 227 case RRType::Finish:
c@116 228 rr.finishRequest = VampJson::toRpcRequest_Finish(j, mapper, err);
c@116 229 break;
c@75 230 case RRType::NotValid:
c@116 231 break;
c@75 232 }
c@75 233
c@75 234 return rr;
c@75 235 }
c@75 236
c@75 237 void
c@75 238 writeRequestJson(RequestOrResponse &rr, bool useBase64)
c@75 239 {
c@75 240 Json j;
c@75 241
c@75 242 VampJson::BufferSerialisation serialisation =
c@75 243 (useBase64 ?
c@75 244 VampJson::BufferSerialisation::Base64 :
c@75 245 VampJson::BufferSerialisation::Array);
c@75 246
c@75 247 Json id = writeJsonId(rr.id);
c@75 248
c@75 249 switch (rr.type) {
c@75 250
c@75 251 case RRType::List:
c@127 252 j = VampJson::fromRpcRequest_List(rr.listRequest, id);
c@116 253 break;
c@75 254 case RRType::Load:
c@116 255 j = VampJson::fromRpcRequest_Load(rr.loadRequest, id);
c@116 256 break;
c@75 257 case RRType::Configure:
c@116 258 j = VampJson::fromRpcRequest_Configure(rr.configurationRequest, mapper, id);
c@116 259 break;
c@75 260 case RRType::Process:
c@116 261 j = VampJson::fromRpcRequest_Process
c@116 262 (rr.processRequest, mapper, serialisation, id);
c@116 263 break;
c@75 264 case RRType::Finish:
c@116 265 j = VampJson::fromRpcRequest_Finish(rr.finishRequest, mapper, id);
c@116 266 break;
c@75 267 case RRType::NotValid:
c@116 268 break;
c@75 269 }
c@75 270
c@75 271 cout << j.dump() << endl;
c@75 272 }
c@75 273
c@75 274 RequestOrResponse
cannam@158 275 readResponseJson(string &err, bool &eof)
c@75 276 {
c@75 277 RequestOrResponse rr;
c@75 278 rr.direction = RequestOrResponse::Response;
c@75 279
c@75 280 string input;
c@75 281 if (!getline(cin, input)) {
c@116 282 // the EOF case, not actually an error
cannam@158 283 eof = true;
c@116 284 return rr;
c@75 285 }
c@75 286
c@75 287 Json j = convertResponseJson(input, err);
c@75 288 if (err != "") return {};
c@75 289
c@75 290 rr.type = VampJson::getRequestResponseType(j, err);
c@75 291 if (err != "") return {};
c@75 292
c@75 293 rr.id = readJsonId(j);
c@75 294
c@75 295 VampJson::BufferSerialisation serialisation =
c@75 296 VampJson::BufferSerialisation::Array;
c@75 297
dev@174 298 const bool isSuccess = j["result"].is_object();
dev@174 299 const bool isError = j["error"].is_object();
dev@174 300 rr.success = isSuccess;
dev@174 301 rr.errorText = isError ? j["error"]["message"].string_value() : "";
c@75 302
c@75 303 switch (rr.type) {
c@75 304
c@75 305 case RRType::List:
c@116 306 rr.listResponse = VampJson::toRpcResponse_List(j, err);
c@116 307 break;
c@75 308 case RRType::Load:
c@116 309 rr.loadResponse = VampJson::toRpcResponse_Load(j, mapper, err);
c@116 310 break;
c@75 311 case RRType::Configure:
c@116 312 rr.configurationResponse = VampJson::toRpcResponse_Configure(j, mapper, err);
c@116 313 break;
c@75 314 case RRType::Process:
c@116 315 rr.processResponse = VampJson::toRpcResponse_Process(j, mapper, serialisation, err);
c@116 316 break;
c@75 317 case RRType::Finish:
c@116 318 rr.finishResponse = VampJson::toRpcResponse_Finish(j, mapper, serialisation, err);
c@116 319 break;
c@75 320 case RRType::NotValid:
c@116 321 break;
c@75 322 }
c@75 323
c@75 324 return rr;
c@75 325 }
c@75 326
c@75 327 void
c@75 328 writeResponseJson(RequestOrResponse &rr, bool useBase64)
c@75 329 {
c@75 330 Json j;
c@75 331
c@75 332 VampJson::BufferSerialisation serialisation =
c@75 333 (useBase64 ?
c@75 334 VampJson::BufferSerialisation::Base64 :
c@75 335 VampJson::BufferSerialisation::Array);
c@75 336
c@75 337 Json id = writeJsonId(rr.id);
c@75 338
c@75 339 if (!rr.success) {
dev@176 340 // errorText here likely contains a full message produced by simple-server
dev@176 341 // setting writeVerbatimError to true avoids doubling error descriptions
dev@176 342 j = VampJson::fromError(rr.errorText, rr.type, id, true);
c@75 343
c@75 344 } else {
c@116 345 switch (rr.type) {
c@75 346
c@116 347 case RRType::List:
c@116 348 j = VampJson::fromRpcResponse_List(rr.listResponse, id);
c@116 349 break;
c@116 350 case RRType::Load:
c@116 351 j = VampJson::fromRpcResponse_Load(rr.loadResponse, mapper, id);
c@116 352 break;
c@116 353 case RRType::Configure:
c@116 354 j = VampJson::fromRpcResponse_Configure(rr.configurationResponse,
c@75 355 mapper, id);
c@116 356 break;
c@116 357 case RRType::Process:
c@116 358 j = VampJson::fromRpcResponse_Process
c@116 359 (rr.processResponse, mapper, serialisation, id);
c@116 360 break;
c@116 361 case RRType::Finish:
c@116 362 j = VampJson::fromRpcResponse_Finish
c@116 363 (rr.finishResponse, mapper, serialisation, id);
c@116 364 break;
c@116 365 case RRType::NotValid:
cannam@158 366 j = VampJson::fromError(rr.errorText, rr.type, id);
c@116 367 break;
c@116 368 }
c@75 369 }
c@75 370
c@75 371 cout << j.dump() << endl;
c@75 372 }
c@75 373
c@75 374 RequestOrResponse
c@75 375 readRequestCapnp(kj::BufferedInputStreamWrapper &buffered)
c@75 376 {
c@75 377 RequestOrResponse rr;
c@75 378 rr.direction = RequestOrResponse::Request;
c@75 379
c@97 380 capnp::InputStreamMessageReader message(buffered);
c@97 381 piper::RpcRequest::Reader reader = message.getRoot<piper::RpcRequest>();
c@75 382
c@75 383 rr.type = VampnProto::getRequestResponseType(reader);
cannam@294 384 rr.id = readCapnpId<piper::RpcRequest::Reader, piper::RpcRequest::Id>
cannam@294 385 (reader);
c@75 386
c@75 387 switch (rr.type) {
c@75 388
c@75 389 case RRType::List:
c@127 390 VampnProto::readRpcRequest_List(rr.listRequest, reader);
c@116 391 break;
c@75 392 case RRType::Load:
c@116 393 VampnProto::readRpcRequest_Load(rr.loadRequest, reader);
c@116 394 break;
c@75 395 case RRType::Configure:
c@116 396 VampnProto::readRpcRequest_Configure(rr.configurationRequest,
c@116 397 reader, mapper);
c@116 398 break;
c@75 399 case RRType::Process:
c@116 400 VampnProto::readRpcRequest_Process(rr.processRequest, reader, mapper);
c@116 401 break;
c@75 402 case RRType::Finish:
c@116 403 VampnProto::readRpcRequest_Finish(rr.finishRequest, reader, mapper);
c@116 404 break;
c@75 405 case RRType::NotValid:
c@116 406 break;
c@75 407 }
c@75 408
c@75 409 return rr;
c@75 410 }
c@75 411
c@75 412 void
c@75 413 writeRequestCapnp(RequestOrResponse &rr)
c@75 414 {
c@97 415 capnp::MallocMessageBuilder message;
c@97 416 piper::RpcRequest::Builder builder = message.initRoot<piper::RpcRequest>();
c@75 417
c@75 418 buildCapnpId(builder, rr.id);
c@75 419
c@75 420 switch (rr.type) {
c@75 421
c@75 422 case RRType::List:
c@127 423 VampnProto::buildRpcRequest_List(builder, rr.listRequest);
c@116 424 break;
c@75 425 case RRType::Load:
c@116 426 VampnProto::buildRpcRequest_Load(builder, rr.loadRequest);
c@116 427 break;
c@75 428 case RRType::Configure:
c@116 429 VampnProto::buildRpcRequest_Configure(builder,
c@75 430 rr.configurationRequest, mapper);
c@116 431 break;
c@75 432 case RRType::Process:
c@116 433 VampnProto::buildRpcRequest_Process(builder, rr.processRequest, mapper);
c@116 434 break;
c@75 435 case RRType::Finish:
c@116 436 VampnProto::buildRpcRequest_Finish(builder, rr.finishRequest, mapper);
c@116 437 break;
c@75 438 case RRType::NotValid:
c@116 439 break;
c@75 440 }
c@75 441
c@75 442 writeMessageToFd(1, message);
c@75 443 }
c@75 444
c@75 445 RequestOrResponse
c@75 446 readResponseCapnp(kj::BufferedInputStreamWrapper &buffered)
c@75 447 {
c@75 448 RequestOrResponse rr;
c@75 449 rr.direction = RequestOrResponse::Response;
c@75 450
c@97 451 capnp::InputStreamMessageReader message(buffered);
c@97 452 piper::RpcResponse::Reader reader = message.getRoot<piper::RpcResponse>();
c@75 453
c@75 454 rr.type = VampnProto::getRequestResponseType(reader);
c@75 455 rr.success = true;
c@75 456 rr.errorText = "";
cannam@294 457 rr.id = readCapnpId<piper::RpcResponse::Reader, piper::RpcResponse::Id>
cannam@294 458 (reader);
c@75 459 int errorCode = 0;
c@75 460
c@75 461 switch (rr.type) {
c@75 462
c@75 463 case RRType::List:
c@116 464 VampnProto::readRpcResponse_List(rr.listResponse, reader);
c@116 465 break;
c@75 466 case RRType::Load:
c@116 467 VampnProto::readRpcResponse_Load(rr.loadResponse, reader, mapper);
c@116 468 break;
c@75 469 case RRType::Configure:
c@116 470 VampnProto::readRpcResponse_Configure(rr.configurationResponse,
c@116 471 reader, mapper);
c@116 472 break;
c@75 473 case RRType::Process:
c@116 474 VampnProto::readRpcResponse_Process(rr.processResponse, reader, mapper);
c@116 475 break;
c@75 476 case RRType::Finish:
c@116 477 VampnProto::readRpcResponse_Finish(rr.finishResponse, reader, mapper);
c@116 478 break;
c@75 479 case RRType::NotValid:
c@75 480 VampnProto::readRpcResponse_Error(errorCode, rr.errorText, reader);
c@116 481 break;
c@75 482 }
c@75 483
c@75 484 return rr;
c@75 485 }
c@75 486
c@75 487 void
c@75 488 writeResponseCapnp(RequestOrResponse &rr)
c@75 489 {
c@97 490 capnp::MallocMessageBuilder message;
c@97 491 piper::RpcResponse::Builder builder = message.initRoot<piper::RpcResponse>();
c@75 492
c@75 493 buildCapnpId(builder, rr.id);
c@75 494
c@75 495 if (!rr.success) {
c@75 496
c@116 497 VampnProto::buildRpcResponse_Error(builder, rr.errorText, rr.type);
c@75 498
c@75 499 } else {
c@116 500
c@116 501 switch (rr.type) {
c@75 502
c@116 503 case RRType::List:
c@116 504 VampnProto::buildRpcResponse_List(builder, rr.listResponse);
c@116 505 break;
c@116 506 case RRType::Load:
c@116 507 VampnProto::buildRpcResponse_Load(builder, rr.loadResponse, mapper);
c@116 508 break;
c@116 509 case RRType::Configure:
c@116 510 VampnProto::buildRpcResponse_Configure(builder, rr.configurationResponse, mapper);
c@116 511 break;
c@116 512 case RRType::Process:
c@116 513 VampnProto::buildRpcResponse_Process(builder, rr.processResponse, mapper);
c@116 514 break;
c@116 515 case RRType::Finish:
c@116 516 VampnProto::buildRpcResponse_Finish(builder, rr.finishResponse, mapper);
c@116 517 break;
c@116 518 case RRType::NotValid:
cannam@158 519 VampnProto::buildRpcResponse_Error(builder, rr.errorText, rr.type);
c@116 520 break;
c@116 521 }
c@75 522 }
c@75 523
c@75 524 writeMessageToFd(1, message);
c@75 525 }
c@75 526
c@75 527 RequestOrResponse
cannam@158 528 readInputJson(RequestOrResponse::Direction direction, string &err, bool &eof)
c@75 529 {
c@75 530 if (direction == RequestOrResponse::Request) {
cannam@158 531 return readRequestJson(err, eof);
c@75 532 } else {
cannam@158 533 return readResponseJson(err, eof);
c@75 534 }
c@75 535 }
c@75 536
c@75 537 RequestOrResponse
cannam@158 538 readInputCapnp(RequestOrResponse::Direction direction, bool &eof)
c@75 539 {
c@75 540 static kj::FdInputStream stream(0); // stdin
c@75 541 static kj::BufferedInputStreamWrapper buffered(stream);
c@75 542
c@75 543 if (buffered.tryGetReadBuffer() == nullptr) {
cannam@158 544 eof = true;
c@116 545 return {};
c@75 546 }
c@75 547
c@75 548 if (direction == RequestOrResponse::Request) {
c@116 549 return readRequestCapnp(buffered);
c@75 550 } else {
c@116 551 return readResponseCapnp(buffered);
c@75 552 }
c@75 553 }
c@75 554
c@75 555 RequestOrResponse
cannam@158 556 readInput(string format, RequestOrResponse::Direction direction, bool &eof)
c@75 557 {
cannam@158 558 eof = false;
cannam@158 559
c@75 560 if (format == "json") {
c@116 561 string err;
cannam@158 562 auto result = readInputJson(direction, err, eof);
dev@180 563 if (err != "") throw runtime_error(err);
dev@180 564 else return result;
c@75 565 } else if (format == "capnp") {
cannam@158 566 return readInputCapnp(direction, eof);
c@75 567 } else {
c@116 568 throw runtime_error("unknown input format \"" + format + "\"");
c@75 569 }
c@75 570 }
c@75 571
c@75 572 void
c@75 573 writeOutput(string format, RequestOrResponse &rr)
c@75 574 {
c@75 575 if (format == "json") {
c@116 576 if (rr.direction == RequestOrResponse::Request) {
c@116 577 writeRequestJson(rr, false);
c@116 578 } else {
c@116 579 writeResponseJson(rr, false);
c@116 580 }
c@75 581 } else if (format == "json-b64") {
c@116 582 if (rr.direction == RequestOrResponse::Request) {
c@116 583 writeRequestJson(rr, true);
c@116 584 } else {
c@116 585 writeResponseJson(rr, true);
c@116 586 }
c@75 587 } else if (format == "capnp") {
c@116 588 if (rr.direction == RequestOrResponse::Request) {
c@116 589 writeRequestCapnp(rr);
c@116 590 } else {
c@116 591 writeResponseCapnp(rr);
c@116 592 }
c@75 593 } else {
c@116 594 throw runtime_error("unknown output format \"" + format + "\"");
c@75 595 }
c@75 596 }
c@75 597
c@75 598 int main(int argc, char **argv)
c@75 599 {
c@75 600 if (argc < 2) {
c@116 601 usage();
c@75 602 }
c@75 603
c@75 604 string informat = "json", outformat = "json";
c@75 605 RequestOrResponse::Direction direction = RequestOrResponse::Request;
c@75 606 bool haveDirection = false;
c@75 607
c@75 608 for (int i = 1; i < argc; ++i) {
c@75 609
c@116 610 string arg = argv[i];
c@116 611 bool final = (i + 1 == argc);
c@116 612
c@116 613 if (arg == "-i") {
c@116 614 if (final) usage();
c@116 615 else informat = argv[++i];
c@75 616
c@116 617 } else if (arg == "-o") {
c@116 618 if (final) usage();
c@116 619 else outformat = argv[++i];
c@75 620
c@116 621 } else if (arg == "request") {
c@116 622 direction = RequestOrResponse::Request;
c@116 623 haveDirection = true;
c@75 624
c@116 625 } else if (arg == "response") {
c@116 626 direction = RequestOrResponse::Response;
c@116 627 haveDirection = true;
c@116 628
c@116 629 } else {
c@116 630 usage();
c@116 631 }
c@75 632 }
c@75 633
c@75 634 if (informat == "" || outformat == "" || !haveDirection) {
c@116 635 usage();
c@75 636 }
c@75 637
c@123 638 #ifdef _WIN32
c@123 639 if (informat == "capnp") {
c@123 640 int result = _setmode(_fileno(stdin), _O_BINARY);
c@123 641 if (result == -1) {
c@123 642 cerr << "Failed to set binary mode on stdin, necessary for capnp format" << endl;
c@123 643 exit(1);
c@123 644 }
c@123 645 }
c@123 646 if (outformat == "capnp") {
c@123 647 int result = _setmode(_fileno(stdout), _O_BINARY);
c@123 648 if (result == -1) {
c@123 649 cerr << "Failed to set binary mode on stdout, necessary for capnp format" << endl;
c@123 650 exit(1);
c@123 651 }
c@123 652 }
c@123 653 #endif
c@123 654
c@75 655 while (true) {
c@75 656
c@116 657 try {
c@75 658
cannam@158 659 bool eof = false;
cannam@158 660 RequestOrResponse rr = readInput(informat, direction, eof);
cannam@158 661 if (eof) break;
c@75 662
c@116 663 writeOutput(outformat, rr);
cannam@158 664
c@116 665 } catch (std::exception &e) {
c@116 666 cerr << "Error: " << e.what() << endl;
c@116 667 exit(1);
c@116 668 }
c@75 669 }
c@75 670
c@75 671 exit(0);
c@75 672 }
c@75 673
c@75 674