<commit_before>#include "~/gitRepos/night/sandbox/tests/testHeader.hpp"

/*
  /* Testing " '
*/

#define BOXIFY(x)                               \
  {                                             \
    if ((x) >= 0.5)                             \
      x -= 1.;                                  \
    else if ((x) < -0.5)                        \
      x += 1.;                                  \
  }

typedef int blah234;

// 0.9899*sqrt(8.0*log(10.0))/(PI*freq);
const tFloat hat_t0 = 1.3523661426929/freq; /* Testing 3 */
const tFloat &hat_t1 = hat_t0;

occaFunction tFloat hatWavelet(tFloat t);

occaFunction tFloat dummyFunction(shared tFloat t){
  return 0;
}

occaFunction tFloat hatWavelet(tFloat t);
occaFunction tFloat hatWavelet(tFloat t){
  const tFloat pift  = PI*freq*(t - hat_t0);
  const tFloat pift2 = pift*pift;

  double *psi @(dim(X,Y,Z), idxOrder(2,1,0));
  psi(a,b,c);

  double *phi @dim(D);
  phi(blah + 1);

  double *delta @(dim(AI,BJ,BI,AJ), idxOrder(3,2,1,0));

  for(int ai = 0; ai < 10; ++ai) @loopOrder("a", 1) {
    for(int bj = 0; bj < 10; ++bj) @loopOrder("b", 1) {
      for(int bi = 0; bi < 10; ++bi) @loopOrder("b", 0) {
        for(int aj = 0; aj < 10; ++aj) @loopOrder("a", 0) {
            delta(aj,bi,bj,ai) = 0;
        }
      }
    }
  }

  return (1. - 2.0*pift2)*exp(-pift2);
}

const int2 * const a34;

float numberSamples[] = {1, +1, -1,
                         1., +1., -1.,
                         1.0, -1.0, +1.0,
                         1.0f, -1.0f, +1.0f,
                         1.01F, -1.01F, +1.01F,
                         1l, -1l, +1l,
                         1.01L, -1.01L, +1.01L,
                         0b001, -0b010, +0b011,
                         0B100, -0B101, +0B110,
                         00001, -00010, +00011,
                         00100, -00101, +00110,
                         0x001, -0x010, +0x011,
                         0X100, -0X101, +0X110};

#if 1
occaKernel void fd2d(tFloat *u1,
                     tFloat *u2,
                     tFloat *u3,
                     const texture tFloat tex1[],
                     texture tFloat tex2[][],
                     texture tFloat **tex3,
                     const tFloat currentTime){

  const int bDimX = 16;
  const int bDimY = 16 + bDimX;
  const int bDimZ = 16 + bDimY;

  const int lDimX = 16 + bDimY;
  int lDimY = lDimX;
  int lDimZ = lDimX + lDimY;

  double2 s[2];

  BOXIFY(s[i].x);

  for(int n = 0; n < bDimX; ++n; tile(lDimX)){
  }

  // for(int2 i(0,1); i.x < bDimX, i.y < bDimY; i.y += 2, ++i.x; tile(lDimX,lDimY)){
  // }

  // for(int2 i(0,1); i.x < bDimX, i.y < bDimY; ++i; tile(lDimX,lDimY)){
  // }

  for(int by = 0; by < bDimY; by += 16; outer0){
    for(int bx = 0; bx < bDimX; bx += 16; outer1){
      shared tFloat Lu[bDimY + 2*sr][bDimX + 2*sr];
      exclusive tFloat r_u2 = 2, r_u3 = 3, r_u4[3], *r_u5, *r_u6[3];

      for(int ly = by; ly < (by + lDimY); ++ly; inner1){
        for(int lx = bx; lx < (by + lDimX); ++lx; inner0){
          const int tx = bx * lDimX + lx;
          const int ty = by * lDimY + ly;

          float2 sj, si;
          float2 s = sj - si;

          Lu[0] = WR_MIN(Lu[tx], Lu[tx+512]);

          int y1, y2;

          {
            y1 = y2 = 0;
          }

          int tmpin = *u1;

          switch(y1){
          case 0 : printf("0\n"); break;
          case 1 : {printf("1\n");}
          default: printf("default\n"); break;
          }

          switch(y2)
          case 0: printf("0\n");

          const int id = ty*w + tx;

          float *__u1 = &u1[bDimX];
          float *__u2 = (float*) (&(u1[bDimX]));

          float data = tex1[0][0];
          tex1[0][0] = data;

          r_u2 = u2[id];
          r_u3 = u3[id];

          const int nX1 = (tx - sr + w) % w;
          const int nY1 = (ty - sr + h) % h;

          const int nX2 = (tx + bDimX - sr + w) % w;
          const int nY2 = (ty + bDimY - sr + h) % h;

          Lu[ly][lx] = u2[nY1*w + nX1];

          if(lx < 2*sr){
            Lu[ly][lx + bDimX] = u2[nY1*w + nX2];

            if(ly < 2*sr)
              Lu[ly + bDimY][lx + bDimX] = u2[nY2*w + nX2];
          }

          if(ly < 2*sr)
            Lu[ly + bDimY][lx] = u2[nY2*w + nX1];

          a.b = 3;
        }
      }

      // barrier(localMemFence);

      for(int ly = 0; ly < lDimY; ++ly; inner1){
        for(int lx = 0; lx < lDimX; ++lx; inner0){
          const int tx = bx * lDimX + lx;
          const int ty = by * lDimY + ly;

          const int id = ty*w + tx;

          tFloat lap = 0.0;

          if(true)
            blah;
          else if(true)
            blah;
          else
            blah;

          for(int i = 0; i < (2*sr + 1); i++){
            lap += xStencil[i]*Lu[ly + sr][lx + i] + xStencil[i]*Lu[ly + i][lx + sr];
            if(i < 2)
              continue;
            break;
          }

          continue;

          for(int i = 0; i < (2*sr + 1); i++){
            lap += xStencil[i]*Lu[ly + sr][lx + i] + xStencil[i]*Lu[ly + i][lx + sr];
          }

          const tFloat u_n1 = (-tStencil[1]*r_u2 - tStencil[2]*r_u3 + lap)/tStencil[0];

          if((tx == mX) && (ty == mY))
            u1[id] = u_n1 + hatWavelet(currentTime, 1, 2)/tStencil[0];
          else
            u1[id] = u_n1;
        }
      }
    }
  }
}
#endif
<commit_msg>[Parser] Added e to the numberSamples in test.cpp<commit_after>#include "~/gitRepos/night/sandbox/tests/testHeader.hpp"

/*
  /* Testing " '
*/

#define BOXIFY(x)                               \
  {                                             \
    if ((x) >= 0.5)                             \
      x -= 1.;                                  \
    else if ((x) < -0.5)                        \
      x += 1.;                                  \
  }

typedef int blah234;

// 0.9899*sqrt(8.0*log(10.0))/(PI*freq);
const tFloat hat_t0 = 1.3523661426929/freq; /* Testing 3 */
const tFloat &hat_t1 = hat_t0;

occaFunction tFloat hatWavelet(tFloat t);

occaFunction tFloat dummyFunction(shared tFloat t){
  return 0;
}

occaFunction tFloat hatWavelet(tFloat t);
occaFunction tFloat hatWavelet(tFloat t){
  const tFloat pift  = PI*freq*(t - hat_t0);
  const tFloat pift2 = pift*pift;

  double *psi @(dim(X,Y,Z), idxOrder(2,1,0));
  psi(a,b,c);

  double *phi @dim(D);
  phi(blah + 1);

  double *delta @(dim(BJ,BI,BJ,AI), idxOrder(3,2,1,0));

  for(int ai = 0; ai < 10; ++ai) @loopOrder("a", 1) {
    for(int bj = 0; bj < 10; ++bj) @loopOrder("b", 1) {
      for(int bi = 0; bi < 10; ++bi) @loopOrder("b", 0) {
        for(int aj = 0; aj < 10; ++aj) @loopOrder("a", 0) {
            delta(aj,bi,bj,ai) = 0;
        }
      }
    }
  }

  return (1. - 2.0*pift2)*exp(-pift2);
}

const int2 * const a34;

float numberSamples[] = {1, +1, -1,
                         1., +1., -1.,
                         1.0, -1.0, +1.0,
                         1.0f, -1.0f, +1.0f,
                         1.01F, -1.01F, +1.01F,
                         1.0e1f, -1.0e-11f, +1.0e+111f,
                         1.0E1, -1.0E-11, +1.0E+111,
                         1.01F, -1.01F, +1.01F,
                         1l, -1l, +1l,
                         1.01L, -1.01L, +1.01L,
                         0b001, -0b010, +0b011,
                         0B100, -0B101, +0B110,
                         00001, -00010, +00011,
                         00100, -00101, +00110,
                         0x001, -0x010, +0x011,
                         0X100, -0X101, +0X110};

#if 1
occaKernel void fd2d(tFloat *u1,
                     tFloat *u2,
                     tFloat *u3,
                     const texture tFloat tex1[],
                     texture tFloat tex2[][],
                     texture tFloat **tex3,
                     const tFloat currentTime){

  const int bDimX = 16;
  const int bDimY = 16 + bDimX;
  const int bDimZ = 16 + bDimY;

  const int lDimX = 16 + bDimY;
  int lDimY = lDimX;
  int lDimZ = lDimX + lDimY;

  double2 s[2];

  BOXIFY(s[i].x);

  for(int n = 0; n < bDimX; ++n; tile(lDimX)){
  }

  // for(int2 i(0,1); i.x < bDimX, i.y < bDimY; i.y += 2, ++i.x; tile(lDimX,lDimY)){
  // }

  // for(int2 i(0,1); i.x < bDimX, i.y < bDimY; ++i; tile(lDimX,lDimY)){
  // }

  for(int by = 0; by < bDimY; by += 16; outer0){
    for(int bx = 0; bx < bDimX; bx += 16; outer1){
      shared tFloat Lu[bDimY + 2*sr][bDimX + 2*sr];
      exclusive tFloat r_u2 = 2, r_u3 = 3, r_u4[3], *r_u5, *r_u6[3];

      for(int ly = by; ly < (by + lDimY); ++ly; inner1){
        for(int lx = bx; lx < (by + lDimX); ++lx; inner0){
          const int tx = bx * lDimX + lx;
          const int ty = by * lDimY + ly;

          float2 sj, si;
          float2 s = sj - si;

          Lu[0] = WR_MIN(Lu[tx], Lu[tx+512]);

          int y1, y2;

          {
            y1 = y2 = 0;
          }

          int tmpin = *u1;

          switch(y1){
          case 0 : printf("0\n"); break;
          case 1 : {printf("1\n");}
          default: printf("default\n"); break;
          }

          switch(y2)
          case 0: printf("0\n");

          const int id = ty*w + tx;

          float *__u1 = &u1[bDimX];
          float *__u2 = (float*) (&(u1[bDimX]));

          float data = tex1[0][0];
          tex1[0][0] = data;

          r_u2 = u2[id];
          r_u3 = u3[id];

          const int nX1 = (tx - sr + w) % w;
          const int nY1 = (ty - sr + h) % h;

          const int nX2 = (tx + bDimX - sr + w) % w;
          const int nY2 = (ty + bDimY - sr + h) % h;

          Lu[ly][lx] = u2[nY1*w + nX1];

          if(lx < 2*sr){
            Lu[ly][lx + bDimX] = u2[nY1*w + nX2];

            if(ly < 2*sr)
              Lu[ly + bDimY][lx + bDimX] = u2[nY2*w + nX2];
          }

          if(ly < 2*sr)
            Lu[ly + bDimY][lx] = u2[nY2*w + nX1];

          a.b = 3;
        }
      }

      // barrier(localMemFence);

      for(int ly = 0; ly < lDimY; ++ly; inner1){
        for(int lx = 0; lx < lDimX; ++lx; inner0){
          const int tx = bx * lDimX + lx;
          const int ty = by * lDimY + ly;

          const int id = ty*w + tx;

          tFloat lap = 0.0;

          if(true)
            blah;
          else if(true)
            blah;
          else
            blah;

          for(int i = 0; i < (2*sr + 1); i++){
            lap += xStencil[i]*Lu[ly + sr][lx + i] + xStencil[i]*Lu[ly + i][lx + sr];
            if(i < 2)
              continue;
            break;
          }

          continue;

          for(int i = 0; i < (2*sr + 1); i++){
            lap += xStencil[i]*Lu[ly + sr][lx + i] + xStencil[i]*Lu[ly + i][lx + sr];
          }

          const tFloat u_n1 = (-tStencil[1]*r_u2 - tStencil[2]*r_u3 + lap)/tStencil[0];

          if((tx == mX) && (ty == mY))
            u1[id] = u_n1 + hatWavelet(currentTime, 1, 2)/tStencil[0];
          else
            u1[id] = u_n1;
        }
      }
    }
  }
}
#endif
<|endoftext|>


