<commit_before>#include "lm/enumerate_vocab.hh"
#include "lm/model.hh"

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>

#include <ctype.h>

#include <sys/resource.h>
#include <sys/time.h>

float FloatSec(const struct timeval &tv) {
  return static_cast<float>(tv.tv_sec) + (static_cast<float>(tv.tv_usec) / 1000000000.0);
}

void PrintUsage(const char *message) {
  struct rusage usage;
  if (getrusage(RUSAGE_SELF, &usage)) {
    perror("getrusage");
    return;
  }
  std::cerr << message;
  std::cerr << "user\t" << FloatSec(usage.ru_utime) << "\nsys\t" << FloatSec(usage.ru_stime) << '\n';

  // Linux doesn't set memory usage :-(.
  std::ifstream status("/proc/self/status", std::ios::in);
  std::string line;
  while (getline(status, line)) {
    if (!strncmp(line.c_str(), "VmRSS:\t", 7)) {
      std::cerr << "rss " << (line.c_str() + 7) << '\n';
      break;
    }
  }
}

template <class Model> void Query(const Model &model) {
  PrintUsage("Loading statistics:\n");
  typename Model::State state, out;
  lm::FullScoreReturn ret;
  std::string word;

  while (std::cin) {
    state = model.BeginSentenceState();
    float total = 0.0;
    bool got = false;
    unsigned int oov = 0;
    while (std::cin >> word) {
      got = true;
      lm::WordIndex vocab = model.GetVocabulary().Index(word);
      if (vocab == 0) ++oov;
      ret = model.FullScore(state, vocab, out);
      total += ret.prob;
      std::cout << word << '=' << vocab << ' ' << static_cast<unsigned int>(ret.ngram_length)  << ' ' << ret.prob << '\n';
      state = out;
      char c;
      while (true) {
        c = std::cin.get();
        if (!std::cin) break;
        if (c == '\n') break;
        if (!isspace(c)) {
          std::cin.unget();
          break;
        }
      }
      if (c == '\n') break;
    }
    if (!got && !std::cin) break;
    ret = model.FullScore(state, model.GetVocabulary().EndSentence(), out);
    total += ret.prob;
    std::cout << "</s>=" << model.GetVocabulary().EndSentence() << ' ' << static_cast<unsigned int>(ret.ngram_length)  << ' ' << ret.prob << '\n';
    std::cout << "Total: " << total << " OOV: " << oov << '\n';
  }
  PrintUsage("After queries:\n");
}

template <class Model> void Query(const char *name) {
  lm::ngram::Config config;
  Model model(name, config);
  Query(model);
}

int main(int argc, char *argv[]) {
  if (argc < 2) {
    std::cerr << "Pass language model name." << std::endl;
    return 0;
  }
  lm::ngram::ModelType model_type;
  if (lm::ngram::RecognizeBinary(argv[1], model_type)) {
    switch(model_type) {
      case lm::ngram::HASH_PROBING:
        Query<lm::ngram::ProbingModel>(argv[1]);
        break;
      case lm::ngram::HASH_SORTED:
        Query<lm::ngram::SortedModel>(argv[1]);
        break;
      case lm::ngram::TRIE_SORTED:
        Query<lm::ngram::TrieModel>(argv[1]);
        break;
      default:
        std::cerr << "Unrecognized kenlm model type " << model_type << std::endl;
        abort();
    }
  } else {
    Query<lm::ngram::ProbingModel>(argv[1]);
  }

  PrintUsage("Total time including destruction:\n");
}
<commit_msg>Option for null context in n-gram query, use tab for delimiter<commit_after>#include "lm/enumerate_vocab.hh"
#include "lm/model.hh"

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>

#include <ctype.h>

#include <sys/resource.h>
#include <sys/time.h>

float FloatSec(const struct timeval &tv) {
  return static_cast<float>(tv.tv_sec) + (static_cast<float>(tv.tv_usec) / 1000000000.0);
}

void PrintUsage(const char *message) {
  struct rusage usage;
  if (getrusage(RUSAGE_SELF, &usage)) {
    perror("getrusage");
    return;
  }
  std::cerr << message;
  std::cerr << "user\t" << FloatSec(usage.ru_utime) << "\nsys\t" << FloatSec(usage.ru_stime) << '\n';

  // Linux doesn't set memory usage :-(.
  std::ifstream status("/proc/self/status", std::ios::in);
  std::string line;
  while (getline(status, line)) {
    if (!strncmp(line.c_str(), "VmRSS:\t", 7)) {
      std::cerr << "rss " << (line.c_str() + 7) << '\n';
      break;
    }
  }
}

template <class Model> void Query(const Model &model, bool sentence_context) {
  PrintUsage("Loading statistics:\n");
  typename Model::State state, out;
  lm::FullScoreReturn ret;
  std::string word;

  while (std::cin) {
    state = sentence_context ? model.BeginSentenceState() : model.NullContextState();
    float total = 0.0;
    bool got = false;
    unsigned int oov = 0;
    while (std::cin >> word) {
      got = true;
      lm::WordIndex vocab = model.GetVocabulary().Index(word);
      if (vocab == 0) ++oov;
      ret = model.FullScore(state, vocab, out);
      total += ret.prob;
      std::cout << word << '=' << vocab << ' ' << static_cast<unsigned int>(ret.ngram_length)  << ' ' << ret.prob << '\t';
      state = out;
      char c;
      while (true) {
        c = std::cin.get();
        if (!std::cin) break;
        if (c == '\n') break;
        if (!isspace(c)) {
          std::cin.unget();
          break;
        }
      }
      if (c == '\n') break;
    }
    if (!got && !std::cin) break;
    if (sentence_context) {
      ret = model.FullScore(state, model.GetVocabulary().EndSentence(), out);
      total += ret.prob;
      std::cout << "</s>=" << model.GetVocabulary().EndSentence() << ' ' << static_cast<unsigned int>(ret.ngram_length)  << ' ' << ret.prob << '\t';
    }
    std::cout << "Total: " << total << " OOV: " << oov << '\n';
  }
  PrintUsage("After queries:\n");
}

template <class Model> void Query(const char *name) {
  lm::ngram::Config config;
  Model model(name, config);
  Query(model);
}

int main(int argc, char *argv[]) {
  if (!(argc == 2 || (argc == 3 && !strcmp(argv[2], "null")))) {
    std::cerr << "Usage: " << argv[0] << " lm_file [null]" << std::endl;
    std::cerr << "Input is wrapped in <s> and </s> unless null is passed." << std::endl;
    return 1;
  }
  bool sentence_context = (argc == 2);
  lm::ngram::ModelType model_type;
  if (lm::ngram::RecognizeBinary(argv[1], model_type)) {
    switch(model_type) {
      case lm::ngram::HASH_PROBING:
        Query<lm::ngram::ProbingModel>(argv[1], sentence_context);
        break;
      case lm::ngram::TRIE_SORTED:
        Query<lm::ngram::TrieModel>(argv[1], sentence_context);
        break;
      case lm::ngram::HASH_SORTED:
      default:
        std::cerr << "Unrecognized kenlm model type " << model_type << std::endl;
        abort();
    }
  } else {
    Query<lm::ngram::ProbingModel>(argv[1], sentence_context);
  }

  PrintUsage("Total time including destruction:\n");
  return 0;
}
<|endoftext|>


<commit_before>#include "pattern_search.h"

void findPattern(const string& pattern, const string& text,
  vector<int> *ppositions) {

  if (pattern.empty())
    return;

  auto& positions = *ppositions;
  positions.clear();

  for (size_t i = 0; i < text.size(); i++) {
    bool found = true;
    for (size_t j = 0; j < pattern.size(); j++) {
      if (pattern[j] != text[i + j]) {
        found = false;
        break;
      }
    }
    if (found)
      positions.push_back(i);
  }
}<commit_msg>Fix pattern search<commit_after>#include "pattern_search.h"

void findPattern(const string& pattern, const string& text,
  vector<int> *ppositions) {

  auto& positions = *ppositions;
  positions.clear();

  if (pattern.empty())
    return;

  for (size_t i = 0; i < text.size(); i++) {
    bool found = true;
    for (size_t j = 0; j < pattern.size(); j++) {
      if (pattern[j] != text[i + j]) {
        found = false;
        break;
      }
    }
    if (found)
      positions.push_back(i);
  }
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "SkPDFImage.h"

#include "SkBitmap.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkPaint.h"
#include "SkPackBits.h"
#include "SkPDFCatalog.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkUnPreMultiply.h"

namespace {

SkMemoryStream* extractImageData(const SkBitmap& bitmap) {
    SkMemoryStream* result;

    switch (bitmap.getConfig()) {
        case SkBitmap::kIndex8_Config:
            result = new SkMemoryStream(bitmap.getPixels(), bitmap.getSize(),
                                        true);
            break;
        case SkBitmap::kRLE_Index8_Config: {
            result = new SkMemoryStream(bitmap.getSize());
            const SkBitmap::RLEPixels* rle =
                (const SkBitmap::RLEPixels*)bitmap.getPixels();
            uint8_t* dst = (uint8_t*)result->getMemoryBase();
            const int width = bitmap.width();
            for (int y = 0; y < bitmap.height(); y++) {
                SkPackBits::Unpack8(rle->packedAtY(y), width, dst);
                dst += width;
            }
            break;
        }
        case SkBitmap::kARGB_4444_Config: {
            const int width = bitmap.width();
            const int rowBytes = (width * 3 + 1) / 2;
            result = new SkMemoryStream(rowBytes * bitmap.height());
            uint8_t* dst = (uint8_t*)result->getMemoryBase();
            for (int y = 0; y < bitmap.height(); y++) {
                uint16_t* src = bitmap.getAddr16(0, y);
                for (int x = 0; x < width; x += 2) {
                    dst[0] = (SkGetPackedR4444(src[0]) << 4) |
                        SkGetPackedG4444(src[0]);
                    dst[1] = (SkGetPackedB4444(src[0]) << 4) |
                        SkGetPackedR4444(src[1]);
                    dst[2] = (SkGetPackedG4444(src[1]) << 4) |
                        SkGetPackedB4444(src[1]);
                    src += 2;
                    dst += 3;
                }
                if (width & 1) {
                    dst[0] = (SkGetPackedR4444(src[0]) << 4) |
                        SkGetPackedG4444(src[0]);
                    dst[1] = (SkGetPackedB4444(src[0]) << 4);
                }
            }
            break;
        }
        case SkBitmap::kRGB_565_Config: {
            const int width = bitmap.width();
            const int rowBytes = width * 3;
            result = new SkMemoryStream(rowBytes * bitmap.height());
            uint8_t* dst = (uint8_t*)result->getMemoryBase();
            for (int y = 0; y < bitmap.height(); y++) {
                uint16_t* src = bitmap.getAddr16(0, y);
                for (int x = 0; x < width; x++) {
                    dst[0] = SkGetPackedR16(src[0]);
                    dst[1] = SkGetPackedG16(src[0]);
                    dst[2] = SkGetPackedB16(src[0]);
                    src++;
                    dst += 3;
                }
            }
            break;
        }
        case SkBitmap::kARGB_8888_Config: {
            const int width = bitmap.width();
            const int rowBytes = width * 3;
            result = new SkMemoryStream(rowBytes * bitmap.height());
            uint8_t* dst = (uint8_t*)result->getMemoryBase();
            for (int y = 0; y < bitmap.height(); y++) {
                uint32_t* src = bitmap.getAddr32(0, y);
                for (int x = 0; x < width; x++) {
                    dst[0] = SkGetPackedR32(src[0]);
                    dst[1] = SkGetPackedG32(src[0]);
                    dst[2] = SkGetPackedB32(src[0]);
                    src++;
                    dst += 3;
                }
            }
            break;
        }
        default:
            SkASSERT(false);
    }
    return result;
}

SkPDFArray* makeIndexedColorSpace(SkColorTable* table) {
    SkPDFArray* result = new SkPDFArray();
    result->reserve(4);
    SkRefPtr<SkPDFName> indexedName = new SkPDFName("Indexed");
    indexedName->unref();  // SkRefPtr and new both took a reference.
    result->append(indexedName.get());

    SkRefPtr<SkPDFName> rgbName = new SkPDFName("DeviceRGB");
    rgbName->unref();  // SkRefPtr and new both took a reference.
    result->append(rgbName.get());

    rgbName->unref();  // SkRefPtr and new both took a reference.
    SkRefPtr<SkPDFInt> countValue = new SkPDFInt(table->count() - 1);
    result->append(countValue.get());

    // Potentially, this could be represented in fewer bytes with a stream.
    // Max size as a string is 1.5k.
    SkString index;
    for (int i = 0; i < table->count(); i++) {
        char buf[3];
        SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]);
        buf[0] = SkGetPackedR32(color);
        buf[1] = SkGetPackedG32(color);
        buf[2] = SkGetPackedB32(color);
        index.append(buf, 3);
    }
    SkRefPtr<SkPDFString> indexValue = new SkPDFString(index);
    indexValue->unref();  // SkRefPtr and new both took a reference.
    result->append(indexValue.get());
    return result;
}

};  // namespace

