<commit_before>/* bzflag
 * Copyright (c) 1993-2010 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// BZFlag common header
#include "common.h"

// Interface header
#include "MatchManager.h"

#include "StateDatabase.h"
#include "BzTime.h"
#include "TextUtils.h"

/** Utility Countdown class */

CountDown::CountDown(double interval, int count)
{
  _interval = interval;
  _currentTime = 0;
  _previousTime = 0;
  _startCount = count + 1;
  _counter = _startCount;
}

int CountDown::getCounter()
{
  return _counter;
}

void CountDown::setCounter(int count)
{
  _startCount = _counter = count + 1;
}

void CountDown::doReset()
{
  _currentTime = bz_getCurrentTime();
  _previousTime = _currentTime;
  _counter = _startCount;
}

bool CountDown::doCountdown()
{
  _currentTime = bz_getCurrentTime();

  if ((_currentTime - _previousTime) > _interval) {
    _counter--;
    _previousTime = _currentTime;
    return true;
  }

  return false;
}

bool CountDown::inProgress()
{
  return (_counter > 1);
}

/** MatchManager class */

/** initialize the singleton */
template <>
MatchManager* Singleton<MatchManager>::_instance = (MatchManager*)0;

/**
 * default constructor, protected because of singleton
 */
MatchManager::MatchManager() : Singleton<MatchManager>()
{
  // start future BZDB vars
  _matchPregameTime = 60;
  _matchDuration = 1800;
  _matchEndCountdown = 30;
  _matchResetTime = 120;

  _matchDisallowJoins = false;
  _matchResetScoreOnEnd = true;
  _matchReportMatches = true;
  // end future BZDB vars

  matchState = eOff;
  startTime = -1;
  duration = -1;
  endTime = 0;
  resetTime = _matchResetTime;

  resumeTime = -1;
  pauseTime = -1;

  paused = false;
  report = false;

  currentTime = 0;

  // register events & commands
  bz_registerCustomSlashCommand("match",this);
  bz_registerEvent(bz_eGetAutoTeamEvent,this);
  bz_registerEvent(bz_eTickEvent,this);
  bz_registerEvent(bz_eReportFiledEvent,this);

  bz_setMaxWaitTime(0.1f,"MATCHMANAGER");
}

/**
 * default destructor, protected because of singleton
 */
MatchManager::~MatchManager()
{
  bz_removeCustomSlashCommand("match");
  bz_removeEvent(bz_eGetAutoTeamEvent,this);
  bz_removeEvent(bz_eTickEvent,this);
  bz_removeEvent(bz_eReportFiledEvent,this);

  bz_clearMaxWaitTime("MATCHMANAGER");
}

void MatchManager::start (int playerID, bz_APIStringList *params)
{
  if (matchState == eOn || matchState == ePregame)
    bz_sendTextMessage (BZ_SERVER, playerID, "A match is currently in progress");
  else {
    if (matchState == eOff || matchState == ePostgame) {
      if (params->size() == 2)
	duration = atoi(params->get(1).c_str());
      else
	duration = _matchDuration;

      matchState = ePregame;
      preGameTimer.doReset();
      preGameTimer.setCounter((int) _matchPregameTime);

      // disable player spawn
      disablePlayerSpawn();

      // reset flags
      bz_resetFlags(false);

      // reset player/team scores
      resetTeamScores();
      resetPlayerScores();

      bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "A match will start in %.0f seconds", _matchPregameTime);
    }
  }
}

void MatchManager::end (int playerID, bz_APIStringList * /* params */)
{
  if (matchState == eOn) {
    matchState = ePostgame;
    paused = false;
    bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "The match ended after %.0f seconds", bz_getCurrentTime() - startTime);
  } else {
    bz_sendTextMessage (BZ_SERVER, playerID, "No match in progress");
  }
}

void MatchManager::pause (int playerID, bz_APIStringList *params)
{

  // pause can only be used when a match is in progress
  if (matchState == eOn) {
    double d = 0;

    if (params->size() == 2)
      d = atoi(params->get(1).c_str());

    // resume the match when already paused else pause
    if (paused) {
      resumeTime = bz_getCurrentTime() + d;
      bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "The match will be resumed in %.0f seconds", resumeTime - currentTime);
    } else {
      paused=true;
      pauseTime = bz_getCurrentTime();

      if (d > 0) {
	resumeTime = bz_getCurrentTime() + d;
	bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "The match will be paused for %.0f seconds", resumeTime - currentTime);
      } else {
	bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "The match is paused");
      }
    }
  } else {
    bz_sendTextMessagef (BZ_SERVER, playerID, "No match to pause");
  }
}

void MatchManager::substitute (int /* playerID */, bz_APIStringList * /* params */)
{

}

void MatchManager::doPregame()
{
  if (preGameTimer.inProgress()) {
    if (preGameTimer.doCountdown())
      bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "%d ...", preGameTimer.getCounter());
  } else {
    matchState = eOn;
    endTimer.setCounter((int) _matchEndCountdown);
    endTimer.doReset();
    startTime = currentTime;

    bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "The match started");
  }
}

void MatchManager::doOngame()
{

  // check if someone unpaused the match, if so resume it
  if (paused && currentTime >= resumeTime && resumeTime != -1) {
    duration += currentTime - pauseTime;
    paused = false;

    bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "Match resumed after %.0f seconds", currentTime - pauseTime);

    resumeTime = -1;
    pauseTime = -1;
  }

  // start match end countdown
  if (!paused && currentTime >= ((startTime + duration) - _matchEndCountdown)) {
    if (endTimer.inProgress()) {
      if (endTimer.doCountdown())
	bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "Still %d sec to go before match ends", endTimer.getCounter());
    } else {
      matchState = ePostgame;
      endTime = startTime + duration + resetTime;
      bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "The match ended");
      if (report)
	doReportgame();

      startTime = -1;
    }
  }
}

void MatchManager::doPostgame()
{
  if (currentTime >= endTime) {
    matchState = eOff;
    bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "Free play is resumed");
  }
}

void MatchManager::doReportgame()
{
  bz_fileReport("report scores to the report channel","MatchMaker");
}

void MatchManager::disablePlayerSpawn()
{
  bz_APIIntList * players = bz_getPlayerIndexList();

  for (unsigned int i = 0; i < players->size(); i++) {
    if (bz_getPlayerTeam(players->get(i)) != eObservers) {
      if (bz_setPlayerSpawnable(players->get(i), false))
	bz_debugMessagef(2, "DEBUG :: no spawn success :: player => %d ", players->get(i));
      else
	bz_debugMessagef(2, "DEBUG :: no spawn failed :: player => %d ", players->get(i));
    }
  }

}

void MatchManager::resetTeamScores()
{

}

void MatchManager::resetPlayerScores()
{

}

void MatchManager::process (bz_EventData *eventData)
{

  if (!eventData)
    return;

  if (eventData->eventType == bz_eGetAutoTeamEvent) {

  }

  if (eventData->eventType == bz_eTickEvent) {
    currentTime = ((bz_TickEventData_V1 *) eventData)->eventTime;

    if (matchState == ePregame) {
      doPregame();
    } else {
      if (matchState == eOn) {
	doOngame();
      } else {
	if (matchState == ePostgame)
	  doPostgame();
      }
    }
  }

  if (eventData->eventType == bz_eReportFiledEvent)
  {
    bz_ReportFiledEventData_V1 * data = (bz_ReportFiledEventData_V1 *) eventData;
    bz_debugMessagef(2, "DEBUG :: version => %d reporter => %s :: message => %s :: time => %.0f",
		     data->version, data->from.c_str(), data->message.c_str(), data->eventTime);
  }

}

bool MatchManager::handle (int playerID, bz_ApiString command, bz_ApiString /* message */, bz_APIStringList *params)
{

  if (command == "match") {
    double now = BzTime::getCurrent().getSeconds();

    if (!params->size()) {
      std::string msg;
      switch (matchState) {

	default:
	  msg = "No match is in progress";
	  break;

	case ePregame:
	  msg = TextUtils::format("Match will start in %.0f seconds", startTime - now);
	  break;

	case eOn:
	  if (!paused)
	    msg = TextUtils::format("Match is in progress, still %.0f seconds to go", (startTime + duration) - now);
	  else
	    msg = "Match is paused";
	  break;

	case ePostgame:
	  msg = TextUtils::format("Match is over, server will resume free play in %.0f seconds",endTime - now);
	  break;
      }

      bz_sendTextMessagef (BZ_SERVER, playerID, "%s", msg.c_str());
      return true;

    } else {
      // check if player has the perms to exectue the match command
      if (!bz_hasPerm(playerID, "MATCH")) {
	bz_sendTextMessage (BZ_SERVER, playerID, "You do not have permission to run the match command");
	return true;
      }

      if (params->size()) {
	bz_ApiString action = params->get(0);
	action.tolower();

	if (action == "start") {
	  start(playerID, params);
	  return true;
	}

	if (action == "end") {
	  end(playerID, params);
	  return true;
	}

	if (action == "pause") {
	  pause(playerID, params);
	  return true;
	}

	if (action == "sub") {
	  substitute(playerID, params);
	  return true;
	}

	if (action == "noreport") {
	  if (report) {
	    report = false;
	    bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "Reporting is disabled.");
	  } else {
	    report = true;
	    bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "Reporting is enabled.");
	  }

	  return true;
	}
      }
    }
  }

  return false;
}

/**
 * Init the MatchManager. Should be hooked into bzfs.cxx at some point,
 * but not yet as this is far from finished.
 */