<commit_before>#include "llvm/Pass.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/TypeBuilder.h"

using namespace llvm;

namespace {
	struct PointerObservation : public FunctionPass {
		static char ID;
		PointerObservation() : FunctionPass(ID) {}

		bool runOnFunction(Function& f) override {

      // Identify injection points
      DenseSet<Instruction*> pointerInstructions;
      for(BasicBlock &bb : f) {
        	for(Instruction &i : bb) {
        		if (GetElementPtrInst* gep = dyn_cast<GetElementPtrInst>(&i)) {
              pointerInstructions.insert(gep);
        		}
        	}
      }

      // Inject instructions
      for (Instruction *i : pointerInstructions) {
        errs() << "Injections print operation\n";
        IRBuilder<> builder(i);
        Function *printfFunction = getPrintFPrototype(i->getContext(), i->getModule());

        builder.CreateCall(printfFunction, geti8StrVal(*i->getModule(), "test\n", "name"));
      }

			return true;
		}

    Function *getPrintFPrototype(LLVMContext &ctx, Module *mod) {
      FunctionType *printf_type = TypeBuilder<int(char*, ...), false>::get(getGlobalContext());
      Function *func = cast<Function>(mod->getOrInsertFunction("printf", printf_type, AttributeSet().addAttribute(mod->getContext(), 1U, Attribute::NoAlias)));
      return func;
    }

    Constant* geti8StrVal(Module& M, char const* str, Twine const& name) {
      LLVMContext& ctx = getGlobalContext();
      Constant* strConstant = ConstantDataArray::getString(ctx, str);
      GlobalVariable* GVStr =
          new GlobalVariable(M, strConstant->getType(), true,
                             GlobalValue::InternalLinkage, strConstant, name);
      Constant* zero = Constant::getNullValue(IntegerType::getInt32Ty(ctx));
      Constant* indices[] = {zero, zero};
      Constant* strVal = ConstantExpr::getGetElementPtr(Type::getInt8PtrTy(ctx), GVStr, indices, true);
      return strVal;
    }

	};

}

char PointerObservation::ID = 0;
static RegisterPass<PointerObservation> X("PointerObservation", "Injects print calls before pointer operations", false, false);<commit_msg>Corrected strings<commit_after>#include "llvm/Pass.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/TypeBuilder.h"

using namespace llvm;

namespace {
	struct PointerObservation : public FunctionPass {
		static char ID;
		PointerObservation() : FunctionPass(ID) {}

		bool runOnFunction(Function& f) override {

      // Identify injection points
      DenseSet<Instruction*> pointerInstructions;
      for(BasicBlock &bb : f) {
        	for(Instruction &i : bb) {
        		if (GetElementPtrInst* gep = dyn_cast<GetElementPtrInst>(&i)) {
              pointerInstructions.insert(gep);
        		}
        	}
      }

      // Inject instructions
      for (Instruction *i : pointerInstructions) {
        errs() << "Injecting print operation\n";
        IRBuilder<> builder(i);
        Function *printfFunction = getPrintFPrototype(i->getContext(), i->getModule());

        builder.CreateCall(printfFunction, geti8StrVal(*i->getModule(), "Pointer instruction\n", "name"));
      }

			return true;
		}

    Function *getPrintFPrototype(LLVMContext &ctx, Module *mod) {
      FunctionType *printf_type = TypeBuilder<int(char*, ...), false>::get(getGlobalContext());
      Function *func = cast<Function>(mod->getOrInsertFunction("printf", printf_type, AttributeSet().addAttribute(mod->getContext(), 1U, Attribute::NoAlias)));
      return func;
    }

    Constant* geti8StrVal(Module& M, char const* str, Twine const& name) {
      LLVMContext& ctx = getGlobalContext();
      Constant* strConstant = ConstantDataArray::getString(ctx, str);
      GlobalVariable* GVStr =
          new GlobalVariable(M, strConstant->getType(), true,
                             GlobalValue::InternalLinkage, strConstant, name);
      Constant* zero = Constant::getNullValue(IntegerType::getInt32Ty(ctx));
      Constant* indices[] = {zero, zero};
      Constant* strVal = ConstantExpr::getGetElementPtr(Type::getInt8PtrTy(ctx), GVStr, indices, true);
      return strVal;
    }

	};

}

char PointerObservation::ID = 0;
static RegisterPass<PointerObservation> X("PointerObservation", "Injects print calls before pointer operations", false, false);<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "BenchTimer.h"
#include "PictureBenchmark.h"
#include "SkBenchLogger.h"
#include "SkCanvas.h"
#include "SkGraphics.h"
#include "SkMath.h"
#include "SkOSFile.h"
#include "SkPicture.h"
#include "SkStream.h"
#include "SkTArray.h"
#include "picture_utils.h"

const int DEFAULT_REPEATS = 100;

static void usage(const char* argv0) {
    SkDebugf("SkPicture benchmarking tool\n");
    SkDebugf("\n"
"Usage: \n"
"     %s <inputDir>...\n"
"     [--logFile filename][--timers [wcgWC]*][--logPerIter 1|0][--min]\n"
"     [--repeat] \n"
"     [--mode pow2tile minWidth height[] (multi) | record | simple\n"
"             | tile width[] height[] (multi) | playbackCreation]\n"
"     [--pipe]\n"
"     [--device bitmap"
#if SK_SUPPORT_GPU
" | gpu"
#endif
"]"
, argv0);
    SkDebugf("\n\n");
    SkDebugf(
"     inputDir:  A list of directories and files to use as input. Files are\n"
"                expected to have the .skp extension.\n\n"
"     --logFile filename : destination for writing log output, in addition to stdout.\n");
    SkDebugf("     --logPerIter 1|0 : "
             "Log each repeat timer instead of mean, default is disabled.\n");
    SkDebugf("     --min : Print the minimum times (instead of average).\n");
    SkDebugf("     --timers [wcgWC]* : "
             "Display wall, cpu, gpu, truncated wall or truncated cpu time for each picture.\n");
    SkDebugf(
"     --mode pow2tile minWidht height[] (multi) | record | simple\n"
"            | tile width[] height[] (multi) | playbackCreation:\n"
"            Run in the corresponding mode.\n"
"            Default is simple.\n");
    SkDebugf(
"                     pow2tile minWidth height[], Creates tiles with widths\n"
"                                                 that are all a power of two\n"
"                                                 such that they minimize the\n"
"                                                 amount of wasted tile space.\n"
"                                                 minWidth is the minimum width\n"
"                                                 of these tiles and must be a\n"
"                                                 power of two. Simple\n"
"                                                 rendering using these tiles\n"
"                                                 is benchmarked.\n"
"                                                 Append \"multi\" for multithreaded\n"
"                                                 drawing.\n");
    SkDebugf(
"                     record, Benchmark picture to picture recording.\n");
    SkDebugf(
"                     simple, Benchmark a simple rendering.\n");
    SkDebugf(
"                     tile width[] height[], Benchmark simple rendering using\n"
"                                            tiles with the given dimensions.\n"
"                                            Append \"multi\" for multithreaded\n"
"                                            drawing.\n");
    SkDebugf(
"                     playbackCreation, Benchmark creation of the SkPicturePlayback.\n");
    SkDebugf("\n");
    SkDebugf(
"     --pipe: Benchmark SkGPipe rendering. Compatible with tiled, multithreaded rendering.\n");
    SkDebugf(
"     --device bitmap"
#if SK_SUPPORT_GPU
" | gpu"
#endif
": Use the corresponding device. Default is bitmap.\n");
    SkDebugf(
"                     bitmap, Render to a bitmap.\n");
#if SK_SUPPORT_GPU
    SkDebugf(
"                     gpu, Render to the GPU.\n");
#endif
    SkDebugf("\n");
    SkDebugf(
"     --repeat:  "
"Set the number of times to repeat each test."
" Default is %i.\n", DEFAULT_REPEATS);
}

SkBenchLogger gLogger;

static void run_single_benchmark(const SkString& inputPath,
                                 sk_tools::PictureBenchmark& benchmark) {
    SkFILEStream inputStream;

    inputStream.setPath(inputPath.c_str());
    if (!inputStream.isValid()) {
        SkString err;
        err.printf("Could not open file %s\n", inputPath.c_str());
        gLogger.logError(err);
        return;
    }

    SkPicture picture(&inputStream);

    SkString filename;
    sk_tools::get_basename(&filename, inputPath);

    SkString result;
    result.printf("running bench [%i %i] %s ", picture.width(), picture.height(),
                  filename.c_str());
    gLogger.logProgress(result);

    benchmark.run(&picture);
}