SkPDFImage::SkPDFImage(const SkBitmap& bitmap, const SkPaint& paint) {
    SkBitmap::Config config = bitmap.getConfig();

    // TODO(vandebo) Handle alpha and alpha only images correctly.
    SkASSERT(config == SkBitmap::kRGB_565_Config ||
             config == SkBitmap::kARGB_4444_Config ||
             config == SkBitmap::kARGB_8888_Config ||
             config == SkBitmap::kIndex8_Config ||
             config == SkBitmap::kRLE_Index8_Config);

    SkMemoryStream* image_data = extractImageData(bitmap);
    SkAutoUnref image_data_unref(image_data);
    fStream = new SkPDFStream(image_data);
    fStream->unref();  // SkRefPtr and new both took a reference.

    SkRefPtr<SkPDFName> typeValue = new SkPDFName("XObject");
    typeValue->unref();  // SkRefPtr and new both took a reference.
    insert("Type", typeValue.get());

    SkRefPtr<SkPDFName> subTypeValue = new SkPDFName("Image");
    subTypeValue->unref();  // SkRefPtr and new both took a reference.
    insert("Subtype", subTypeValue.get());

    SkRefPtr<SkPDFInt> widthValue = new SkPDFInt(bitmap.width());
    widthValue->unref();  // SkRefPtr and new both took a reference.
    insert("Width", widthValue.get());

    SkRefPtr<SkPDFInt> heightValue = new SkPDFInt(bitmap.height());
    heightValue->unref();  // SkRefPtr and new both took a reference.
    insert("Height", heightValue.get());

    // if (!image mask) {
    SkRefPtr<SkPDFObject> colorSpaceValue;
    if (config == SkBitmap::kIndex8_Config ||
        config == SkBitmap::kRLE_Index8_Config) {
        colorSpaceValue = makeIndexedColorSpace(bitmap.getColorTable());
    } else {
        colorSpaceValue = new SkPDFName("DeviceRGB");
    }
    colorSpaceValue->unref();  // SkRefPtr and new both took a reference.
    insert("ColorSpace", colorSpaceValue.get());
    // }

    int bitsPerComp = bitmap.bytesPerPixel() * 2;
    if (bitsPerComp == 0) {
        SkASSERT(config == SkBitmap::kA1_Config);
        bitsPerComp = 1;
    } else if (bitsPerComp == 2 ||
               (bitsPerComp == 4 && config == SkBitmap::kRGB_565_Config)) {
        bitsPerComp = 8;
    }
    SkRefPtr<SkPDFInt> bitsPerCompValue = new SkPDFInt(bitsPerComp);
    bitsPerCompValue->unref();  // SkRefPtr and new both took a reference.
    insert("BitsPerComponent", bitsPerCompValue.get());

    if (config == SkBitmap::kRGB_565_Config) {
        SkRefPtr<SkPDFInt> zeroVal = new SkPDFInt(0);
        zeroVal->unref();  // SkRefPtr and new both took a reference.
        SkRefPtr<SkPDFScalar> scale5Val = new SkPDFScalar(8.2258);  // 255/2^5-1
        scale5Val->unref();  // SkRefPtr and new both took a reference.
        SkRefPtr<SkPDFScalar> scale6Val = new SkPDFScalar(4.0476);  // 255/2^6-1
        scale6Val->unref();  // SkRefPtr and new both took a reference.
        SkRefPtr<SkPDFArray> decodeValue = new SkPDFArray();
        decodeValue->unref();  // SkRefPtr and new both took a reference.
        decodeValue->reserve(6);
        decodeValue->append(zeroVal.get());
        decodeValue->append(scale5Val.get());
        decodeValue->append(zeroVal.get());
        decodeValue->append(scale6Val.get());
        decodeValue->append(zeroVal.get());
        decodeValue->append(scale5Val.get());
        insert("Decode", decodeValue.get());
    }
}

SkPDFImage::~SkPDFImage() {}

void SkPDFImage::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
                             bool indirect) {
    if (indirect)
        return emitIndirectObject(stream, catalog);

    fStream->emitObject(stream, catalog, indirect);
}

size_t SkPDFImage::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    if (indirect)
        return getIndirectOutputSize(catalog);

    return fStream->getOutputSize(catalog, indirect);
}

void SkPDFImage::insert(SkPDFName* key, SkPDFObject* value) {
    fStream->insert(key, value);
}

void SkPDFImage::insert(const char key[], SkPDFObject* value) {
    fStream->insert(key, value);
}
<commit_msg>Bug fix in SkPDFImage.<commit_after>/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "SkPDFImage.h"

#include "SkBitmap.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkPaint.h"
#include "SkPackBits.h"
#include "SkPDFCatalog.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkUnPreMultiply.h"

namespace {

SkMemoryStream* extractImageData(const SkBitmap& bitmap) {
    SkMemoryStream* result;

    bitmap.lockPixels();
    switch (bitmap.getConfig()) {
        case SkBitmap::kIndex8_Config:
            result = new SkMemoryStream(bitmap.getPixels(), bitmap.getSize(),
                                        true);
            break;
        case SkBitmap::kRLE_Index8_Config: {
            result = new SkMemoryStream(bitmap.getSize());
            const SkBitmap::RLEPixels* rle =
                (const SkBitmap::RLEPixels*)bitmap.getPixels();
            uint8_t* dst = (uint8_t*)result->getMemoryBase();
            const int width = bitmap.width();
            for (int y = 0; y < bitmap.height(); y++) {
                SkPackBits::Unpack8(rle->packedAtY(y), width, dst);
                dst += width;
            }
            break;
        }
        case SkBitmap::kARGB_4444_Config: {
            const int width = bitmap.width();
            const int rowBytes = (width * 3 + 1) / 2;
            result = new SkMemoryStream(rowBytes * bitmap.height());
            uint8_t* dst = (uint8_t*)result->getMemoryBase();
            for (int y = 0; y < bitmap.height(); y++) {
                uint16_t* src = bitmap.getAddr16(0, y);
                for (int x = 0; x < width; x += 2) {
                    dst[0] = (SkGetPackedR4444(src[0]) << 4) |
                        SkGetPackedG4444(src[0]);
                    dst[1] = (SkGetPackedB4444(src[0]) << 4) |
                        SkGetPackedR4444(src[1]);
                    dst[2] = (SkGetPackedG4444(src[1]) << 4) |
                        SkGetPackedB4444(src[1]);
                    src += 2;
                    dst += 3;
                }
                if (width & 1) {
                    dst[0] = (SkGetPackedR4444(src[0]) << 4) |
                        SkGetPackedG4444(src[0]);
                    dst[1] = (SkGetPackedB4444(src[0]) << 4);
                }
            }
            break;
        }
        case SkBitmap::kRGB_565_Config: {
            const int width = bitmap.width();
            const int rowBytes = width * 3;
            result = new SkMemoryStream(rowBytes * bitmap.height());
            uint8_t* dst = (uint8_t*)result->getMemoryBase();
            for (int y = 0; y < bitmap.height(); y++) {
                uint16_t* src = bitmap.getAddr16(0, y);
                for (int x = 0; x < width; x++) {
                    dst[0] = SkGetPackedR16(src[0]);
                    dst[1] = SkGetPackedG16(src[0]);
                    dst[2] = SkGetPackedB16(src[0]);
                    src++;
                    dst += 3;
                }
            }
            break;
        }
        case SkBitmap::kARGB_8888_Config: {
            const int width = bitmap.width();
            const int rowBytes = width * 3;
            result = new SkMemoryStream(rowBytes * bitmap.height());
            uint8_t* dst = (uint8_t*)result->getMemoryBase();
            for (int y = 0; y < bitmap.height(); y++) {
                uint32_t* src = bitmap.getAddr32(0, y);
                for (int x = 0; x < width; x++) {
                    dst[0] = SkGetPackedR32(src[0]);
                    dst[1] = SkGetPackedG32(src[0]);
                    dst[2] = SkGetPackedB32(src[0]);
                    src++;
                    dst += 3;
                }
            }
            break;
        }
        default:
            SkASSERT(false);
    }
    bitmap.unlockPixels();
    return result;
}

SkPDFArray* makeIndexedColorSpace(SkColorTable* table) {
    SkPDFArray* result = new SkPDFArray();
    result->reserve(4);
    SkRefPtr<SkPDFName> indexedName = new SkPDFName("Indexed");
    indexedName->unref();  // SkRefPtr and new both took a reference.
    result->append(indexedName.get());

    SkRefPtr<SkPDFName> rgbName = new SkPDFName("DeviceRGB");
    rgbName->unref();  // SkRefPtr and new both took a reference.
    result->append(rgbName.get());

    rgbName->unref();  // SkRefPtr and new both took a reference.
    SkRefPtr<SkPDFInt> countValue = new SkPDFInt(table->count() - 1);
    result->append(countValue.get());

    // Potentially, this could be represented in fewer bytes with a stream.
    // Max size as a string is 1.5k.
    SkString index;
    for (int i = 0; i < table->count(); i++) {
        char buf[3];
        SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]);
        buf[0] = SkGetPackedR32(color);
        buf[1] = SkGetPackedG32(color);
        buf[2] = SkGetPackedB32(color);
        index.append(buf, 3);
    }
    SkRefPtr<SkPDFString> indexValue = new SkPDFString(index);
    indexValue->unref();  // SkRefPtr and new both took a reference.
    result->append(indexValue.get());
    return result;
}

};  // namespace

