<commit_before>#include "output_ts_base.h"
#include <mist/bitfields.h>

namespace Mist{
  TSOutput::TSOutput(Socket::Connection &conn) : TS_BASECLASS(conn){
    packCounter = 0;
    ts_from = 0;
    setBlocking(true);
    sendRepeatingHeaders = 0;
    lastHeaderTime = 0;
  }

  void TSOutput::fillPacket(char const *data, size_t dataLen, bool &firstPack, bool video,
                            bool keyframe, size_t pkgPid, uint16_t &contPkg){
    do{
      if (!packData.getBytesFree()){
        if ((sendRepeatingHeaders && thisPacket.getTime() - lastHeaderTime > sendRepeatingHeaders) || !packCounter){

          std::set<size_t> selectedTracks;
          for (std::map<size_t, Comms::Users>::iterator it = userSelect.begin(); it != userSelect.end(); it++){
            selectedTracks.insert(it->first);
          }

          lastHeaderTime = thisPacket.getTime();
          TS::Packet tmpPack;
          tmpPack.FromPointer(TS::PAT);
          tmpPack.setContinuityCounter(++contPAT);
          sendTS(tmpPack.checkAndGetBuffer());
          sendTS(TS::createPMT(selectedTracks, M, ++contPMT));
          sendTS(TS::createSDT(streamName, ++contSDT));
          packCounter += 3;
        }
        sendTS(packData.checkAndGetBuffer());
        packCounter++;
        packData.clear();
      }

      if (!dataLen){return;}

      if (packData.getBytesFree() == 184){
        packData.clear();
        packData.setPID(pkgPid);
        packData.setContinuityCounter(++contPkg);
        if (firstPack){
          packData.setUnitStart(1);
          if (video){
            if (keyframe){
              packData.setRandomAccess(true);
              packData.setESPriority(true);
            }
            packData.setPCR(thisPacket.getTime() * 27000);
          }
          firstPack = false;
        }
      }

      size_t tmp = packData.fillFree(data, dataLen);
      data += tmp;
      dataLen -= tmp;
    }while (dataLen);
  }