static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
                              sk_tools::PictureBenchmark* benchmark) {
    const char* argv0 = argv[0];
    char* const* stop = argv + argc;

    int repeats = DEFAULT_REPEATS;
    sk_tools::PictureRenderer::SkDeviceTypes deviceType =
        sk_tools::PictureRenderer::kBitmap_DeviceType;

    sk_tools::PictureRenderer* renderer = NULL;

    // Create a string to show our current settings.
    // TODO: Make it prettier. Currently it just repeats the command line.
    SkString commandLine("bench_pictures:");
    for (int i = 1; i < argc; i++) {
        commandLine.appendf(" %s", *(argv+i));
    }
    commandLine.append("\n");

    bool usePipe = false;
    bool multiThreaded = false;
    bool useTiles = false;
    const char* widthString = NULL;
    const char* heightString = NULL;
    bool isPowerOf2Mode = false;
    const char* mode = NULL;
    for (++argv; argv < stop; ++argv) {
        if (0 == strcmp(*argv, "--repeat")) {
            ++argv;
            if (argv < stop) {
                repeats = atoi(*argv);
                if (repeats < 1) {
                    gLogger.logError("--repeat must be given a value > 0\n");
                    exit(-1);
                }
            } else {
                gLogger.logError("Missing arg for --repeat\n");
                usage(argv0);
                exit(-1);
            }
        } else if (0 == strcmp(*argv, "--pipe")) {
            usePipe = true;
        } else if (0 == strcmp(*argv, "--logFile")) {
            argv++;
            if (argv < stop) {
                if (!gLogger.SetLogFile(*argv)) {
                    SkString str;
                    str.printf("Could not open %s for writing.", *argv);
                    gLogger.logError(str);
                    usage(argv0);
                    exit(-1);
                }
            } else {
                gLogger.logError("Missing arg for --logFile\n");
                usage(argv0);
                exit(-1);
            }
        } else if (0 == strcmp(*argv, "--mode")) {

            ++argv;
            if (argv >= stop) {
                gLogger.logError("Missing mode for --mode\n");
                usage(argv0);
                exit(-1);
            }

            if (0 == strcmp(*argv, "record")) {
                renderer = SkNEW(sk_tools::RecordPictureRenderer);
            } else if (0 == strcmp(*argv, "simple")) {
                renderer = SkNEW(sk_tools::SimplePictureRenderer);
            } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) {
                useTiles = true;
                mode = *argv;

                if (0 == strcmp(*argv, "pow2tile")) {
                    isPowerOf2Mode = true;
                }

                ++argv;
                if (argv >= stop) {
                    SkString err;
                    err.printf("Missing width for --mode %s\n", mode);
                    gLogger.logError(err);
                    usage(argv0);
                    exit(-1);
                }

                widthString = *argv;
                ++argv;
                if (argv >= stop) {
                    gLogger.logError("Missing height for --mode tile\n");
                    usage(argv0);
                    exit(-1);
                }
                heightString = *argv;

                ++argv;
                if (argv < stop && 0 == strcmp(*argv, "multi")) {
                    multiThreaded = true;
                } else {
                    --argv;
                }
            } else if (0 == strcmp(*argv, "playbackCreation")) {
                renderer = SkNEW(sk_tools::PlaybackCreationRenderer);
            } else {
                SkString err;
                err.printf("%s is not a valid mode for --mode\n", *argv);
                gLogger.logError(err);
                usage(argv0);
                exit(-1);
            }
        }  else if (0 == strcmp(*argv, "--device")) {
            ++argv;
            if (argv >= stop) {
                gLogger.logError("Missing mode for --deivce\n");
                usage(argv0);
                exit(-1);
            }

            if (0 == strcmp(*argv, "bitmap")) {
                deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
            }
#if SK_SUPPORT_GPU
            else if (0 == strcmp(*argv, "gpu")) {
                deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
            }
#endif
            else {
                SkString err;
                err.printf("%s is not a valid mode for --device\n", *argv);
                gLogger.logError(err);
                usage(argv0);
                exit(-1);
            }
        } else if (0 == strcmp(*argv, "--timers")) {
            ++argv;
            if (argv < stop) {
                bool timerWall = false;
                bool truncatedTimerWall = false;
                bool timerCpu = false;
                bool truncatedTimerCpu = false;
                bool timerGpu = false;
                for (char* t = *argv; *t; ++t) {
                    switch (*t) {
                        case 'w':
                            timerWall = true;
                            break;
                        case 'c':
                            timerCpu = true;
                            break;
                        case 'W':
                            truncatedTimerWall = true;
                            break;
                        case 'C':
                            truncatedTimerCpu = true;
                            break;
                        case 'g':
                            timerGpu = true;
                            break;
                        default: {
                            break;
                        }
                    }
                }
                benchmark->setTimersToShow(timerWall, truncatedTimerWall, timerCpu,
                                           truncatedTimerCpu, timerGpu);
            } else {
                gLogger.logError("Missing arg for --timers\n");
                usage(argv0);
                exit(-1);
            }
        } else if (0 == strcmp(*argv, "--min")) {
            benchmark->setPrintMin(true);
        } else if (0 == strcmp(*argv, "--logPerIter")) {
            ++argv;
            if (argv < stop) {
                bool log = atoi(*argv) != 0;
                benchmark->setLogPerIter(log);
            } else {
                gLogger.logError("Missing arg for --logPerIter\n");
                usage(argv0);
                exit(-1);
            }
        } else if (0 == strcmp(*argv, "--help") || 0 == strcmp(*argv, "-h")) {
            usage(argv0);
            exit(0);
        } else {
            inputs->push_back(SkString(*argv));
        }
    }

    if (useTiles) {
        SkASSERT(NULL == renderer);
        sk_tools::TiledPictureRenderer* tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
        if (isPowerOf2Mode) {
            int minWidth = atoi(widthString);
            if (!SkIsPow2(minWidth) || minWidth < 0) {
                tiledRenderer->unref();
                SkString err;
                err.printf("-mode %s must be given a width"
                         " value that is a power of two\n", mode);
                gLogger.logError(err);
                exit(-1);
            }
            tiledRenderer->setTileMinPowerOf2Width(minWidth);
        } else if (sk_tools::is_percentage(widthString)) {
            tiledRenderer->setTileWidthPercentage(atof(widthString));
            if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
                tiledRenderer->unref();
                gLogger.logError("--mode tile must be given a width percentage > 0\n");
                exit(-1);
            }
        } else {
            tiledRenderer->setTileWidth(atoi(widthString));
            if (!(tiledRenderer->getTileWidth() > 0)) {
                tiledRenderer->unref();
                gLogger.logError("--mode tile must be given a width > 0\n");
                exit(-1);
            }
        }

        if (sk_tools::is_percentage(heightString)) {
            tiledRenderer->setTileHeightPercentage(atof(heightString));
            if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
                tiledRenderer->unref();
                gLogger.logError("--mode tile must be given a height percentage > 0\n");
                exit(-1);
            }
        } else {
            tiledRenderer->setTileHeight(atoi(heightString));
            if (!(tiledRenderer->getTileHeight() > 0)) {
                tiledRenderer->unref();
                gLogger.logError("--mode tile must be given a height > 0\n");
                exit(-1);
            }
        }
        tiledRenderer->setMultiThreaded(multiThreaded);
        tiledRenderer->setUsePipe(usePipe);
        renderer = tiledRenderer;
    } else if (usePipe) {
        renderer = SkNEW(sk_tools::PipePictureRenderer);
    }
    if (inputs->count() < 1) {
        SkDELETE(benchmark);
        usage(argv0);
        exit(-1);
    }

    if (NULL == renderer) {
        renderer = SkNEW(sk_tools::SimplePictureRenderer);
    }
    benchmark->setRenderer(renderer)->unref();
    benchmark->setRepeats(repeats);
    benchmark->setDeviceType(deviceType);
    benchmark->setLogger(&gLogger);
    // Report current settings:
    gLogger.logProgress(commandLine);
}

static void process_input(const SkString& input, sk_tools::PictureBenchmark& benchmark) {
    SkOSFile::Iter iter(input.c_str(), "skp");
    SkString inputFilename;

    if (iter.next(&inputFilename)) {
        do {
            SkString inputPath;
            sk_tools::make_filepath(&inputPath, input, inputFilename);
            run_single_benchmark(inputPath, benchmark);
        } while(iter.next(&inputFilename));
    } else {
          run_single_benchmark(input, benchmark);
    }
}

int main(int argc, char* const argv[]) {
#ifdef SK_ENABLE_INST_COUNT
    gPrintInstCount = true;
#endif
    SkAutoGraphics ag;

    SkTArray<SkString> inputs;
    sk_tools::PictureBenchmark benchmark;

    parse_commandline(argc, argv, &inputs, &benchmark);

    for (int i = 0; i < inputs.count(); ++i) {
        process_input(inputs[i], benchmark);
    }
}
<commit_msg>Do not exit on failure to open logFile<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "BenchTimer.h"
#include "PictureBenchmark.h"
#include "SkBenchLogger.h"
#include "SkCanvas.h"
#include "SkGraphics.h"
#include "SkMath.h"
#include "SkOSFile.h"
#include "SkPicture.h"
#include "SkStream.h"
#include "SkTArray.h"
#include "picture_utils.h"

const int DEFAULT_REPEATS = 100;

static void usage(const char* argv0) {
    SkDebugf("SkPicture benchmarking tool\n");
    SkDebugf("\n"
"Usage: \n"
"     %s <inputDir>...\n"
"     [--logFile filename][--timers [wcgWC]*][--logPerIter 1|0][--min]\n"
"     [--repeat] \n"
"     [--mode pow2tile minWidth height[] (multi) | record | simple\n"
"             | tile width[] height[] (multi) | playbackCreation]\n"
"     [--pipe]\n"
"     [--device bitmap"
#if SK_SUPPORT_GPU
" | gpu"
#endif
"]"
, argv0);
    SkDebugf("\n\n");
    SkDebugf(
"     inputDir:  A list of directories and files to use as input. Files are\n"
"                expected to have the .skp extension.\n\n"
"     --logFile filename : destination for writing log output, in addition to stdout.\n");
    SkDebugf("     --logPerIter 1|0 : "
             "Log each repeat timer instead of mean, default is disabled.\n");
    SkDebugf("     --min : Print the minimum times (instead of average).\n");
    SkDebugf("     --timers [wcgWC]* : "
             "Display wall, cpu, gpu, truncated wall or truncated cpu time for each picture.\n");
    SkDebugf(
"     --mode pow2tile minWidht height[] (multi) | record | simple\n"
"            | tile width[] height[] (multi) | playbackCreation:\n"
"            Run in the corresponding mode.\n"
"            Default is simple.\n");
    SkDebugf(
"                     pow2tile minWidth height[], Creates tiles with widths\n"
"                                                 that are all a power of two\n"
"                                                 such that they minimize the\n"
"                                                 amount of wasted tile space.\n"
"                                                 minWidth is the minimum width\n"
"                                                 of these tiles and must be a\n"
"                                                 power of two. Simple\n"
"                                                 rendering using these tiles\n"
"                                                 is benchmarked.\n"
"                                                 Append \"multi\" for multithreaded\n"
"                                                 drawing.\n");
    SkDebugf(
"                     record, Benchmark picture to picture recording.\n");
    SkDebugf(
"                     simple, Benchmark a simple rendering.\n");
    SkDebugf(
"                     tile width[] height[], Benchmark simple rendering using\n"
"                                            tiles with the given dimensions.\n"
"                                            Append \"multi\" for multithreaded\n"
"                                            drawing.\n");
    SkDebugf(
"                     playbackCreation, Benchmark creation of the SkPicturePlayback.\n");
    SkDebugf("\n");
    SkDebugf(
"     --pipe: Benchmark SkGPipe rendering. Compatible with tiled, multithreaded rendering.\n");
    SkDebugf(
"     --device bitmap"
#if SK_SUPPORT_GPU
" | gpu"
#endif
": Use the corresponding device. Default is bitmap.\n");
    SkDebugf(
"                     bitmap, Render to a bitmap.\n");
#if SK_SUPPORT_GPU
    SkDebugf(
"                     gpu, Render to the GPU.\n");
#endif
    SkDebugf("\n");
    SkDebugf(
"     --repeat:  "
"Set the number of times to repeat each test."
" Default is %i.\n", DEFAULT_REPEATS);
}