SkPDFImage::SkPDFImage(const SkBitmap& bitmap, const SkPaint& paint) {
    SkBitmap::Config config = bitmap.getConfig();

    // TODO(vandebo) Handle alpha and alpha only images correctly.
    SkASSERT(config == SkBitmap::kRGB_565_Config ||
             config == SkBitmap::kARGB_4444_Config ||
             config == SkBitmap::kARGB_8888_Config ||
             config == SkBitmap::kIndex8_Config ||
             config == SkBitmap::kRLE_Index8_Config);

    SkMemoryStream* image_data = extractImageData(bitmap);
    SkAutoUnref image_data_unref(image_data);
    fStream = new SkPDFStream(image_data);
    fStream->unref();  // SkRefPtr and new both took a reference.

    SkRefPtr<SkPDFName> typeValue = new SkPDFName("XObject");
    typeValue->unref();  // SkRefPtr and new both took a reference.
    insert("Type", typeValue.get());

    SkRefPtr<SkPDFName> subTypeValue = new SkPDFName("Image");
    subTypeValue->unref();  // SkRefPtr and new both took a reference.
    insert("Subtype", subTypeValue.get());

    SkRefPtr<SkPDFInt> widthValue = new SkPDFInt(bitmap.width());
    widthValue->unref();  // SkRefPtr and new both took a reference.
    insert("Width", widthValue.get());

    SkRefPtr<SkPDFInt> heightValue = new SkPDFInt(bitmap.height());
    heightValue->unref();  // SkRefPtr and new both took a reference.
    insert("Height", heightValue.get());

    // if (!image mask) {
    SkRefPtr<SkPDFObject> colorSpaceValue;
    if (config == SkBitmap::kIndex8_Config ||
        config == SkBitmap::kRLE_Index8_Config) {
        colorSpaceValue = makeIndexedColorSpace(bitmap.getColorTable());
    } else {
        colorSpaceValue = new SkPDFName("DeviceRGB");
    }
    colorSpaceValue->unref();  // SkRefPtr and new both took a reference.
    insert("ColorSpace", colorSpaceValue.get());
    // }

    int bitsPerComp = bitmap.bytesPerPixel() * 2;
    if (bitsPerComp == 0) {
        SkASSERT(config == SkBitmap::kA1_Config);
        bitsPerComp = 1;
    } else if (bitsPerComp == 2 ||
               (bitsPerComp == 4 && config == SkBitmap::kRGB_565_Config)) {
        bitsPerComp = 8;
    }
    SkRefPtr<SkPDFInt> bitsPerCompValue = new SkPDFInt(bitsPerComp);
    bitsPerCompValue->unref();  // SkRefPtr and new both took a reference.
    insert("BitsPerComponent", bitsPerCompValue.get());

    if (config == SkBitmap::kRGB_565_Config) {
        SkRefPtr<SkPDFInt> zeroVal = new SkPDFInt(0);
        zeroVal->unref();  // SkRefPtr and new both took a reference.
        SkRefPtr<SkPDFScalar> scale5Val = new SkPDFScalar(8.2258);  // 255/2^5-1
        scale5Val->unref();  // SkRefPtr and new both took a reference.
        SkRefPtr<SkPDFScalar> scale6Val = new SkPDFScalar(4.0476);  // 255/2^6-1
        scale6Val->unref();  // SkRefPtr and new both took a reference.
        SkRefPtr<SkPDFArray> decodeValue = new SkPDFArray();
        decodeValue->unref();  // SkRefPtr and new both took a reference.
        decodeValue->reserve(6);
        decodeValue->append(zeroVal.get());
        decodeValue->append(scale5Val.get());
        decodeValue->append(zeroVal.get());
        decodeValue->append(scale6Val.get());
        decodeValue->append(zeroVal.get());
        decodeValue->append(scale5Val.get());
        insert("Decode", decodeValue.get());
    }
}

SkPDFImage::~SkPDFImage() {}

void SkPDFImage::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
                             bool indirect) {
    if (indirect)
        return emitIndirectObject(stream, catalog);

    fStream->emitObject(stream, catalog, indirect);
}

size_t SkPDFImage::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    if (indirect)
        return getIndirectOutputSize(catalog);

    return fStream->getOutputSize(catalog, indirect);
}

void SkPDFImage::insert(SkPDFName* key, SkPDFObject* value) {
    fStream->insert(key, value);
}