  void TSOutput::sendNext(){
    // Get ready some data to speed up accesses
    std::string type = M.getType(thisIdx);
    std::string codec = M.getCodec(thisIdx);
    bool video = (type == "video");
    size_t pkgPid = TS::getUniqTrackID(M, thisIdx);
    bool &firstPack = first[thisIdx];
    uint16_t &contPkg = contCounters[pkgPid];
    uint64_t packTime = thisPacket.getTime();
    bool keyframe = thisPacket.getInt("keyframe");
    firstPack = true;
    char *dataPointer = 0;
    size_t dataLen = 0;
    thisPacket.getString("data", dataPointer, dataLen); // data

    packTime *= 90;
    std::string bs;
    // prepare bufferstring
    if (video){
      if (codec == "H264" || codec == "HEVC"){
        uint32_t extraSize = 0;
        // dataPointer[4] & 0x1f is used to check if this should be done later:
        // fillPacket("\000\000\000\001\011\360", 6);
        if (codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){extraSize += 6;}
        if (keyframe){
          if (codec == "H264"){
            MP4::AVCC avccbox;
            avccbox.setPayload(M.getInit(thisIdx));
            bs = avccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-START*/
          if (codec == "HEVC"){
            MP4::HVCC hvccbox;
            hvccbox.setPayload(M.getInit(thisIdx));
            bs = hvccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-END*/
        }

        const uint32_t MAX_PES_SIZE = 65490 - 13;
        uint32_t ThisNaluSize = 0;
        uint32_t i = 0;
        uint64_t offset = thisPacket.getInt("offset") * 90;

        bs.clear();
        TS::Packet::getPESVideoLeadIn(bs,
            (((dataLen + extraSize) > MAX_PES_SIZE) ? 0 : dataLen + extraSize),
            packTime, offset, true, M.getBps(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
        if (codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){
          // End of previous nal unit, if not already present
          fillPacket("\000\000\000\001\011\360", 6, firstPack, video, keyframe, pkgPid, contPkg);
        }
        if (keyframe){
          if (codec == "H264"){
            MP4::AVCC avccbox;
            avccbox.setPayload(M.getInit(thisIdx));
            bs = avccbox.asAnnexB();
            fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
          }
          /*LTS-START*/
          if (codec == "HEVC"){
            MP4::HVCC hvccbox;
            hvccbox.setPayload(M.getInit(thisIdx));
            bs = hvccbox.asAnnexB();
            fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
          }
          /*LTS-END*/
        }
        while (i + 4 < (unsigned int)dataLen){
          ThisNaluSize = Bit::btohl(dataPointer + i);
          if (ThisNaluSize + i + 4 > dataLen){
            WARN_MSG("Too big NALU detected (%" PRIu32 " > %zu) - skipping!",
                     ThisNaluSize + i + 4, dataLen);
            break;
          }
          fillPacket("\000\000\000\001", 4, firstPack, video, keyframe, pkgPid, contPkg);
          fillPacket(dataPointer + i + 4, ThisNaluSize, firstPack, video, keyframe, pkgPid, contPkg);
          i += ThisNaluSize + 4;
        }
      }else{
        uint64_t offset = thisPacket.getInt("offset") * 90;
        bs.clear();
        TS::Packet::getPESVideoLeadIn(bs, 0, packTime, offset, true, M.getBps(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);

        fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
      }
    }else if (type == "audio"){
      size_t tempLen = dataLen;
      if (codec == "AAC"){
        tempLen += 7;
        // Make sure TS timestamp is sample-aligned, if possible
        uint32_t freq = M.getRate(thisIdx);
        if (freq){
          uint64_t aacSamples = packTime * freq / 90000;
          //round to nearest packet, assuming all 1024 samples (probably wrong, but meh)
          aacSamples &= ~0x3FF;
          //Get closest 90kHz clock time to perfect sample alignment
          packTime = aacSamples * 90000 / freq;
        }
      }
      if (codec == "opus"){
        tempLen += 3 + (dataLen/255);
        bs = TS::Packet::getPESPS1LeadIn(tempLen, packTime, M.getBps(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
        bs = "\177\340";
        bs.append(dataLen/255, (char)255);
        bs.append(1, (char)(dataLen-255*(dataLen/255)));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      }else{
        bs.clear();
        TS::Packet::getPESAudioLeadIn(bs, tempLen, packTime, M.getBps(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
        if (codec == "AAC"){
          bs = TS::getAudioHeader(dataLen, M.getInit(thisIdx));
          fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
        }
      }
      fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
    }else if (type == "meta"){
      long unsigned int tempLen = dataLen;
      bs = TS::Packet::getPESMetaLeadIn(tempLen, packTime, M.getBps(thisIdx));
      fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
    }
    if (packData.getBytesFree() < 184){
      packData.addStuffing();
      fillPacket(0, 0, firstPack, video, keyframe, pkgPid, contPkg);
    }
  }
}// namespace Mist
<commit_msg>Add a quarter frame offset to MPEG-TS AAC timestamp rounding<commit_after>#include "output_ts_base.h"
#include <mist/bitfields.h>

namespace Mist{
  TSOutput::TSOutput(Socket::Connection &conn) : TS_BASECLASS(conn){
    packCounter = 0;
    ts_from = 0;
    setBlocking(true);
    sendRepeatingHeaders = 0;
    lastHeaderTime = 0;
  }

  void TSOutput::fillPacket(char const *data, size_t dataLen, bool &firstPack, bool video,
                            bool keyframe, size_t pkgPid, uint16_t &contPkg){
    do{
      if (!packData.getBytesFree()){
        if ((sendRepeatingHeaders && thisPacket.getTime() - lastHeaderTime > sendRepeatingHeaders) || !packCounter){

          std::set<size_t> selectedTracks;
          for (std::map<size_t, Comms::Users>::iterator it = userSelect.begin(); it != userSelect.end(); it++){
            selectedTracks.insert(it->first);
          }

          lastHeaderTime = thisPacket.getTime();
          TS::Packet tmpPack;
          tmpPack.FromPointer(TS::PAT);
          tmpPack.setContinuityCounter(++contPAT);
          sendTS(tmpPack.checkAndGetBuffer());
          sendTS(TS::createPMT(selectedTracks, M, ++contPMT));
          sendTS(TS::createSDT(streamName, ++contSDT));
          packCounter += 3;
        }
        sendTS(packData.checkAndGetBuffer());
        packCounter++;
        packData.clear();
      }

      if (!dataLen){return;}

      if (packData.getBytesFree() == 184){
        packData.clear();
        packData.setPID(pkgPid);
        packData.setContinuityCounter(++contPkg);
        if (firstPack){
          packData.setUnitStart(1);
          if (video){
            if (keyframe){
              packData.setRandomAccess(true);
              packData.setESPriority(true);
            }
            packData.setPCR(thisPacket.getTime() * 27000);
          }
          firstPack = false;
        }
      }

      size_t tmp = packData.fillFree(data, dataLen);
      data += tmp;
      dataLen -= tmp;
    }while (dataLen);
  }

  void TSOutput::sendNext(){
    // Get ready some data to speed up accesses
    std::string type = M.getType(thisIdx);
    std::string codec = M.getCodec(thisIdx);
    bool video = (type == "video");
    size_t pkgPid = TS::getUniqTrackID(M, thisIdx);
    bool &firstPack = first[thisIdx];
    uint16_t &contPkg = contCounters[pkgPid];
    uint64_t packTime = thisPacket.getTime();
    bool keyframe = thisPacket.getInt("keyframe");
    firstPack = true;
    char *dataPointer = 0;
    size_t dataLen = 0;
    thisPacket.getString("data", dataPointer, dataLen); // data

    packTime *= 90;
    std::string bs;
    // prepare bufferstring
    if (video){
      if (codec == "H264" || codec == "HEVC"){
        uint32_t extraSize = 0;
        // dataPointer[4] & 0x1f is used to check if this should be done later:
        // fillPacket("\000\000\000\001\011\360", 6);
        if (codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){extraSize += 6;}
        if (keyframe){
          if (codec == "H264"){
            MP4::AVCC avccbox;
            avccbox.setPayload(M.getInit(thisIdx));
            bs = avccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-START*/
          if (codec == "HEVC"){
            MP4::HVCC hvccbox;
            hvccbox.setPayload(M.getInit(thisIdx));
            bs = hvccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-END*/
        }

        const uint32_t MAX_PES_SIZE = 65490 - 13;
        uint32_t ThisNaluSize = 0;
        uint32_t i = 0;
        uint64_t offset = thisPacket.getInt("offset") * 90;

        bs.clear();
        TS::Packet::getPESVideoLeadIn(bs,
            (((dataLen + extraSize) > MAX_PES_SIZE) ? 0 : dataLen + extraSize),
            packTime, offset, true, M.getBps(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
        if (codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){
          // End of previous nal unit, if not already present
          fillPacket("\000\000\000\001\011\360", 6, firstPack, video, keyframe, pkgPid, contPkg);
        }
        if (keyframe){
          if (codec == "H264"){
            MP4::AVCC avccbox;
            avccbox.setPayload(M.getInit(thisIdx));
            bs = avccbox.asAnnexB();
            fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
          }
          /*LTS-START*/
          if (codec == "HEVC"){
            MP4::HVCC hvccbox;
            hvccbox.setPayload(M.getInit(thisIdx));
            bs = hvccbox.asAnnexB();
            fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
          }
          /*LTS-END*/
        }
        while (i + 4 < (unsigned int)dataLen){
          ThisNaluSize = Bit::btohl(dataPointer + i);
          if (ThisNaluSize + i + 4 > dataLen){
            WARN_MSG("Too big NALU detected (%" PRIu32 " > %zu) - skipping!",
                     ThisNaluSize + i + 4, dataLen);
            break;
          }
          fillPacket("\000\000\000\001", 4, firstPack, video, keyframe, pkgPid, contPkg);
          fillPacket(dataPointer + i + 4, ThisNaluSize, firstPack, video, keyframe, pkgPid, contPkg);
          i += ThisNaluSize + 4;
        }
      }else{
        uint64_t offset = thisPacket.getInt("offset") * 90;
        bs.clear();
        TS::Packet::getPESVideoLeadIn(bs, 0, packTime, offset, true, M.getBps(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);

        fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
      }
    }else if (type == "audio"){
      size_t tempLen = dataLen;
      if (codec == "AAC"){
        tempLen += 7;
        // Make sure TS timestamp is sample-aligned, if possible
        uint32_t freq = M.getRate(thisIdx);
        if (freq){
          uint64_t aacSamples = packTime * freq / 90000;
          //round to nearest packet, assuming all 1024 samples (probably wrong, but meh)
          aacSamples += 256;//Add a quarter frame of offset to encourage correct rounding
          aacSamples &= ~0x3FF;
          //Get closest 90kHz clock time to perfect sample alignment
          packTime = aacSamples * 90000 / freq;
        }
      }
      if (codec == "opus"){
        tempLen += 3 + (dataLen/255);
        bs = TS::Packet::getPESPS1LeadIn(tempLen, packTime, M.getBps(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
        bs = "\177\340";
        bs.append(dataLen/255, (char)255);
        bs.append(1, (char)(dataLen-255*(dataLen/255)));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      }else{
        bs.clear();
        TS::Packet::getPESAudioLeadIn(bs, tempLen, packTime, M.getBps(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
        if (codec == "AAC"){
          bs = TS::getAudioHeader(dataLen, M.getInit(thisIdx));
          fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
        }
      }
      fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
    }else if (type == "meta"){
      long unsigned int tempLen = dataLen;
      bs = TS::Packet::getPESMetaLeadIn(tempLen, packTime, M.getBps(thisIdx));
      fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
    }
    if (packData.getBytesFree() < 184){
      packData.addStuffing();
      fillPacket(0, 0, firstPack, video, keyframe, pkgPid, contPkg);
    }
  }
}// namespace Mist
<|endoftext|>


<commit_before>#include "output_ts_base.h"
#include <mist/bitfields.h>

namespace Mist{
  TSOutput::TSOutput(Socket::Connection &conn) : TS_BASECLASS(conn){
    packCounter = 0;
    ts_from = 0;
    setBlocking(true);
    sendRepeatingHeaders = 0;
    lastHeaderTime = 0;
  }

  void TSOutput::fillPacket(char const *data, size_t dataLen, bool &firstPack, bool video,
                            bool keyframe, size_t pkgPid, uint16_t &contPkg){
    do{
      if (!packData.getBytesFree()){
        if ((sendRepeatingHeaders && thisPacket.getTime() - lastHeaderTime > sendRepeatingHeaders) || !packCounter){

          std::set<size_t> selectedTracks;
          for (std::map<size_t, Comms::Users>::iterator it = userSelect.begin(); it != userSelect.end(); it++){
            selectedTracks.insert(it->first);
          }

          lastHeaderTime = thisPacket.getTime();
          TS::Packet tmpPack;
          tmpPack.FromPointer(TS::PAT);
          tmpPack.setContinuityCounter(++contPAT);
          sendTS(tmpPack.checkAndGetBuffer());
          sendTS(TS::createPMT(selectedTracks, M, ++contPMT));
          sendTS(TS::createSDT(streamName, ++contSDT));
          packCounter += 3;
        }
        sendTS(packData.checkAndGetBuffer());
        packCounter++;
        packData.clear();
      }

      if (!dataLen){return;}

      if (packData.getBytesFree() == 184){
        packData.clear();
        packData.setPID(pkgPid);
        packData.setContinuityCounter(++contPkg);
        if (firstPack){
          packData.setUnitStart(1);
          if (video){
            if (keyframe){
              packData.setRandomAccess(true);
              packData.setESPriority(true);
            }
            packData.setPCR(thisPacket.getTime() * 27000);
          }
          firstPack = false;
        }
      }

      size_t tmp = packData.fillFree(data, dataLen);
      data += tmp;
      dataLen -= tmp;
    }while (dataLen);
  }

  void TSOutput::sendNext(){
    // Get ready some data to speed up accesses
    std::string type = M.getType(thisIdx);
    std::string codec = M.getCodec(thisIdx);
    bool video = (type == "video");
    size_t pkgPid = TS::getUniqTrackID(M, thisIdx);
    bool &firstPack = first[thisIdx];
    uint16_t &contPkg = contCounters[pkgPid];
    uint64_t packTime = thisPacket.getTime();
    bool keyframe = thisPacket.getInt("keyframe");
    firstPack = true;
    char *dataPointer = 0;
    size_t dataLen = 0;
    thisPacket.getString("data", dataPointer, dataLen); // data

    packTime *= 90;
    std::string bs;
    // prepare bufferstring
    if (video){
      if (codec == "H264" || codec == "HEVC"){
        unsigned int extraSize = 0;
        // dataPointer[4] & 0x1f is used to check if this should be done later:
        // fillPacket("\000\000\000\001\011\360", 6);
        if (codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){extraSize += 6;}
        if (keyframe){
          if (codec == "H264"){
            MP4::AVCC avccbox;
            avccbox.setPayload(M.getInit(thisIdx));
            bs = avccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-START*/
          if (codec == "HEVC"){
            MP4::HVCC hvccbox;
            hvccbox.setPayload(M.getInit(thisIdx));
            bs = hvccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-END*/
        }

        unsigned int watKunnenWeIn1Ding = 65490 - 13;
        unsigned int splitCount = (dataLen + extraSize) / watKunnenWeIn1Ding;
        unsigned int currPack = 0;
        uint64_t ThisNaluSize = 0;
        unsigned int i = 0;
        unsigned int nalLead = 0;
        uint64_t offset = thisPacket.getInt("offset") * 90;

        while (currPack <= splitCount){
          unsigned int alreadySent = 0;
          bs = TS::Packet::getPESVideoLeadIn(
              (currPack != splitCount ? watKunnenWeIn1Ding : dataLen + extraSize - currPack * watKunnenWeIn1Ding),
              packTime, offset, !currPack, M.getBps(thisIdx));
          fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
          if (!currPack){
            if (codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){
              // End of previous nal unit, if not already present
              fillPacket("\000\000\000\001\011\360", 6, firstPack, video, keyframe, pkgPid, contPkg);
              alreadySent += 6;
            }
            if (keyframe){
              if (codec == "H264"){
                MP4::AVCC avccbox;
                avccbox.setPayload(M.getInit(thisIdx));
                bs = avccbox.asAnnexB();
                fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
                alreadySent += bs.size();
              }
              /*LTS-START*/
              if (codec == "HEVC"){
                MP4::HVCC hvccbox;
                hvccbox.setPayload(M.getInit(thisIdx));
                bs = hvccbox.asAnnexB();
                fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
                alreadySent += bs.size();
              }
              /*LTS-END*/
            }
          }
          while (i + 4 < (unsigned int)dataLen){
            if (nalLead){
              fillPacket(&"\000\000\000\001"[4 - nalLead], nalLead, firstPack, video, keyframe, pkgPid, contPkg);
              i += nalLead;
              alreadySent += nalLead;
              nalLead = 0;
            }
            if (!ThisNaluSize){
              ThisNaluSize = Bit::btohl(dataPointer + i);
              if (ThisNaluSize + i + 4 > dataLen){
                WARN_MSG("Too big NALU detected (%" PRIu64 " > %" PRIu64 ") - skipping!",
                         ThisNaluSize + i + 4, dataLen);
                break;
              }
              if (alreadySent + 4 > watKunnenWeIn1Ding){
                nalLead = 4 - (watKunnenWeIn1Ding - alreadySent);
                fillPacket("\000\000\000\001", watKunnenWeIn1Ding - alreadySent, firstPack, video,
                           keyframe, pkgPid, contPkg);
                i += watKunnenWeIn1Ding - alreadySent;
                alreadySent += watKunnenWeIn1Ding - alreadySent;
              }else{
                fillPacket("\000\000\000\001", 4, firstPack, video, keyframe, pkgPid, contPkg);
                alreadySent += 4;
                i += 4;
              }
            }
            if (alreadySent + ThisNaluSize > watKunnenWeIn1Ding){
              fillPacket(dataPointer + i, watKunnenWeIn1Ding - alreadySent, firstPack, video,
                         keyframe, pkgPid, contPkg);
              i += watKunnenWeIn1Ding - alreadySent;
              ThisNaluSize -= watKunnenWeIn1Ding - alreadySent;
              alreadySent += watKunnenWeIn1Ding - alreadySent;
            }else{
              fillPacket(dataPointer + i, ThisNaluSize, firstPack, video, keyframe, pkgPid, contPkg);
              alreadySent += ThisNaluSize;
              i += ThisNaluSize;
              ThisNaluSize = 0;
            }
            if (alreadySent == watKunnenWeIn1Ding){
              packData.addStuffing();
              fillPacket(0, 0, firstPack, video, keyframe, pkgPid, contPkg);
              firstPack = true;
              break;
            }
          }
          currPack++;
        }
      }else{
        uint64_t offset = thisPacket.getInt("offset") * 90;
        bs = TS::Packet::getPESVideoLeadIn(0, packTime, offset, true, M.getBps(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);

        fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
      }
    }else if (type == "audio"){
      size_t tempLen = dataLen;
      if (codec == "AAC"){
        tempLen += 7;
        // Make sure TS timestamp is sample-aligned, if possible
        uint32_t freq = M.getRate(thisIdx);
        if (freq){
          uint64_t aacSamples = (packTime / 90) * freq / 1000;
          // round to nearest packet, assuming all 1024 samples (probably wrong, but meh)
          aacSamples += 512;
          aacSamples /= 1024;
          aacSamples *= 1024;
          // Get closest 90kHz clock time to perfect sample alignment
          packTime = aacSamples * 90000 / freq;
        }
      }
      bs = TS::Packet::getPESAudioLeadIn(tempLen, packTime, M.getBps(thisIdx));
      fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      if (codec == "AAC"){
        bs = TS::getAudioHeader(dataLen, M.getInit(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      }
      fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
    }else if (type == "meta"){
      long unsigned int tempLen = dataLen;
      bs = TS::Packet::getPESMetaLeadIn(tempLen, packTime, M.getBps(thisIdx));
      fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
    }
    if (packData.getBytesFree() < 184){
      packData.addStuffing();
      fillPacket(0, 0, firstPack, video, keyframe, pkgPid, contPkg);
    }
  }
}// namespace Mist
<commit_msg>Large video PES packets are now sent as unbounded packets instead of split over multiple PES packets<commit_after>#include "output_ts_base.h"
#include <mist/bitfields.h>

namespace Mist{
  TSOutput::TSOutput(Socket::Connection &conn) : TS_BASECLASS(conn){
    packCounter = 0;
    ts_from = 0;
    setBlocking(true);
    sendRepeatingHeaders = 0;
    lastHeaderTime = 0;
  }

  void TSOutput::fillPacket(char const *data, size_t dataLen, bool &firstPack, bool video,
                            bool keyframe, size_t pkgPid, uint16_t &contPkg){
    do{
      if (!packData.getBytesFree()){
        if ((sendRepeatingHeaders && thisPacket.getTime() - lastHeaderTime > sendRepeatingHeaders) || !packCounter){

          std::set<size_t> selectedTracks;
          for (std::map<size_t, Comms::Users>::iterator it = userSelect.begin(); it != userSelect.end(); it++){
            selectedTracks.insert(it->first);
          }

          lastHeaderTime = thisPacket.getTime();
          TS::Packet tmpPack;
          tmpPack.FromPointer(TS::PAT);
          tmpPack.setContinuityCounter(++contPAT);
          sendTS(tmpPack.checkAndGetBuffer());
          sendTS(TS::createPMT(selectedTracks, M, ++contPMT));
          sendTS(TS::createSDT(streamName, ++contSDT));
          packCounter += 3;
        }
        sendTS(packData.checkAndGetBuffer());
        packCounter++;
        packData.clear();
      }

      if (!dataLen){return;}

      if (packData.getBytesFree() == 184){
        packData.clear();
        packData.setPID(pkgPid);
        packData.setContinuityCounter(++contPkg);
        if (firstPack){
          packData.setUnitStart(1);
          if (video){
            if (keyframe){
              packData.setRandomAccess(true);
              packData.setESPriority(true);
            }
            packData.setPCR(thisPacket.getTime() * 27000);
          }
          firstPack = false;
        }
      }

      size_t tmp = packData.fillFree(data, dataLen);
      data += tmp;
      dataLen -= tmp;
    }while (dataLen);
  }

  void TSOutput::sendNext(){
    // Get ready some data to speed up accesses
    std::string type = M.getType(thisIdx);
    std::string codec = M.getCodec(thisIdx);
    bool video = (type == "video");
    size_t pkgPid = TS::getUniqTrackID(M, thisIdx);
    bool &firstPack = first[thisIdx];
    uint16_t &contPkg = contCounters[pkgPid];
    uint64_t packTime = thisPacket.getTime();
    bool keyframe = thisPacket.getInt("keyframe");
    firstPack = true;
    char *dataPointer = 0;
    size_t dataLen = 0;
    thisPacket.getString("data", dataPointer, dataLen); // data

    packTime *= 90;
    std::string bs;
    // prepare bufferstring
    if (video){
      if (codec == "H264" || codec == "HEVC"){
        uint32_t extraSize = 0;
        // dataPointer[4] & 0x1f is used to check if this should be done later:
        // fillPacket("\000\000\000\001\011\360", 6);
        if (codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){extraSize += 6;}
        if (keyframe){
          if (codec == "H264"){
            MP4::AVCC avccbox;
            avccbox.setPayload(M.getInit(thisIdx));
            bs = avccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-START*/
          if (codec == "HEVC"){
            MP4::HVCC hvccbox;
            hvccbox.setPayload(M.getInit(thisIdx));
            bs = hvccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-END*/
        }

        const uint32_t MAX_PES_SIZE = 65490 - 13;
        uint32_t ThisNaluSize = 0;
        uint32_t i = 0;
        uint64_t offset = thisPacket.getInt("offset") * 90;

        bs = TS::Packet::getPESVideoLeadIn(
            (((dataLen + extraSize) > MAX_PES_SIZE) ? 0 : dataLen + extraSize),
            packTime, offset, true, M.getBps(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
        if (codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){
          // End of previous nal unit, if not already present
          fillPacket("\000\000\000\001\011\360", 6, firstPack, video, keyframe, pkgPid, contPkg);
        }
        if (keyframe){
          if (codec == "H264"){
            MP4::AVCC avccbox;
            avccbox.setPayload(M.getInit(thisIdx));
            bs = avccbox.asAnnexB();
            fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
          }
          /*LTS-START*/
          if (codec == "HEVC"){
            MP4::HVCC hvccbox;
            hvccbox.setPayload(M.getInit(thisIdx));
            bs = hvccbox.asAnnexB();
            fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
          }
          /*LTS-END*/
        }
        while (i + 4 < (unsigned int)dataLen){
          ThisNaluSize = Bit::btohl(dataPointer + i);
          if (ThisNaluSize + i + 4 > dataLen){
            WARN_MSG("Too big NALU detected (%" PRIu32 " > %" PRIu64 ") - skipping!",
                     ThisNaluSize + i + 4, dataLen);
            break;
          }
          fillPacket("\000\000\000\001", 4, firstPack, video, keyframe, pkgPid, contPkg);
          fillPacket(dataPointer + i + 4, ThisNaluSize, firstPack, video, keyframe, pkgPid, contPkg);
          i += ThisNaluSize + 4;
        }
      }else{
        uint64_t offset = thisPacket.getInt("offset") * 90;
        bs = TS::Packet::getPESVideoLeadIn(0, packTime, offset, true, M.getBps(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);

        fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
      }
    }else if (type == "audio"){
      size_t tempLen = dataLen;
      if (codec == "AAC"){
        tempLen += 7;
        // Make sure TS timestamp is sample-aligned, if possible
        uint32_t freq = M.getRate(thisIdx);
        if (freq){
          uint64_t aacSamples = (packTime / 90) * freq / 1000;
          // round to nearest packet, assuming all 1024 samples (probably wrong, but meh)
          aacSamples += 512;
          aacSamples /= 1024;
          aacSamples *= 1024;
          // Get closest 90kHz clock time to perfect sample alignment
          packTime = aacSamples * 90000 / freq;
        }
      }
      bs = TS::Packet::getPESAudioLeadIn(tempLen, packTime, M.getBps(thisIdx));
      fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      if (codec == "AAC"){
        bs = TS::getAudioHeader(dataLen, M.getInit(thisIdx));
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      }
      fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
    }else if (type == "meta"){
      long unsigned int tempLen = dataLen;
      bs = TS::Packet::getPESMetaLeadIn(tempLen, packTime, M.getBps(thisIdx));
      fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
    }
    if (packData.getBytesFree() < 184){
      packData.addStuffing();
      fillPacket(0, 0, firstPack, video, keyframe, pkgPid, contPkg);
    }
  }
}// namespace Mist
<|endoftext|>


<commit_before>/**
* @file pendingcontactrequest.cpp
* @brief Class for manipulating pending contact requests
*
* (c) 2013-2014 by Mega Limited, Wellsford, New Zealand
*
* This file is part of the MEGA SDK - Client Access Engine.
*
* Applications using the MEGA API must present a valid application key
* and comply with the the rules set forth in the Terms of Service.
*
* The MEGA SDK 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.
*
* @copyright Simplified (2-clause) BSD License.
*
* You should have received a copy of the license along with this
* program.
*/

#include "mega/pendingcontactrequest.h"
#include "mega/megaclient.h"

namespace mega {

PendingContactRequest::PendingContactRequest(const handle id)
{
    this->id = id;
    this->ts = 0;
    this->uts = 0;
    this->isoutgoing = true;

    memset(&changed, 0, sizeof changed);
}

PendingContactRequest::PendingContactRequest(const handle id,const char *oemail, const char *temail, const m_time_t ts, const m_time_t uts, const char *msg, bool outgoing)
{
    this->id = id;
    this->targetemail = "";
    this->update(oemail, temail, ts, uts, msg, outgoing);
}

void PendingContactRequest::update(const char *oemail, const char *temail, const m_time_t ts, const m_time_t uts, const char *msg, bool outgoing)
{
    if (oemail)
    {
        Node::copystring(&(this->originatoremail), oemail);
    }
    if (temail)
    {
        Node::copystring(&(this->targetemail), temail);
    }
    this->ts = ts;
    this->uts = uts;
    if (msg)
    {
        Node::copystring(&(this->msg), msg);
    }

    this->isoutgoing = outgoing;
    memset(&changed, 0, sizeof changed);
}

bool PendingContactRequest::removed()
{
    return changed.accepted || changed.denied || changed.ignored || changed.deleted;
}

bool PendingContactRequest::serialize(string *d)
{
    unsigned char l;

    d->append((char*)&id, sizeof id);

    l = (unsigned char)originatoremail.size();
    d->append((char*)&l, sizeof l);
    d->append(originatoremail.c_str(), l);

    l = (unsigned char)targetemail.size();
    d->append((char*)&l, sizeof l);
    d->append(targetemail.c_str(), l);

    d->append((char*)&ts, sizeof ts);
    d->append((char*)&uts, sizeof uts);

    l = (unsigned char)msg.size();
    d->append((char*)&l, sizeof l);
    d->append(msg.c_str(), l);

    d->append((char*)&isoutgoing, sizeof isoutgoing);

    return true;
}

PendingContactRequest* PendingContactRequest::unserialize(class MegaClient *client, string *d)
{
    handle id;
    string oemail;
    string temail;
    m_time_t ts;
    m_time_t uts;
    string msg;
    bool isoutgoing;

    const char* ptr = d->data();
    const char* end = ptr + d->size();
    unsigned char l;

    if (ptr + sizeof id + sizeof l > end)
    {
        return NULL;
    }

    id = MemAccess::get<handle>(ptr);
    ptr += sizeof id;

    l = *ptr++;
    if (ptr + l + sizeof l > end)
    {
        return NULL;
    }

    oemail.assign(ptr, l);
    ptr += l;

    l = *ptr++;
    if (ptr + l + sizeof ts + sizeof uts + sizeof l > end)
    {
        return NULL;
    }

    temail.assign(ptr, l);
    ptr += l;

    ts = MemAccess::get<m_time_t>(ptr);
    ptr += sizeof ts;

    uts = MemAccess::get<m_time_t>(ptr);
    ptr += sizeof uts;

    l = *ptr++;
    if (ptr + l > end)
    {
        return NULL;
    }

    msg.assign(ptr, l);
    ptr += l;

    isoutgoing = MemAccess::get<bool>(ptr);
    ptr += sizeof isoutgoing;

    if (ptr == end)
    {
        PendingContactRequest *pcr = new PendingContactRequest(id, oemail.c_str(), temail.c_str(), ts, uts, msg.c_str(), isoutgoing);
        client->mappcr(id, pcr);
        return pcr;
    }
    else
    {
        return NULL;
    }
}

} //namespace
<commit_msg>Fix PCR::unserialize to protect against 0 byte field<commit_after>/**
* @file pendingcontactrequest.cpp
* @brief Class for manipulating pending contact requests
*
* (c) 2013-2014 by Mega Limited, Wellsford, New Zealand
*
* This file is part of the MEGA SDK - Client Access Engine.
*
* Applications using the MEGA API must present a valid application key
* and comply with the the rules set forth in the Terms of Service.
*
* The MEGA SDK 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.
*
* @copyright Simplified (2-clause) BSD License.
*
* You should have received a copy of the license along with this
* program.
*/

#include "mega/pendingcontactrequest.h"
#include "mega/megaclient.h"

namespace mega {

PendingContactRequest::PendingContactRequest(const handle id)
{
    this->id = id;
    this->ts = 0;
    this->uts = 0;
    this->isoutgoing = true;

    memset(&changed, 0, sizeof changed);
}

PendingContactRequest::PendingContactRequest(const handle id,const char *oemail, const char *temail, const m_time_t ts, const m_time_t uts, const char *msg, bool outgoing)
{
    this->id = id;
    this->targetemail = "";
    this->update(oemail, temail, ts, uts, msg, outgoing);
}

void PendingContactRequest::update(const char *oemail, const char *temail, const m_time_t ts, const m_time_t uts, const char *msg, bool outgoing)
{
    if (oemail)
    {
        Node::copystring(&(this->originatoremail), oemail);
    }
    if (temail)
    {
        Node::copystring(&(this->targetemail), temail);
    }
    this->ts = ts;
    this->uts = uts;
    if (msg)
    {
        Node::copystring(&(this->msg), msg);
    }

    this->isoutgoing = outgoing;
    memset(&changed, 0, sizeof changed);
}

bool PendingContactRequest::removed()
{
    return changed.accepted || changed.denied || changed.ignored || changed.deleted;
}

bool PendingContactRequest::serialize(string *d)
{
    unsigned char l;

    d->append((char*)&id, sizeof id);

    l = (unsigned char)originatoremail.size();
    d->append((char*)&l, sizeof l);
    d->append(originatoremail.c_str(), l);

    l = (unsigned char)targetemail.size();
    d->append((char*)&l, sizeof l);
    d->append(targetemail.c_str(), l);

    d->append((char*)&ts, sizeof ts);
    d->append((char*)&uts, sizeof uts);

    l = (unsigned char)msg.size();
    d->append((char*)&l, sizeof l);
    d->append(msg.c_str(), l);

    d->append((char*)&isoutgoing, sizeof isoutgoing);

    return true;
}

PendingContactRequest* PendingContactRequest::unserialize(class MegaClient *client, string *d)
{
    handle id;
    string oemail;
    string temail;
    m_time_t ts;
    m_time_t uts;
    string msg;
    bool isoutgoing;

    const char* ptr = d->data();
    const char* end = ptr + d->size();
    unsigned char l;

    if (ptr + sizeof id + sizeof l > end)
    {
        return NULL;
    }

    id = MemAccess::get<handle>(ptr);
    ptr += sizeof id;

    l = *ptr++;
    if (ptr + l + sizeof l > end)
    {
        return NULL;
    }

    oemail.assign(ptr, l);
    ptr += l;

    l = *ptr++;
    if (ptr + l + sizeof ts + sizeof uts + sizeof l > end)
    {
        return NULL;
    }

    temail.assign(ptr, l);
    ptr += l;

    ts = MemAccess::get<m_time_t>(ptr);
    ptr += sizeof ts;

    uts = MemAccess::get<m_time_t>(ptr);
    ptr += sizeof uts;

    l = *ptr++;
    if (ptr + l > end)
    // should be ptr+l+sizeof(isoutgoing), but legacy code writes 0 bytes when false
    {
        return NULL;
    }

    msg.assign(ptr, l);
    ptr += l;

    if (ptr == end) // legacy bug writes 0 bytes for incoming PCRs
    {
        isoutgoing = false;
    }
    else if (ptr + sizeof isoutgoing == end)
    {
        isoutgoing = MemAccess::get<bool>(ptr);
        ptr += sizeof isoutgoing;
    }

    if (ptr == end)
    {
        PendingContactRequest *pcr = new PendingContactRequest(id, oemail.c_str(), temail.c_str(), ts, uts, msg.c_str(), isoutgoing);
        client->mappcr(id, pcr);
        return pcr;
    }
    else
    {
        return NULL;
    }
}

} //namespace
<|endoftext|>


<commit_before><commit_msg>distance joint spring enabled by default<commit_after><|endoftext|>


<commit_before>#include <os>

#include <info>
#include <smp>
#include <statman>
#include <kernel/timers.hpp>
#include <kernel/solo5_manager.hpp>

extern "C" {
#include <solo5.h>
}

// sleep statistics
static uint64_t os_cycles_hlt = 0;

extern "C" void* get_cpu_esp();
extern uintptr_t _start;
extern uintptr_t _end;
extern uintptr_t mem_size;
extern uintptr_t _ELF_START_;
extern uintptr_t _TEXT_START_;
extern uintptr_t _LOAD_START_;
extern uintptr_t _ELF_END_;
// in kernel/os.cpp
extern bool os_default_stdout;

typedef void (*ctor_t) ();
extern ctor_t __init_array_start;
extern ctor_t __init_array_end;
extern int __run_ctors(ctor_t* begin, ctor_t* end);

#define MYINFO(X,...) INFO("Kernel", X, ##__VA_ARGS__)

#ifdef ENABLE_PROFILERS
#include <profile>
#define PROFILE(name)  ScopedProfiler __CONCAT(sp, __COUNTER__){name};
#else
#define PROFILE(name) /* name */
#endif

void solo5_poweroff()
{
  __asm__ __volatile__("cli; hlt");
  for(;;);
}

// returns wall clock time in nanoseconds since the UNIX epoch
uint64_t __arch_system_time() noexcept
{
  return solo5_clock_wall();
}
timespec __arch_wall_clock() noexcept
{
  uint64_t stamp = solo5_clock_wall();
  timespec result;
  result.tv_sec = stamp / 1000000000ul;
  result.tv_nsec = stamp % 1000000000ul;
  return result;
}

// actually uses nanoseconds (but its just a number)
uint64_t OS::cycles_asleep() noexcept {
  return os_cycles_hlt;
}
uint64_t OS::nanos_asleep() noexcept {
  return os_cycles_hlt;
}

void OS::default_stdout(const char* str, const size_t len)
{
  solo5_console_write(str, len);
}

void OS::start(const char* cmdline)
{
  OS::cmdline = cmdline;

  // Initialize stdout handlers
  if(os_default_stdout) {
    OS::add_stdout(&OS::default_stdout);
  }

  PROFILE("");
  // Print a fancy header
  CAPTION("#include<os> // Literally");

  void* esp = get_cpu_esp();
  MYINFO("Stack: %p", esp);

  /// STATMAN ///
  /// initialize on page 7, 2 pages in size
  Statman::get().init(0x6000, 0x3000);

  // Call global ctors
  PROFILE("Global kernel constructors");
  __run_ctors(&__init_array_start, &__init_array_end);

  PROFILE("Memory map");
  // Assign memory ranges used by the kernel
  auto& memmap = memory_map();
  MYINFO("Assigning fixed memory ranges (Memory map)");

  memmap.assign_range({0x500, 0x5fff, "solo5"});
  memmap.assign_range({0x6000, 0x8fff, "Statman"});
  memmap.assign_range({0xA000, 0x9fbff, "Stack"});
  memmap.assign_range({(uintptr_t)&_LOAD_START_, (uintptr_t)&_end,
        "ELF"});

  Expects(heap_begin() and heap_max_);
  // @note for security we don't want to expose this
  memmap.assign_range({(uintptr_t)&_end + 1, heap_begin() - 1,
        "Pre-heap"});

  uintptr_t span_max = std::numeric_limits<std::ptrdiff_t>::max();
  uintptr_t heap_range_max_ = std::min(span_max, heap_max_);

  MYINFO("Assigning heap");
  memmap.assign_range({heap_begin(), heap_range_max_,
        "Dynamic memory", heap_usage });

  MYINFO("Printing memory map");
  for (const auto &i : memmap)
    INFO2("* %s",i.second.to_string().c_str());

  extern void __platform_init();
  __platform_init();

  MYINFO("Booted at monotonic_ns=%ld walltime_ns=%ld",
         solo5_clock_monotonic(), solo5_clock_wall());

  Solo5_manager::init();

  // We don't need a start or stop function in solo5.
  Timers::init(
    // timer start function
    [] (auto) {},
    // timer stop function
    [] () {});

  Timers::ready();
}

static inline void event_loop_inner()
{
  int res = 0;
  auto nxt = Timers::next();
  if (nxt == std::chrono::nanoseconds(0))
  {
    // no next timer, just wait a while
    res = solo5_yield(solo5_clock_monotonic() + 500000000ULL); // 500 ms
    //printf("Waiting, next is indeterminate...\n");
  }
  else if (nxt == std::chrono::nanoseconds(1))
  {
    // there is an imminent or activated timer, don't wait
    //printf("Not waiting, imminent timer...\n");
  }
  else
  {
    res = solo5_yield(solo5_clock_monotonic() + nxt.count());
    //printf("Waiting %llu nanos\n", nxt.count());
  }

  // handle any activated timers
  Timers::timers_handler();
  if (res != 0)
  {
    // handle any network traffic
    for(auto& nic : hw::Devices::devices<hw::Nic>()) {
      nic->poll();
    }
  }
}

void OS::event_loop()
{
  while (power_)
  {
    // add a global symbol here so we can quickly discard
    // event loop from stack sampling
    asm volatile(
    ".global _irq_cb_return_location;\n"
    "_irq_cb_return_location:" );

    event_loop_inner();
  }

  MYINFO("Stopping service");
  Service::stop();

  MYINFO("Powering off");
  solo5_poweroff();
}

__attribute__((noinline))
void OS::halt() {
  auto cycles_before = solo5_clock_monotonic();
#if defined(ARCH_x86)
  asm volatile("hlt");
#else
#warning "OS::halt() not implemented for selected arch"
#endif
  // Count sleep nanos
  os_cycles_hlt += solo5_clock_monotonic() - cycles_before;
}

void OS::block()
{
  static uint32_t blocking_level = 0;
  blocking_level += 1;
  // prevent recursion stack overflow
  assert(blocking_level < 200);

  event_loop_inner();

  // Decrement level
  blocking_level -= 1;
}
<commit_msg>solo5: Wait longer, process events<commit_after>#include <os>

#include <info>
#include <smp>
#include <statman>
#include <kernel/events.hpp>
#include <kernel/timers.hpp>
#include <kernel/solo5_manager.hpp>

extern "C" {
#include <solo5.h>
}

// sleep statistics
static uint64_t os_cycles_hlt = 0;

extern "C" void* get_cpu_esp();
extern uintptr_t _start;
extern uintptr_t _end;
extern uintptr_t mem_size;
extern uintptr_t _ELF_START_;
extern uintptr_t _TEXT_START_;
extern uintptr_t _LOAD_START_;
extern uintptr_t _ELF_END_;
// in kernel/os.cpp
extern bool os_default_stdout;

typedef void (*ctor_t) ();
extern ctor_t __init_array_start;
extern ctor_t __init_array_end;
extern int __run_ctors(ctor_t* begin, ctor_t* end);

#define MYINFO(X,...) INFO("Kernel", X, ##__VA_ARGS__)

#ifdef ENABLE_PROFILERS
#include <profile>
#define PROFILE(name)  ScopedProfiler __CONCAT(sp, __COUNTER__){name};
#else
#define PROFILE(name) /* name */
#endif

void solo5_poweroff()
{
  __asm__ __volatile__("cli; hlt");
  for(;;);
}

// returns wall clock time in nanoseconds since the UNIX epoch
uint64_t __arch_system_time() noexcept
{
  return solo5_clock_wall();
}
timespec __arch_wall_clock() noexcept
{
  uint64_t stamp = solo5_clock_wall();
  timespec result;
  result.tv_sec = stamp / 1000000000ul;
  result.tv_nsec = stamp % 1000000000ul;
  return result;
}

// actually uses nanoseconds (but its just a number)
uint64_t OS::cycles_asleep() noexcept {
  return os_cycles_hlt;
}
uint64_t OS::nanos_asleep() noexcept {
  return os_cycles_hlt;
}

void OS::default_stdout(const char* str, const size_t len)
{
  solo5_console_write(str, len);
}

void OS::start(const char* cmdline)
{
  OS::cmdline = cmdline;

  // Initialize stdout handlers
  if(os_default_stdout) {
    OS::add_stdout(&OS::default_stdout);
  }

  PROFILE("");
  // Print a fancy header
  CAPTION("#include<os> // Literally");

  void* esp = get_cpu_esp();
  MYINFO("Stack: %p", esp);

  /// STATMAN ///
  /// initialize on page 7, 2 pages in size
  Statman::get().init(0x6000, 0x3000);

  // Call global ctors
  PROFILE("Global kernel constructors");
  __run_ctors(&__init_array_start, &__init_array_end);

  PROFILE("Memory map");
  // Assign memory ranges used by the kernel
  auto& memmap = memory_map();
  MYINFO("Assigning fixed memory ranges (Memory map)");

  memmap.assign_range({0x500, 0x5fff, "solo5"});
  memmap.assign_range({0x6000, 0x8fff, "Statman"});
  memmap.assign_range({0xA000, 0x9fbff, "Stack"});
  memmap.assign_range({(uintptr_t)&_LOAD_START_, (uintptr_t)&_end,
        "ELF"});

  Expects(heap_begin() and heap_max_);
  // @note for security we don't want to expose this
  memmap.assign_range({(uintptr_t)&_end + 1, heap_begin() - 1,
        "Pre-heap"});

  uintptr_t span_max = std::numeric_limits<std::ptrdiff_t>::max();
  uintptr_t heap_range_max_ = std::min(span_max, heap_max_);

  MYINFO("Assigning heap");
  memmap.assign_range({heap_begin(), heap_range_max_,
        "Dynamic memory", heap_usage });

  MYINFO("Printing memory map");
  for (const auto &i : memmap)
    INFO2("* %s",i.second.to_string().c_str());

  extern void __platform_init();
  __platform_init();

  MYINFO("Booted at monotonic_ns=%ld walltime_ns=%ld",
         solo5_clock_monotonic(), solo5_clock_wall());

  Solo5_manager::init();

  // We don't need a start or stop function in solo5.
  Timers::init(
    // timer start function
    [] (auto) {},
    // timer stop function
    [] () {});

  Events::get().defer(Timers::ready);
}

static inline void event_loop_inner()
{
  int res = 0;
  auto nxt = Timers::next();
  if (nxt == std::chrono::nanoseconds(0))
  {
    // no next timer, wait forever
    //printf("Waiting 15s, next is indeterminate...\n");
    const unsigned long long count = 15000000000ULL;
    res = solo5_yield(solo5_clock_monotonic() + count);
    os_cycles_hlt += count;
  }
  else if (nxt == std::chrono::nanoseconds(1))
  {
    // there is an imminent or activated timer, don't wait
    //printf("Not waiting, imminent timer...\n");
  }
  else
  {
    //printf("Waiting %llu nanos\n", nxt.count());
    res = solo5_yield(solo5_clock_monotonic() + nxt.count());
    os_cycles_hlt += nxt.count();
  }

  // handle any activated timers
  Timers::timers_handler();
  Events::get().process_events();
  if (res != 0)
  {
    // handle any network traffic
    for(auto& nic : hw::Devices::devices<hw::Nic>()) {
      nic->poll();
    }
  }
}

void OS::event_loop()
{
  while (power_)
  {
    // add a global symbol here so we can quickly discard
    // event loop from stack sampling
    asm volatile(
    ".global _irq_cb_return_location;\n"
    "_irq_cb_return_location:" );

    event_loop_inner();
  }

  MYINFO("Stopping service");
  Service::stop();

  MYINFO("Powering off");
  solo5_poweroff();
}

__attribute__((noinline))
void OS::halt() {
  auto cycles_before = solo5_clock_monotonic();
#if defined(ARCH_x86)
  asm volatile("hlt");
#else
#warning "OS::halt() not implemented for selected arch"
#endif
  // Count sleep nanos
  os_cycles_hlt += solo5_clock_monotonic() - cycles_before;
}

void OS::block()
{
  static uint32_t blocking_level = 0;
  blocking_level += 1;
  // prevent recursion stack overflow
  assert(blocking_level < 200);

  event_loop_inner();

  // Decrement level
  blocking_level -= 1;
}
<|endoftext|>


<commit_before>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2014 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

// QtMWidgets include.
#include "cursorshifter.hpp"
#include "color.hpp"
#include "fingergeometry.hpp"

// Qt include.
#include <QTimer>
#include <QPainter>
#include <QMouseEvent>
#include <QPainterPath>
#include <QApplication>
#include <QEvent>
#include <QBitmap>

namespace QtMWidgets {

//
// CursorShifterPrivate
//

class CursorShifterPrivate {
public:
	CursorShifterPrivate( CursorShifter * parent )
		:	q( parent )
		,	leftMouseButtonPressed( false )
		,	cursorOverrided( false )
	{
	}

	void init();

	CursorShifter * q;
	QColor color;
	QColor light;
	int basicSize;
	QPoint cursorPos;
	QTimer * timer;
	bool leftMouseButtonPressed;
	QPoint offset;
	bool cursorOverrided;
}; // class CursorShifterPrivate

void
CursorShifterPrivate::init()
{
	color = q->palette().color( QPalette::Highlight );
	light = lighterColor( color, 75 );
	basicSize = qRound( (qreal) FingerGeometry::width() * 0.2 );
	timer = new QTimer( q );
	q->setAttribute( Qt::WA_TranslucentBackground );
	q->setAttribute( Qt::WA_NoSystemBackground );
	q->setWindowModality( Qt::NonModal );

	QObject::connect( timer, SIGNAL( timeout() ),
		q, SLOT( _q_hideTimer() ) );
}

//
// CursorShifter
//

CursorShifter::CursorShifter( QWidget * parent )
	:	QWidget( parent, Qt::ToolTip | Qt::FramelessWindowHint |
			Qt::WindowDoesNotAcceptFocus |
			Qt::WindowTransparentForInput |
			Qt::NoDropShadowWindowHint |
			Qt::WindowStaysOnTopHint )
	,	d( new CursorShifterPrivate( this ) )
{
	d->init();
}

CursorShifter::~CursorShifter()
{
}

QPoint
CursorShifter::cursorPos() const
{
	return d->cursorPos;
}

QSize
CursorShifter::minimumSizeHint() const
{
	return QSize( d->basicSize * 2, d->basicSize * 3 );
}

QSize
CursorShifter::sizeHint() const
{
	return minimumSizeHint();
}

void
CursorShifter::setCursorPos( const QPoint & pos )
{
	if( d->cursorPos != pos )
	{
		d->cursorPos = pos;

		move( QPoint( d->cursorPos.x() - d->basicSize, d->cursorPos.y() ) );
	}
}

void
CursorShifter::popup()
{
	qApp->installEventFilter( this );
	show();
	d->timer->start( 3000 );
}

void
CursorShifter::immediatelyHide()
{
	d->timer->stop();

	qApp->removeEventFilter( this );

	hide();

	if( d->cursorOverrided )
	{
		d->cursorOverrided = false;
		QApplication::restoreOverrideCursor();
	}
}

void
CursorShifter::paintEvent( QPaintEvent * )
{
	QPainter p( this );
	p.setRenderHint( QPainter::Antialiasing );

	QPainterPath roof;
	roof.moveTo( d->basicSize, 0 );
	roof.lineTo( d->basicSize * 2, d->basicSize );
	roof.lineTo( 0, d->basicSize );
	roof.lineTo( d->basicSize, 0 );

	p.setPen( d->color );
	p.setBrush( d->light );
	p.drawPath( roof );

	p.setBrush( d->color );
	p.drawRect( 0, d->basicSize, d->basicSize * 2, d->basicSize * 2 );
}

bool
CursorShifter::eventFilter( QObject * obj, QEvent * e )
{
	Q_UNUSED( obj )

	switch( e->type() )
	{
		case QEvent::MouseButtonPress :
		{
			QMouseEvent * me = static_cast< QMouseEvent* > ( e );
			QRect r = rect();
			r.moveTo( pos() );
			const QPoint pos = me->globalPos();

			if( isVisible() && r.contains( pos ) )
			{
				d->leftMouseButtonPressed = true;
				d->timer->stop();
				d->offset = QPoint( r.topLeft().x() + d->basicSize - pos.x(),
					pos.y() - r.topLeft().y() );

				return true;
			}

			return false;
		}
		break;

		case QEvent::MouseButtonRelease :
		{
			if( d->leftMouseButtonPressed )
			{
				d->leftMouseButtonPressed = false;
				d->timer->start( 3000 );

				return true;
			}

			return false;
		}
		break;

		case QEvent::MouseMove :
		{
			QMouseEvent * me = static_cast< QMouseEvent* > ( e );

			QRect r = rect();
			r.moveTo( pos() );
			const QPoint pos = me->globalPos();

			if( isVisible() && r.contains( pos ) && !d->cursorOverrided )
			{
				d->cursorOverrided = true;
				QApplication::setOverrideCursor( QCursor( Qt::ArrowCursor ) );
			}
			else if( d->cursorOverrided && ( !r.contains( pos ) | !isVisible() ) )
			{
				d->cursorOverrided = false;
				QApplication::restoreOverrideCursor();
			}

			if( d->leftMouseButtonPressed )
			{
				emit posChanged( me->globalPos() - d->offset );

				return true;
			}

			return false;
		}
		break;

		default :
			return false;
	}
}

void
CursorShifter::_q_hideTimer()
{
	qApp->removeEventFilter( this );

	hide();

	if( d->cursorOverrided )
	{
		d->cursorOverrided = false;
		QApplication::restoreOverrideCursor();
	}
}

} /* namespace QtMWidgets */
<commit_msg>Modifier CursorShifter.<commit_after>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2014 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

// QtMWidgets include.
#include "cursorshifter.hpp"
#include "color.hpp"
#include "fingergeometry.hpp"

// Qt include.
#include <QTimer>
#include <QPainter>
#include <QMouseEvent>
#include <QPainterPath>
#include <QApplication>
#include <QEvent>
#include <QBitmap>

namespace QtMWidgets {

//
// CursorShifterPrivate
//

class CursorShifterPrivate {
public:
	CursorShifterPrivate( CursorShifter * parent )
		:	q( parent )
		,	leftMouseButtonPressed( false )
		,	cursorOverrided( false )
	{
	}

	void init();

	CursorShifter * q;
	QColor color;
	QColor light;
	int basicSize;
	QPoint cursorPos;
	QTimer * timer;
	bool leftMouseButtonPressed;
	QPoint offset;
	bool cursorOverrided;
}; // class CursorShifterPrivate

void
CursorShifterPrivate::init()
{
	color = q->palette().color( QPalette::Highlight );
	light = lighterColor( color, 75 );
	basicSize = qRound( (qreal) FingerGeometry::width() * 0.2 );
	timer = new QTimer( q );
	q->setWindowModality( Qt::NonModal );

	QObject::connect( timer, SIGNAL( timeout() ),
		q, SLOT( _q_hideTimer() ) );
}

//
// CursorShifter
//

CursorShifter::CursorShifter( QWidget * parent )
	:	QWidget( parent, Qt::ToolTip | Qt::FramelessWindowHint |
			Qt::WindowDoesNotAcceptFocus |
			Qt::WindowTransparentForInput |
			Qt::NoDropShadowWindowHint |
			Qt::WindowStaysOnTopHint )
	,	d( new CursorShifterPrivate( this ) )
{
	d->init();
}

CursorShifter::~CursorShifter()
{
}

QPoint
CursorShifter::cursorPos() const
{
	return d->cursorPos;
}

QSize
CursorShifter::minimumSizeHint() const
{
	return QSize( d->basicSize * 2, d->basicSize * 3 );
}

QSize
CursorShifter::sizeHint() const
{
	return minimumSizeHint();
}

void
CursorShifter::setCursorPos( const QPoint & pos )
{
	if( d->cursorPos != pos )
	{
		d->cursorPos = pos;

		move( QPoint( d->cursorPos.x() - d->basicSize, d->cursorPos.y() ) );
	}
}

void
CursorShifter::popup()
{
	qApp->installEventFilter( this );
	show();
	d->timer->start( 3000 );
}

void
CursorShifter::immediatelyHide()
{
	d->timer->stop();

	qApp->removeEventFilter( this );

	hide();

	if( d->cursorOverrided )
	{
		d->cursorOverrided = false;
		QApplication::restoreOverrideCursor();
	}
}

void
CursorShifter::paintEvent( QPaintEvent * )
{
	QPainter p( this );
	p.setRenderHint( QPainter::Antialiasing );

	QPainterPath roof;
	roof.moveTo( d->basicSize, 0 );
	roof.lineTo( d->basicSize * 2, d->basicSize );
	roof.lineTo( 0, d->basicSize );
	roof.lineTo( d->basicSize, 0 );

	p.setPen( d->color );
	p.setBrush( d->light );
	p.drawPath( roof );

	p.setBrush( d->color );
	p.drawRect( 0, d->basicSize, d->basicSize * 2, d->basicSize * 2 );
}

bool
CursorShifter::eventFilter( QObject * obj, QEvent * e )
{
	Q_UNUSED( obj )

	switch( e->type() )
	{
		case QEvent::MouseButtonPress :
		{
			QMouseEvent * me = static_cast< QMouseEvent* > ( e );
			QRect r = rect();
			r.moveTo( pos() );
			const QPoint pos = me->globalPos();

			if( isVisible() && r.contains( pos ) )
			{
				d->leftMouseButtonPressed = true;
				d->timer->stop();
				d->offset = QPoint( r.topLeft().x() + d->basicSize - pos.x(),
					pos.y() - r.topLeft().y() );

				return true;
			}

			return false;
		}
		break;

		case QEvent::MouseButtonRelease :
		{
			if( d->leftMouseButtonPressed )
			{
				d->leftMouseButtonPressed = false;
				d->timer->start( 3000 );

				return true;
			}

			return false;
		}
		break;

		case QEvent::MouseMove :
		{
			QMouseEvent * me = static_cast< QMouseEvent* > ( e );

			QRect r = rect();
			r.moveTo( pos() );
			const QPoint pos = me->globalPos();

			if( isVisible() && r.contains( pos ) && !d->cursorOverrided )
			{
				d->cursorOverrided = true;
				QApplication::setOverrideCursor( QCursor( Qt::ArrowCursor ) );
			}
			else if( d->cursorOverrided && ( !r.contains( pos ) | !isVisible() ) )
			{
				d->cursorOverrided = false;
				QApplication::restoreOverrideCursor();
			}

			if( d->leftMouseButtonPressed )
			{
				emit posChanged( me->globalPos() - d->offset );

				return true;
			}

			return false;
		}
		break;

		default :
			return false;
	}
}

void
CursorShifter::_q_hideTimer()
{
	qApp->removeEventFilter( this );

	hide();

	if( d->cursorOverrided )
	{
		d->cursorOverrided = false;
		QApplication::restoreOverrideCursor();
	}
}

} /* namespace QtMWidgets */
<|endoftext|>


<commit_before>// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <wallet/wallet.h>

#include <qt/receivecoinsdialog.h>
#include <qt/forms/ui_receivecoinsdialog.h>

#include <qt/addressbookpage.h>
#include <qt/addresstablemodel.h>
#include <qt/bitcoinunits.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/receiverequestdialog.h>
#include <qt/recentrequeststablemodel.h>
#include <qt/walletmodel.h>

#include <QAction>
#include <QCursor>
#include <QMessageBox>
#include <QScrollBar>
#include <QTextDocument>

ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ReceiveCoinsDialog),
    columnResizingFixer(0),
    model(0),
    platformStyle(_platformStyle)
{
    ui->setupUi(this);
    QString theme = GUIUtil::getThemeName();

    if (!_platformStyle->getImagesOnButtons()) {
        ui->clearButton->setIcon(QIcon());
        ui->receiveButton->setIcon(QIcon());
        ui->showRequestButton->setIcon(QIcon());
        ui->removeRequestButton->setIcon(QIcon());
    } else {
        ui->clearButton->setIcon(QIcon(":/icons/" + theme + "/remove"));
        ui->receiveButton->setIcon(QIcon(":/icons/" + theme + "/receiving_addresses"));
        ui->showRequestButton->setIcon(QIcon(":/icons/" + theme + "/edit"));
        ui->removeRequestButton->setIcon(QIcon(":/icons/" + theme + "/remove"));
    }

    // context menu actions
    QAction *copyURIAction = new QAction(tr("Copy URI"), this);
    QAction *copyLabelAction = new QAction(tr("Copy label"), this);
    QAction *copyMessageAction = new QAction(tr("Copy message"), this);
    QAction *copyAmountAction = new QAction(tr("Copy amount"), this);

    // context menu
    contextMenu = new QMenu(this);
    contextMenu->addAction(copyURIAction);
    contextMenu->addAction(copyLabelAction);
    contextMenu->addAction(copyMessageAction);
    contextMenu->addAction(copyAmountAction);

    // context menu signals
    connect(ui->recentRequestsView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));
    connect(copyURIAction, SIGNAL(triggered()), this, SLOT(copyURI()));
    connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
    connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage()));
    connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));

    connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
}

void ReceiveCoinsDialog::setModel(WalletModel *_model)
{
    this->model = _model;

    if(_model && _model->getOptionsModel())
    {
        _model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
        connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
        updateDisplayUnit();

        QTableView* tableView = ui->recentRequestsView;

        tableView->verticalHeader()->hide();
        tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        tableView->setModel(_model->getRecentRequestsTableModel());
        tableView->setAlternatingRowColors(true);
        tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
        tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
        tableView->setColumnWidth(RecentRequestsTableModel::Date, DATE_COLUMN_WIDTH);
        tableView->setColumnWidth(RecentRequestsTableModel::Label, LABEL_COLUMN_WIDTH);

        connect(tableView->selectionModel(),
            SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this,
            SLOT(recentRequestsView_selectionChanged(QItemSelection, QItemSelection)));
        // Last 2 columns are set by the columnResizingFixer, when the table geometry is ready.
        columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);

        // configure bech32 checkbox, disable if launched with legacy as default:
        if (model->wallet().getDefaultAddressType() == OutputType::BECH32) {
            ui->useBech32->setCheckState(Qt::Checked);
        } else {
            ui->useBech32->setCheckState(Qt::Unchecked);
        }

        ui->useBech32->setVisible(model->wallet().getDefaultAddressType() != OutputType::LEGACY);
    }
}

ReceiveCoinsDialog::~ReceiveCoinsDialog()
{
    delete ui;
}

void ReceiveCoinsDialog::clear()
{
    ui->reqAmount->clear();
    ui->reqLabel->setText("");
    ui->reqMessage->setText("");
    updateDisplayUnit();
}

void ReceiveCoinsDialog::reject()
{
    clear();
}

void ReceiveCoinsDialog::accept()
{
    clear();
}

void ReceiveCoinsDialog::updateDisplayUnit()
{
    if(model && model->getOptionsModel())
    {
        ui->reqAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
    }
}

void ReceiveCoinsDialog::on_receiveButton_clicked()
{
    if(!model || !model->getOptionsModel() || !model->getAddressTableModel() || !model->getRecentRequestsTableModel())
        return;

    QString address;
    QString label = ui->reqLabel->text();
    /* Generate new receiving address */
    OutputType address_type = model->wallet().getDefaultAddressType();
    if (address_type != OutputType::LEGACY) {
        address_type = ui->useBech32->isChecked() ? OutputType::BECH32 : OutputType::P2SH_SEGWIT;
    }
    address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", address_type);
    SendCoinsRecipient info(address, label,
        ui->reqAmount->value(), ui->reqMessage->text());
    ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->setModel(model);
    dialog->setInfo(info);
    dialog->show();
    clear();

    /* Store request for later reference */
    model->getRecentRequestsTableModel()->addNewRequest(info);
}

void ReceiveCoinsDialog::on_recentRequestsView_doubleClicked(const QModelIndex &index)
{
    const RecentRequestsTableModel *submodel = model->getRecentRequestsTableModel();
    ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
    dialog->setModel(model);
    dialog->setInfo(submodel->entry(index.row()).recipient);
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->show();
}

void ReceiveCoinsDialog::recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
    // Enable Show/Remove buttons only if anything is selected.
    bool enable = !ui->recentRequestsView->selectionModel()->selectedRows().isEmpty();
    ui->showRequestButton->setEnabled(enable);
    ui->removeRequestButton->setEnabled(enable);
}

void ReceiveCoinsDialog::on_showRequestButton_clicked()
{
    if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
        return;
    QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();

    for (const QModelIndex& index : selection) {
        on_recentRequestsView_doubleClicked(index);
    }
}

void ReceiveCoinsDialog::on_removeRequestButton_clicked()
{
    if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
        return;
    QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
    if(selection.empty())
        return;
    // correct for selection mode ContiguousSelection
    QModelIndex firstIndex = selection.at(0);
    model->getRecentRequestsTableModel()->removeRows(firstIndex.row(), selection.length(), firstIndex.parent());
}

// We override the virtual resizeEvent of the QWidget to adjust tables column
// sizes as the tables width is proportional to the dialogs width.
void ReceiveCoinsDialog::resizeEvent(QResizeEvent *event)
{
    QWidget::resizeEvent(event);
    columnResizingFixer->stretchColumnWidth(RecentRequestsTableModel::Message);
}

void ReceiveCoinsDialog::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Return)
    {
        // press return -> submit form
        if (ui->reqLabel->hasFocus() || ui->reqAmount->hasFocus() || ui->reqMessage->hasFocus())
        {
            event->ignore();
            on_receiveButton_clicked();
            return;
        }
    }

    this->QDialog::keyPressEvent(event);
}

QModelIndex ReceiveCoinsDialog::selectedRow()
{
    if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
        return QModelIndex();
    QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
    if(selection.empty())
        return QModelIndex();
    // correct for selection mode ContiguousSelection
    QModelIndex firstIndex = selection.at(0);
    return firstIndex;
}

// copy column of selected row to clipboard
void ReceiveCoinsDialog::copyColumnToClipboard(int column)
{
    QModelIndex firstIndex = selectedRow();
    if (!firstIndex.isValid()) {
        return;
    }
    GUIUtil::setClipboard(model->getRecentRequestsTableModel()->data(firstIndex.child(firstIndex.row(), column), Qt::EditRole).toString());
}

// context menu
void ReceiveCoinsDialog::showMenu(const QPoint &point)
{
    if (!selectedRow().isValid()) {
        return;
    }
    contextMenu->exec(QCursor::pos());
}

// context menu action: copy URI
void ReceiveCoinsDialog::copyURI()
{
    QModelIndex sel = selectedRow();
    if (!sel.isValid()) {
        return;
    }

    const RecentRequestsTableModel * const submodel = model->getRecentRequestsTableModel();
    const QString uri = GUIUtil::formatBitcoinURI(submodel->entry(sel.row()).recipient);
    GUIUtil::setClipboard(uri);
}

// context menu action: copy label
void ReceiveCoinsDialog::copyLabel()
{
    copyColumnToClipboard(RecentRequestsTableModel::Label);
}

// context menu action: copy message
void ReceiveCoinsDialog::copyMessage()
{
    copyColumnToClipboard(RecentRequestsTableModel::Message);
}

// context menu action: copy amount
void ReceiveCoinsDialog::copyAmount()
{
    copyColumnToClipboard(RecentRequestsTableModel::Amount);
}
<commit_msg>GUI: Allow generating Bech32 addresses with a legacy-address default<commit_after>// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <wallet/wallet.h>

#include <qt/receivecoinsdialog.h>
#include <qt/forms/ui_receivecoinsdialog.h>

#include <qt/addressbookpage.h>
#include <qt/addresstablemodel.h>
#include <qt/bitcoinunits.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/receiverequestdialog.h>
#include <qt/recentrequeststablemodel.h>
#include <qt/walletmodel.h>

#include <QAction>
#include <QCursor>
#include <QMessageBox>
#include <QScrollBar>
#include <QTextDocument>

ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ReceiveCoinsDialog),
    columnResizingFixer(0),
    model(0),
    platformStyle(_platformStyle)
{
    ui->setupUi(this);
    QString theme = GUIUtil::getThemeName();

    if (!_platformStyle->getImagesOnButtons()) {
        ui->clearButton->setIcon(QIcon());
        ui->receiveButton->setIcon(QIcon());
        ui->showRequestButton->setIcon(QIcon());
        ui->removeRequestButton->setIcon(QIcon());
    } else {
        ui->clearButton->setIcon(QIcon(":/icons/" + theme + "/remove"));
        ui->receiveButton->setIcon(QIcon(":/icons/" + theme + "/receiving_addresses"));
        ui->showRequestButton->setIcon(QIcon(":/icons/" + theme + "/edit"));
        ui->removeRequestButton->setIcon(QIcon(":/icons/" + theme + "/remove"));
    }

    // context menu actions
    QAction *copyURIAction = new QAction(tr("Copy URI"), this);
    QAction *copyLabelAction = new QAction(tr("Copy label"), this);
    QAction *copyMessageAction = new QAction(tr("Copy message"), this);
    QAction *copyAmountAction = new QAction(tr("Copy amount"), this);

    // context menu
    contextMenu = new QMenu(this);
    contextMenu->addAction(copyURIAction);
    contextMenu->addAction(copyLabelAction);
    contextMenu->addAction(copyMessageAction);
    contextMenu->addAction(copyAmountAction);

    // context menu signals
    connect(ui->recentRequestsView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));
    connect(copyURIAction, SIGNAL(triggered()), this, SLOT(copyURI()));
    connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
    connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage()));
    connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));

    connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
}

void ReceiveCoinsDialog::setModel(WalletModel *_model)
{
    this->model = _model;

    if(_model && _model->getOptionsModel())
    {
        _model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
        connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
        updateDisplayUnit();

        QTableView* tableView = ui->recentRequestsView;

        tableView->verticalHeader()->hide();
        tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        tableView->setModel(_model->getRecentRequestsTableModel());
        tableView->setAlternatingRowColors(true);
        tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
        tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
        tableView->setColumnWidth(RecentRequestsTableModel::Date, DATE_COLUMN_WIDTH);
        tableView->setColumnWidth(RecentRequestsTableModel::Label, LABEL_COLUMN_WIDTH);

        connect(tableView->selectionModel(),
            SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this,
            SLOT(recentRequestsView_selectionChanged(QItemSelection, QItemSelection)));
        // Last 2 columns are set by the columnResizingFixer, when the table geometry is ready.
        columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);

        if (model->wallet().getDefaultAddressType() == OutputType::BECH32) {
            ui->useBech32->setCheckState(Qt::Checked);
        } else {
            ui->useBech32->setCheckState(Qt::Unchecked);
        }
    }
}

ReceiveCoinsDialog::~ReceiveCoinsDialog()
{
    delete ui;
}

void ReceiveCoinsDialog::clear()
{
    ui->reqAmount->clear();
    ui->reqLabel->setText("");
    ui->reqMessage->setText("");
    updateDisplayUnit();
}

void ReceiveCoinsDialog::reject()
{
    clear();
}

void ReceiveCoinsDialog::accept()
{
    clear();
}

void ReceiveCoinsDialog::updateDisplayUnit()
{
    if(model && model->getOptionsModel())
    {
        ui->reqAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
    }
}

void ReceiveCoinsDialog::on_receiveButton_clicked()
{
    if(!model || !model->getOptionsModel() || !model->getAddressTableModel() || !model->getRecentRequestsTableModel())
        return;

    QString address;
    QString label = ui->reqLabel->text();
    /* Generate new receiving address */
    OutputType address_type;
    if (ui->useBech32->isChecked()) {
        address_type = OutputType::BECH32;
    } else {
        address_type = model->wallet().getDefaultAddressType();
        if (address_type == OutputType::BECH32) {
            address_type = OutputType::P2SH_SEGWIT;
        }
    }
    address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", address_type);
    SendCoinsRecipient info(address, label,
        ui->reqAmount->value(), ui->reqMessage->text());
    ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->setModel(model);
    dialog->setInfo(info);
    dialog->show();
    clear();

    /* Store request for later reference */
    model->getRecentRequestsTableModel()->addNewRequest(info);
}

void ReceiveCoinsDialog::on_recentRequestsView_doubleClicked(const QModelIndex &index)
{
    const RecentRequestsTableModel *submodel = model->getRecentRequestsTableModel();
    ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
    dialog->setModel(model);
    dialog->setInfo(submodel->entry(index.row()).recipient);
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->show();
}

void ReceiveCoinsDialog::recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
    // Enable Show/Remove buttons only if anything is selected.
    bool enable = !ui->recentRequestsView->selectionModel()->selectedRows().isEmpty();
    ui->showRequestButton->setEnabled(enable);
    ui->removeRequestButton->setEnabled(enable);
}

void ReceiveCoinsDialog::on_showRequestButton_clicked()
{
    if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
        return;
    QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();

    for (const QModelIndex& index : selection) {
        on_recentRequestsView_doubleClicked(index);
    }
}

void ReceiveCoinsDialog::on_removeRequestButton_clicked()
{
    if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
        return;
    QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
    if(selection.empty())
        return;
    // correct for selection mode ContiguousSelection
    QModelIndex firstIndex = selection.at(0);
    model->getRecentRequestsTableModel()->removeRows(firstIndex.row(), selection.length(), firstIndex.parent());
}

// We override the virtual resizeEvent of the QWidget to adjust tables column
// sizes as the tables width is proportional to the dialogs width.
void ReceiveCoinsDialog::resizeEvent(QResizeEvent *event)
{
    QWidget::resizeEvent(event);
    columnResizingFixer->stretchColumnWidth(RecentRequestsTableModel::Message);
}

void ReceiveCoinsDialog::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Return)
    {
        // press return -> submit form
        if (ui->reqLabel->hasFocus() || ui->reqAmount->hasFocus() || ui->reqMessage->hasFocus())
        {
            event->ignore();
            on_receiveButton_clicked();
            return;
        }
    }

    this->QDialog::keyPressEvent(event);
}

QModelIndex ReceiveCoinsDialog::selectedRow()
{
    if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
        return QModelIndex();
    QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
    if(selection.empty())
        return QModelIndex();
    // correct for selection mode ContiguousSelection
    QModelIndex firstIndex = selection.at(0);
    return firstIndex;
}

// copy column of selected row to clipboard
void ReceiveCoinsDialog::copyColumnToClipboard(int column)
{
    QModelIndex firstIndex = selectedRow();
    if (!firstIndex.isValid()) {
        return;
    }
    GUIUtil::setClipboard(model->getRecentRequestsTableModel()->data(firstIndex.child(firstIndex.row(), column), Qt::EditRole).toString());
}

// context menu
void ReceiveCoinsDialog::showMenu(const QPoint &point)
{
    if (!selectedRow().isValid()) {
        return;
    }
    contextMenu->exec(QCursor::pos());
}

// context menu action: copy URI
void ReceiveCoinsDialog::copyURI()
{
    QModelIndex sel = selectedRow();
    if (!sel.isValid()) {
        return;
    }

    const RecentRequestsTableModel * const submodel = model->getRecentRequestsTableModel();
    const QString uri = GUIUtil::formatBitcoinURI(submodel->entry(sel.row()).recipient);
    GUIUtil::setClipboard(uri);
}

// context menu action: copy label
void ReceiveCoinsDialog::copyLabel()
{
    copyColumnToClipboard(RecentRequestsTableModel::Label);
}

// context menu action: copy message
void ReceiveCoinsDialog::copyMessage()
{
    copyColumnToClipboard(RecentRequestsTableModel::Message);
}

// context menu action: copy amount
void ReceiveCoinsDialog::copyAmount()
{
    copyColumnToClipboard(RecentRequestsTableModel::Amount);
}
<|endoftext|>


<commit_before>#include "Utility/String.h"

#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <cctype>

namespace String
{
    namespace
    {
        const auto whitespace = " \t\n";
    }
}

std::vector<std::string> String::split(std::string s, std::string delim, size_t count)
{
    if(delim.empty())
    {
        s = remove_extra_whitespace(s);
        delim = " ";
    }

    std::vector<std::string> result;
    size_t start_index = 0;
    size_t end_index = 0;
    size_t split_count = 0;
    while(end_index < s.size() && split_count < count)
    {
        end_index = s.find(delim, start_index);
        result.push_back(s.substr(start_index, end_index - start_index));
        start_index = std::min(end_index, s.size()) + delim.size();
        ++split_count;
    }

    if(start_index <= s.size())
    {
        result.push_back(s.substr(start_index));
    }

    return result;
}

bool String::starts_with(const std::string& s, const std::string& beginning)
{
    return (beginning.size() <= s.size()) && std::equal(beginning.begin(), beginning.end(), s.begin());
}

bool String::ends_with(const std::string& s, const std::string& ending)
{
    return (ending.size() <= s.size()) && std::equal(ending.rbegin(), ending.rend(), s.rbegin());
}

std::string String::trim_outer_whitespace(const std::string& s)
{
    auto text_start = s.find_first_not_of(whitespace);
    if(text_start == std::string::npos)
    {
        return {};
    }

    auto text_end = s.find_last_not_of(whitespace);
    return s.substr(text_start, text_end - text_start + 1);
}

std::string String::remove_extra_whitespace(const std::string& s)
{
    std::string result;

    for(auto c : trim_outer_whitespace(s))
    {
        if(contains(whitespace, c))
        {
            if(result.back() != ' ')
            {
                result.push_back(' ');
            }
        }
        else
        {
            result.push_back(c);
        }
    }

    return result;
}

std::string String::strip_comments(const std::string& str, const std::string& comment)
{
    return trim_outer_whitespace(str.substr(0, str.find(comment)));
}

std::string String::strip_block_comment(const std::string& str, const std::string& start, const std::string& end)
{
    auto start_comment_index = str.find(start);
    auto end_comment_index = str.find(end);

    if(start_comment_index == std::string::npos && end_comment_index == std::string::npos)
    {
        return trim_outer_whitespace(str);
    }

    if(start_comment_index == std::string::npos || end_comment_index == std::string::npos)
    {
        throw std::invalid_argument("\"" + str + "\" is missing a comment delimiter: " + std::string{start} + std::string{end});
    }

    if(start_comment_index >= end_comment_index)
    {
        throw std::invalid_argument("\"" + str + "\" contains bad comment delimiters: " + std::string{start} + std::string{end});
    }

    auto first_part = str.substr(0, start_comment_index);
    auto last_part = str.substr(end_comment_index + end.size());
    return strip_block_comment(trim_outer_whitespace(first_part) + " " + trim_outer_whitespace(last_part), start, end);
}

std::string String::lowercase(std::string s)
{
    for(auto& c : s){ c = std::tolower(c); }
    return s;
}

std::string String::format_integer(int n, const std::string& separator)
{
    if(n < 0)
    {
        return '-' + format_integer(size_t(-n), separator);
    }
    else
    {
        return format_integer(size_t(n), separator);
    }
}

std::string String::format_integer(size_t n, const std::string& separator)
{
    auto s = std::to_string(n);
    auto index = s.size() % 3;
    index = (index == 0 ? 3 : index);
    auto result = s.substr(0, index);

    for( ; index < s.size(); index += 3)
    {
        result += separator;
        result += s.substr(index, 3);
    }

    return result;
}
<commit_msg>Empty string results in an empty split() vector<commit_after>#include "Utility/String.h"

#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <cctype>

namespace String
{
    namespace
    {
        const auto whitespace = " \t\n";
    }
}

std::vector<std::string> String::split(std::string s, std::string delim, size_t count)
{
    if(delim.empty())
    {
        s = remove_extra_whitespace(s);
        delim = " ";
    }

    if(s.empty())
    {
        return {};
    }

    std::vector<std::string> result;
    size_t start_index = 0;
    size_t end_index = 0;
    size_t split_count = 0;
    while(end_index < s.size() && split_count < count)
    {
        end_index = s.find(delim, start_index);
        result.push_back(s.substr(start_index, end_index - start_index));
        start_index = std::min(end_index, s.size()) + delim.size();
        ++split_count;
    }

    if(start_index <= s.size())
    {
        result.push_back(s.substr(start_index));
    }

    return result;
}

bool String::starts_with(const std::string& s, const std::string& beginning)
{
    return (beginning.size() <= s.size()) && std::equal(beginning.begin(), beginning.end(), s.begin());
}

bool String::ends_with(const std::string& s, const std::string& ending)
{
    return (ending.size() <= s.size()) && std::equal(ending.rbegin(), ending.rend(), s.rbegin());
}

std::string String::trim_outer_whitespace(const std::string& s)
{
    auto text_start = s.find_first_not_of(whitespace);
    if(text_start == std::string::npos)
    {
        return {};
    }

    auto text_end = s.find_last_not_of(whitespace);
    return s.substr(text_start, text_end - text_start + 1);
}

std::string String::remove_extra_whitespace(const std::string& s)
{
    std::string result;

    for(auto c : trim_outer_whitespace(s))
    {
        if(contains(whitespace, c))
        {
            if(result.back() != ' ')
            {
                result.push_back(' ');
            }
        }
        else
        {
            result.push_back(c);
        }
    }

    return result;
}

std::string String::strip_comments(const std::string& str, const std::string& comment)
{
    return trim_outer_whitespace(str.substr(0, str.find(comment)));
}

std::string String::strip_block_comment(const std::string& str, const std::string& start, const std::string& end)
{
    auto start_comment_index = str.find(start);
    auto end_comment_index = str.find(end);

    if(start_comment_index == std::string::npos && end_comment_index == std::string::npos)
    {
        return trim_outer_whitespace(str);
    }

    if(start_comment_index == std::string::npos || end_comment_index == std::string::npos)
    {
        throw std::invalid_argument("\"" + str + "\" is missing a comment delimiter: " + std::string{start} + std::string{end});
    }

    if(start_comment_index >= end_comment_index)
    {
        throw std::invalid_argument("\"" + str + "\" contains bad comment delimiters: " + std::string{start} + std::string{end});
    }

    auto first_part = str.substr(0, start_comment_index);
    auto last_part = str.substr(end_comment_index + end.size());
    return strip_block_comment(trim_outer_whitespace(first_part) + " " + trim_outer_whitespace(last_part), start, end);
}

std::string String::lowercase(std::string s)
{
    for(auto& c : s){ c = std::tolower(c); }
    return s;
}

std::string String::format_integer(int n, const std::string& separator)
{
    if(n < 0)
    {
        return '-' + format_integer(size_t(-n), separator);
    }
    else
    {
        return format_integer(size_t(n), separator);
    }
}

std::string String::format_integer(size_t n, const std::string& separator)
{
    auto s = std::to_string(n);
    auto index = s.size() % 3;
    index = (index == 0 ? 3 : index);
    auto result = s.substr(0, index);

    for( ; index < s.size(); index += 3)
    {
        result += separator;
        result += s.substr(index, 3);
    }

    return result;
}
<|endoftext|>


<commit_before>/*
 * Tetromino4.cpp
 *
 *  Created on: 28.04.2014
 *      Author: nicola
 */

#include <iostream>
#include "Libraries.hpp"
#include "Tetromino4.hpp"
#include <sstream>

std::string itos(int i){
	std::stringstream ss;
	ss<<i;
	return ss.str();
}

/* Definition of static const, Tick time in ms */
const Point2D Tetromino4::startPos = {
	static_cast<int>(MAP_WIDTH/2),
	-2  /* So it's not visible just yet */};

Tetromino4::Tetromino4(ColorType Color)
:Tetromino(startPos) {
	/* Initialise square list with only blocks */
	for(unsigned int i=0; i<4; i++) {
		squares.push_back(new Block(Color));
	}
}

Tetromino4::~Tetromino4() {
	/* Delete square list */
	squares.clear();
}

void Tetromino4::rotate(bool Cw) {
	/* Tetromino4 doesn't need to be rotated */
}

void Tetromino4::draw() {
	/* Draw each square */
	for(unsigned int i=0; i<4; i++) {
		if(squares[i].getType() == typeBlock) {
			int x = position.x*SQUARE_WIDTH;
			int y = position.y*SQUARE_WIDTH;
			if(y >= 0) {
				DrawFilledRectangle(x, y, SQUARE_WIDTH, SQUARE_WIDTH, squares[i].getColor(), 0);
			}
		}
	}
}
<commit_msg>Fixed block position drawing<commit_after>/*
 * Tetromino4.cpp
 *
 *  Created on: 28.04.2014
 *      Author: nicola
 */

#include <iostream>
#include "Libraries.hpp"
#include "Tetromino4.hpp"
#include <sstream>

std::string itos(int i){
	std::stringstream ss;
	ss<<i;
	return ss.str();
}

/* Definition of static const, Tick time in ms */
const Point2D Tetromino4::startPos = {
	static_cast<int>(MAP_WIDTH/2)-1,
	-2  /* So it's not visible just yet */};

Tetromino4::Tetromino4(ColorType Color)
:Tetromino(startPos) {
	/* Initialise square list with only blocks */
	for(unsigned int i=0; i<4; i++) {
		squares.push_back(new Block(Color));
	}
}

Tetromino4::~Tetromino4() {
	/* Delete square list */
	squares.clear();
}

void Tetromino4::rotate(bool Cw) {
	/* Tetromino4 doesn't need to be rotated */
}

void Tetromino4::draw() {
	/* Draw each square */
	for(unsigned int i=0; i<2; i++) {
		for(unsigned int j=0; j<2; j++) {
			if(squares[i+j].getType() == typeBlock) {
				int x = (position.x + i%2) * SQUARE_WIDTH;
				int y = (position.y + j%2) * SQUARE_WIDTH;
				if(y >= 0) {
					DrawFilledRectangle(x, y, SQUARE_WIDTH, SQUARE_WIDTH, squares[i+j].getColor(), 0);
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* libmspub
 * Version: MPL 1.1 / GPLv2+ / LGPLv2+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License or as specified alternatively below. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Major Contributor(s):
 * Copyright (C) 2012 Fridrich Strba <fridrich.strba@bluewin.ch>
 *
 *
 * All Rights Reserved.
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
 * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
 * instead of those above.
 */

#include <vector>
#include "MSPUBStringVector.h"

namespace libmspub
{
class MSPUBStringVectorImpl
{
public:
  MSPUBStringVectorImpl() : m_strings() {}
  ~MSPUBStringVectorImpl() {}
  std::vector<WPXString> m_strings;
};

} // namespace libmspub

libmspub::MSPUBStringVector::MSPUBStringVector()
  : m_pImpl(new MSPUBStringVectorImpl())
{
}

libmspub::MSPUBStringVector::MSPUBStringVector(const MSPUBStringVector &vec)
  : m_pImpl(new MSPUBStringVectorImpl(*(vec.m_pImpl)))
{
}

libmspub::MSPUBStringVector::~MSPUBStringVector()
{
}

libmspub::MSPUBStringVector &libmspub::MSPUBStringVector::operator=(const MSPUBStringVector &vec)
{
  // Check for self-assignment
  if (this == &vec)
    return *this;
  if (m_pImpl)
    delete m_pImpl;
  m_pImpl = new MSPUBStringVectorImpl(*(vec.m_pImpl));
  return *this;
}

unsigned libmspub::MSPUBStringVector::size() const
{
  return (unsigned)(m_pImpl->m_strings.size());
}

bool libmspub::MSPUBStringVector::empty() const
{
  return m_pImpl->m_strings.empty();
}

const WPXString &libmspub::MSPUBStringVector::operator[](unsigned idx) const
{
  return m_pImpl->m_strings[idx];
}

void libmspub::MSPUBStringVector::append(const WPXString &str)
{
  m_pImpl->m_strings.push_back(str);
}

void libmspub::MSPUBStringVector::clear()
{
  m_pImpl->m_strings.clear();
}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<commit_msg>coverity: memory leak<commit_after>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* libmspub
 * Version: MPL 1.1 / GPLv2+ / LGPLv2+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License or as specified alternatively below. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Major Contributor(s):
 * Copyright (C) 2012 Fridrich Strba <fridrich.strba@bluewin.ch>
 *
 *
 * All Rights Reserved.
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
 * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
 * instead of those above.
 */

#include <vector>
#include "MSPUBStringVector.h"

namespace libmspub
{
class MSPUBStringVectorImpl
{
public:
  MSPUBStringVectorImpl() : m_strings() {}
  ~MSPUBStringVectorImpl() {}
  std::vector<WPXString> m_strings;
};

} // namespace libmspub

libmspub::MSPUBStringVector::MSPUBStringVector()
  : m_pImpl(new MSPUBStringVectorImpl())
{
}

libmspub::MSPUBStringVector::MSPUBStringVector(const MSPUBStringVector &vec)
  : m_pImpl(new MSPUBStringVectorImpl(*(vec.m_pImpl)))
{
}

libmspub::MSPUBStringVector::~MSPUBStringVector()
{
  delete m_pImpl;
}

libmspub::MSPUBStringVector &libmspub::MSPUBStringVector::operator=(const MSPUBStringVector &vec)
{
  // Check for self-assignment
  if (this == &vec)
    return *this;
  if (m_pImpl)
    delete m_pImpl;
  m_pImpl = new MSPUBStringVectorImpl(*(vec.m_pImpl));
  return *this;
}

unsigned libmspub::MSPUBStringVector::size() const
{
  return (unsigned)(m_pImpl->m_strings.size());
}

bool libmspub::MSPUBStringVector::empty() const
{
  return m_pImpl->m_strings.empty();
}

const WPXString &libmspub::MSPUBStringVector::operator[](unsigned idx) const
{
  return m_pImpl->m_strings[idx];
}

void libmspub::MSPUBStringVector::append(const WPXString &str)
{
  m_pImpl->m_strings.push_back(str);
}

void libmspub::MSPUBStringVector::clear()
{
  m_pImpl->m_strings.clear();
}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<|endoftext|>