void MatchManager::init()
{
  bz_debugMessage(2, "Initialize MatchManager");
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Replace the one use of BzTime::getCurrent().getSeconds() with bz_getCurrentTime() to match the rest of the file.<commit_after>/* bzflag
 * Copyright (c) 1993-2010 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// BZFlag common header
#include "common.h"

// Interface header
#include "MatchManager.h"

#include "StateDatabase.h"
#include "TextUtils.h"

/** Utility Countdown class */

CountDown::CountDown(double interval, int count)
{
  _interval = interval;
  _currentTime = 0;
  _previousTime = 0;
  _startCount = count + 1;
  _counter = _startCount;
}

int CountDown::getCounter()
{
  return _counter;
}

void CountDown::setCounter(int count)
{
  _startCount = _counter = count + 1;
}

void CountDown::doReset()
{
  _currentTime = bz_getCurrentTime();
  _previousTime = _currentTime;
  _counter = _startCount;
}

bool CountDown::doCountdown()
{
  _currentTime = bz_getCurrentTime();

  if ((_currentTime - _previousTime) > _interval) {
    _counter--;
    _previousTime = _currentTime;
    return true;
  }

  return false;
}

bool CountDown::inProgress()
{
  return (_counter > 1);
}

/** MatchManager class */

/** initialize the singleton */
template <>
MatchManager* Singleton<MatchManager>::_instance = (MatchManager*)0;

/**
 * default constructor, protected because of singleton
 */
MatchManager::MatchManager() : Singleton<MatchManager>()
{
  // start future BZDB vars
  _matchPregameTime = 60;
  _matchDuration = 1800;
  _matchEndCountdown = 30;
  _matchResetTime = 120;

  _matchDisallowJoins = false;
  _matchResetScoreOnEnd = true;
  _matchReportMatches = true;
  // end future BZDB vars

  matchState = eOff;
  startTime = -1;
  duration = -1;
  endTime = 0;
  resetTime = _matchResetTime;

  resumeTime = -1;
  pauseTime = -1;

  paused = false;
  report = false;

  currentTime = 0;

  // register events & commands
  bz_registerCustomSlashCommand("match",this);
  bz_registerEvent(bz_eGetAutoTeamEvent,this);
  bz_registerEvent(bz_eTickEvent,this);
  bz_registerEvent(bz_eReportFiledEvent,this);

  bz_setMaxWaitTime(0.1f,"MATCHMANAGER");
}

/**
 * default destructor, protected because of singleton
 */
MatchManager::~MatchManager()
{
  bz_removeCustomSlashCommand("match");
  bz_removeEvent(bz_eGetAutoTeamEvent,this);
  bz_removeEvent(bz_eTickEvent,this);
  bz_removeEvent(bz_eReportFiledEvent,this);

  bz_clearMaxWaitTime("MATCHMANAGER");
}

void MatchManager::start (int playerID, bz_APIStringList *params)
{
  if (matchState == eOn || matchState == ePregame)
    bz_sendTextMessage (BZ_SERVER, playerID, "A match is currently in progress");
  else {
    if (matchState == eOff || matchState == ePostgame) {
      if (params->size() == 2)
	duration = atoi(params->get(1).c_str());
      else
	duration = _matchDuration;

      matchState = ePregame;
      preGameTimer.doReset();
      preGameTimer.setCounter((int) _matchPregameTime);

      // disable player spawn
      disablePlayerSpawn();

      // reset flags
      bz_resetFlags(false);

      // reset player/team scores
      resetTeamScores();
      resetPlayerScores();

      bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "A match will start in %.0f seconds", _matchPregameTime);
    }
  }
}

void MatchManager::end (int playerID, bz_APIStringList * /* params */)
{
  if (matchState == eOn) {
    matchState = ePostgame;
    paused = false;
    bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "The match ended after %.0f seconds", bz_getCurrentTime() - startTime);
  } else {
    bz_sendTextMessage (BZ_SERVER, playerID, "No match in progress");
  }
}

void MatchManager::pause (int playerID, bz_APIStringList *params)
{

  // pause can only be used when a match is in progress
  if (matchState == eOn) {
    double d = 0;

    if (params->size() == 2)
      d = atoi(params->get(1).c_str());

    // resume the match when already paused else pause
    if (paused) {
      resumeTime = bz_getCurrentTime() + d;
      bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "The match will be resumed in %.0f seconds", resumeTime - currentTime);
    } else {
      paused=true;
      pauseTime = bz_getCurrentTime();

      if (d > 0) {
	resumeTime = bz_getCurrentTime() + d;
	bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "The match will be paused for %.0f seconds", resumeTime - currentTime);
      } else {
	bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "The match is paused");
      }
    }
  } else {
    bz_sendTextMessagef (BZ_SERVER, playerID, "No match to pause");
  }
}

void MatchManager::substitute (int /* playerID */, bz_APIStringList * /* params */)
{

}

void MatchManager::doPregame()
{
  if (preGameTimer.inProgress()) {
    if (preGameTimer.doCountdown())
      bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "%d ...", preGameTimer.getCounter());
  } else {
    matchState = eOn;
    endTimer.setCounter((int) _matchEndCountdown);
    endTimer.doReset();
    startTime = currentTime;

    bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "The match started");
  }
}

void MatchManager::doOngame()
{

  // check if someone unpaused the match, if so resume it
  if (paused && currentTime >= resumeTime && resumeTime != -1) {
    duration += currentTime - pauseTime;
    paused = false;

    bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "Match resumed after %.0f seconds", currentTime - pauseTime);

    resumeTime = -1;
    pauseTime = -1;
  }

  // start match end countdown
  if (!paused && currentTime >= ((startTime + duration) - _matchEndCountdown)) {
    if (endTimer.inProgress()) {
      if (endTimer.doCountdown())
	bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "Still %d sec to go before match ends", endTimer.getCounter());
    } else {
      matchState = ePostgame;
      endTime = startTime + duration + resetTime;
      bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "The match ended");
      if (report)
	doReportgame();

      startTime = -1;
    }
  }
}

void MatchManager::doPostgame()
{
  if (currentTime >= endTime) {
    matchState = eOff;
    bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "Free play is resumed");
  }
}

void MatchManager::doReportgame()
{
  bz_fileReport("report scores to the report channel","MatchMaker");
}

void MatchManager::disablePlayerSpawn()
{
  bz_APIIntList * players = bz_getPlayerIndexList();

  for (unsigned int i = 0; i < players->size(); i++) {
    if (bz_getPlayerTeam(players->get(i)) != eObservers) {
      if (bz_setPlayerSpawnable(players->get(i), false))
	bz_debugMessagef(2, "DEBUG :: no spawn success :: player => %d ", players->get(i));
      else
	bz_debugMessagef(2, "DEBUG :: no spawn failed :: player => %d ", players->get(i));
    }
  }

}

void MatchManager::resetTeamScores()
{

}

void MatchManager::resetPlayerScores()
{

}

void MatchManager::process (bz_EventData *eventData)
{

  if (!eventData)
    return;

  if (eventData->eventType == bz_eGetAutoTeamEvent) {

  }

  if (eventData->eventType == bz_eTickEvent) {
    currentTime = ((bz_TickEventData_V1 *) eventData)->eventTime;

    if (matchState == ePregame) {
      doPregame();
    } else {
      if (matchState == eOn) {
	doOngame();
      } else {
	if (matchState == ePostgame)
	  doPostgame();
      }
    }
  }

  if (eventData->eventType == bz_eReportFiledEvent)
  {
    bz_ReportFiledEventData_V1 * data = (bz_ReportFiledEventData_V1 *) eventData;
    bz_debugMessagef(2, "DEBUG :: version => %d reporter => %s :: message => %s :: time => %.0f",
		     data->version, data->from.c_str(), data->message.c_str(), data->eventTime);
  }

}

bool MatchManager::handle (int playerID, bz_ApiString command, bz_ApiString /* message */, bz_APIStringList *params)
{

  if (command == "match") {
    double now = bz_getCurrentTime();

    if (!params->size()) {
      std::string msg;
      switch (matchState) {

	default:
	  msg = "No match is in progress";
	  break;

	case ePregame:
	  msg = TextUtils::format("Match will start in %.0f seconds", startTime - now);
	  break;

	case eOn:
	  if (!paused)
	    msg = TextUtils::format("Match is in progress, still %.0f seconds to go", (startTime + duration) - now);
	  else
	    msg = "Match is paused";
	  break;

	case ePostgame:
	  msg = TextUtils::format("Match is over, server will resume free play in %.0f seconds",endTime - now);
	  break;
      }

      bz_sendTextMessagef (BZ_SERVER, playerID, "%s", msg.c_str());
      return true;

    } else {
      // check if player has the perms to exectue the match command
      if (!bz_hasPerm(playerID, "MATCH")) {
	bz_sendTextMessage (BZ_SERVER, playerID, "You do not have permission to run the match command");
	return true;
      }

      if (params->size()) {
	bz_ApiString action = params->get(0);
	action.tolower();

	if (action == "start") {
	  start(playerID, params);
	  return true;
	}

	if (action == "end") {
	  end(playerID, params);
	  return true;
	}

	if (action == "pause") {
	  pause(playerID, params);
	  return true;
	}

	if (action == "sub") {
	  substitute(playerID, params);
	  return true;
	}

	if (action == "noreport") {
	  if (report) {
	    report = false;
	    bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "Reporting is disabled.");
	  } else {
	    report = true;
	    bz_sendTextMessage (BZ_SERVER, BZ_ALLUSERS, "Reporting is enabled.");
	  }

	  return true;
	}
      }
    }
  }

  return false;
}

/**
 * Init the MatchManager. Should be hooked into bzfs.cxx at some point,
 * but not yet as this is far from finished.
 */