void SkPDFImage::insert(const char key[], SkPDFObject* value) {
    fStream->insert(key, value);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

struct Node
{
	Node* left;
	Node* right;
	Node* p;
	int v;
};

Node* search(Node* tree, int value)
{
	Node* c = tree;
	while (c != nullptr && c->v != value)
	{
		if (value < c->v)
		{
			c = c->left;
		}
		else
		{
			c = c->right;
		}
	}

	return c;
}

Node* min(Node* tree)
{
	if (tree == nullptr)
	{
		return nullptr;
	}

	while (tree->left != nullptr)
	{
		tree = tree->left;
	}

	return tree;
}
Node* max(Node* tree)
{
	if (tree == nullptr)
	{
		return nullptr;
	}

	while (tree->right != nullptr)
	{
		tree = tree->right;
	}

	return tree;
}

Node* successor(Node* node)
{
	if (node == nullptr)
	{
		return nullptr;
	}

	Node* successor = node->right;
	if (successor != nullptr)
	{
		while (successor->left != nullptr)
		{
			successor = successor->left;
		}
	}
	else
	{
		successor = node->p;
		while (successor != nullptr && successor->right == node)
		{
			node = successor;
			successor = node->p;
		}
	}

	return successor;
}

void insert(Node** root, Node* newNode)
{
	if (newNode == nullptr)
	{
		return;
	}

	if (root == nullptr || *root == nullptr)
	{
		*root = newNode;
		newNode->p = nullptr;

		return;
	}

	Node* current = *root;
	Node* temp = current;

	while (current != nullptr)
	{
		temp = current;
		if (newNode->v < current->v)
		{
			current = current->left;
		}
		else
		{
			current = current->right;
		}
	};

	newNode->p = temp;
	if (newNode->v < temp->v)
	{
		temp->left = newNode;
	}
	else
	{
		temp->right = newNode;
	}
}

int main()
{
	Node* tree = nullptr;
	std::vector<int> input = { 15, 6, 18, 3, 7, 17, 20, 2, 4, 13, 9 };
	for (auto iter = input.begin(); iter != input.end(); ++iter)
	{
		Node* n = new Node();
		n->v = *iter;

		insert(&tree, n);
	}

	// Search
	Node* s = search(tree, 15);
	std::cout << "search result : " << s->v << std::endl;

	// Min
	Node* minNode = min(tree);
	std::cout << "min result : " << minNode->v << std::endl;

	// Max
	Node* maxNode = max(tree);
	std::cout << "max result : " << maxNode->v << std::endl;

	// Successor
	Node* successorNode = successor(s);
	std::cout << "successor of " << s->v << " is " << successorNode->v << std::endl;

	// Release allocated memories of the tree.
	Node* c = tree;
	Node* p = nullptr;
	while (c != nullptr)
	{
		p = c;
		if (c->left != nullptr)
		{
			c = c->left;
		}
		else if (c->right != nullptr)
		{
			c = c->right;
		}
		else
		{
			p = c->p;
			if (p == nullptr)
			{
				delete c;
				c = nullptr;
				continue;
			}

			if (c->v < p->v)
			{
				p->left = nullptr;
			}
			else
			{
				p->right = nullptr;
			}

			delete c;
			c = p;
		}
	}

	return 0;
}
<commit_msg>Fixed a bug for BST implementation.<commit_after>#include <iostream>
#include <vector>

struct Node
{
	Node* left;
	Node* right;
	Node* p;
	int v;
};

Node* search(Node* tree, int value)
{
	Node* c = tree;
	while (c != nullptr && c->v != value)
	{
		if (value < c->v)
		{
			c = c->left;
		}
		else
		{
			c = c->right;
		}
	}

	return c;
}

Node* min(Node* tree)
{
	if (tree == nullptr)
	{
		return nullptr;
	}

	while (tree->left != nullptr)
	{
		tree = tree->left;
	}

	return tree;
}
Node* max(Node* tree)
{
	if (tree == nullptr)
	{
		return nullptr;
	}

	while (tree->right != nullptr)
	{
		tree = tree->right;
	}

	return tree;
}

Node* successor(Node* node)
{
	if (node == nullptr)
	{
		return nullptr;
	}

	Node* successor = node->right;
	if (successor != nullptr)
	{
		while (successor->left != nullptr)
		{
			successor = successor->left;
		}
	}
	else
	{
		successor = node->p;
		while (successor != nullptr && successor->right == node)
		{
			node = successor;
			successor = node->p;
		}
	}

	return successor;
}

void insert(Node** root, Node* newNode)
{
	if (newNode == nullptr || root == nullptr)
	{
		return;
	}

	if (*root == nullptr)
	{
		*root = newNode;
		newNode->p = nullptr;

		return;
	}

	Node* current = *root;
	Node* temp = current;

	while (current != nullptr)
	{
		temp = current;
		if (newNode->v < current->v)
		{
			current = current->left;
		}
		else
		{
			current = current->right;
		}
	};

	newNode->p = temp;
	if (newNode->v < temp->v)
	{
		temp->left = newNode;
	}
	else
	{
		temp->right = newNode;
	}
}

int main()
{
	Node* tree = nullptr;
	std::vector<int> input = { 15, 6, 18, 3, 7, 17, 20, 2, 4, 13, 9 };
	for (auto iter = input.begin(); iter != input.end(); ++iter)
	{
		Node* n = new Node();
		n->v = *iter;

		insert(&tree, n);
	}

	// Search
	Node* s = search(tree, 15);
	std::cout << "search result : " << s->v << std::endl;

	// Min
	Node* minNode = min(tree);
	std::cout << "min result : " << minNode->v << std::endl;

	// Max
	Node* maxNode = max(tree);
	std::cout << "max result : " << maxNode->v << std::endl;

	// Successor
	Node* successorNode = successor(s);
	std::cout << "successor of " << s->v << " is " << successorNode->v << std::endl;

	// Release allocated memories of the tree.
	Node* c = tree;
	Node* p = nullptr;
	while (c != nullptr)
	{
		p = c;
		if (c->left != nullptr)
		{
			c = c->left;
		}
		else if (c->right != nullptr)
		{
			c = c->right;
		}
		else
		{
			p = c->p;
			if (p == nullptr)
			{
				delete c;
				c = nullptr;
				continue;
			}

			if (c->v < p->v)
			{
				p->left = nullptr;
			}
			else
			{
				p->right = nullptr;
			}

			delete c;
			c = p;
		}
	}

	return 0;
}
<|endoftext|>


<commit_before>#include "phase_unfolder.hpp"

#include <iostream>
#include <map>

namespace vg {

PhaseUnfolder::PhaseUnfolder(const xg::XG& xg_index, const gbwt::GBWT& gbwt_index, vg::id_t next_node) :
    xg_index(xg_index), gbwt_index(gbwt_index), mapping(next_node) {
}

void PhaseUnfolder::unfold(VG& graph, bool show_progress) {
    std::list<VG> components = this->complement_components(graph, show_progress);

    size_t haplotype_paths = 0;
    VG unfolded;
    for (VG& component : components) {
        haplotype_paths += this->unfold_component(component, graph, unfolded);
    }
    if (show_progress) {
        std::cerr << "Unfolded graph: "
                  << unfolded.node_count() << " nodes, " << unfolded.edge_count() << " edges on "
                  << haplotype_paths << " paths" << std::endl;
    }

    graph.extend(unfolded);
}

void PhaseUnfolder::write_mapping(const std::string& filename) const {
    std::ofstream out(filename, std::ios_base::binary);
    if (!out) {
        std::cerr << "[PhaseUnfolder]: cannot create mapping file " << filename << std::endl;
        return;
    }
    this->mapping.serialize(out);
    out.close();
}

void PhaseUnfolder::read_mapping(const std::string& filename) {
    std::ifstream in(filename, std::ios_base::binary);
    if (!in) {
        std::cerr << "[PhaseUnfolder]: cannot open mapping file " << filename << std::endl;
        return;
    }
    this->mapping.load(in);
    in.close();
}

vg::id_t PhaseUnfolder::get_mapping(vg::id_t node) const {
    return this->mapping(node);
}

std::list<VG> PhaseUnfolder::complement_components(VG& graph, bool show_progress) {
    VG complement;

    // Add missing edges supported by XG paths.
    for (size_t path_rank = 1; path_rank <= this->xg_index.max_path_rank(); path_rank++) {
        const xg::XGPath& path = this->xg_index.get_path(this->xg_index.path_name(path_rank));
        size_t path_length = path.ids.size();
        if (path_length == 0) {
            continue;
        }
        gbwt::node_type prev = gbwt::Node::encode(path.node(0), path.is_reverse(0));
        for (size_t i = 1; i < path_length; i++) {
            gbwt::node_type curr = gbwt::Node::encode(path.node(i), path.is_reverse(i));
            Edge candidate = xg::make_edge(gbwt::Node::id(prev), gbwt::Node::is_reverse(prev),
                                           gbwt::Node::id(curr), gbwt::Node::is_reverse(curr));
            if (!graph.has_edge(candidate)) {
                complement.add_node(this->xg_index.node(candidate.from()));
                complement.add_node(this->xg_index.node(candidate.to()));
                complement.add_edge(candidate);
            }
            prev = curr;
        }
    }

    // Add missing edges supported by GBWT threads.
    for (gbwt::comp_type comp = 1; comp < this->gbwt_index.effective(); comp++) {
        gbwt::node_type gbwt_node = this->gbwt_index.toNode(comp);
        std::vector<gbwt::edge_type> outgoing = this->gbwt_index.edges(gbwt_node);
        for (gbwt::edge_type outedge : outgoing) {
            if (outedge.first == gbwt::ENDMARKER) {
                continue;
            }
            Edge candidate = xg::make_edge(gbwt::Node::id(gbwt_node), gbwt::Node::is_reverse(gbwt_node),
                                           gbwt::Node::id(outedge.first), gbwt::Node::is_reverse(outedge.first));
            if (!graph.has_edge(candidate)) {
                complement.add_node(this->xg_index.node(candidate.from()));
                complement.add_node(this->xg_index.node(candidate.to()));
                complement.add_edge(candidate);
            }
        }
    }

    std::list<VG> components;
    complement.disjoint_subgraphs(components);
    if (show_progress) {
        std::cerr << "Complement graph: "
                  << complement.node_count() << " nodes, " << complement.edge_count() << " edges in "
                  << components.size() << " components" << std::endl;
    }
    return components;
}

size_t PhaseUnfolder::unfold_component(VG& component, VG& graph, VG& unfolded) {
    // Find the border nodes shared between the component and the graph.
    component.for_each_node([&](Node* node) {
       if (graph.has_node(node->id())) {
           this->border.insert(node->id());
       }
    });

    // Generate the paths starting from each border node.
    for (vg::id_t start_node : this->border) {
        this->generate_paths(component, start_node);
        this->generate_threads(component, start_node);
    }
    size_t haplotype_paths = this->paths.size();

    // Unfold the generated paths. We merge duplicated nodes by shared
    // prefixes in the first half of the path and by shared suffixes in
    // the second half. Needless duplication would otherwise make GCSA2
    // index construction too expensive.
    std::map<path_type, vg::id_t> node_by_prefix, node_by_suffix;
    for (const path_type& path : this->paths) {
        Node prev = this->xg_index.node(gbwt::Node::id(path.front()));
        unfolded.add_node(prev);
        for (size_t i = 1; i < path.size(); i++) {
            Node curr = this->xg_index.node(gbwt::Node::id(path[i]));
            bool is_prefix = (i < (path.size() + 1) / 2);
            bool is_suffix = !is_prefix & (i + 1 < path.size());
            if (is_prefix) {
                auto iter = node_by_prefix.emplace(path_type(path.begin(), path.begin() + i + 1), 0).first;
                if (iter->second == 0) {      // No cached node with the same prefix.
                    iter->second = this->mapping.insert(curr.id());
                }
                curr.set_id(iter->second);
            } else if (is_suffix) {
                auto iter = node_by_suffix.emplace(path_type(path.begin() + i, path.end()), 0).first;
                if (iter->second == 0) {      // No cached node with the same suffix.
                    iter->second = this->mapping.insert(curr.id());
                }
                curr.set_id(iter->second);
            }
            unfolded.add_node(curr);
            Edge edge = xg::make_edge(prev.id(), gbwt::Node::is_reverse(path[i - 1]),
                                      curr.id(), gbwt::Node::is_reverse(path[i]));
            unfolded.add_edge(edge);
            prev = curr;
        }
    }

    this->border.clear();
    this->paths.clear();
    return haplotype_paths;
}

// TODO: Also generate paths backwards.
void PhaseUnfolder::generate_paths(VG& component, vg::id_t from) {
    static int component_id = 0;
    for (size_t path_rank = 1; path_rank <= this->xg_index.max_path_rank(); path_rank++) {
        const xg::XGPath& path = this->xg_index.get_path(this->xg_index.path_name(path_rank));
        size_t path_length = path.ids.size();

        std::vector<size_t> occurrences = this->xg_index.node_ranks_in_path(from, path_rank);
        for (size_t occurrence : occurrences) {
            gbwt::node_type prev = gbwt::Node::encode(path.node(occurrence), path.is_reverse(occurrence));
            path_type buffer { prev };
            bool found_border = false;
            for (size_t i = occurrence + 1; i < path_length; i++) {
                gbwt::node_type curr = gbwt::Node::encode(path.node(i), path.is_reverse(i));
                Edge candidate = xg::make_edge(gbwt::Node::id(prev), gbwt::Node::is_reverse(prev),
                                               gbwt::Node::id(curr), gbwt::Node::is_reverse(curr));
                if (!component.has_edge(candidate)) {
                    break;
                }
                buffer.push_back(curr);
                if (this->border.find(gbwt::Node::id(curr)) != this->border.end()) {
                    this->insert_path(buffer);  // Insert a border-to-border path.
                    found_border = true;
                    break;
                }
                prev = curr;
            }
            if (!found_border) {
                this->insert_path(buffer);  // Insert a maximal path.
            }
        }
    }
}

void PhaseUnfolder::generate_threads(VG& component, vg::id_t from) {
    this->create_state(from, false);
    this->create_state(from, true);

    while (!this->states.empty()) {
        state_type state = this->states.top(); this->states.pop();
        vg::id_t node = gbwt::Node::id(state.second.back());
        bool is_reverse = gbwt::Node::is_reverse(state.second.back());

        std::vector<Edge*> edges = component.edges_of(component.get_node(node));
        bool was_extended = false;
        for (Edge* edge : edges) {
            if (edge->from() == node && edge->from_start() == is_reverse) {
                was_extended = this->extend_state(state, edge->to(), edge->to_end());
            }
            else if (edge->to() == node && edge->to_end() != is_reverse) {
                was_extended = this->extend_state(state, edge->from(), !edge->from_start());
            }
        }

        if (!was_extended || this->border.find(node) != this->border.end()) {
            this->insert_path(state.second);
        }
    }
}

void PhaseUnfolder::create_state(vg::id_t node, bool is_reverse) {
    search_type search = this->gbwt_index.find(gbwt::Node::encode(node, is_reverse));
    if (search.empty()) {
        return;
    }
    this->states.push(std::make_pair(search, path_type {search.node}));
}

bool PhaseUnfolder::extend_state(state_type state, vg::id_t node, bool is_reverse) {
    state.first = this->gbwt_index.extend(state.first, gbwt::Node::encode(node, is_reverse));
    if (state.first.empty()) {
        return false;
    }
    state.second.push_back(state.first.node);
    this->states.push(state);
    return true;
}

void PhaseUnfolder::insert_path(const path_type& path) {
    if (path.size() < 2) {
        return;
    }
    path_type reverse_complement(path.size(), 0);
    for (size_t i = 0; i < path.size(); i++) {
        reverse_complement[path.size() - 1 - i] = gbwt::Node::reverse(path[i]);
    }
    this->paths.insert(std::min(path, reverse_complement));
}

}
<commit_msg>Also unfold the reverse reference<commit_after>#include "phase_unfolder.hpp"

#include <iostream>
#include <map>

namespace vg {

PhaseUnfolder::PhaseUnfolder(const xg::XG& xg_index, const gbwt::GBWT& gbwt_index, vg::id_t next_node) :
    xg_index(xg_index), gbwt_index(gbwt_index), mapping(next_node) {
}

void PhaseUnfolder::unfold(VG& graph, bool show_progress) {
    std::list<VG> components = this->complement_components(graph, show_progress);

    size_t haplotype_paths = 0;
    VG unfolded;
    for (VG& component : components) {
        haplotype_paths += this->unfold_component(component, graph, unfolded);
    }
    if (show_progress) {
        std::cerr << "Unfolded graph: "
                  << unfolded.node_count() << " nodes, " << unfolded.edge_count() << " edges on "
                  << haplotype_paths << " paths" << std::endl;
    }

    graph.extend(unfolded);
}

void PhaseUnfolder::write_mapping(const std::string& filename) const {
    std::ofstream out(filename, std::ios_base::binary);
    if (!out) {
        std::cerr << "[PhaseUnfolder]: cannot create mapping file " << filename << std::endl;
        return;
    }
    this->mapping.serialize(out);
    out.close();
}

void PhaseUnfolder::read_mapping(const std::string& filename) {
    std::ifstream in(filename, std::ios_base::binary);
    if (!in) {
        std::cerr << "[PhaseUnfolder]: cannot open mapping file " << filename << std::endl;
        return;
    }
    this->mapping.load(in);
    in.close();
}

vg::id_t PhaseUnfolder::get_mapping(vg::id_t node) const {
    return this->mapping(node);
}

std::list<VG> PhaseUnfolder::complement_components(VG& graph, bool show_progress) {
    VG complement;

    // Add missing edges supported by XG paths.
    for (size_t path_rank = 1; path_rank <= this->xg_index.max_path_rank(); path_rank++) {
        const xg::XGPath& path = this->xg_index.get_path(this->xg_index.path_name(path_rank));
        size_t path_length = path.ids.size();
        if (path_length == 0) {
            continue;
        }
        gbwt::node_type prev = gbwt::Node::encode(path.node(0), path.is_reverse(0));
        for (size_t i = 1; i < path_length; i++) {
            gbwt::node_type curr = gbwt::Node::encode(path.node(i), path.is_reverse(i));
            Edge candidate = xg::make_edge(gbwt::Node::id(prev), gbwt::Node::is_reverse(prev),
                                           gbwt::Node::id(curr), gbwt::Node::is_reverse(curr));
            if (!graph.has_edge(candidate)) {
                complement.add_node(this->xg_index.node(candidate.from()));
                complement.add_node(this->xg_index.node(candidate.to()));
                complement.add_edge(candidate);
            }
            prev = curr;
        }
    }

    // Add missing edges supported by GBWT threads.
    for (gbwt::comp_type comp = 1; comp < this->gbwt_index.effective(); comp++) {
        gbwt::node_type gbwt_node = this->gbwt_index.toNode(comp);
        std::vector<gbwt::edge_type> outgoing = this->gbwt_index.edges(gbwt_node);
        for (gbwt::edge_type outedge : outgoing) {
            if (outedge.first == gbwt::ENDMARKER) {
                continue;
            }
            Edge candidate = xg::make_edge(gbwt::Node::id(gbwt_node), gbwt::Node::is_reverse(gbwt_node),
                                           gbwt::Node::id(outedge.first), gbwt::Node::is_reverse(outedge.first));
            if (!graph.has_edge(candidate)) {
                complement.add_node(this->xg_index.node(candidate.from()));
                complement.add_node(this->xg_index.node(candidate.to()));
                complement.add_edge(candidate);
            }
        }
    }

    std::list<VG> components;
    complement.disjoint_subgraphs(components);
    if (show_progress) {
        std::cerr << "Complement graph: "
                  << complement.node_count() << " nodes, " << complement.edge_count() << " edges in "
                  << components.size() << " components" << std::endl;
    }
    return components;
}

size_t PhaseUnfolder::unfold_component(VG& component, VG& graph, VG& unfolded) {
    // Find the border nodes shared between the component and the graph.
    component.for_each_node([&](Node* node) {
       if (graph.has_node(node->id())) {
           this->border.insert(node->id());
       }
    });

    // Generate the paths starting from each border node.
    for (vg::id_t start_node : this->border) {
        this->generate_paths(component, start_node);
        this->generate_threads(component, start_node);
    }
    size_t haplotype_paths = this->paths.size();

    // Unfold the generated paths. We merge duplicated nodes by shared
    // prefixes in the first half of the path and by shared suffixes in
    // the second half. Needless duplication would otherwise make GCSA2
    // index construction too expensive.
    std::map<path_type, vg::id_t> node_by_prefix, node_by_suffix;
    for (const path_type& path : this->paths) {
        Node prev = this->xg_index.node(gbwt::Node::id(path.front()));
        unfolded.add_node(prev);
        for (size_t i = 1; i < path.size(); i++) {
            Node curr = this->xg_index.node(gbwt::Node::id(path[i]));
            bool is_prefix = (i < (path.size() + 1) / 2);
            bool is_suffix = !is_prefix & (i + 1 < path.size());
            if (is_prefix) {
                auto iter = node_by_prefix.emplace(path_type(path.begin(), path.begin() + i + 1), 0).first;
                if (iter->second == 0) {      // No cached node with the same prefix.
                    iter->second = this->mapping.insert(curr.id());
                }
                curr.set_id(iter->second);
            } else if (is_suffix) {
                auto iter = node_by_suffix.emplace(path_type(path.begin() + i, path.end()), 0).first;
                if (iter->second == 0) {      // No cached node with the same suffix.
                    iter->second = this->mapping.insert(curr.id());
                }
                curr.set_id(iter->second);
            }
            unfolded.add_node(curr);
            Edge edge = xg::make_edge(prev.id(), gbwt::Node::is_reverse(path[i - 1]),
                                      curr.id(), gbwt::Node::is_reverse(path[i]));
            unfolded.add_edge(edge);
            prev = curr;
        }
    }

    this->border.clear();
    this->paths.clear();
    return haplotype_paths;
}

void PhaseUnfolder::generate_paths(VG& component, vg::id_t from) {
    static int component_id = 0;
    for (size_t path_rank = 1; path_rank <= this->xg_index.max_path_rank(); path_rank++) {
        const xg::XGPath& path = this->xg_index.get_path(this->xg_index.path_name(path_rank));
        size_t path_length = path.ids.size();

        std::vector<size_t> occurrences = this->xg_index.node_ranks_in_path(from, path_rank);
        for (size_t occurrence : occurrences) {
            // Forward.
            {
                gbwt::node_type prev = gbwt::Node::encode(path.node(occurrence), path.is_reverse(occurrence));
                path_type buffer { prev };
                for (size_t i = occurrence + 1; i < path_length; i++) {
                    gbwt::node_type curr = gbwt::Node::encode(path.node(i), path.is_reverse(i));
                    Edge candidate = xg::make_edge(gbwt::Node::id(prev), gbwt::Node::is_reverse(prev),
                                                   gbwt::Node::id(curr), gbwt::Node::is_reverse(curr));
                    if (!component.has_edge(candidate)) {
                        break;  // Found a maximal path.
                    }
                    buffer.push_back(curr);
                    if (this->border.find(gbwt::Node::id(curr)) != this->border.end()) {
                        break;  // Found a border-to-border path.
                    }
                    prev = curr;
                }
                this->insert_path(buffer);
            }

            // Backward.
            {
                gbwt::node_type prev = gbwt::Node::encode(path.node(occurrence), !path.is_reverse(occurrence));
                path_type buffer { prev };
                bool found_border = false;
                for (size_t i = occurrence; i > 0 ; i--) {
                    gbwt::node_type curr = gbwt::Node::encode(path.node(i - 1), !path.is_reverse(i - 1));
                    Edge candidate = xg::make_edge(gbwt::Node::id(prev), gbwt::Node::is_reverse(prev),
                                                   gbwt::Node::id(curr), gbwt::Node::is_reverse(curr));
                    if (!component.has_edge(candidate)) {
                        break;  // Found a maximal path.
                    }
                    buffer.push_back(curr);
                    if (this->border.find(gbwt::Node::id(curr)) != this->border.end()) {
                        break;  // Found a border-to-border path.
                    }
                    prev = curr;
                }
                this->insert_path(buffer);
            }
        }
    }
}

void PhaseUnfolder::generate_threads(VG& component, vg::id_t from) {
    this->create_state(from, false);
    this->create_state(from, true);

    while (!this->states.empty()) {
        state_type state = this->states.top(); this->states.pop();
        vg::id_t node = gbwt::Node::id(state.second.back());
        bool is_reverse = gbwt::Node::is_reverse(state.second.back());

        std::vector<Edge*> edges = component.edges_of(component.get_node(node));
        bool was_extended = false;
        for (Edge* edge : edges) {
            if (edge->from() == node && edge->from_start() == is_reverse) {
                was_extended = this->extend_state(state, edge->to(), edge->to_end());
            }
            else if (edge->to() == node && edge->to_end() != is_reverse) {
                was_extended = this->extend_state(state, edge->from(), !edge->from_start());
            }
        }

        if (!was_extended || this->border.find(node) != this->border.end()) {
            this->insert_path(state.second);
        }
    }
}

void PhaseUnfolder::create_state(vg::id_t node, bool is_reverse) {
    search_type search = this->gbwt_index.find(gbwt::Node::encode(node, is_reverse));
    if (search.empty()) {
        return;
    }
    this->states.push(std::make_pair(search, path_type {search.node}));
}

bool PhaseUnfolder::extend_state(state_type state, vg::id_t node, bool is_reverse) {
    state.first = this->gbwt_index.extend(state.first, gbwt::Node::encode(node, is_reverse));
    if (state.first.empty()) {
        return false;
    }
    state.second.push_back(state.first.node);
    this->states.push(state);
    return true;
}

void PhaseUnfolder::insert_path(const path_type& path) {
    if (path.size() < 2) {
        return;
    }
    path_type reverse_complement(path.size(), 0);
    for (size_t i = 0; i < path.size(); i++) {
        reverse_complement[path.size() - 1 - i] = gbwt::Node::reverse(path[i]);
    }
    this->paths.insert(std::min(path, reverse_complement));
}

}
<|endoftext|>


<commit_before>#include <unordered_map>
#include <string>
#include "imgui.h"
#include "app_config.h"
#include "console_log.h"

typedef void(*PFN_EXECUTE_COMMAND)(const std::string &);

class CGuiConsole
{
public:
	static inline CGuiConsole& singleton()
	{
		static CGuiConsole s_console;
		return s_console;
	}

	void draw()
	{
		ImGui::SetNextWindowSize(ImVec2(m_width, m_height), ImGuiCond_Always);
		if (!ImGui::Begin("console", 0, m_flags))
		{
			ImGui::End();
			return;
		}

		const auto &style = ImGui::GetStyle();
		float progress_bar_height = 4;
		ImGui::SetCursorPosX(style.WindowPadding.x * 0.5f);
		ImGui::ProgressBar(0, ImVec2(ImGui::GetWindowWidth() - style.WindowPadding.x, progress_bar_height), "");
		ImGui::Separator();

		// BEGIN log
		ImGui::BeginChild("console_log", ImVec2(0, -ImGui::GetItemsLineHeightWithSpacing() - progress_bar_height - style.ItemSpacing.y),
			false, ImGuiWindowFlags_HorizontalScrollbar);
		CConsoleLogger *logger = LOGGER_GET(CConsoleLogger);
		for (auto &str : *logger) {
			draw_log(str);
		}
		ImGui::EndChild(); // END log

		// BEGIN input
		ImGui::Separator();
		ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
		if (ImGui::InputText("", m_input_beg, m_input_max, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory,
			[] (ImGuiTextEditCallbackData *ctx) -> int {
			((CGuiConsole*)ctx)->on_input_end();
			return 0;
		}, (void*)this))
		{
			if (!m_input_beg[0])
				return;
			logger->output(m_input_buf);
			std::string cmd_name = strtok(m_input_beg, " ");
			if (cmd_name == "help")
			{
				for (auto &it : m_commands)
					log_info("- %s\t\t%s", it.first.c_str(), it.second.second.c_str());
				log_info("- help\t\tshow help");
			}
			else {
				auto iter = m_commands.find(cmd_name);
				if (iter == m_commands.end())
					log_error("Unkonwn command");
				else
					iter->second.first(m_input_beg + cmd_name.size() + 1);
			}
			m_input_beg[0] = 0;
		}
		ImGui::PopItemWidth();

		 // Demonstrate keeping auto focus on the input box
		if (ImGui::IsItemHovered() || (ImGui::IsRootWindowOrAnyChildFocused() && !ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0)))
			ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
		// END input

		ImGui::End(); // END console
	}

	void on_input_end()
	{
	}

	void draw_log(const std::string &str)
	{
		static const std::pair<std::string, ImVec4> s_tag_color[] = {
			std::make_pair(std::string("# "), ImVec4(0.0f, 1.0f, 0.0f, 1.0f)),
			std::make_pair(std::string("[ERROR]") , ImVec4(1.0f, 0.4f, 0.4f, 1.0f)),
			std::make_pair(std::string("[WARNING]"), ImVec4(1.0f, 1.0f, 0.0f, 1.0f)),
		};
		for (auto &tag : s_tag_color) {
			if (!str.compare(0, tag.first.size(), tag.first)) {
				ImGui::PushStyleColor(ImGuiCol_Text, tag.second);
				ImGui::TextUnformatted(str.c_str());
				ImGui::PopStyleColor();
				return;
			}
		}
		ImGui::TextUnformatted(str.c_str());
	}

	bool add_command(const char *cmd_name, PFN_EXECUTE_COMMAND func, const char *desc)
	{
		if (!func || !cmd_name || *cmd_name == 0)
			return false;
		auto &ret = m_commands.emplace(std::make_pair(cmd_name, std::make_pair(func, desc)));
		if (!ret.second)
			return false;
		return true;
	}

private:
	int m_width, m_height;
	ImGuiWindowFlags m_flags;
	static constexpr size_t INPUT_BUFF_SIZE = 256;
	char m_input_buf[INPUT_BUFF_SIZE];
	char *m_input_beg;
	size_t m_input_max;
	std::unordered_map<std::string, std::pair<PFN_EXECUTE_COMMAND, std::string>> m_commands;

	CGuiConsole()
	{
		m_width = int(AppConfig::window_width * 0.382f), m_height = int(AppConfig::window_height);
		m_flags = ImGuiWindowFlags_NoResize
			| ImGuiWindowFlags_NoMove
			| ImGuiWindowFlags_ShowBorders;
		const char *prompt = "# ";
		size_t prompt_len = strlen(prompt);
		strncpy(m_input_buf, prompt, INPUT_BUFF_SIZE);
		m_input_beg = m_input_buf + prompt_len;
		m_input_max = INPUT_BUFF_SIZE - prompt_len;
	}
};