SkBenchLogger gLogger;

static void run_single_benchmark(const SkString& inputPath,
                                 sk_tools::PictureBenchmark& benchmark) {
    SkFILEStream inputStream;

    inputStream.setPath(inputPath.c_str());
    if (!inputStream.isValid()) {
        SkString err;
        err.printf("Could not open file %s\n", inputPath.c_str());
        gLogger.logError(err);
        return;
    }

    SkPicture picture(&inputStream);

    SkString filename;
    sk_tools::get_basename(&filename, inputPath);

    SkString result;
    result.printf("running bench [%i %i] %s ", picture.width(), picture.height(),
                  filename.c_str());
    gLogger.logProgress(result);

    benchmark.run(&picture);
}

static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
                              sk_tools::PictureBenchmark* benchmark) {
    const char* argv0 = argv[0];
    char* const* stop = argv + argc;

    int repeats = DEFAULT_REPEATS;
    sk_tools::PictureRenderer::SkDeviceTypes deviceType =
        sk_tools::PictureRenderer::kBitmap_DeviceType;

    sk_tools::PictureRenderer* renderer = NULL;

    // Create a string to show our current settings.
    // TODO: Make it prettier. Currently it just repeats the command line.
    SkString commandLine("bench_pictures:");
    for (int i = 1; i < argc; i++) {
        commandLine.appendf(" %s", *(argv+i));
    }
    commandLine.append("\n");

    bool usePipe = false;
    bool multiThreaded = false;
    bool useTiles = false;
    const char* widthString = NULL;
    const char* heightString = NULL;
    bool isPowerOf2Mode = false;
    const char* mode = NULL;
    for (++argv; argv < stop; ++argv) {
        if (0 == strcmp(*argv, "--repeat")) {
            ++argv;
            if (argv < stop) {
                repeats = atoi(*argv);
                if (repeats < 1) {
                    gLogger.logError("--repeat must be given a value > 0\n");
                    exit(-1);
                }
            } else {
                gLogger.logError("Missing arg for --repeat\n");
                usage(argv0);
                exit(-1);
            }
        } else if (0 == strcmp(*argv, "--pipe")) {
            usePipe = true;
        } else if (0 == strcmp(*argv, "--logFile")) {
            argv++;
            if (argv < stop) {
                if (!gLogger.SetLogFile(*argv)) {
                    SkString str;
                    str.printf("Could not open %s for writing.", *argv);
                    gLogger.logError(str);
                    usage(argv0);
                    // TODO(borenet): We're disabling this for now, due to
                    // write-protected Android devices.  The very short-term
                    // solution is to ignore the fact that we have no log file.
                    //exit(-1);
                }
            } else {
                gLogger.logError("Missing arg for --logFile\n");
                usage(argv0);
                exit(-1);
            }
        } else if (0 == strcmp(*argv, "--mode")) {

            ++argv;
            if (argv >= stop) {
                gLogger.logError("Missing mode for --mode\n");
                usage(argv0);
                exit(-1);
            }

            if (0 == strcmp(*argv, "record")) {
                renderer = SkNEW(sk_tools::RecordPictureRenderer);
            } else if (0 == strcmp(*argv, "simple")) {
                renderer = SkNEW(sk_tools::SimplePictureRenderer);
            } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) {
                useTiles = true;
                mode = *argv;

                if (0 == strcmp(*argv, "pow2tile")) {
                    isPowerOf2Mode = true;
                }

                ++argv;
                if (argv >= stop) {
                    SkString err;
                    err.printf("Missing width for --mode %s\n", mode);
                    gLogger.logError(err);
                    usage(argv0);
                    exit(-1);
                }

                widthString = *argv;
                ++argv;
                if (argv >= stop) {
                    gLogger.logError("Missing height for --mode tile\n");
                    usage(argv0);
                    exit(-1);
                }
                heightString = *argv;

                ++argv;
                if (argv < stop && 0 == strcmp(*argv, "multi")) {
                    multiThreaded = true;
                } else {
                    --argv;
                }
            } else if (0 == strcmp(*argv, "playbackCreation")) {
                renderer = SkNEW(sk_tools::PlaybackCreationRenderer);
            } else {
                SkString err;
                err.printf("%s is not a valid mode for --mode\n", *argv);
                gLogger.logError(err);
                usage(argv0);
                exit(-1);
            }
        }  else if (0 == strcmp(*argv, "--device")) {
            ++argv;
            if (argv >= stop) {
                gLogger.logError("Missing mode for --device\n");
                usage(argv0);
                exit(-1);
            }

            if (0 == strcmp(*argv, "bitmap")) {
                deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
            }
#if SK_SUPPORT_GPU
            else if (0 == strcmp(*argv, "gpu")) {
                deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
            }
#endif
            else {
                SkString err;
                err.printf("%s is not a valid mode for --device\n", *argv);
                gLogger.logError(err);
                usage(argv0);
                exit(-1);
            }
        } else if (0 == strcmp(*argv, "--timers")) {
            ++argv;
            if (argv < stop) {
                bool timerWall = false;
                bool truncatedTimerWall = false;
                bool timerCpu = false;
                bool truncatedTimerCpu = false;
                bool timerGpu = false;
                for (char* t = *argv; *t; ++t) {
                    switch (*t) {
                        case 'w':
                            timerWall = true;
                            break;
                        case 'c':
                            timerCpu = true;
                            break;
                        case 'W':
                            truncatedTimerWall = true;
                            break;
                        case 'C':
                            truncatedTimerCpu = true;
                            break;
                        case 'g':
                            timerGpu = true;
                            break;
                        default: {
                            break;
                        }
                    }
                }
                benchmark->setTimersToShow(timerWall, truncatedTimerWall, timerCpu,
                                           truncatedTimerCpu, timerGpu);
            } else {
                gLogger.logError("Missing arg for --timers\n");
                usage(argv0);
                exit(-1);
            }
        } else if (0 == strcmp(*argv, "--min")) {
            benchmark->setPrintMin(true);
        } else if (0 == strcmp(*argv, "--logPerIter")) {
            ++argv;
            if (argv < stop) {
                bool log = atoi(*argv) != 0;
                benchmark->setLogPerIter(log);
            } else {
                gLogger.logError("Missing arg for --logPerIter\n");
                usage(argv0);
                exit(-1);
            }
        } else if (0 == strcmp(*argv, "--help") || 0 == strcmp(*argv, "-h")) {
            usage(argv0);
            exit(0);
        } else {
            inputs->push_back(SkString(*argv));
        }
    }

    if (useTiles) {
        SkASSERT(NULL == renderer);
        sk_tools::TiledPictureRenderer* tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
        if (isPowerOf2Mode) {
            int minWidth = atoi(widthString);
            if (!SkIsPow2(minWidth) || minWidth < 0) {
                tiledRenderer->unref();
                SkString err;
                err.printf("-mode %s must be given a width"
                         " value that is a power of two\n", mode);
                gLogger.logError(err);
                exit(-1);
            }
            tiledRenderer->setTileMinPowerOf2Width(minWidth);
        } else if (sk_tools::is_percentage(widthString)) {
            tiledRenderer->setTileWidthPercentage(atof(widthString));
            if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
                tiledRenderer->unref();
                gLogger.logError("--mode tile must be given a width percentage > 0\n");
                exit(-1);
            }
        } else {
            tiledRenderer->setTileWidth(atoi(widthString));
            if (!(tiledRenderer->getTileWidth() > 0)) {
                tiledRenderer->unref();
                gLogger.logError("--mode tile must be given a width > 0\n");
                exit(-1);
            }
        }

        if (sk_tools::is_percentage(heightString)) {
            tiledRenderer->setTileHeightPercentage(atof(heightString));
            if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
                tiledRenderer->unref();
                gLogger.logError("--mode tile must be given a height percentage > 0\n");
                exit(-1);
            }
        } else {
            tiledRenderer->setTileHeight(atoi(heightString));
            if (!(tiledRenderer->getTileHeight() > 0)) {
                tiledRenderer->unref();
                gLogger.logError("--mode tile must be given a height > 0\n");
                exit(-1);
            }
        }
        tiledRenderer->setMultiThreaded(multiThreaded);
        tiledRenderer->setUsePipe(usePipe);
        renderer = tiledRenderer;
    } else if (usePipe) {
        renderer = SkNEW(sk_tools::PipePictureRenderer);
    }
    if (inputs->count() < 1) {
        SkDELETE(benchmark);
        usage(argv0);
        exit(-1);
    }

    if (NULL == renderer) {
        renderer = SkNEW(sk_tools::SimplePictureRenderer);
    }
    benchmark->setRenderer(renderer)->unref();
    benchmark->setRepeats(repeats);
    benchmark->setDeviceType(deviceType);
    benchmark->setLogger(&gLogger);
    // Report current settings:
    gLogger.logProgress(commandLine);
}

static void process_input(const SkString& input, sk_tools::PictureBenchmark& benchmark) {
    SkOSFile::Iter iter(input.c_str(), "skp");
    SkString inputFilename;

    if (iter.next(&inputFilename)) {
        do {
            SkString inputPath;
            sk_tools::make_filepath(&inputPath, input, inputFilename);
            run_single_benchmark(inputPath, benchmark);
        } while(iter.next(&inputFilename));
    } else {
          run_single_benchmark(input, benchmark);
    }
}