void MatchManager::init()
{
  bz_debugMessage(2, "Initialize MatchManager");
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>//---------------------------------------------------------- -*- Mode: C++ -*-
// $Id$
//
// Created 2016/8/9
// Author: Mike Ovsiannikov
//
// Copyright 2014 Quantcast Corp.
//
// This file is part of Kosmos File System (KFS).
//
// Licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
//
// Chunk / object store block's file name / key generation implementation.
//
//----------------------------------------------------------------------------

#include "blockname.h"
#include "Base64.h"
#include "Checksum.h"

#include "common/IntToString.h"

#include <algorithm>

namespace KFS
{
using std::max;

template<typename T>
    inline static char*
IntToBytes(
    char*    inBufPtr,
    const T& inVal)
{
    char* thePtr  = inBufPtr;
    T     theByte = inVal;
    for (char* const theEndPtr = thePtr + sizeof(T); ;) {
        *thePtr++ = (char)theByte;
        if (theEndPtr <= thePtr) {
            break;
        }
        theByte >>= 8;
    }
    return thePtr;
}

    static inline size_t
UrlSafeBase64Encode(
    const char* inDataPtr,
    size_t      inSize,
    char*       inBufPtr)
{
    int theLen = Base64::Encode(inDataPtr, (int)inSize, inBufPtr);
    // Convert to url safe encoding with no padding.
    while (0 < theLen && (inBufPtr[theLen - 1] & 0xFF) == '=') {
        theLen--;
    }
    for (int i = 0; i < theLen; i++) {
        switch (inBufPtr[i] & 0xFF) {
            case '/': inBufPtr[i] = '_'; break;
            case '+': inBufPtr[i] = '-'; break;
            default:                break;
        }
    }
    return (theLen < 0 ? 0 : theLen);
}

    bool
AppendChunkFileNameOrObjectStoreBlockKey(
    string&      inName,
    int64_t      inFileSystemId,
    kfsFileId_t  inFileId,
    kfsChunkId_t inId,
    kfsSeq_t     inVersion,
    string&      ioFileSystemIdSuffix)
{
    const char kSeparator = '.';
    if (inVersion < 0) {
        uint32_t     theCrc32;
        const size_t kBlockIdSize = sizeof(inId) + sizeof(inVersion);
        char         theBuf[max(
            (size_t)Base64::EncodedLength(sizeof(theCrc32)) + 1, kBlockIdSize)];
        char         theCrc32Buf[sizeof(theCrc32)];
        IntToBytes(IntToBytes(theBuf, inId), inVersion);
        theCrc32 = ComputeCrc32(theBuf, kBlockIdSize);
        size_t theLen = IntToBytes(theCrc32Buf, theCrc32) - theCrc32Buf;
        theLen = UrlSafeBase64Encode(theCrc32Buf, theLen, theBuf);
        if (theLen <= 0) {
            return false;
        }
        theBuf[theLen++] = kSeparator;
        inName.append(theBuf, theLen);
    }
    if (0 <= inVersion || inFileId != inId) {
        AppendDecIntToString(inName, inFileId);
        inName += kSeparator;
    }
    AppendDecIntToString(inName, inId);
    inName += kSeparator;
    AppendDecIntToString(inName, inVersion);
    if (inVersion < 0 && 0 <= inFileSystemId) {
        if (ioFileSystemIdSuffix.empty()) {
            char bytes[sizeof(inFileSystemId)];
            const size_t theLen = IntToBytes(bytes, inFileSystemId) - bytes;
            char theBuf[Base64::EncodedLength(sizeof(inFileSystemId)) + 1];
            theBuf[0] = kSeparator;
            // The "theLen" below is one byte short, therefore the 4 most
            // significant bits of file system ID are not included in the
            // suffix. The most significant bit is always 0, i.e. only 3 bits
            // are actually lost. Do not attempt to "fix" / change this, as
            // doing now so will break backward compatibility with the existing
            // object store QFS file systems.
            ioFileSystemIdSuffix.assign(theBuf, UrlSafeBase64Encode(
                bytes, theLen, theBuf + 1));
            if (ioFileSystemIdSuffix.empty()) {
                return false;
            }
        }
        inName += ioFileSystemIdSuffix;
    }
    return true;
}

} // namespace KFS
<commit_msg>IO library: fix include file name.<commit_after>//---------------------------------------------------------- -*- Mode: C++ -*-
// $Id$
//
// Created 2016/8/9
// Author: Mike Ovsiannikov
//
// Copyright 2014 Quantcast Corp.
//
// This file is part of Kosmos File System (KFS).
//
// Licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
//
// Chunk / object store block's file name / key generation implementation.
//
//----------------------------------------------------------------------------

#include "blockname.h"
#include "Base64.h"
#include "checksum.h"

#include "common/IntToString.h"

#include <algorithm>

namespace KFS
{
using std::max;

template<typename T>
    inline static char*
IntToBytes(
    char*    inBufPtr,
    const T& inVal)
{
    char* thePtr  = inBufPtr;
    T     theByte = inVal;
    for (char* const theEndPtr = thePtr + sizeof(T); ;) {
        *thePtr++ = (char)theByte;
        if (theEndPtr <= thePtr) {
            break;
        }
        theByte >>= 8;
    }
    return thePtr;
}

    static inline size_t
UrlSafeBase64Encode(
    const char* inDataPtr,
    size_t      inSize,
    char*       inBufPtr)
{
    int theLen = Base64::Encode(inDataPtr, (int)inSize, inBufPtr);
    // Convert to url safe encoding with no padding.
    while (0 < theLen && (inBufPtr[theLen - 1] & 0xFF) == '=') {
        theLen--;
    }
    for (int i = 0; i < theLen; i++) {
        switch (inBufPtr[i] & 0xFF) {
            case '/': inBufPtr[i] = '_'; break;
            case '+': inBufPtr[i] = '-'; break;
            default:                break;
        }
    }
    return (theLen < 0 ? 0 : theLen);
}

    bool
AppendChunkFileNameOrObjectStoreBlockKey(
    string&      inName,
    int64_t      inFileSystemId,
    kfsFileId_t  inFileId,
    kfsChunkId_t inId,
    kfsSeq_t     inVersion,
    string&      ioFileSystemIdSuffix)
{
    const char kSeparator = '.';
    if (inVersion < 0) {
        uint32_t     theCrc32;
        const size_t kBlockIdSize = sizeof(inId) + sizeof(inVersion);
        char         theBuf[max(
            (size_t)Base64::EncodedLength(sizeof(theCrc32)) + 1, kBlockIdSize)];
        char         theCrc32Buf[sizeof(theCrc32)];
        IntToBytes(IntToBytes(theBuf, inId), inVersion);
        theCrc32 = ComputeCrc32(theBuf, kBlockIdSize);
        size_t theLen = IntToBytes(theCrc32Buf, theCrc32) - theCrc32Buf;
        theLen = UrlSafeBase64Encode(theCrc32Buf, theLen, theBuf);
        if (theLen <= 0) {
            return false;
        }
        theBuf[theLen++] = kSeparator;
        inName.append(theBuf, theLen);
    }
    if (0 <= inVersion || inFileId != inId) {
        AppendDecIntToString(inName, inFileId);
        inName += kSeparator;
    }
    AppendDecIntToString(inName, inId);
    inName += kSeparator;
    AppendDecIntToString(inName, inVersion);
    if (inVersion < 0 && 0 <= inFileSystemId) {
        if (ioFileSystemIdSuffix.empty()) {
            char bytes[sizeof(inFileSystemId)];
            const size_t theLen = IntToBytes(bytes, inFileSystemId) - bytes;
            char theBuf[Base64::EncodedLength(sizeof(inFileSystemId)) + 1];
            theBuf[0] = kSeparator;
            // The "theLen" below is one byte short, therefore the 4 most
            // significant bits of file system ID are not included in the
            // suffix. The most significant bit is always 0, i.e. only 3 bits
            // are actually lost. Do not attempt to "fix" / change this, as
            // doing now so will break backward compatibility with the existing
            // object store QFS file systems.
            ioFileSystemIdSuffix.assign(theBuf, UrlSafeBase64Encode(
                bytes, theLen, theBuf + 1));
            if (ioFileSystemIdSuffix.empty()) {
                return false;
            }
        }
        inName += ioFileSystemIdSuffix;
    }
    return true;
}

} // namespace KFS
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSTLWriter.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkSTLWriter.hh"
#include "vtkPolygon.hh"
#include "vtkByteSwap.hh"

vtkSTLWriter::vtkSTLWriter()
{
  this->Filename = NULL;
  this->FileType = VTK_ASCII;
}

vtkSTLWriter::~vtkSTLWriter()
{
  if ( this->Filename ) delete [] this->Filename;
}

// Description:
// Specify the input data or filter.
void vtkSTLWriter::SetInput(vtkPolyData *input)
{
  if ( this->Input != input )
    {
    vtkDebugMacro(<<" setting Input to " << (void *)input);
    this->Input = (vtkDataSet *) input;
    this->Modified();
    }
}

void vtkSTLWriter::WriteData()
{
  vtkPoints *pts;
  vtkCellArray *polys;
  vtkPolyData *input=(vtkPolyData *)this->Input;

  polys = input->GetPolys();
  pts = input->GetPoints();
  if (pts == NULL || polys == NULL )
    {
    vtkErrorMacro(<<"No data to write!");
    return;
    }

  if ( this->Filename == NULL)
    {
    vtkErrorMacro(<< "Please specify filename to write");
    return;
    }

  if ( this->FileType == VTK_BINARY ) this->WriteBinarySTL(pts,polys);
  else this->WriteAsciiSTL(pts,polys);
}

static char header[]="Visualization Toolkit generated SLA File                                        ";

void vtkSTLWriter::WriteAsciiSTL(vtkPoints *pts, vtkCellArray *polys)
{
  FILE *fp;
  float n[3], *v1, *v2, *v3;
  int npts, *indx;
  vtkPolygon poly;

  if ((fp = fopen(this->Filename, "w")) == NULL)
    {
    vtkErrorMacro(<< "Couldn't open file: " << this->Filename);
    return;
    }
//
//  Write header
//
  vtkDebugMacro("Writing ASCII sla file");
  fprintf (fp, "%80s\n", header);
//
//  Write out triangle polygons.  In not a triangle polygon, only first
//  three vertices are written.
//
  for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
    {
    v1 = pts->GetPoint(indx[0]);
    v2 = pts->GetPoint(indx[1]);
    v3 = pts->GetPoint(indx[2]);

    poly.ComputeNormal(pts, npts, indx, n);

    fprintf (fp, " FACET NORMAL %.6g %.6g %.6g\n  OUTER LOOP\n",
            n[0], n[1], n[2]);

    fprintf (fp, "   VERTEX %.6g %.6g %.6g\n", v1[0], v1[1], v1[2]);
    fprintf (fp, "   VERTEX %.6g %.6g %.6g\n", v2[0], v2[1], v2[2]);
    fprintf (fp, "   VERTEX %.6g %.6g %.6g\n", v3[0], v3[1], v3[2]);

    fprintf (fp, "  ENDLOOP\n ENDFACET\n");
    }
  fprintf (fp, "ENDSOLID\n");
  fclose (fp);
}

void vtkSTLWriter::WriteBinarySTL(vtkPoints *pts, vtkCellArray *polys)
{
  FILE *fp;
  float n[3], *v1, *v2, *v3;
  int npts, *indx;
  vtkPolygon poly;
  vtkByteSwap swap;
  unsigned long ulint;
  unsigned short ibuff2=0;

  if ((fp = fopen(this->Filename, "wb")) == NULL)
    {
    vtkErrorMacro(<< "Couldn't open file: " << this->Filename);
    return;
    }
//
//  Write header
//
  vtkDebugMacro("Writing Binary sla file");
  fwrite (header, 1, 80, fp);

  ulint = (unsigned long int) polys->GetNumberOfCells();
  swap.Swap4LE(&ulint);
  fwrite (&ulint, 1, 4, fp);
//
//  Write out triangle polygons.  In not a triangle polygon, only first
//  three vertices are written.
//
  for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
    {
    v1 = pts->GetPoint(indx[0]);
    v2 = pts->GetPoint(indx[1]);
    v3 = pts->GetPoint(indx[2]);

    poly.ComputeNormal(pts, npts, indx, n);
    swap.Swap4LE(n); swap.Swap4LE(n+1); swap.Swap4LE(n+2);
    fwrite (n, 4, 3, fp);

    n[0] = v1[0];  n[1] = v1[1];  n[2] = v1[2];
    swap.Swap4LE(n); swap.Swap4LE(n+1); swap.Swap4LE(n+2);
    fwrite (n, 4, 3, fp);

    n[0] = v2[0];  n[1] = v2[1];  n[2] = v2[2];
    swap.Swap4LE(n); swap.Swap4LE(n+1); swap.Swap4LE(n+2);
    fwrite (n, 4, 3, fp);

    n[0] = v3[0];  n[1] = v3[1];  n[2] = v3[2];
    swap.Swap4LE(n); swap.Swap4LE(n+1); swap.Swap4LE(n+2);
    fwrite (n, 4, 3, fp);

    fwrite (&ibuff2, 2, 1, fp);
    }
  fclose (fp);
}

void vtkSTLWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkWriter::PrintSelf(os,indent);

  os << indent << "Filename: " << this->Filename << "\n";

  if ( this->FileType == VTK_ASCII  )
    os << indent << "FileType: ASCII\n";
  else
    os << indent << "FileType: BINARY\n";
}