bool console_command(const char *cmd_name, PFN_EXECUTE_COMMAND func, const char *desc)
{
	auto &console = CGuiConsole::singleton();
	return console.add_command(cmd_name, func, desc);
}

void show_console()
{
	auto &console = CGuiConsole::singleton();
	console.draw();
}
<commit_msg>fix bugs<commit_after>#include <unordered_map>
#include <string>
#include "imgui.h"
#include "app_config.h"
#include "console_log.h"

typedef void(*PFN_EXECUTE_COMMAND)(const std::string &);

class CGuiConsole
{
public:
	static inline CGuiConsole& singleton()
	{
		static CGuiConsole s_console;
		return s_console;
	}

	void draw()
	{
		ImGui::SetNextWindowSize(ImVec2(m_width, m_height), ImGuiCond_Always);
		if (!ImGui::Begin("console", 0, m_flags))
		{
			ImGui::End();
			return;
		}

		const auto &style = ImGui::GetStyle();
		float progress_bar_height = 4;
		ImGui::SetCursorPosX(style.WindowPadding.x * 0.5f);
		ImGui::ProgressBar(0, ImVec2(ImGui::GetWindowWidth() - style.WindowPadding.x, progress_bar_height), "");
		ImGui::Separator();

		// BEGIN log
		ImGui::BeginChild("console_log", ImVec2(0, -ImGui::GetItemsLineHeightWithSpacing() - progress_bar_height - style.ItemSpacing.y),
			false, ImGuiWindowFlags_HorizontalScrollbar);
		CConsoleLogger *logger = LOGGER_GET(CConsoleLogger);
		for (auto &str : *logger) {
			draw_log(str);
		}
		ImGui::EndChild(); // END log

		// BEGIN input
		ImGui::Separator();
		ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
		if (ImGui::InputText("", m_input_beg, m_input_max, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory,
			[] (ImGuiTextEditCallbackData *ctx) -> int {
			((CGuiConsole*)ctx)->on_input_end();
			return 0;
		}, (void*)this))
		{
			if (m_input_beg[0]) {
				logger->output(m_input_buf);
				process_input();
			}
			m_input_beg[0] = 0;
		}
		ImGui::PopItemWidth();

		 // Demonstrate keeping auto focus on the input box
		if (ImGui::IsItemHovered() || (ImGui::IsRootWindowOrAnyChildFocused() && !ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0)))
			ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
		// END input