int main(int argc, char* const argv[]) {
#ifdef SK_ENABLE_INST_COUNT
    gPrintInstCount = true;
#endif
    SkAutoGraphics ag;

    SkTArray<SkString> inputs;
    sk_tools::PictureBenchmark benchmark;

    parse_commandline(argc, argv, &inputs, &benchmark);

    for (int i = 0; i < inputs.count(); ++i) {
        process_input(inputs[i], benchmark);
    }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <getopt.h>
#include <algorithm>
#include <memory>

#include <zcm/zcm-cpp.hpp>
#include <zcm/zcm_coretypes.h>

#include "zcm/json/json.h"

#include "util/TranscoderPluginDb.hpp"

using namespace std;

struct Args
{
    string inlog       = "";
    string outlog      = "";
    string plugin_path = "";
    bool debug         = false;

    bool parse(int argc, char *argv[])
    {
        // set some defaults
        const char *optstring = "l:o:p:dh";
        struct option long_opts[] = {
            { "log",         required_argument, 0, 'l' },
            { "output",      required_argument, 0, 'o' },
            { "plugin-path", required_argument, 0, 'p' },
            { "debug",       no_argument,       0, 'd' },
            { "help",        no_argument,       0, 'h' },
            { 0, 0, 0, 0 }
        };

        int c;
        while ((c = getopt_long (argc, argv, optstring, long_opts, 0)) >= 0) {
            switch (c) {
                case 'l': inlog       = string(optarg); break;
                case 'o': outlog      = string(optarg); break;
                case 'p': plugin_path = string(optarg); break;
                case 'd': debug       = true;           break;
                case 'h': default: usage(); return false;
            };
        }

        if (inlog == "") {
            cerr << "Please specify logfile input" << endl;
            return false;
        }

        if (outlog  == "") {
            cerr << "Please specify log file output" << endl;
            return false;
        }

        const char* plugin_path_env = getenv("ZCM_LOG_TRANSCODER_PLUGINS_PATH");
        if (plugin_path == "" && plugin_path_env) plugin_path = plugin_path_env;
        if (plugin_path == "") {
            cerr << "No plugin specified. Nothing to do" << endl;
            return false;
        }

        return true;
    }

    void usage()
    {
        cout << "usage: zcm-log-transcoder [options]" << endl
             << "" << endl
             << "    Convert messages in one log file from one zcm type to another" << endl
             << "" << endl
             << "Example:" << endl
             << "    zcm-log-transcoder -l zcm.log -o zcmout.log -p path/to/plugin.so" << endl
             << "" << endl
             << "Options:" << endl
             << "" << endl
             << "  -h, --help              Shows this help text and exits" << endl
             << "  -l, --log=logfile       Input log to convert" << endl
             << "  -o, --output=logfile    Output converted log file" << endl
             << "  -p, --plugin-path=path  Path to shared library containing transcoder plugins" << endl
             << "                          Can also be specified via the environment variable" << endl
             << "                          ZCM_LOG_TRANSCODER_PLUGINS_PATH" << endl
             << "  -d, --debug             Run a dry run to ensure proper transcoder setup" << endl
             << endl << endl;
    }
};

int main(int argc, char* argv[])
{
    Args args;
    if (!args.parse(argc, argv)) return 1;

    zcm::LogFile inlog(args.inlog, "r");
    if (!inlog.good()) {
        cerr << "Unable to open input zcm log: " << args.inlog << endl;
        return 1;
    }
    fseeko(inlog.getFilePtr(), 0, SEEK_END);
    off64_t logSize = ftello(inlog.getFilePtr());
    fseeko(inlog.getFilePtr(), 0, SEEK_SET);

    zcm::LogFile outlog(args.outlog, "w");
    if (!outlog.good()) {
        cerr << "Unable to open output zcm log: " << args.inlog << endl;
        return 1;
    }

    vector<zcm::TranscoderPlugin*> plugins;
    TranscoderPluginDb pluginDb(args.plugin_path, args.debug);
    vector<const zcm::TranscoderPlugin*> dbPlugins = pluginDb.getPlugins();
    if (dbPlugins.empty()) {
        cerr << "Couldn't find any plugins. Aborting." << endl;
        return 1;
    }
    vector<string> dbPluginNames = pluginDb.getPluginNames();
    for (size_t i = 0; i < dbPlugins.size(); ++i) {
        plugins.push_back((zcm::TranscoderPlugin*) dbPlugins[i]);
        if (args.debug) cout << "Loaded plugin: " << dbPluginNames[i] << endl;
    }

    if (args.debug) return 0;

    size_t numInEvents = 0, numOutEvents = 0;
    const zcm::LogEvent* evt;
    off64_t offset;

    while (1) {
        offset = ftello(inlog.getFilePtr());

        static int lastPrintPercent = 0;
        int percent = (100.0 * offset / (logSize == 0 ? 1 : logSize)) * 100;
        if (percent != lastPrintPercent) {
            cout << "\r" << "Percent Complete: " << (percent / 100) << flush;
            lastPrintPercent = percent;
        }

        evt = inlog.readNextEvent();
        if (evt == nullptr) break;

        vector<const zcm::LogEvent*> evts;

        if (!plugins.empty()) {
            int64_t msg_hash;
            __int64_t_decode_array(evt->data, 0, 8, &msg_hash, 1);

            for (auto& p : plugins) {
                vector<const zcm::LogEvent*> pevts =
                    p->transcodeEvent((uint64_t) msg_hash, evt);
                evts.insert(evts.end(), pevts.begin(), pevts.end());
            }
        }

        if (evts.empty()) evts.push_back(evt);

        for (auto* evt : evts) {
            if (!evt) continue;
            outlog.writeEvent(evt);
            numOutEvents++;
        }

        numInEvents++;
    }
    cout << endl;

    inlog.close();
    outlog.close();

    cout << "Transcoded " << numInEvents << " events into " << numOutEvents << " events" << endl;
    return 0;
}
<commit_msg>Fixed printout for transcoder<commit_after>#include <iostream>
#include <fstream>
#include <getopt.h>
#include <algorithm>
#include <memory>

#include <zcm/zcm-cpp.hpp>
#include <zcm/zcm_coretypes.h>

#include "zcm/json/json.h"

#include "util/TranscoderPluginDb.hpp"

using namespace std;

struct Args
{
    string inlog       = "";
    string outlog      = "";
    string plugin_path = "";
    bool debug         = false;

    bool parse(int argc, char *argv[])
    {
        // set some defaults
        const char *optstring = "l:o:p:dh";
        struct option long_opts[] = {
            { "log",         required_argument, 0, 'l' },
            { "output",      required_argument, 0, 'o' },
            { "plugin-path", required_argument, 0, 'p' },
            { "debug",       no_argument,       0, 'd' },
            { "help",        no_argument,       0, 'h' },
            { 0, 0, 0, 0 }
        };

        int c;
        while ((c = getopt_long (argc, argv, optstring, long_opts, 0)) >= 0) {
            switch (c) {
                case 'l': inlog       = string(optarg); break;
                case 'o': outlog      = string(optarg); break;
                case 'p': plugin_path = string(optarg); break;
                case 'd': debug       = true;           break;
                case 'h': default: usage(); return false;
            };
        }

        if (inlog == "") {
            cerr << "Please specify logfile input" << endl;
            return false;
        }

        if (outlog  == "") {
            cerr << "Please specify log file output" << endl;
            return false;
        }

        const char* plugin_path_env = getenv("ZCM_LOG_TRANSCODER_PLUGINS_PATH");
        if (plugin_path == "" && plugin_path_env) plugin_path = plugin_path_env;
        if (plugin_path == "") {
            cerr << "No plugin specified. Nothing to do" << endl;
            return false;
        }

        return true;
    }

    void usage()
    {
        cout << "usage: zcm-log-transcoder [options]" << endl
             << "" << endl
             << "    Convert messages in one log file from one zcm type to another" << endl
             << "" << endl
             << "Example:" << endl
             << "    zcm-log-transcoder -l zcm.log -o zcmout.log -p path/to/plugin.so" << endl
             << "" << endl
             << "Options:" << endl
             << "" << endl
             << "  -h, --help              Shows this help text and exits" << endl
             << "  -l, --log=logfile       Input log to convert" << endl
             << "  -o, --output=logfile    Output converted log file" << endl
             << "  -p, --plugin-path=path  Path to shared library containing transcoder plugins" << endl
             << "                          Can also be specified via the environment variable" << endl
             << "                          ZCM_LOG_TRANSCODER_PLUGINS_PATH" << endl
             << "  -d, --debug             Run a dry run to ensure proper transcoder setup" << endl
             << endl << endl;
    }
};

int main(int argc, char* argv[])
{
    Args args;
    if (!args.parse(argc, argv)) return 1;

    zcm::LogFile inlog(args.inlog, "r");
    if (!inlog.good()) {
        cerr << "Unable to open input zcm log: " << args.inlog << endl;
        return 1;
    }
    fseeko(inlog.getFilePtr(), 0, SEEK_END);
    off64_t logSize = ftello(inlog.getFilePtr());
    fseeko(inlog.getFilePtr(), 0, SEEK_SET);

    zcm::LogFile outlog(args.outlog, "w");
    if (!outlog.good()) {
        cerr << "Unable to open output zcm log: " << args.outlog << endl;
        return 1;
    }

    vector<zcm::TranscoderPlugin*> plugins;
    TranscoderPluginDb pluginDb(args.plugin_path, args.debug);
    vector<const zcm::TranscoderPlugin*> dbPlugins = pluginDb.getPlugins();
    if (dbPlugins.empty()) {
        cerr << "Couldn't find any plugins. Aborting." << endl;
        return 1;
    }
    vector<string> dbPluginNames = pluginDb.getPluginNames();
    for (size_t i = 0; i < dbPlugins.size(); ++i) {
        plugins.push_back((zcm::TranscoderPlugin*) dbPlugins[i]);
        if (args.debug) cout << "Loaded plugin: " << dbPluginNames[i] << endl;
    }

    if (args.debug) return 0;

    size_t numInEvents = 0, numOutEvents = 0;
    const zcm::LogEvent* evt;
    off64_t offset;

    while (1) {
        offset = ftello(inlog.getFilePtr());

        static int lastPrintPercent = 0;
        int percent = (100.0 * offset / (logSize == 0 ? 1 : logSize)) * 100;
        if (percent != lastPrintPercent) {
            cout << "\r" << "Percent Complete: " << (percent / 100) << flush;
            lastPrintPercent = percent;
        }

        evt = inlog.readNextEvent();
        if (evt == nullptr) break;

        vector<const zcm::LogEvent*> evts;

        if (!plugins.empty()) {
            int64_t msg_hash;
            __int64_t_decode_array(evt->data, 0, 8, &msg_hash, 1);

            for (auto& p : plugins) {
                vector<const zcm::LogEvent*> pevts =
                    p->transcodeEvent((uint64_t) msg_hash, evt);
                evts.insert(evts.end(), pevts.begin(), pevts.end());
            }
        }

        if (evts.empty()) evts.push_back(evt);

        for (auto* evt : evts) {
            if (!evt) continue;
            outlog.writeEvent(evt);
            numOutEvents++;
        }

        numInEvents++;
    }
    cout << endl;

    inlog.close();
    outlog.close();

    cout << "Transcoded " << numInEvents << " events into " << numOutEvents << " events" << endl;
    return 0;
}
<|endoftext|>


<commit_before>#include <windows.h>
#include <vector>
#include "ddraw7proxy.hpp"

#include "detours.h"

/*static*/ DirectSurface7Proxy* DirectSurface7Proxy::g_Primary;
/*static*/ DirectSurface7Proxy* DirectSurface7Proxy::g_BackBuffer;
/*static*/ DirectSurface7Proxy* DirectSurface7Proxy::g_FakePrimary;

HINSTANCE gDllInstance = NULL;
HRESULT WINAPI NewDirectDrawCreate(GUID* lpGUID, IDirectDraw** lplpDD, IUnknown* pUnkOuter);
using TDirectDrawCreate = decltype(&NewDirectDrawCreate);

inline void FatalExit(const char* msg)
{
    ::MessageBox(NULL, msg, "Error", MB_OK | MB_ICONEXCLAMATION);
    exit(-1);
}

static HMODULE LoadRealDDrawDll()
{
    char infoBuf[MAX_PATH] = {};
    ::GetSystemDirectory(infoBuf, MAX_PATH);

    strcat_s(infoBuf, "\\ddraw.dll");

    const HMODULE hRealDll = ::LoadLibrary(infoBuf);
    if (!hRealDll)
    {
        FatalExit("Can't load or find real DDraw.dll");
    }
    return hRealDll;
}

template<class T>
inline T TGetProcAddress(HMODULE hDll, const char* func)
{
    #pragma warning(suppress: 4191)
    return reinterpret_cast<T>(::GetProcAddress(hDll, func));
}

static TDirectDrawCreate GetFunctionPointersToRealDDrawFunctions(HMODULE hRealDll)
{
    auto ptr = TGetProcAddress<TDirectDrawCreate>(hRealDll, "DirectDrawCreate");
    if (!ptr)
    {
        FatalExit("Can't find DirectDrawCreate function in real dll");
    }
    return ptr;
}

// =================
WNDPROC g_pOldProc = 0;

static LRESULT CALLBACK NewWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
        break;

    case WM_ERASEBKGND:
    {
        RECT rcWin;
        HDC hDC = GetDC(hwnd);
        GetClipBox((HDC)wParam, &rcWin);
        FillRect(hDC, &rcWin, GetSysColorBrush(COLOR_DESKTOP));  // hBrush can be obtained by calling GetWindowLong()
    }
    return TRUE;

    case WM_GETICON:
    case WM_MOUSEACTIVATE:
    case WM_NCLBUTTONDOWN:
    case WM_NCMOUSELEAVE:
    case WM_KILLFOCUS:
    case WM_SETFOCUS:
    case WM_ACTIVATEAPP:
    case WM_NCHITTEST:
    case WM_ACTIVATE:
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_LBUTTONDBLCLK:
    case WM_NCCALCSIZE:
    case WM_MOVE:
    case WM_WINDOWPOSCHANGED:
    case WM_WINDOWPOSCHANGING:
    case WM_NCMOUSEMOVE:
    case WM_MOUSEMOVE:
        return DefWindowProc(hwnd, message, wParam, lParam);

    case WM_SETCURSOR:
    {
        // Set the cursor so the resize cursor or whatever doesn't "stick"
        // when we move the mouse over the game window.
        static HCURSOR cur = LoadCursor(0, IDC_ARROW);
        if (cur)
        {
            SetCursor(cur);
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        BeginPaint(hwnd, &ps);
        EndPaint(hwnd, &ps);

    }
    return FALSE;
    }

    return g_pOldProc(hwnd, message, wParam, lParam);
}