<commit_msg>ERR: Removed SetInput. No longer required when inheriting from vtkPolyWriter.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSTLWriter.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkSTLWriter.hh"
#include "vtkPolygon.hh"
#include "vtkByteSwap.hh"

vtkSTLWriter::vtkSTLWriter()
{
  this->Filename = NULL;
  this->FileType = VTK_ASCII;
}

vtkSTLWriter::~vtkSTLWriter()
{
  if ( this->Filename ) delete [] this->Filename;
}

void vtkSTLWriter::WriteData()
{
  vtkPoints *pts;
  vtkCellArray *polys;
  vtkPolyData *input=(vtkPolyData *)this->Input;

  polys = input->GetPolys();
  pts = input->GetPoints();
  if (pts == NULL || polys == NULL )
    {
    vtkErrorMacro(<<"No data to write!");
    return;
    }

  if ( this->Filename == NULL)
    {
    vtkErrorMacro(<< "Please specify filename to write");
    return;
    }

  if ( this->FileType == VTK_BINARY ) this->WriteBinarySTL(pts,polys);
  else this->WriteAsciiSTL(pts,polys);
}

static char header[]="Visualization Toolkit generated SLA File                                        ";

void vtkSTLWriter::WriteAsciiSTL(vtkPoints *pts, vtkCellArray *polys)
{
  FILE *fp;
  float n[3], *v1, *v2, *v3;
  int npts, *indx;
  vtkPolygon poly;

  if ((fp = fopen(this->Filename, "w")) == NULL)
    {
    vtkErrorMacro(<< "Couldn't open file: " << this->Filename);
    return;
    }
//
//  Write header
//
  vtkDebugMacro("Writing ASCII sla file");
  fprintf (fp, "%80s\n", header);
//
//  Write out triangle polygons.  In not a triangle polygon, only first
//  three vertices are written.
//
  for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
    {
    v1 = pts->GetPoint(indx[0]);
    v2 = pts->GetPoint(indx[1]);
    v3 = pts->GetPoint(indx[2]);

    poly.ComputeNormal(pts, npts, indx, n);

    fprintf (fp, " FACET NORMAL %.6g %.6g %.6g\n  OUTER LOOP\n",
            n[0], n[1], n[2]);

    fprintf (fp, "   VERTEX %.6g %.6g %.6g\n", v1[0], v1[1], v1[2]);
    fprintf (fp, "   VERTEX %.6g %.6g %.6g\n", v2[0], v2[1], v2[2]);
    fprintf (fp, "   VERTEX %.6g %.6g %.6g\n", v3[0], v3[1], v3[2]);

    fprintf (fp, "  ENDLOOP\n ENDFACET\n");
    }
  fprintf (fp, "ENDSOLID\n");
  fclose (fp);
}

void vtkSTLWriter::WriteBinarySTL(vtkPoints *pts, vtkCellArray *polys)
{
  FILE *fp;
  float n[3], *v1, *v2, *v3;
  int npts, *indx;
  vtkPolygon poly;
  vtkByteSwap swap;
  unsigned long ulint;
  unsigned short ibuff2=0;

  if ((fp = fopen(this->Filename, "wb")) == NULL)
    {
    vtkErrorMacro(<< "Couldn't open file: " << this->Filename);
    return;
    }
//
//  Write header
//
  vtkDebugMacro("Writing Binary sla file");
  fwrite (header, 1, 80, fp);

  ulint = (unsigned long int) polys->GetNumberOfCells();
  swap.Swap4LE(&ulint);
  fwrite (&ulint, 1, 4, fp);
//
//  Write out triangle polygons.  In not a triangle polygon, only first
//  three vertices are written.
//
  for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
    {
    v1 = pts->GetPoint(indx[0]);
    v2 = pts->GetPoint(indx[1]);
    v3 = pts->GetPoint(indx[2]);

    poly.ComputeNormal(pts, npts, indx, n);
    swap.Swap4LE(n); swap.Swap4LE(n+1); swap.Swap4LE(n+2);
    fwrite (n, 4, 3, fp);

    n[0] = v1[0];  n[1] = v1[1];  n[2] = v1[2];
    swap.Swap4LE(n); swap.Swap4LE(n+1); swap.Swap4LE(n+2);
    fwrite (n, 4, 3, fp);

    n[0] = v2[0];  n[1] = v2[1];  n[2] = v2[2];
    swap.Swap4LE(n); swap.Swap4LE(n+1); swap.Swap4LE(n+2);
    fwrite (n, 4, 3, fp);

    n[0] = v3[0];  n[1] = v3[1];  n[2] = v3[2];
    swap.Swap4LE(n); swap.Swap4LE(n+1); swap.Swap4LE(n+2);
    fwrite (n, 4, 3, fp);

    fwrite (&ibuff2, 2, 1, fp);
    }
  fclose (fp);
}

void vtkSTLWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkWriter::PrintSelf(os,indent);

  os << indent << "Filename: " << this->Filename << "\n";

  if ( this->FileType == VTK_ASCII  )
    os << indent << "FileType: ASCII\n";
  else
    os << indent << "FileType: BINARY\n";
}

<|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 "SkOrderedWriteBuffer.h"
#include "SkBitmap.h"
#include "SkData.h"
#include "SkPixelRef.h"
#include "SkPtrRecorder.h"
#include "SkStream.h"
#include "SkTypeface.h"

SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize)
    : INHERITED()
    , fFactorySet(NULL)
    , fNamedFactorySet(NULL)
    , fWriter(minSize)
    , fBitmapHeap(NULL)
    , fTFSet(NULL)
    , fBitmapEncoder(NULL) {
}

SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize, void* storage, size_t storageSize)
    : INHERITED()
    , fFactorySet(NULL)
    , fNamedFactorySet(NULL)
    , fWriter(minSize, storage, storageSize)
    , fBitmapHeap(NULL)
    , fTFSet(NULL)
    , fBitmapEncoder(NULL) {
}

SkOrderedWriteBuffer::~SkOrderedWriteBuffer() {
    SkSafeUnref(fFactorySet);
    SkSafeUnref(fNamedFactorySet);
    SkSafeUnref(fBitmapHeap);
    SkSafeUnref(fTFSet);
}

void SkOrderedWriteBuffer::writeByteArray(const void* data, size_t size) {
    fWriter.write32(size);
    fWriter.writePad(data, size);
}

void SkOrderedWriteBuffer::writeBool(bool value) {
    fWriter.writeBool(value);
}

void SkOrderedWriteBuffer::writeFixed(SkFixed value) {
    fWriter.write32(value);
}

void SkOrderedWriteBuffer::writeScalar(SkScalar value) {
    fWriter.writeScalar(value);
}

void SkOrderedWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) {
    fWriter.write32(count);
    fWriter.write(value, count * sizeof(SkScalar));
}

void SkOrderedWriteBuffer::writeInt(int32_t value) {
    fWriter.write32(value);
}

void SkOrderedWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) {
    fWriter.write32(count);
    fWriter.write(value, count * sizeof(int32_t));
}

void SkOrderedWriteBuffer::writeUInt(uint32_t value) {
    fWriter.write32(value);
}

void SkOrderedWriteBuffer::write32(int32_t value) {
    fWriter.write32(value);
}

void SkOrderedWriteBuffer::writeString(const char* value) {
    fWriter.writeString(value);
}

void SkOrderedWriteBuffer::writeEncodedString(const void* value, size_t byteLength,
                                              SkPaint::TextEncoding encoding) {
    fWriter.writeInt(encoding);
    fWriter.writeInt(byteLength);
    fWriter.write(value, byteLength);
}

void SkOrderedWriteBuffer::writeColor(const SkColor& color) {
    fWriter.write32(color);
}

void SkOrderedWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) {
    fWriter.write32(count);
    fWriter.write(color, count * sizeof(SkColor));
}

void SkOrderedWriteBuffer::writePoint(const SkPoint& point) {
    fWriter.writeScalar(point.fX);
    fWriter.writeScalar(point.fY);
}

void SkOrderedWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) {
    fWriter.write32(count);
    fWriter.write(point, count * sizeof(SkPoint));
}

void SkOrderedWriteBuffer::writeMatrix(const SkMatrix& matrix) {
    fWriter.writeMatrix(matrix);
}

void SkOrderedWriteBuffer::writeIRect(const SkIRect& rect) {
    fWriter.write(&rect, sizeof(SkIRect));
}

void SkOrderedWriteBuffer::writeRect(const SkRect& rect) {
    fWriter.writeRect(rect);
}

void SkOrderedWriteBuffer::writeRegion(const SkRegion& region) {
    fWriter.writeRegion(region);
}

void SkOrderedWriteBuffer::writePath(const SkPath& path) {
    fWriter.writePath(path);
}

size_t SkOrderedWriteBuffer::writeStream(SkStream* stream, size_t length) {
    return fWriter.readFromStream(stream, length);
}

bool SkOrderedWriteBuffer::writeToStream(SkWStream* stream) {
    return fWriter.writeToStream(stream);
}