		ImGui::End(); // END console
	}

	void on_input_end()
	{
	}

	void process_input()
	{
		std::string cmd_name = strtok(m_input_beg, " ");
		if (cmd_name == "help")
		{
			for (auto &it : m_commands)
				log_info("- %s\t\t%s", it.first.c_str(), it.second.second.c_str());
			log_info("- help\t\tshow help");
			return;
		}
		auto iter = m_commands.find(cmd_name);
		if (iter == m_commands.end()) {
			log_error("Unkonwn command");
			return;
		}
		iter->second.first(m_input_beg + cmd_name.size() + 1);
	}

	void draw_log(const std::string &str)
	{
		static const std::pair<std::string, ImVec4> s_tag_color[] = {
			std::make_pair(std::string("# "), ImVec4(0.0f, 1.0f, 0.0f, 1.0f)),
			std::make_pair(std::string("[ERROR]") , ImVec4(1.0f, 0.4f, 0.4f, 1.0f)),
			std::make_pair(std::string("[WARNING]"), ImVec4(1.0f, 1.0f, 0.0f, 1.0f)),
		};
		for (auto &tag : s_tag_color) {
			if (!str.compare(0, tag.first.size(), tag.first)) {
				ImGui::PushStyleColor(ImGuiCol_Text, tag.second);
				ImGui::TextUnformatted(str.c_str());
				ImGui::PopStyleColor();
				return;
			}
		}
		ImGui::TextUnformatted(str.c_str());
	}

	bool add_command(const char *cmd_name, PFN_EXECUTE_COMMAND func, const char *desc)
	{
		if (!func || !cmd_name || *cmd_name == 0)
			return false;
		auto &ret = m_commands.emplace(std::make_pair(cmd_name, std::make_pair(func, desc)));
		if (!ret.second)
			return false;
		return true;
	}

private:
	int m_width, m_height;
	ImGuiWindowFlags m_flags;
	static constexpr size_t INPUT_BUFF_SIZE = 256;
	char m_input_buf[INPUT_BUFF_SIZE];
	char *m_input_beg;
	size_t m_input_max;
	std::unordered_map<std::string, std::pair<PFN_EXECUTE_COMMAND, std::string>> m_commands;

	CGuiConsole()
	{
		m_width = int(AppConfig::window_width * 0.382f), m_height = int(AppConfig::window_height);
		m_flags = ImGuiWindowFlags_NoResize
			| ImGuiWindowFlags_NoMove
			| ImGuiWindowFlags_ShowBorders;
		const char *prompt = "# ";
		size_t prompt_len = strlen(prompt);
		strncpy(m_input_buf, prompt, INPUT_BUFF_SIZE);
		m_input_beg = m_input_buf + prompt_len;
		m_input_max = INPUT_BUFF_SIZE - prompt_len;
	}
};

bool console_command(const char *cmd_name, PFN_EXECUTE_COMMAND func, const char *desc)
{
	auto &console = CGuiConsole::singleton();
	return console.add_command(cmd_name, func, desc);
}

void show_console()
{
	auto &console = CGuiConsole::singleton();
	console.draw();
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2004 David Faure <faure@kde.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of this program with any edition of
 *  the Qt library by Trolltech AS, Norway (or with modified versions
 *  of Qt that use the same license as Qt), and distribute linked
 *  combinations including the two.  You must obey the GNU General
 *  Public License in all respects for all of the code used other than
 *  Qt.  If you modify this file, you may extend this exception to
 *  your version of the file, but you are not obligated to do so.  If
 *  you do not wish to do so, delete this exception statement from
 *  your version.
 */

#include "compactionjob.h"
#include "kmfolder.h"
#include "broadcaststatus.h"
using KPIM::BroadcastStatus;
#include "kmfoldermbox.h"
#include "kmfoldermaildir.h"

#include <kdebug.h>
#include <klocale.h>

#include <QFile>
#include <QFileInfo>
#include <QDir>

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

using namespace KMail;

// Look at this number of messages in each slotDoWork call
#define COMPACTIONJOB_NRMESSAGES 100
// And wait this number of milliseconds before calling it again
#define COMPACTIONJOB_TIMERINTERVAL 100

MboxCompactionJob::MboxCompactionJob( KMFolder* folder, bool immediate )
 : ScheduledJob( folder, immediate ), mTimer( this ), mTmpFile( 0 ),
   mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false )
{
}

MboxCompactionJob::~MboxCompactionJob()
{
}

void MboxCompactionJob::kill()
{
  Q_ASSERT( mCancellable );
  // We must close the folder if we opened it and got interrupted
  if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() ) {
    mSrcFolder->storage()->close( "mboxcompact" );
  }

  if ( mTmpFile ) {
    fclose( mTmpFile );
  }
  mTmpFile = 0;
  if ( !mTempName.isEmpty() ) {
    QFile::remove( mTempName );
  }
  FolderJob::kill();
}

QString MboxCompactionJob::realLocation() const
{
  QString location = mSrcFolder->location();
  QFileInfo inf( location );
  if (inf.isSymLink()) {
    KUrl u; u.setPath( location );
    // follow (and resolve) symlinks so that the final ::rename() always works
    // KUrl gives us support for absolute and relative links transparently.
    return KUrl( u, inf.readLink() ).path();
  }
  return location;
}

int MboxCompactionJob::executeNow( bool silent )
{
  mSilent = silent;
  FolderStorage *storage = mSrcFolder->storage();
  KMFolderMbox *mbox = static_cast<KMFolderMbox *>( storage );
  if ( !storage->compactable() ) {
    kDebug(5006) << storage->location() <<" compaction skipped.";
    if ( !mSilent ) {
      QString str = i18n( "For safety reasons, compaction has been disabled for %1", mbox->label() );
      BroadcastStatus::instance()->setStatusMsg( str );
    }
    return 0;
  }
  kDebug(5006) <<"Compacting" << mSrcFolder->idString();

  if ( KMFolderIndex::IndexOk != mbox->indexStatus() ) {
    kDebug(5006) <<"Critical error:" << storage->location()
                 << "has been modified by an external application while KMail was running.";
    //      exit(1); backed out due to broken nfs
  }

  const QFileInfo pathInfo( realLocation() );
  // Use /dir/.mailboxname.compacted so that it's hidden, and doesn't show up after restarting kmail
  // (e.g. due to an unfortunate crash while compaction is happening)
  mTempName = pathInfo.path() + "/." + pathInfo.fileName() + ".compacted";

  mode_t old_umask = umask( 077 );
  mTmpFile = fopen( QFile::encodeName( mTempName ), "w" );
  umask( old_umask );
  if (!mTmpFile) {
    kWarning(5006) <<"Couldn't start compacting" << mSrcFolder->label()
                   << ":" << strerror( errno )
                   << "while creating" << mTempName;
    return errno;
  }
  mOpeningFolder = true; // Ignore open-notifications while opening the folder
  storage->open( "mboxcompact" );
  mOpeningFolder = false;
  mFolderOpen = true;
  mOffset = 0;
  mCurrentIndex = 0;

  kDebug(5006) <<"MboxCompactionJob: starting to compact folder"
               << mSrcFolder->location() << "into" << mTempName;
  connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) );
  if ( !mImmediate ) {
    mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
  }
  slotDoWork();
  return mErrorCode;
}

void MboxCompactionJob::slotDoWork()
{
  // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
  KMFolderMbox *mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
  bool bDone = false;
  int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES;
  int rc = mbox->compact( mCurrentIndex, nbMessages,
                          mTmpFile, mOffset /*in-out*/, bDone /*out*/ );
  if ( !mImmediate )
    mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
  if ( rc || bDone ) // error, or finished
    done( rc );
}

void MboxCompactionJob::done( int rc )
{
  mTimer.stop();
  mCancellable = false;
  KMFolderMbox *mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
  if ( !rc ) {
    rc = fflush( mTmpFile );
  }
  if ( !rc ) {
    rc = fsync( fileno( mTmpFile ) );
  }
  rc |= fclose( mTmpFile );
  QString str;
  if ( !rc ) {
    bool autoCreate = mbox->autoCreateIndex();
    QString box( realLocation() );
    ::rename( QFile::encodeName( mTempName ), QFile::encodeName( box ) );
    mbox->writeIndex();
    mbox->writeConfig();
    mbox->setAutoCreateIndex( false );
    mbox->close( "mboxcompact", true );
    mbox->setAutoCreateIndex( autoCreate );
    mbox->setNeedsCompacting( false );            // We are clean now
    str = i18n( "Folder \"%1\" successfully compacted", mSrcFolder->label() );
    kDebug(5006) << str;
  } else {
    mbox->close( "mboxcompact" );
    str = i18n( "Error occurred while compacting \"%1\". Compaction aborted.", mSrcFolder->label() );
    kDebug(5006) <<"Error occurred while compacting" << mbox->location();
    kDebug(5006) <<"Compaction aborted.";
    QFile::remove( mTempName );
  }
  mErrorCode = rc;

  if ( !mSilent )
    BroadcastStatus::instance()->setStatusMsg( str );

  mFolderOpen = false;
  deleteLater(); // later, because of the "return mErrorCode"
}

////

MaildirCompactionJob::MaildirCompactionJob( KMFolder* folder, bool immediate )
 : ScheduledJob( folder, immediate ), mTimer( this ),
   mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false )
{
}

MaildirCompactionJob::~MaildirCompactionJob()
{
}

void MaildirCompactionJob::kill()
{
  Q_ASSERT( mCancellable );
  // We must close the folder if we opened it and got interrupted
  if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() ) {
    mSrcFolder->storage()->close( "maildircompact" );
  }

  FolderJob::kill();
}

int MaildirCompactionJob::executeNow( bool silent )
{
  mSilent = silent;
  KMFolderMaildir *storage =
    static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
  kDebug(5006) <<"Compacting" << mSrcFolder->idString();

  mOpeningFolder = true; // Ignore open-notifications while opening the folder
  storage->open( "maildircompact" );
  mOpeningFolder = false;
  mFolderOpen = true;
  QString subdirNew( storage->location() + "/new/" );
  QDir d( subdirNew );
  mEntryList = d.entryList();
  mCurrentIndex = 0;

  kDebug(5006) <<"MaildirCompactionJob: starting to compact in folder"
               << mSrcFolder->location();
  connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) );
  if ( !mImmediate ) {
    mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
  }
  slotDoWork();
  return mErrorCode;
}

void MaildirCompactionJob::slotDoWork()
{
  // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
  KMFolderMaildir *storage =
    static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
  bool bDone = false;
  int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES;
  int rc = storage->compact( mCurrentIndex, nbMessages, mEntryList, bDone /*out*/ );
  if ( !mImmediate )
    mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
  if ( rc || bDone ) // error, or finished
    done( rc );
}

void MaildirCompactionJob::done( int rc )
{
  KMFolderMaildir *storage =
    static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
  mTimer.stop();
  mCancellable = false;
  QString str;
  if ( !rc ) {
    str = i18n( "Folder \"%1\" successfully compacted", mSrcFolder->label() );
  } else {
    str = i18n( "Error occurred while compacting \"%1\". Compaction aborted.", mSrcFolder->label() );
  }
  mErrorCode = rc;
  storage->setNeedsCompacting( false );
  storage->close( "maildircompact" );
  if ( storage->isOpened() ) {
    storage->updateIndex();
  }
  if ( !mSilent ) {
    BroadcastStatus::instance()->setStatusMsg( str );
  }

  mFolderOpen = false;
  deleteLater(); // later, because of the "return mErrorCode"
}

ScheduledJob *ScheduledCompactionTask::run()
{
  if ( !folder() || !folder()->needsCompacting() )
    return 0;
  switch( folder()->storage()->folderType() ) {
  case KMFolderTypeMbox:
    return new MboxCompactionJob( folder(), isImmediate() );
  case KMFolderTypeCachedImap:
  case KMFolderTypeMaildir:
    return new MaildirCompactionJob( folder(), isImmediate() );
  default: // imap, search, unknown...
    return 0;
  }
}