static void CenterWnd(HWND wnd)
{
    RECT r, r1;
    GetWindowRect(wnd, &r);
    GetWindowRect(GetDesktopWindow(), &r1);
    MoveWindow(wnd, ((r1.right - r1.left) - (r.right - r.left)) / 2,
        ((r1.bottom - r1.top) - (r.bottom - r.top)) / 2,
        (r.right - r.left), (r.bottom - r.top), 0);
}

static void SubClassWindow()
{
    HWND wnd = FindWindow("ABE_WINCLASS", NULL);
    g_pOldProc = (WNDPROC)SetWindowLong(wnd, GWL_WNDPROC, (LONG)NewWindowProc);

    for (int i = 0; i < 70; ++i)
    {
        ShowCursor(TRUE);
    }

    RECT rc;
    SetRect(&rc, 0, 0, 640, 480);
    AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW | WS_VISIBLE, TRUE, 0);
    SetWindowPos(wnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
        SWP_SHOWWINDOW);

    ShowWindow(wnd, SW_HIDE);

    CenterWnd(wnd);

    ShowWindow(wnd, SW_SHOW);

    InvalidateRect(GetDesktopWindow(), NULL, TRUE);
}

static void PatchWindowTitle()
{
    HWND wnd = FindWindow("ABE_WINCLASS", NULL);
    if (wnd)
    {
        const int length = GetWindowTextLength(wnd) + 1;
        std::vector< char > titleBuffer(length+1);
        if (GetWindowText(wnd, titleBuffer.data(), length))
        {
            std::string titleStr(titleBuffer.data());
            titleStr += " under ALIVE hook";
            SetWindowText(wnd, titleStr.c_str());
        }
    }
}

template<class FunctionType, class RealFunctionType = FunctionType>
class Hook
{
public:
    Hook(const Hook&) = delete;
    Hook& operator = (const Hook&) = delete;
    explicit Hook(FunctionType oldFunc)
        : mOldPtr(oldFunc)
    {

    }

    explicit Hook(DWORD oldFunc)
        : mOldPtr(reinterpret_cast<FunctionType>(oldFunc))
    {

    }

    void Install(FunctionType newFunc)
    {
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach(&(PVOID&)mOldPtr, newFunc);
        if (DetourTransactionCommit() != NO_ERROR)
        {
            FatalExit("detouring failed");
        }
    }

    RealFunctionType Real() const
    {
        #pragma warning(suppress: 4191)
        return reinterpret_cast<RealFunctionType>(mOldPtr);
    }

private:
    FunctionType mOldPtr;
};

static int __fastcall set_first_camera_hook(void *thisPtr, void*, __int16 a2, __int16 a3, __int16 a4, __int16 a5, __int16 a6, __int16 a7);
typedef int(__thiscall* set_first_camera_thiscall)(void *thisPtr, __int16 a2, __int16 a3, __int16 a4, __int16 a5, __int16 a6, __int16 a7);

namespace Hooks
{
    Hook<decltype(&::SetWindowLongA)> SetWindowLong(::SetWindowLongA);
    Hook<decltype(&::set_first_camera_hook), set_first_camera_thiscall> set_first_camera(0x00401415);
}

LONG WINAPI Hook_SetWindowLongA(HWND hWnd, int nIndex, LONG dwNewLong)
{
    if (nIndex == GWL_STYLE)
    {
        dwNewLong = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
    }
    return Hooks::SetWindowLong.Real()(hWnd, nIndex, dwNewLong);
}

static int __fastcall set_first_camera_hook(void *thisPtr, void* , __int16 levelNumber, __int16 pathNumber, __int16 cameraNumber, __int16 screenChangeEffect, __int16 a6, __int16 a7)
{
    // AE Cheat screen, I think we have to fake cheat input or set a bool for this to work :(
    // cameraNumber = 31;

    // Setting to Feco lets us go directly in game, with the side effect that pausing will crash
    // and some other nasties, still its good enough for debugging animations
    levelNumber = 5;

    // Abe "hello" screen when levelNumber is left as the intro level
    cameraNumber = 1;

    // pathNumber = 4;

    // 5 = "flash" on
    // 4 = top to bottom
    // 8 = door effect/sound
    screenChangeEffect = 5;

    return Hooks::set_first_camera.Real()(thisPtr, levelNumber, pathNumber, cameraNumber, screenChangeEffect, a6, a7);
}

void HookMain()
{
    Hooks::SetWindowLong.Install(Hook_SetWindowLongA);
    Hooks::set_first_camera.Install(set_first_camera_hook);

    SubClassWindow();
    PatchWindowTitle();
}

// Proxy DLL entry point
HRESULT WINAPI NewDirectDrawCreate(GUID* lpGUID, IDirectDraw** lplpDD, IUnknown* pUnkOuter)
{
    const HMODULE hDDrawDll = LoadRealDDrawDll();
    const TDirectDrawCreate pRealDirectDrawCreate = GetFunctionPointersToRealDDrawFunctions(hDDrawDll);
    const HRESULT ret = pRealDirectDrawCreate(lpGUID, lplpDD, pUnkOuter);
    if (SUCCEEDED(ret))
    {
        *lplpDD = new DirectDraw7Proxy(*lplpDD);
        HookMain();
    }
    return ret;
}

extern "C" BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID /*lpReserved*/)
{
    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
    {
        gDllInstance = hModule;
    }
    return TRUE;
}
<commit_msg>add hook for anim_decode, serves as a base for extracting the anim id/frame/index that is being rendered<commit_after>#include <windows.h>
#include <vector>
#include "ddraw7proxy.hpp"
#include "detours.h"
#include "logger.hpp"

/*static*/ DirectSurface7Proxy* DirectSurface7Proxy::g_Primary;
/*static*/ DirectSurface7Proxy* DirectSurface7Proxy::g_BackBuffer;
/*static*/ DirectSurface7Proxy* DirectSurface7Proxy::g_FakePrimary;

HINSTANCE gDllInstance = NULL;
HRESULT WINAPI NewDirectDrawCreate(GUID* lpGUID, IDirectDraw** lplpDD, IUnknown* pUnkOuter);
using TDirectDrawCreate = decltype(&NewDirectDrawCreate);

inline void FatalExit(const char* msg)
{
    ::MessageBox(NULL, msg, "Error", MB_OK | MB_ICONEXCLAMATION);
    exit(-1);
}

static HMODULE LoadRealDDrawDll()
{
    char infoBuf[MAX_PATH] = {};
    ::GetSystemDirectory(infoBuf, MAX_PATH);

    strcat_s(infoBuf, "\\ddraw.dll");

    const HMODULE hRealDll = ::LoadLibrary(infoBuf);
    if (!hRealDll)
    {
        FatalExit("Can't load or find real DDraw.dll");
    }
    return hRealDll;
}

template<class T>
inline T TGetProcAddress(HMODULE hDll, const char* func)
{
    #pragma warning(suppress: 4191)
    return reinterpret_cast<T>(::GetProcAddress(hDll, func));
}

static TDirectDrawCreate GetFunctionPointersToRealDDrawFunctions(HMODULE hRealDll)
{
    auto ptr = TGetProcAddress<TDirectDrawCreate>(hRealDll, "DirectDrawCreate");
    if (!ptr)
    {
        FatalExit("Can't find DirectDrawCreate function in real dll");
    }
    return ptr;
}

// =================
WNDPROC g_pOldProc = 0;

static LRESULT CALLBACK NewWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
        break;

    case WM_ERASEBKGND:
    {
        RECT rcWin;
        HDC hDC = GetDC(hwnd);
        GetClipBox((HDC)wParam, &rcWin);
        FillRect(hDC, &rcWin, GetSysColorBrush(COLOR_DESKTOP));  // hBrush can be obtained by calling GetWindowLong()
    }
    return TRUE;

    case WM_GETICON:
    case WM_MOUSEACTIVATE:
    case WM_NCLBUTTONDOWN:
    case WM_NCMOUSELEAVE:
    case WM_KILLFOCUS:
    case WM_SETFOCUS:
    case WM_ACTIVATEAPP:
    case WM_NCHITTEST:
    case WM_ACTIVATE:
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_LBUTTONDBLCLK:
    case WM_NCCALCSIZE:
    case WM_MOVE:
    case WM_WINDOWPOSCHANGED:
    case WM_WINDOWPOSCHANGING:
    case WM_NCMOUSEMOVE:
    case WM_MOUSEMOVE:
        return DefWindowProc(hwnd, message, wParam, lParam);

    case WM_SETCURSOR:
    {
        // Set the cursor so the resize cursor or whatever doesn't "stick"
        // when we move the mouse over the game window.
        static HCURSOR cur = LoadCursor(0, IDC_ARROW);
        if (cur)
        {
            SetCursor(cur);
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        BeginPaint(hwnd, &ps);
        EndPaint(hwnd, &ps);

    }
    return FALSE;
    }

    return g_pOldProc(hwnd, message, wParam, lParam);
}

static void CenterWnd(HWND wnd)
{
    RECT r, r1;
    GetWindowRect(wnd, &r);
    GetWindowRect(GetDesktopWindow(), &r1);
    MoveWindow(wnd, ((r1.right - r1.left) - (r.right - r.left)) / 2,
        ((r1.bottom - r1.top) - (r.bottom - r.top)) / 2,
        (r.right - r.left), (r.bottom - r.top), 0);
}