void SkOrderedWriteBuffer::writeBitmap(const SkBitmap& bitmap) {
    // Record information about the bitmap in one of three ways, in order of priority:
    // 1. If there is an SkBitmapHeap, store it in the heap. The client can avoid serializing the
    //    bitmap entirely or serialize it later as desired.
    // 2. Write an encoded version of the bitmap. Afterwards the width and height are written, so
    //    a reader without a decoder can draw a dummy bitmap of the right size.
    //    A. If the bitmap has an encoded representation, write it to the stream.
    //    B. If there is a function for encoding bitmaps, use it.
    // 3. Call SkBitmap::flatten.
    // For an encoded bitmap, write the size first. Otherwise store a 0 so the reader knows not to
    // decode.
    if (fBitmapHeap != NULL) {
        SkASSERT(NULL == fBitmapEncoder);
        // Bitmap was not encoded. Record a zero, implying that the reader need not decode.
        this->writeUInt(0);
        int32_t slot = fBitmapHeap->insert(bitmap);
        fWriter.write32(slot);
        // crbug.com/155875
        // The generation ID is not required information. We write it to prevent collisions
        // in SkFlatDictionary.  It is possible to get a collision when a previously
        // unflattened (i.e. stale) instance of a similar flattenable is in the dictionary
        // and the instance currently being written is re-using the same slot from the
        // bitmap heap.
        fWriter.write32(bitmap.getGenerationID());
        return;
    }
    bool encoded = false;
    // Before attempting to encode the SkBitmap, check to see if there is already an encoded
    // version.
    SkPixelRef* ref = bitmap.pixelRef();
    if (ref != NULL) {
        SkAutoDataUnref data(ref->refEncodedData());
        if (data.get() != NULL) {
            // Write the length to indicate that the bitmap was encoded successfully, followed
            // by the actual data. This must match the case where fBitmapEncoder is used so the
            // reader need not know the difference.
            this->writeUInt(data->size());
            fWriter.writePad(data->data(), data->size());
            encoded = true;
        }
    }
    if (fBitmapEncoder != NULL && !encoded) {
        SkASSERT(NULL == fBitmapHeap);
        SkDynamicMemoryWStream stream;
        if (fBitmapEncoder(&stream, bitmap)) {
            uint32_t offset = fWriter.bytesWritten();
            // Write the length to indicate that the bitmap was encoded successfully, followed
            // by the actual data. This must match the case where the original data is used so the
            // reader need not know the difference.
            size_t length = stream.getOffset();
            this->writeUInt(length);
            if (stream.read(fWriter.reservePad(length), 0, length)) {
                encoded = true;
            } else {
                // Writing the stream failed, so go back to original state to store another way.
                fWriter.rewindToOffset(offset);
            }
        }
    }
    if (encoded) {
        // Write the width and height in case the reader does not have a decoder.
        this->writeInt(bitmap.width());
        this->writeInt(bitmap.height());
    } else {
        // Bitmap was not encoded. Record a zero, implying that the reader need not decode.
        this->writeUInt(0);
        bitmap.flatten(*this);
    }
}

void SkOrderedWriteBuffer::writeTypeface(SkTypeface* obj) {
    if (NULL == obj || NULL == fTFSet) {
        fWriter.write32(0);
    } else {
        fWriter.write32(fTFSet->add(obj));
    }
}

SkFactorySet* SkOrderedWriteBuffer::setFactoryRecorder(SkFactorySet* rec) {
    SkRefCnt_SafeAssign(fFactorySet, rec);
    if (fNamedFactorySet != NULL) {
        fNamedFactorySet->unref();
        fNamedFactorySet = NULL;
    }
    return rec;
}

SkNamedFactorySet* SkOrderedWriteBuffer::setNamedFactoryRecorder(SkNamedFactorySet* rec) {
    SkRefCnt_SafeAssign(fNamedFactorySet, rec);
    if (fFactorySet != NULL) {
        fFactorySet->unref();
        fFactorySet = NULL;
    }
    return rec;
}

SkRefCntSet* SkOrderedWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) {
    SkRefCnt_SafeAssign(fTFSet, rec);
    return rec;
}

void SkOrderedWriteBuffer::setBitmapHeap(SkBitmapHeap* bitmapHeap) {
    SkRefCnt_SafeAssign(fBitmapHeap, bitmapHeap);
    if (bitmapHeap != NULL) {
        SkASSERT(NULL == fBitmapEncoder);
        fBitmapEncoder = NULL;
    }
}

void SkOrderedWriteBuffer::setBitmapEncoder(SkSerializationHelpers::EncodeBitmap bitmapEncoder) {
    fBitmapEncoder = bitmapEncoder;
    if (bitmapEncoder != NULL) {
        SkASSERT(NULL == fBitmapHeap);
        SkSafeUnref(fBitmapHeap);
        fBitmapHeap = NULL;
    }
}

void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) {
    /*
     *  If we have a factoryset, then the first 32bits tell us...
     *       0: failure to write the flattenable
     *      >0: (1-based) index into the SkFactorySet or SkNamedFactorySet
     *  If we don't have a factoryset, then the first "ptr" is either the
     *  factory, or null for failure.
     *
     *  The distinction is important, since 0-index is 32bits (always), but a
     *  0-functionptr might be 32 or 64 bits.
     */

    SkFlattenable::Factory factory = NULL;
    if (flattenable) {
        factory = flattenable->getFactory();
    }
    if (NULL == factory) {
        if (fFactorySet != NULL || fNamedFactorySet != NULL) {
            this->write32(0);
        } else {
            this->writeFunctionPtr(NULL);
        }
        return;
    }

    /*
     *  We can write 1 of 3 versions of the flattenable:
     *  1.  function-ptr : this is the fastest for the reader, but assumes that
     *      the writer and reader are in the same process.
     *  2.  index into fFactorySet : This is assumes the writer will later
     *      resolve the function-ptrs into strings for its reader. SkPicture
     *      does exactly this, by writing a table of names (matching the indices)
     *      up front in its serialized form.
     *  3.  index into fNamedFactorySet. fNamedFactorySet will also store the
     *      name. SkGPipe uses this technique so it can write the name to its
     *      stream before writing the flattenable.
     */
    if (fFactorySet) {
        this->write32(fFactorySet->add(factory));
    } else if (fNamedFactorySet) {
        int32_t index = fNamedFactorySet->find(factory);
        this->write32(index);
        if (0 == index) {
            return;
        }
    } else {
        this->writeFunctionPtr((void*)factory);
    }

    // make room for the size of the flattened object
    (void)fWriter.reserve(sizeof(uint32_t));
    // record the current size, so we can subtract after the object writes.
    uint32_t offset = fWriter.size();
    // now flatten the object
    flattenObject(flattenable, *this);
    uint32_t objSize = fWriter.size() - offset;
    // record the obj's size
    *fWriter.peek32(offset - sizeof(uint32_t)) = objSize;
}
<commit_msg>Ensure that streams written using SkFlattenableBuffer's can be read with readByteArray(...)<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 "SkOrderedWriteBuffer.h"
#include "SkBitmap.h"
#include "SkData.h"
#include "SkPixelRef.h"
#include "SkPtrRecorder.h"
#include "SkStream.h"
#include "SkTypeface.h"

SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize)
    : INHERITED()
    , fFactorySet(NULL)
    , fNamedFactorySet(NULL)
    , fWriter(minSize)
    , fBitmapHeap(NULL)
    , fTFSet(NULL)
    , fBitmapEncoder(NULL) {
}

SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize, void* storage, size_t storageSize)
    : INHERITED()
    , fFactorySet(NULL)
    , fNamedFactorySet(NULL)
    , fWriter(minSize, storage, storageSize)
    , fBitmapHeap(NULL)
    , fTFSet(NULL)
    , fBitmapEncoder(NULL) {
}

SkOrderedWriteBuffer::~SkOrderedWriteBuffer() {
    SkSafeUnref(fFactorySet);
    SkSafeUnref(fNamedFactorySet);
    SkSafeUnref(fBitmapHeap);
    SkSafeUnref(fTFSet);
}

void SkOrderedWriteBuffer::writeByteArray(const void* data, size_t size) {
    fWriter.write32(size);
    fWriter.writePad(data, size);
}

void SkOrderedWriteBuffer::writeBool(bool value) {
    fWriter.writeBool(value);
}

void SkOrderedWriteBuffer::writeFixed(SkFixed value) {
    fWriter.write32(value);
}

void SkOrderedWriteBuffer::writeScalar(SkScalar value) {
    fWriter.writeScalar(value);
}

void SkOrderedWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) {
    fWriter.write32(count);
    fWriter.write(value, count * sizeof(SkScalar));
}

void SkOrderedWriteBuffer::writeInt(int32_t value) {
    fWriter.write32(value);
}

void SkOrderedWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) {
    fWriter.write32(count);
    fWriter.write(value, count * sizeof(int32_t));
}

void SkOrderedWriteBuffer::writeUInt(uint32_t value) {
    fWriter.write32(value);
}

void SkOrderedWriteBuffer::write32(int32_t value) {
    fWriter.write32(value);
}

void SkOrderedWriteBuffer::writeString(const char* value) {
    fWriter.writeString(value);
}

void SkOrderedWriteBuffer::writeEncodedString(const void* value, size_t byteLength,
                                              SkPaint::TextEncoding encoding) {
    fWriter.writeInt(encoding);
    fWriter.writeInt(byteLength);
    fWriter.write(value, byteLength);
}

void SkOrderedWriteBuffer::writeColor(const SkColor& color) {
    fWriter.write32(color);
}

void SkOrderedWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) {
    fWriter.write32(count);
    fWriter.write(color, count * sizeof(SkColor));
}

void SkOrderedWriteBuffer::writePoint(const SkPoint& point) {
    fWriter.writeScalar(point.fX);
    fWriter.writeScalar(point.fY);
}

void SkOrderedWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) {
    fWriter.write32(count);
    fWriter.write(point, count * sizeof(SkPoint));
}

void SkOrderedWriteBuffer::writeMatrix(const SkMatrix& matrix) {
    fWriter.writeMatrix(matrix);
}

void SkOrderedWriteBuffer::writeIRect(const SkIRect& rect) {
    fWriter.write(&rect, sizeof(SkIRect));
}

void SkOrderedWriteBuffer::writeRect(const SkRect& rect) {
    fWriter.writeRect(rect);
}

void SkOrderedWriteBuffer::writeRegion(const SkRegion& region) {
    fWriter.writeRegion(region);
}

void SkOrderedWriteBuffer::writePath(const SkPath& path) {
    fWriter.writePath(path);
}

size_t SkOrderedWriteBuffer::writeStream(SkStream* stream, size_t length) {
    fWriter.write32(length);
    size_t bytesWritten = fWriter.readFromStream(stream, length);
    if (bytesWritten < length) {
        fWriter.reservePad(length - bytesWritten);
    }
    return bytesWritten;
}

bool SkOrderedWriteBuffer::writeToStream(SkWStream* stream) {
    return fWriter.writeToStream(stream);
}