#include "compactionjob.moc"
<commit_msg>Need unistd for fsync()<commit_after>/**
 * Copyright (c) 2004 David Faure <faure@kde.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of this program with any edition of
 *  the Qt library by Trolltech AS, Norway (or with modified versions
 *  of Qt that use the same license as Qt), and distribute linked
 *  combinations including the two.  You must obey the GNU General
 *  Public License in all respects for all of the code used other than
 *  Qt.  If you modify this file, you may extend this exception to
 *  your version of the file, but you are not obligated to do so.  If
 *  you do not wish to do so, delete this exception statement from
 *  your version.
 */

#include "compactionjob.h"
#include "kmfolder.h"
#include "broadcaststatus.h"
using KPIM::BroadcastStatus;
#include "kmfoldermbox.h"
#include "kmfoldermaildir.h"

#include <kdebug.h>
#include <klocale.h>

#include <QFile>
#include <QFileInfo>
#include <QDir>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>

using namespace KMail;

// Look at this number of messages in each slotDoWork call
#define COMPACTIONJOB_NRMESSAGES 100
// And wait this number of milliseconds before calling it again
#define COMPACTIONJOB_TIMERINTERVAL 100

MboxCompactionJob::MboxCompactionJob( KMFolder* folder, bool immediate )
 : ScheduledJob( folder, immediate ), mTimer( this ), mTmpFile( 0 ),
   mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false )
{
}

MboxCompactionJob::~MboxCompactionJob()
{
}

void MboxCompactionJob::kill()
{
  Q_ASSERT( mCancellable );
  // We must close the folder if we opened it and got interrupted
  if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() ) {
    mSrcFolder->storage()->close( "mboxcompact" );
  }

  if ( mTmpFile ) {
    fclose( mTmpFile );
  }
  mTmpFile = 0;
  if ( !mTempName.isEmpty() ) {
    QFile::remove( mTempName );
  }
  FolderJob::kill();
}

QString MboxCompactionJob::realLocation() const
{
  QString location = mSrcFolder->location();
  QFileInfo inf( location );
  if (inf.isSymLink()) {
    KUrl u; u.setPath( location );
    // follow (and resolve) symlinks so that the final ::rename() always works
    // KUrl gives us support for absolute and relative links transparently.
    return KUrl( u, inf.readLink() ).path();
  }
  return location;
}

int MboxCompactionJob::executeNow( bool silent )
{
  mSilent = silent;
  FolderStorage *storage = mSrcFolder->storage();
  KMFolderMbox *mbox = static_cast<KMFolderMbox *>( storage );
  if ( !storage->compactable() ) {
    kDebug(5006) << storage->location() <<" compaction skipped.";
    if ( !mSilent ) {
      QString str = i18n( "For safety reasons, compaction has been disabled for %1", mbox->label() );
      BroadcastStatus::instance()->setStatusMsg( str );
    }
    return 0;
  }
  kDebug(5006) <<"Compacting" << mSrcFolder->idString();

  if ( KMFolderIndex::IndexOk != mbox->indexStatus() ) {
    kDebug(5006) <<"Critical error:" << storage->location()
                 << "has been modified by an external application while KMail was running.";
    //      exit(1); backed out due to broken nfs
  }

  const QFileInfo pathInfo( realLocation() );
  // Use /dir/.mailboxname.compacted so that it's hidden, and doesn't show up after restarting kmail
  // (e.g. due to an unfortunate crash while compaction is happening)
  mTempName = pathInfo.path() + "/." + pathInfo.fileName() + ".compacted";

  mode_t old_umask = umask( 077 );
  mTmpFile = fopen( QFile::encodeName( mTempName ), "w" );
  umask( old_umask );
  if (!mTmpFile) {
    kWarning(5006) <<"Couldn't start compacting" << mSrcFolder->label()
                   << ":" << strerror( errno )
                   << "while creating" << mTempName;
    return errno;
  }
  mOpeningFolder = true; // Ignore open-notifications while opening the folder
  storage->open( "mboxcompact" );
  mOpeningFolder = false;
  mFolderOpen = true;
  mOffset = 0;
  mCurrentIndex = 0;

  kDebug(5006) <<"MboxCompactionJob: starting to compact folder"
               << mSrcFolder->location() << "into" << mTempName;
  connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) );
  if ( !mImmediate ) {
    mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
  }
  slotDoWork();
  return mErrorCode;
}

void MboxCompactionJob::slotDoWork()
{
  // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
  KMFolderMbox *mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
  bool bDone = false;
  int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES;
  int rc = mbox->compact( mCurrentIndex, nbMessages,
                          mTmpFile, mOffset /*in-out*/, bDone /*out*/ );
  if ( !mImmediate )
    mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
  if ( rc || bDone ) // error, or finished
    done( rc );
}

void MboxCompactionJob::done( int rc )
{
  mTimer.stop();
  mCancellable = false;
  KMFolderMbox *mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
  if ( !rc ) {
    rc = fflush( mTmpFile );
  }
  if ( !rc ) {
    rc = fsync( fileno( mTmpFile ) );
  }
  rc |= fclose( mTmpFile );
  QString str;
  if ( !rc ) {
    bool autoCreate = mbox->autoCreateIndex();
    QString box( realLocation() );
    ::rename( QFile::encodeName( mTempName ), QFile::encodeName( box ) );
    mbox->writeIndex();
    mbox->writeConfig();
    mbox->setAutoCreateIndex( false );
    mbox->close( "mboxcompact", true );
    mbox->setAutoCreateIndex( autoCreate );
    mbox->setNeedsCompacting( false );            // We are clean now
    str = i18n( "Folder \"%1\" successfully compacted", mSrcFolder->label() );
    kDebug(5006) << str;
  } else {
    mbox->close( "mboxcompact" );
    str = i18n( "Error occurred while compacting \"%1\". Compaction aborted.", mSrcFolder->label() );
    kDebug(5006) <<"Error occurred while compacting" << mbox->location();
    kDebug(5006) <<"Compaction aborted.";
    QFile::remove( mTempName );
  }
  mErrorCode = rc;

  if ( !mSilent )
    BroadcastStatus::instance()->setStatusMsg( str );

  mFolderOpen = false;
  deleteLater(); // later, because of the "return mErrorCode"
}

////

MaildirCompactionJob::MaildirCompactionJob( KMFolder* folder, bool immediate )
 : ScheduledJob( folder, immediate ), mTimer( this ),
   mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false )
{
}

MaildirCompactionJob::~MaildirCompactionJob()
{
}

void MaildirCompactionJob::kill()
{
  Q_ASSERT( mCancellable );
  // We must close the folder if we opened it and got interrupted
  if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() ) {
    mSrcFolder->storage()->close( "maildircompact" );
  }

  FolderJob::kill();
}

int MaildirCompactionJob::executeNow( bool silent )
{
  mSilent = silent;
  KMFolderMaildir *storage =
    static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
  kDebug(5006) <<"Compacting" << mSrcFolder->idString();

  mOpeningFolder = true; // Ignore open-notifications while opening the folder
  storage->open( "maildircompact" );
  mOpeningFolder = false;
  mFolderOpen = true;
  QString subdirNew( storage->location() + "/new/" );
  QDir d( subdirNew );
  mEntryList = d.entryList();
  mCurrentIndex = 0;

  kDebug(5006) <<"MaildirCompactionJob: starting to compact in folder"
               << mSrcFolder->location();
  connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) );
  if ( !mImmediate ) {
    mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
  }
  slotDoWork();
  return mErrorCode;
}

void MaildirCompactionJob::slotDoWork()
{
  // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
  KMFolderMaildir *storage =
    static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
  bool bDone = false;
  int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES;
  int rc = storage->compact( mCurrentIndex, nbMessages, mEntryList, bDone /*out*/ );
  if ( !mImmediate )
    mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
  if ( rc || bDone ) // error, or finished
    done( rc );
}

void MaildirCompactionJob::done( int rc )
{
  KMFolderMaildir *storage =
    static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
  mTimer.stop();
  mCancellable = false;
  QString str;
  if ( !rc ) {
    str = i18n( "Folder \"%1\" successfully compacted", mSrcFolder->label() );
  } else {
    str = i18n( "Error occurred while compacting \"%1\". Compaction aborted.", mSrcFolder->label() );
  }
  mErrorCode = rc;
  storage->setNeedsCompacting( false );
  storage->close( "maildircompact" );
  if ( storage->isOpened() ) {
    storage->updateIndex();
  }
  if ( !mSilent ) {
    BroadcastStatus::instance()->setStatusMsg( str );
  }

  mFolderOpen = false;
  deleteLater(); // later, because of the "return mErrorCode"
}

ScheduledJob *ScheduledCompactionTask::run()
{
  if ( !folder() || !folder()->needsCompacting() )
    return 0;
  switch( folder()->storage()->folderType() ) {
  case KMFolderTypeMbox:
    return new MboxCompactionJob( folder(), isImmediate() );
  case KMFolderTypeCachedImap:
  case KMFolderTypeMaildir:
    return new MaildirCompactionJob( folder(), isImmediate() );
  default: // imap, search, unknown...
    return 0;
  }
}

#include "compactionjob.moc"
<|endoftext|>


<commit_before>
// Player.cpp : Defines the class behaviors for the application.
//

#include "stdafx.h"
#include "afxwinappex.h"
#include "afxdialogex.h"
#include "Player.h"
#include "MainFrm.h"

#include "PlayerDoc.h"
#include "PlayerView.h"
#include "PlayerViewD2D.h"

#include "I420Effect.h"

#include "AsyncGetUrlUnderMouseCursor.h"

#include <boost/log/sinks/debug_output_backend.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/core/core.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>

#include <boost/log/expressions.hpp>

#include <boost/log/trivial.hpp>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//#define USE_DIRECT2D_VIEW

namespace {

void init_logging()
{
    namespace expr = boost::log::expressions;

    boost::log::add_common_attributes();

    auto core = boost::log::core::get();

    // Create the sink. The backend requires synchronization in the frontend.
    auto sink(boost::make_shared<boost::log::sinks::synchronous_sink<boost::log::sinks::debug_output_backend>>());

    sink->set_formatter(expr::stream
        << expr::if_(expr::has_attr("Severity"))
        [
            expr::stream << '[' << expr::attr< boost::log::trivial::severity_level >("Severity") << ']'
        ]
        << expr::if_(expr::has_attr("Channel"))
        [
            expr::stream << '[' << expr::attr< std::string >("Channel") << ']'
        ]
        << expr::smessage << '\n');

    // Set the special filter to the frontend
    // in order to skip the sink when no debugger is available
    //sink->set_filter(expr::is_debugger_present());

    core->add_sink(sink);
}

} // namespace

// CPlayerApp

BEGIN_MESSAGE_MAP(CPlayerApp, CWinAppEx)
    ON_COMMAND(ID_APP_ABOUT, &CPlayerApp::OnAppAbout)
    // Standard file based document commands
    ON_COMMAND(ID_FILE_NEW, &CWinAppEx::OnFileNew)
    ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen)
    // Standard print setup command
    ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinAppEx::OnFilePrintSetup)
    ON_THREAD_MESSAGE(WM_ON_ASYNC_URL, &CPlayerApp::OnAsyncUrl)
END_MESSAGE_MAP()

// CPlayerApp construction

CPlayerApp::CPlayerApp()
{
    // support Restart Manager
    m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS;
#ifdef _MANAGED
    // If the application is built using Common Language Runtime support (/clr):
    //     1) This additional setting is needed for Restart Manager support to work properly.
    //     2) In your project, you must add a reference to System.Windows.Forms in order to build.
    System::Windows::Forms::Application::SetUnhandledExceptionMode(System::Windows::Forms::UnhandledExceptionMode::ThrowException);
#endif

    // TODO: replace application ID string below with unique ID string; recommended
    // format for string is CompanyName.ProductName.SubProduct.VersionInformation
    SetAppID(_T("Player.AppID.NoVersion"));

    // Place all significant initialization in InitInstance
    init_logging();
}

// The one and only CPlayerApp object

CPlayerApp theApp;

// CPlayerApp initialization