static void SubClassWindow()
{
    HWND wnd = FindWindow("ABE_WINCLASS", NULL);
    g_pOldProc = (WNDPROC)SetWindowLong(wnd, GWL_WNDPROC, (LONG)NewWindowProc);

    for (int i = 0; i < 70; ++i)
    {
        ShowCursor(TRUE);
    }

    RECT rc;
    SetRect(&rc, 0, 0, 640, 480);
    AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW | WS_VISIBLE, TRUE, 0);
    SetWindowPos(wnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
        SWP_SHOWWINDOW);

    ShowWindow(wnd, SW_HIDE);

    CenterWnd(wnd);

    ShowWindow(wnd, SW_SHOW);

    InvalidateRect(GetDesktopWindow(), NULL, TRUE);
}

static void PatchWindowTitle()
{
    HWND wnd = FindWindow("ABE_WINCLASS", NULL);
    if (wnd)
    {
        const int length = GetWindowTextLength(wnd) + 1;
        std::vector< char > titleBuffer(length+1);
        if (GetWindowText(wnd, titleBuffer.data(), length))
        {
            std::string titleStr(titleBuffer.data());
            titleStr += " under ALIVE hook";
            SetWindowText(wnd, titleStr.c_str());
        }
    }
}

template<class FunctionType, class RealFunctionType = FunctionType>
class Hook
{
public:
    Hook(const Hook&) = delete;
    Hook& operator = (const Hook&) = delete;
    explicit Hook(FunctionType oldFunc)
        : mOldPtr(oldFunc)
    {

    }

    explicit Hook(DWORD oldFunc)
        : mOldPtr(reinterpret_cast<FunctionType>(oldFunc))
    {

    }

    void Install(FunctionType newFunc)
    {
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach(&(PVOID&)mOldPtr, newFunc);
        if (DetourTransactionCommit() != NO_ERROR)
        {
            FatalExit("detouring failed");
        }
    }

    RealFunctionType Real() const
    {
        #pragma warning(suppress: 4191)
        return reinterpret_cast<RealFunctionType>(mOldPtr);
    }

private:
    FunctionType mOldPtr;
};

static int __fastcall set_first_camera_hook(void *thisPtr, void*, __int16 a2, __int16 a3, __int16 a4, __int16 a5, __int16 a6, __int16 a7);
typedef int(__thiscall* set_first_camera_thiscall)(void *thisPtr, __int16 a2, __int16 a3, __int16 a4, __int16 a5, __int16 a6, __int16 a7);

struct anim_struct
{
    void* mVtbl;
    BYTE field_4; // max w?
    BYTE field_5; // max h?
    WORD flags;
    DWORD field_8;
    WORD field_C;
    WORD field_E;
    DWORD field_10;
    DWORD field_14;
    DWORD mFrameTableOffset; // offset to frame table from anim data header
    DWORD field_1C;
    void** field_20; // pointer to a pointer which points to anim data?
    DWORD iDbufPtr;
    DWORD iAnimSize;
    DWORD field_2C;
    DWORD field_30;
    DWORD field_34;
    DWORD field_38;
    DWORD field_3C;
    DWORD field_40;
    DWORD field_44;
    DWORD field_48;
    DWORD field_4C;
    DWORD field_50;
    DWORD field_54;
    DWORD field_58;
    DWORD field_5C;
    DWORD field_60;
    DWORD field_64;
    DWORD field_68;
    DWORD field_6C;
    DWORD field_70;
    DWORD field_74;
    DWORD field_78;
    DWORD field_7C;
    DWORD field_80;
    WORD iRect;
    WORD field_86;
    WORD field_88;
    WORD field_8A;
    DWORD field_8C;
    WORD field_90;
    WORD field_92;
};

void __fastcall anim_decode_hook(anim_struct* thisPtr, void*);
typedef void (__thiscall* anim_decode_thiscall)(anim_struct* thisPtr);

namespace Hooks
{
    Hook<decltype(&::SetWindowLongA)> SetWindowLong(::SetWindowLongA);
    Hook<decltype(&::set_first_camera_hook), set_first_camera_thiscall> set_first_camera(0x00401415);
    Hook<decltype(&::anim_decode_hook), anim_decode_thiscall> anim_decode(0x0040AC90);
}

LONG WINAPI Hook_SetWindowLongA(HWND hWnd, int nIndex, LONG dwNewLong)
{
    if (nIndex == GWL_STYLE)
    {
        dwNewLong = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
    }
    return Hooks::SetWindowLong.Real()(hWnd, nIndex, dwNewLong);
}

static int __fastcall set_first_camera_hook(void *thisPtr, void* , __int16 levelNumber, __int16 pathNumber, __int16 cameraNumber, __int16 screenChangeEffect, __int16 a6, __int16 a7)
{
    // AE Cheat screen, I think we have to fake cheat input or set a bool for this to work :(
    // cameraNumber = 31;

    // Setting to Feco lets us go directly in game, with the side effect that pausing will crash
    // and some other nasties, still its good enough for debugging animations
    levelNumber = 5;

    // Abe "hello" screen when levelNumber is left as the intro level
    cameraNumber = 1;

    // pathNumber = 4;

    // 5 = "flash" on
    // 4 = top to bottom
    // 8 = door effect/sound
    screenChangeEffect = 5;

    return Hooks::set_first_camera.Real()(thisPtr, levelNumber, pathNumber, cameraNumber, screenChangeEffect, a6, a7);
}

void __fastcall anim_decode_hook(anim_struct* thisPtr, void*)
{
    // TODO Hook int __fastcall get_anim_frame_q(int a1, int a2, __int16 a3)  @ 0x004042CD
    // seems its return value can be used to get the anim data frame pointer

    OutputDebugString("anim_decode\n");
    Hooks::anim_decode.Real()(thisPtr);
}

void HookMain()
{
    Hooks::SetWindowLong.Install(Hook_SetWindowLongA);
    Hooks::set_first_camera.Install(set_first_camera_hook);
    Hooks::anim_decode.Install(anim_decode_hook);

    SubClassWindow();
    PatchWindowTitle();
}

// Proxy DLL entry point
HRESULT WINAPI NewDirectDrawCreate(GUID* lpGUID, IDirectDraw** lplpDD, IUnknown* pUnkOuter)
{
    const HMODULE hDDrawDll = LoadRealDDrawDll();
    const TDirectDrawCreate pRealDirectDrawCreate = GetFunctionPointersToRealDDrawFunctions(hDDrawDll);
    const HRESULT ret = pRealDirectDrawCreate(lpGUID, lplpDD, pUnkOuter);
    if (SUCCEEDED(ret))
    {
        *lplpDD = new DirectDraw7Proxy(*lplpDD);
        HookMain();
    }
    return ret;
}

extern "C" BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID /*lpReserved*/)
{
    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
    {
        gDllInstance = hModule;
    }
    return TRUE;
}
<|endoftext|>


<commit_before>#include "ProxyHttpClient.hpp"
#include "api/Error.hpp"
#include "api/HttpMethod.hpp"
#include "api/HttpRequest.hpp"
#include <api/HttpReadBodyResult.hpp>
#include <experimental/filesystem>
#include <algorithm>
#include <fstream>
#include <functional>
#include <memory>
#include <mutex>
#include <gtest/gtest.h>

#define HTTP_CACHE_DIR "http_cache"

#if defined(UPDATE_HTTP_CACHE) && defined(ALLOW_HTTP_ACCESS) && !defined(LOAD_HTTP_CACHE)
#pragma message "ProxyHttpClient is configured to update HTTP cache"
#elif !UPDATE_HTTP_CACHE && ALLOW_HTTP_ACCESS && !LOAD_HTTP_CACHE
#pragma message "ProxyHttpClient is configured to run tests agains real web services"
#elif !UPDATE_HTTP_CACHE && !ALLOW_HTTP_ACCESS && LOAD_HTTP_CACHE
#pragma message "ProxyHttpClient is configured to use HTTP cache instead of real web services"
#else
#error "Incorrect configuration of HTTP caching"
#endif

namespace fs = std::experimental::filesystem;

namespace ledger {
    namespace core {
        namespace test {
            namespace impl {
                class TrafficLogger {
                public:
                    TrafficLogger()
                        : _cache_fn(getCacheFileName()) {
                    }

                    ~TrafficLogger() {
                        save();
                    }

                    void add(const std::string& type,
                             const std::string& url,
                             const std::string& request_body,
                             const std::string& response_body) {
                        std::ostringstream oss;
                        oss << type << " " << url << std::endl;
                        oss << encodeBody(request_body);

                        std::lock_guard<std::mutex> guard(_mutex);
                        _data[oss.str()] = encodeBody(response_body);
                    }

                    static std::string getCacheFileName() {
                        const testing::TestInfo* const test_info =
                            testing::UnitTest::GetInstance()->current_test_info();

                        const std::string cache_fn = std::string(HTTP_CACHE_DIR)
                                + std::string("/")
                                + std::string(test_info->test_suite_name())
                                + std::string(".")
                                + std::string(test_info->name());

                        return cache_fn;
                    }

                protected:
                    typedef std::unordered_map<std::string, std::string> map_type_t;

                    std::string encodeBody(const std::string& body) {
                        std::ostringstream oss;
                        if (body.size() == 0) {
                            oss << 0 << std::endl;
                        } else {
                            oss << std::count(body.begin(), body.end(), '\n') + 1 << std::endl;
                            oss << body << std::endl;
                        }
                        return oss.str();
                    }

                    void save() {
                        std::lock_guard<std::mutex> guard(_mutex);

                        if (_data.empty())
                            return;

                        if (!fs::exists(HTTP_CACHE_DIR))
                            fs::create_directory(HTTP_CACHE_DIR);

                        std::ofstream out(_cache_fn);

                        for (const auto& kv : _data)
                            out << kv.first << kv.second << std::endl;
                    }

                    std::mutex _mutex;
                    map_type_t _data;
                    std::string _cache_fn;
                };

                class LoggingHttpRequest : public api::HttpRequest {
                public:
                    typedef std::function<void(const std::string& type,
                                               const std::string& url,
                                               const std::vector<uint8_t>& req_body,
                                               const std::string& resp_body)> callback_t;

                    LoggingHttpRequest(const std::shared_ptr<api::HttpRequest>& request, callback_t fn)
                        : _request(request), _callback(fn) {}

                    virtual ~LoggingHttpRequest() {}

                    virtual api::HttpMethod getMethod() {
                        return _request->getMethod();
                    }

                    virtual std::unordered_map<std::string, std::string> getHeaders() {
                        return _request->getHeaders();
                    }

                    virtual std::vector<uint8_t> getBody() {
                        return _request->getBody();
                    }

                    virtual std::string getUrl() {
                        return _request->getUrl();
                    }

                    virtual void complete(const std::shared_ptr<api::HttpUrlConnection> & response,
                                          const std::experimental::optional<api::Error> & error) {
                        const std::string response_body = readResponseBody(response);
                        _callback(to_string(getMethod()), getUrl(), getBody(), response_body);
                        _request->complete(FakeUrlConnection::fromString(response_body), error);
                    }