void SkOrderedWriteBuffer::writeBitmap(const SkBitmap& bitmap) {
    // Record information about the bitmap in one of three ways, in order of priority:
    // 1. If there is an SkBitmapHeap, store it in the heap. The client can avoid serializing the
    //    bitmap entirely or serialize it later as desired.
    // 2. Write an encoded version of the bitmap. Afterwards the width and height are written, so
    //    a reader without a decoder can draw a dummy bitmap of the right size.
    //    A. If the bitmap has an encoded representation, write it to the stream.
    //    B. If there is a function for encoding bitmaps, use it.
    // 3. Call SkBitmap::flatten.
    // For an encoded bitmap, write the size first. Otherwise store a 0 so the reader knows not to
    // decode.
    if (fBitmapHeap != NULL) {
        SkASSERT(NULL == fBitmapEncoder);
        // Bitmap was not encoded. Record a zero, implying that the reader need not decode.
        this->writeUInt(0);
        int32_t slot = fBitmapHeap->insert(bitmap);
        fWriter.write32(slot);
        // crbug.com/155875
        // The generation ID is not required information. We write it to prevent collisions
        // in SkFlatDictionary.  It is possible to get a collision when a previously
        // unflattened (i.e. stale) instance of a similar flattenable is in the dictionary
        // and the instance currently being written is re-using the same slot from the
        // bitmap heap.
        fWriter.write32(bitmap.getGenerationID());
        return;
    }
    bool encoded = false;
    // Before attempting to encode the SkBitmap, check to see if there is already an encoded
    // version.
    SkPixelRef* ref = bitmap.pixelRef();
    if (ref != NULL) {
        SkAutoDataUnref data(ref->refEncodedData());
        if (data.get() != NULL) {
            // Write the length to indicate that the bitmap was encoded successfully, followed
            // by the actual data. This must match the case where fBitmapEncoder is used so the
            // reader need not know the difference.
            this->writeUInt(data->size());
            fWriter.writePad(data->data(), data->size());
            encoded = true;
        }
    }
    if (fBitmapEncoder != NULL && !encoded) {
        SkASSERT(NULL == fBitmapHeap);
        SkDynamicMemoryWStream stream;
        if (fBitmapEncoder(&stream, bitmap)) {
            uint32_t offset = fWriter.bytesWritten();
            // Write the length to indicate that the bitmap was encoded successfully, followed
            // by the actual data. This must match the case where the original data is used so the
            // reader need not know the difference.
            size_t length = stream.getOffset();
            this->writeUInt(length);
            if (stream.read(fWriter.reservePad(length), 0, length)) {
                encoded = true;
            } else {
                // Writing the stream failed, so go back to original state to store another way.
                fWriter.rewindToOffset(offset);
            }
        }
    }
    if (encoded) {
        // Write the width and height in case the reader does not have a decoder.
        this->writeInt(bitmap.width());
        this->writeInt(bitmap.height());
    } else {
        // Bitmap was not encoded. Record a zero, implying that the reader need not decode.
        this->writeUInt(0);
        bitmap.flatten(*this);
    }
}

void SkOrderedWriteBuffer::writeTypeface(SkTypeface* obj) {
    if (NULL == obj || NULL == fTFSet) {
        fWriter.write32(0);
    } else {
        fWriter.write32(fTFSet->add(obj));
    }
}

SkFactorySet* SkOrderedWriteBuffer::setFactoryRecorder(SkFactorySet* rec) {
    SkRefCnt_SafeAssign(fFactorySet, rec);
    if (fNamedFactorySet != NULL) {
        fNamedFactorySet->unref();
        fNamedFactorySet = NULL;
    }
    return rec;
}

SkNamedFactorySet* SkOrderedWriteBuffer::setNamedFactoryRecorder(SkNamedFactorySet* rec) {
    SkRefCnt_SafeAssign(fNamedFactorySet, rec);
    if (fFactorySet != NULL) {
        fFactorySet->unref();
        fFactorySet = NULL;
    }
    return rec;
}

SkRefCntSet* SkOrderedWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) {
    SkRefCnt_SafeAssign(fTFSet, rec);
    return rec;
}

void SkOrderedWriteBuffer::setBitmapHeap(SkBitmapHeap* bitmapHeap) {
    SkRefCnt_SafeAssign(fBitmapHeap, bitmapHeap);
    if (bitmapHeap != NULL) {
        SkASSERT(NULL == fBitmapEncoder);
        fBitmapEncoder = NULL;
    }
}

void SkOrderedWriteBuffer::setBitmapEncoder(SkSerializationHelpers::EncodeBitmap bitmapEncoder) {
    fBitmapEncoder = bitmapEncoder;
    if (bitmapEncoder != NULL) {
        SkASSERT(NULL == fBitmapHeap);
        SkSafeUnref(fBitmapHeap);
        fBitmapHeap = NULL;
    }
}

void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) {
    /*
     *  If we have a factoryset, then the first 32bits tell us...
     *       0: failure to write the flattenable
     *      >0: (1-based) index into the SkFactorySet or SkNamedFactorySet
     *  If we don't have a factoryset, then the first "ptr" is either the
     *  factory, or null for failure.
     *
     *  The distinction is important, since 0-index is 32bits (always), but a
     *  0-functionptr might be 32 or 64 bits.
     */

    SkFlattenable::Factory factory = NULL;
    if (flattenable) {
        factory = flattenable->getFactory();
    }
    if (NULL == factory) {
        if (fFactorySet != NULL || fNamedFactorySet != NULL) {
            this->write32(0);
        } else {
            this->writeFunctionPtr(NULL);
        }
        return;
    }

    /*
     *  We can write 1 of 3 versions of the flattenable:
     *  1.  function-ptr : this is the fastest for the reader, but assumes that
     *      the writer and reader are in the same process.
     *  2.  index into fFactorySet : This is assumes the writer will later
     *      resolve the function-ptrs into strings for its reader. SkPicture
     *      does exactly this, by writing a table of names (matching the indices)
     *      up front in its serialized form.
     *  3.  index into fNamedFactorySet. fNamedFactorySet will also store the
     *      name. SkGPipe uses this technique so it can write the name to its
     *      stream before writing the flattenable.
     */
    if (fFactorySet) {
        this->write32(fFactorySet->add(factory));
    } else if (fNamedFactorySet) {
        int32_t index = fNamedFactorySet->find(factory);
        this->write32(index);
        if (0 == index) {
            return;
        }
    } else {
        this->writeFunctionPtr((void*)factory);
    }

    // make room for the size of the flattened object
    (void)fWriter.reserve(sizeof(uint32_t));
    // record the current size, so we can subtract after the object writes.
    uint32_t offset = fWriter.size();
    // now flatten the object
    flattenObject(flattenable, *this);
    uint32_t objSize = fWriter.size() - offset;
    // record the obj's size
    *fWriter.peek32(offset - sizeof(uint32_t)) = objSize;
}
<|endoftext|>


<commit_before>struct MfEdge {
  int v, cap, cpu;
  int backid; // id to the back edge
};

struct FlowResult {
  int flow, cost;
};

struct McMaxFlow {
  vector<vector<int>> g;  // integers represent edges' ids
  vector<MfEdge> edges;   // edges.size() should always be even
  int n, s, t;            // n = # vertices, s = src vertex, t = sink vertex

  FlowResult find_path() {
    const int inf = int(1e9 + 7);
    vector<int> from(n, -1), used_edge(n, -1);

    vector<int> dist(n, inf);
    dist[s] = 0;
    for (int iter = 1; iter < n; ++iter) {
      for (int u = 0; u < n; ++u) {
        for (int eid : g[u]) {
          int v = edges[eid].v;
          int cand_dist = dist[u] + edges[eid].cpu;
          if (edges[eid].cap > 0 && cand_dist < dist[v]) {
            dist[v] = cand_dist;
            from[v] = u; used_edge[v] = eid;
          }
        }
      }
    }

    int f = 0, fcost = 0;
    if (from[t] != -1) {
      f = inf;
      for (int v = t; from[v] > -1; v = from[v]) {
        f = min(edges[used_edge[v]].cap, f);
        fcost += edges[used_edge[v]].cpu;
      }
      for (int v = t; from[v] > -1; v = from[v]) {
        int backid = edges[used_edge[v]].backid;
        edges[used_edge[v]].cap -= f;
        edges[backid].cap += f;
      }
      fcost *= f;
    }

    return (FlowResult){f, fcost};
  }

  FlowResult get() {
    FlowResult res = {0, 0};
    while (true) {
      FlowResult fr = find_path();
      if (fr.flow == 0) break;
      res.flow += fr.flow;
      res.cost += fr.cost;
    }
    return res;
  }
};
<commit_msg>Updated MinCostMaxFlow to use SPFA<commit_after>struct McMaxFlow {
  struct MfEdge { int v, cap, cpu, backid; };
  struct FlowResult { int flow, cost; };
  vector<vector<int>> g;  // integers represent edges' ids
  vector<MfEdge> edges;   // edges.size() should always be even
  int n, s, t;            // n = # vertices, s = src vertex, t = sink vertex

  // Directed Edge u - > v with capacity 'cap' and cost per unit 'cpu'
  void add_edge(int u, int v, int cap, int cpu) {
    int eid = edges.size();
    g[u].push_back(eid);
    g[v].push_back(eid + 1);
    edges.push_back((MfEdge){v, cap, cpu, eid + 1});
    edges.push_back((MfEdge){u, 0, -cpu, eid});
  }

  FlowResult find_path() {
    const int inf = int(1e9 + 7);
    vector<int> from(n, -1), used_edge(n, -1);

    vector<int> dist(n, inf);
    queue<int> q; vector<bool> queued(n, false);
    dist[s] = 0; q.push(s); queued[s] = true;

    while (!q.empty()) {
      const int u = q.front(); q.pop();
      queued[u] = false;

      for (int eid : g[u]) {
        int v = edges[eid].v;
        int cand_dist = dist[u] + edges[eid].cpu;
        if (edges[eid].cap > 0 && cand_dist < dist[v]) {
          dist[v] = cand_dist;
          from[v] = u; used_edge[v] = eid;
          if (!queued[v]) { q.push(v); queued[v] = true; }
        }
      }
    }

    int f = 0, fcost = 0;
    if (from[t] != -1) {
      f = inf;
      for (int v = t; from[v] > -1; v = from[v]) {
        f = min(edges[used_edge[v]].cap, f);
        fcost += edges[used_edge[v]].cpu;
      }
      for (int v = t; from[v] > -1; v = from[v]) {
        int backid = edges[used_edge[v]].backid;
        edges[used_edge[v]].cap -= f;
        edges[backid].cap += f;
      }
      fcost *= f;
    }

    return (FlowResult){f, fcost};
  }

  FlowResult get() {
    FlowResult res = {0, 0};
    while (true) {
      FlowResult fr = find_path();
      if (fr.flow == 0) break;
      res.flow += fr.flow;
      res.cost += fr.cost;
    }
    return res;
  }
};
<|endoftext|>