BOOL CPlayerApp::InitInstance()
{
    CPane::m_bHandleMinSize = true;

    // InitCommonControlsEx() is required on Windows XP if an application
    // manifest specifies use of ComCtl32.dll version 6 or later to enable
    // visual styles.  Otherwise, any window creation will fail.
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    // Set this to include all the common control classes you want to use
    // in your application.
    InitCtrls.dwICC = ICC_STANDARD_CLASSES;
    InitCommonControlsEx(&InitCtrls);

    __super::InitInstance();

    AfxOleInit();

    // Parse command line for standard shell commands, DDE, file open
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo);
    if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileNew)
    {
        AsyncGetUrlUnderMouseCursor();
    }

#ifdef USE_DIRECT2D_VIEW
    if (AfxGetD2DState()->GetDirect2dFactory() == NULL)
    {
        return FALSE;
    }
    HRESULT hr_create = I420Effect::Register(static_cast<ID2D1Factory1*>(AfxGetD2DState()->GetDirect2dFactory()));
    if (FAILED(hr_create))
    {
        return FALSE;
    }
#endif // USE_DIRECT2D_VIEW

    EnableTaskbarInteraction(FALSE);

    // AfxInitRichEdit2() is required to use RichEdit control
    // AfxInitRichEdit2();

    // Standard initialization
    // If you are not using these features and wish to reduce the size
    // of your final executable, you should remove from the following
    // the specific initialization routines you do not need
    // Change the registry key under which our settings are stored
    // TODO: You should modify this string to be something appropriate
    // such as the name of your company or organization
    SetRegistryKey(_T("FFMPEG Player"));
    LoadStdProfileSettings(_AFX_MRU_MAX_COUNT);  // Load standard INI file options (including MRU)

    // MFC Feature Pack
    InitContextMenuManager();
    InitShellManager();
    InitKeyboardManager();
    InitTooltipManager();
    CMFCToolTipInfo ttParams;
    ttParams.m_bVislManagerTheme = TRUE;
    theApp.GetTooltipManager()->
        SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
        RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);

    // Register the application's document templates.  Document templates
    //  serve as the connection between documents, frame windows and views
    CSingleDocTemplate* pDocTemplate = new CSingleDocTemplate(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CPlayerDoc),
        RUNTIME_CLASS(CMainFrame),       // main SDI frame window
#ifdef USE_DIRECT2D_VIEW
        RUNTIME_CLASS(CPlayerViewD2D));
#else
        RUNTIME_CLASS(CPlayerView));
#endif
    if (!pDocTemplate)
        return FALSE;
    AddDocTemplate(pDocTemplate);

    // Dispatch commands specified on the command line.  Will return FALSE if
    // app was launched with /RegServer, /Register, /Unregserver or /Unregister.
    if (!ProcessShellCommand(cmdInfo))
        return FALSE;

    // The one and only window has been initialized, so show and update it
    m_pMainWnd->ShowWindow(SW_SHOW);
    m_pMainWnd->UpdateWindow();
    return TRUE;
}

// CPlayerApp message handlers

// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// Dialog Data
    enum { IDD = IDD_ABOUTBOX };

    CString m_videoProperties;

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_VIDEO_PROPERTIES, m_videoProperties);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

CPlayerDoc* CPlayerApp::GetPlayerDocument()
{
    POSITION pos1 = GetFirstDocTemplatePosition();
    if (CDocTemplate* templ = GetNextDocTemplate(pos1))
    {
        POSITION pos2 = templ->GetFirstDocPosition();
        return dynamic_cast<CPlayerDoc*>(templ->GetNextDoc(pos2));
    }

    return nullptr;
}

// App command to run the dialog
void CPlayerApp::OnAppAbout()
{
    CAboutDlg aboutDlg;

    if (CPlayerDoc* doc = GetPlayerDocument())
    {
        const auto properties = doc->getFrameDecoder()->getProperties();
        for (const auto& prop : properties)
        {
            if (!aboutDlg.m_videoProperties.IsEmpty())
                aboutDlg.m_videoProperties += '\n';
            aboutDlg.m_videoProperties += prop.c_str();
        }
    }

    aboutDlg.DoModal();
}

void CPlayerApp::OnAsyncUrl(WPARAM wParam, LPARAM)
{
    CComBSTR url;
    url.Attach((BSTR)wParam);
    if (CPlayerDoc* doc = GetPlayerDocument())
    {
        doc->OnAsyncUrl(CString(url));
    }
}

// CPlayerApp message handlers

<commit_msg>semi-transparent about box<commit_after>
// Player.cpp : Defines the class behaviors for the application.
//

#include "stdafx.h"
#include "afxwinappex.h"
#include "afxdialogex.h"
#include "Player.h"
#include "MainFrm.h"

#include "PlayerDoc.h"
#include "PlayerView.h"
#include "PlayerViewD2D.h"

#include "I420Effect.h"

#include "AsyncGetUrlUnderMouseCursor.h"

#include <boost/log/sinks/debug_output_backend.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/core/core.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>

#include <boost/log/expressions.hpp>

#include <boost/log/trivial.hpp>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//#define USE_DIRECT2D_VIEW

namespace {

void init_logging()
{
    namespace expr = boost::log::expressions;

    boost::log::add_common_attributes();

    auto core = boost::log::core::get();

    // Create the sink. The backend requires synchronization in the frontend.
    auto sink(boost::make_shared<boost::log::sinks::synchronous_sink<boost::log::sinks::debug_output_backend>>());

    sink->set_formatter(expr::stream
        << expr::if_(expr::has_attr("Severity"))
        [
            expr::stream << '[' << expr::attr< boost::log::trivial::severity_level >("Severity") << ']'
        ]
        << expr::if_(expr::has_attr("Channel"))
        [
            expr::stream << '[' << expr::attr< std::string >("Channel") << ']'
        ]
        << expr::smessage << '\n');

    // Set the special filter to the frontend
    // in order to skip the sink when no debugger is available
    //sink->set_filter(expr::is_debugger_present());

    core->add_sink(sink);
}

} // namespace

// CPlayerApp

BEGIN_MESSAGE_MAP(CPlayerApp, CWinAppEx)
    ON_COMMAND(ID_APP_ABOUT, &CPlayerApp::OnAppAbout)
    // Standard file based document commands
    ON_COMMAND(ID_FILE_NEW, &CWinAppEx::OnFileNew)
    ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen)
    // Standard print setup command
    ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinAppEx::OnFilePrintSetup)
    ON_THREAD_MESSAGE(WM_ON_ASYNC_URL, &CPlayerApp::OnAsyncUrl)
END_MESSAGE_MAP()

// CPlayerApp construction

CPlayerApp::CPlayerApp()
{
    // support Restart Manager
    m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS;
#ifdef _MANAGED
    // If the application is built using Common Language Runtime support (/clr):
    //     1) This additional setting is needed for Restart Manager support to work properly.
    //     2) In your project, you must add a reference to System.Windows.Forms in order to build.
    System::Windows::Forms::Application::SetUnhandledExceptionMode(System::Windows::Forms::UnhandledExceptionMode::ThrowException);
#endif

    // TODO: replace application ID string below with unique ID string; recommended
    // format for string is CompanyName.ProductName.SubProduct.VersionInformation
    SetAppID(_T("Player.AppID.NoVersion"));

    // Place all significant initialization in InitInstance
    init_logging();
}

// The one and only CPlayerApp object

CPlayerApp theApp;

// CPlayerApp initialization

BOOL CPlayerApp::InitInstance()
{
    CPane::m_bHandleMinSize = true;

    // InitCommonControlsEx() is required on Windows XP if an application
    // manifest specifies use of ComCtl32.dll version 6 or later to enable
    // visual styles.  Otherwise, any window creation will fail.
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    // Set this to include all the common control classes you want to use
    // in your application.
    InitCtrls.dwICC = ICC_STANDARD_CLASSES;
    InitCommonControlsEx(&InitCtrls);

    __super::InitInstance();

    AfxOleInit();

    // Parse command line for standard shell commands, DDE, file open
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo);
    if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileNew)
    {
        AsyncGetUrlUnderMouseCursor();
    }

#ifdef USE_DIRECT2D_VIEW
    if (AfxGetD2DState()->GetDirect2dFactory() == NULL)
    {
        return FALSE;
    }
    HRESULT hr_create = I420Effect::Register(static_cast<ID2D1Factory1*>(AfxGetD2DState()->GetDirect2dFactory()));
    if (FAILED(hr_create))
    {
        return FALSE;
    }
#endif // USE_DIRECT2D_VIEW

    EnableTaskbarInteraction(FALSE);

    // AfxInitRichEdit2() is required to use RichEdit control
    // AfxInitRichEdit2();

    // Standard initialization
    // If you are not using these features and wish to reduce the size
    // of your final executable, you should remove from the following
    // the specific initialization routines you do not need
    // Change the registry key under which our settings are stored
    // TODO: You should modify this string to be something appropriate
    // such as the name of your company or organization
    SetRegistryKey(_T("FFMPEG Player"));
    LoadStdProfileSettings(_AFX_MRU_MAX_COUNT);  // Load standard INI file options (including MRU)

    // MFC Feature Pack
    InitContextMenuManager();
    InitShellManager();
    InitKeyboardManager();
    InitTooltipManager();
    CMFCToolTipInfo ttParams;
    ttParams.m_bVislManagerTheme = TRUE;
    theApp.GetTooltipManager()->
        SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
        RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);

    // Register the application's document templates.  Document templates
    //  serve as the connection between documents, frame windows and views
    CSingleDocTemplate* pDocTemplate = new CSingleDocTemplate(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CPlayerDoc),
        RUNTIME_CLASS(CMainFrame),       // main SDI frame window
#ifdef USE_DIRECT2D_VIEW
        RUNTIME_CLASS(CPlayerViewD2D));
#else
        RUNTIME_CLASS(CPlayerView));
#endif
    if (!pDocTemplate)
        return FALSE;
    AddDocTemplate(pDocTemplate);

    // Dispatch commands specified on the command line.  Will return FALSE if
    // app was launched with /RegServer, /Register, /Unregserver or /Unregister.
    if (!ProcessShellCommand(cmdInfo))
        return FALSE;

    // The one and only window has been initialized, so show and update it
    m_pMainWnd->ShowWindow(SW_SHOW);
    m_pMainWnd->UpdateWindow();
    return TRUE;
}

// CPlayerApp message handlers

// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

    BOOL OnInitDialog() override;

// Dialog Data
    enum { IDD = IDD_ABOUTBOX };

    CString m_videoProperties;

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

BOOL CAboutDlg::OnInitDialog()
{
    ModifyStyleEx(0, WS_EX_LAYERED);
    SetLayeredWindowAttributes(0, (255 * 75) / 100, LWA_ALPHA);
    return __super::OnInitDialog();
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_VIDEO_PROPERTIES, m_videoProperties);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

CPlayerDoc* CPlayerApp::GetPlayerDocument()
{
    POSITION pos1 = GetFirstDocTemplatePosition();
    if (CDocTemplate* templ = GetNextDocTemplate(pos1))
    {
        POSITION pos2 = templ->GetFirstDocPosition();
        return dynamic_cast<CPlayerDoc*>(templ->GetNextDoc(pos2));
    }

    return nullptr;
}

// App command to run the dialog
void CPlayerApp::OnAppAbout()
{
    CAboutDlg aboutDlg;

    if (CPlayerDoc* doc = GetPlayerDocument())
    {
        const auto properties = doc->getFrameDecoder()->getProperties();
        for (const auto& prop : properties)
        {
            if (!aboutDlg.m_videoProperties.IsEmpty())
                aboutDlg.m_videoProperties += '\n';
            aboutDlg.m_videoProperties += prop.c_str();
        }
    }

    aboutDlg.DoModal();
}

void CPlayerApp::OnAsyncUrl(WPARAM wParam, LPARAM)
{
    CComBSTR url;
    url.Attach((BSTR)wParam);
    if (CPlayerDoc* doc = GetPlayerDocument())
    {
        doc->OnAsyncUrl(CString(url));
    }
}

// CPlayerApp message handlers

<|endoftext|>