                protected:
                    static std::string readResponseBody(const std::shared_ptr<api::HttpUrlConnection> & response) {
                        std::string response_body;
                        while (true) {
                            api::HttpReadBodyResult body = response->readBody();

                            if (body.error)
                                throw std::runtime_error(body.error->message);

                            if (body.data) {
                                const std::vector<uint8_t>& data = *(body.data);
                                if (data.empty())
                                    break;
                                response_body += std::string(data.begin(), data.end());
                                continue;
                            }
                            break;
                        }
                        return response_body;
                    }

                    const std::shared_ptr<api::HttpRequest> _request;
                    callback_t _callback;
                };
            }

            ProxyHttpClient::ProxyHttpClient(std::shared_ptr<api::HttpClient> httpClient)
                : _httpClient(httpClient)
            {
#ifdef UPDATE_HTTP_CACHE
                _logger = make_shared<impl::TrafficLogger>();
#endif

#ifdef LOAD_HTTP_CACHE
                if (!_logger)
                    loadCache(impl::TrafficLogger::getCacheFileName());
#endif
            }

            void ProxyHttpClient::execute(const std::shared_ptr<api::HttpRequest>& request) {
                auto vector_uint8_to_string = [](const std::vector<uint8_t>& v) {
                    return std::string(v.begin(), v.end());
                };
                auto it = _cache.find(request->getUrl() + vector_uint8_to_string(request->getBody()));
                if (it != _cache.end() && !_logger) {
                    std::cout << "get response from cache : " << request->getUrl() << std::endl;
                    request->complete(it->second, std::experimental::nullopt);
                    return;
                }

#ifndef ALLOW_HTTP_ACCESS
                throw std::runtime_error("HTTP access isn't allowed.");
#endif
                if (_logger) {
                    std::shared_ptr<impl::LoggingHttpRequest> temp
                            = std::make_shared<impl::LoggingHttpRequest>(request,
                                                                    [this, vector_uint8_to_string](const std::string& type,
                                                                                const std::string& url,
                                                                                const std::vector<uint8_t>& req_body,
                                                                                const std::string& resp_body){
                        _logger->add(type, url, vector_uint8_to_string(req_body), resp_body);
                    });

#ifdef ALLOW_HTTP_ACCESS
                    _httpClient->execute(temp);
#endif
                } else {
#ifdef ALLOW_HTTP_ACCESS
                    _httpClient->execute(request);
#endif
                }
            }

            void ProxyHttpClient::loadCache(const std::string& file_name) {
                // Cache file format:
                // (GET|POST) URL
                // request length in lines
                // request body
                // response length in lines
                // response body
                // empty line
                auto read_body = [](std::ifstream& file) {
                    std::string s, line;
                    size_t n = 0;

                    file >> n;
                    while (n > 0 && std::getline(file, line)) {
                        if (s.empty() && line.empty())
                            continue;
                        if (!s.empty())
                            s += "\n";
                        s += line;
                        n--;
                    }

                    return s;
                };

                std::ifstream input_file(file_name);
                if (input_file.is_open()) {
                    std::string line;
                    std::string type, url;
                    while (input_file >> type >> url) {
                        const std::string request_body = read_body(input_file);
                        const std::string response_body = read_body(input_file);

                        url += request_body;
                        addCache(url, response_body);
                    }
                }
            }

            void ProxyHttpClient::addCache(const std::string& url, const std::string& body) {
                _cache.emplace(url, FakeUrlConnection::fromString(body));
            }
        }
    }
}
<commit_msg>Add missing std:: namespace<commit_after>#include "ProxyHttpClient.hpp"
#include "api/Error.hpp"
#include "api/HttpMethod.hpp"
#include "api/HttpRequest.hpp"
#include <api/HttpReadBodyResult.hpp>
#include <experimental/filesystem>
#include <algorithm>
#include <fstream>
#include <functional>
#include <memory>
#include <mutex>
#include <gtest/gtest.h>

#define HTTP_CACHE_DIR "http_cache"

#if defined(UPDATE_HTTP_CACHE) && defined(ALLOW_HTTP_ACCESS) && !defined(LOAD_HTTP_CACHE)
#pragma message "ProxyHttpClient is configured to update HTTP cache"
#elif !UPDATE_HTTP_CACHE && ALLOW_HTTP_ACCESS && !LOAD_HTTP_CACHE
#pragma message "ProxyHttpClient is configured to run tests agains real web services"
#elif !UPDATE_HTTP_CACHE && !ALLOW_HTTP_ACCESS && LOAD_HTTP_CACHE
#pragma message "ProxyHttpClient is configured to use HTTP cache instead of real web services"
#else
#error "Incorrect configuration of HTTP caching"
#endif

namespace fs = std::experimental::filesystem;

namespace ledger {
    namespace core {
        namespace test {
            namespace impl {
                class TrafficLogger {
                public:
                    TrafficLogger()
                        : _cache_fn(getCacheFileName()) {
                    }

                    ~TrafficLogger() {
                        save();
                    }

                    void add(const std::string& type,
                             const std::string& url,
                             const std::string& request_body,
                             const std::string& response_body) {
                        std::ostringstream oss;
                        oss << type << " " << url << std::endl;
                        oss << encodeBody(request_body);

                        std::lock_guard<std::mutex> guard(_mutex);
                        _data[oss.str()] = encodeBody(response_body);
                    }

                    static std::string getCacheFileName() {
                        const testing::TestInfo* const test_info =
                            testing::UnitTest::GetInstance()->current_test_info();

                        const std::string cache_fn = std::string(HTTP_CACHE_DIR)
                                + std::string("/")
                                + std::string(test_info->test_suite_name())
                                + std::string(".")
                                + std::string(test_info->name());

                        return cache_fn;
                    }

                protected:
                    typedef std::unordered_map<std::string, std::string> map_type_t;

                    std::string encodeBody(const std::string& body) {
                        std::ostringstream oss;
                        if (body.size() == 0) {
                            oss << 0 << std::endl;
                        } else {
                            oss << std::count(body.begin(), body.end(), '\n') + 1 << std::endl;
                            oss << body << std::endl;
                        }
                        return oss.str();
                    }

                    void save() {
                        std::lock_guard<std::mutex> guard(_mutex);

                        if (_data.empty())
                            return;

                        if (!fs::exists(HTTP_CACHE_DIR))
                            fs::create_directory(HTTP_CACHE_DIR);

                        std::ofstream out(_cache_fn);

                        for (const auto& kv : _data)
                            out << kv.first << kv.second << std::endl;
                    }

                    std::mutex _mutex;
                    map_type_t _data;
                    std::string _cache_fn;
                };

                class LoggingHttpRequest : public api::HttpRequest {
                public:
                    typedef std::function<void(const std::string& type,
                                               const std::string& url,
                                               const std::vector<uint8_t>& req_body,
                                               const std::string& resp_body)> callback_t;

                    LoggingHttpRequest(const std::shared_ptr<api::HttpRequest>& request, callback_t fn)
                        : _request(request), _callback(fn) {}

                    virtual ~LoggingHttpRequest() {}

                    virtual api::HttpMethod getMethod() {
                        return _request->getMethod();
                    }

                    virtual std::unordered_map<std::string, std::string> getHeaders() {
                        return _request->getHeaders();
                    }

                    virtual std::vector<uint8_t> getBody() {
                        return _request->getBody();
                    }

                    virtual std::string getUrl() {
                        return _request->getUrl();
                    }

                    virtual void complete(const std::shared_ptr<api::HttpUrlConnection> & response,
                                          const std::experimental::optional<api::Error> & error) {
                        const std::string response_body = readResponseBody(response);
                        _callback(to_string(getMethod()), getUrl(), getBody(), response_body);
                        _request->complete(FakeUrlConnection::fromString(response_body), error);
                    }

                protected:
                    static std::string readResponseBody(const std::shared_ptr<api::HttpUrlConnection> & response) {
                        std::string response_body;
                        while (true) {
                            api::HttpReadBodyResult body = response->readBody();

                            if (body.error)
                                throw std::runtime_error(body.error->message);

                            if (body.data) {
                                const std::vector<uint8_t>& data = *(body.data);
                                if (data.empty())
                                    break;
                                response_body += std::string(data.begin(), data.end());
                                continue;
                            }
                            break;
                        }
                        return response_body;
                    }

                    const std::shared_ptr<api::HttpRequest> _request;
                    callback_t _callback;
                };
            }

            ProxyHttpClient::ProxyHttpClient(std::shared_ptr<api::HttpClient> httpClient)
                : _httpClient(httpClient)
            {
#ifdef UPDATE_HTTP_CACHE
                _logger = std::make_shared<impl::TrafficLogger>();
#endif

#ifdef LOAD_HTTP_CACHE
                if (!_logger)
                    loadCache(impl::TrafficLogger::getCacheFileName());
#endif
            }

            void ProxyHttpClient::execute(const std::shared_ptr<api::HttpRequest>& request) {
                auto vector_uint8_to_string = [](const std::vector<uint8_t>& v) {
                    return std::string(v.begin(), v.end());
                };
                auto it = _cache.find(request->getUrl() + vector_uint8_to_string(request->getBody()));
                if (it != _cache.end() && !_logger) {
                    std::cout << "get response from cache : " << request->getUrl() << std::endl;
                    request->complete(it->second, std::experimental::nullopt);
                    return;
                }

#ifndef ALLOW_HTTP_ACCESS
                throw std::runtime_error("HTTP access isn't allowed.");
#endif
                if (_logger) {
                    std::shared_ptr<impl::LoggingHttpRequest> temp
                            = std::make_shared<impl::LoggingHttpRequest>(request,
                                                                    [this, vector_uint8_to_string](const std::string& type,
                                                                                const std::string& url,
                                                                                const std::vector<uint8_t>& req_body,
                                                                                const std::string& resp_body){
                        _logger->add(type, url, vector_uint8_to_string(req_body), resp_body);
                    });

#ifdef ALLOW_HTTP_ACCESS
                    _httpClient->execute(temp);
#endif
                } else {
#ifdef ALLOW_HTTP_ACCESS
                    _httpClient->execute(request);
#endif
                }
            }

            void ProxyHttpClient::loadCache(const std::string& file_name) {
                // Cache file format:
                // (GET|POST) URL
                // request length in lines
                // request body
                // response length in lines
                // response body
                // empty line
                auto read_body = [](std::ifstream& file) {
                    std::string s, line;
                    size_t n = 0;

                    file >> n;
                    while (n > 0 && std::getline(file, line)) {
                        if (s.empty() && line.empty())
                            continue;
                        if (!s.empty())
                            s += "\n";
                        s += line;
                        n--;
                    }

                    return s;
                };

                std::ifstream input_file(file_name);
                if (input_file.is_open()) {
                    std::string line;
                    std::string type, url;
                    while (input_file >> type >> url) {
                        const std::string request_body = read_body(input_file);
                        const std::string response_body = read_body(input_file);

                        url += request_body;
                        addCache(url, response_body);
                    }
                }
            }

            void ProxyHttpClient::addCache(const std::string& url, const std::string& body) {
                _cache.emplace(url, FakeUrlConnection::fromString(body));
            }
        }
    }
}
<|endoftext|>