<commit_before>/*
 * GameKeeper Framework
 *
 * Copyright (C) 2013 Karol Herbst <gamekeeper@karolherbst.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <gamekeeper/core/log4cppLogger.h>
#include <gamekeeper/core/log4cpploggerFactory.h>
#include <gamekeeper/core/userpaths.h>

#include <string>
#include <vector>

#include <boost/algorithm/string/erase.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>

#include <log4cpp/Category.hh>
#include <log4cpp/Configurator.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/Priority.hh>

// sadly this is the only way to use a different file format to configure our logger :(
// reimplmeneting this doesn't make much sense to me
namespace log4cpp
{
	class PropertyConfiguratorImpl
	{
	public:
		PropertyConfiguratorImpl();
		virtual ~PropertyConfiguratorImpl();
		virtual void doConfigure(std::istream& in) throw (ConfigureFailure);
	};
}

namespace balgo = boost::algorithm;
namespace bfs = boost::filesystem;
namespace bio = boost::iostreams;

GAMEKEEPER_NAMESPACE_START(core)

static std::string
parseLine(std::string line, std::shared_ptr<UserPaths> & userpaths)
{
	balgo::erase_all(line, " ");
	std::string::size_type pos = line.find(".fileName=");

	if(pos != std::string::npos)
	{
		std::string filename = line.substr(pos + 10);
		bfs::path logfile = userpaths->getDataFile(std::string("log/") + filename);
		bfs::create_directories(logfile.parent_path());
		line.replace(pos + 10, std::string::npos, logfile.string());
	}

	if(line.find_first_of("rootCategory") != 0)
	{
		balgo::replace_all(line, "category.", "category.GameKeeper.");
	}
	return line;
}

Log4cppLoggerFactory::Log4cppLoggerFactory(std::shared_ptr<UserPaths> userpaths)
:	appender(new log4cpp::OstreamAppender("console", &std::cout))
{
	log4cpp::Category & rootCategory = log4cpp::Category::getInstance("GameKeeper");

	// add default appender
	log4cpp::PatternLayout * layout = new log4cpp::PatternLayout();
	layout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S} [%c] %p: %m%n");
	this->appender->setLayout(layout);

	// start with DEBUG level until the file is loaded, so that we get all errors
	rootCategory.setPriority(log4cpp::Priority::DEBUG);
	rootCategory.addAppender(this->appender);

	this->rootLogger = new Log4cppLogger(rootCategory);

	// read configuration file if exists
	bfs::path cFile = userpaths->getConfigFile("log.conf");
	if(!bfs::exists(cFile))
	{
		return;
	}

	Logger& logger = this->getComponentLogger("logger");
	logger << LogLevel::Debug << "parse config file at: " << cFile.string() << endl;

	bfs::ifstream ifstream(cFile);
	std::vector<char> buffer;
	std::string line;
	std::string parsedLine;

	while(!ifstream.eof())
	{
		std::getline(ifstream, line);
		// ignore empty lines
		if(line.empty())
		{
			continue;
		}

		parsedLine = parseLine(line, userpaths);
		logger << LogLevel::Debug << "parsed line \"" << line << "\" to: \"" << parsedLine << "\"" << endl;
		buffer.insert(buffer.end(), parsedLine.begin(), parsedLine.end());
		buffer.insert(buffer.end(), '\n');
	}

	// ignore the file if nothing was parsed
	if(buffer.empty())
	{
		return;
	}

	logger << LogLevel::Info << "moving to new configuration" << endl;

	bio::stream<bio::array_source> stream(buffer.data(), buffer.size());
	log4cpp::PropertyConfiguratorImpl pci;
	pci.doConfigure(stream);

	// we have another logger noew
	log4cpp::Category::getInstance("GameKeeper").removeAppender(this->appender);
	this->appender = nullptr;
	delete this->rootLogger;
	this->rootLogger = new Log4cppLogger(log4cpp::Category::getInstance("GameKeeper"));
}

Logger&
Log4cppLoggerFactory::getDefaultLogger()
{
	return getComponentLogger("GameKeeper.Default");
}

Logger&
Log4cppLoggerFactory::getComponentLogger(const char * const id)
{
	if(this->loggers.find(id) == this->loggers.end())
	{
		std::string log4cppname = "GameKeeper.";
		log4cppname += id;
		Logger * newLogger = new Log4cppLogger(log4cpp::Category::getInstance(log4cppname));
		this->loggers.insert(std::make_pair(id, newLogger));
		return *newLogger;
	}
	return *this->loggers.at(id);
}

Log4cppLoggerFactory::~Log4cppLoggerFactory()
{
	if(this->appender != nullptr)
	{
		log4cpp::Category::getInstance("GameKeeper").removeAppender(this->appender);
	}

	if(this->rootLogger != nullptr)
	{
		delete this->rootLogger;
	}

	for(auto entry : this->loggers)
	{
		delete entry.second;
	}
}

GAMEKEEPER_NAMESPACE_END(core)
<commit_msg>core/log4cpploggerfactory: remove usage of internal classes<commit_after>/*
 * GameKeeper Framework
 *
 * Copyright (C) 2013 Karol Herbst <gamekeeper@karolherbst.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <gamekeeper/core/log4cppLogger.h>
#include <gamekeeper/core/log4cpploggerFactory.h>
#include <gamekeeper/core/userpaths.h>

#include <string>
#include <vector>

#include <boost/algorithm/string/erase.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>

#include <log4cpp/Category.hh>
#include <log4cpp/Configurator.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/Priority.hh>
#include <log4cpp/PropertyConfigurator.hh>

namespace balgo = boost::algorithm;
namespace bfs = boost::filesystem;

GAMEKEEPER_NAMESPACE_START(core)

static std::string
parseLine(std::string line, std::shared_ptr<UserPaths> & userpaths)
{
	balgo::erase_all(line, " ");
	std::string::size_type pos = line.find(".fileName=");

	if(pos != std::string::npos)
	{
		std::string filename = line.substr(pos + 10);
		bfs::path logfile = userpaths->getDataFile(std::string("log/") + filename);
		bfs::create_directories(logfile.parent_path());
		line.replace(pos + 10, std::string::npos, logfile.string());
	}

	if(line.find_first_of("rootCategory") != 0)
	{
		balgo::replace_all(line, "category.", "category.GameKeeper.");
	}
	return line;
}

Log4cppLoggerFactory::Log4cppLoggerFactory(std::shared_ptr<UserPaths> userpaths)
:	appender(new log4cpp::OstreamAppender("console", &std::cout))
{
	log4cpp::Category & rootCategory = log4cpp::Category::getInstance("GameKeeper");

	// add default appender
	log4cpp::PatternLayout * layout = new log4cpp::PatternLayout();
	layout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S} [%c] %p: %m%n");
	this->appender->setLayout(layout);

	// start with DEBUG level until the file is loaded, so that we get all errors
	rootCategory.setPriority(log4cpp::Priority::DEBUG);
	rootCategory.addAppender(this->appender);

	this->rootLogger = new Log4cppLogger(rootCategory);

	// read configuration file if exists
	bfs::path cFile = userpaths->getConfigFile("log.conf");
	if(!bfs::exists(cFile))
	{
		return;
	}

	Logger& logger = this->getComponentLogger("logger");
	logger << LogLevel::Debug << "parse config file at: " << cFile.string() << endl;

	bfs::ifstream ifstream(cFile);
	bfs::path cFileGen = userpaths->getConfigFile("log.conf.gen");
	bfs::remove(cFileGen);
	bfs::ofstream ofstream(cFileGen);
	std::string line;
	std::string parsedLine;

	while(!ifstream.eof())
	{
		std::getline(ifstream, line);
		// ignore empty lines
		if(line.empty())
		{
			continue;
		}

		parsedLine = parseLine(line, userpaths);
		logger << LogLevel::Debug << "parsed line \"" << line << "\" to: \"" << parsedLine << "\"" << endl;
		ofstream << parsedLine << std::endl;
	}

	// ignore the file if nothing was parsed
	if(ofstream.tellp() <= 0)
	{
		return;
	}

	logger << LogLevel::Info << "moving to new configuration" << endl;

	log4cpp::PropertyConfigurator pci;
	pci.configure(cFileGen.string());
	bfs::remove(cFileGen);

	// we have another logger noew
	log4cpp::Category::getInstance("GameKeeper").removeAppender(this->appender);
	this->appender = nullptr;
	delete this->rootLogger;
	this->rootLogger = new Log4cppLogger(log4cpp::Category::getInstance("GameKeeper"));
}

Logger&
Log4cppLoggerFactory::getDefaultLogger()
{
	return getComponentLogger("GameKeeper.Default");
}

Logger&
Log4cppLoggerFactory::getComponentLogger(const char * const id)
{
	if(this->loggers.find(id) == this->loggers.end())
	{
		std::string log4cppname = "GameKeeper.";
		log4cppname += id;
		Logger * newLogger = new Log4cppLogger(log4cpp::Category::getInstance(log4cppname));
		this->loggers.insert(std::make_pair(id, newLogger));
		return *newLogger;
	}
	return *this->loggers.at(id);
}

Log4cppLoggerFactory::~Log4cppLoggerFactory()
{
	if(this->appender != nullptr)
	{
		log4cpp::Category::getInstance("GameKeeper").removeAppender(this->appender);
	}

	if(this->rootLogger != nullptr)
	{
		delete this->rootLogger;
	}

	for(auto entry : this->loggers)
	{
		delete entry.second;
	}
}

GAMEKEEPER_NAMESPACE_END(core)
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Netflix, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY NETFLIX, INC. AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NETFLIX OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "DialServer.h"
#include <curl/curl.h>

using namespace std;

enum DIAL_COMMAND{
    COMMAND_LAUNCH,
    COMMAND_STATUS,
    COMMAND_KILL
};

static size_t header_cb(void* ptr, size_t size, size_t nmemb, void* userdata)
{
    if ((size * nmemb) != 0) {
        string newHeader((char*)ptr);
        string *header = static_cast<string*>(userdata);
        header->append(newHeader);
        ATRACE("%s: Adding header: %s", __FUNCTION__, newHeader.c_str());
    }
    return (size * nmemb);
}

static size_t receiveData(void *ptr, size_t size, size_t nmemb, void *userdata)
{
    if ((size * nmemb) != 0) {
        string *body= static_cast<string*>(userdata);
        body->append((char*)ptr);
        ATRACE("%s: Adding to Body: %s", __FUNCTION__, (char*)ptr);
    }
    return (size * nmemb);
}

int DialServer::sendCommand(
        string &url,
        int command,
        string &payload,
        string &responseHeaders,
        string &responseBody )
{
    CURL *curl;
    CURLcode res = CURLE_OK;

    if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
    {
        fprintf(stderr, "curl_global_init() failed\n");
        return 0;
    }

    if ((curl = curl_easy_init()) == NULL)
    {
        fprintf(stderr, "curl_easy_init() failed\n");
        curl_global_cleanup();
        return 0;
    }

    if (command == COMMAND_LAUNCH)
    {
        curl_easy_setopt(curl, CURLOPT_POST, true);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, payload.size());
        if( payload.size() )
        {
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str());
        }
#ifdef DEBUG
        else ATRACE("Sending empty POST\n");
#endif
    }
    else if (command == COMMAND_KILL)
    {
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
    }
    ATRACE("Sending %s:%s\n",
        command == COMMAND_LAUNCH ? "LAUNCH" :
            (command == COMMAND_KILL ? "KILL" : "STATUS"),
        url.c_str());

    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_cb);
    curl_easy_setopt(curl, CURLOPT_HEADERDATA, &responseHeaders);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveData);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBody);
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
    curl_global_cleanup();
    return (res == CURLE_OK);
}

string DialServer::getIpAddress()
{
    // m_appsUrl=http://192.168.1.103:36269/apps/
    if( m_ipAddr.empty() )
    {
        size_t begin = m_appsUrl.find("//");
        if( begin != m_appsUrl.npos )
        {
            begin += 2; // move to the start of the IP address
            size_t end = m_appsUrl.find(":", begin);
            if( end != m_appsUrl.npos )
            {
                m_ipAddr = m_appsUrl.substr( begin, end-begin );
                ATRACE("IP ADDRESS: %s\n", m_ipAddr.c_str() );
            }
        }
    }
    return m_ipAddr;
}

bool DialServer::getFriendlyName( string& name )
{
    bool retval = false;
    if( !m_ddxml.empty() )
    {
        string friendlyName = "<friendlyName>";
        size_t pos;
        if( ( pos = m_ddxml.find( friendlyName ) ) != m_ddxml.npos )
        {
            string friendlyNameEnd = "</friendlyName>";
            size_t end = m_ddxml.find( friendlyNameEnd );
            name = m_ddxml.substr( pos + friendlyName.size(),
                        (end - (pos + friendlyName.size())) );
            ATRACE("***Friendly name=%s***", name.c_str());
            retval = true;
        }
#ifdef DEBUG
        else
        {
            ATRACE("Friendly name not found\n%s\n", m_ddxml.c_str());
        }
#endif
    }

    return retval;
}

bool DialServer::getUuid( string& uuid )
{
    bool retval = false;
    if( !m_ddxml.empty() )
    {
        string udn = "<UDN>";
        size_t pos;
        if( ( pos = m_ddxml.find( udn ) ) != m_ddxml.npos )
        {
            string udnEnd = "</UDN>";
            size_t end = m_ddxml.find( udnEnd );
            uuid = m_ddxml.substr( pos + udn.size(),
                        (end - (pos + udn.size())) );
            ATRACE("***UUID=%s***", uuid.c_str() );
            retval = true;
        }
#ifdef DEBUG
        else
        {
            ATRACE("Friendly name not found\n%s\n", m_ddxml.c_str());
        }
#endif
    }

    return retval;
}

int DialServer::launchApplication(
    string &application,
    string &payload,
    string &responseHeaders,
    string &responseBody )
{
    ATRACE("%s: Launch %s\n", __FUNCTION__, application.c_str());
    string appUrl = m_appsUrl;
    sendCommand( appUrl.append(application), COMMAND_LAUNCH, payload, responseHeaders, responseBody);
    return 0;
}

int DialServer::getStatus(
    string &application,
    string &responseHeaders,
    string &responseBody )
{
    ATRACE("%s: GetStatus %s\n", __FUNCTION__, application.c_str());
    string emptyPayload;
    string appUrl = m_appsUrl;
    sendCommand( appUrl.append(application), COMMAND_STATUS, emptyPayload, responseHeaders, responseBody );

    ATRACE("Body: %s\n", responseBody.c_str());
    unsigned found = responseBody.find("href=");
    if( found != string::npos )
    {
        // The start of href is after href= and the quote
        unsigned href_start = found + 5 + 1;

        // get the body from the start of href to the end, then find
        // the last quote delimiter.
        string tmp = responseBody.substr( href_start );
        unsigned href_end = tmp.find("\"");
        m_stopEndPoint = responseBody.substr( href_start, href_end );
    }
    return 0;
}

int DialServer::stopApplication(
    string &application,
    string &responseHeaders )
{
    ATRACE("%s: Quit %s\n", __FUNCTION__, application.c_str());
    string emptyPayload, responseBody;  // dropping this
    string appUrl = m_appsUrl;

    // just call status to update the run endpoint
    getStatus( application, responseHeaders, responseBody );

    sendCommand(
            (appUrl.append(application)).append("/"+m_stopEndPoint),
            COMMAND_KILL, emptyPayload, responseHeaders, responseBody );
    return 0;
}

int DialServer::getHttpResponseHeader(
    string &responseHeaders,
    string &header,
    string &value )
{
    return 0;
}
<commit_msg>add "/" between "apps" and app_name in case of sending request.<commit_after>/*
 * Copyright (c) 2014 Netflix, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY NETFLIX, INC. AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NETFLIX OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "DialServer.h"
#include <curl/curl.h>

using namespace std;

enum DIAL_COMMAND{
    COMMAND_LAUNCH,
    COMMAND_STATUS,
    COMMAND_KILL
};

static size_t header_cb(void* ptr, size_t size, size_t nmemb, void* userdata)
{
    if ((size * nmemb) != 0) {
        string newHeader((char*)ptr);
        string *header = static_cast<string*>(userdata);
        header->append(newHeader);
        ATRACE("%s: Adding header: %s", __FUNCTION__, newHeader.c_str());
    }
    return (size * nmemb);
}

static size_t receiveData(void *ptr, size_t size, size_t nmemb, void *userdata)
{
    if ((size * nmemb) != 0) {
        string *body= static_cast<string*>(userdata);
        body->append((char*)ptr);
        ATRACE("%s: Adding to Body: %s", __FUNCTION__, (char*)ptr);
    }
    return (size * nmemb);
}

int DialServer::sendCommand(
        string &url,
        int command,
        string &payload,
        string &responseHeaders,
        string &responseBody )
{
    CURL *curl;
    CURLcode res = CURLE_OK;

    if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
    {
        fprintf(stderr, "curl_global_init() failed\n");
        return 0;
    }

    if ((curl = curl_easy_init()) == NULL)
    {
        fprintf(stderr, "curl_easy_init() failed\n");
        curl_global_cleanup();
        return 0;
    }

    if (command == COMMAND_LAUNCH)
    {
        curl_easy_setopt(curl, CURLOPT_POST, true);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, payload.size());
        if( payload.size() )
        {
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str());
        }
#ifdef DEBUG
        else ATRACE("Sending empty POST\n");
#endif
    }
    else if (command == COMMAND_KILL)
    {
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
    }
    ATRACE("Sending %s:%s\n",
        command == COMMAND_LAUNCH ? "LAUNCH" :
            (command == COMMAND_KILL ? "KILL" : "STATUS"),
        url.c_str());

    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_cb);
    curl_easy_setopt(curl, CURLOPT_HEADERDATA, &responseHeaders);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveData);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBody);
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
    curl_global_cleanup();
    return (res == CURLE_OK);
}

string DialServer::getIpAddress()
{
    // m_appsUrl=http://192.168.1.103:36269/apps/
    if( m_ipAddr.empty() )
    {
        size_t begin = m_appsUrl.find("//");
        if( begin != m_appsUrl.npos )
        {
            begin += 2; // move to the start of the IP address
            size_t end = m_appsUrl.find(":", begin);
            if( end != m_appsUrl.npos )
            {
                m_ipAddr = m_appsUrl.substr( begin, end-begin );
                ATRACE("IP ADDRESS: %s\n", m_ipAddr.c_str() );
            }
        }
    }
    return m_ipAddr;
}

bool DialServer::getFriendlyName( string& name )
{
    bool retval = false;
    if( !m_ddxml.empty() )
    {
        string friendlyName = "<friendlyName>";
        size_t pos;
        if( ( pos = m_ddxml.find( friendlyName ) ) != m_ddxml.npos )
        {
            string friendlyNameEnd = "</friendlyName>";
            size_t end = m_ddxml.find( friendlyNameEnd );
            name = m_ddxml.substr( pos + friendlyName.size(),
                        (end - (pos + friendlyName.size())) );
            ATRACE("***Friendly name=%s***", name.c_str());
            retval = true;
        }
#ifdef DEBUG
        else
        {
            ATRACE("Friendly name not found\n%s\n", m_ddxml.c_str());
        }
#endif
    }

    return retval;
}

bool DialServer::getUuid( string& uuid )
{
    bool retval = false;
    if( !m_ddxml.empty() )
    {
        string udn = "<UDN>";
        size_t pos;
        if( ( pos = m_ddxml.find( udn ) ) != m_ddxml.npos )
        {
            string udnEnd = "</UDN>";
            size_t end = m_ddxml.find( udnEnd );
            uuid = m_ddxml.substr( pos + udn.size(),
                        (end - (pos + udn.size())) );
            ATRACE("***UUID=%s***", uuid.c_str() );
            retval = true;
        }
#ifdef DEBUG
        else
        {
            ATRACE("Friendly name not found\n%s\n", m_ddxml.c_str());
        }
#endif
    }

    return retval;
}

int DialServer::launchApplication(
    string &application,
    string &payload,
    string &responseHeaders,
    string &responseBody )
{
    ATRACE("%s: Launch %s\n", __FUNCTION__, application.c_str());
    string appUrl = m_appsUrl;
    appUrl.append("/");;
    sendCommand( appUrl.append(application), COMMAND_LAUNCH, payload, responseHeaders, responseBody);
    return 0;
}

int DialServer::getStatus(
    string &application,
    string &responseHeaders,
    string &responseBody )
{
    ATRACE("%s: GetStatus %s\n", __FUNCTION__, application.c_str());
    string emptyPayload;
    string appUrl = m_appsUrl;
    appUrl.append("/");;
    sendCommand( appUrl.append(application), COMMAND_STATUS, emptyPayload, responseHeaders, responseBody );

    ATRACE("Body: %s\n", responseBody.c_str());
    unsigned found = responseBody.find("href=");
    if( found != string::npos )
    {
        // The start of href is after href= and the quote
        unsigned href_start = found + 5 + 1;

        // get the body from the start of href to the end, then find
        // the last quote delimiter.
        string tmp = responseBody.substr( href_start );
        unsigned href_end = tmp.find("\"");
        m_stopEndPoint = responseBody.substr( href_start, href_end );
    }
    return 0;
}

int DialServer::stopApplication(
    string &application,
    string &responseHeaders )
{
    ATRACE("%s: Quit %s\n", __FUNCTION__, application.c_str());
    string emptyPayload, responseBody;  // dropping this
    string appUrl = m_appsUrl;
    appUrl.append("/");;

    // just call status to update the run endpoint
    getStatus( application, responseHeaders, responseBody );

    sendCommand(
            (appUrl.append(application)).append("/"+m_stopEndPoint),
            COMMAND_KILL, emptyPayload, responseHeaders, responseBody );
    return 0;
}

int DialServer::getHttpResponseHeader(
    string &responseHeaders,
    string &header,
    string &value )
{
    return 0;
}
<|endoftext|>