13d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// Protocol Buffers - Google's data interchange format
23d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// Copyright 2012 Google Inc.  All rights reserved.
33d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// http://code.google.com/p/protobuf/
43d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch//
53d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// Redistribution and use in source and binary forms, with or without
63d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// modification, are permitted provided that the following conditions are
73d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// met:
83d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch//
93d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch//     * Redistributions of source code must retain the above copyright
103d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// notice, this list of conditions and the following disclaimer.
113d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch//     * Redistributions in binary form must reproduce the above
123d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// copyright notice, this list of conditions and the following disclaimer
133d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// in the documentation and/or other materials provided with the
143d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// distribution.
153d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch//     * Neither the name of Google Inc. nor the names of its
163d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// contributors may be used to endorse or promote products derived from
173d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// this software without specific prior written permission.
183d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch//
193d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
203d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
213d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
223d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
233d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
243d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
253d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
263d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
273d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
283d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
293d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
303d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
313d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// from google3/base/stringprintf.cc
323d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
333d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#include <google/protobuf/stubs/stringprintf.h>
343d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
353d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#include <errno.h>
363d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#include <stdarg.h> // For va_list and related operations
373d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#include <stdio.h> // MSVC requires this for _vsnprintf
383d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#include <vector>
393d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#include <google/protobuf/stubs/common.h>
403d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#include <google/protobuf/testing/googletest.h>
413d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
423d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdochnamespace google {
433d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdochnamespace protobuf {
443d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
453d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#ifdef _MSC_VER
463d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdochenum { IS_COMPILER_MSVC = 1 };
473d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#ifndef va_copy
483d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// Define va_copy for MSVC. This is a hack, assuming va_list is simply a
493d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// pointer into the stack and is safe to copy.
503d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#define va_copy(dest, src) ((dest) = (src))
513d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#endif
523d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#else
533d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdochenum { IS_COMPILER_MSVC = 0 };
543d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch#endif
553d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
563d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdochvoid StringAppendV(string* dst, const char* format, va_list ap) {
573d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // First try with a small fixed size buffer
583d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  static const int kSpaceLength = 1024;
593d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  char space[kSpaceLength];
603d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
613d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // It's possible for methods that use a va_list to invalidate
623d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // the data in it upon use.  The fix is to make a copy
633d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // of the structure before using it and use that copy instead.
643d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_list backup_ap;
653d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_copy(backup_ap, ap);
663d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  int result = vsnprintf(space, kSpaceLength, format, backup_ap);
673d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_end(backup_ap);
683d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
693d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  if (result < kSpaceLength) {
703d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch    if (result >= 0) {
713d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      // Normal case -- everything fit.
723d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      dst->append(space, result);
733d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      return;
743d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch    }
753d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
763d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch    if (IS_COMPILER_MSVC) {
773d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      // Error or MSVC running out of space.  MSVC 8.0 and higher
783d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      // can be asked about space needed with the special idiom below:
793d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      va_copy(backup_ap, ap);
803d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      result = vsnprintf(NULL, 0, format, backup_ap);
813d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      va_end(backup_ap);
823d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch    }
833d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
843d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch    if (result < 0) {
853d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      // Just an error.
863d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      return;
873d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch    }
883d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  }
893d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
903d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // Increase the buffer size to the size requested by vsnprintf,
913d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // plus one for the closing \0.
923d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  int length = result+1;
933d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  char* buf = new char[length];
943d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
953d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // Restore the va_list before we use it again
963d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_copy(backup_ap, ap);
973d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  result = vsnprintf(buf, length, format, backup_ap);
983d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_end(backup_ap);
993d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1003d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  if (result >= 0 && result < length) {
1013d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch    // It fit
1023d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch    dst->append(buf, result);
1033d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  }
1043d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  delete[] buf;
1053d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch}
1063d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1073d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1083d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdochstring StringPrintf(const char* format, ...) {
1093d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_list ap;
1103d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_start(ap, format);
1113d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  string result;
1123d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  StringAppendV(&result, format, ap);
1133d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_end(ap);
1143d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  return result;
1153d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch}
1163d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1173d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdochconst string& SStringPrintf(string* dst, const char* format, ...) {
1183d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_list ap;
1193d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_start(ap, format);
1203d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  dst->clear();
1213d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  StringAppendV(dst, format, ap);
1223d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_end(ap);
1233d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  return *dst;
1243d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch}
1253d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1263d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdochvoid StringAppendF(string* dst, const char* format, ...) {
1273d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_list ap;
1283d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_start(ap, format);
1293d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  StringAppendV(dst, format, ap);
1303d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  va_end(ap);
1313d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch}
1323d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1333d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// Max arguments supported by StringPrintVector
1343d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdochconst int kStringPrintfVectorMaxArgs = 32;
1353d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1363d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// An empty block of zero for filler arguments.  This is const so that if
1373d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// printf tries to write to it (via %n) then the program gets a SIGSEGV
1383d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch// and we can fix the problem or protect against an attack.
1393d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdochstatic const char string_printf_empty_block[256] = { '\0' };
1403d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1413d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdochstring StringPrintfVector(const char* format, const vector<string>& v) {
1423d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  GOOGLE_CHECK_LE(v.size(), kStringPrintfVectorMaxArgs)
1433d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      << "StringPrintfVector currently only supports up to "
1443d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      << kStringPrintfVectorMaxArgs << " arguments. "
1453d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch      << "Feel free to add support for more if you need it.";
1463d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1473d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // Add filler arguments so that bogus format+args have a harder time
1483d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // crashing the program, corrupting the program (%n),
1493d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // or displaying random chunks of memory to users.
1503d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1513d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  const char* cstr[kStringPrintfVectorMaxArgs];
1523d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  for (int i = 0; i < v.size(); ++i) {
1533d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch    cstr[i] = v[i].c_str();
1543d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  }
1553d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  for (int i = v.size(); i < GOOGLE_ARRAYSIZE(cstr); ++i) {
1563d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch    cstr[i] = &string_printf_empty_block[0];
1573d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  }
1583d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1593d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // I do not know any way to pass kStringPrintfVectorMaxArgs arguments,
1603d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // or any way to build a va_list by hand, or any API for printf
1613d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // that accepts an array of arguments.  The best I can do is stick
1623d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  // this COMPILE_ASSERT right next to the actual statement.
1633d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch
1643d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  GOOGLE_COMPILE_ASSERT(kStringPrintfVectorMaxArgs == 32, arg_count_mismatch);
1653d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch  return StringPrintf(format,
1663d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch                      cstr[0], cstr[1], cstr[2], cstr[3], cstr[4],
1673d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch                      cstr[5], cstr[6], cstr[7], cstr[8], cstr[9],
1683d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch                      cstr[10], cstr[11], cstr[12], cstr[13], cstr[14],
1693d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch                      cstr[15], cstr[16], cstr[17], cstr[18], cstr[19],
1703d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch                      cstr[20], cstr[21], cstr[22], cstr[23], cstr[24],
1713d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch                      cstr[25], cstr[26], cstr[27], cstr[28], cstr[29],
1723d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch                      cstr[30], cstr[31]);
1733d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch}
1743d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch}  // namespace protobuf
1753d4dfb6f11fb4e934d658743a8efc26d5490fdb0Ben Murdoch}  // namespace google
176